diff --git a/src/cpu/extable.rs b/src/cpu/extable.rs index 790941fe9..390136a9a 100644 --- a/src/cpu/extable.rs +++ b/src/cpu/extable.rs @@ -9,7 +9,7 @@ extern "C" { pub static exception_table_end: u8; } -use super::idt::X86ExceptionContext; +use super::idt::common::X86ExceptionContext; use crate::address::{Address, VirtAddr}; use core::mem; diff --git a/src/cpu/idt.rs b/src/cpu/idt/common.rs similarity index 55% rename from src/cpu/idt.rs rename to src/cpu/idt/common.rs index 3084ac072..b367262df 100644 --- a/src/cpu/idt.rs +++ b/src/cpu/idt/common.rs @@ -4,13 +4,8 @@ // // Author: Joerg Roedel -use super::control_regs::read_cr2; -use super::tss::IST_DF; -use super::vc::handle_vc_exception; -use super::{X86GeneralRegs, X86InterruptFrame}; use crate::address::{Address, VirtAddr}; -use crate::cpu::extable::handle_exception_table; -use crate::debug::gdbstub::svsm_gdbstub::handle_bp_exception; +use crate::cpu::registers::{X86GeneralRegs, X86InterruptFrame}; use crate::types::SVSM_CS; use core::arch::{asm, global_asm}; use core::mem; @@ -39,6 +34,9 @@ pub const _HV_VECTOR: usize = 28; pub const VC_VECTOR: usize = 29; pub const _SX_VECTOR: usize = 30; +pub const SVM_EXIT_EXCP_BASE: usize = 0x40; +pub const X86_TRAP_DB: usize = 0x01; + #[repr(C, packed)] #[derive(Default, Debug)] pub struct X86ExceptionContext { @@ -50,7 +48,7 @@ pub struct X86ExceptionContext { #[derive(Copy, Clone, Default, Debug)] #[repr(C, packed)] -struct IdtEntry { +pub struct IdtEntry { low: u64, high: u64, } @@ -107,13 +105,9 @@ struct IdtDesc { address: VirtAddr, } -extern "C" { - static idt_handler_array: u8; -} - -type Idt = [IdtEntry; IDT_ENTRIES]; +pub type Idt = [IdtEntry; IDT_ENTRIES]; -static mut GLOBAL_IDT: Idt = [IdtEntry::no_handler(); IDT_ENTRIES]; +pub static mut GLOBAL_IDT: Idt = [IdtEntry::no_handler(); IDT_ENTRIES]; pub fn idt_base_limit() -> (u64, u32) { unsafe { @@ -123,20 +117,7 @@ pub fn idt_base_limit() -> (u64, u32) { } } -fn init_idt(idt: &mut Idt) { - // Set IDT handlers - let handlers = unsafe { VirtAddr::from(&idt_handler_array as *const u8) }; - for (i, entry) in idt.iter_mut().enumerate() { - *entry = IdtEntry::entry(handlers + (32 * i)); - } -} - -unsafe fn init_ist_vectors(idt: &mut Idt) { - let handler = VirtAddr::from(&idt_handler_array as *const u8) + (32 * DF_VECTOR); - idt[DF_VECTOR] = IdtEntry::ist_entry(handler, IST_DF.try_into().unwrap()); -} - -fn load_idt(idt: &Idt) { +pub fn load_idt(idt: &Idt) { let desc: IdtDesc = IdtDesc { size: (IDT_ENTRIES * 16) as u16, address: VirtAddr::from(idt.as_ptr()), @@ -147,69 +128,6 @@ fn load_idt(idt: &Idt) { } } -pub fn early_idt_init() { - unsafe { - init_idt(&mut GLOBAL_IDT); - load_idt(&GLOBAL_IDT); - } -} - -pub fn idt_init() { - // Set IST vectors - unsafe { - init_ist_vectors(&mut GLOBAL_IDT); - } -} - -#[no_mangle] -fn generic_idt_handler(ctx: &mut X86ExceptionContext) { - if ctx.vector == DF_VECTOR { - let cr2 = read_cr2(); - let rip = ctx.frame.rip; - let rsp = ctx.frame.rsp; - panic!( - "Double-Fault at RIP {:#018x} RSP: {:#018x} CR2: {:#018x}", - rip, rsp, cr2 - ); - } else if ctx.vector == GP_VECTOR { - let rip = ctx.frame.rip; - let err = ctx.error_code; - - if !handle_exception_table(ctx) { - panic!( - "Unhandled General-Protection-Fault at RIP {:#018x} error code: {:#018x}", - rip, err - ); - } - } else if ctx.vector == PF_VECTOR { - let cr2 = read_cr2(); - let rip = ctx.frame.rip; - let err = ctx.error_code; - - if !handle_exception_table(ctx) { - panic!( - "Unhandled Page-Fault at RIP {:#018x} CR2: {:#018x} error code: {:#018x}", - rip, cr2, err - ); - } - } else if ctx.vector == VC_VECTOR { - handle_vc_exception(ctx); - } else if ctx.vector == BP_VECTOR { - handle_bp_exception(ctx); - } else { - let err = ctx.error_code; - let vec = ctx.vector; - let rip = ctx.frame.rip; - - if !handle_exception_table(ctx) { - panic!( - "Unhandled exception {} RIP {:#018x} error code: {:#018x}", - vec, rip, err - ); - } - } -} - #[cfg(feature = "enable-stacktrace")] extern "C" { static generic_idt_handler_return: u8; @@ -221,30 +139,8 @@ pub fn is_exception_handler_return_site(rip: VirtAddr) -> bool { addr == rip } -// Entry Code global_asm!( r#" - .text - push_regs: - pushq %rax - pushq %rbx - pushq %rcx - pushq %rdx - pushq %rsi - pushq %rdi - pushq %rbp - pushq %r8 - pushq %r9 - pushq %r10 - pushq %r11 - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - - movq %rsp, %rdi - call generic_idt_handler - /* Needed by the stack unwinder to recognize exception frames. */ .globl generic_idt_handler_return generic_idt_handler_return: @@ -268,20 +164,6 @@ global_asm!( addq $16, %rsp /* Skip vector and error code */ iretq - - .align 32 - .globl idt_handler_array - idt_handler_array: - i = 0 - .rept 32 - .align 32 - .if ((0x20027d00 >> i) & 1) == 0 - pushq $0 - .endif - pushq $i /* Vector Number */ - jmp push_regs - i = i + 1 - .endr "#, options(att_syntax) ); diff --git a/src/cpu/idt/mod.rs b/src/cpu/idt/mod.rs new file mode 100644 index 000000000..d707cdb7d --- /dev/null +++ b/src/cpu/idt/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022-2023 SUSE LLC +// +// Author: Thomas Leroy + +pub mod common; +pub mod stage2; +pub mod svsm; diff --git a/src/cpu/idt/stage2.rs b/src/cpu/idt/stage2.rs new file mode 100644 index 000000000..e7c6a6d8a --- /dev/null +++ b/src/cpu/idt/stage2.rs @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022-2023 SUSE LLC +// +// Author: Joerg Roedel + +use super::super::tss::IST_DF; +use super::common::{load_idt, Idt, IdtEntry, BP_VECTOR, DF_VECTOR, GLOBAL_IDT, VC_VECTOR}; +use crate::address::VirtAddr; +use crate::cpu::control_regs::read_cr2; +use crate::cpu::vc::stage2_handle_vc_exception; +use crate::cpu::X86ExceptionContext; +use crate::debug::gdbstub::svsm_gdbstub::handle_bp_exception; +use core::arch::global_asm; + +fn init_idt(idt: &mut Idt) { + // Set IDT handlers + let handlers = unsafe { VirtAddr::from(&stage2_idt_handler_array as *const u8) }; + for (i, entry) in idt.iter_mut().enumerate() { + *entry = IdtEntry::entry(handlers + (32 * i)); + } +} + +unsafe fn init_ist_vectors(idt: &mut Idt) { + let handler = VirtAddr::from(&stage2_idt_handler_array as *const u8) + (32 * DF_VECTOR); + idt[DF_VECTOR] = IdtEntry::ist_entry(handler, IST_DF.try_into().unwrap()); +} + +pub fn early_idt_init() { + unsafe { + init_idt(&mut GLOBAL_IDT); + load_idt(&GLOBAL_IDT); + } +} + +pub fn idt_init() { + // Set IST vectors + unsafe { + init_ist_vectors(&mut GLOBAL_IDT); + } +} + +#[no_mangle] +fn stage2_generic_idt_handler(ctx: &mut X86ExceptionContext) { + if ctx.vector == DF_VECTOR { + let cr2 = read_cr2(); + let rip = ctx.frame.rip; + let rsp = ctx.frame.rsp; + panic!( + "Double-Fault at RIP {:#018x} RSP: {:#018x} CR2: {:#018x}", + rip, rsp, cr2 + ); + } else if ctx.vector == VC_VECTOR { + stage2_handle_vc_exception(ctx); + } else if ctx.vector == BP_VECTOR { + handle_bp_exception(ctx); + } else { + let err = ctx.error_code; + let vec = ctx.vector; + let rip = ctx.frame.rip; + + panic!( + "Unhandled exception {} RIP {:#018x} error code: {:#018x}", + vec, rip, err + ); + } +} + +extern "C" { + static stage2_idt_handler_array: u8; +} + +// Entry Code +global_asm!( + r#" + .text + push_regs: + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rdi + pushq %rbp + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + movq %rsp, %rdi + call stage2_generic_idt_handler + + .align 32 + .globl stage2_idt_handler_array + stage2_idt_handler_array: + i = 0 + .rept 32 + .align 32 + .if ((0x20027d00 >> i) & 1) == 0 + pushq $0 + .endif + pushq $i /* Vector Number */ + jmp push_regs + i = i + 1 + .endr + "#, + options(att_syntax) +); diff --git a/src/cpu/idt/svsm.rs b/src/cpu/idt/svsm.rs new file mode 100644 index 000000000..364ce968f --- /dev/null +++ b/src/cpu/idt/svsm.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022-2023 SUSE LLC +// +// Authors: Joerg Roedel + +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::common::{ + load_idt, Idt, IdtEntry, BP_VECTOR, DF_VECTOR, GLOBAL_IDT, GP_VECTOR, PF_VECTOR, VC_VECTOR, +}; +use crate::address::VirtAddr; +use crate::cpu::X86ExceptionContext; +use crate::debug::gdbstub::svsm_gdbstub::handle_bp_exception; +use core::arch::global_asm; + +fn init_idt(idt: &mut Idt) { + // Set IDT handlers + let handlers = unsafe { VirtAddr::from(&svsm_idt_handler_array as *const u8) }; + for (i, entry) in idt.iter_mut().enumerate() { + *entry = IdtEntry::entry(handlers + (32 * i)); + } +} + +unsafe fn init_ist_vectors(idt: &mut Idt) { + let handler = VirtAddr::from(&svsm_idt_handler_array as *const u8) + (32 * DF_VECTOR); + idt[DF_VECTOR] = IdtEntry::ist_entry(handler, IST_DF.try_into().unwrap()); +} + +pub fn early_idt_init() { + unsafe { + init_idt(&mut GLOBAL_IDT); + load_idt(&GLOBAL_IDT); + } +} + +pub fn idt_init() { + // Set IST vectors + unsafe { + init_ist_vectors(&mut GLOBAL_IDT); + } +} + +#[no_mangle] +pub fn generic_idt_handler(ctx: &mut X86ExceptionContext) { + if ctx.vector == DF_VECTOR { + let cr2 = read_cr2(); + let rip = ctx.frame.rip; + let rsp = ctx.frame.rsp; + panic!( + "Double-Fault at RIP {:#018x} RSP: {:#018x} CR2: {:#018x}", + rip, rsp, cr2 + ); + } else if ctx.vector == GP_VECTOR { + let rip = ctx.frame.rip; + let err = ctx.error_code; + + if !handle_exception_table(ctx) { + panic!( + "Unhandled General-Protection-Fault at RIP {:#018x} error code: {:#018x}", + rip, err + ); + } + } else if ctx.vector == PF_VECTOR { + let cr2 = read_cr2(); + let rip = ctx.frame.rip; + let err = ctx.error_code; + + if !handle_exception_table(ctx) { + panic!( + "Unhandled Page-Fault at RIP {:#018x} CR2: {:#018x} error code: {:#018x}", + rip, cr2, err + ); + } + } else if ctx.vector == VC_VECTOR { + handle_vc_exception(ctx); + } else if ctx.vector == BP_VECTOR { + handle_bp_exception(ctx); + } else { + let err = ctx.error_code; + let vec = ctx.vector; + let rip = ctx.frame.rip; + + if !handle_exception_table(ctx) { + panic!( + "Unhandled exception {} RIP {:#018x} error code: {:#018x}", + vec, rip, err + ); + } + } +} + +extern "C" { + static svsm_idt_handler_array: u8; +} + +global_asm!( + r#" + .text + push_regs: + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rdi + pushq %rbp + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + movq %rsp, %rdi + call generic_idt_handler + + .align 32 + .globl svsm_idt_handler_array + svsm_idt_handler_array: + i = 0 + .rept 32 + .align 32 + .if ((0x20027d00 >> i) & 1) == 0 + pushq $0 + .endif + pushq $i /* Vector Number */ + jmp push_regs + i = i + 1 + .endr + "#, + options(att_syntax) +); diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index c339e4a56..0f2df17d1 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -20,6 +20,6 @@ pub mod tss; pub mod vc; pub mod vmsa; -pub use idt::X86ExceptionContext; +pub use idt::common::X86ExceptionContext; pub use registers::{X86GeneralRegs, X86InterruptFrame, X86SegmentRegs}; pub use tlb::*; diff --git a/src/cpu/vc.rs b/src/cpu/vc.rs index c5d688c47..44cec4595 100644 --- a/src/cpu/vc.rs +++ b/src/cpu/vc.rs @@ -4,13 +4,30 @@ // // Author: Joerg Roedel -use super::idt::X86ExceptionContext; +use super::idt::common::X86ExceptionContext; use crate::cpu::extable::handle_exception_table; use crate::debug::gdbstub::svsm_gdbstub::handle_db_exception; pub const SVM_EXIT_EXCP_BASE: usize = 0x40; pub const X86_TRAP_DB: usize = 0x01; +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; + } + + panic!( + "Unhandled #VC exception RIP {:#018x} error code: {:#018x}", + rip, err + ); +} + pub fn handle_vc_exception(ctx: &mut X86ExceptionContext) { let err = ctx.error_code; let rip = ctx.frame.rip; diff --git a/src/cpu/vmsa.rs b/src/cpu/vmsa.rs index 3d57f6a07..dac65b163 100644 --- a/src/cpu/vmsa.rs +++ b/src/cpu/vmsa.rs @@ -11,7 +11,7 @@ use crate::types::{GUEST_VMPL, SVSM_CS, SVSM_CS_FLAGS, SVSM_DS, SVSM_DS_FLAGS}; use super::control_regs::{read_cr0, read_cr3, read_cr4}; use super::efer::read_efer; use super::gdt::gdt_base_limit; -use super::idt::idt_base_limit; +use super::idt::common::idt_base_limit; use super::msr::read_msr; fn svsm_code_segment() -> VMSASegment { diff --git a/src/debug/stacktrace.rs b/src/debug/stacktrace.rs index 144f1c66c..ca7f8ad6c 100644 --- a/src/debug/stacktrace.rs +++ b/src/debug/stacktrace.rs @@ -6,8 +6,8 @@ use crate::address::{Address, VirtAddr}; #[cfg(feature = "enable-stacktrace")] -use crate::cpu::idt::is_exception_handler_return_site; -use crate::cpu::idt::X86ExceptionContext; +use crate::cpu::idt::common::is_exception_handler_return_site; +use crate::cpu::idt::common::X86ExceptionContext; #[cfg(feature = "enable-stacktrace")] use crate::mm::address_space::{STACK_SIZE, SVSM_STACKS_INIT_TASK, SVSM_STACK_IST_DF_BASE}; #[cfg(feature = "enable-stacktrace")] diff --git a/src/stage2.rs b/src/stage2.rs old mode 100644 new mode 100755 index 5dd87a793..a3f9a8f92 --- a/src/stage2.rs +++ b/src/stage2.rs @@ -15,6 +15,8 @@ use core::slice; use svsm::address::{Address, PhysAddr, VirtAddr}; use svsm::console::{init_console, install_console_logger, WRITER}; use svsm::cpu::cpuid::{dump_cpuid_table, register_cpuid_table, SnpCpuidTable}; +use svsm::cpu::gdt::load_gdt; +use svsm::cpu::idt::stage2::early_idt_init; use svsm::cpu::percpu::{this_cpu_mut, PerCpu}; use svsm::elf; use svsm::fw_cfg::FwCfg; @@ -83,6 +85,9 @@ static mut CONSOLE_SERIAL: SerialPort = SerialPort { }; fn setup_env() { + load_gdt(); + early_idt_init(); + install_console_logger("Stage2"); init_kernel_mapping_info( VirtAddr::null(), diff --git a/src/svsm.rs b/src/svsm.rs old mode 100644 new mode 100755 index 73a25e51c..bd1e7cda2 --- a/src/svsm.rs +++ b/src/svsm.rs @@ -22,7 +22,7 @@ use svsm::cpu::control_regs::{cr0_init, cr4_init}; use svsm::cpu::cpuid::{dump_cpuid_table, register_cpuid_table, SnpCpuidTable}; use svsm::cpu::efer::efer_init; use svsm::cpu::gdt::load_gdt; -use svsm::cpu::idt::{early_idt_init, idt_init}; +use svsm::cpu::idt::svsm::{early_idt_init, idt_init}; use svsm::cpu::percpu::PerCpu; use svsm::cpu::percpu::{this_cpu, this_cpu_mut}; use svsm::cpu::smp::start_secondary_cpus;