Skip to content

Commit 3fd4ca5

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 <168595099+syntactically@users.noreply.github.com>
1 parent cb631ad commit 3fd4ca5

File tree

3 files changed

+78
-11
lines changed

3 files changed

+78
-11
lines changed

src/hyperlight_guest_bin/src/exceptions/handler.rs

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,89 @@ 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+
// We don't presently have any need for user-defined interrupts,
88+
// so we only support handlers for the architecture-defined
89+
// vectors (0-31)
90+
if exception_number < 31 {
91+
let handler =
92+
handlers[exception_number as usize].load(core::sync::atomic::Ordering::Acquire);
93+
if handler != 0
94+
&& unsafe {
95+
core::mem::transmute::<_, handler_t>(handler)(
96+
exception_number,
97+
exn_info,
98+
ctx,
99+
page_fault_address,
100+
)
101+
}
102+
{
103+
return;
104+
}
105+
}
106+
38107
unsafe {
39108
abort_with_code_and_message(
40109
&[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]

src/hyperlight_host/src/sandbox/initialized_multi_use.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ limitations under the License.
1515
*/
1616

1717
#[cfg(unix)]
18-
use std::mem::MaybeUninit;
19-
#[cfg(unix)]
20-
use std::os::fd::AsFd;
18+
use std::os::fd::AsRawFd;
2119
#[cfg(unix)]
2220
use std::os::linux::fs::MetadataExt;
2321
use std::path::Path;
@@ -226,18 +224,17 @@ impl MultiUseSandbox {
226224
.read(true)
227225
.write(true)
228226
.open(_fp)?;
229-
let file_size = fs::metadata()?.st_size();
227+
let file_size = file.metadata()?.st_size();
230228
let page_size = page_size::get();
231229
let size = (file_size as usize).div_ceil(page_size) * page_size;
232230
let base = libc::mmap(
233231
std::ptr::null_mut(),
234232
size,
235233
libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC,
236234
libc::MAP_PRIVATE,
237-
file.as_fd(),
235+
file.as_raw_fd(),
238236
0,
239237
);
240-
libc::close(fd);
241238
if base == libc::MAP_FAILED {
242239
log_then_return!("mmap error: {:?}", std::io::Error::last_os_error());
243240
}

0 commit comments

Comments
 (0)