Skip to content
This repository was archived by the owner on Sep 1, 2024. It is now read-only.

Commit 6844000

Browse files
committed
vmclear and ptrload works, time to launch vm
1 parent 8604cd8 commit 6844000

File tree

3 files changed

+70
-210
lines changed

3 files changed

+70
-210
lines changed

driver/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
5050

5151
info!("The hypervisor has been installed successfully!");
5252

53-
//system_table.boot_services().stall(10_000_000);
53+
system_table.boot_services().stall(20_000_000);
5454

5555
Status::SUCCESS
5656
}

hypervisor/src/intel/segmentation.rs

+40-168
Original file line numberDiff line numberDiff line change
@@ -1,177 +1,49 @@
1-
//! This module provides utilities and structures to manage segment descriptors
2-
//! in the GDT (Global Descriptor Table) and LDT (Local Descriptor Table).
3-
//! It handles the extraction, representation, and manipulation of segment descriptors.
4-
//!
5-
//! Credits to rCore OS for providing an accessible and comprehensible implementation of segmentation:
6-
//! https://github.com/rcore-os/RVM1.5/blob/main/src/arch/x86_64/segmentation.rs
1+
use core::arch::asm;
2+
use x86::bits64::rflags::RFlags;
3+
use x86::segmentation::SegmentSelector;
74

