Skip to content

Commit

Permalink
cpu/idt: separate stage2 and SVSM IDT
Browse files Browse the repository at this point in the history
Stage2 and SVSM kernel have to handle
interrupts in different ways.

This creates 2 different IDT handler arrays: one
calling stage2 handlers, and one calling SVSM
handlers.

cpu/idt/stage2.rs and cpu/idt/svsm.rs exposes
the same functions, callable from the appropriate
context (stage2 or SVSM).

Signed-off-by: Thomas Leroy <[email protected]>
  • Loading branch information
p4zuu committed Aug 17, 2023
1 parent a65f897 commit 57d1f3c
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 133 deletions.
2 changes: 1 addition & 1 deletion src/cpu/extable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
134 changes: 8 additions & 126 deletions src/cpu/idt.rs → src/cpu/idt/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@
//
// Author: Joerg Roedel <[email protected]>

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;
Expand Down Expand Up @@ -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 {
Expand All @@ -50,7 +48,7 @@ pub struct X86ExceptionContext {

#[derive(Copy, Clone, Default, Debug)]
#[repr(C, packed)]
struct IdtEntry {
pub struct IdtEntry {
low: u64,
high: u64,
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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()),
Expand All @@ -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;
Expand All @@ -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:
Expand All @@ -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)
);
9 changes: 9 additions & 0 deletions src/cpu/idt/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022-2023 SUSE LLC
//
// Author: Thomas Leroy <[email protected]>

pub mod common;
pub mod stage2;
pub mod svsm;
112 changes: 112 additions & 0 deletions src/cpu/idt/stage2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022-2023 SUSE LLC
//
// Author: Joerg Roedel <[email protected]>

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)
);
Loading

0 comments on commit 57d1f3c

Please sign in to comment.