Skip to content

Commit

Permalink
td-exception: use global asm to replace naked interrupt handler
Browse files Browse the repository at this point in the history
An interrupt handler table is used to handle all 256 interrupts. They
share common handler that saves the interrupt vector and context. If the
interrupt is not an error, a zero is pushed to the stack to align with
the error one.

Function `generic_interrupt_handler` is called to find and call the
corresponding callback in the `CALLBACK_TABLE`.

For virtualization exception, when the CET shadow stack is enabled, we
need to update the LIP value in the shadow stack. As shadow stack saves
the latest two return address after interrupt entry and the SSP, the
position of saved LIP value is the top address of shadow stack minus
0x18 bytes.

Signed-off-by: Jiaqi Gao <[email protected]>
  • Loading branch information
gaojiaqi7 committed Dec 17, 2024
1 parent b4ee544 commit b3391da
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 278 deletions.
60 changes: 60 additions & 0 deletions td-exception/src/asm/handler.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright (c) 2024 Intel Corporation
# SPDX-License-Identifier: BSD-2-Clause-Patent

.section .text
interrupt_handler_entry:
push rax
push rcx
push rdx
push rdi
push rsi
push r8
push r9
push r10
push r11
push rbx
push rbp
push r12
push r13
push r14
push r15

mov rdi, rsp
call generic_interrupt_handler

pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
pop rax

# vector number and error code
add rsp, 16

iretq

.align 32
.global interrupt_handler_table
interrupt_handler_table:
i = 0
.rept 256
.align 32
.if ((0x20027d00 >> i) & 1) == 0
push 0
.endif
push i
jmp interrupt_handler_entry
i = i + 1
.endr

ret
7 changes: 7 additions & 0 deletions td-exception/src/asm/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use core::arch::global_asm;

global_asm!(include_str!("handler.asm"));

extern "C" {
pub(crate) static interrupt_handler_table: u8;
}
46 changes: 8 additions & 38 deletions td-exception/src/idt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ use x86_64::{
VirtAddr,
};

use crate::interrupt;
use crate::asm::interrupt_handler_table;
use crate::interrupt::init_interrupt_callbacks;

const IDT_ENTRY_COUNT: usize = 256;
pub(crate) const IDT_ENTRY_COUNT: usize = 256;

lazy_static! {
static ref INIT_IDT: Mutex<Idt> = Mutex::new(Idt::new());
Expand Down Expand Up @@ -71,44 +72,13 @@ impl Idt {

pub fn init(&mut self) {
let current_idt = &mut self.entries;
let handler_table = unsafe { &interrupt_handler_table as *const u8 as usize };

// Set up exceptions handler according to Intel64 & IA32 Software Developer Manual
// Reference: https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
current_idt[0].set_func(interrupt::divide_by_zero as usize);
current_idt[1].set_func(interrupt::debug as usize);
current_idt[2].set_func(interrupt::non_maskable as usize);
current_idt[3].set_func(interrupt::breakpoint as usize);
current_idt[4].set_func(interrupt::overflow as usize);
current_idt[5].set_func(interrupt::bound_range as usize);
current_idt[6].set_func(interrupt::invalid_opcode as usize);
current_idt[7].set_func(interrupt::device_not_available as usize);
current_idt[8].set_func(interrupt::double_fault as usize);
// 9 no longer available
current_idt[9].set_func(interrupt::default_exception as usize);
current_idt[10].set_func(interrupt::invalid_tss as usize);
current_idt[11].set_func(interrupt::segment_not_present as usize);
current_idt[12].set_func(interrupt::stack_segment as usize);
current_idt[13].set_func(interrupt::protection as usize);
current_idt[14].set_func(interrupt::page as usize);
// 15 reserved
current_idt[15].set_func(interrupt::default_exception as usize);
current_idt[16].set_func(interrupt::fpu as usize);
current_idt[17].set_func(interrupt::alignment_check as usize);
current_idt[18].set_func(interrupt::machine_check as usize);
current_idt[19].set_func(interrupt::simd as usize);
#[cfg(feature = "tdx")]
current_idt[20].set_func(interrupt::virtualization as usize);
#[cfg(not(feature = "tdx"))]
current_idt[20].set_func(interrupt::default_exception as usize);
current_idt[21].set_func(interrupt::control_flow as usize);
// reset exception reserved
for idt in current_idt.iter_mut().take(32).skip(22) {
idt.set_func(interrupt::default_exception as usize);
}
// Setup reset potential interrupt handler.
for idt in current_idt.iter_mut().take(IDT_ENTRY_COUNT).skip(32) {
idt.set_func(interrupt::default_interrupt as usize);
for (idx, idt) in current_idt.iter_mut().enumerate() {
idt.set_func(handler_table + idx * 32);
}

init_interrupt_callbacks();
}

// Construct the Interrupt Descriptor Table Pointer (IDTR) based
Expand Down
Loading

0 comments on commit b3391da

Please sign in to comment.