qual, cr
Some checks failed
Check / Build ISO (nightly-2025-04-27) (push) Failing after 45s

This commit is contained in:
Masato Imai
2025-08-22 09:01:32 +00:00
parent a0a204b43c
commit 4a44cdea8d
4 changed files with 294 additions and 0 deletions

View File

@ -0,0 +1,166 @@
use x86::vmx::vmcs;
use crate::vmm::x86_64::{
common::read_msr,
intel::{
qual::{AccessType, QualCr, Register},
vcpu::IntelVCpu,
vmread, vmwrite,
},
};
pub fn handle_cr_access(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<(), &'static str> {
match AccessType::try_from(qual.access_type()).unwrap() {
AccessType::MovTo => match qual.index() {
0 | 4 => {
passthrough_write(vcpu, qual);
update_ia32e(vcpu);
}
_ => panic!("Unsupported CR index: {}", qual.index()),
},
AccessType::MovFrom => passthrough_read(vcpu, qual)?,
_ => {
panic!("Unsupported CR access type: {:?}", qual.access_type());
}
}
Ok(())
}
fn passthrough_read(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<(), &'static str> {
let value = match qual.index() {
3 => vmread(x86::vmx::vmcs::guest::CR3)?,
_ => panic!("Unsupported CR index: {}", qual.index()),
};
set_value(vcpu, qual, value);
Ok(())
}
fn passthrough_write(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<(), &'static str> {
let value = get_value(vcpu, qual)?;
match qual.index() {
0 => {
vmwrite(vmcs::guest::CR0, adjust_cr0(value))?;
vmwrite(vmcs::control::CR0_READ_SHADOW, value)?;
}
4 => {
vmwrite(vmcs::guest::CR4, adjust_cr4(value))?;
vmwrite(vmcs::control::CR4_READ_SHADOW, value)?;
}
_ => {
panic!("Unsupported CR index: {}", qual.index());
}
}
Ok(())
}
pub fn update_ia32e(vcpu: &mut IntelVCpu) -> Result<(), &'static str> {
let cr0 = vmread(x86::vmx::vmcs::guest::CR0)?;
let cr4 = vmread(x86::vmx::vmcs::guest::CR4)?;
let ia32e_enabled = (cr0 & 1 << 31) != 0 && (cr4 & 1 << 5) != 0;
vcpu.ia32e_enabled = ia32e_enabled;
let mut entry_ctrl = super::vmcs::controls::EntryControls::read()?;
entry_ctrl.set_ia32e_mode_guest(ia32e_enabled);
entry_ctrl.write();
let mut efer = vmread(x86::vmx::vmcs::guest::IA32_EFER_FULL)?;
let lma = (vcpu.ia32e_enabled as u64) << 10;
if lma != 0 {
efer |= lma;
} else {
efer &= !lma;
}
let lme = if cr0 & (1 << 31) != 0 {
efer & (1 << 10)
} else {
efer & !(1 << 8)
};
if lme != 0 {
efer |= lme;
} else {
efer &= lme;
}
vmwrite(x86::vmx::vmcs::guest::IA32_EFER_FULL, efer)?;
Ok(())
}
pub fn adjust_cr0(value: u64) -> u64 {
let mut result = value;
let cr0_fixed0 = read_msr(x86::msr::IA32_VMX_CR0_FIXED0);
let cr0_fixed1 = read_msr(x86::msr::IA32_VMX_CR0_FIXED1);
result |= cr0_fixed0;
result &= cr0_fixed1;
result
}
pub fn adjust_cr4(value: u64) -> u64 {
let mut result = value;
let cr4_fixed0 = read_msr(x86::msr::IA32_VMX_CR4_FIXED0);
let cr4_fixed1 = read_msr(x86::msr::IA32_VMX_CR4_FIXED1);
result |= cr4_fixed0;
result &= cr4_fixed1;
result
}
fn set_value(vcpu: &mut IntelVCpu, qual: &QualCr, value: u64) -> Result<(), &'static str> {
let guest_regs = &mut vcpu.guest_registers;
match qual.register() {
Register::Rax => guest_regs.rax = value,
Register::Rcx => guest_regs.rcx = value,
Register::Rdx => guest_regs.rdx = value,
Register::Rbx => guest_regs.rbx = value,
Register::Rbp => guest_regs.rbp = value,
Register::Rsi => guest_regs.rsi = value,
Register::Rdi => guest_regs.rdi = value,
Register::R8 => guest_regs.r8 = value,
Register::R9 => guest_regs.r9 = value,
Register::R10 => guest_regs.r10 = value,
Register::R11 => guest_regs.r11 = value,
Register::R12 => guest_regs.r12 = value,
Register::R13 => guest_regs.r13 = value,
Register::R14 => guest_regs.r14 = value,
Register::R15 => guest_regs.r15 = value,
Register::Rsp => vmwrite(x86::vmx::vmcs::guest::RSP, value)?,
}
Ok(())
}
fn get_value(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<u64, &'static str> {
let guest_regs = &mut vcpu.guest_registers;
Ok(match qual.register() {
Register::Rax => guest_regs.rax,
Register::Rcx => guest_regs.rcx,
Register::Rdx => guest_regs.rdx,
Register::Rbx => guest_regs.rbx,
Register::Rbp => guest_regs.rbp,
Register::Rsi => guest_regs.rsi,
Register::Rdi => guest_regs.rdi,
Register::R8 => guest_regs.r8,
Register::R9 => guest_regs.r9,
Register::R10 => guest_regs.r10,
Register::R11 => guest_regs.r11,
Register::R12 => guest_regs.r12,
Register::R13 => guest_regs.r13,
Register::R14 => guest_regs.r14,
Register::R15 => guest_regs.r15,
Register::Rsp => vmread(x86::vmx::vmcs::guest::RSP)?,
})
}

