Debugging scenarios when OSv crashes due to an unexpected exception
can be quite tedious given they are handled by entry_invalid which
simply makes kernel "hang" waiting for an interrupt. One needs to connect
with gdb and introspect registers to make sense of what happenned.

This patch improves the unexpected exception handling by defining
proper handlers for each exception level and exception type. When exception
is triggered corresponding handler prints exception type, exception level and
all registers and aborts potentially printing a backtrace.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
---
 arch/aarch64/entry.S       | 125 +++++++++++++++++++++++--------------
 arch/aarch64/exceptions.cc |  30 +++++++--
 2 files changed, 103 insertions(+), 52 deletions(-)

diff --git a/arch/aarch64/entry.S b/arch/aarch64/entry.S
index 0c2a6e82..03266f9c 100644
--- a/arch/aarch64/entry.S
+++ b/arch/aarch64/entry.S
@@ -22,10 +22,10 @@
         Lower Exception level, from AArch32              0x600     0x680     
0x700     0x780
  */
 
-.macro vector_entry label idx
+.macro vector_entry level, type
 /* every entry is at 2^7 bits distance */
 .align 7
-        b       \label
+        b       entry_\level\()_\type
 .endm
 
 .global exception_vectors
@@ -34,28 +34,28 @@
 .align 12
 exception_vectors:
         /* Current Exception level with SP_EL0 : unused */
-        vector_entry entry_invalid  0   // Synchronous
-        vector_entry entry_invalid  1   // IRQ or vIRQ
-        vector_entry entry_invalid  2   // FIQ or vFIQ
-        vector_entry entry_invalid  3   // SError or vSError
+        vector_entry curr_el_sp0      sync   // Synchronous
+        vector_entry curr_el_sp0      irq    // IRQ or vIRQ
+        vector_entry curr_el_sp0      fiq    // FIQ or vFIQ
+        vector_entry curr_el_sp0      serror // SError or vSError
 
         /* Current Exception level with SP_ELx : only actually used */
-        vector_entry entry_sync     4
-        vector_entry entry_irq      5
-        vector_entry entry_fiq      6
-        vector_entry entry_serror   7
+        vector_entry curr_el_spx      sync
+        vector_entry curr_el_spx      irq
+        vector_entry curr_el_spx      fiq
+        vector_entry curr_el_spx      serror
 
         /* Lower Exception level in AArch64 : unused since we don't go to EL0 
*/
-        vector_entry entry_invalid  8
-        vector_entry entry_invalid  9
-        vector_entry entry_invalid 10
-        vector_entry entry_invalid 11
+        vector_entry lower_el_aarch64 sync
+        vector_entry lower_el_aarch64 irq
+        vector_entry lower_el_aarch64 fiq
+        vector_entry lower_el_aarch64 serror
 
         /* Lower Exception level in AArch32 : no El0, no AArch32 */
-        vector_entry entry_invalid 12
-        vector_entry entry_invalid 13
-        vector_entry entry_invalid 14
-        vector_entry entry_invalid 15
+        vector_entry lower_el_aarch32 sync
+        vector_entry lower_el_aarch32 irq
+        vector_entry lower_el_aarch32 fiq
+        vector_entry lower_el_aarch32 serror
 
 /* keep in sync with the struct in exceptions.hh */
 .macro push_state_to_exception_frame
@@ -131,24 +131,61 @@ thread_main:
 .equ ESR_FLT_BEG,2 // we strip LL
 .equ ESR_FLT_END,5
 
