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 <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2020-11-26 19:01:10 +01:00 committed by Rob Bradford
parent b3a1f5f1be
commit 3faffcb087
2 changed files with 48 additions and 0 deletions

View File

@ -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),

View File

@ -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<CpuMode, PlatformError>;
}
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<CpuMode, PlatformError> {
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> {