@@ -21,20 +21,89 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2121use hyperlight_common:: outb:: Exception ;
2222use 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) ]
2665pub 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 ] ,
0 commit comments