This commit is contained in:
Masato Imai
2025-05-03 14:50:20 +00:00
parent 54712e2fe8
commit 570dd19af6
7 changed files with 355 additions and 21 deletions

12
Cargo.lock generated
View File

@ -107,6 +107,7 @@ dependencies = [
"pc-keyboard", "pc-keyboard",
"pic8259", "pic8259",
"rand", "rand",
"raw-cpuid 11.5.0",
"spin 0.5.2", "spin 0.5.2",
"uart_16550", "uart_16550",
"volatile 0.2.7", "volatile 0.2.7",
@ -253,6 +254,15 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "raw-cpuid"
version = "11.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146"
dependencies = [
"bitflags 2.9.0",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.20" version = "1.0.20"
@ -356,7 +366,7 @@ checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
dependencies = [ dependencies = [
"bit_field", "bit_field",
"bitflags 1.3.2", "bitflags 1.3.2",
"raw-cpuid", "raw-cpuid 10.7.0",
] ]
[[package]] [[package]]

View File

@ -16,6 +16,7 @@ x86 = "0.52.0"
bitfield = "0.19.0" bitfield = "0.19.0"
numeric-enum-macro = "0.2.0" numeric-enum-macro = "0.2.0"
rand = { version = "0.6.5", default-features = false } rand = { version = "0.6.5", default-features = false }
raw-cpuid = "11.5.0"
[dependencies.lazy_static] [dependencies.lazy_static]
version = "1.0" version = "1.0"

BIN
bzImage

Binary file not shown.

257
src/vmm/cpuid.rs Normal file
View File

@ -0,0 +1,257 @@
use raw_cpuid::cpuid;
use crate::info;
use super::{vcpu::VCpu, vmcs::VmxLeaf};
pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
let regs = &mut vcpu.guest_registers;
let vendor: &[u8; 12] = b"NelogikaNelo";
let vendor = unsafe { core::mem::transmute::<&[u8; 12], &[u32; 3]>(vendor) };
match VmxLeaf::from(regs.rax) {
VmxLeaf::MAXIMUM_INPUT => {
info!("CPUID max input");
regs.rax = 0x20;
regs.rbx = vendor[0] as u64;
regs.rcx = vendor[1] as u64;
regs.rdx = vendor[2] as u64;
}
VmxLeaf::VERSION_AND_FEATURE_INFO => {
info!("CPUID version and feature info");
let ecx = FeatureInfoEcx {
sse3: false,
pclmulqdq: false,
dtes64: false,
monitor: false,
ds_cpl: false,
vmx: false,
smx: false,
eist: false,
tm2: false,
ssse3: false,
cnxt_id: false,
sdbg: false,
fma: false,
cmpxchg16b: false,
xtpr: false,
pdcm: false,
_reserved_0: false,
pcid: true,
dca: false,
sse4_1: false,
sse4_2: false,
x2apic: false,
movbe: false,
popcnt: false,
tsc_deadline: false,
aesni: false,
xsave: false,
osxsave: false,
avx: false,
f16c: false,
rdrand: false,
hypervisor: false,
};
let edx = FeatureInfoEdx {
fpu: true,
vme: true,
de: true,
pse: true,
tsc: false,
msr: true,
pae: true,
mce: false,
cx8: true,
apic: false,
_reserved_0: false,
sep: true,
mtrr: false,
pge: true,
mca: false,
cmov: true,
pat: false,
pse36: true,
psn: false,
clfsh: false,
_reserved_1: false,
ds: false,
acpi: true,
mmx: false,
fxsr: true,
sse: false,
sse2: false,
ss: false,
htt: false,
tm: false,
_reserved_2: false,
pbe: false,
};
let cpuid = cpuid!(0x1, 0);
regs.rax = cpuid.eax as u64;
regs.rbx = cpuid.ebx as u64;
regs.rcx = ecx.to_u32() as u64;
regs.rdx = edx.to_u32() as u64;
}
_ => {
info!("Unhandled CPUID leaf: {:#x}", regs.rax);
invalid(vcpu);
}
};
}
fn invalid(vcpu: &mut VCpu) {
let regs = &mut vcpu.guest_registers;
regs.rax = 0;
regs.rbx = 0;
regs.rcx = 0;
regs.rdx = 0;
}
#[derive(Default)]
#[repr(C, packed)]
pub struct FeatureInfoEcx {
pub sse3: bool,
pub pclmulqdq: bool,
pub dtes64: bool,
pub monitor: bool,
pub ds_cpl: bool,
pub vmx: bool,
pub smx: bool,
pub eist: bool,
pub tm2: bool,
pub ssse3: bool,
pub cnxt_id: bool,
pub sdbg: bool,
pub fma: bool,
pub cmpxchg16b: bool,
pub xtpr: bool,
pub pdcm: bool,
pub _reserved_0: bool,
pub pcid: bool,
pub dca: bool,
pub sse4_1: bool,
pub sse4_2: bool,
pub x2apic: bool,
pub movbe: bool,
pub popcnt: bool,
pub tsc_deadline: bool,
pub aesni: bool,
pub xsave: bool,
pub osxsave: bool,
pub avx: bool,
pub f16c: bool,
pub rdrand: bool,
pub hypervisor: bool,
}
impl FeatureInfoEcx {
pub fn to_u32(&self) -> u32 {
(self.sse3 as u32) << 0
| (self.pclmulqdq as u32) << 1
| (self.dtes64 as u32) << 2
| (self.monitor as u32) << 3
| (self.ds_cpl as u32) << 4
| (self.vmx as u32) << 5
| (self.smx as u32) << 6
| (self.eist as u32) << 7
| (self.tm2 as u32) << 8
| (self.ssse3 as u32) << 9
| (self.cnxt_id as u32) << 10
| (self.sdbg as u32) << 11
| (self.fma as u32) << 12
| (self.cmpxchg16b as u32) << 13
| (self.xtpr as u32) << 14
| (self.pdcm as u32) << 15
| (self._reserved_0 as u32) << 16
| (self.pcid as u32) << 17
| (self.dca as u32) << 18
| (self.sse4_1 as u32) << 19
| (self.sse4_2 as u32) << 20
| (self.x2apic as u32) << 21
| (self.movbe as u32) << 22
| (self.popcnt as u32) << 23
| (self.tsc_deadline as u32) << 24
| (self.aesni as u32) << 25
| (self.xsave as u32) << 26
| (self.osxsave as u32) << 27
| (self.avx as u32) << 28
| (self.f16c as u32) << 29
| (self.rdrand as u32) << 30
| (self.hypervisor as u32) << 31
}
}
#[derive(Default)]
#[repr(C, packed)]
pub struct FeatureInfoEdx {
pub fpu: bool,
pub vme: bool,
pub de: bool,
pub pse: bool,
pub tsc: bool,
pub msr: bool,
pub pae: bool,
pub mce: bool,
pub cx8: bool,
pub apic: bool,
pub _reserved_0: bool,
pub sep: bool,
pub mtrr: bool,
pub pge: bool,
pub mca: bool,
pub cmov: bool,
pub pat: bool,
pub pse36: bool,
pub psn: bool,
pub clfsh: bool,
pub _reserved_1: bool,
pub ds: bool,
pub acpi: bool,
pub mmx: bool,
pub fxsr: bool,
pub sse: bool,
pub sse2: bool,
pub ss: bool,
pub htt: bool,
pub tm: bool,
pub _reserved_2: bool,
pub pbe: bool,
}
impl FeatureInfoEdx {
pub fn to_u32(&self) -> u32 {
(self.fpu as u32) << 0
| (self.vme as u32) << 1
| (self.de as u32) << 2
| (self.pse as u32) << 3
| (self.tsc as u32) << 4
| (self.msr as u32) << 5
| (self.pae as u32) << 6
| (self.mce as u32) << 7
| (self.cx8 as u32) << 8
| (self.apic as u32) << 9
| (self._reserved_0 as u32) << 10
| (self.sep as u32) << 11
| (self.mtrr as u32) << 12
| (self.pge as u32) << 13
| (self.mca as u32) << 14
| (self.cmov as u32) << 15
| (self.pat as u32) << 16
| (self.pse36 as u32) << 17
| (self.psn as u32) << 18
| (self.clfsh as u32) << 19
| (self._reserved_1 as u32) << 20
| (self.ds as u32) << 21
| (self.acpi as u32) << 22
| (self.mmx as u32) << 23
| (self.fxsr as u32) << 24
| (self.sse as u32) << 25
| (self.sse2 as u32) << 26
| (self.ss as u32) << 27
| (self.htt as u32) << 28
| (self.tm as u32) << 29
| (self._reserved_2 as u32) << 30
| (self.pbe as u32) << 31
}
}

View File

@ -1,4 +1,5 @@
pub mod asm; pub mod asm;
pub mod cpuid;
pub mod ept; pub mod ept;
pub mod error; pub mod error;
pub mod linux; pub mod linux;

View File

@ -11,10 +11,13 @@ use x86_64::VirtAddr;
use crate::{ use crate::{
info, info,
memory::BootInfoFrameAllocator, memory::BootInfoFrameAllocator,
vmm::vmcs::{ vmm::{
DescriptorType, EntryControls, Granularity, PrimaryExitControls, cpuid,
PrimaryProcessorBasedVmExecutionControls, SecondaryProcessorBasedVmExecutionControls, vmcs::{
SegmentRights, VmxExitInfo, VmxExitReason, DescriptorType, EntryControls, Granularity, PrimaryExitControls,
PrimaryProcessorBasedVmExecutionControls, SecondaryProcessorBasedVmExecutionControls,
SegmentRights, VmxExitInfo, VmxExitReason,
},
}, },
}; };
@ -215,7 +218,7 @@ impl VCpu {
primary_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32; primary_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
primary_exec_ctrl.0 &= (reserved_bits >> 32) as u32; primary_exec_ctrl.0 &= (reserved_bits >> 32) as u32;
primary_exec_ctrl.set_hlt(true); primary_exec_ctrl.set_hlt(false);
primary_exec_ctrl.set_activate_secondary_controls(true); primary_exec_ctrl.set_activate_secondary_controls(true);
primary_exec_ctrl.write(); primary_exec_ctrl.write();
@ -256,6 +259,8 @@ impl VCpu {
entry_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32; entry_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
entry_ctrl.0 &= (reserved_bits >> 32) as u32; entry_ctrl.0 &= (reserved_bits >> 32) as u32;
entry_ctrl.set_ia32e_mode_guest(false); entry_ctrl.set_ia32e_mode_guest(false);
entry_ctrl.set_load_ia32_efer(true);
entry_ctrl.set_load_ia32_pat(true);
entry_ctrl.write(); entry_ctrl.write();
@ -279,6 +284,9 @@ impl VCpu {
exit_ctrl.0 &= (reserved_bits >> 32) as u32; exit_ctrl.0 &= (reserved_bits >> 32) as u32;
exit_ctrl.set_host_addr_space_size(true); exit_ctrl.set_host_addr_space_size(true);
exit_ctrl.set_load_ia32_efer(true); exit_ctrl.set_load_ia32_efer(true);
exit_ctrl.set_save_ia32_efer(true);
exit_ctrl.set_load_ia32_pat(true);
exit_ctrl.set_save_ia32_pat(true);
exit_ctrl.write(); exit_ctrl.write();
@ -355,8 +363,6 @@ impl VCpu {
vmwrite(vmcs::guest::SS_BASE, 0)?; vmwrite(vmcs::guest::SS_BASE, 0)?;
vmwrite(vmcs::guest::DS_BASE, 0)?; vmwrite(vmcs::guest::DS_BASE, 0)?;
vmwrite(vmcs::guest::ES_BASE, 0)?; vmwrite(vmcs::guest::ES_BASE, 0)?;
vmwrite(vmcs::guest::FS_BASE, 0)?;
vmwrite(vmcs::guest::GS_BASE, 0)?;
vmwrite(vmcs::guest::TR_BASE, 0)?; vmwrite(vmcs::guest::TR_BASE, 0)?;
vmwrite(vmcs::guest::GDTR_BASE, 0)?; vmwrite(vmcs::guest::GDTR_BASE, 0)?;
vmwrite(vmcs::guest::IDTR_BASE, 0)?; vmwrite(vmcs::guest::IDTR_BASE, 0)?;
@ -373,15 +379,6 @@ impl VCpu {
vmwrite(vmcs::guest::IDTR_LIMIT, 0)?; vmwrite(vmcs::guest::IDTR_LIMIT, 0)?;
vmwrite(vmcs::guest::LDTR_LIMIT, 0)?; vmwrite(vmcs::guest::LDTR_LIMIT, 0)?;
vmwrite(vmcs::guest::CS_SELECTOR, 0)?;
vmwrite(vmcs::guest::SS_SELECTOR, 0)?;
vmwrite(vmcs::guest::DS_SELECTOR, 0)?;
vmwrite(vmcs::guest::ES_SELECTOR, 0)?;
vmwrite(vmcs::guest::FS_SELECTOR, 0)?;
vmwrite(vmcs::guest::GS_SELECTOR, 0)?;
vmwrite(vmcs::guest::TR_SELECTOR, 0)?;
vmwrite(vmcs::guest::LDTR_SELECTOR, 0)?;
let cs_right = { let cs_right = {
let mut rights = SegmentRights::default(); let mut rights = SegmentRights::default();
rights.set_rw(true); rights.set_rw(true);
@ -448,7 +445,19 @@ impl VCpu {
vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, tr_right.0 as u64)?; vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, tr_right.0 as u64)?;
vmwrite(vmcs::guest::LDTR_ACCESS_RIGHTS, ldtr_right.0 as u64)?; vmwrite(vmcs::guest::LDTR_ACCESS_RIGHTS, ldtr_right.0 as u64)?;
vmwrite(vmcs::guest::CS_SELECTOR, 0)?;
vmwrite(vmcs::guest::SS_SELECTOR, 0)?;
vmwrite(vmcs::guest::DS_SELECTOR, 0)?;
vmwrite(vmcs::guest::ES_SELECTOR, 0)?;
vmwrite(vmcs::guest::FS_SELECTOR, 0)?;
vmwrite(vmcs::guest::GS_SELECTOR, 0)?;
vmwrite(vmcs::guest::TR_SELECTOR, 0)?;
vmwrite(vmcs::guest::LDTR_SELECTOR, 0)?;
vmwrite(vmcs::guest::FS_BASE, 0)?;
vmwrite(vmcs::guest::GS_BASE, 0)?;
vmwrite(vmcs::guest::IA32_EFER_FULL, 0)?; vmwrite(vmcs::guest::IA32_EFER_FULL, 0)?;
vmwrite(vmcs::guest::IA32_EFER_HIGH, 0)?;
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)?;
@ -477,9 +486,29 @@ impl VCpu {
} }
} }
fn print_guest_regs(&self) {
info!("Guest Registers:");
info!("RAX: {:#x}", self.guest_registers.rax);
info!("RBX: {:#x}", self.guest_registers.rbx);
info!("RCX: {:#x}", self.guest_registers.rcx);
info!("RDX: {:#x}", self.guest_registers.rdx);
info!("RSI: {:#x}", self.guest_registers.rsi);
info!("RDI: {:#x}", self.guest_registers.rdi);
info!("RBP: {:#x}", self.guest_registers.rbp);
info!("R8: {:#x}", self.guest_registers.r8);
info!("R9: {:#x}", self.guest_registers.r9);
info!("R10: {:#x}", self.guest_registers.r10);
info!("R11: {:#x}", self.guest_registers.r11);
info!("R12: {:#x}", self.guest_registers.r12);
info!("R13: {:#x}", self.guest_registers.r13);
info!("R14: {:#x}", self.guest_registers.r14);
info!("R15: {:#x}", self.guest_registers.r15);
}
fn vmentry(&mut self) -> Result<(), InstructionError> { fn vmentry(&mut self) -> Result<(), InstructionError> {
let success = { let success = {
let result: u16; let result: u16;
self.print_guest_regs();
if !self.launch_done { if !self.launch_done {
unsafe { unsafe {
result = crate::vmm::asm::asm_vm_entry(self as *mut _); result = crate::vmm::asm::asm_vm_entry(self as *mut _);
@ -512,6 +541,16 @@ impl VCpu {
vmwrite(vmcs::host::RSP, rsp).unwrap(); vmwrite(vmcs::host::RSP, rsp).unwrap();
} }
fn step_next_inst(&mut self) -> Result<(), VmFail> {
unsafe {
let rip = vmread(vmcs::guest::RIP)?;
vmwrite(
vmcs::guest::RIP,
rip + vmread(vmcs::ro::VMEXIT_INSTRUCTION_LEN)?,
)
}
}
fn vmexit_handler(&mut self) { fn vmexit_handler(&mut self) {
let info = VmxExitInfo::read(); let info = VmxExitInfo::read();
@ -530,14 +569,16 @@ impl VCpu {
_ => {} _ => {}
} }
} else { } else {
info!( info!("RIP: {:#x}", unsafe { vmread(vmcs::guest::RIP) }.unwrap());
"vcpu RIP: {:#x}",
unsafe { vmread(vmcs::guest::RIP) }.unwrap()
);
match info.get_reason() { match info.get_reason() {
VmxExitReason::HLT => { VmxExitReason::HLT => {
info!("HLT instruction executed"); info!("HLT instruction executed");
} }
VmxExitReason::CPUID => {
info!("CPUID instruction executed");
cpuid::handle_cpuid_exit(self);
self.step_next_inst().unwrap();
}
_ => { _ => {
panic!("VMExit reason: {:?}", info.get_reason()); panic!("VMExit reason: {:?}", info.get_reason());
} }

View File

@ -629,3 +629,27 @@ impl VmxExitInfo {
reason.try_into().unwrap() reason.try_into().unwrap()
} }
} }
pub enum VmxLeaf {
MAXIMUM_INPUT = 0x0,
VERSION_AND_FEATURE_INFO = 0x1,
EXTENDED_FEATURE = 0x7,
EXTENDED_ENUMERATION = 0xD,
EXTENDED_FUNCTION = 0x80000000,
EXTENDED_PROCESSOR_SIGNATURE = 0x80000001,
UNKNOWN = 0xFFFFFFFF,
}
impl VmxLeaf {
pub fn from(rax: u64) -> VmxLeaf {
match rax {
0x0 => VmxLeaf::MAXIMUM_INPUT,
0x1 => VmxLeaf::VERSION_AND_FEATURE_INFO,
0x7 => VmxLeaf::EXTENDED_FEATURE,
0xD => VmxLeaf::EXTENDED_ENUMERATION,
0x80000000 => VmxLeaf::EXTENDED_FUNCTION,
0x80000001 => VmxLeaf::EXTENDED_PROCESSOR_SIGNATURE,
_ => VmxLeaf::UNKNOWN,
}
}
}