Skip to content

Commit 6e895d8

Browse files
committed
[hyperlight_host] exceptions: allow guests to register handlers
This commit adds a simple mechanism for guests to register exception handlers. It does not support any kind of chaining, so there can only be one exception handler per exception per guest, which should probably be improved in the future. This will be used in hyperlight-wasm shortly. Signed-off-by: Lucy Menon <[email protected]>
1 parent f74981b commit 6e895d8

File tree

2 files changed

+72
-5
lines changed

2 files changed

+72
-5
lines changed

src/hyperlight_guest_bin/src/exceptions/handler.rs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,86 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2121
use hyperlight_common::outb::Exception;
2222
use hyperlight_guest::exit::abort_with_code_and_message;
2323

24+
use crate::paging;
25+
26+
/// See AMD64 Architecture Programmer's Manual, Volume 2
27+
/// §8.9.3 Interrupt Stack Frame, pp. 283--284
28+
/// Figure 8-14: Long-Mode Stack After Interrupt---Same Privilege,
29+
/// Figure 8-15: Long-Mode Stack After Interrupt---Higher Privilege
30+
/// Subject to the proviso that we push a dummy error code of 0 for exceptions
31+
/// for which the processor does not provide one
32+
#[repr(C)]
33+
pub struct ExceptionInfo {
34+
pub error_code: u64,
35+
pub rip: u64,
36+
pub cs: u64,
37+
pub rflags: u64,
38+
pub rsp: u64,
39+
pub ss: u64,
40+
}
41+
const _: () = assert!(core::mem::offset_of!(ExceptionInfo, rip) == 8);
42+
const _: () = assert!(core::mem::offset_of!(ExceptionInfo, rsp) == 32);
43+
44+
#[repr(C)]
45+
/// Saved context, pushed onto the stack by exception entry code
46+
pub struct Context {
47+
/// in order: gs, fs, es
48+
pub segments: [u64; 3],
49+
pub fxsave: [u8; 512],
50+
pub ds: u64,
51+
/// no `rsp`, since the processor saved it
52+
/// `rax` is at the top, `r15` the bottom
53+
pub gprs: [u64; 15],
54+
}
55+
const _: () = assert!(size_of::<Context>() == 152 + 512);
56+
57+
// TODO: This will eventually need to end up in a per-thread context,
58+
// when there are threads.
59+
pub static handlers: [core::sync::atomic::AtomicU64; 31] =
60+
[const { core::sync::atomic::AtomicU64::new(0) }; 31];
61+
type handler_t = fn(n: u64, info: *mut ExceptionInfo, ctx: *mut Context, pf_addr: u64) -> bool;
62+
2463
/// Exception handler
2564
#[unsafe(no_mangle)]
2665
pub extern "C" fn hl_exception_handler(
2766
stack_pointer: u64,
2867
exception_number: u64,
2968
page_fault_address: u64,
3069
) {
70+
let ctx = stack_pointer as *mut Context;
71+
let exn_info = (stack_pointer + size_of::<Context>() as u64) as *mut ExceptionInfo;
72+
3173
let exception = Exception::try_from(exception_number as u8).expect("Invalid exception number");
74+
75+
let saved_rip = unsafe { (&raw const (*exn_info).rip).read_volatile() };
76+
let error_code = unsafe { (&raw const (*exn_info).error_code).read_volatile() };
77+
3278
let msg = format!(
33-
"Page Fault Address: {:#x}\n\
34-
Stack Pointer: {:#x}",
35-
page_fault_address, stack_pointer
79+
"Exception vector: {:#}\n\
80+
Faulting Instruction: {:#x}\n\
81+
Page Fault Address: {:#x}\n\
82+
Error code: {:#x}\n\
83+
Stack Pointer: {:#x}",
84+
exception_number, saved_rip, page_fault_address, error_code, stack_pointer
3685
);
3786

87+
if exception_number < 31 {
88+
let handler =
89+
handlers[exception_number as usize].load(core::sync::atomic::Ordering::Acquire);
90+
if handler != 0
91+
&& unsafe {
92+
core::mem::transmute::<_, handler_t>(handler)(
93+
exception_number,
94+
exn_info,
95+
ctx,
96+
page_fault_address,
97+
)
98+
}
99+
{
100+
return;
101+
}
102+
}
103+
38104
unsafe {
39105
abort_with_code_and_message(
40106
&[ErrorCode::GuestError as u8, exception as u8],

src/hyperlight_guest_bin/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ use spin::Once;
3535

3636
// === Modules ===
3737
#[cfg(target_arch = "x86_64")]
38-
mod exceptions {
38+
pub mod exceptions {
3939
pub(super) mod gdt;
40-
mod handler;
40+
pub mod handler;
4141
mod idt;
4242
pub(super) mod idtr;
4343
mod interrupt_entry;
@@ -52,6 +52,7 @@ pub mod guest_function {
5252
pub mod guest_logger;
5353
pub mod host_comm;
5454
pub mod memory;
55+
pub mod paging;
5556

5657
// === Globals ===
5758
#[global_allocator]

0 commit comments

Comments
 (0)