diff --git a/src/cpu/cpuid.rs b/src/cpu/cpuid.rs index e59043b71..5520fb708 100644 --- a/src/cpu/cpuid.rs +++ b/src/cpu/cpuid.rs @@ -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, diff --git a/src/cpu/idt/svsm.rs b/src/cpu/idt/svsm.rs index 364ce968f..035f62647 100644 --- a/src/cpu/idt/svsm.rs +++ b/src/cpu/idt/svsm.rs @@ -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, }; @@ -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 { diff --git a/src/cpu/vc.rs b/src/cpu/vc.rs index 44cec4595..2ca6a65ea 100644 --- a/src/cpu/vc.rs +++ b/src/cpu/vc.rs @@ -5,27 +5,108 @@ // Author: Joerg Roedel 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 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) { diff --git a/src/error.rs b/src/error.rs index a86729851..5e36df7bc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,4 @@ +use crate::cpu::vc::VcError; use crate::fs::FsError; use crate::fw_cfg::FwCfgError; use crate::sev::ghcb::GhcbError; @@ -33,4 +34,6 @@ pub enum SvsmError { Acpi, // Errors from file systems FileSystem(FsError), + // Errors from #VC handler + Vc(VcError), }