This commit is contained in:
Masato Imai
2025-08-05 16:43:15 +00:00
parent ff14f69742
commit bb95e9e595
7 changed files with 186 additions and 134 deletions

View File

@ -145,6 +145,7 @@ dependencies = [
"raw-cpuid 11.5.0", "raw-cpuid 11.5.0",
"spin 0.10.0", "spin 0.10.0",
"uart_16550", "uart_16550",
"x86",
"x86_64", "x86_64",
] ]

View File

@ -15,3 +15,4 @@ raw-cpuid = "11.5.0"
acpi = "5.2.0" acpi = "5.2.0"
modular-bitfield = "0.12.0" modular-bitfield = "0.12.0"
numeric-enum-macro = "0.2.0" numeric-enum-macro = "0.2.0"
x86 = "0.52.0"

View File

@ -3,7 +3,7 @@ use alloc::boxed::Box;
use crate::{ use crate::{
platform, platform,
vmm::x86_64::{amd::AMDVCpu, intel::IntelVCpu}, vmm::x86_64::{amd::vcpu::AMDVCpu, intel::vcpu::IntelVCpu},
}; };
pub mod x86_64; pub mod x86_64;

View File

@ -1,45 +1 @@
use raw_cpuid::cpuid; pub mod vcpu;
use x86_64::structures::paging::{FrameAllocator, Size4KiB};
use crate::{
error, info,
vmm::{x86_64::common, VCpu},
};
pub struct AMDVCpu;
impl VCpu for AMDVCpu {
fn run(&mut self) -> Result<(), &'static str> {
info!("VCpu on AMD");
Ok(())
}
fn new(_frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Result<Self, &'static str>
where
Self: Sized,
{
let mut efer = common::read_msr(0xc000_0080);
efer |= 1 << 12;
common::write_msr(0xc000_0080, efer);
Ok(AMDVCpu)
}
fn is_supported() -> bool
where
Self: Sized,
{
if cpuid!(0x8000_0001).ecx & (1 << 2) == 0 {
error!("SVM not supported by CPU");
return false;
}
if common::read_msr(0xc001_0114) & (1 << 4) != 0 {
error!("SVM disabled by BIOS");
return false;
}
true
}
}

View File

@ -0,0 +1,45 @@
use raw_cpuid::cpuid;
use x86_64::structures::paging::{FrameAllocator, Size4KiB};
use crate::{
error, info,
vmm::{x86_64::common, VCpu},
};
pub struct AMDVCpu;
impl VCpu for AMDVCpu {
fn run(&mut self) -> Result<(), &'static str> {
info!("VCpu on AMD");
Ok(())
}
fn new(_frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Result<Self, &'static str>
where
Self: Sized,
{
let mut efer = common::read_msr(0xc000_0080);
efer |= 1 << 12;
common::write_msr(0xc000_0080, efer);
Ok(AMDVCpu)
}
fn is_supported() -> bool
where
Self: Sized,
{
if cpuid!(0x8000_0001).ecx & (1 << 2) == 0 {
error!("SVM not supported by CPU");
return false;
}
if common::read_msr(0xc001_0114) & (1 << 4) != 0 {
error!("SVM disabled by BIOS");
return false;
}
true
}
}

View File

