@@ -21,46 +21,98 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2121use hyperlight_common:: outb:: Exception ;
2222use hyperlight_guest:: exit:: abort_with_code_and_message;
2323
24+ /// Exception information pushed onto the stack by the CPU during an excpection.
25+ ///
2426/// See AMD64 Architecture Programmer's Manual, Volume 2
2527/// §8.9.3 Interrupt Stack Frame, pp. 283--284
2628/// Figure 8-14: Long-Mode Stack After Interrupt---Same Privilege,
2729/// Figure 8-15: Long-Mode Stack After Interrupt---Higher Privilege
28- /// Subject to the proviso that we push a dummy error code of 0 for exceptions
29- /// for which the processor does not provide one
30+ /// Note: For exceptions that don't provide an error code, we push a dummy value of 0.
3031#[ repr( C ) ]
3132pub struct ExceptionInfo {
33+ /// Error code provided by the processor (or 0 if not applicable).
3234 pub error_code : u64 ,
35+ /// Instruction pointer at the time of the exception.
3336 pub rip : u64 ,
37+ /// Code segment selector.
3438 pub cs : u64 ,
39+ /// CPU flags register.
3540 pub rflags : u64 ,
41+ /// Stack pointer at the time of the exception.
3642 pub rsp : u64 ,
43+ /// Stack segment selector.
3744 pub ss : u64 ,
3845}
3946const _: ( ) = assert ! ( core:: mem:: offset_of!( ExceptionInfo , rip) == 8 ) ;
4047const _: ( ) = assert ! ( core:: mem:: offset_of!( ExceptionInfo , rsp) == 32 ) ;
4148
49+ /// Saved CPU context pushed onto the stack by exception entry code.
50+ ///
51+ /// This structure contains all the saved CPU state needed to resume execution
52+ /// after handling an exception. It includes segment registers, floating-point state,
53+ /// and general-purpose registers.
4254#[ repr( C ) ]
43- /// Saved context, pushed onto the stack by exception entry code
4455pub struct Context {
45- /// in order: gs, fs, es
46- pub segments : [ u64 ; 3 ] ,
56+ /// Segment registers in order: GS, FS, ES, DS.
57+ pub segments : [ u64 ; 4 ] ,
58+ /// FPU/SSE state saved via FXSAVE instruction (512 bytes).
4759 pub fxsave : [ u8 ; 512 ] ,
48- pub ds : u64 ,
49- /// no `rsp`, since the processor saved it
50- /// `rax` is at the top, `r15` the bottom
60+ /// General-purpose registers (RAX through R15, excluding RSP).
61+ ///
62+ /// The stack pointer (RSP) is not included here since it's saved
63+ /// by the processor in the `ExceptionInfo` structure.
64+ /// R15 is at index 0, RAX is at index 14.
5165 pub gprs : [ u64 ; 15 ] ,
66+ /// Padding to ensure 16-byte alignment when combined with ExceptionInfo.
67+ padding : [ u64 ; 1 ] ,
5268}
53- const _: ( ) = assert ! ( size_of:: <Context >( ) == 152 + 512 ) ;
69+ const _: ( ) = assert ! ( size_of:: <Context >( ) == 32 + 512 + 120 + 8 ) ;
70+ // The combination of the ExceptionInfo (pushed by the CPU) and the register Context
71+ // that we save to the stack must be 16byte aligned before calling the hl_exception_handler
72+ // as specified in the x86-64 ELF System V psABI specification, Section 3.2.2:
73+ //
74+ // https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build
75+ const _: ( ) = assert ! ( ( size_of:: <Context >( ) + size_of:: <ExceptionInfo >( ) ) % 16 == 0 ) ;
5476
55- // TODO: This will eventually need to end up in a per-thread context,
56- // when there are threads.
77+ /// Array of installed exception handlers for vectors 0-30.
78+ ///
79+ /// TODO: This will eventually need to be part of a per-thread context when threading is implemented.
5780pub static HANDLERS : [ core:: sync:: atomic:: AtomicU64 ; 31 ] =
5881 [ const { core:: sync:: atomic:: AtomicU64 :: new ( 0 ) } ; 31 ] ;
59- pub type HandlerT = fn ( n : u64 , info : * mut ExceptionInfo , ctx : * mut Context , pf_addr : u64 ) -> bool ;
6082
61- /// Exception handler
83+ /// Exception handler function type.
84+ ///
85+ /// Handlers receive mutable pointers to the exception information and CPU context,
86+ /// allowing direct access and modification of exception state.
87+ ///
88+ /// # Parameters
89+ /// * `exception_number` - Exception vector number (0-30)
90+ /// * `exception_info` - Mutable pointer to exception information (instruction pointer, error code, etc.)
91+ /// * `context` - Mutable pointer to saved CPU context (registers, FPU state, etc.)
92+ /// * `page_fault_address` - Page fault address (only valid for page fault exceptions)
93+ ///
94+ /// # Returns
95+ /// * `true` - Suppress the default abort behavior and continue execution
96+ /// * `false` - Allow the default abort to occur
97+ ///
98+ /// # Safety
99+ /// This function type uses raw mutable pointers. Handlers must ensure:
100+ /// - Pointers are valid for the duration of the handler
101+ /// - Any modifications to exception state maintain system integrity
102+ /// - Modified values are valid for CPU state (e.g., valid instruction pointers, aligned stack pointers)
103+ pub type ExceptionHandler = fn (
104+ exception_number : u64 ,
105+ exception_info : * mut ExceptionInfo ,
106+ context : * mut Context ,
107+ page_fault_address : u64 ,
108+ ) -> bool ;
109+
110+ /// Internal exception handler invoked by the low-level exception entry code.
111+ ///
112+ /// This function is called from assembly when an exception occurs. It checks for
113+ /// registered user handlers and either invokes them or aborts with an error message.
62114#[ unsafe( no_mangle) ]
63- pub extern "C" fn hl_exception_handler (
115+ pub ( crate ) extern "C" fn hl_exception_handler (
64116 stack_pointer : u64 ,
65117 exception_number : u64 ,
66118 page_fault_address : u64 ,
@@ -82,20 +134,18 @@ pub extern "C" fn hl_exception_handler(
82134 exception_number, saved_rip, page_fault_address, error_code, stack_pointer
83135 ) ;
84136
85- // We don't presently have any need for user-defined interrupts,
86- // so we only support handlers for the architecture-defined
87- // vectors (0-31)
137+ // Check for registered user handlers (only for architecture-defined vectors 0-30)
88138 if exception_number < 31 {
89139 let handler =
90140 HANDLERS [ exception_number as usize ] . load ( core:: sync:: atomic:: Ordering :: Acquire ) ;
91- if handler != 0
92- && unsafe {
93- core:: mem:: transmute :: < u64 , fn ( u64 , * mut ExceptionInfo , * mut Context , u64 ) -> bool > (
94- handler ,
95- ) ( exception_number , exn_info , ctx , page_fault_address )
96- }
97- {
98- return ;
141+ if handler != 0 {
142+ unsafe {
143+ let handler = core:: mem:: transmute :: < u64 , ExceptionHandler > ( handler ) ;
144+ if handler ( exception_number , exn_info , ctx , page_fault_address ) {
145+ return ;
146+ }
147+ // Handler returned false, fall through to abort
148+ } ;
99149 }
100150 }
101151
0 commit comments