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