-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4afc124
commit cb87672
Showing
19 changed files
with
556 additions
and
13 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use rvm::{HostPhysAddr, HostVirtAddr, RvmHal}; | ||
|
||
use crate::mm::{address, frame}; | ||
|
||
pub struct RvmHalImpl; | ||
|
||
impl RvmHal for RvmHalImpl { | ||
fn alloc_page() -> Option<HostPhysAddr> { | ||
unsafe { frame::alloc_page() } | ||
} | ||
|
||
fn dealloc_page(paddr: HostPhysAddr) { | ||
unsafe { frame::dealloc_page(paddr) } | ||
} | ||
|
||
fn phys_to_virt(paddr: HostPhysAddr) -> HostVirtAddr { | ||
address::phys_to_virt(paddr) | ||
} | ||
|
||
fn virt_to_phys(vaddr: HostVirtAddr) -> HostPhysAddr { | ||
address::virt_to_phys(vaddr) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
mod hal; | ||
|
||
use rvm::RvmPerCpu; | ||
|
||
use self::hal::RvmHalImpl; | ||
|
||
pub fn run() { | ||
println!("Starting virtualization..."); | ||
println!("Hardware support: {:?}", rvm::has_hardware_support()); | ||
|
||
let mut percpu = RvmPerCpu::<RvmHalImpl>::new(0); | ||
let res = percpu.hardware_enable(); | ||
println!("Hardware enable: {:?}", res); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
#![allow(dead_code)] | ||
|
||
mod heap; | ||
|
||
pub mod address; | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,17 @@ authors = ["Yuekai Jia <[email protected]>"] | |
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[features] | ||
default = ["vmx"] | ||
vmx = [] | ||
|
||
[dependencies] | ||
log = "0.4" | ||
cfg-if = "1.0" | ||
bitflags = "1.3" | ||
bit_field = "0.10" | ||
|
||
[target.'cfg(target_arch = "x86_64")'.dependencies] | ||
x86 = "0.52" | ||
x86_64 = "0.14" | ||
raw-cpuid = "10.6" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//! Architecture dependent structures. | ||
cfg_if::cfg_if! { | ||
if #[cfg(target_arch = "x86_64")] { | ||
mod x86_64; | ||
pub use self::x86_64::*; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
pub(crate) mod msr; | ||
|
||
cfg_if::cfg_if! { | ||
if #[cfg(feature = "vmx")] { | ||
mod vmx; | ||
use vmx as vender; | ||
} | ||
} | ||
|
||
pub use vender::{has_hardware_support, ArchPerCpuState}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
use x86::msr::{rdmsr, wrmsr}; | ||
|
||
/// X86 model-specific registers. (SDM Vol. 4) | ||
#[repr(u32)] | ||
#[derive(Debug, Copy, Clone)] | ||
#[allow(non_camel_case_types)] | ||
pub enum Msr { | ||
IA32_FEATURE_CONTROL = 0x3a, | ||
IA32_VMX_BASIC = 0x480, | ||
|
||
IA32_VMX_CR0_FIXED0 = 0x486, | ||
IA32_VMX_CR0_FIXED1 = 0x487, | ||
IA32_VMX_CR4_FIXED0 = 0x488, | ||
IA32_VMX_CR4_FIXED1 = 0x489, | ||
} | ||
|
||
impl Msr { | ||
/// Read 64 bits msr register. | ||
#[inline(always)] | ||
pub fn read(self) -> u64 { | ||
unsafe { rdmsr(self as _) } | ||
} | ||
|
||
/// Write 64 bits to msr register. | ||
/// | ||
/// # Safety | ||
/// | ||
/// The caller must ensure that this write operation has no unsafe side | ||
/// effects. | ||
#[inline(always)] | ||
pub unsafe fn write(self, value: u64) { | ||
wrmsr(self as _, value) | ||
} | ||
} | ||
|
||
pub(super) trait MsrReadWrite { | ||
const MSR: Msr; | ||
|
||
fn read_raw() -> u64 { | ||
Self::MSR.read() | ||
} | ||
|
||
unsafe fn write_raw(flags: u64) { | ||
Self::MSR.write(flags); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
mod structs; | ||
|
||
use raw_cpuid::CpuId; | ||
use x86::{bits64::vmx, vmx::VmFail}; | ||
use x86_64::registers::control::{Cr0, Cr4, Cr4Flags}; | ||
|
||
use self::structs::{FeatureControl, FeatureControlFlags, VmxBasic, VmxRegion}; | ||
use crate::arch::msr::Msr; | ||
use crate::error::{RvmError, RvmResult}; | ||
use crate::hal::RvmHal; | ||
|
||
pub use self::VmxPerCpuState as ArchPerCpuState; | ||
|
||
pub fn has_hardware_support() -> bool { | ||
if let Some(feature) = CpuId::new().get_feature_info() { | ||
feature.has_vmx() | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
pub struct VmxPerCpuState<H: RvmHal> { | ||
vmcs_revision_id: u32, | ||
vmx_region: VmxRegion<H>, | ||
} | ||
|
||
impl<H: RvmHal> VmxPerCpuState<H> { | ||
pub const fn new() -> Self { | ||
Self { | ||
vmcs_revision_id: 0, | ||
vmx_region: unsafe { VmxRegion::uninit() }, | ||
} | ||
} | ||
|
||
pub fn is_enabled(&self) -> bool { | ||
Cr4::read().contains(Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS) | ||
} | ||
|
||
pub fn hardware_enable(&mut self) -> RvmResult { | ||
if !has_hardware_support() { | ||
return rvm_err!(Unsupported, "CPU does not support feature VMX"); | ||
} | ||
if self.is_enabled() { | ||
return rvm_err!(ResourceBusy, "VMX is already turned on"); | ||
} | ||
|
||
// Enable VMXON, if required. | ||
let ctrl = FeatureControl::read(); | ||
let locked = ctrl.contains(FeatureControlFlags::LOCKED); | ||
let vmxon_outside = ctrl.contains(FeatureControlFlags::VMXON_ENABLED_OUTSIDE_SMX); | ||
if !locked { | ||
FeatureControl::write( | ||
ctrl | FeatureControlFlags::LOCKED | FeatureControlFlags::VMXON_ENABLED_OUTSIDE_SMX, | ||
) | ||
} else if !vmxon_outside { | ||
return rvm_err!(Unsupported, "VMX disabled by BIOS"); | ||
} | ||
|
||
// Check control registers are in a VMX-friendly state. (SDM Vol. 3C, Appendix A.7, A.8) | ||
macro_rules! cr_is_valid { | ||
($value: expr, $crx: ident) => {{ | ||
use Msr::*; | ||
let value = $value; | ||
let fixed0 = concat_idents!(IA32_VMX_, $crx, _FIXED0).read(); | ||
let fixed1 = concat_idents!(IA32_VMX_, $crx, _FIXED1).read(); | ||
(!fixed0 | value != 0) && (fixed1 | !value != 0) | ||
}}; | ||
} | ||
if !cr_is_valid!(Cr0::read().bits(), CR0) { | ||
return rvm_err!(BadState, "host CR0 is not valid in VMX operation"); | ||
} | ||
if !cr_is_valid!(Cr4::read().bits(), CR4) { | ||
return rvm_err!(BadState, "host CR4 is not valid in VMX operation"); | ||
} | ||
|
||
// Get VMCS revision identifier in IA32_VMX_BASIC MSR. | ||
let vmx_basic = VmxBasic::read(); | ||
if vmx_basic.region_size as usize != crate::mm::PAGE_SIZE { | ||
return rvm_err!(Unsupported); | ||
} | ||
if vmx_basic.mem_type != VmxBasic::VMX_MEMORY_TYPE_WRITE_BACK { | ||
return rvm_err!(Unsupported); | ||
} | ||
if vmx_basic.is_32bit_address { | ||
return rvm_err!(Unsupported); | ||
} | ||
if !vmx_basic.io_exit_info { | ||
return rvm_err!(Unsupported); | ||
} | ||
if !vmx_basic.vmx_flex_controls { | ||
return rvm_err!(Unsupported); | ||
} | ||
self.vmcs_revision_id = vmx_basic.revision_id; | ||
self.vmx_region = VmxRegion::new(vmx_basic.revision_id, false)?; | ||
|
||
unsafe { | ||
// Enable VMX using the VMXE bit. | ||
Cr4::write(Cr4::read() | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS); | ||
// Execute VMXON. | ||
vmx::vmxon(self.vmx_region.phys_addr() as _)?; | ||
} | ||
info!("[RVM] successed to turn on VMX."); | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn hardware_disable(&mut self) -> RvmResult { | ||
if !self.is_enabled() { | ||
return rvm_err!(BadState, "VMX is not enabled"); | ||
} | ||
|
||
unsafe { | ||
// Execute VMXOFF. | ||
vmx::vmxoff()?; | ||
// Remove VMXE bit in CR4. | ||
Cr4::update(|cr4| cr4.remove(Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS)); | ||
}; | ||
info!("[RVM] successed to turn off VMX."); | ||
|
||
self.vmx_region = unsafe { VmxRegion::uninit() }; | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl From<VmFail> for RvmError { | ||
fn from(err: VmFail) -> Self { | ||
rvm_err_type!(BadState, format_args!("VMX instruction failed: {:?}", err)) | ||
} | ||
} |
Oops, something went wrong.