mirror of
https://github.com/mii443/nel_os.git
synced 2025-08-22 16:15:38 +00:00
fix kernel panic
This commit is contained in:
@ -30,6 +30,11 @@ macro_rules! info {
|
||||
($($arg:tt)*) => ($crate::print!("[info] {}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => ($crate::print!("[error] {}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
|
@ -1,17 +1,48 @@
|
||||
use crate::info;
|
||||
use raw_cpuid::cpuid;
|
||||
|
||||
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"miHypervisor";
|
||||
let vendor: &[u8; 12] = b"KVMKVMKVMKVM";
|
||||
let vendor: &[u8; 12] = b"miHypervisor";
|
||||
|
||||
let vendor = unsafe { core::mem::transmute::<&[u8; 12], &[u32; 3]>(vendor) };
|
||||
|
||||
match VmxLeaf::from(regs.rax) {
|
||||
VmxLeaf::EXTENDED_ENUMERATION => {
|
||||
info!("CPUID: {:#x}.{:#x}", regs.rax, regs.rcx);
|
||||
match regs.rcx {
|
||||
0 => {
|
||||
// EAX: supported XSAVE features (x87=bit0, SSE=bit1)
|
||||
regs.rax = 0b11; // Only x87 and SSE supported
|
||||
regs.rbx = 576; // Size required for enabled features
|
||||
regs.rcx = 576; // Size required for all features
|
||||
regs.rdx = 0x00000000;
|
||||
}
|
||||
1 => {
|
||||
// EAX: XSAVEOPT and extended features
|
||||
regs.rax = 0x00000001; // XSAVEOPT supported
|
||||
regs.rbx = 0; // Size of enabled features in compacted format
|
||||
regs.rcx = 0; // Lower 32 bits of XCR0 | IA32_XSS
|
||||
regs.rdx = 0; // Upper 32 bits of XCR0 | IA32_XSS
|
||||
}
|
||||
2 => {
|
||||
// x87 state component
|
||||
regs.rax = 512; // Size of x87 state
|
||||
regs.rbx = 0; // Offset in save area
|
||||
regs.rcx = 0; // Not used for legacy components
|
||||
regs.rdx = 0; // Not used for legacy components
|
||||
}
|
||||
_ => {
|
||||
invalid(vcpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
VmxLeaf::EXTENDED_FEATURE => match regs.rcx {
|
||||
0 => {
|
||||
let mut ebx = ExtFeatureEbx0::default();
|
||||
ebx.fsgsbase = false;
|
||||
ebx.smep = true;
|
||||
ebx.invpcid = false;
|
||||
ebx.smap = true;
|
||||
@ -70,15 +101,15 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
|
||||
_reserved_0: false,
|
||||
pcid: true,
|
||||
dca: false,
|
||||
sse4_1: false,
|
||||
sse4_2: false,
|
||||
sse4_1: true,
|
||||
sse4_2: true,
|
||||
x2apic: false,
|
||||
movbe: false,
|
||||
popcnt: false,
|
||||
tsc_deadline: false,
|
||||
aesni: false,
|
||||
xsave: false,
|
||||
osxsave: false,
|
||||
xsave: true,
|
||||
osxsave: true,
|
||||
avx: false,
|
||||
f16c: false,
|
||||
rdrand: false,
|
||||
@ -94,7 +125,7 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
|
||||
pae: true,
|
||||
mce: false,
|
||||
cx8: true,
|
||||
apic: false,
|
||||
apic: true,
|
||||
_reserved_0: false,
|
||||
sep: true,
|
||||
mtrr: false,
|
||||
@ -118,9 +149,14 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
|
||||
_reserved_2: false,
|
||||
pbe: false,
|
||||
};
|
||||
let cpuid = cpuid!(0x1, 0);
|
||||
regs.rax = cpuid.eax as u64;
|
||||
regs.rbx = cpuid.ebx as u64;
|
||||
let mut version_and_feature_info = cpuid!(0x1, 0);
|
||||
let feature = cpuid!(0x0, 0);
|
||||
if !((feature.ecx & (1 << 17)) == 1) {
|
||||
version_and_feature_info.ecx &= !(1 << 17);
|
||||
}
|
||||
|
||||
regs.rax = version_and_feature_info.eax as u64;
|
||||
regs.rbx = version_and_feature_info.ebx as u64;
|
||||
regs.rcx = ecx.to_u32() as u64;
|
||||
regs.rdx = edx.to_u32() as u64;
|
||||
}
|
||||
@ -132,6 +168,7 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
|
||||
|
||||
fn invalid(vcpu: &mut VCpu) {
|
||||
let regs = &mut vcpu.guest_registers;
|
||||
//info!("Invalid CPUID: {:#x}.{:#x}", regs.rax, regs.rcx);
|
||||
|
||||
regs.rax = 0;
|
||||
regs.rbx = 0;
|
||||
|
@ -6,8 +6,6 @@ use x86::{
|
||||
vmx::vmcs,
|
||||
};
|
||||
|
||||
use crate::info;
|
||||
|
||||
use super::{
|
||||
qual::{AccessType, QualCr, Register},
|
||||
vcpu::VCpu,
|
||||
|
75
src/vmm/fpu.rs
Normal file
75
src/vmm/fpu.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use bitfield::bitfield;
|
||||
|
||||
use crate::{error, info};
|
||||
|
||||
use super::vcpu::VCpu;
|
||||
|
||||
bitfield! {
|
||||
pub struct XCR0(u64);
|
||||
|
||||
pub x87, set_x87: 0, 1;
|
||||
pub sse, set_sse: 1, 1;
|
||||
pub avx, set_avx: 2, 1;
|
||||
pub bndreg, set_bndreg: 3, 1;
|
||||
pub bndcsr, set_bndcsr: 4, 1;
|
||||
pub opmask, set_opmask: 5, 1;
|
||||
pub zmm_hi256, set_zmm_hi256: 6, 1;
|
||||
pub hi16_zmm, set_hi16_zmm: 7, 1;
|
||||
pub pt, set_pt: 8, 1;
|
||||
pub pkru, set_pkru: 9, 1;
|
||||
pub pasid, set_pasid: 10, 1;
|
||||
pub cet_u, set_cet_u: 11, 1;
|
||||
pub cet_s, set_cet_s: 12, 1;
|
||||
pub hdc, set_hdc: 13, 1;
|
||||
pub intr, set_intr: 14, 1;
|
||||
pub lbr, set_lbr: 15, 1;
|
||||
pub hwp, set_hwp: 16, 1;
|
||||
pub xtilecfg, set_xtilecfg: 17, 1;
|
||||
pub xtiledata, set_xtiledata: 18, 1;
|
||||
pub apx, set_apx: 19, 1;
|
||||
pub reserved, set_reserved: 20, 44;
|
||||
}
|
||||
|
||||
pub fn set_xcr(vcpu: &mut VCpu, index: u32, xcr: u64) -> Result<(), ()> {
|
||||
info!("Setting XCR0: index={}, xcr={:x}", index, xcr);
|
||||
if index != 0 {
|
||||
error!("Invalid XCR index: {}", index);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if !(xcr & 0b1 != 0) {
|
||||
error!("X87 is not enabled");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if (xcr & 0b100 != 0) && !(xcr & 0b10 != 0) {
|
||||
error!("SSE is not enabled");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if !(xcr & 0b1000) != (!(xcr & 0b10000)) {
|
||||
error!("BNDREGS and BNDCSR are not both enabled");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if xcr & 0b11100000 != 0 {
|
||||
if !(xcr & 0b100 != 0) {
|
||||
error!("YMM bits are not enabled");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if (xcr & 0b11100000) != 0b11100000 {
|
||||
error!("Invalid bits set in XCR0");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
if (xcr & 0b1000000000000 != 0) && (xcr & 0b1000000000000 != 0b1000000000000) {
|
||||
error!("xtile bits are not both enabled");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
vcpu.xcr0 = XCR0(xcr);
|
||||
|
||||
Ok(())
|
||||
}
|
@ -3,6 +3,7 @@ pub mod cpuid;
|
||||
pub mod cr;
|
||||
pub mod ept;
|
||||
pub mod error;
|
||||
pub mod fpu;
|
||||
pub mod linux;
|
||||
pub mod msr;
|
||||
pub mod qual;
|
||||
|
@ -128,7 +128,7 @@ impl ShadowMsr {
|
||||
}
|
||||
x86::msr::IA32_KERNEL_GSBASE => Self::shadow_read(vcpu, msr_kind),
|
||||
_ => {
|
||||
panic!("Unhandled RDMSR: {}", msr_kind);
|
||||
panic!("Unhandled RDMSR: {:#x}", msr_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,6 +145,7 @@ impl ShadowMsr {
|
||||
x86::msr::IA32_TSC_AUX => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::IA32_FMASK => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::IA32_KERNEL_GSBASE => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::MSR_C5_PMON_BOX_CTRL => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::SYSENTER_CS_MSR => unsafe {
|
||||
vmwrite(vmcs::guest::IA32_SYSENTER_CS, value).unwrap()
|
||||
},
|
||||
@ -157,8 +158,9 @@ impl ShadowMsr {
|
||||
x86::msr::IA32_EFER => unsafe { vmwrite(vmcs::guest::IA32_EFER_FULL, value).unwrap() },
|
||||
x86::msr::IA32_FS_BASE => unsafe { vmwrite(vmcs::guest::FS_BASE, value).unwrap() },
|
||||
x86::msr::IA32_GS_BASE => unsafe { vmwrite(vmcs::guest::GS_BASE, value).unwrap() },
|
||||
|
||||
_ => {
|
||||
panic!("Unhandled WRMSR: {}", msr_kind);
|
||||
panic!("Unhandled WRMSR: {:#x}", msr_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,3 +125,16 @@ impl QualCr {
|
||||
self.set_register_raw(val as u8);
|
||||
}
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct QualIo(u64);
|
||||
impl Debug;
|
||||
|
||||
u8, size, set_size: 3, 0;
|
||||
u8, direction, set_direction: 4, 4;
|
||||
u8, string, set_string: 5, 5;
|
||||
u8, rep, set_rep: 6, 6;
|
||||
u8, operand_encoding, set_operand_encoding: 7, 7;
|
||||
u16, port, set_port: 31, 16;
|
||||
}
|
||||
|
100
src/vmm/vcpu.rs
100
src/vmm/vcpu.rs
@ -1,4 +1,7 @@
|
||||
use core::u64;
|
||||
use core::{
|
||||
arch::x86_64::{_xgetbv, _xsetbv},
|
||||
u64,
|
||||
};
|
||||
|
||||
use x86::{
|
||||
bits64::vmx::{vmread, vmwrite},
|
||||
@ -13,7 +16,7 @@ use crate::{
|
||||
info,
|
||||
memory::BootInfoFrameAllocator,
|
||||
vmm::{
|
||||
cpuid, cr, msr,
|
||||
cpuid, cr, fpu, msr,
|
||||
qual::QualCr,
|
||||
vmcs::{
|
||||
DescriptorType, EntryControls, Granularity, PrimaryExitControls,
|
||||
@ -25,6 +28,7 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
ept::{EPT, EPTP},
|
||||
fpu::XCR0,
|
||||
linux::{self, BootParams, E820Type},
|
||||
msr::ShadowMsr,
|
||||
register::GuestRegisters,
|
||||
@ -44,6 +48,8 @@ pub struct VCpu {
|
||||
pub host_msr: ShadowMsr,
|
||||
pub guest_msr: ShadowMsr,
|
||||
pub ia32e_enabled: bool,
|
||||
pub xcr0: XCR0,
|
||||
pub host_xcr0: u64,
|
||||
}
|
||||
|
||||
const TEMP_STACK_SIZE: usize = 4096;
|
||||
@ -68,6 +74,8 @@ impl VCpu {
|
||||
host_msr: ShadowMsr::new(),
|
||||
guest_msr: ShadowMsr::new(),
|
||||
ia32e_enabled: false,
|
||||
xcr0: XCR0(3),
|
||||
host_xcr0: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,6 +208,9 @@ impl VCpu {
|
||||
rdmsr(x86::msr::IA32_KERNEL_GSBASE) as u64,
|
||||
)
|
||||
.unwrap();
|
||||
self.host_msr
|
||||
.set(x86::msr::MSR_C5_PMON_BOX_CTRL, 0)
|
||||
.unwrap();
|
||||
|
||||
self.guest_msr.set(x86::msr::IA32_TSC_AUX, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_STAR, 0).unwrap();
|
||||
@ -207,6 +218,9 @@ impl VCpu {
|
||||
self.guest_msr.set(x86::msr::IA32_CSTAR, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_FMASK, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_KERNEL_GSBASE, 0).unwrap();
|
||||
self.guest_msr
|
||||
.set(x86::msr::MSR_C5_PMON_BOX_CTRL, 0)
|
||||
.unwrap();
|
||||
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_LOAD_ADDR_FULL,
|
||||
@ -286,10 +300,11 @@ impl VCpu {
|
||||
|
||||
primary_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) 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_use_tpr_shadow(true);
|
||||
primary_exec_ctrl.set_use_msr_bitmap(false);
|
||||
primary_exec_ctrl.set_unconditional_io(true);
|
||||
|
||||
primary_exec_ctrl.write();
|
||||
|
||||
@ -365,6 +380,14 @@ impl VCpu {
|
||||
|
||||
exit_ctrl.write();
|
||||
|
||||
unsafe {
|
||||
vmwrite(
|
||||
vmcs::control::EXCEPTION_BITMAP,
|
||||
0, /*(1u64 << irq::INVALID_OPCODE_VECTOR)*/
|
||||
)
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -373,7 +396,10 @@ impl VCpu {
|
||||
unsafe {
|
||||
vmwrite(vmcs::host::CR0, cr0().bits() as u64)?;
|
||||
vmwrite(vmcs::host::CR3, cr3())?;
|
||||
vmwrite(vmcs::host::CR4, cr4().bits() as u64)?;
|
||||
vmwrite(
|
||||
vmcs::host::CR4,
|
||||
cr4().bits() as u64 | Cr4Flags::OSXSAVE.bits(),
|
||||
)?;
|
||||
|
||||
vmwrite(vmcs::host::RIP, crate::vmm::asm::asm_vmexit_handler as u64)?;
|
||||
vmwrite(
|
||||
@ -433,10 +459,7 @@ impl VCpu {
|
||||
vmwrite(vmcs::guest::CR3, cr3())?;
|
||||
vmwrite(
|
||||
vmcs::guest::CR4,
|
||||
vmread(vmcs::guest::CR4)?
|
||||
| 1 << 5
|
||||
| 1 << 7
|
||||
| Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits(),
|
||||
vmread(vmcs::guest::CR4)? | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits(),
|
||||
)?;
|
||||
|
||||
vmwrite(vmcs::guest::CS_BASE, 0)?;
|
||||
@ -570,13 +593,57 @@ impl VCpu {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_guest_xcr0(&mut self) -> Result<(), VmFail> {
|
||||
let host_cr4 = unsafe { cr4() };
|
||||
if (host_cr4.bits() & Cr4Flags::OSXSAVE.bits() as usize) == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.host_xcr0 == 0 {
|
||||
self.host_xcr0 = unsafe { _xgetbv(0) };
|
||||
}
|
||||
|
||||
let guest_cr4 = unsafe { vmread(vmcs::guest::CR4)? };
|
||||
|
||||
if guest_cr4 & Cr4Flags::OSXSAVE.bits() != 0 && self.xcr0.0 != self.host_xcr0 {
|
||||
unsafe {
|
||||
_xsetbv(0, self.xcr0.0);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_host_xcr0(&mut self) -> Result<(), VmFail> {
|
||||
let host_cr4 = unsafe { cr4() };
|
||||
if (host_cr4.bits() & Cr4Flags::OSXSAVE.bits() as usize) == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let guest_cr4 = unsafe { vmread(vmcs::guest::CR4)? };
|
||||
|
||||
if guest_cr4 & Cr4Flags::OSXSAVE.bits() != 0 {
|
||||
let current_xcr0 = unsafe { _xgetbv(0) };
|
||||
if current_xcr0 != self.host_xcr0 {
|
||||
self.xcr0 = XCR0(current_xcr0);
|
||||
unsafe {
|
||||
_xsetbv(0, self.host_xcr0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vmentry(&mut self) -> Result<(), InstructionError> {
|
||||
let success = {
|
||||
let result: u16;
|
||||
|
||||
self.load_guest_xcr0().unwrap();
|
||||
unsafe {
|
||||
result = crate::vmm::asm::asm_vm_entry(self as *mut _);
|
||||
};
|
||||
self.load_host_xcr0().unwrap();
|
||||
result == 0
|
||||
};
|
||||
|
||||
@ -627,6 +694,7 @@ impl VCpu {
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
info!("RIP: {:#x}", unsafe { vmread(vmcs::guest::RIP) }.unwrap());
|
||||
match info.get_reason() {
|
||||
VmxExitReason::HLT => {
|
||||
info!("HLT instruction executed");
|
||||
@ -649,6 +717,22 @@ impl VCpu {
|
||||
cr::handle_cr_access(self, &qual);
|
||||
self.step_next_inst().unwrap();
|
||||
}
|
||||
VmxExitReason::XSETBV => {
|
||||
fpu::set_xcr(
|
||||
self,
|
||||
self.guest_registers.rcx as u32,
|
||||
self.guest_registers.rax,
|
||||
)
|
||||
.unwrap();
|
||||
self.step_next_inst().unwrap();
|
||||
}
|
||||
VmxExitReason::EXCEPTION => {
|
||||
self.step_next_inst().unwrap();
|
||||
}
|
||||
VmxExitReason::IO_INSTRUCTION => {
|
||||
info!("IO instruction executed");
|
||||
self.step_next_inst().unwrap();
|
||||
}
|
||||
_ => {
|
||||
panic!("VMExit reason: {:?}", info.get_reason());
|
||||
}
|
||||
|
Reference in New Issue
Block a user