View File

@ -2,8 +2,10 @@ pub mod asm;
mod auditor; mod auditor;
mod controls; mod controls;
mod cpuid; mod cpuid;
mod cr;
mod ept; mod ept;
mod msr; mod msr;
mod qual;
mod register; mod register;
pub mod vcpu; pub mod vcpu;
mod vmcs; mod vmcs;

View File

@ -0,0 +1,124 @@
#![allow(non_snake_case)]
use core::convert::TryFrom;
use core::fmt::Debug;
use modular_bitfield::prelude::{B1, B16, B32, B4, B8};
use modular_bitfield::{bitfield, Specifier};
#[repr(u8)]
#[derive(Specifier, Debug, Clone, Copy, PartialEq, Eq)]
pub enum AccessType {
MovTo = 0,
MovFrom = 1,
Clts = 2,
Lmsw = 3,
}
impl TryFrom<u8> for AccessType {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(AccessType::MovTo),
1 => Ok(AccessType::MovFrom),
2 => Ok(AccessType::Clts),
3 => Ok(AccessType::Lmsw),
_ => Err("Invalid AccessType value"),
}
}
}
#[repr(u8)]
#[derive(Specifier, Debug, Clone, Copy, PartialEq, Eq)]
pub enum LmswOperandType {
Reg = 0,
Mem = 1,
}
impl TryFrom<u8> for LmswOperandType {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(LmswOperandType::Reg),
1 => Ok(LmswOperandType::Mem),
_ => Err("Invalid LmswOperandType value"),
}
}
}
#[repr(u8)]
#[derive(Specifier, Debug, Clone, Copy, PartialEq, Eq)]
pub enum Register {
Rax = 0,
Rcx = 1,
Rdx = 2,
Rbx = 3,
Rsp = 4,
Rbp = 5,
Rsi = 6,
Rdi = 7,
R8 = 8,
R9 = 9,
R10 = 10,
R11 = 11,
R12 = 12,
R13 = 13,
R14 = 14,
R15 = 15,
}
impl TryFrom<u8> for Register {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Register::Rax),
1 => Ok(Register::Rcx),
2 => Ok(Register::Rdx),
3 => Ok(Register::Rbx),
4 => Ok(Register::Rsp),
5 => Ok(Register::Rbp),
6 => Ok(Register::Rsi),
7 => Ok(Register::Rdi),
8 => Ok(Register::R8),
9 => Ok(Register::R9),
10 => Ok(Register::R10),
11 => Ok(Register::R11),
12 => Ok(Register::R12),
13 => Ok(Register::R13),
14 => Ok(Register::R14),
15 => Ok(Register::R15),
_ => Err("Invalid Register value"),
}
}
}
#[bitfield]
#[repr(u64)]
#[derive(Debug, Clone, Copy)]
pub struct QualCr {
pub index: B4,
#[bits = 2]
pub access_type: AccessType,
#[bits = 1]
pub lmsw_operand_type: LmswOperandType,
_reserved1: B1,
#[bits = 4]
pub register: Register,
_reserved2: B4,
pub lmsw_source: B16,
_reseved3: B32,
}
#[bitfield]
#[repr(u64)]
#[derive(Debug, Clone, Copy)]
pub struct QualIo {
pub size: B4,
pub direction: B1,
pub string: B1,
pub rep: B1,
pub operand_encoding: B1,
_reserved1: B8,
pub port: B16,
_reserved2: B32,
}

View File

@ -42,6 +42,7 @@ pub struct IntelVCpu {
guest_memory_size: u64, guest_memory_size: u64,
pub host_msr: ShadowMsr, pub host_msr: ShadowMsr,
pub guest_msr: ShadowMsr, pub guest_msr: ShadowMsr,
pub ia32e_enabled: bool,
} }
impl IntelVCpu { impl IntelVCpu {
@ -666,6 +667,7 @@ impl VCpu for IntelVCpu {
guest_memory_size: 1024 * 1024 * 256, // 256 MiB guest_memory_size: 1024 * 1024 * 256, // 256 MiB
host_msr: ShadowMsr::new(), host_msr: ShadowMsr::new(),
guest_msr: ShadowMsr::new(), guest_msr: ShadowMsr::new(),
ia32e_enabled: false,
}) })
} }