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