vcpu
This commit is contained in:
1
nel_os_kernel/Cargo.lock
generated
1
nel_os_kernel/Cargo.lock
generated
@ -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",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
45
nel_os_kernel/src/vmm/x86_64/amd/vcpu.rs
Normal file
45
nel_os_kernel/src/vmm/x86_64/amd/vcpu.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
135
nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs
Normal file
135
nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user