zmatt

cortex-a8 abort handling

Jun 30th, 2023
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.52 KB | None | 0 0
  1. #include <stdint.h>
  2. #include <stddef.h>
  3.  
  4. // which processor state (and associated stack) is used for exception handling.
  5. // this should be supervisor (0b10011) or system (0b11111) and must match
  6. // whatever the assembly wrappers use (see further down).
  7. #define MODE_HND 0b10011
  8.  
  9. // state saved on handler stack by assembly code (see below)
  10. struct ExcState {
  11.     // saved r0-r12 shared between modes.
  12.     uint32_t r[13];
  13.  
  14.     // saved link register of handler mode.
  15.     uint32_t lr;
  16.  
  17.     // saved state of interrupted processor mode.
  18.     uint32_t pc;
  19.     uint32_t psr;
  20. };
  21.  
  22. static void dump_state( ExcState *state )
  23. {
  24.     unsigned mode = ( state->psr & 0b11111 );
  25.     printf( "psr: 0x%08x\n", state->psr );
  26.     printf( "pc:  0x%08x\n", state->pc );
  27.     if( mode == MODE_HND || ( MODE_HND == 0b11111 && mode == 0b10000 ) ) {
  28.         // the interrupted mode uses same SP and LR as handler mode
  29.         printf( "lr:  0x%08x\n", state->lr );
  30.         printf( "sp:  0x%08x\n", (uint32_t)( state + 1 ) );
  31.     } else {
  32.         // FIXME obtain banked SP and LR for other modes
  33.     }
  34.     for( int i = 0; i <= 9; ++i )
  35.         printf( "r%u:  0x%08x\n", i, state->r[i] );
  36.     for( int i = 10; i <= 12; ++i )
  37.         printf( "r%u: 0x%08x\n", i, state->r[i] );
  38. }
  39.  
  40. static void abort_common( ExcState *state, char const *msg )
  41. {
  42.     if( msg )
  43.         printf( "\e[1;31m### %s\e[m\n", msg );
  44.     if( state )
  45.         dump_state( state );
  46.  
  47.     // XXX if you want to trigger a system reset, this is the place for it.
  48.     // otherwise just hang in infinite loop:
  49.     for(;;)
  50.         asm( "wfe" );
  51. }
  52.  
  53.  
  54. //-------------- Debug monitor events ----------------------------------------//
  55.  
  56. static void debug_watchpoint( ExcState *state )
  57. {
  58.     abort_common( state, "unexpected watchpoint" );
  59. }
  60.  
  61. static void debug_breakpoint( ExcState *state )
  62. {
  63.     abort_common( state, "unexpected breakpoint" );
  64. }
  65.  
  66.  
  67. //-------------- Asynchronous aborts -----------------------------------------//
  68. //
  69. // In these cases the CPU gives you no info whatsoever about the access that
  70. // caused the abort, and it may be taken long after the instruction that caused
  71. // it.  In general, the instruction at state->pc is not related to the error.
  72. //
  73. // Fortunately on the Cortex-A8 most aborts are synchronous.  (In contrast, on
  74. // the Cortex-A15 nearly all aborts are asynchronous.)
  75.  
  76. static void async_bus_error()
  77. {
  78.     abort_common( NULL, "async bus error" );
  79. }
  80.  
  81. static void async_parity_error()
  82. {
  83.     abort_common( NULL, "async parity error" );
  84. }
  85.  
  86.  
  87. //-------------- Synchronous aborts ------------------------------------------//
  88. //
  89. static void sync_abort_common( ExcState *state, uint32_t fsr, uint32_t addr )
  90. {
  91.     // create order in the chaos of fault types
  92.     static uint8_t const typemap[2][16] = {
  93.            0, 0x01,    0, 0x21,    0, 0x20, 0x41, 0x40,
  94.         0x71, 0x22,    0, 0x42, 0x11, 0x23, 0x31, 0x43,
  95.         0x02,    0,    0,    0, 0x03,    0,    0,    0,
  96.            0, 0x70, 0x04,    0, 0x10,    0, 0x30,    0,
  97.     };
  98.     int type = typemap[ fsr >> 10 & 1 ][ fsr & 0xf ];
  99.  
  100.     if( ( type & 0x1f ) == 0x11 )  // bus error
  101.         type += fsr >> 12 & 1;  // bus error subtype
  102.  
  103.     int phase = type >> 4;
  104.     int subtype = type & 0xf;
  105.     int access = ( fsr >> 11 & 1 ) | ( fsr >> 13 & 1 ) << 1;
  106.  
  107.     char const *fault_name = NULL;
  108.  
  109.     if( phase == 0 ) {
  110.         // subtype:
  111.         static char const *const names[] = {
  112.             "unknown abort",
  113.             "alignment fault",
  114.             "TLB conflict",     // since v7L/v7VE
  115.             "lockdown abort",   // implementation-defined
  116.             "coprocessor abort",    // implementation-defined
  117.         };
  118.         fault_name = names[ subtype ];
  119.  
  120.     } else if( phase & 1 ) {
  121.         // phase:
  122.         //  1 section table walk
  123.         //  3 page table walk
  124.         //  7 access
  125.         //
  126.         // subtype:
  127.         static char const *const names[] = {
  128.             "cache parity/ECC error",
  129.             "bus error (DECERR)",
  130.             "bus error (SLVERR)",
  131.         };
  132.         fault_name = names[ subtype ];
  133.  
  134.     } else {
  135.         // phase:
  136.         //  2 section translation
  137.         //  4 page translation
  138.         //
  139.         // subtype:
  140.         static char const *const names[] = {
  141.             "translation fault",
  142.             "access flag fault",
  143.             "domain fault",
  144.             "permission fault",
  145.         };
  146.         fault_name = names[ subtype ];
  147.     }
  148.  
  149.     static char const *const phase_names[8] = {
  150.         NULL,
  151.         "section table walk",
  152.         "section translation",
  153.         "page table walk",
  154.         "page translation",
  155.         NULL,
  156.         NULL,
  157.         NULL,
  158.     };
  159.  
  160.     static char const *const access_names[] = {
  161.         "data read",
  162.         "data write",
  163.         "instruction fetch",
  164.         "i-side maintenance",
  165.     };
  166.  
  167.     printf( "\e[1;31m### %s on ", fault_name );
  168.     if( phase_names[ phase ] )
  169.         printf( "%s for ", phase_names[ phase ] );
  170.     printf( "%s at 0x%08x\e[m\n", access_names[ access ], addr );
  171.  
  172.     if( type == 0 )
  173.         printf( "fsr: 0x%08x\n", fsr );
  174.     abort_common( state, NULL );
  175. }
  176.  
  177.  
  178. //-------------- Exception handlers ------------------------------------------//
  179. //
  180. // These can't be called directly from the vector table but require small
  181. // assembly wrappers:  (Note: MODE_HND is defined at the top of this file)
  182. //
  183. // undef_exception:
  184. //  srsfd   sp!, MODE_HND   // push { lr, spsr } to handler stack
  185. //  cpsid   ia, MODE_HND    // change to handler mode, mask async aborts
  186. //  push    { r0-r12, lr }
  187. //  mov r0, sp
  188. //  blx undef_handler
  189. //  pop { r0-r12, lr }
  190. //  rfefd   sp!     // pop { pc, cpsr }
  191. //
  192. // iabort_exception:
  193. //  sub lr, 4       // fix return address
  194. //  srsfd   sp!, MODE_HND   // push { lr, spsr } to handler stack
  195. //  cpsid   ia, MODE_HND    // change to handler mode, mask async aborts
  196. //  push    { r0-r12, lr }
  197. //  mov r0, sp
  198. //  blx iabort_handler
  199. //  pop { r0-r12, lr }
  200. //  rfefd   sp!     // pop { pc, cpsr }
  201. //
  202. // dabort_exception:
  203. //  sub lr, 8       // fix return address
  204. //  srsfd   sp!, MODE_HND   // push { lr, spsr } to handler stack
  205. //  cpsid   ia, MODE_HND    // change to handler mode, mask async aborts
  206. //  push    { r0-r12, lr }
  207. //  mov r0, sp
  208. //  blx dabort_handler
  209. //  pop { r0-r12, lr }
  210. //  rfefd   sp!     // pop { pc, cpsr }
  211.  
  212. extern "C"
  213. void undef_handler( ExcState *state )
  214. {
  215.     if( state->psr & (1 << 5) ) {
  216.         // thumb (or thumbEE if psr bit 24 also set)
  217.         state->pc -= 2;
  218.  
  219.     } else if( state->psr & (1 << 24) ) {
  220.         // Can only happen on attempted exception return to jazelle
  221.         // state when not implemented.
  222.         //
  223.         // state->pc is undefined.
  224.  
  225.     } else {
  226.         // legacy ARM mode
  227.         state->pc -= 4;
  228.     }
  229.  
  230.     // Returning with the pc as corrected above will retry the instruction,
  231.     // which could be ok if for example you'd implement task switching with
  232.     // lazy fpu/neon register save/restore.
  233.     //
  234.     // If you emulate an instruction in thumb mode, don't forget to check
  235.     // the IT state whether it passes its condition and advance IT state.
  236.  
  237.     abort_common( state, "undefined instruction or invalid cpu state" );
  238. }
  239.  
  240. // Abort resulting from instruction fetch.
  241. extern "C"
  242. void iabort_handler( ExcState *state )
  243. {
  244.     uint32_t fsr;
  245.     asm( "mrc  p15, 0, %0, c5, c0, 1" : "=r"(fsr) );  // read IFSR
  246.     fsr |= 0x2000;
  247.  
  248.     switch( fsr & 0x040f ) {
  249.     case 0x0002:
  250.         return debug_breakpoint( state );
  251.     }
  252.  
  253.     uint32_t addr;
  254.     asm( "mrc  p15, 0, %0, c6, c0, 2" : "=r"(addr) );  // read IFAR
  255.  
  256.     return sync_abort_common( state, fsr, addr );
  257. }
  258.  
  259. // Abort resulting from instruction execution.
  260. extern "C"
  261. void dabort_handler( ExcState *state )
  262. {
  263.     uint32_t fsr;
  264.     asm( "mrc  p15, 0, %0, c5, c0, 0" : "=r"(fsr) );  // read DFSR
  265.  
  266.     switch( fsr & 0x040f ) {
  267.     case 0x0406:
  268.         return async_bus_error();
  269.     case 0x0408:
  270.         return async_parity_error();
  271.     case 0x0002:
  272.         return debug_watchpoint( state );
  273.     case 0x0004:
  274.         // Instruction-side maintenance fault.
  275.         asm( "mrc  p15, 0, %0, c5, c0, 1" : "=r"(fsr) );  // read IFSR
  276.         fsr |= 0x2800;
  277.         break;
  278.     }
  279.  
  280.     uint32_t addr;
  281.     asm( "mrc  p15, 0, %0, c6, c0, 0" : "=r"(addr) );  // read DFAR
  282.  
  283.     return sync_abort_common( state, fsr, addr );
  284. }
Advertisement
Add Comment
Please, Sign In to add comment