This commit is contained in:
166
nel_os_kernel/src/vmm/x86_64/intel/cr.rs
Normal file
166
nel_os_kernel/src/vmm/x86_64/intel/cr.rs
Normal 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)?,
|
||||
})
|
||||
}
|
@ -2,8 +2,10 @@ pub mod asm;
|
||||
mod auditor;
|
||||
mod controls;
|
||||
mod cpuid;
|
||||
mod cr;
|
||||
mod ept;
|
||||
mod msr;
|
||||
mod qual;
|
||||
mod register;
|
||||
pub mod vcpu;
|
||||
mod vmcs;
|
||||
|
124
nel_os_kernel/src/vmm/x86_64/intel/qual.rs
Normal file
124
nel_os_kernel/src/vmm/x86_64/intel/qual.rs
Normal 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,
|
||||
}
|
@ -42,6 +42,7 @@ pub struct IntelVCpu {
|
||||
guest_memory_size: u64,
|
||||
pub host_msr: ShadowMsr,
|
||||
pub guest_msr: ShadowMsr,
|
||||
pub ia32e_enabled: bool,
|
||||
}
|
||||
|
||||
impl IntelVCpu {
|
||||
@ -666,6 +667,7 @@ impl VCpu for IntelVCpu {
|
||||
guest_memory_size: 1024 * 1024 * 256, // 256 MiB
|
||||
host_msr: ShadowMsr::new(),
|
||||
guest_msr: ShadowMsr::new(),
|
||||
ia32e_enabled: false,
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user