From 96fdbed1d27e2cf7c63dca8155e4e006cb51128f Mon Sep 17 00:00:00 2001 From: Masato Imai Date: Wed, 6 Aug 2025 10:22:29 +0000 Subject: [PATCH] WIP --- nel_os_kernel/src/main.rs | 4 +- nel_os_kernel/src/vmm/mod.rs | 5 +- nel_os_kernel/src/vmm/x86_64/amd/vcpu.rs | 5 +- .../src/vmm/x86_64/intel/controls.rs | 17 ++-- nel_os_kernel/src/vmm/x86_64/intel/ept.rs | 2 +- nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs | 77 +++++++++++++++---- 6 files changed, 79 insertions(+), 31 deletions(-) diff --git a/nel_os_kernel/src/main.rs b/nel_os_kernel/src/main.rs index a13e029..ffc68ab 100644 --- a/nel_os_kernel/src/main.rs +++ b/nel_os_kernel/src/main.rs @@ -158,7 +158,9 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) { info!("Interrupts enabled"); let mut vcpu = vmm::get_vcpu(&mut bitmap_table).unwrap(); - while vcpu.run().is_ok() {} + loop { + info!("{:?}", vcpu.run(&mut bitmap_table)); + } hlt_loop(); } diff --git a/nel_os_kernel/src/vmm/mod.rs b/nel_os_kernel/src/vmm/mod.rs index 1b15462..67851bf 100644 --- a/nel_os_kernel/src/vmm/mod.rs +++ b/nel_os_kernel/src/vmm/mod.rs @@ -15,7 +15,10 @@ pub trait VCpu { fn is_supported() -> bool where Self: Sized; - fn run(&mut self) -> Result<(), &'static str>; + fn run( + &mut self, + frame_allocator: &mut dyn FrameAllocator, + ) -> Result<(), &'static str>; } pub fn get_vcpu( diff --git a/nel_os_kernel/src/vmm/x86_64/amd/vcpu.rs b/nel_os_kernel/src/vmm/x86_64/amd/vcpu.rs index fbc1efb..cd3753d 100644 --- a/nel_os_kernel/src/vmm/x86_64/amd/vcpu.rs +++ b/nel_os_kernel/src/vmm/x86_64/amd/vcpu.rs @@ -9,7 +9,10 @@ use crate::{ pub struct AMDVCpu; impl VCpu for AMDVCpu { - fn run(&mut self) -> Result<(), &'static str> { + fn run( + &mut self, + _frame_allocator: &mut dyn FrameAllocator, + ) -> Result<(), &'static str> { info!("VCpu on AMD"); Ok(()) diff --git a/nel_os_kernel/src/vmm/x86_64/intel/controls.rs b/nel_os_kernel/src/vmm/x86_64/intel/controls.rs index 8e60950..64440e3 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/controls.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/controls.rs @@ -34,15 +34,15 @@ pub fn setup_exec_controls() -> Result<(), &'static str> { let mut primary_exec_ctrl = vmcs::controls::PrimaryProcessorBasedVmExecutionControls::from(raw_primary_exec_ctrl); primary_exec_ctrl.set_hlt(true); - primary_exec_ctrl.set_activate_secondary_controls(false); + primary_exec_ctrl.set_activate_secondary_controls(true); primary_exec_ctrl.write()?; - /*let mut raw_secondary_exec_ctrl = + let mut raw_secondary_exec_ctrl = u32::from(vmcs::controls::SecondaryProcessorBasedVmExecutionControls::read()?); let reserved_bits = if basic_msr & (1 << 55) != 0 { - common::read_msr(0x48b) + common::read_msr(x86::msr::IA32_VMX_PROCBASED_CTLS2) } else { 0 }; @@ -51,15 +51,12 @@ pub fn setup_exec_controls() -> Result<(), &'static str> { let mut secondary_exec_ctrl = vmcs::controls::SecondaryProcessorBasedVmExecutionControls::from(raw_secondary_exec_ctrl); - secondary_exec_ctrl.set_ept(false); // TODO: true - secondary_exec_ctrl.set_unrestricted_guest(false); //TODO: true - secondary_exec_ctrl.set_virtualize_apic_accesses(false); // TODO: true + secondary_exec_ctrl.set_ept(true); // TODO: true + secondary_exec_ctrl.set_unrestricted_guest(true); //TODO: true + //secondary_exec_ctrl.set_virtualize_apic_accesses(false); // TODO: true secondary_exec_ctrl.write()?; - vmwrite(0x6000, 0)?; - vmwrite(0x6002, 0)?;*/ - Ok(()) } @@ -76,7 +73,7 @@ pub fn setup_entry_controls() -> Result<(), &'static str> { raw_entry_ctrl &= (reserved_bits >> 32) as u32; let mut entry_ctrl = vmcs::controls::EntryControls::from(raw_entry_ctrl); - entry_ctrl.set_ia32e_mode_guest(true); + entry_ctrl.set_ia32e_mode_guest(false); /*entry_ctrl.set_load_ia32_efer(true); entry_ctrl.set_load_ia32_pat(true);*/ diff --git a/nel_os_kernel/src/vmm/x86_64/intel/ept.rs b/nel_os_kernel/src/vmm/x86_64/intel/ept.rs index e0a33ed..2a6a4fa 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/ept.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/ept.rs @@ -41,7 +41,7 @@ impl EPT { &mut self, gpa: u64, hpa: u64, - allocator: &mut impl FrameAllocator, + allocator: &mut dyn FrameAllocator, ) -> Result<(), &'static str> { let lv4_index = (gpa >> 39) & 0x1FF; let lv3_index = (gpa >> 30) & 0x1FF; diff --git a/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs b/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs index ec65fa2..441e2a9 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs @@ -3,7 +3,7 @@ use core::arch::naked_asm; use raw_cpuid::cpuid; use x86_64::{ registers::control::Cr4Flags, - structures::paging::{FrameAllocator, Size4KiB}, + structures::paging::{frame, FrameAllocator, Size4KiB}, VirtAddr, }; @@ -13,7 +13,7 @@ use crate::{ x86_64::{ common::{self, read_msr}, intel::{ - controls, + controls, ept, register::GuestRegisters, vmcs::{ self, @@ -38,6 +38,8 @@ pub struct IntelVCpu { activated: bool, vmxon: vmxon::Vmxon, vmcs: vmcs::Vmcs, + ept: ept::EPT, + eptp: ept::EPTP, } impl IntelVCpu { @@ -84,6 +86,7 @@ impl IntelVCpu { } fn vmentry(&mut self) -> Result<(), InstructionError> { + info!("VMEntry"); let success = { let result: u16; unsafe { @@ -91,6 +94,7 @@ impl IntelVCpu { }; result == 0 }; + info!("VMEntry result: {}", success); if !self.launch_done && success { self.launch_done = true; @@ -106,7 +110,10 @@ impl IntelVCpu { Ok(()) } - fn activate(&mut self) -> Result<(), &'static str> { + fn activate( + &mut self, + frame_allocator: &mut dyn FrameAllocator, + ) -> Result<(), &'static str> { let revision_id = common::read_msr(0x480) as u32; self.vmcs.write_revision_id(revision_id); self.vmcs.reset()?; @@ -116,6 +123,36 @@ impl IntelVCpu { Self::setup_host_state()?; Self::setup_guest_state()?; + self.init_guest_memory(frame_allocator)?; + + Ok(()) + } + + fn init_guest_memory( + &mut self, + frame_allocator: &mut dyn FrameAllocator, + ) -> Result<(), &'static str> { + let mut pages = 1000; + let mut gpa = 0; + + while pages > 0 { + let frame = frame_allocator.allocate_frame().ok_or("No free frames")?; + let hpa = frame.start_address().as_u64(); + + self.ept.map_2m(gpa, hpa, frame_allocator)?; + gpa += (4 * 1024) << 9; + pages -= 1; + } + + let guest_ptr = Self::test_guest_code as u64; + let guest_addr = self.ept.get_phys_addr(0).unwrap(); + unsafe { + core::ptr::copy_nonoverlapping(guest_ptr as *const u8, guest_addr as *mut u8, 200); + } + + let eptp = ept::EPTP::init(&self.ept.root_table); + vmwrite(x86::vmx::vmcs::control::EPTP_FULL, u64::from(eptp))?; + Ok(()) } @@ -168,11 +205,9 @@ impl IntelVCpu { fn setup_guest_state() -> Result<(), &'static str> { use x86::{controlregs::*, vmx::vmcs}; - let cr0 = unsafe { cr0() }/*(Cr0::empty() + let cr0 = Cr0::empty() | Cr0::CR0_PROTECTED_MODE - | Cr0::CR0_NUMERIC_ERROR - | Cr0::CR0_EXTENSION_TYPE) - & !Cr0::CR0_ENABLE_PAGING*/; + | Cr0::CR0_NUMERIC_ERROR & !Cr0::CR0_ENABLE_PAGING; vmwrite(vmcs::guest::CR0, cr0.bits() as u64)?; vmwrite(vmcs::guest::CR3, unsafe { cr3() })?; vmwrite( @@ -189,12 +224,12 @@ impl IntelVCpu { vmwrite(vmcs::guest::IDTR_BASE, 0)?; vmwrite(vmcs::guest::LDTR_BASE, 0xDEAD00)?; - vmwrite(vmcs::guest::CS_LIMIT, u32::MAX as u64)?; - vmwrite(vmcs::guest::SS_LIMIT, u32::MAX as u64)?; - vmwrite(vmcs::guest::DS_LIMIT, u32::MAX as u64)?; - vmwrite(vmcs::guest::ES_LIMIT, u32::MAX as u64)?; - vmwrite(vmcs::guest::FS_LIMIT, u32::MAX as u64)?; - vmwrite(vmcs::guest::GS_LIMIT, u32::MAX as u64)?; + vmwrite(vmcs::guest::CS_LIMIT, 0xffff)?; + vmwrite(vmcs::guest::SS_LIMIT, 0xffff)?; + vmwrite(vmcs::guest::DS_LIMIT, 0xffff)?; + vmwrite(vmcs::guest::ES_LIMIT, 0xffff)?; + vmwrite(vmcs::guest::FS_LIMIT, 0xffff)?; + vmwrite(vmcs::guest::GS_LIMIT, 0xffff)?; vmwrite(vmcs::guest::TR_LIMIT, 0)?; vmwrite(vmcs::guest::GDTR_LIMIT, 0)?; vmwrite(vmcs::guest::IDTR_LIMIT, 0)?; @@ -271,8 +306,8 @@ impl IntelVCpu { vmwrite(vmcs::guest::RFLAGS, 0x2)?; vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?; - vmwrite(vmcs::guest::RIP, Self::test_guest_code as u64)?; // TODO: Set linux kernel base - // TODO: RSI + vmwrite(vmcs::guest::RIP, 0)?; // TODO: Set linux kernel base + // TODO: RSI //vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?; //vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?; @@ -302,9 +337,12 @@ impl IntelVCpu { } impl VCpu for IntelVCpu { - fn run(&mut self) -> Result<(), &'static str> { + fn run( + &mut self, + frame_allocator: &mut dyn FrameAllocator, + ) -> Result<(), &'static str> { if !self.activated { - self.activate()?; + self.activate(frame_allocator)?; self.activated = true; } @@ -336,12 +374,17 @@ impl VCpu for IntelVCpu { let vmcs = vmcs::Vmcs::new(frame_allocator)?; + let ept = ept::EPT::new(frame_allocator)?; + let eptp = ept::EPTP::init(&ept.root_table); + Ok(IntelVCpu { launch_done: false, guest_registers: GuestRegisters::default(), activated: false, vmxon, vmcs, + ept, + eptp, }) }