WIP
This commit is contained in:
@ -158,7 +158,9 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
|
|||||||
info!("Interrupts enabled");
|
info!("Interrupts enabled");
|
||||||
|
|
||||||
let mut vcpu = vmm::get_vcpu(&mut bitmap_table).unwrap();
|
let mut vcpu = vmm::get_vcpu(&mut bitmap_table).unwrap();
|
||||||
while vcpu.run().is_ok() {}
|
loop {
|
||||||
|
info!("{:?}", vcpu.run(&mut bitmap_table));
|
||||||
|
}
|
||||||
|
|
||||||
hlt_loop();
|
hlt_loop();
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,10 @@ pub trait VCpu {
|
|||||||
fn is_supported() -> bool
|
fn is_supported() -> bool
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
fn run(&mut self) -> Result<(), &'static str>;
|
fn run(
|
||||||
|
&mut self,
|
||||||
|
frame_allocator: &mut dyn FrameAllocator<Size4KiB>,
|
||||||
|
) -> Result<(), &'static str>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_vcpu(
|
pub fn get_vcpu(
|
||||||
|
@ -9,7 +9,10 @@ use crate::{
|
|||||||
pub struct AMDVCpu;
|
pub struct AMDVCpu;
|
||||||
|
|
||||||
impl VCpu for AMDVCpu {
|
impl VCpu for AMDVCpu {
|
||||||
fn run(&mut self) -> Result<(), &'static str> {
|
fn run(
|
||||||
|
&mut self,
|
||||||
|
_frame_allocator: &mut dyn FrameAllocator<Size4KiB>,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
info!("VCpu on AMD");
|
info!("VCpu on AMD");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -34,15 +34,15 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
|||||||
let mut primary_exec_ctrl =
|
let mut primary_exec_ctrl =
|
||||||
vmcs::controls::PrimaryProcessorBasedVmExecutionControls::from(raw_primary_exec_ctrl);
|
vmcs::controls::PrimaryProcessorBasedVmExecutionControls::from(raw_primary_exec_ctrl);
|
||||||
primary_exec_ctrl.set_hlt(true);
|
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()?;
|
primary_exec_ctrl.write()?;
|
||||||
|
|
||||||
/*let mut raw_secondary_exec_ctrl =
|
let mut raw_secondary_exec_ctrl =
|
||||||
u32::from(vmcs::controls::SecondaryProcessorBasedVmExecutionControls::read()?);
|
u32::from(vmcs::controls::SecondaryProcessorBasedVmExecutionControls::read()?);
|
||||||
|
|
||||||
let reserved_bits = if basic_msr & (1 << 55) != 0 {
|
let reserved_bits = if basic_msr & (1 << 55) != 0 {
|
||||||
common::read_msr(0x48b)
|
common::read_msr(x86::msr::IA32_VMX_PROCBASED_CTLS2)
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
@ -51,15 +51,12 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
|||||||
|
|
||||||
let mut secondary_exec_ctrl =
|
let mut secondary_exec_ctrl =
|
||||||
vmcs::controls::SecondaryProcessorBasedVmExecutionControls::from(raw_secondary_exec_ctrl);
|
vmcs::controls::SecondaryProcessorBasedVmExecutionControls::from(raw_secondary_exec_ctrl);
|
||||||
secondary_exec_ctrl.set_ept(false); // TODO: true
|
secondary_exec_ctrl.set_ept(true); // TODO: true
|
||||||
secondary_exec_ctrl.set_unrestricted_guest(false); //TODO: true
|
secondary_exec_ctrl.set_unrestricted_guest(true); //TODO: true
|
||||||
secondary_exec_ctrl.set_virtualize_apic_accesses(false); // TODO: true
|
//secondary_exec_ctrl.set_virtualize_apic_accesses(false); // TODO: true
|
||||||
|
|
||||||
secondary_exec_ctrl.write()?;
|
secondary_exec_ctrl.write()?;
|
||||||
|
|
||||||
vmwrite(0x6000, 0)?;
|
|
||||||
vmwrite(0x6002, 0)?;*/
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +73,7 @@ pub fn setup_entry_controls() -> Result<(), &'static str> {
|
|||||||
raw_entry_ctrl &= (reserved_bits >> 32) as u32;
|
raw_entry_ctrl &= (reserved_bits >> 32) as u32;
|
||||||
|
|
||||||
let mut entry_ctrl = vmcs::controls::EntryControls::from(raw_entry_ctrl);
|
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_efer(true);
|
||||||
entry_ctrl.set_load_ia32_pat(true);*/
|
entry_ctrl.set_load_ia32_pat(true);*/
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ impl EPT {
|
|||||||
&mut self,
|
&mut self,
|
||||||
gpa: u64,
|
gpa: u64,
|
||||||
hpa: u64,
|
hpa: u64,
|
||||||
allocator: &mut impl FrameAllocator<Size4KiB>,
|
allocator: &mut dyn FrameAllocator<Size4KiB>,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
let lv4_index = (gpa >> 39) & 0x1FF;
|
let lv4_index = (gpa >> 39) & 0x1FF;
|
||||||
let lv3_index = (gpa >> 30) & 0x1FF;
|
let lv3_index = (gpa >> 30) & 0x1FF;
|
||||||
|
@ -3,7 +3,7 @@ use core::arch::naked_asm;
|
|||||||
use raw_cpuid::cpuid;
|
use raw_cpuid::cpuid;
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
registers::control::Cr4Flags,
|
registers::control::Cr4Flags,
|
||||||
structures::paging::{FrameAllocator, Size4KiB},
|
structures::paging::{frame, FrameAllocator, Size4KiB},
|
||||||
VirtAddr,
|
VirtAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ use crate::{
|
|||||||
x86_64::{
|
x86_64::{
|
||||||
common::{self, read_msr},
|
common::{self, read_msr},
|
||||||
intel::{
|
intel::{
|
||||||
controls,
|
controls, ept,
|
||||||
register::GuestRegisters,
|
register::GuestRegisters,
|
||||||
vmcs::{
|
vmcs::{
|
||||||
self,
|
self,
|
||||||
@ -38,6 +38,8 @@ pub struct IntelVCpu {
|
|||||||
activated: bool,
|
activated: bool,
|
||||||
vmxon: vmxon::Vmxon,
|
vmxon: vmxon::Vmxon,
|
||||||
vmcs: vmcs::Vmcs,
|
vmcs: vmcs::Vmcs,
|
||||||
|
ept: ept::EPT,
|
||||||
|
eptp: ept::EPTP,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntelVCpu {
|
impl IntelVCpu {
|
||||||
@ -84,6 +86,7 @@ impl IntelVCpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn vmentry(&mut self) -> Result<(), InstructionError> {
|
fn vmentry(&mut self) -> Result<(), InstructionError> {
|
||||||
|
info!("VMEntry");
|
||||||
let success = {
|
let success = {
|
||||||
let result: u16;
|
let result: u16;
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -91,6 +94,7 @@ impl IntelVCpu {
|
|||||||
};
|
};
|
||||||
result == 0
|
result == 0
|
||||||
};
|
};
|
||||||
|
info!("VMEntry result: {}", success);
|
||||||
|
|
||||||
if !self.launch_done && success {
|
if !self.launch_done && success {
|
||||||
self.launch_done = true;
|
self.launch_done = true;
|
||||||
@ -106,7 +110,10 @@ impl IntelVCpu {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(&mut self) -> Result<(), &'static str> {
|
fn activate(
|
||||||
|
&mut self,
|
||||||
|
frame_allocator: &mut dyn FrameAllocator<Size4KiB>,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
let revision_id = common::read_msr(0x480) as u32;
|
let revision_id = common::read_msr(0x480) as u32;
|
||||||
self.vmcs.write_revision_id(revision_id);
|
self.vmcs.write_revision_id(revision_id);
|
||||||
self.vmcs.reset()?;
|
self.vmcs.reset()?;
|
||||||
@ -116,6 +123,36 @@ impl IntelVCpu {
|
|||||||
Self::setup_host_state()?;
|
Self::setup_host_state()?;
|
||||||
Self::setup_guest_state()?;
|
Self::setup_guest_state()?;
|
||||||
|
|
||||||
|
self.init_guest_memory(frame_allocator)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_guest_memory(
|
||||||
|
&mut self,
|
||||||
|
frame_allocator: &mut dyn FrameAllocator<Size4KiB>,
|
||||||
|
) -> 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,11 +205,9 @@ impl IntelVCpu {
|
|||||||
|
|
||||||
fn setup_guest_state() -> Result<(), &'static str> {
|
fn setup_guest_state() -> Result<(), &'static str> {
|
||||||
use x86::{controlregs::*, vmx::vmcs};
|
use x86::{controlregs::*, vmx::vmcs};
|
||||||
let cr0 = unsafe { cr0() }/*(Cr0::empty()
|
let cr0 = Cr0::empty()
|
||||||
| Cr0::CR0_PROTECTED_MODE
|
| Cr0::CR0_PROTECTED_MODE
|
||||||
| Cr0::CR0_NUMERIC_ERROR
|
| Cr0::CR0_NUMERIC_ERROR & !Cr0::CR0_ENABLE_PAGING;
|
||||||
| Cr0::CR0_EXTENSION_TYPE)
|
|
||||||
& !Cr0::CR0_ENABLE_PAGING*/;
|
|
||||||
vmwrite(vmcs::guest::CR0, cr0.bits() as u64)?;
|
vmwrite(vmcs::guest::CR0, cr0.bits() as u64)?;
|
||||||
vmwrite(vmcs::guest::CR3, unsafe { cr3() })?;
|
vmwrite(vmcs::guest::CR3, unsafe { cr3() })?;
|
||||||
vmwrite(
|
vmwrite(
|
||||||
@ -189,12 +224,12 @@ impl IntelVCpu {
|
|||||||
vmwrite(vmcs::guest::IDTR_BASE, 0)?;
|
vmwrite(vmcs::guest::IDTR_BASE, 0)?;
|
||||||
vmwrite(vmcs::guest::LDTR_BASE, 0xDEAD00)?;
|
vmwrite(vmcs::guest::LDTR_BASE, 0xDEAD00)?;
|
||||||
|
|
||||||
vmwrite(vmcs::guest::CS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::CS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::SS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::SS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::DS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::DS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::ES_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::ES_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::FS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::FS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::GS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::GS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::TR_LIMIT, 0)?;
|
vmwrite(vmcs::guest::TR_LIMIT, 0)?;
|
||||||
vmwrite(vmcs::guest::GDTR_LIMIT, 0)?;
|
vmwrite(vmcs::guest::GDTR_LIMIT, 0)?;
|
||||||
vmwrite(vmcs::guest::IDTR_LIMIT, 0)?;
|
vmwrite(vmcs::guest::IDTR_LIMIT, 0)?;
|
||||||
@ -271,8 +306,8 @@ impl IntelVCpu {
|
|||||||
vmwrite(vmcs::guest::RFLAGS, 0x2)?;
|
vmwrite(vmcs::guest::RFLAGS, 0x2)?;
|
||||||
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?;
|
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?;
|
||||||
|
|
||||||
vmwrite(vmcs::guest::RIP, Self::test_guest_code as u64)?; // TODO: Set linux kernel base
|
vmwrite(vmcs::guest::RIP, 0)?; // TODO: Set linux kernel base
|
||||||
// TODO: RSI
|
// TODO: RSI
|
||||||
|
|
||||||
//vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?;
|
//vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?;
|
||||||
//vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?;
|
//vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?;
|
||||||
@ -302,9 +337,12 @@ impl IntelVCpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VCpu for IntelVCpu {
|
impl VCpu for IntelVCpu {
|
||||||
fn run(&mut self) -> Result<(), &'static str> {
|
fn run(
|
||||||
|
&mut self,
|
||||||
|
frame_allocator: &mut dyn FrameAllocator<Size4KiB>,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
if !self.activated {
|
if !self.activated {
|
||||||
self.activate()?;
|
self.activate(frame_allocator)?;
|
||||||
self.activated = true;
|
self.activated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,12 +374,17 @@ impl VCpu for IntelVCpu {
|
|||||||
|
|
||||||
let vmcs = vmcs::Vmcs::new(frame_allocator)?;
|
let vmcs = vmcs::Vmcs::new(frame_allocator)?;
|
||||||
|
|
||||||
|
let ept = ept::EPT::new(frame_allocator)?;
|
||||||
|
let eptp = ept::EPTP::init(&ept.root_table);
|
||||||
|
|
||||||
Ok(IntelVCpu {
|
Ok(IntelVCpu {
|
||||||
launch_done: false,
|
launch_done: false,
|
||||||
guest_registers: GuestRegisters::default(),
|
guest_registers: GuestRegisters::default(),
|
||||||
activated: false,
|
activated: false,
|
||||||
vmxon,
|
vmxon,
|
||||||
vmcs,
|
vmcs,
|
||||||
|
ept,
|
||||||
|
eptp,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user