Skip to content

Commit

Permalink
cpu/idt: add CPUID handling in stage 2 #VC handler
Browse files Browse the repository at this point in the history
TODO: not complete yet

Signed-off-by: Thomas Leroy <[email protected]>
  • Loading branch information
p4zuu committed Aug 17, 2023
1 parent 57d1f3c commit dd7bd2b
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 11 deletions.
24 changes: 24 additions & 0 deletions src/cpu/cpuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,30 @@ pub fn register_cpuid_table(table: &'static SnpCpuidTable) {
.expect("Could not initialize CPUID page");
}

#[repr(C, packed)]
#[derive(Debug)]
pub struct CpuidLeaf {
pub cpuid_fn: u32,
pub cpuid_subfn: u32,
pub eax: u32,
pub ebx: u32,
pub ecx: u32,
pub edx: u32,
}

impl CpuidLeaf {
pub fn new(cpuid_fn: u32, cpuid_subfn: u32) -> Self {
CpuidLeaf {
cpuid_fn,
cpuid_subfn,
eax: 0,
ebx: 0,
ecx: 0,
edx: 0,
}
}
}

pub struct CpuidResult {
pub eax: u32,
pub ebx: u32,
Expand Down
4 changes: 2 additions & 2 deletions src/cpu/idt/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use super::super::control_regs::read_cr2;
use super::super::extable::handle_exception_table;
use super::super::tss::IST_DF;
use super::super::vc::handle_vc_exception;
use super::super::vc::stage2_handle_vc_exception;
use super::common::{
load_idt, Idt, IdtEntry, BP_VECTOR, DF_VECTOR, GLOBAL_IDT, GP_VECTOR, PF_VECTOR, VC_VECTOR,
};
Expand Down Expand Up @@ -75,7 +75,7 @@ pub fn generic_idt_handler(ctx: &mut X86ExceptionContext) {
);
}
} else if ctx.vector == VC_VECTOR {
handle_vc_exception(ctx);
stage2_handle_vc_exception(ctx);
} else if ctx.vector == BP_VECTOR {
handle_bp_exception(ctx);
} else {
Expand Down
99 changes: 90 additions & 9 deletions src/cpu/vc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,108 @@
// Author: Joerg Roedel <[email protected]>

use super::idt::common::X86ExceptionContext;
use crate::cpu::cpuid::{cpuid_table_raw, dump_cpuid_table, CpuidLeaf};
use crate::cpu::extable::handle_exception_table;
use crate::cpu::X86GeneralRegs;
use crate::debug::gdbstub::svsm_gdbstub::handle_db_exception;
use crate::error::SvsmError;

pub const SVM_EXIT_EXCP_BASE: usize = 0x40;
pub const SVM_EXIT_CPUID: usize = 0x72;
pub const X86_TRAP_DB: usize = 0x01;
pub const X86_TRAP: usize = SVM_EXIT_EXCP_BASE + X86_TRAP_DB;

#[derive(Clone, Copy, Debug)]
pub enum VcError {
Unsupported,
VMMError,
DecodeFailed,
Exception,
Retry,
}

impl From<VcError> for SvsmError {
fn from(e: VcError) -> Self {
Self::Vc(e)
}
}

pub fn stage2_handle_vc_exception(ctx: &mut X86ExceptionContext) {
let err = ctx.error_code;
let rip = ctx.frame.rip;

// If the debugger is enabled then handle the DB exception
// by directly invoking the exception hander
if err == (SVM_EXIT_EXCP_BASE + X86_TRAP_DB) {
handle_db_exception(ctx);
return;
let ret = match err {
// If the debugger is enabled then handle the DB exception
// by directly invoking the exception handler
X86_TRAP_DB => {
handle_db_exception(ctx);
Ok(())
}

SVM_EXIT_CPUID => handle_cpuid(ctx),
_ => Err(SvsmError::Vc(VcError::Unsupported)),
};

if ret.is_err() {
panic!(
"Unhandled #VC exception RIP {:#018x} error code: {:#018x}: error: {:?}",
rip,
err,
ret.err()
);
}

vc_finish_insn(ctx);
}

fn handle_cpuid(ctx: &mut X86ExceptionContext) -> Result<(), SvsmError> {
let regs = &mut ctx.regs;

/*
* For SEV-ES/SEV-SNP, we can use the CPUID table already defined and populated with
* firmware information.
* We choose for now not to call the hypervisor to perform CPUID, since it's no trusted.
* Since GHCB is not needed to handle CPUID with the firmware table, we can call the handler
* very soon in stage 2.
*/
snp_cpuid(regs)?;

Ok(())
}

fn snp_cpuid(regs: &mut X86GeneralRegs) -> Result<(), SvsmError> {
let leaf = &mut CpuidLeaf::new(regs.rax as u32, regs.rcx as u32);

let ret = match cpuid_table_raw(leaf.cpuid_fn, leaf.cpuid_subfn, 0, 0) {
None => Err(SvsmError::Vc(VcError::Unsupported)),
Some(v) => Ok(v),
}?;

leaf.eax = ret.eax;
leaf.ebx = ret.ebx;
leaf.ecx = ret.ecx;
leaf.edx = ret.edx;

snp_cpuid_postprocess(leaf)?;

regs.rax = leaf.eax as usize;
regs.rbx = leaf.ebx as usize;
regs.rcx = leaf.ecx as usize;
regs.rdx = leaf.edx as usize;

Ok(())
}

fn snp_cpuid_postprocess(leaf: &mut CpuidLeaf) -> Result<(), VcError> {
// TODO(tleroy): complete this
match leaf.cpuid_fn {
_ => Ok(()),
}
}

panic!(
"Unhandled #VC exception RIP {:#018x} error code: {:#018x}",
rip, err
);
fn vc_finish_insn(ctx: &mut X86ExceptionContext) {
//TODO(tleroy): add insn info in context
// ctx.frame.rip +=
}

pub fn handle_vc_exception(ctx: &mut X86ExceptionContext) {
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::cpu::vc::VcError;
use crate::fs::FsError;
use crate::fw_cfg::FwCfgError;
use crate::sev::ghcb::GhcbError;
Expand Down Expand Up @@ -33,4 +34,6 @@ pub enum SvsmError {
Acpi,
// Errors from file systems
FileSystem(FsError),
// Errors from #VC handler
Vc(VcError),
}

0 comments on commit dd7bd2b

Please sign in to comment.