From 3faffcb087cd61cd3854d3b2397987545d3ddbff Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 26 Nov 2020 19:01:10 +0100 Subject: [PATCH] hypervisor: emulator: Add a CPU mode getter to CpuStateManager We need to be able to build the CPU mode from its state in order to start implementing mode related checks in the x86 emulator. Signed-off-by: Samuel Ortiz --- hypervisor/src/arch/emulator/mod.rs | 3 ++ hypervisor/src/arch/x86/emulator/mod.rs | 45 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/hypervisor/src/arch/emulator/mod.rs b/hypervisor/src/arch/emulator/mod.rs index 678b57cd8..37a6e20c8 100644 --- a/hypervisor/src/arch/emulator/mod.rs +++ b/hypervisor/src/arch/emulator/mod.rs @@ -29,6 +29,9 @@ pub enum PlatformError { #[error("Invalid register: {0}")] InvalidRegister(#[source] anyhow::Error), + #[error("Invalid state: {0}")] + InvalidState(#[source] anyhow::Error), + #[error("Memory read failure: {0}")] MemoryReadFailure(#[source] anyhow::Error), diff --git a/hypervisor/src/arch/x86/emulator/mod.rs b/hypervisor/src/arch/x86/emulator/mod.rs index 0f4285eee..fa71b78a6 100644 --- a/hypervisor/src/arch/x86/emulator/mod.rs +++ b/hypervisor/src/arch/x86/emulator/mod.rs @@ -8,6 +8,7 @@ extern crate iced_x86; use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError}; use crate::arch::x86::emulator::instructions::*; +use crate::arch::x86::regs::*; use crate::arch::x86::Exception; use crate::x86_64::{SegmentRegister, SpecialRegisters, StandardRegisters}; use iced_x86::*; @@ -15,6 +16,25 @@ use iced_x86::*; #[macro_use] mod instructions; +/// x86 CPU modes +#[derive(Debug, PartialEq)] +pub enum CpuMode { + /// Real mode + Real, + + /// Virtual 8086 mode + Virtual8086, + + /// 16-bit protected mode + Protected16, + + /// 32-bit protected mode + Protected, + + /// 64-bit mode, a.k.a. long mode + Long, +} + /// CpuStateManager manages an x86 CPU state. /// /// Instruction emulation handlers get a mutable reference to @@ -88,6 +108,9 @@ pub trait CpuStateManager: Clone { /// /// * `flags` - The CPU flags fn set_flags(&mut self, flags: u64); + + /// Get the CPU mode. + fn mode(&self) -> Result; } const REGISTER_MASK_64: u64 = 0xffff_ffff_ffff_ffffu64; @@ -346,6 +369,28 @@ impl CpuStateManager for EmulatorCpuState { fn set_flags(&mut self, flags: u64) { self.regs.rflags = flags; } + + fn mode(&self) -> Result { + let efer = self.efer(); + let cr0 = self.read_reg(Register::CR0)?; + let mut mode = CpuMode::Real; + + if (cr0 & CR0_PE) == CR0_PE { + mode = CpuMode::Protected; + } + + if (efer & EFER_LMA) == EFER_LMA { + if mode != CpuMode::Protected { + return Err(PlatformError::InvalidState(anyhow!( + "Protection must be enabled in long mode" + ))); + } + + mode = CpuMode::Long; + } + + Ok(mode) + } } pub struct Emulator<'a, T: CpuStateManager> {