8-
use {
9-
crate::intel::descriptor::Descriptors,
10-
bit_field::BitField,
11-
bitflags::bitflags,
12-
x86::{dtables::DescriptorTablePointer, segmentation::SegmentSelector},
13-
x86_64::structures::gdt::DescriptorFlags,
14-
};
5+
pub fn access_rights_from_native(access_rights: u32) -> u32 {
6+
const VMX_SEGMENT_ACCESS_RIGHTS_UNUSABLE_FLAG: u32 = 1 << 16;
157

16-
bitflags! {
17-
/// Access rights for VMCS guest register states.
18-
///
19-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 24.4.1 Guest Register State
20-
/// and Table 24-2. Format of Access Rights.
21-
pub struct SegmentAccessRights: u32 {
22-
/// Accessed flag.
23-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5.1 Code- and Data-Segment Descriptor Types
24-
const ACCESSED = 1 << 0;
25-
26-
/// Readable (for code segments) or Writable (for data segments).
27-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5.1 Code- and Data-Segment Descriptor Types
28-
const RW = 1 << 1;
29-
30-
/// Conforming bit for code segments.
31-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5.1 Code- and Data-Segment Descriptor Types
32-
const CONFORMING = 1 << 2;
33-
34-
/// Executable bit. Must be set for code segments.
35-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5.1 Code- and Data-Segment Descriptor Types
36-
const EXECUTABLE = 1 << 3;
37-
38-
/// Descriptor type (0 = system; 1 = code or data).
39-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5 Segment Descriptors
40-
const CODE_DATA = 1 << 4;
41-
42-
/// Segment present.
43-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5 Segment Descriptors
44-
const PRESENT = 1 << 7;
45-
46-
/// Long mode active (for CS only).
47-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5.1 Code- and Data-Segment Descriptor Types
48-
const LONG_MODE = 1 << 13;
49-
50-
/// Default operation size (0 = 16-bit segment; 1 = 32-bit segment).
51-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5 Segment Descriptors
52-
const DB = 1 << 14;
53-
54-
/// Granularity.
55-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5 Segment Descriptors
56-
const GRANULARITY = 1 << 15;
57-
58-
/// Segment unusable (0 = usable; 1 = unusable).
59-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 24.4.1 Guest Register State
60-
const UNUSABLE = 1 << 16;
61-
62-
/// Privilege level mask (bits 5-6).
63-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5 Segment Descriptors
64-
const DPL_MASK = 3 << 5;
8+
if access_rights == 0 {
9+
return VMX_SEGMENT_ACCESS_RIGHTS_UNUSABLE_FLAG;
6510
}
66-
}
67-
68-
impl SegmentAccessRights {
69-
/// Constructs `SegmentAccessRights` from a segment descriptor.
70-
///
71-
/// The access rights are extracted from bits 40-55 of the segment descriptor.
72-
/// Only bits 8-15 and 0-7 within this range are directly related to access rights.
73-
///
74-
/// # Arguments
75-
///
76-
/// * `desc` - The segment descriptor from which to extract access rights.
77-
///
78-
/// # Returns
79-
///
80-
/// A `SegmentAccessRights` instance representing the extracted access rights.
81-
pub fn from_descriptor(desc: u64) -> Self {
82-
// Extract bits 40-55 from the descriptor
83-
let access_bits = desc.get_bits(40..56) as u32;
8411

85-
// Mask out the unwanted bits to get only the relevant access rights
86-
let relevant_bits = access_bits & 0xf0ff;
87-
88-
Self::from_bits_truncate(relevant_bits)
89-
}
12+
(access_rights >> 8) & 0b1111_0000_1111_1111
9013
}
9114

92-
/// Represents the details of a segment descriptor in the GDT or LDT.
93-
/// Segment descriptors are used to define the characteristics of a segment.
94-
///
95-
/// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.5 Segment Descriptors
96-
/// and Figure 3-8. Segment Descriptor
97-
#[repr(C, align(16))]
98-
pub struct SegmentDescriptor {
99-
/// Selector provides an index into the GDT or LDT, pointing to the segment descriptor.
100-
pub selector: SegmentSelector,
101-
/// The starting address of the segment.
102-
pub base_address: u64,
103-
/// The size of the segment. The ending address is calculated as base_address + segment_limit.
104-
pub segment_limit: u32,
105-
/// Flags detailing the properties of the segment.
106-
pub access_rights: SegmentAccessRights,
15+
//
16+
pub(crate) fn lsl(selector: SegmentSelector) -> u32 {
17+
let flags: u64;
18+
let mut limit: u64;
19+
unsafe {
20+
asm!(
21+
"lsl {}, {}",
22+
"pushfq",
23+
"pop {}",
24+
out(reg) limit,
25+
in(reg) u64::from(selector.bits()),
26+
lateout(reg) flags
27+
);
28+
};
29+
assert!(RFlags::from_raw(flags).contains(RFlags::FLAGS_ZF));
30+
limit as u32
10731
}
10832

109-
impl SegmentDescriptor {
110-
/// Returns an invalid `SegmentDescriptor`.
111-
/// This is useful to represent a non-present or non-configured segment.
112-
pub const fn invalid() -> Self {
113-
Self {
114-
selector: SegmentSelector::empty(),
115-
base_address: 0,
116-
segment_limit: 0,
117-
access_rights: SegmentAccessRights::UNUSABLE,
118-
}
119-
}
120-
121-
/// Constructs a `SegmentDescriptor` from a given segment selector and a pointer to the GDT.
122-
///
123-
/// The method uses the segment selector to index into the GDT and retrieve the associated segment descriptor.
124-
/// It then extracts the base address, segment limit, and access rights from the descriptor.
125-
///
126-
/// # Arguments
127-
///
128-
/// * `selector` - A segment selector that provides an index into the GDT.
129-
/// * `gdtr` - A pointer to the GDT.
130-
pub fn from_selector(selector: SegmentSelector, gdtr: &DescriptorTablePointer<u64>) -> Self {
131-
// Index into the GDT using the selector's index value.
132-
let index = selector.index() as usize;
133-
let table = Descriptors::from_pointer(gdtr);
134-
135-
// Fetch the descriptor entry from the GDT.
136-
let entry_value = table[index];
137-
138-
// Convert the entry value into descriptor flags.
139-
let entry = DescriptorFlags::from_bits_truncate(entry_value);
140-
141-
// If the segment is present in memory, extract its properties.
142-
if entry.contains(DescriptorFlags::PRESENT) {
143-
// Extract base address from the descriptor.
144-
let base_low = entry_value.get_bits(16..40);
145-
let base_high = entry_value.get_bits(56..64) << 24;
146-
let mut base_address = base_low | base_high;
147-
148-
// Extract segment limit from the descriptor.
149-
let segment_limit_low = entry_value.get_bits(0..16);
150-
let segment_limit_high = entry_value.get_bits(48..52) << 12;
151-
let mut segment_limit = segment_limit_low | segment_limit_high;
152-
153-
// For non-user segments (like TSS), the base address can span two GDT entries.
154-
// If this is the case, fetch the high 32 bits of the base address from the next GDT entry.
155-
if !entry.contains(DescriptorFlags::USER_SEGMENT) {
156-
let high = table[index + 1];
157-
base_address += high << 32;
158-
}
159-
160-
// If the granularity flag is set, the segment limit is scaled by a factor of 4096.
161-
if entry.contains(DescriptorFlags::GRANULARITY) {
162-
segment_limit = (segment_limit << 12) | 0xfff;
163-
}
164-
165-
// Construct and return the `SegmentDescriptor`.
166-
Self {
167-
selector,
168-
base_address,
169-
segment_limit: segment_limit as _,
170-
access_rights: SegmentAccessRights::from_descriptor(entry_value),
171-
}
172-
} else {
173-
// If the segment is not present, return an invalid descriptor.
174-
Self::invalid()
175-
}
176-
}
33+
/// LAR-Load Access Rights Byte
34+
pub(crate) fn lar(selector: SegmentSelector) -> u32 {
35+
let flags: u64;
36+
let mut access_rights: u64;
37+
unsafe {
38+
asm!(
39+
"lar {}, {}",
40+
"pushfq",
41+
"pop {}",
42+
out(reg) access_rights,
43+
in(reg) u64::from(selector.bits()),
44+
lateout(reg) flags
45+
);
46+
};
47+
assert!(RFlags::from_raw(flags).contains(RFlags::FLAGS_ZF));
48+
access_rights as u32
17749
}

hypervisor/src/intel/vmcs.rs

+29-41
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use {
99
paging::BASE_PAGE_SIZE,
1010
rflags,
1111
},
12-
controlregs, dtables, msr,
13-
segmentation::{cs, ds, es, fs, gs, SegmentSelector, ss},
12+
msr,
13+
segmentation::{cs, ds, es, fs, gs, ss},
1414
vmx::vmcs,
1515
debugregs::dr7,
1616
},
@@ -22,12 +22,12 @@ use {
2222
controls::{adjust_vmx_controls, VmxControl},
2323
descriptor::Descriptors,
2424
paging::PageTables,
25-
segmentation::SegmentDescriptor,
2625
shared_data::SharedData,
27-
support::{rdmsr, sidt, vmread, vmwrite},
26+
support::{rdmsr, sidt, vmread, vmwrite, cr0, cr3},
2827
invvpid::{invvpid_single_context, VPID_TAG},
2928
invept::invept_single_context,
3029
page::Page,
30+
segmentation::{access_rights_from_native, lar, lsl},
3131
},
3232
},
3333
};
@@ -71,8 +71,8 @@ impl Vmcs {
7171

7272
let idtr = sidt();
7373

74-
unsafe { vmwrite(vmcs::guest::CR0, controlregs::cr0().bits() as u64) };
75-
unsafe { vmwrite(vmcs::guest::CR3, controlregs::cr3()) };
74+
vmwrite(vmcs::guest::CR0, cr0().bits() as u64);
75+
vmwrite(vmcs::guest::CR3, cr3());
7676
vmwrite(vmcs::guest::CR4, Cr4::read_raw());
7777

7878
vmwrite(vmcs::guest::DR7, unsafe { dr7().0 as u64 });
@@ -88,48 +88,38 @@ impl Vmcs {
8888
vmwrite(vmcs::guest::FS_SELECTOR, fs().bits());
8989
vmwrite(vmcs::guest::GS_SELECTOR, gs().bits());
9090

91-
vmwrite(vmcs::guest::LDTR_SELECTOR, 0u16); // this is not 0 in Hypervisor-101-in-Rust but is in Hello-VT-rp
91+
vmwrite(vmcs::guest::LDTR_SELECTOR, 0u16);
9292
vmwrite(vmcs::guest::TR_SELECTOR, guest_descriptor.tr.bits());
9393

94-
unsafe { vmwrite(vmcs::guest::FS_BASE, msr::rdmsr(msr::IA32_FS_BASE)) };
95-
unsafe { vmwrite(vmcs::guest::GS_BASE, msr::rdmsr(msr::IA32_GS_BASE)) };
96-
unsafe { vmwrite(vmcs::guest::LDTR_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(dtables::ldtr().bits()), &guest_descriptor.gdtr).base_address) };
94+
// All segment base registers are assumed to be zero, except that of TR.
9795
vmwrite(vmcs::guest::TR_BASE, guest_descriptor.tss.base);
9896

99-
vmwrite(vmcs::guest::CS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(ss().bits()), &guest_descriptor.gdtr).segment_limit);
100-
vmwrite(vmcs::guest::SS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(ss().bits()), &guest_descriptor.gdtr).segment_limit);
101-
vmwrite(vmcs::guest::DS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(ds().bits()), &guest_descriptor.gdtr).segment_limit);
102-
vmwrite(vmcs::guest::ES_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(es().bits()), &guest_descriptor.gdtr).segment_limit);
103-
vmwrite(vmcs::guest::FS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(fs().bits()), &guest_descriptor.gdtr).segment_limit);
104-
vmwrite(vmcs::guest::GS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(gs().bits()), &guest_descriptor.gdtr).segment_limit);
105-
106-
vmwrite(vmcs::guest::LDTR_LIMIT, 0u32); // this is not 0 in Hypervisor-101-in-Rust but is in Hello-VT-rp
97+
vmwrite(vmcs::guest::CS_LIMIT, lsl(ss()));
98+
vmwrite(vmcs::guest::SS_LIMIT, lsl(ss()));
99+
vmwrite(vmcs::guest::DS_LIMIT, lsl(ds()));
100+
vmwrite(vmcs::guest::ES_LIMIT, lsl(es()));
101+
vmwrite(vmcs::guest::FS_LIMIT, lsl(fs()));
102+
vmwrite(vmcs::guest::GS_LIMIT, lsl(gs()));
103+
vmwrite(vmcs::guest::LDTR_LIMIT, 0u32);
107104
vmwrite(vmcs::guest::TR_LIMIT, guest_descriptor.tr.bits());
108105