@ -1,97 +1,11 @@
mod controls; mod controls;
pub mod vcpu;
mod vmcs; mod vmcs;
mod vmxon; mod vmxon;
use core::arch::asm; use core::arch::asm;
use raw_cpuid::cpuid; use x86_64::registers::rflags::{self, RFlags};
use x86_64::{
registers::rflags::{self, RFlags},
structures::paging::{FrameAllocator, Size4KiB},
};
use crate::{
info,
vmm::{x86_64::common, VCpu},
};
pub struct IntelVCpu {
activated: bool,
vmxon: vmxon::Vmxon,
vmcs: vmcs::Vmcs,
}
impl IntelVCpu {
fn activate(&mut self) -> Result<(), &'static str> {
let revision_id = common::read_msr(0x480) as u32;
self.vmcs.write_revision_id(revision_id);
self.vmcs.reset()?;
controls::setup_exec_controls()?;
controls::setup_entry_controls()?;
controls::setup_exit_controls()?;
Ok(())
}
}
impl VCpu for IntelVCpu {
fn run(&mut self) -> Result<(), &'static str> {
info!("VCpu on Intel");
if !self.activated {
self.activate()?;
self.activated = true;
}
Ok(())
}
fn new(frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Result<Self, &'static str>
where
Self: Sized,
{
let mut msr = common::read_msr(0x3a);
if msr & (1 << 2) == 0 {
msr |= 1 << 2;
msr |= 1;
common::write_msr(0x3a, msr);
}
let msr = common::read_msr(0x3a);
if msr & (1 << 2) == 0 {
return Err("VMX is not enabled in the BIOS");
}
let mut vmxon = vmxon::Vmxon::new(frame_allocator)?;
vmxon.activate()?;
let vmcs = vmcs::Vmcs::new(frame_allocator)?;
Ok(IntelVCpu {
activated: false,
vmxon,
vmcs,
})
}
fn is_supported() -> bool
where
Self: Sized,
{
if cpuid!(0x1).ecx & (1 << 5) == 0 {
info!("Intel CPU does not support VMX");
return false;
}
let msr = common::read_msr(0x3a);
if msr & (1 << 2) == 0 && msr & 1 != 0 {
info!("VMX is not enabled in the BIOS");
return false;
}
true
}
}
pub fn vmx_capture_status() -> Result<(), &'static str> { pub fn vmx_capture_status() -> Result<(), &'static str> {
let flags = rflags::read(); let flags = rflags::read();

View File

@ -0,0 +1,135 @@
use raw_cpuid::cpuid;
use x86_64::{
registers::control::Cr4Flags,
structures::paging::{FrameAllocator, Size4KiB},
};
use crate::{
info,
vmm::{
x86_64::{
common::{self, read_msr},
intel::{controls, vmcs, vmwrite, vmxon},
},
VCpu,
},
};
pub struct IntelVCpu {
activated: bool,
vmxon: vmxon::Vmxon,
vmcs: vmcs::Vmcs,
}
impl IntelVCpu {
fn activate(&mut self) -> Result<(), &'static str> {
let revision_id = common::read_msr(0x480) as u32;
self.vmcs.write_revision_id(revision_id);
self.vmcs.reset()?;
controls::setup_exec_controls()?;
controls::setup_entry_controls()?;
controls::setup_exit_controls()?;
Self::setup_host_state()?;
Ok(())
}
fn setup_host_state() -> Result<(), &'static str> {
use x86::{
controlregs::*, dtables, dtables::DescriptorTablePointer, segmentation::*, vmx::vmcs,
};
vmwrite(vmcs::host::CR0, unsafe { cr0() }.bits() as u64)?;
vmwrite(vmcs::host::CR3, unsafe { cr3() })?;
vmwrite(
vmcs::host::CR4,
unsafe { cr4() }.bits() as u64 | Cr4Flags::OSXSAVE.bits(),
)?;
// TODO: set RIP to VMExit handler and stack
vmwrite(vmcs::host::ES_SELECTOR, es().bits() as u64)?;
vmwrite(vmcs::host::CS_SELECTOR, cs().bits() as u64)?;
vmwrite(vmcs::host::SS_SELECTOR, ss().bits() as u64)?;
vmwrite(vmcs::host::DS_SELECTOR, ds().bits() as u64)?;
vmwrite(vmcs::host::FS_SELECTOR, fs().bits() as u64)?;
vmwrite(vmcs::host::GS_SELECTOR, gs().bits() as u64)?;
vmwrite(vmcs::host::FS_BASE, read_msr(x86::msr::IA32_FS_BASE))?;
vmwrite(vmcs::host::GS_BASE, read_msr(x86::msr::IA32_GS_BASE))?;
let tr = unsafe { x86::task::tr() };
let mut gdtp = DescriptorTablePointer::<u64>::default();
let mut idtp = DescriptorTablePointer::<u64>::default();
unsafe {
dtables::sgdt(&mut gdtp);
dtables::sidt(&mut idtp);
}
vmwrite(vmcs::host::GDTR_BASE, gdtp.base as u64)?;
vmwrite(vmcs::host::IDTR_BASE, idtp.base as u64)?;
vmwrite(vmcs::host::TR_SELECTOR, tr.bits() as u64)?;
vmwrite(vmcs::host::TR_BASE, 0)?;
vmwrite(vmcs::host::IA32_EFER_FULL, read_msr(x86::msr::IA32_EFER))?;
Ok(())
}
}
impl VCpu for IntelVCpu {
fn run(&mut self) -> Result<(), &'static str> {
info!("VCpu on Intel");
if !self.activated {
self.activate()?;
self.activated = true;
}
Ok(())
}
fn new(frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Result<Self, &'static str>
where
Self: Sized,
{
let mut msr = common::read_msr(0x3a);
if msr & (1 << 2) == 0 {
msr |= 1 << 2;
msr |= 1;
common::write_msr(0x3a, msr);
}
let msr = common::read_msr(0x3a);
if msr & (1 << 2) == 0 {
return Err("VMX is not enabled in the BIOS");
}
let mut vmxon = vmxon::Vmxon::new(frame_allocator)?;
vmxon.activate()?;
let vmcs = vmcs::Vmcs::new(frame_allocator)?;
Ok(IntelVCpu {
activated: false,
vmxon,
vmcs,
})
}
fn is_supported() -> bool
where
Self: Sized,
{
if cpuid!(0x1).ecx & (1 << 5) == 0 {
info!("Intel CPU does not support VMX");
return false;
}
let msr = common::read_msr(0x3a);
if msr & (1 << 2) == 0 && msr & 1 != 0 {
info!("VMX is not enabled in the BIOS");
return false;
}
true
}
}