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