109-
vmwrite(vmcs::guest::CS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(cs().bits()), &guest_descriptor.gdtr).access_rights.bits());
110-
vmwrite(vmcs::guest::SS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(ss().bits()), &guest_descriptor.gdtr).access_rights.bits());
111-
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(ds().bits()), &guest_descriptor.gdtr).access_rights.bits());
112-
vmwrite(vmcs::guest::ES_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(es().bits()), &guest_descriptor.gdtr).access_rights.bits());
113-
vmwrite(vmcs::guest::FS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(fs().bits()), &guest_descriptor.gdtr).access_rights.bits());
114-
vmwrite(vmcs::guest::GS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(gs().bits()), &guest_descriptor.gdtr).access_rights.bits());
115-
116-
// https://github.com/tandasat/Hello-VT-rp/blob/main/hypervisor/src/intel_vt/vm.rs#L93-L97
117-
vmwrite(vmcs::guest::LDTR_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(0), &guest_descriptor.gdtr).access_rights.bits());
118-
vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(guest_descriptor.tss.ar as u16), &guest_descriptor.gdtr).access_rights.bits());
106+
vmwrite(vmcs::guest::CS_ACCESS_RIGHTS, access_rights_from_native(lar(cs())) as u64);
107+
vmwrite(vmcs::guest::SS_ACCESS_RIGHTS, access_rights_from_native(lar(ss())) as u64);
108+
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, access_rights_from_native(lar(ds())) as u64);
109+
vmwrite(vmcs::guest::ES_ACCESS_RIGHTS, access_rights_from_native(lar(es())) as u64);
110+
vmwrite(vmcs::guest::FS_ACCESS_RIGHTS, access_rights_from_native(lar(fs())) as u64);
111+
vmwrite(vmcs::guest::GS_ACCESS_RIGHTS, access_rights_from_native(lar(gs())) as u64);
112+
vmwrite(vmcs::guest::LDTR_ACCESS_RIGHTS, access_rights_from_native(0u32));
113+
vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, access_rights_from_native(guest_descriptor.tss.ar));
119114

