xref: /DragonOS/kernel/src/arch/x86_64/kvm/vmx/vcpu.rs (revision 40314b30ab2a7e1fd06a05a00f693e644e446035)
1*40314b30SXiaoye Zheng use super::vmcs::{
2*40314b30SXiaoye Zheng     VMCSRegion, VmcsFields, VmxEntryCtrl, VmxPrimaryExitCtrl, VmxPrimaryProcessBasedExecuteCtrl,
3*40314b30SXiaoye Zheng     VmxSecondaryProcessBasedExecuteCtrl,
4*40314b30SXiaoye Zheng };
5*40314b30SXiaoye Zheng use super::vmx_asm_wrapper::{vmx_vmclear, vmx_vmptrld, vmx_vmread, vmx_vmwrite, vmxoff, vmxon};
6*40314b30SXiaoye Zheng use crate::arch::kvm::vmx::mmu::KvmMmu;
7*40314b30SXiaoye Zheng use crate::arch::kvm::vmx::seg::{seg_setup, Sreg};
8*40314b30SXiaoye Zheng use crate::arch::kvm::vmx::{VcpuRegIndex, X86_CR0};
9*40314b30SXiaoye Zheng use crate::arch::mm::{LockedFrameAllocator, PageMapper};
10*40314b30SXiaoye Zheng use crate::arch::x86_64::mm::X86_64MMArch;
11*40314b30SXiaoye Zheng use crate::arch::MMArch;
12*40314b30SXiaoye Zheng use crate::kdebug;
13*40314b30SXiaoye Zheng use crate::mm::{phys_2_virt, VirtAddr};
14*40314b30SXiaoye Zheng use crate::mm::{MemoryManagementArch, PageTableKind};
15*40314b30SXiaoye Zheng use crate::syscall::SystemError;
16*40314b30SXiaoye Zheng use crate::virt::kvm::vcpu::Vcpu;
17*40314b30SXiaoye Zheng use crate::virt::kvm::vm::Vm;
18*40314b30SXiaoye Zheng use alloc::alloc::Global;
19*40314b30SXiaoye Zheng use alloc::boxed::Box;
20*40314b30SXiaoye Zheng use core::slice;
21*40314b30SXiaoye Zheng use raw_cpuid::CpuId;
22*40314b30SXiaoye Zheng use x86;
23*40314b30SXiaoye Zheng use x86::{controlregs, msr, segmentation};
24*40314b30SXiaoye Zheng // use crate::arch::kvm::vmx::seg::RMODE_TSS_SIZE;
25*40314b30SXiaoye Zheng // use crate::virt::kvm::{KVM};
26*40314b30SXiaoye Zheng 
27*40314b30SXiaoye Zheng // KERNEL_ALLOCATOR
28*40314b30SXiaoye Zheng pub const PAGE_SIZE: usize = 0x1000;
29*40314b30SXiaoye Zheng pub const NR_VCPU_REGS: usize = 16;
30*40314b30SXiaoye Zheng 
31*40314b30SXiaoye Zheng #[repr(C, align(4096))]
32*40314b30SXiaoye Zheng #[derive(Debug)]
33*40314b30SXiaoye Zheng pub struct VmxonRegion {
34*40314b30SXiaoye Zheng     pub revision_id: u32,
35*40314b30SXiaoye Zheng     pub data: [u8; PAGE_SIZE - 4],
36*40314b30SXiaoye Zheng }
37*40314b30SXiaoye Zheng 
38*40314b30SXiaoye Zheng #[repr(C, align(4096))]
39*40314b30SXiaoye Zheng #[derive(Debug)]
40*40314b30SXiaoye Zheng pub struct MSRBitmap {
41*40314b30SXiaoye Zheng     pub data: [u8; PAGE_SIZE],
42*40314b30SXiaoye Zheng }
43*40314b30SXiaoye Zheng 
44*40314b30SXiaoye Zheng #[derive(Debug)]
45*40314b30SXiaoye Zheng pub struct VcpuData {
46*40314b30SXiaoye Zheng     /// The virtual and physical address of the Vmxon naturally aligned 4-KByte region of memory
47*40314b30SXiaoye Zheng     pub vmxon_region: Box<VmxonRegion>,
48*40314b30SXiaoye Zheng     pub vmxon_region_physical_address: u64, // vmxon需要该地址
49*40314b30SXiaoye Zheng     /// The virtual and physical address of the Vmcs naturally aligned 4-KByte region of memory
50*40314b30SXiaoye Zheng     /// holds the complete CPU state of both the host and the guest.
51*40314b30SXiaoye Zheng     /// includes the segment registers, GDT, IDT, TR, various MSR’s
52*40314b30SXiaoye Zheng     /// and control field structures for handling exit and entry operations
53*40314b30SXiaoye Zheng     pub vmcs_region: Box<VMCSRegion>,
54*40314b30SXiaoye Zheng     pub vmcs_region_physical_address: u64, // vmptrld, vmclear需要该地址
55*40314b30SXiaoye Zheng     pub msr_bitmap: Box<MSRBitmap>,
56*40314b30SXiaoye Zheng     pub msr_bitmap_physical_address: u64,
57*40314b30SXiaoye Zheng }
58*40314b30SXiaoye Zheng 
59*40314b30SXiaoye Zheng #[derive(Default, Debug)]
60*40314b30SXiaoye Zheng #[repr(C)]
61*40314b30SXiaoye Zheng pub struct VcpuContextFrame {
62*40314b30SXiaoye Zheng     pub regs: [usize; NR_VCPU_REGS], // 通用寄存器
63*40314b30SXiaoye Zheng     pub rip: usize,
64*40314b30SXiaoye Zheng     pub rflags: usize,
65*40314b30SXiaoye Zheng }
66*40314b30SXiaoye Zheng 
67*40314b30SXiaoye Zheng #[derive(Debug)]
68*40314b30SXiaoye Zheng #[allow(dead_code)]
69*40314b30SXiaoye Zheng pub enum VcpuState {
70*40314b30SXiaoye Zheng     VcpuInv = 0,
71*40314b30SXiaoye Zheng     VcpuPend = 1,
72*40314b30SXiaoye Zheng     VcpuAct = 2,
73*40314b30SXiaoye Zheng }
74*40314b30SXiaoye Zheng 
75*40314b30SXiaoye Zheng #[derive(Debug)]
76*40314b30SXiaoye Zheng pub struct VmxVcpu {
77*40314b30SXiaoye Zheng     pub vcpu_id: u32,
78*40314b30SXiaoye Zheng     pub vcpu_ctx: VcpuContextFrame, // 保存vcpu切换时的上下文,如通用寄存器等
79*40314b30SXiaoye Zheng     pub vcpu_state: VcpuState,      // vcpu当前运行状态
80*40314b30SXiaoye Zheng     pub mmu: KvmMmu,                // vcpu的内存管理单元
81*40314b30SXiaoye Zheng     pub data: VcpuData,             // vcpu的数据
82*40314b30SXiaoye Zheng     pub parent_vm: Vm,              // parent KVM
83*40314b30SXiaoye Zheng }
84*40314b30SXiaoye Zheng 
85*40314b30SXiaoye Zheng impl VcpuData {
86*40314b30SXiaoye Zheng     pub fn alloc() -> Result<Self, SystemError> {
87*40314b30SXiaoye Zheng         let vmxon_region: Box<VmxonRegion> = unsafe {
88*40314b30SXiaoye Zheng             Box::try_new_zeroed_in(Global)
89*40314b30SXiaoye Zheng                 .expect("Try new zeroed fail!")
90*40314b30SXiaoye Zheng                 .assume_init()
91*40314b30SXiaoye Zheng         };
92*40314b30SXiaoye Zheng         let vmcs_region: Box<VMCSRegion> = unsafe {
93*40314b30SXiaoye Zheng             Box::try_new_zeroed_in(Global)
94*40314b30SXiaoye Zheng                 .expect("Try new zeroed fail!")
95*40314b30SXiaoye Zheng                 .assume_init()
96*40314b30SXiaoye Zheng         };
97*40314b30SXiaoye Zheng         let msr_bitmap: Box<MSRBitmap> = unsafe {
98*40314b30SXiaoye Zheng             Box::try_new_zeroed_in(Global)
99*40314b30SXiaoye Zheng                 .expect("Try new zeroed fail!")
100*40314b30SXiaoye Zheng                 .assume_init()
101*40314b30SXiaoye Zheng         };
102*40314b30SXiaoye Zheng         // FIXME: virt_2_phys的转换正确性存疑
103*40314b30SXiaoye Zheng         let vmxon_region_physical_address = {
104*40314b30SXiaoye Zheng             let vaddr = VirtAddr::new(vmxon_region.as_ref() as *const _ as _);
105*40314b30SXiaoye Zheng             unsafe { MMArch::virt_2_phys(vaddr).unwrap().data() as u64 }
106*40314b30SXiaoye Zheng         };
107*40314b30SXiaoye Zheng         let vmcs_region_physical_address = {
108*40314b30SXiaoye Zheng             let vaddr = VirtAddr::new(vmcs_region.as_ref() as *const _ as _);
109*40314b30SXiaoye Zheng             unsafe { MMArch::virt_2_phys(vaddr).unwrap().data() as u64 }
110*40314b30SXiaoye Zheng         };
111*40314b30SXiaoye Zheng         let msr_bitmap_physical_address = {
112*40314b30SXiaoye Zheng             let vaddr = VirtAddr::new(msr_bitmap.as_ref() as *const _ as _);
113*40314b30SXiaoye Zheng             unsafe { MMArch::virt_2_phys(vaddr).unwrap().data() as u64 }
114*40314b30SXiaoye Zheng         };
115*40314b30SXiaoye Zheng 
116*40314b30SXiaoye Zheng         let mut instance = Self {
117*40314b30SXiaoye Zheng             // Allocate a naturally aligned 4-KByte VMXON region of memory to enable VMX operation (Intel Manual: 25.11.5 VMXON Region)
118*40314b30SXiaoye Zheng             vmxon_region,
119*40314b30SXiaoye Zheng             vmxon_region_physical_address,
120*40314b30SXiaoye Zheng             // Allocate a naturally aligned 4-KByte VMCS region of memory
121*40314b30SXiaoye Zheng             vmcs_region,
122*40314b30SXiaoye Zheng             vmcs_region_physical_address,
123*40314b30SXiaoye Zheng             msr_bitmap,
124*40314b30SXiaoye Zheng             msr_bitmap_physical_address,
125*40314b30SXiaoye Zheng         };
126*40314b30SXiaoye Zheng         // printk_color!(GREEN, BLACK, "[+] init_region\n");
127*40314b30SXiaoye Zheng         instance.init_region()?;
128*40314b30SXiaoye Zheng         Ok(instance)
129*40314b30SXiaoye Zheng     }
130*40314b30SXiaoye Zheng 
131*40314b30SXiaoye Zheng     pub fn init_region(&mut self) -> Result<(), SystemError> {
132*40314b30SXiaoye Zheng         // Get the Virtual Machine Control Structure revision identifier (VMCS revision ID)
133*40314b30SXiaoye Zheng         // (Intel Manual: 25.11.5 VMXON Region)
134*40314b30SXiaoye Zheng         let revision_id = unsafe { (msr::rdmsr(msr::IA32_VMX_BASIC) as u32) & 0x7FFF_FFFF };
135*40314b30SXiaoye Zheng         kdebug!("[+] VMXON Region Virtual Address: {:p}", self.vmxon_region);
136*40314b30SXiaoye Zheng         kdebug!(
137*40314b30SXiaoye Zheng             "[+] VMXON Region Physical Addresss: 0x{:x}",
138*40314b30SXiaoye Zheng             self.vmxon_region_physical_address
139*40314b30SXiaoye Zheng         );
140*40314b30SXiaoye Zheng         kdebug!("[+] VMCS Region Virtual Address: {:p}", self.vmcs_region);
141*40314b30SXiaoye Zheng         kdebug!(
142*40314b30SXiaoye Zheng             "[+] VMCS Region Physical Address1: 0x{:x}",
143*40314b30SXiaoye Zheng             self.vmcs_region_physical_address
144*40314b30SXiaoye Zheng         );
145*40314b30SXiaoye Zheng         self.vmxon_region.revision_id = revision_id;
146*40314b30SXiaoye Zheng         self.vmcs_region.revision_id = revision_id;
147*40314b30SXiaoye Zheng         return Ok(());
148*40314b30SXiaoye Zheng     }
149*40314b30SXiaoye Zheng }
150*40314b30SXiaoye Zheng 
151*40314b30SXiaoye Zheng impl VmxVcpu {
152*40314b30SXiaoye Zheng     pub fn new(vcpu_id: u32, parent_vm: Vm) -> Result<Self, SystemError> {
153*40314b30SXiaoye Zheng         kdebug!("Creating processor {}", vcpu_id);
154*40314b30SXiaoye Zheng         let instance = Self {
155*40314b30SXiaoye Zheng             vcpu_id,
156*40314b30SXiaoye Zheng             vcpu_ctx: VcpuContextFrame {
157*40314b30SXiaoye Zheng                 regs: [0; NR_VCPU_REGS],
158*40314b30SXiaoye Zheng                 rip: 0,
159*40314b30SXiaoye Zheng                 rflags: 0,
160*40314b30SXiaoye Zheng             },
161*40314b30SXiaoye Zheng             vcpu_state: VcpuState::VcpuInv,
162*40314b30SXiaoye Zheng             mmu: KvmMmu::default(),
163*40314b30SXiaoye Zheng             data: VcpuData::alloc()?,
164*40314b30SXiaoye Zheng             parent_vm,
165*40314b30SXiaoye Zheng         };
166*40314b30SXiaoye Zheng         Ok(instance)
167*40314b30SXiaoye Zheng     }
168*40314b30SXiaoye Zheng 
169*40314b30SXiaoye Zheng     pub fn vmx_set_cr0(cr0: X86_CR0) -> Result<(), SystemError> {
170*40314b30SXiaoye Zheng         let mut hw_cr0 = cr0 & !(X86_CR0::CR0_NW | X86_CR0::CR0_CD);
171*40314b30SXiaoye Zheng         hw_cr0 |= X86_CR0::CR0_WP | X86_CR0::CR0_NE;
172*40314b30SXiaoye Zheng 
173*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CR0 as u32, cr0.bits() as u64)?;
174*40314b30SXiaoye Zheng         Ok(())
175*40314b30SXiaoye Zheng     }
176*40314b30SXiaoye Zheng 
177*40314b30SXiaoye Zheng     pub fn vmcs_init_guest(&self) -> Result<(), SystemError> {
178*40314b30SXiaoye Zheng         // https://www.sandpile.org/x86/initial.htm
179*40314b30SXiaoye Zheng         // segment field initialization
180*40314b30SXiaoye Zheng         seg_setup(Sreg::CS as usize)?;
181*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CS_SELECTOR as u32, 0xf000)?;
182*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CS_BASE as u32, 0xffff0000)?;
183*40314b30SXiaoye Zheng 
184*40314b30SXiaoye Zheng         seg_setup(Sreg::DS as usize)?;
185*40314b30SXiaoye Zheng         seg_setup(Sreg::ES as usize)?;
186*40314b30SXiaoye Zheng         seg_setup(Sreg::FS as usize)?;
187*40314b30SXiaoye Zheng         seg_setup(Sreg::GS as usize)?;
188*40314b30SXiaoye Zheng         seg_setup(Sreg::SS as usize)?;
189*40314b30SXiaoye Zheng 
190*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_SELECTOR as u32, 0)?;
191*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_BASE as u32, 0)?;
192*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_LIMIT as u32, 0xffff)?;
193*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_ACCESS_RIGHTS as u32, 0x008b)?;
194*40314b30SXiaoye Zheng 
195*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_SELECTOR as u32, 0)?;
196*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_BASE as u32, 0)?;
197*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_LIMIT as u32, 0xffff)?;
198*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_ACCESS_RIGHTS as u32, 0x00082)?;
199*40314b30SXiaoye Zheng 
200*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_RFLAGS as u32, 2)?;
201*40314b30SXiaoye Zheng 
202*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_GDTR_BASE as u32, 0)?;
203*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_GDTR_LIMIT as u32, 0x0000_FFFF as u64)?;
204*40314b30SXiaoye Zheng 
205*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_IDTR_BASE as u32, 0)?;
206*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_IDTR_LIMIT as u32, 0x0000_FFFF as u64)?;
207*40314b30SXiaoye Zheng 
208*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_ACTIVITY_STATE as u32, 0)?; // State = Active
209*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_INTERRUPTIBILITY_STATE as u32, 0)?;
210*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_PENDING_DBG_EXCEPTIONS as u32, 0)?;
211*40314b30SXiaoye Zheng 
212*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_VM_ENTRY_INTR_INFO_FIELD as u32, 0)?;
213*40314b30SXiaoye Zheng 
214*40314b30SXiaoye Zheng         let cr0 = X86_CR0::CR0_NW | X86_CR0::CR0_CD | X86_CR0::CR0_ET;
215*40314b30SXiaoye Zheng         Self::vmx_set_cr0(cr0)?;
216*40314b30SXiaoye Zheng 
217*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CR0 as u32, cr0.bits() as u64)?;
218*40314b30SXiaoye Zheng 
219*40314b30SXiaoye Zheng         vmx_vmwrite(
220*40314b30SXiaoye Zheng             VmcsFields::GUEST_SYSENTER_CS as u32,
221*40314b30SXiaoye Zheng             vmx_vmread(VmcsFields::HOST_SYSENTER_CS as u32).unwrap(),
222*40314b30SXiaoye Zheng         )?;
223*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_VMX_PREEMPT_TIMER_VALUE as u32, 0)?;
224*40314b30SXiaoye Zheng 
225*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_INTR_STATUS as u32, 0)?;
226*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_PML_INDEX as u32, 0)?;
227*40314b30SXiaoye Zheng 
228*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_VMCS_LINK_PTR as u32, u64::MAX)?;
229*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_DEBUGCTL as u32, unsafe {
230*40314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_DEBUGCTL)
231*40314b30SXiaoye Zheng         })?;
232*40314b30SXiaoye Zheng 
233*40314b30SXiaoye Zheng         vmx_vmwrite(
234*40314b30SXiaoye Zheng             VmcsFields::GUEST_SYSENTER_ESP as u32,
235*40314b30SXiaoye Zheng             vmx_vmread(VmcsFields::HOST_SYSENTER_ESP as u32).unwrap(),
236*40314b30SXiaoye Zheng         )?;
237*40314b30SXiaoye Zheng         vmx_vmwrite(
238*40314b30SXiaoye Zheng             VmcsFields::GUEST_SYSENTER_EIP as u32,
239*40314b30SXiaoye Zheng             vmx_vmread(VmcsFields::HOST_SYSENTER_EIP as u32).unwrap(),
240*40314b30SXiaoye Zheng         )?;
241*40314b30SXiaoye Zheng 
242*40314b30SXiaoye Zheng         // Self::vmx_set_cr0();
243*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CR3 as u32, 0)?;
244*40314b30SXiaoye Zheng         vmx_vmwrite(
245*40314b30SXiaoye Zheng             VmcsFields::GUEST_CR4 as u32,
246*40314b30SXiaoye Zheng             1, // enable vme
247*40314b30SXiaoye Zheng         )?;
248*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_DR7 as u32, 0x0000_0000_0000_0400)?;
249*40314b30SXiaoye Zheng         vmx_vmwrite(
250*40314b30SXiaoye Zheng             VmcsFields::GUEST_RSP as u32,
251*40314b30SXiaoye Zheng             self.vcpu_ctx.regs[VcpuRegIndex::Rsp as usize] as u64,
252*40314b30SXiaoye Zheng         )?;
253*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_RIP as u32, self.vcpu_ctx.rip as u64)?;
254*40314b30SXiaoye Zheng         kdebug!("vmcs init guest rip: {:#x}", self.vcpu_ctx.rip as u64);
255*40314b30SXiaoye Zheng         kdebug!(
256*40314b30SXiaoye Zheng             "vmcs init guest rsp: {:#x}",
257*40314b30SXiaoye Zheng             self.vcpu_ctx.regs[VcpuRegIndex::Rsp as usize] as u64
258*40314b30SXiaoye Zheng         );
259*40314b30SXiaoye Zheng 
260*40314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::GUEST_RFLAGS as u32, x86::bits64::rflags::read().bits())?;
261*40314b30SXiaoye Zheng         Ok(())
262*40314b30SXiaoye Zheng     }
263*40314b30SXiaoye Zheng 
264*40314b30SXiaoye Zheng     #[allow(deprecated)]
265*40314b30SXiaoye Zheng     pub fn vmcs_init_host(&self) -> Result<(), SystemError> {
266*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_CR0 as u32, unsafe {
267*40314b30SXiaoye Zheng             controlregs::cr0().bits().try_into().unwrap()
268*40314b30SXiaoye Zheng         })?;
269*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_CR3 as u32, unsafe { controlregs::cr3() })?;
270*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_CR4 as u32, unsafe {
271*40314b30SXiaoye Zheng             controlregs::cr4().bits().try_into().unwrap()
272*40314b30SXiaoye Zheng         })?;
273*40314b30SXiaoye Zheng         vmx_vmwrite(
274*40314b30SXiaoye Zheng             VmcsFields::HOST_ES_SELECTOR as u32,
275*40314b30SXiaoye Zheng             (segmentation::es().bits() & (!0x07)).into(),
276*40314b30SXiaoye Zheng         )?;
277*40314b30SXiaoye Zheng         vmx_vmwrite(
278*40314b30SXiaoye Zheng             VmcsFields::HOST_CS_SELECTOR as u32,
279*40314b30SXiaoye Zheng             (segmentation::cs().bits() & (!0x07)).into(),
280*40314b30SXiaoye Zheng         )?;
281*40314b30SXiaoye Zheng         vmx_vmwrite(
282*40314b30SXiaoye Zheng             VmcsFields::HOST_SS_SELECTOR as u32,
283*40314b30SXiaoye Zheng             (segmentation::ss().bits() & (!0x07)).into(),
284*40314b30SXiaoye Zheng         )?;
285*40314b30SXiaoye Zheng         vmx_vmwrite(
286*40314b30SXiaoye Zheng             VmcsFields::HOST_DS_SELECTOR as u32,
287*40314b30SXiaoye Zheng             (segmentation::ds().bits() & (!0x07)).into(),
288*40314b30SXiaoye Zheng         )?;
289*40314b30SXiaoye Zheng         vmx_vmwrite(
290*40314b30SXiaoye Zheng             VmcsFields::HOST_FS_SELECTOR as u32,
291*40314b30SXiaoye Zheng             (segmentation::fs().bits() & (!0x07)).into(),
292*40314b30SXiaoye Zheng         )?;
293*40314b30SXiaoye Zheng         vmx_vmwrite(
294*40314b30SXiaoye Zheng             VmcsFields::HOST_GS_SELECTOR as u32,
295*40314b30SXiaoye Zheng             (segmentation::gs().bits() & (!0x07)).into(),
296*40314b30SXiaoye Zheng         )?;
297*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_TR_SELECTOR as u32, unsafe {
298*40314b30SXiaoye Zheng             (x86::task::tr().bits() & (!0x07)).into()
299*40314b30SXiaoye Zheng         })?;
300*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_FS_BASE as u32, unsafe {
301*40314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_FS_BASE)
302*40314b30SXiaoye Zheng         })?;
303*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_GS_BASE as u32, unsafe {
304*40314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_GS_BASE)
305*40314b30SXiaoye Zheng         })?;
306*40314b30SXiaoye Zheng 
307*40314b30SXiaoye Zheng         let mut pseudo_descriptpr: x86::dtables::DescriptorTablePointer<u64> = Default::default();
308*40314b30SXiaoye Zheng         unsafe {
309*40314b30SXiaoye Zheng             x86::dtables::sgdt(&mut pseudo_descriptpr);
310*40314b30SXiaoye Zheng         };
311*40314b30SXiaoye Zheng 
312*40314b30SXiaoye Zheng         vmx_vmwrite(
313*40314b30SXiaoye Zheng             VmcsFields::HOST_TR_BASE as u32,
314*40314b30SXiaoye Zheng             get_segment_base(pseudo_descriptpr.base, pseudo_descriptpr.limit, unsafe {
315*40314b30SXiaoye Zheng                 x86::task::tr().bits().into()
316*40314b30SXiaoye Zheng             }),
317*40314b30SXiaoye Zheng         )?;
318*40314b30SXiaoye Zheng         vmx_vmwrite(
319*40314b30SXiaoye Zheng             VmcsFields::HOST_GDTR_BASE as u32,
320*40314b30SXiaoye Zheng             pseudo_descriptpr.base.to_bits() as u64,
321*40314b30SXiaoye Zheng         )?;
322*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_IDTR_BASE as u32, unsafe {
323*40314b30SXiaoye Zheng             let mut pseudo_descriptpr: x86::dtables::DescriptorTablePointer<u64> =
324*40314b30SXiaoye Zheng                 Default::default();
325*40314b30SXiaoye Zheng             x86::dtables::sidt(&mut pseudo_descriptpr);
326*40314b30SXiaoye Zheng             pseudo_descriptpr.base.to_bits() as u64
327*40314b30SXiaoye Zheng         })?;
328*40314b30SXiaoye Zheng 
329*40314b30SXiaoye Zheng         // fast entry into the kernel
330*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_SYSENTER_ESP as u32, unsafe {
331*40314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_SYSENTER_ESP)
332*40314b30SXiaoye Zheng         })?;
333*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_SYSENTER_EIP as u32, unsafe {
334*40314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_SYSENTER_EIP)
335*40314b30SXiaoye Zheng         })?;
336*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_SYSENTER_CS as u32, unsafe {
337*40314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_SYSENTER_CS)
338*40314b30SXiaoye Zheng         })?;
339*40314b30SXiaoye Zheng 
340*40314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RIP as u32, vmx_return as *const () as u64)?;
341*40314b30SXiaoye Zheng         // kdebug!("vmcs init host rip: {:#x}", vmx_return as *const () as u64);
342*40314b30SXiaoye Zheng 
343*40314b30SXiaoye Zheng         Ok(())
344*40314b30SXiaoye Zheng     }
345*40314b30SXiaoye Zheng 
346*40314b30SXiaoye Zheng     // Intel SDM Volume 3C Chapter 25.3 “Organization of VMCS Data”
347*40314b30SXiaoye Zheng     pub fn vmcs_init(&self) -> Result<(), SystemError> {
348*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_PAGE_FAULT_ERR_CODE_MASK as u32, 0)?;
349*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_PAGE_FAULT_ERR_CODE_MATCH as u32, 0)?;
350*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_CR3_TARGET_COUNT as u32, 0)?;
351*40314b30SXiaoye Zheng 
352*40314b30SXiaoye Zheng         vmx_vmwrite(
353*40314b30SXiaoye Zheng             VmcsFields::CTRL_PIN_BASED_VM_EXEC_CTRLS as u32,
354*40314b30SXiaoye Zheng             adjust_vmx_pinbased_controls() as u64,
355*40314b30SXiaoye Zheng         )?;
356*40314b30SXiaoye Zheng 
357*40314b30SXiaoye Zheng         vmx_vmwrite(
358*40314b30SXiaoye Zheng             VmcsFields::CTRL_MSR_BITMAP_ADDR as u32,
359*40314b30SXiaoye Zheng             self.data.msr_bitmap_physical_address,
360*40314b30SXiaoye Zheng         )?;
361*40314b30SXiaoye Zheng 
362*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_CR0_READ_SHADOW as u32, unsafe {
363*40314b30SXiaoye Zheng             controlregs::cr0().bits().try_into().unwrap()
364*40314b30SXiaoye Zheng         })?;
365*40314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_CR4_READ_SHADOW as u32, unsafe {
366*40314b30SXiaoye Zheng             controlregs::cr4().bits().try_into().unwrap()
367*40314b30SXiaoye Zheng         })?;
368*40314b30SXiaoye Zheng         vmx_vmwrite(
369*40314b30SXiaoye Zheng             VmcsFields::CTRL_VM_ENTRY_CTRLS as u32,
370*40314b30SXiaoye Zheng             adjust_vmx_entry_controls() as u64,
371*40314b30SXiaoye Zheng         )?;
372*40314b30SXiaoye Zheng         vmx_vmwrite(
373*40314b30SXiaoye Zheng             VmcsFields::CTRL_PRIMARY_VM_EXIT_CTRLS as u32,
374*40314b30SXiaoye Zheng             adjust_vmx_exit_controls() as u64,
375*40314b30SXiaoye Zheng         )?;
376*40314b30SXiaoye Zheng         vmx_vmwrite(
377*40314b30SXiaoye Zheng             VmcsFields::CTRL_PRIMARY_PROCESSOR_VM_EXEC_CTRLS as u32,
378*40314b30SXiaoye Zheng             adjust_vmx_primary_process_exec_controls() as u64,
379*40314b30SXiaoye Zheng         )?;
380*40314b30SXiaoye Zheng         vmx_vmwrite(
381*40314b30SXiaoye Zheng             VmcsFields::CTRL_SECONDARY_PROCESSOR_VM_EXEC_CTRLS as u32,
382*40314b30SXiaoye Zheng             adjust_vmx_secondary_process_exec_controls() as u64,
383*40314b30SXiaoye Zheng         )?;
384*40314b30SXiaoye Zheng 
385*40314b30SXiaoye Zheng         self.vmcs_init_host()?;
386*40314b30SXiaoye Zheng         self.vmcs_init_guest()?;
387*40314b30SXiaoye Zheng         Ok(())
388*40314b30SXiaoye Zheng     }
389*40314b30SXiaoye Zheng 
390*40314b30SXiaoye Zheng     fn kvm_mmu_load(&mut self) -> Result<(), SystemError> {
391*40314b30SXiaoye Zheng         kdebug!("kvm_mmu_load!");
392*40314b30SXiaoye Zheng         // 申请并创建新的页表
393*40314b30SXiaoye Zheng         let mapper: crate::mm::page::PageMapper<X86_64MMArch, LockedFrameAllocator> = unsafe {
394*40314b30SXiaoye Zheng             PageMapper::create(PageTableKind::EPT, LockedFrameAllocator)
395*40314b30SXiaoye Zheng                 .ok_or(SystemError::ENOMEM)?
396*40314b30SXiaoye Zheng         };
397*40314b30SXiaoye Zheng 
398*40314b30SXiaoye Zheng         let ept_root_hpa = mapper.table().phys();
399*40314b30SXiaoye Zheng         let set_eptp_fn = self.mmu.set_eptp.unwrap();
400*40314b30SXiaoye Zheng         set_eptp_fn(ept_root_hpa.data() as u64)?;
401*40314b30SXiaoye Zheng         self.mmu.root_hpa = ept_root_hpa.data() as u64;
402*40314b30SXiaoye Zheng         kdebug!("ept_root_hpa:{:x}!", ept_root_hpa.data() as u64);
403*40314b30SXiaoye Zheng 
404*40314b30SXiaoye Zheng         return Ok(());
405*40314b30SXiaoye Zheng     }
406*40314b30SXiaoye Zheng 
407*40314b30SXiaoye Zheng     pub fn set_regs(&mut self, regs: VcpuContextFrame) -> Result<(), SystemError> {
408*40314b30SXiaoye Zheng         self.vcpu_ctx = regs;
409*40314b30SXiaoye Zheng         Ok(())
410*40314b30SXiaoye Zheng     }
411*40314b30SXiaoye Zheng }
412*40314b30SXiaoye Zheng 
413*40314b30SXiaoye Zheng impl Vcpu for VmxVcpu {
414*40314b30SXiaoye Zheng     /// Virtualize the CPU
415*40314b30SXiaoye Zheng     fn virtualize_cpu(&mut self) -> Result<(), SystemError> {
416*40314b30SXiaoye Zheng         match has_intel_vmx_support() {
417*40314b30SXiaoye Zheng             Ok(_) => {
418*40314b30SXiaoye Zheng                 kdebug!("[+] CPU supports Intel VMX");
419*40314b30SXiaoye Zheng             }
420*40314b30SXiaoye Zheng             Err(e) => {
421*40314b30SXiaoye Zheng                 kdebug!("[-] CPU does not support Intel VMX: {:?}", e);
422*40314b30SXiaoye Zheng                 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
423*40314b30SXiaoye Zheng             }
424*40314b30SXiaoye Zheng         };
425*40314b30SXiaoye Zheng 
426*40314b30SXiaoye Zheng         match enable_vmx_operation() {
427*40314b30SXiaoye Zheng             Ok(_) => {
428*40314b30SXiaoye Zheng                 kdebug!("[+] Enabling Virtual Machine Extensions (VMX)");
429*40314b30SXiaoye Zheng             }
430*40314b30SXiaoye Zheng             Err(_) => {
431*40314b30SXiaoye Zheng                 kdebug!("[-] VMX operation is not supported on this processor.");
432*40314b30SXiaoye Zheng                 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
433*40314b30SXiaoye Zheng             }
434*40314b30SXiaoye Zheng         }
435*40314b30SXiaoye Zheng 
436*40314b30SXiaoye Zheng         vmxon(self.data.vmxon_region_physical_address)?;
437*40314b30SXiaoye Zheng         kdebug!("[+] VMXON successful!");
438*40314b30SXiaoye Zheng         vmx_vmclear(self.data.vmcs_region_physical_address)?;
439*40314b30SXiaoye Zheng         vmx_vmptrld(self.data.vmcs_region_physical_address)?;
440*40314b30SXiaoye Zheng         kdebug!("[+] VMPTRLD successful!");
441*40314b30SXiaoye Zheng         self.vmcs_init().expect("vncs_init fail");
442*40314b30SXiaoye Zheng         kdebug!("[+] VMCS init!");
443*40314b30SXiaoye Zheng         // kdebug!("vmcs init host rip: {:#x}", vmx_return as *const () as u64);
444*40314b30SXiaoye Zheng         // kdebug!("vmcs init host rsp: {:#x}", x86::bits64::registers::rsp());
445*40314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RSP as u32, x86::bits64::registers::rsp())?;
446*40314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RIP as u32, vmx_return as *const () as u64)?;
447*40314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RSP as u32,  x86::bits64::registers::rsp())?;
448*40314b30SXiaoye Zheng         self.kvm_mmu_load()?;
449*40314b30SXiaoye Zheng         Ok(())
450*40314b30SXiaoye Zheng     }
451*40314b30SXiaoye Zheng 
452*40314b30SXiaoye Zheng     fn devirtualize_cpu(&self) -> Result<(), SystemError> {
453*40314b30SXiaoye Zheng         vmxoff()?;
454*40314b30SXiaoye Zheng         Ok(())
455*40314b30SXiaoye Zheng     }
456*40314b30SXiaoye Zheng 
457*40314b30SXiaoye Zheng     /// Gets the index of the current logical/virtual processor
458*40314b30SXiaoye Zheng     fn id(&self) -> u32 {
459*40314b30SXiaoye Zheng         self.vcpu_id
460*40314b30SXiaoye Zheng     }
461*40314b30SXiaoye Zheng }
462*40314b30SXiaoye Zheng 
463*40314b30SXiaoye Zheng pub fn get_segment_base(gdt_base: *const u64, gdt_size: u16, segment_selector: u16) -> u64 {
464*40314b30SXiaoye Zheng     let table = segment_selector & 0x0004; // get table indicator in selector
465*40314b30SXiaoye Zheng     let index = (segment_selector >> 3) as usize; // get index in selector
466*40314b30SXiaoye Zheng     if table == 0 && index == 0 {
467*40314b30SXiaoye Zheng         return 0;
468*40314b30SXiaoye Zheng     }
469*40314b30SXiaoye Zheng     let descriptor_table = unsafe { slice::from_raw_parts(gdt_base, gdt_size.into()) };
470*40314b30SXiaoye Zheng     let descriptor = descriptor_table[index];
471*40314b30SXiaoye Zheng 
472*40314b30SXiaoye Zheng     let base_high = (descriptor & 0xFF00_0000_0000_0000) >> 32;
473*40314b30SXiaoye Zheng     let base_mid = (descriptor & 0x0000_00FF_0000_0000) >> 16;
474*40314b30SXiaoye Zheng     let base_low = (descriptor & 0x0000_0000_FFFF_0000) >> 16;
475*40314b30SXiaoye Zheng     let segment_base = (base_high | base_mid | base_low) & 0xFFFFFFFF;
476*40314b30SXiaoye Zheng     let virtaddr = phys_2_virt(segment_base.try_into().unwrap())
477*40314b30SXiaoye Zheng         .try_into()
478*40314b30SXiaoye Zheng         .unwrap();
479*40314b30SXiaoye Zheng     kdebug!(
480*40314b30SXiaoye Zheng         "segment_base={:x}",
481*40314b30SXiaoye Zheng         phys_2_virt(segment_base.try_into().unwrap())
482*40314b30SXiaoye Zheng     );
483*40314b30SXiaoye Zheng     return virtaddr;
484*40314b30SXiaoye Zheng }
485*40314b30SXiaoye Zheng 
486*40314b30SXiaoye Zheng // FIXME: may have bug
487*40314b30SXiaoye Zheng // pub fn read_segment_access_rights(segement_selector: u16) -> u32{
488*40314b30SXiaoye Zheng //     let table = segement_selector & 0x0004; // get table indicator in selector
489*40314b30SXiaoye Zheng //     let index = segement_selector & 0xFFF8; // get index in selector
490*40314b30SXiaoye Zheng //     let mut flag: u16;
491*40314b30SXiaoye Zheng //     if table==0 && index==0 {
492*40314b30SXiaoye Zheng //         return 0;
493*40314b30SXiaoye Zheng //     }
494*40314b30SXiaoye Zheng //     unsafe{
495*40314b30SXiaoye Zheng //         asm!(
496*40314b30SXiaoye Zheng //             "lar {0:r}, rcx",
497*40314b30SXiaoye Zheng //             "mov {1:r}, {0:r}",
498*40314b30SXiaoye Zheng //             in(reg) segement_selector,
499*40314b30SXiaoye Zheng //             out(reg) flag,
500*40314b30SXiaoye Zheng //         );
501*40314b30SXiaoye Zheng //     }
502*40314b30SXiaoye Zheng //     return (flag >> 8) as u32;
503*40314b30SXiaoye Zheng // }
504*40314b30SXiaoye Zheng pub fn adjust_vmx_controls(ctl_min: u32, ctl_opt: u32, msr: u32, result: &mut u32) {
505*40314b30SXiaoye Zheng     let vmx_msr_low: u32 = unsafe { (msr::rdmsr(msr) & 0x0000_0000_FFFF_FFFF) as u32 };
506*40314b30SXiaoye Zheng     let vmx_msr_high: u32 = unsafe { (msr::rdmsr(msr) << 32) as u32 };
507*40314b30SXiaoye Zheng     let mut ctl: u32 = ctl_min | ctl_opt;
508*40314b30SXiaoye Zheng     ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */
509*40314b30SXiaoye Zheng     ctl |= vmx_msr_low; /* bit == 1 in low word  ==> must be one  */
510*40314b30SXiaoye Zheng     *result = ctl;
511*40314b30SXiaoye Zheng }
512*40314b30SXiaoye Zheng 
513*40314b30SXiaoye Zheng pub fn adjust_vmx_entry_controls() -> u32 {
514*40314b30SXiaoye Zheng     let mut entry_controls: u32 = 0;
515*40314b30SXiaoye Zheng     adjust_vmx_controls(
516*40314b30SXiaoye Zheng         VmxEntryCtrl::LOAD_DBG_CTRLS.bits(),
517*40314b30SXiaoye Zheng         VmxEntryCtrl::IA32E_MODE_GUEST.bits(),
518*40314b30SXiaoye Zheng         msr::IA32_VMX_ENTRY_CTLS, //Capability Reporting Register of VM-entry Controls (R/O)
519*40314b30SXiaoye Zheng         &mut entry_controls,
520*40314b30SXiaoye Zheng     );
521*40314b30SXiaoye Zheng     return entry_controls;
522*40314b30SXiaoye Zheng     // msr::IA32_VMX_TRUE_ENTRY_CTLS//Capability Reporting Register of VM-entry Flex Controls (R/O) See Table 35-2
523*40314b30SXiaoye Zheng }
524*40314b30SXiaoye Zheng 
525*40314b30SXiaoye Zheng pub fn adjust_vmx_exit_controls() -> u32 {
526*40314b30SXiaoye Zheng     let mut exit_controls: u32 = 0;
527*40314b30SXiaoye Zheng     adjust_vmx_controls(
528*40314b30SXiaoye Zheng         VmxPrimaryExitCtrl::SAVE_DBG_CTRLS.bits(),
529*40314b30SXiaoye Zheng         VmxPrimaryExitCtrl::HOST_ADDR_SPACE_SIZE.bits(),
530*40314b30SXiaoye Zheng         msr::IA32_VMX_EXIT_CTLS,
531*40314b30SXiaoye Zheng         &mut exit_controls,
532*40314b30SXiaoye Zheng     );
533*40314b30SXiaoye Zheng     return exit_controls;
534*40314b30SXiaoye Zheng }
535*40314b30SXiaoye Zheng 
536*40314b30SXiaoye Zheng pub fn adjust_vmx_pinbased_controls() -> u32 {
537*40314b30SXiaoye Zheng     let mut controls: u32 = 0000_0016;
538*40314b30SXiaoye Zheng     adjust_vmx_controls(0, 0, msr::IA32_VMX_TRUE_PINBASED_CTLS, &mut controls);
539*40314b30SXiaoye Zheng     // kdebug!("adjust_vmx_pinbased_controls: {:x}", controls);
540*40314b30SXiaoye Zheng     return controls;
541*40314b30SXiaoye Zheng }
542*40314b30SXiaoye Zheng 
543*40314b30SXiaoye Zheng pub fn adjust_vmx_primary_process_exec_controls() -> u32 {
544*40314b30SXiaoye Zheng     let mut controls: u32 = 0;
545*40314b30SXiaoye Zheng     adjust_vmx_controls(
546*40314b30SXiaoye Zheng         0,
547*40314b30SXiaoye Zheng         VmxPrimaryProcessBasedExecuteCtrl::USE_MSR_BITMAPS.bits()
548*40314b30SXiaoye Zheng             | VmxPrimaryProcessBasedExecuteCtrl::ACTIVATE_SECONDARY_CONTROLS.bits(),
549*40314b30SXiaoye Zheng         msr::IA32_VMX_PROCBASED_CTLS,
550*40314b30SXiaoye Zheng         &mut controls,
551*40314b30SXiaoye Zheng     );
552*40314b30SXiaoye Zheng     return controls;
553*40314b30SXiaoye Zheng }
554*40314b30SXiaoye Zheng 
555*40314b30SXiaoye Zheng pub fn adjust_vmx_secondary_process_exec_controls() -> u32 {
556*40314b30SXiaoye Zheng     let mut controls: u32 = 0;
557*40314b30SXiaoye Zheng     adjust_vmx_controls(
558*40314b30SXiaoye Zheng         0,
559*40314b30SXiaoye Zheng         VmxSecondaryProcessBasedExecuteCtrl::ENABLE_RDTSCP.bits()
560*40314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::ENABLE_XSAVES_XRSTORS.bits()
561*40314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::ENABLE_INVPCID.bits()
562*40314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::ENABLE_EPT.bits()
563*40314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::UNRESTRICTED_GUEST.bits(),
564*40314b30SXiaoye Zheng         msr::IA32_VMX_PROCBASED_CTLS2,
565*40314b30SXiaoye Zheng         &mut controls,
566*40314b30SXiaoye Zheng     );
567*40314b30SXiaoye Zheng     return controls;
568*40314b30SXiaoye Zheng }
569*40314b30SXiaoye Zheng 
570*40314b30SXiaoye Zheng /// Check to see if CPU is Intel (“GenuineIntel”).
571*40314b30SXiaoye Zheng /// Check processor supports for Virtual Machine Extension (VMX) technology
572*40314b30SXiaoye Zheng //  CPUID.1:ECX.VMX[bit 5] = 1 (Intel Manual: 24.6 Discovering Support for VMX)
573*40314b30SXiaoye Zheng pub fn has_intel_vmx_support() -> Result<(), SystemError> {
574*40314b30SXiaoye Zheng     let cpuid = CpuId::new();
575*40314b30SXiaoye Zheng     if let Some(vi) = cpuid.get_vendor_info() {
576*40314b30SXiaoye Zheng         if vi.as_str() != "GenuineIntel" {
577*40314b30SXiaoye Zheng             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
578*40314b30SXiaoye Zheng         }
579*40314b30SXiaoye Zheng     }
580*40314b30SXiaoye Zheng     if let Some(fi) = cpuid.get_feature_info() {
581*40314b30SXiaoye Zheng         if !fi.has_vmx() {
582*40314b30SXiaoye Zheng             return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
583*40314b30SXiaoye Zheng         }
584*40314b30SXiaoye Zheng     }
585*40314b30SXiaoye Zheng     Ok(())
586*40314b30SXiaoye Zheng }
587*40314b30SXiaoye Zheng 
588*40314b30SXiaoye Zheng /// Enables Virtual Machine Extensions
589*40314b30SXiaoye Zheng // - CR4.VMXE[bit 13] = 1 (Intel Manual: 24.7 Enabling and Entering VMX Operation)
590*40314b30SXiaoye Zheng pub fn enable_vmx_operation() -> Result<(), SystemError> {
591*40314b30SXiaoye Zheng     let mut cr4 = unsafe { controlregs::cr4() };
592*40314b30SXiaoye Zheng     cr4.set(controlregs::Cr4::CR4_ENABLE_VMX, true);
593*40314b30SXiaoye Zheng     unsafe { controlregs::cr4_write(cr4) };
594*40314b30SXiaoye Zheng 
595*40314b30SXiaoye Zheng     set_lock_bit()?;
596*40314b30SXiaoye Zheng     kdebug!("[+] Lock bit set via IA32_FEATURE_CONTROL");
597*40314b30SXiaoye Zheng     set_cr0_bits();
598*40314b30SXiaoye Zheng     kdebug!("[+] Mandatory bits in CR0 set/cleared");
599*40314b30SXiaoye Zheng     set_cr4_bits();
600*40314b30SXiaoye Zheng     kdebug!("[+] Mandatory bits in CR4 set/cleared");
601*40314b30SXiaoye Zheng 
602*40314b30SXiaoye Zheng     Ok(())
603*40314b30SXiaoye Zheng }
604*40314b30SXiaoye Zheng 
605*40314b30SXiaoye Zheng /// Check if we need to set bits in IA32_FEATURE_CONTROL
606*40314b30SXiaoye Zheng // (Intel Manual: 24.7 Enabling and Entering VMX Operation)
607*40314b30SXiaoye Zheng fn set_lock_bit() -> Result<(), SystemError> {
608*40314b30SXiaoye Zheng     const VMX_LOCK_BIT: u64 = 1 << 0;
609*40314b30SXiaoye Zheng     const VMXON_OUTSIDE_SMX: u64 = 1 << 2;
610*40314b30SXiaoye Zheng 
611*40314b30SXiaoye Zheng     let ia32_feature_control = unsafe { msr::rdmsr(msr::IA32_FEATURE_CONTROL) };
612*40314b30SXiaoye Zheng 
613*40314b30SXiaoye Zheng     if (ia32_feature_control & VMX_LOCK_BIT) == 0 {
614*40314b30SXiaoye Zheng         unsafe {
615*40314b30SXiaoye Zheng             msr::wrmsr(
616*40314b30SXiaoye Zheng                 msr::IA32_FEATURE_CONTROL,
617*40314b30SXiaoye Zheng                 VMXON_OUTSIDE_SMX | VMX_LOCK_BIT | ia32_feature_control,
618*40314b30SXiaoye Zheng             )
619*40314b30SXiaoye Zheng         };
620*40314b30SXiaoye Zheng     } else if (ia32_feature_control & VMXON_OUTSIDE_SMX) == 0 {
621*40314b30SXiaoye Zheng         return Err(SystemError::EPERM);
622*40314b30SXiaoye Zheng     }
623*40314b30SXiaoye Zheng 
624*40314b30SXiaoye Zheng     Ok(())
625*40314b30SXiaoye Zheng }
626*40314b30SXiaoye Zheng 
627*40314b30SXiaoye Zheng /// Set the mandatory bits in CR0 and clear bits that are mandatory zero
628*40314b30SXiaoye Zheng /// (Intel Manual: 24.8 Restrictions on VMX Operation)
629*40314b30SXiaoye Zheng fn set_cr0_bits() {
630*40314b30SXiaoye Zheng     let ia32_vmx_cr0_fixed0 = unsafe { msr::rdmsr(msr::IA32_VMX_CR0_FIXED0) };
631*40314b30SXiaoye Zheng     let ia32_vmx_cr0_fixed1 = unsafe { msr::rdmsr(msr::IA32_VMX_CR0_FIXED1) };
632*40314b30SXiaoye Zheng 
633*40314b30SXiaoye Zheng     let mut cr0 = unsafe { controlregs::cr0() };
634*40314b30SXiaoye Zheng 
635*40314b30SXiaoye Zheng     cr0 |= controlregs::Cr0::from_bits_truncate(ia32_vmx_cr0_fixed0 as usize);
636*40314b30SXiaoye Zheng     cr0 &= controlregs::Cr0::from_bits_truncate(ia32_vmx_cr0_fixed1 as usize);
637*40314b30SXiaoye Zheng 
638*40314b30SXiaoye Zheng     unsafe { controlregs::cr0_write(cr0) };
639*40314b30SXiaoye Zheng }
640*40314b30SXiaoye Zheng 
641*40314b30SXiaoye Zheng /// Set the mandatory bits in CR4 and clear bits that are mandatory zero
642*40314b30SXiaoye Zheng /// (Intel Manual: 24.8 Restrictions on VMX Operation)
643*40314b30SXiaoye Zheng fn set_cr4_bits() {
644*40314b30SXiaoye Zheng     let ia32_vmx_cr4_fixed0 = unsafe { msr::rdmsr(msr::IA32_VMX_CR4_FIXED0) };
645*40314b30SXiaoye Zheng     let ia32_vmx_cr4_fixed1 = unsafe { msr::rdmsr(msr::IA32_VMX_CR4_FIXED1) };
646*40314b30SXiaoye Zheng 
647*40314b30SXiaoye Zheng     let mut cr4 = unsafe { controlregs::cr4() };
648*40314b30SXiaoye Zheng 
649*40314b30SXiaoye Zheng     cr4 |= controlregs::Cr4::from_bits_truncate(ia32_vmx_cr4_fixed0 as usize);
650*40314b30SXiaoye Zheng     cr4 &= controlregs::Cr4::from_bits_truncate(ia32_vmx_cr4_fixed1 as usize);
651*40314b30SXiaoye Zheng 
652*40314b30SXiaoye Zheng     unsafe { controlregs::cr4_write(cr4) };
653*40314b30SXiaoye Zheng }
654