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