120115
vmwrite(vmcs::guest::GDTR_BASE, guest_descriptor.gdtr.base as u64);
121116
vmwrite(vmcs::guest::IDTR_BASE, idtr.base as u64);
122117

123118
vmwrite(vmcs::guest::GDTR_LIMIT, guest_descriptor.gdtr.limit as u64);
124119
vmwrite(vmcs::guest::IDTR_LIMIT, idtr.limit as u64);
125120

126-
unsafe {
127-
vmwrite(vmcs::guest::IA32_DEBUGCTL_FULL, msr::rdmsr(msr::IA32_DEBUGCTL));
128-
vmwrite(vmcs::guest::IA32_SYSENTER_CS, msr::rdmsr(msr::IA32_SYSENTER_CS));
129-
vmwrite(vmcs::guest::IA32_SYSENTER_ESP, msr::rdmsr(msr::IA32_SYSENTER_ESP));
130-
vmwrite(vmcs::guest::IA32_SYSENTER_EIP, msr::rdmsr(msr::IA32_SYSENTER_EIP));
131-
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX);
132-
}
121+
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX);
122+
133123

134124
// Note: VMCS does not manage all registers; some require manual intervention for saving and loading.
135125
// This includes general-purpose registers and xmm registers, which must be explicitly preserved and restored by the software.
@@ -185,9 +175,9 @@ impl Vmcs {
185175

186176
let pml4_pa = host_paging.get_pml4_pa()?;
187177

188-
unsafe { vmwrite(vmcs::host::CR0, controlregs::cr0().bits() as u64) };
178+
vmwrite(vmcs::host::CR0, cr0().bits() as u64);
189179
vmwrite(vmcs::host::CR3, pml4_pa);
190-
unsafe { vmwrite(vmcs::host::CR4, controlregs::cr4().bits() as u64) };
180+
vmwrite(vmcs::host::CR4, Cr4::read_raw());
191181

192182
vmwrite(vmcs::host::CS_SELECTOR, host_descriptor.cs.bits());
193183
vmwrite(vmcs::host::TR_SELECTOR, host_descriptor.tr.bits());
@@ -231,10 +221,8 @@ impl Vmcs {
231221
vmwrite(vmcs::control::VMEXIT_CONTROLS, adjust_vmx_controls(VmxControl::VmExit, EXIT_CTL));
232222
vmwrite(vmcs::control::PINBASED_EXEC_CONTROLS, adjust_vmx_controls(VmxControl::PinBased, PINBASED_CTL));
233223

234-
unsafe {
235-
vmwrite(vmcs::control::CR0_READ_SHADOW, controlregs::cr0().bits() as u64);
236-
vmwrite(vmcs::control::CR4_READ_SHADOW, controlregs::cr4().bits() as u64);
237-
};
224+
vmwrite(vmcs::control::CR0_READ_SHADOW, cr0().bits() as u64);
225+
vmwrite(vmcs::control::CR4_READ_SHADOW, Cr4::read_raw());
238226

239227
vmwrite(vmcs::control::MSR_BITMAPS_ADDR_FULL, msr_bitmap.as_ref() as *const _ as u64);
240228
//vmwrite(vmcs::control::EXCEPTION_BITMAP, 1u64 << (ExceptionInterrupt::Breakpoint as u32));

0 commit comments

Comments
 (0)