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 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;
|
||||||
|
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,
|
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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user