Initial work for hardware virtualization
Some checks failed
Continuous Integration / Check (push) Failing after 1m11s
Continuous Integration / Clippy (push) Failing after 1m11s

This commit is contained in:
August 2025-10-31 12:49:18 -04:00
parent 4486507316
commit a4ad6da4f7
Signed by: shibedrill
GPG Key ID: 5FE0CB25945EFAA2
5 changed files with 180 additions and 4 deletions

View File

@ -0,0 +1,30 @@
// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT
use intbits::Bits;
use x86_64::registers::control::EferFlags;
use crate::arch::x86_64::cpuid::*;
pub fn amd_v_supported() -> bool {
match ProcessorVendor::try_get_current() {
Ok(vendor) => {
if vendor == ProcessorVendor::AMD {
match CPUID.get_extended_processor_and_feature_identifiers() {
Some(features) => features.has_svm(),
_ => false,
}
} else {
false
}
}
Err(_) => false,
}
}
pub fn enable_svm() {
let mut efer = x86_64::registers::model_specific::Efer::read().bits();
efer.set_bit(12, true);
assert!(efer.bit(12));
unsafe { x86_64::registers::model_specific::Efer::write(EferFlags::from_bits_retain(efer)) };
}

View File

@ -0,0 +1,121 @@
// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT
use lazy_static::lazy_static;
use raw_cpuid::CpuId;
use raw_cpuid::CpuIdReaderNative;
use crate::arch::x86_64::amd_virt::amd_v_supported;
use crate::arch::x86_64::intel_virt::intel_vt_supported;
lazy_static! {
pub static ref CPUID: CpuId<CpuIdReaderNative> = CpuId::new();
}
#[derive(Debug)]
pub enum VirtualizationProvider {
AmdV,
IntelVTx,
None,
}
#[derive(PartialEq, Eq)]
pub enum ProcessorVendor {
AMD,
Intel,
Via,
Transmeta,
Cyrix,
Centaur,
Nexgen,
UMC,
SiS,
NSC,
Rise,
Vortex,
AO486,
Zaoxin,
Hygon,
Elbrus,
QEMU,
KVM,
VMware,
VirtualBox,
Xen,
HyperV,
Parallels,
QNX,
}
impl TryFrom<&str> for ProcessorVendor {
type Error = ();
fn try_from(from: &str) -> Result<Self, Self::Error> {
match from {
"AuthenticAMD" | "AMDisbetter!" => Ok(Self::AMD),
"GenuineIntel" | "GenuineIotel" => Ok(Self::Intel),
"VIA VIA VIA " => Ok(Self::Via),
"GenuineTMx86" | "TransmetaCPU" => Ok(Self::Transmeta),
"CyrixInstead" => Ok(Self::Cyrix),
"CentaurHauls" => Ok(Self::Centaur),
"NexGenDriven" => Ok(Self::Nexgen),
"UMC UMC UMC " => Ok(Self::UMC),
"SiS SiS SiS " => Ok(Self::SiS),
"Geode by NSC" => Ok(Self::NSC),
"RiseRiseRise" => Ok(Self::Rise),
"Vortex86 SoC" => Ok(Self::Vortex),
"MiSTer AO486" | "GenuineAO486" => Ok(Self::AO486),
" Shanghai " => Ok(Self::Zaoxin),
"HygonGenuine" => Ok(Self::Hygon),
"E2K MACHINE " => Ok(Self::Elbrus),
"TCGTCGTCGTCG" => Ok(Self::QEMU),
" KVMKVMKVM " => Ok(Self::KVM),
"VMwareVMware" => Ok(Self::VMware),
"VBoxVBoxVBox" => Ok(Self::VirtualBox),
"XenVMMXenVMM" => Ok(Self::Xen),
"Microsoft Hv" => Ok(Self::HyperV),
" prl hyperv " | " lrpepyh vr " => Ok(Self::Parallels),
" QNXQVMBSQG " => Ok(Self::QNX),
_ => Err(()),
}
}
}
impl ProcessorVendor {
pub fn is_hypervisor(&self) -> bool {
matches!(self, Self::QEMU
| Self::KVM
| Self::VMware
| Self::VirtualBox
| Self::HyperV
| Self::Parallels
| Self::QNX)
}
pub fn try_get_current() -> Result<Self, ()> {
if let Some(brand_string) = CPUID.get_vendor_info() {
Self::try_from(brand_string.as_str())
} else {
Err(())
}
}
}
pub fn virt_supported() -> VirtualizationProvider {
match ProcessorVendor::try_get_current() {
Err(_) => VirtualizationProvider::None,
Ok(ProcessorVendor::Intel) => {
if intel_vt_supported() {
VirtualizationProvider::IntelVTx
} else {
VirtualizationProvider::None
}
}
Ok(ProcessorVendor::AMD) => {
if amd_v_supported() {
VirtualizationProvider::AmdV
} else {
VirtualizationProvider::None
}
}
_ => VirtualizationProvider::None,
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT
use crate::arch::x86_64::cpuid::*;
pub fn intel_vt_supported() -> bool {
match ProcessorVendor::try_get_current() {
Ok(vendor) => match vendor == ProcessorVendor::Intel {
true => match CPUID.get_feature_info() {
Some(features) => features.has_vmx(),
None => false,
},
false => false,
},
Err(_) => false,
}
}

View File

@ -1,8 +1,11 @@
// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT
pub mod amd_virt;
pub mod asm;
pub mod cpuid;
pub mod gdt;
pub mod intel_virt;
pub mod interrupts;
pub mod paging;
pub mod serial;

View File

@ -34,6 +34,8 @@ use lazy_static::lazy_static;
use limine::firmware_type::FirmwareType;
use spin::mutex::Mutex;
use crate::arch::x86_64::{amd_virt, cpuid::{virt_supported, CPUID}};
lazy_static! {
pub static ref SERIAL_3F8: Mutex<SerialPort> =
Mutex::new(arch::x86_64::serial::SerialPort::new(0x3f8));
@ -137,16 +139,19 @@ unsafe extern "C" fn main() -> ! {
arch::x86_64::paging::get_mappings();
let cpuid = raw_cpuid::CpuId::new();
if let Some(string) = cpuid.get_processor_brand_string() {
if let Some(string) = CPUID.get_processor_brand_string() {
log_info!("CPU brand string: {}", string.as_str());
}
if let Some(string) = cpuid.get_vendor_info() {
if let Some(string) = CPUID.get_vendor_info() {
log_info!("CPU vendor: {}", string.as_str());
}
if let Some(string) = cpuid.get_hypervisor_info() {
if let Some(string) = CPUID.get_hypervisor_info() {
log_info!("Hypervisor: {:?}", string.identify());
}
log_info!("Virtualization provider: {:?}", virt_supported());
log_info!("AMD-V info: {}", CPUID.get_svm_info().unwrap().revision());
amd_virt::enable_svm();
loop {
arch::asm::nop();