-.global entry_invalid
-.hidden entry_invalid
-.type entry_invalid, @function
-entry_invalid:
-        mrs     x20, elr_el1       // Exception Link Register -> X20
-        mrs     x21, spsr_el1      // Saved PSTATE -> X21
-        mrs     x22, esr_el1       // Exception Syndrome Register -> X22
+.macro entry_unexpected_exception level, type, level_id, type_id
+.global entry_\level\()_\type
+.hidden entry_\level\()_\type
+.type entry_\level\()_\type, @function
+entry_\level\()_\type:
+        .cfi_startproc simple
+        .cfi_signal_frame
+        .cfi_def_cfa sp, 0
+        .cfi_offset x30, -32 // Point to the elr register located at the -32 
offset
+                             // of the exception frame to help gdb link to the
+                             // address when interrupt was raised
+        push_state_to_exception_frame
+        mrs     x1, esr_el1
+        str     w1, [sp, #272] // Store Exception Syndrom Register in the frame
+        mov     x0, sp         // Save exception_frame to x0
+        mov     x1, \level_id
+        mov     x2, \type_id
+        bl      handle_unexpected_exception
+        pop_state_from_exception_frame
+        bl      abort
+        .cfi_endproc
+.endm
+
+.equ CURR_EL_SP0, 0x0
+.equ CURR_EL_SPX, 0x1
+.equ LOWER_EL_AARCH64, 0x2
+.equ LOWER_EL_AARCH32, 0x3
 
-        ubfm    x23, x22, #ESR_EC_BEG, #ESR_EC_END   // Exception Class -> X23
-        ubfm    x24, x22, #ESR_ISS_BEG, #ESR_ISS_END // Instruction-Specific 
Syndrome -> X24
+.equ EX_TYPE_SYNC, 0x0
+.equ EX_TYPE_IRQ, 0x1
+.equ EX_TYPE_FIQ, 0x2
+.equ EX_TYPE_SERROR, 0x3
 
-1:      wfi
-        b       1b
+entry_unexpected_exception curr_el_sp0, sync, #CURR_EL_SP0, #EX_TYPE_SYNC
+entry_unexpected_exception curr_el_sp0, irq, #CURR_EL_SP0, #EX_TYPE_IRQ
+entry_unexpected_exception curr_el_sp0, fiq, #CURR_EL_SP0, #EX_TYPE_FIQ
+entry_unexpected_exception curr_el_sp0, serror, #CURR_EL_SP0, #EX_TYPE_SERROR
 
-.global entry_sync
-.hidden entry_sync
-.type entry_sync, @function
-entry_sync:
+entry_unexpected_exception curr_el_spx, fiq, #CURR_EL_SPX, #EX_TYPE_FIQ
+entry_unexpected_exception curr_el_spx, serror, #CURR_EL_SPX, #EX_TYPE_SERROR
+
+entry_unexpected_exception lower_el_aarch64, sync, #LOWER_EL_AARCH64, 
#EX_TYPE_SYNC
+entry_unexpected_exception lower_el_aarch64, irq, #LOWER_EL_AARCH64, 
#EX_TYPE_IRQ
+entry_unexpected_exception lower_el_aarch64, fiq, #LOWER_EL_AARCH64, 
#EX_TYPE_FIQ
+entry_unexpected_exception lower_el_aarch64, serror, #LOWER_EL_AARCH64, 
#EX_TYPE_SERROR
+
+entry_unexpected_exception lower_el_aarch32, sync, #LOWER_EL_AARCH32, 
#EX_TYPE_SYNC
+entry_unexpected_exception lower_el_aarch32, irq, #LOWER_EL_AARCH32, 
#EX_TYPE_IRQ
+entry_unexpected_exception lower_el_aarch32, fiq, #LOWER_EL_AARCH32, 
#EX_TYPE_FIQ
+entry_unexpected_exception lower_el_aarch32, serror, #LOWER_EL_AARCH32, 
#EX_TYPE_SERROR
+
+.global entry_curr_el_spx_sync
+.hidden entry_curr_el_spx_sync
+.type entry_curr_el_spx_sync, @function
+entry_curr_el_spx_sync:
         .cfi_startproc simple
         .cfi_signal_frame
         .cfi_def_cfa sp, 0
@@ -177,15 +214,17 @@ handle_mem_abort:
 unexpected_sync_exception:
         .cfi_startproc
         mov     x0, sp  // save exception_frame to x0
-        bl      handle_unexpected_sync_exception
+        mov     x1, #CURR_EL_SPX
+        mov     x2, #EX_TYPE_SYNC
+        bl      handle_unexpected_exception
         pop_state_from_exception_frame
         bl      abort
         .cfi_endproc
 
-.global entry_irq
-.hidden entry_irq
-.type entry_irq, @function
-entry_irq:
+.global entry_curr_el_spx_irq
+.hidden entry_curr_el_spx_irq
+.type entry_curr_el_spx_irq, @function
+entry_curr_el_spx_irq:
         .cfi_startproc simple
         .cfi_signal_frame
         .cfi_def_cfa sp, 0
@@ -199,16 +238,6 @@ entry_irq:
         eret
         .cfi_endproc
 
-.global entry_fiq
-.hidden entry_fiq
-.type entry_fiq, @function
-entry_fiq:
-.global entry_serror
-.hidden entry_serror
-.type entry_serror, @function
-entry_serror:
-        b       entry_invalid
-
 .global call_signal_handler_thunk
 .hidden call_signal_handler_thunk
 call_signal_handler_thunk:
diff --git a/arch/aarch64/exceptions.cc b/arch/aarch64/exceptions.cc
index ce16116b..cadbb3a2 100644
--- a/arch/aarch64/exceptions.cc
+++ b/arch/aarch64/exceptions.cc
@@ -173,16 +173,38 @@ void interrupt(exception_frame* frame)
     sched::preempt();
 }
 
-extern "C" { void handle_unexpected_sync_exception(exception_frame* frame); }
+extern "C" { void handle_unexpected_exception(exception_frame* frame, u64 
level, u64 type); }
+
+#define EX_TYPE_SYNC 0x0
+#define EX_TYPE_IRQ 0x1
+#define EX_TYPE_FIQ 0x2
+#define EX_TYPE_SERROR 0x3
 
 #define ESR_EC_BEG  26 // Exception Class field begins in ESR at the bit 26th
 #define ESR_EC_END  31 // and ends at 31st
 #define ESR_EC_MASK 0b111111UL
 
-void handle_unexpected_sync_exception(exception_frame* frame)
+void handle_unexpected_exception(exception_frame* frame, u64 level, u64 type)
 {
-    u64 exception_class = (frame->esr >> ESR_EC_BEG) & ESR_EC_MASK;
-    debug_ll("unexpected synchronous exception, EC: 0x%04x\n", 
exception_class);
+    switch (type) {
+        case EX_TYPE_SYNC:
+           {
+               u64 exception_class = (frame->esr >> ESR_EC_BEG) & ESR_EC_MASK;
+               debug_ll("unexpected synchronous exception at level:%ld, EC: 
0x%04x\n", level, exception_class);
+           }
+           break;
+        case EX_TYPE_IRQ:
+           debug_ll("unexpected IRQ exception at level:%ld\n", level);
+           break;
+        case EX_TYPE_FIQ:
+           debug_ll("unexpected FIQ exception at level:%ld\n", level);
+           break;
+        case EX_TYPE_SERROR:
+           debug_ll("unexpected system error at level:%ld\n", level);
+           break;
+        default:
+           debug_ll("unexpected exception type:%ld at level:%ld\n", type, 
level);
+    }
     dump_registers(frame);
 }
 
-- 
2.27.0

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/20220313213826.825911-1-jwkozaczuk%40gmail.com.

Reply via email to