xref: /DragonOS/kernel/src/arch/x86_64/kvm/vmx/vcpu.rs (revision 1074eb34e784aa2adfc5b9e0d89fa4b7e6ea03ef)
140314b30SXiaoye Zheng use super::vmcs::{
240314b30SXiaoye Zheng     VMCSRegion, VmcsFields, VmxEntryCtrl, VmxPrimaryExitCtrl, VmxPrimaryProcessBasedExecuteCtrl,
340314b30SXiaoye Zheng     VmxSecondaryProcessBasedExecuteCtrl,
440314b30SXiaoye Zheng };
540314b30SXiaoye Zheng use super::vmx_asm_wrapper::{vmx_vmclear, vmx_vmptrld, vmx_vmread, vmx_vmwrite, vmxoff, vmxon};
640314b30SXiaoye Zheng use crate::arch::kvm::vmx::mmu::KvmMmu;
740314b30SXiaoye Zheng use crate::arch::kvm::vmx::seg::{seg_setup, Sreg};
840314b30SXiaoye Zheng use crate::arch::kvm::vmx::{VcpuRegIndex, X86_CR0};
940314b30SXiaoye Zheng use crate::arch::mm::{LockedFrameAllocator, PageMapper};
1040314b30SXiaoye Zheng use crate::arch::x86_64::mm::X86_64MMArch;
1140314b30SXiaoye Zheng use crate::arch::MMArch;
1240314b30SXiaoye Zheng use crate::kdebug;
1340314b30SXiaoye Zheng use crate::mm::{phys_2_virt, VirtAddr};
1440314b30SXiaoye Zheng use crate::mm::{MemoryManagementArch, PageTableKind};
1540314b30SXiaoye Zheng use crate::virt::kvm::vcpu::Vcpu;
1640314b30SXiaoye Zheng use crate::virt::kvm::vm::Vm;
1740314b30SXiaoye Zheng use alloc::alloc::Global;
1840314b30SXiaoye Zheng use alloc::boxed::Box;
1940314b30SXiaoye Zheng use core::slice;
2040314b30SXiaoye Zheng use raw_cpuid::CpuId;
2191e9d4abSLoGin use system_error::SystemError;
2240314b30SXiaoye Zheng use x86;
2340314b30SXiaoye Zheng use x86::{controlregs, msr, segmentation};
2440314b30SXiaoye Zheng // use crate::arch::kvm::vmx::seg::RMODE_TSS_SIZE;
2540314b30SXiaoye Zheng // use crate::virt::kvm::{KVM};
2640314b30SXiaoye Zheng 
2740314b30SXiaoye Zheng // KERNEL_ALLOCATOR
2840314b30SXiaoye Zheng pub const PAGE_SIZE: usize = 0x1000;
2940314b30SXiaoye Zheng pub const NR_VCPU_REGS: usize = 16;
3040314b30SXiaoye Zheng 
3140314b30SXiaoye Zheng #[repr(C, align(4096))]
3240314b30SXiaoye Zheng #[derive(Debug)]
3340314b30SXiaoye Zheng pub struct VmxonRegion {
3440314b30SXiaoye Zheng     pub revision_id: u32,
3540314b30SXiaoye Zheng     pub data: [u8; PAGE_SIZE - 4],
3640314b30SXiaoye Zheng }
3740314b30SXiaoye Zheng 
3840314b30SXiaoye Zheng #[repr(C, align(4096))]
3940314b30SXiaoye Zheng #[derive(Debug)]
4040314b30SXiaoye Zheng pub struct MSRBitmap {
4140314b30SXiaoye Zheng     pub data: [u8; PAGE_SIZE],
4240314b30SXiaoye Zheng }
4340314b30SXiaoye Zheng 
4440314b30SXiaoye Zheng #[derive(Debug)]
4540314b30SXiaoye Zheng pub struct VcpuData {
4640314b30SXiaoye Zheng     /// The virtual and physical address of the Vmxon naturally aligned 4-KByte region of memory
4740314b30SXiaoye Zheng     pub vmxon_region: Box<VmxonRegion>,
4840314b30SXiaoye Zheng     pub vmxon_region_physical_address: u64, // vmxon需要该地址
4940314b30SXiaoye Zheng     /// The virtual and physical address of the Vmcs naturally aligned 4-KByte region of memory
5040314b30SXiaoye Zheng     /// holds the complete CPU state of both the host and the guest.
5140314b30SXiaoye Zheng     /// includes the segment registers, GDT, IDT, TR, various MSR’s
5240314b30SXiaoye Zheng     /// and control field structures for handling exit and entry operations
5340314b30SXiaoye Zheng     pub vmcs_region: Box<VMCSRegion>,
5440314b30SXiaoye Zheng     pub vmcs_region_physical_address: u64, // vmptrld, vmclear需要该地址
5540314b30SXiaoye Zheng     pub msr_bitmap: Box<MSRBitmap>,
5640314b30SXiaoye Zheng     pub msr_bitmap_physical_address: u64,
5740314b30SXiaoye Zheng }
5840314b30SXiaoye Zheng 
5940314b30SXiaoye Zheng #[derive(Default, Debug)]
6040314b30SXiaoye Zheng #[repr(C)]
6140314b30SXiaoye Zheng pub struct VcpuContextFrame {
6240314b30SXiaoye Zheng     pub regs: [usize; NR_VCPU_REGS], // 通用寄存器
6340314b30SXiaoye Zheng     pub rip: usize,
6440314b30SXiaoye Zheng     pub rflags: usize,
6540314b30SXiaoye Zheng }
6640314b30SXiaoye Zheng 
6740314b30SXiaoye Zheng #[derive(Debug)]
6840314b30SXiaoye Zheng #[allow(dead_code)]
6940314b30SXiaoye Zheng pub enum VcpuState {
70b5b571e0SLoGin     Inv = 0,
71b5b571e0SLoGin     Pend = 1,
72b5b571e0SLoGin     Act = 2,
7340314b30SXiaoye Zheng }
7440314b30SXiaoye Zheng 
7540314b30SXiaoye Zheng #[derive(Debug)]
7640314b30SXiaoye Zheng pub struct VmxVcpu {
7740314b30SXiaoye Zheng     pub vcpu_id: u32,
7840314b30SXiaoye Zheng     pub vcpu_ctx: VcpuContextFrame, // 保存vcpu切换时的上下文,如通用寄存器等
7940314b30SXiaoye Zheng     pub vcpu_state: VcpuState,      // vcpu当前运行状态
8040314b30SXiaoye Zheng     pub mmu: KvmMmu,                // vcpu的内存管理单元
8140314b30SXiaoye Zheng     pub data: VcpuData,             // vcpu的数据
8240314b30SXiaoye Zheng     pub parent_vm: Vm,              // parent KVM
8340314b30SXiaoye Zheng }
8440314b30SXiaoye Zheng 
8540314b30SXiaoye Zheng impl VcpuData {
8640314b30SXiaoye Zheng     pub fn alloc() -> Result<Self, SystemError> {
8740314b30SXiaoye Zheng         let vmxon_region: Box<VmxonRegion> = unsafe {
8840314b30SXiaoye Zheng             Box::try_new_zeroed_in(Global)
8940314b30SXiaoye Zheng                 .expect("Try new zeroed fail!")
9040314b30SXiaoye Zheng                 .assume_init()
9140314b30SXiaoye Zheng         };
9240314b30SXiaoye Zheng         let vmcs_region: Box<VMCSRegion> = unsafe {
9340314b30SXiaoye Zheng             Box::try_new_zeroed_in(Global)
9440314b30SXiaoye Zheng                 .expect("Try new zeroed fail!")
9540314b30SXiaoye Zheng                 .assume_init()
9640314b30SXiaoye Zheng         };
9740314b30SXiaoye Zheng         let msr_bitmap: Box<MSRBitmap> = unsafe {
9840314b30SXiaoye Zheng             Box::try_new_zeroed_in(Global)
9940314b30SXiaoye Zheng                 .expect("Try new zeroed fail!")
10040314b30SXiaoye Zheng                 .assume_init()
10140314b30SXiaoye Zheng         };
10240314b30SXiaoye Zheng         // FIXME: virt_2_phys的转换正确性存疑
10340314b30SXiaoye Zheng         let vmxon_region_physical_address = {
10440314b30SXiaoye Zheng             let vaddr = VirtAddr::new(vmxon_region.as_ref() as *const _ as _);
10540314b30SXiaoye Zheng             unsafe { MMArch::virt_2_phys(vaddr).unwrap().data() as u64 }
10640314b30SXiaoye Zheng         };
10740314b30SXiaoye Zheng         let vmcs_region_physical_address = {
10840314b30SXiaoye Zheng             let vaddr = VirtAddr::new(vmcs_region.as_ref() as *const _ as _);
10940314b30SXiaoye Zheng             unsafe { MMArch::virt_2_phys(vaddr).unwrap().data() as u64 }
11040314b30SXiaoye Zheng         };
11140314b30SXiaoye Zheng         let msr_bitmap_physical_address = {
11240314b30SXiaoye Zheng             let vaddr = VirtAddr::new(msr_bitmap.as_ref() as *const _ as _);
11340314b30SXiaoye Zheng             unsafe { MMArch::virt_2_phys(vaddr).unwrap().data() as u64 }
11440314b30SXiaoye Zheng         };
11540314b30SXiaoye Zheng 
11640314b30SXiaoye Zheng         let mut instance = Self {
11740314b30SXiaoye Zheng             // Allocate a naturally aligned 4-KByte VMXON region of memory to enable VMX operation (Intel Manual: 25.11.5 VMXON Region)
11840314b30SXiaoye Zheng             vmxon_region,
11940314b30SXiaoye Zheng             vmxon_region_physical_address,
12040314b30SXiaoye Zheng             // Allocate a naturally aligned 4-KByte VMCS region of memory
12140314b30SXiaoye Zheng             vmcs_region,
12240314b30SXiaoye Zheng             vmcs_region_physical_address,
12340314b30SXiaoye Zheng             msr_bitmap,
12440314b30SXiaoye Zheng             msr_bitmap_physical_address,
12540314b30SXiaoye Zheng         };
12640314b30SXiaoye Zheng         // printk_color!(GREEN, BLACK, "[+] init_region\n");
12740314b30SXiaoye Zheng         instance.init_region()?;
12840314b30SXiaoye Zheng         Ok(instance)
12940314b30SXiaoye Zheng     }
13040314b30SXiaoye Zheng 
13140314b30SXiaoye Zheng     pub fn init_region(&mut self) -> Result<(), SystemError> {
13240314b30SXiaoye Zheng         // Get the Virtual Machine Control Structure revision identifier (VMCS revision ID)
13340314b30SXiaoye Zheng         // (Intel Manual: 25.11.5 VMXON Region)
13440314b30SXiaoye Zheng         let revision_id = unsafe { (msr::rdmsr(msr::IA32_VMX_BASIC) as u32) & 0x7FFF_FFFF };
13540314b30SXiaoye Zheng         kdebug!("[+] VMXON Region Virtual Address: {:p}", self.vmxon_region);
13640314b30SXiaoye Zheng         kdebug!(
13740314b30SXiaoye Zheng             "[+] VMXON Region Physical Addresss: 0x{:x}",
13840314b30SXiaoye Zheng             self.vmxon_region_physical_address
13940314b30SXiaoye Zheng         );
14040314b30SXiaoye Zheng         kdebug!("[+] VMCS Region Virtual Address: {:p}", self.vmcs_region);
14140314b30SXiaoye Zheng         kdebug!(
14240314b30SXiaoye Zheng             "[+] VMCS Region Physical Address1: 0x{:x}",
14340314b30SXiaoye Zheng             self.vmcs_region_physical_address
14440314b30SXiaoye Zheng         );
14540314b30SXiaoye Zheng         self.vmxon_region.revision_id = revision_id;
14640314b30SXiaoye Zheng         self.vmcs_region.revision_id = revision_id;
14740314b30SXiaoye Zheng         return Ok(());
14840314b30SXiaoye Zheng     }
14940314b30SXiaoye Zheng }
15040314b30SXiaoye Zheng 
15140314b30SXiaoye Zheng impl VmxVcpu {
15240314b30SXiaoye Zheng     pub fn new(vcpu_id: u32, parent_vm: Vm) -> Result<Self, SystemError> {
15340314b30SXiaoye Zheng         kdebug!("Creating processor {}", vcpu_id);
15440314b30SXiaoye Zheng         let instance = Self {
15540314b30SXiaoye Zheng             vcpu_id,
15640314b30SXiaoye Zheng             vcpu_ctx: VcpuContextFrame {
15740314b30SXiaoye Zheng                 regs: [0; NR_VCPU_REGS],
15840314b30SXiaoye Zheng                 rip: 0,
15940314b30SXiaoye Zheng                 rflags: 0,
16040314b30SXiaoye Zheng             },
161b5b571e0SLoGin             vcpu_state: VcpuState::Inv,
16240314b30SXiaoye Zheng             mmu: KvmMmu::default(),
16340314b30SXiaoye Zheng             data: VcpuData::alloc()?,
16440314b30SXiaoye Zheng             parent_vm,
16540314b30SXiaoye Zheng         };
16640314b30SXiaoye Zheng         Ok(instance)
16740314b30SXiaoye Zheng     }
16840314b30SXiaoye Zheng 
16940314b30SXiaoye Zheng     pub fn vmx_set_cr0(cr0: X86_CR0) -> Result<(), SystemError> {
17040314b30SXiaoye Zheng         let mut hw_cr0 = cr0 & !(X86_CR0::CR0_NW | X86_CR0::CR0_CD);
17140314b30SXiaoye Zheng         hw_cr0 |= X86_CR0::CR0_WP | X86_CR0::CR0_NE;
17240314b30SXiaoye Zheng 
17340314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CR0 as u32, cr0.bits() as u64)?;
17440314b30SXiaoye Zheng         Ok(())
17540314b30SXiaoye Zheng     }
17640314b30SXiaoye Zheng 
17740314b30SXiaoye Zheng     pub fn vmcs_init_guest(&self) -> Result<(), SystemError> {
17840314b30SXiaoye Zheng         // https://www.sandpile.org/x86/initial.htm
17940314b30SXiaoye Zheng         // segment field initialization
18040314b30SXiaoye Zheng         seg_setup(Sreg::CS as usize)?;
18140314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CS_SELECTOR as u32, 0xf000)?;
18240314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CS_BASE as u32, 0xffff0000)?;
18340314b30SXiaoye Zheng 
18440314b30SXiaoye Zheng         seg_setup(Sreg::DS as usize)?;
18540314b30SXiaoye Zheng         seg_setup(Sreg::ES as usize)?;
18640314b30SXiaoye Zheng         seg_setup(Sreg::FS as usize)?;
18740314b30SXiaoye Zheng         seg_setup(Sreg::GS as usize)?;
18840314b30SXiaoye Zheng         seg_setup(Sreg::SS as usize)?;
18940314b30SXiaoye Zheng 
19040314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_SELECTOR as u32, 0)?;
19140314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_BASE as u32, 0)?;
19240314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_LIMIT as u32, 0xffff)?;
19340314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_TR_ACCESS_RIGHTS as u32, 0x008b)?;
19440314b30SXiaoye Zheng 
19540314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_SELECTOR as u32, 0)?;
19640314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_BASE as u32, 0)?;
19740314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_LIMIT as u32, 0xffff)?;
19840314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_LDTR_ACCESS_RIGHTS as u32, 0x00082)?;
19940314b30SXiaoye Zheng 
20040314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_RFLAGS as u32, 2)?;
20140314b30SXiaoye Zheng 
20240314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_GDTR_BASE as u32, 0)?;
203b5b571e0SLoGin         vmx_vmwrite(VmcsFields::GUEST_GDTR_LIMIT as u32, 0x0000_FFFF_u64)?;
20440314b30SXiaoye Zheng 
20540314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_IDTR_BASE as u32, 0)?;
206b5b571e0SLoGin         vmx_vmwrite(VmcsFields::GUEST_IDTR_LIMIT as u32, 0x0000_FFFF_u64)?;
20740314b30SXiaoye Zheng 
20840314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_ACTIVITY_STATE as u32, 0)?; // State = Active
20940314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_INTERRUPTIBILITY_STATE as u32, 0)?;
21040314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_PENDING_DBG_EXCEPTIONS as u32, 0)?;
21140314b30SXiaoye Zheng 
21240314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_VM_ENTRY_INTR_INFO_FIELD as u32, 0)?;
21340314b30SXiaoye Zheng 
21440314b30SXiaoye Zheng         let cr0 = X86_CR0::CR0_NW | X86_CR0::CR0_CD | X86_CR0::CR0_ET;
21540314b30SXiaoye Zheng         Self::vmx_set_cr0(cr0)?;
21640314b30SXiaoye Zheng 
21740314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CR0 as u32, cr0.bits() as u64)?;
21840314b30SXiaoye Zheng 
21940314b30SXiaoye Zheng         vmx_vmwrite(
22040314b30SXiaoye Zheng             VmcsFields::GUEST_SYSENTER_CS as u32,
22140314b30SXiaoye Zheng             vmx_vmread(VmcsFields::HOST_SYSENTER_CS as u32).unwrap(),
22240314b30SXiaoye Zheng         )?;
22340314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_VMX_PREEMPT_TIMER_VALUE as u32, 0)?;
22440314b30SXiaoye Zheng 
22540314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_INTR_STATUS as u32, 0)?;
22640314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_PML_INDEX as u32, 0)?;
22740314b30SXiaoye Zheng 
22840314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_VMCS_LINK_PTR as u32, u64::MAX)?;
22940314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_DEBUGCTL as u32, unsafe {
23040314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_DEBUGCTL)
23140314b30SXiaoye Zheng         })?;
23240314b30SXiaoye Zheng 
23340314b30SXiaoye Zheng         vmx_vmwrite(
23440314b30SXiaoye Zheng             VmcsFields::GUEST_SYSENTER_ESP as u32,
23540314b30SXiaoye Zheng             vmx_vmread(VmcsFields::HOST_SYSENTER_ESP as u32).unwrap(),
23640314b30SXiaoye Zheng         )?;
23740314b30SXiaoye Zheng         vmx_vmwrite(
23840314b30SXiaoye Zheng             VmcsFields::GUEST_SYSENTER_EIP as u32,
23940314b30SXiaoye Zheng             vmx_vmread(VmcsFields::HOST_SYSENTER_EIP as u32).unwrap(),
24040314b30SXiaoye Zheng         )?;
24140314b30SXiaoye Zheng 
24240314b30SXiaoye Zheng         // Self::vmx_set_cr0();
24340314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_CR3 as u32, 0)?;
24440314b30SXiaoye Zheng         vmx_vmwrite(
24540314b30SXiaoye Zheng             VmcsFields::GUEST_CR4 as u32,
24640314b30SXiaoye Zheng             1, // enable vme
24740314b30SXiaoye Zheng         )?;
24840314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_DR7 as u32, 0x0000_0000_0000_0400)?;
24940314b30SXiaoye Zheng         vmx_vmwrite(
25040314b30SXiaoye Zheng             VmcsFields::GUEST_RSP as u32,
25140314b30SXiaoye Zheng             self.vcpu_ctx.regs[VcpuRegIndex::Rsp as usize] as u64,
25240314b30SXiaoye Zheng         )?;
25340314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::GUEST_RIP as u32, self.vcpu_ctx.rip as u64)?;
25440314b30SXiaoye Zheng         kdebug!("vmcs init guest rip: {:#x}", self.vcpu_ctx.rip as u64);
25540314b30SXiaoye Zheng         kdebug!(
25640314b30SXiaoye Zheng             "vmcs init guest rsp: {:#x}",
25740314b30SXiaoye Zheng             self.vcpu_ctx.regs[VcpuRegIndex::Rsp as usize] as u64
25840314b30SXiaoye Zheng         );
25940314b30SXiaoye Zheng 
26040314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::GUEST_RFLAGS as u32, x86::bits64::rflags::read().bits())?;
26140314b30SXiaoye Zheng         Ok(())
26240314b30SXiaoye Zheng     }
26340314b30SXiaoye Zheng 
26440314b30SXiaoye Zheng     #[allow(deprecated)]
26540314b30SXiaoye Zheng     pub fn vmcs_init_host(&self) -> Result<(), SystemError> {
26640314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_CR0 as u32, unsafe {
26740314b30SXiaoye Zheng             controlregs::cr0().bits().try_into().unwrap()
26840314b30SXiaoye Zheng         })?;
26940314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_CR3 as u32, unsafe { controlregs::cr3() })?;
27040314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_CR4 as u32, unsafe {
27140314b30SXiaoye Zheng             controlregs::cr4().bits().try_into().unwrap()
27240314b30SXiaoye Zheng         })?;
27340314b30SXiaoye Zheng         vmx_vmwrite(
27440314b30SXiaoye Zheng             VmcsFields::HOST_ES_SELECTOR as u32,
27540314b30SXiaoye Zheng             (segmentation::es().bits() & (!0x07)).into(),
27640314b30SXiaoye Zheng         )?;
27740314b30SXiaoye Zheng         vmx_vmwrite(
27840314b30SXiaoye Zheng             VmcsFields::HOST_CS_SELECTOR as u32,
27940314b30SXiaoye Zheng             (segmentation::cs().bits() & (!0x07)).into(),
28040314b30SXiaoye Zheng         )?;
28140314b30SXiaoye Zheng         vmx_vmwrite(
28240314b30SXiaoye Zheng             VmcsFields::HOST_SS_SELECTOR as u32,
28340314b30SXiaoye Zheng             (segmentation::ss().bits() & (!0x07)).into(),
28440314b30SXiaoye Zheng         )?;
28540314b30SXiaoye Zheng         vmx_vmwrite(
28640314b30SXiaoye Zheng             VmcsFields::HOST_DS_SELECTOR as u32,
28740314b30SXiaoye Zheng             (segmentation::ds().bits() & (!0x07)).into(),
28840314b30SXiaoye Zheng         )?;
28940314b30SXiaoye Zheng         vmx_vmwrite(
29040314b30SXiaoye Zheng             VmcsFields::HOST_FS_SELECTOR as u32,
29140314b30SXiaoye Zheng             (segmentation::fs().bits() & (!0x07)).into(),
29240314b30SXiaoye Zheng         )?;
29340314b30SXiaoye Zheng         vmx_vmwrite(
29440314b30SXiaoye Zheng             VmcsFields::HOST_GS_SELECTOR as u32,
29540314b30SXiaoye Zheng             (segmentation::gs().bits() & (!0x07)).into(),
29640314b30SXiaoye Zheng         )?;
29740314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_TR_SELECTOR as u32, unsafe {
29840314b30SXiaoye Zheng             (x86::task::tr().bits() & (!0x07)).into()
29940314b30SXiaoye Zheng         })?;
30040314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_FS_BASE as u32, unsafe {
30140314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_FS_BASE)
30240314b30SXiaoye Zheng         })?;
30340314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_GS_BASE as u32, unsafe {
30440314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_GS_BASE)
30540314b30SXiaoye Zheng         })?;
30640314b30SXiaoye Zheng 
30740314b30SXiaoye Zheng         let mut pseudo_descriptpr: x86::dtables::DescriptorTablePointer<u64> = Default::default();
30840314b30SXiaoye Zheng         unsafe {
30940314b30SXiaoye Zheng             x86::dtables::sgdt(&mut pseudo_descriptpr);
31040314b30SXiaoye Zheng         };
31140314b30SXiaoye Zheng 
31240314b30SXiaoye Zheng         vmx_vmwrite(
31340314b30SXiaoye Zheng             VmcsFields::HOST_TR_BASE as u32,
31440314b30SXiaoye Zheng             get_segment_base(pseudo_descriptpr.base, pseudo_descriptpr.limit, unsafe {
315b5b571e0SLoGin                 x86::task::tr().bits()
31640314b30SXiaoye Zheng             }),
31740314b30SXiaoye Zheng         )?;
31840314b30SXiaoye Zheng         vmx_vmwrite(
31940314b30SXiaoye Zheng             VmcsFields::HOST_GDTR_BASE as u32,
32040314b30SXiaoye Zheng             pseudo_descriptpr.base.to_bits() as u64,
32140314b30SXiaoye Zheng         )?;
32240314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_IDTR_BASE as u32, unsafe {
32340314b30SXiaoye Zheng             let mut pseudo_descriptpr: x86::dtables::DescriptorTablePointer<u64> =
32440314b30SXiaoye Zheng                 Default::default();
32540314b30SXiaoye Zheng             x86::dtables::sidt(&mut pseudo_descriptpr);
32640314b30SXiaoye Zheng             pseudo_descriptpr.base.to_bits() as u64
32740314b30SXiaoye Zheng         })?;
32840314b30SXiaoye Zheng 
32940314b30SXiaoye Zheng         // fast entry into the kernel
33040314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_SYSENTER_ESP as u32, unsafe {
33140314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_SYSENTER_ESP)
33240314b30SXiaoye Zheng         })?;
33340314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_SYSENTER_EIP as u32, unsafe {
33440314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_SYSENTER_EIP)
33540314b30SXiaoye Zheng         })?;
33640314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::HOST_SYSENTER_CS as u32, unsafe {
33740314b30SXiaoye Zheng             msr::rdmsr(msr::IA32_SYSENTER_CS)
33840314b30SXiaoye Zheng         })?;
33940314b30SXiaoye Zheng 
34040314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RIP as u32, vmx_return as *const () as u64)?;
34140314b30SXiaoye Zheng         // kdebug!("vmcs init host rip: {:#x}", vmx_return as *const () as u64);
34240314b30SXiaoye Zheng 
34340314b30SXiaoye Zheng         Ok(())
34440314b30SXiaoye Zheng     }
34540314b30SXiaoye Zheng 
34640314b30SXiaoye Zheng     // Intel SDM Volume 3C Chapter 25.3 “Organization of VMCS Data”
34740314b30SXiaoye Zheng     pub fn vmcs_init(&self) -> Result<(), SystemError> {
34840314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_PAGE_FAULT_ERR_CODE_MASK as u32, 0)?;
34940314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_PAGE_FAULT_ERR_CODE_MATCH as u32, 0)?;
35040314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_CR3_TARGET_COUNT as u32, 0)?;
35140314b30SXiaoye Zheng 
35240314b30SXiaoye Zheng         vmx_vmwrite(
35340314b30SXiaoye Zheng             VmcsFields::CTRL_PIN_BASED_VM_EXEC_CTRLS as u32,
35440314b30SXiaoye Zheng             adjust_vmx_pinbased_controls() as u64,
35540314b30SXiaoye Zheng         )?;
35640314b30SXiaoye Zheng 
35740314b30SXiaoye Zheng         vmx_vmwrite(
35840314b30SXiaoye Zheng             VmcsFields::CTRL_MSR_BITMAP_ADDR as u32,
35940314b30SXiaoye Zheng             self.data.msr_bitmap_physical_address,
36040314b30SXiaoye Zheng         )?;
36140314b30SXiaoye Zheng 
36240314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_CR0_READ_SHADOW as u32, unsafe {
36340314b30SXiaoye Zheng             controlregs::cr0().bits().try_into().unwrap()
36440314b30SXiaoye Zheng         })?;
36540314b30SXiaoye Zheng         vmx_vmwrite(VmcsFields::CTRL_CR4_READ_SHADOW as u32, unsafe {
36640314b30SXiaoye Zheng             controlregs::cr4().bits().try_into().unwrap()
36740314b30SXiaoye Zheng         })?;
36840314b30SXiaoye Zheng         vmx_vmwrite(
36940314b30SXiaoye Zheng             VmcsFields::CTRL_VM_ENTRY_CTRLS as u32,
37040314b30SXiaoye Zheng             adjust_vmx_entry_controls() as u64,
37140314b30SXiaoye Zheng         )?;
37240314b30SXiaoye Zheng         vmx_vmwrite(
37340314b30SXiaoye Zheng             VmcsFields::CTRL_PRIMARY_VM_EXIT_CTRLS as u32,
37440314b30SXiaoye Zheng             adjust_vmx_exit_controls() as u64,
37540314b30SXiaoye Zheng         )?;
37640314b30SXiaoye Zheng         vmx_vmwrite(
37740314b30SXiaoye Zheng             VmcsFields::CTRL_PRIMARY_PROCESSOR_VM_EXEC_CTRLS as u32,
37840314b30SXiaoye Zheng             adjust_vmx_primary_process_exec_controls() as u64,
37940314b30SXiaoye Zheng         )?;
38040314b30SXiaoye Zheng         vmx_vmwrite(
38140314b30SXiaoye Zheng             VmcsFields::CTRL_SECONDARY_PROCESSOR_VM_EXEC_CTRLS as u32,
38240314b30SXiaoye Zheng             adjust_vmx_secondary_process_exec_controls() as u64,
38340314b30SXiaoye Zheng         )?;
38440314b30SXiaoye Zheng 
38540314b30SXiaoye Zheng         self.vmcs_init_host()?;
38640314b30SXiaoye Zheng         self.vmcs_init_guest()?;
38740314b30SXiaoye Zheng         Ok(())
38840314b30SXiaoye Zheng     }
38940314b30SXiaoye Zheng 
39040314b30SXiaoye Zheng     fn kvm_mmu_load(&mut self) -> Result<(), SystemError> {
39140314b30SXiaoye Zheng         kdebug!("kvm_mmu_load!");
39240314b30SXiaoye Zheng         // 申请并创建新的页表
39340314b30SXiaoye Zheng         let mapper: crate::mm::page::PageMapper<X86_64MMArch, LockedFrameAllocator> = unsafe {
39440314b30SXiaoye Zheng             PageMapper::create(PageTableKind::EPT, LockedFrameAllocator)
39540314b30SXiaoye Zheng                 .ok_or(SystemError::ENOMEM)?
39640314b30SXiaoye Zheng         };
39740314b30SXiaoye Zheng 
39840314b30SXiaoye Zheng         let ept_root_hpa = mapper.table().phys();
39940314b30SXiaoye Zheng         let set_eptp_fn = self.mmu.set_eptp.unwrap();
40040314b30SXiaoye Zheng         set_eptp_fn(ept_root_hpa.data() as u64)?;
40140314b30SXiaoye Zheng         self.mmu.root_hpa = ept_root_hpa.data() as u64;
40240314b30SXiaoye Zheng         kdebug!("ept_root_hpa:{:x}!", ept_root_hpa.data() as u64);
40340314b30SXiaoye Zheng 
40440314b30SXiaoye Zheng         return Ok(());
40540314b30SXiaoye Zheng     }
40640314b30SXiaoye Zheng 
40740314b30SXiaoye Zheng     pub fn set_regs(&mut self, regs: VcpuContextFrame) -> Result<(), SystemError> {
40840314b30SXiaoye Zheng         self.vcpu_ctx = regs;
40940314b30SXiaoye Zheng         Ok(())
41040314b30SXiaoye Zheng     }
41140314b30SXiaoye Zheng }
41240314b30SXiaoye Zheng 
41340314b30SXiaoye Zheng impl Vcpu for VmxVcpu {
41440314b30SXiaoye Zheng     /// Virtualize the CPU
41540314b30SXiaoye Zheng     fn virtualize_cpu(&mut self) -> Result<(), SystemError> {
41640314b30SXiaoye Zheng         match has_intel_vmx_support() {
41740314b30SXiaoye Zheng             Ok(_) => {
41840314b30SXiaoye Zheng                 kdebug!("[+] CPU supports Intel VMX");
41940314b30SXiaoye Zheng             }
42040314b30SXiaoye Zheng             Err(e) => {
42140314b30SXiaoye Zheng                 kdebug!("[-] CPU does not support Intel VMX: {:?}", e);
422*1074eb34SSamuel Dai                 return Err(SystemError::ENOSYS);
42340314b30SXiaoye Zheng             }
42440314b30SXiaoye Zheng         };
42540314b30SXiaoye Zheng 
42640314b30SXiaoye Zheng         match enable_vmx_operation() {
42740314b30SXiaoye Zheng             Ok(_) => {
42840314b30SXiaoye Zheng                 kdebug!("[+] Enabling Virtual Machine Extensions (VMX)");
42940314b30SXiaoye Zheng             }
43040314b30SXiaoye Zheng             Err(_) => {
43140314b30SXiaoye Zheng                 kdebug!("[-] VMX operation is not supported on this processor.");
432*1074eb34SSamuel Dai                 return Err(SystemError::ENOSYS);
43340314b30SXiaoye Zheng             }
43440314b30SXiaoye Zheng         }
43540314b30SXiaoye Zheng 
43640314b30SXiaoye Zheng         vmxon(self.data.vmxon_region_physical_address)?;
43740314b30SXiaoye Zheng         kdebug!("[+] VMXON successful!");
43840314b30SXiaoye Zheng         vmx_vmclear(self.data.vmcs_region_physical_address)?;
43940314b30SXiaoye Zheng         vmx_vmptrld(self.data.vmcs_region_physical_address)?;
44040314b30SXiaoye Zheng         kdebug!("[+] VMPTRLD successful!");
44140314b30SXiaoye Zheng         self.vmcs_init().expect("vncs_init fail");
44240314b30SXiaoye Zheng         kdebug!("[+] VMCS init!");
44340314b30SXiaoye Zheng         // kdebug!("vmcs init host rip: {:#x}", vmx_return as *const () as u64);
44440314b30SXiaoye Zheng         // kdebug!("vmcs init host rsp: {:#x}", x86::bits64::registers::rsp());
44540314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RSP as u32, x86::bits64::registers::rsp())?;
44640314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RIP as u32, vmx_return as *const () as u64)?;
44740314b30SXiaoye Zheng         // vmx_vmwrite(VmcsFields::HOST_RSP as u32,  x86::bits64::registers::rsp())?;
44840314b30SXiaoye Zheng         self.kvm_mmu_load()?;
44940314b30SXiaoye Zheng         Ok(())
45040314b30SXiaoye Zheng     }
45140314b30SXiaoye Zheng 
45240314b30SXiaoye Zheng     fn devirtualize_cpu(&self) -> Result<(), SystemError> {
45340314b30SXiaoye Zheng         vmxoff()?;
45440314b30SXiaoye Zheng         Ok(())
45540314b30SXiaoye Zheng     }
45640314b30SXiaoye Zheng 
45740314b30SXiaoye Zheng     /// Gets the index of the current logical/virtual processor
45840314b30SXiaoye Zheng     fn id(&self) -> u32 {
45940314b30SXiaoye Zheng         self.vcpu_id
46040314b30SXiaoye Zheng     }
46140314b30SXiaoye Zheng }
46240314b30SXiaoye Zheng 
46340314b30SXiaoye Zheng pub fn get_segment_base(gdt_base: *const u64, gdt_size: u16, segment_selector: u16) -> u64 {
46440314b30SXiaoye Zheng     let table = segment_selector & 0x0004; // get table indicator in selector
46540314b30SXiaoye Zheng     let index = (segment_selector >> 3) as usize; // get index in selector
46640314b30SXiaoye Zheng     if table == 0 && index == 0 {
46740314b30SXiaoye Zheng         return 0;
46840314b30SXiaoye Zheng     }
46940314b30SXiaoye Zheng     let descriptor_table = unsafe { slice::from_raw_parts(gdt_base, gdt_size.into()) };
47040314b30SXiaoye Zheng     let descriptor = descriptor_table[index];
47140314b30SXiaoye Zheng 
47240314b30SXiaoye Zheng     let base_high = (descriptor & 0xFF00_0000_0000_0000) >> 32;
47340314b30SXiaoye Zheng     let base_mid = (descriptor & 0x0000_00FF_0000_0000) >> 16;
47440314b30SXiaoye Zheng     let base_low = (descriptor & 0x0000_0000_FFFF_0000) >> 16;
47540314b30SXiaoye Zheng     let segment_base = (base_high | base_mid | base_low) & 0xFFFFFFFF;
47640314b30SXiaoye Zheng     let virtaddr = phys_2_virt(segment_base.try_into().unwrap())
47740314b30SXiaoye Zheng         .try_into()
47840314b30SXiaoye Zheng         .unwrap();
47940314b30SXiaoye Zheng     kdebug!(
48040314b30SXiaoye Zheng         "segment_base={:x}",
48140314b30SXiaoye Zheng         phys_2_virt(segment_base.try_into().unwrap())
48240314b30SXiaoye Zheng     );
48340314b30SXiaoye Zheng     return virtaddr;
48440314b30SXiaoye Zheng }
48540314b30SXiaoye Zheng 
48640314b30SXiaoye Zheng // FIXME: may have bug
48740314b30SXiaoye Zheng // pub fn read_segment_access_rights(segement_selector: u16) -> u32{
48840314b30SXiaoye Zheng //     let table = segement_selector & 0x0004; // get table indicator in selector
48940314b30SXiaoye Zheng //     let index = segement_selector & 0xFFF8; // get index in selector
49040314b30SXiaoye Zheng //     let mut flag: u16;
49140314b30SXiaoye Zheng //     if table==0 && index==0 {
49240314b30SXiaoye Zheng //         return 0;
49340314b30SXiaoye Zheng //     }
49440314b30SXiaoye Zheng //     unsafe{
49540314b30SXiaoye Zheng //         asm!(
49640314b30SXiaoye Zheng //             "lar {0:r}, rcx",
49740314b30SXiaoye Zheng //             "mov {1:r}, {0:r}",
49840314b30SXiaoye Zheng //             in(reg) segement_selector,
49940314b30SXiaoye Zheng //             out(reg) flag,
50040314b30SXiaoye Zheng //         );
50140314b30SXiaoye Zheng //     }
50240314b30SXiaoye Zheng //     return (flag >> 8) as u32;
50340314b30SXiaoye Zheng // }
50440314b30SXiaoye Zheng pub fn adjust_vmx_controls(ctl_min: u32, ctl_opt: u32, msr: u32, result: &mut u32) {
50540314b30SXiaoye Zheng     let vmx_msr_low: u32 = unsafe { (msr::rdmsr(msr) & 0x0000_0000_FFFF_FFFF) as u32 };
50640314b30SXiaoye Zheng     let vmx_msr_high: u32 = unsafe { (msr::rdmsr(msr) << 32) as u32 };
50740314b30SXiaoye Zheng     let mut ctl: u32 = ctl_min | ctl_opt;
50840314b30SXiaoye Zheng     ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */
50940314b30SXiaoye Zheng     ctl |= vmx_msr_low; /* bit == 1 in low word  ==> must be one  */
51040314b30SXiaoye Zheng     *result = ctl;
51140314b30SXiaoye Zheng }
51240314b30SXiaoye Zheng 
51340314b30SXiaoye Zheng pub fn adjust_vmx_entry_controls() -> u32 {
51440314b30SXiaoye Zheng     let mut entry_controls: u32 = 0;
51540314b30SXiaoye Zheng     adjust_vmx_controls(
51640314b30SXiaoye Zheng         VmxEntryCtrl::LOAD_DBG_CTRLS.bits(),
51740314b30SXiaoye Zheng         VmxEntryCtrl::IA32E_MODE_GUEST.bits(),
51840314b30SXiaoye Zheng         msr::IA32_VMX_ENTRY_CTLS, //Capability Reporting Register of VM-entry Controls (R/O)
51940314b30SXiaoye Zheng         &mut entry_controls,
52040314b30SXiaoye Zheng     );
52140314b30SXiaoye Zheng     return entry_controls;
52240314b30SXiaoye Zheng     // msr::IA32_VMX_TRUE_ENTRY_CTLS//Capability Reporting Register of VM-entry Flex Controls (R/O) See Table 35-2
52340314b30SXiaoye Zheng }
52440314b30SXiaoye Zheng 
52540314b30SXiaoye Zheng pub fn adjust_vmx_exit_controls() -> u32 {
52640314b30SXiaoye Zheng     let mut exit_controls: u32 = 0;
52740314b30SXiaoye Zheng     adjust_vmx_controls(
52840314b30SXiaoye Zheng         VmxPrimaryExitCtrl::SAVE_DBG_CTRLS.bits(),
52940314b30SXiaoye Zheng         VmxPrimaryExitCtrl::HOST_ADDR_SPACE_SIZE.bits(),
53040314b30SXiaoye Zheng         msr::IA32_VMX_EXIT_CTLS,
53140314b30SXiaoye Zheng         &mut exit_controls,
53240314b30SXiaoye Zheng     );
53340314b30SXiaoye Zheng     return exit_controls;
53440314b30SXiaoye Zheng }
53540314b30SXiaoye Zheng 
53640314b30SXiaoye Zheng pub fn adjust_vmx_pinbased_controls() -> u32 {
537b5b571e0SLoGin     let mut controls: u32 = 16;
53840314b30SXiaoye Zheng     adjust_vmx_controls(0, 0, msr::IA32_VMX_TRUE_PINBASED_CTLS, &mut controls);
53940314b30SXiaoye Zheng     // kdebug!("adjust_vmx_pinbased_controls: {:x}", controls);
54040314b30SXiaoye Zheng     return controls;
54140314b30SXiaoye Zheng }
54240314b30SXiaoye Zheng 
54340314b30SXiaoye Zheng pub fn adjust_vmx_primary_process_exec_controls() -> u32 {
54440314b30SXiaoye Zheng     let mut controls: u32 = 0;
54540314b30SXiaoye Zheng     adjust_vmx_controls(
54640314b30SXiaoye Zheng         0,
54740314b30SXiaoye Zheng         VmxPrimaryProcessBasedExecuteCtrl::USE_MSR_BITMAPS.bits()
54840314b30SXiaoye Zheng             | VmxPrimaryProcessBasedExecuteCtrl::ACTIVATE_SECONDARY_CONTROLS.bits(),
54940314b30SXiaoye Zheng         msr::IA32_VMX_PROCBASED_CTLS,
55040314b30SXiaoye Zheng         &mut controls,
55140314b30SXiaoye Zheng     );
55240314b30SXiaoye Zheng     return controls;
55340314b30SXiaoye Zheng }
55440314b30SXiaoye Zheng 
55540314b30SXiaoye Zheng pub fn adjust_vmx_secondary_process_exec_controls() -> u32 {
55640314b30SXiaoye Zheng     let mut controls: u32 = 0;
55740314b30SXiaoye Zheng     adjust_vmx_controls(
55840314b30SXiaoye Zheng         0,
55940314b30SXiaoye Zheng         VmxSecondaryProcessBasedExecuteCtrl::ENABLE_RDTSCP.bits()
56040314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::ENABLE_XSAVES_XRSTORS.bits()
56140314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::ENABLE_INVPCID.bits()
56240314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::ENABLE_EPT.bits()
56340314b30SXiaoye Zheng             | VmxSecondaryProcessBasedExecuteCtrl::UNRESTRICTED_GUEST.bits(),
56440314b30SXiaoye Zheng         msr::IA32_VMX_PROCBASED_CTLS2,
56540314b30SXiaoye Zheng         &mut controls,
56640314b30SXiaoye Zheng     );
56740314b30SXiaoye Zheng     return controls;
56840314b30SXiaoye Zheng }
56940314b30SXiaoye Zheng 
57040314b30SXiaoye Zheng /// Check to see if CPU is Intel (“GenuineIntel”).
57140314b30SXiaoye Zheng /// Check processor supports for Virtual Machine Extension (VMX) technology
57240314b30SXiaoye Zheng //  CPUID.1:ECX.VMX[bit 5] = 1 (Intel Manual: 24.6 Discovering Support for VMX)
57340314b30SXiaoye Zheng pub fn has_intel_vmx_support() -> Result<(), SystemError> {
57440314b30SXiaoye Zheng     let cpuid = CpuId::new();
57540314b30SXiaoye Zheng     if let Some(vi) = cpuid.get_vendor_info() {
57640314b30SXiaoye Zheng         if vi.as_str() != "GenuineIntel" {
577*1074eb34SSamuel Dai             return Err(SystemError::ENOSYS);
57840314b30SXiaoye Zheng         }
57940314b30SXiaoye Zheng     }
58040314b30SXiaoye Zheng     if let Some(fi) = cpuid.get_feature_info() {
58140314b30SXiaoye Zheng         if !fi.has_vmx() {
582*1074eb34SSamuel Dai             return Err(SystemError::ENOSYS);
58340314b30SXiaoye Zheng         }
58440314b30SXiaoye Zheng     }
58540314b30SXiaoye Zheng     Ok(())
58640314b30SXiaoye Zheng }
58740314b30SXiaoye Zheng 
58840314b30SXiaoye Zheng /// Enables Virtual Machine Extensions
58940314b30SXiaoye Zheng // - CR4.VMXE[bit 13] = 1 (Intel Manual: 24.7 Enabling and Entering VMX Operation)
59040314b30SXiaoye Zheng pub fn enable_vmx_operation() -> Result<(), SystemError> {
59140314b30SXiaoye Zheng     let mut cr4 = unsafe { controlregs::cr4() };
59240314b30SXiaoye Zheng     cr4.set(controlregs::Cr4::CR4_ENABLE_VMX, true);
59340314b30SXiaoye Zheng     unsafe { controlregs::cr4_write(cr4) };
59440314b30SXiaoye Zheng 
59540314b30SXiaoye Zheng     set_lock_bit()?;
59640314b30SXiaoye Zheng     kdebug!("[+] Lock bit set via IA32_FEATURE_CONTROL");
59740314b30SXiaoye Zheng     set_cr0_bits();
59840314b30SXiaoye Zheng     kdebug!("[+] Mandatory bits in CR0 set/cleared");
59940314b30SXiaoye Zheng     set_cr4_bits();
60040314b30SXiaoye Zheng     kdebug!("[+] Mandatory bits in CR4 set/cleared");
60140314b30SXiaoye Zheng 
60240314b30SXiaoye Zheng     Ok(())
60340314b30SXiaoye Zheng }
60440314b30SXiaoye Zheng 
60540314b30SXiaoye Zheng /// Check if we need to set bits in IA32_FEATURE_CONTROL
60640314b30SXiaoye Zheng // (Intel Manual: 24.7 Enabling and Entering VMX Operation)
60740314b30SXiaoye Zheng fn set_lock_bit() -> Result<(), SystemError> {
60840314b30SXiaoye Zheng     const VMX_LOCK_BIT: u64 = 1 << 0;
60940314b30SXiaoye Zheng     const VMXON_OUTSIDE_SMX: u64 = 1 << 2;
61040314b30SXiaoye Zheng 
61140314b30SXiaoye Zheng     let ia32_feature_control = unsafe { msr::rdmsr(msr::IA32_FEATURE_CONTROL) };
61240314b30SXiaoye Zheng 
61340314b30SXiaoye Zheng     if (ia32_feature_control & VMX_LOCK_BIT) == 0 {
61440314b30SXiaoye Zheng         unsafe {
61540314b30SXiaoye Zheng             msr::wrmsr(
61640314b30SXiaoye Zheng                 msr::IA32_FEATURE_CONTROL,
61740314b30SXiaoye Zheng                 VMXON_OUTSIDE_SMX | VMX_LOCK_BIT | ia32_feature_control,
61840314b30SXiaoye Zheng             )
61940314b30SXiaoye Zheng         };
62040314b30SXiaoye Zheng     } else if (ia32_feature_control & VMXON_OUTSIDE_SMX) == 0 {
62140314b30SXiaoye Zheng         return Err(SystemError::EPERM);
62240314b30SXiaoye Zheng     }
62340314b30SXiaoye Zheng 
62440314b30SXiaoye Zheng     Ok(())
62540314b30SXiaoye Zheng }
62640314b30SXiaoye Zheng 
62740314b30SXiaoye Zheng /// Set the mandatory bits in CR0 and clear bits that are mandatory zero
62840314b30SXiaoye Zheng /// (Intel Manual: 24.8 Restrictions on VMX Operation)
62940314b30SXiaoye Zheng fn set_cr0_bits() {
63040314b30SXiaoye Zheng     let ia32_vmx_cr0_fixed0 = unsafe { msr::rdmsr(msr::IA32_VMX_CR0_FIXED0) };
63140314b30SXiaoye Zheng     let ia32_vmx_cr0_fixed1 = unsafe { msr::rdmsr(msr::IA32_VMX_CR0_FIXED1) };
63240314b30SXiaoye Zheng 
63340314b30SXiaoye Zheng     let mut cr0 = unsafe { controlregs::cr0() };
63440314b30SXiaoye Zheng 
63540314b30SXiaoye Zheng     cr0 |= controlregs::Cr0::from_bits_truncate(ia32_vmx_cr0_fixed0 as usize);
63640314b30SXiaoye Zheng     cr0 &= controlregs::Cr0::from_bits_truncate(ia32_vmx_cr0_fixed1 as usize);
63740314b30SXiaoye Zheng 
63840314b30SXiaoye Zheng     unsafe { controlregs::cr0_write(cr0) };
63940314b30SXiaoye Zheng }
64040314b30SXiaoye Zheng 
64140314b30SXiaoye Zheng /// Set the mandatory bits in CR4 and clear bits that are mandatory zero
64240314b30SXiaoye Zheng /// (Intel Manual: 24.8 Restrictions on VMX Operation)
64340314b30SXiaoye Zheng fn set_cr4_bits() {
64440314b30SXiaoye Zheng     let ia32_vmx_cr4_fixed0 = unsafe { msr::rdmsr(msr::IA32_VMX_CR4_FIXED0) };
64540314b30SXiaoye Zheng     let ia32_vmx_cr4_fixed1 = unsafe { msr::rdmsr(msr::IA32_VMX_CR4_FIXED1) };
64640314b30SXiaoye Zheng 
64740314b30SXiaoye Zheng     let mut cr4 = unsafe { controlregs::cr4() };
64840314b30SXiaoye Zheng 
64940314b30SXiaoye Zheng     cr4 |= controlregs::Cr4::from_bits_truncate(ia32_vmx_cr4_fixed0 as usize);
65040314b30SXiaoye Zheng     cr4 &= controlregs::Cr4::from_bits_truncate(ia32_vmx_cr4_fixed1 as usize);
65140314b30SXiaoye Zheng 
65240314b30SXiaoye Zheng     unsafe { controlregs::cr4_write(cr4) };
65340314b30SXiaoye Zheng }
654