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