title: How to return from a Cortex-M3 Hard/Usage/Bus Fault?
body: <p>I am working on a microkernel for cortex-m3. I have created a small test application that intentionally causes a fault.</p>
  
  <p>Now I am unsure how to return from a fault. I understand that the stack likely needs to be updated with the address of a different function. I also understand that returning from faults could be a bad idea in some cases, but my kernel is written accordingly.</p>
  
  <p>Here's some sample code:</p>
  
  <pre><code>#include "core_cm3.h"
  
  // PSR flags
  
  // EPSR flags
  #define TFLG (1&lt;&lt;24)
  #define puts printk
  #define printf printk
  #define error printk
  // APSR flags
  #define NFLG (1&lt;&lt;31)
  #define ZFLG (1&lt;&lt;30)
  #define CFLG (1&lt;&lt;29)
  #define VFLG (1&lt;&lt;28)
  #define QFLG (1&lt;&lt;27)
  // IPSR flags
  #define ISR_THREADMODE  0
  #define ISR_NMI         2
  #define ISR_HARDFAULT   3
  #define ISR_MEMMANAGE   4
  #define ISR_BUSFAULT    5
  #define ISR_USAGEFAULT  6
  #define ISR_SVCALL      11
  #define ISR_PENDSV      14
  #define ISR_SYSTICK     15
  #define ISR_IRQ0        16
  
  // HFSR flags
  #define VECTTBL     (1&lt;&lt;1)
  #define FORCED      (1&lt;&lt;30)
  #define DEBUGEVT    (1&lt;&lt;31)
  
  // CFSR flags
  
  // BFSR flags
  #define IBUSERR     (1&lt;&lt;0)
  #define PRECISERR   (1&lt;&lt;1)
  #define IMPRECISERR (1&lt;&lt;2)
  #define UNSTKERR    (1&lt;&lt;3)
  #define STKERR      (1&lt;&lt;4)
  #define BFARVALID   (1&lt;&lt;7)
  
  // UFSR flags
  #define UNDEFINSTR  (1&lt;&lt;0)
  #define INVSTATE    (1&lt;&lt;1)
  #define INVPC       (1&lt;&lt;2)
  #define NOCP        (1&lt;&lt;3)
  #define UNALIGNED   (1&lt;&lt;8)
  #define DIVBYZERO   (1&lt;&lt;9)
  
  // MMFSR flags
  #define IACCVIOL    (1&lt;&lt;0)
  #define DACCVIOL    (1&lt;&lt;1)
  #define MUNSTKERR   (1&lt;&lt;3)
  #define MSTKERR     (1&lt;&lt;4)
  #define MMARVALID   (1&lt;&lt;7)
  
  // DFSR
  #define EXTERNAL    (1&lt;&lt;4)
  #define VCATCH      (1&lt;&lt;3)
  #define DWTTRAP     (1&lt;&lt;2)
  #define BKPT        (1&lt;&lt;1)
  #define HALTED      (1&lt;&lt;0)
  
  /** Hard Fault Handler code comes from these spots:
   *
   * http://blog.frankvh.com/2011/12/07/cortex-m3-m4-hard-fault-handler/
   * http://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
   */
  
  /**
   * This is the actual handler, which sets up the data to be used by the C function, then calls it.
   */
  void __attribute__((naked)) HardFault_Handler(void)
  {
      __asm__(
              ".thumb                                 \n"
              "   tst     lr, #4                      \n" // for priv/non-priv, test for msp or psp in return (thread or handler mode)
              "   ite     eq                          \n"
              "   mrseq   r0, MSP                     \n" // move main stack pointer into r0
              "   mrsne   r0, PSP                     \n" // move process stack pointer into r0
              "   b       hard_fault_handler          \n" // jump to the c function
              :
              :
              :
              );
  }
  
  /**
   * Here we print out the junk in the stack and some special registers to help with debugging.
   */
  void hard_fault_handler(unsigned int *hardfault_args)
  {
        unsigned int stacked_r0;
        unsigned int stacked_r1;
        unsigned int stacked_r2;
        unsigned int stacked_r3;
        unsigned int stacked_r12;
        unsigned int stacked_lr;
        unsigned int stacked_pc;
        unsigned int stacked_psr;
        unsigned int cfsr, bfsr, ufsr, mmfsr;
        //unsigned int control;
  
        stacked_r0 = ((unsigned long) hardfault_args[0]);
        stacked_r1 = ((unsigned long) hardfault_args[1]);
        stacked_r2 = ((unsigned long) hardfault_args[2]);
        stacked_r3 = ((unsigned long) hardfault_args[3]);
  
        stacked_r12 = ((unsigned long) hardfault_args[4]);
        stacked_lr = ((unsigned long) hardfault_args[5]);
        stacked_pc = ((unsigned long) hardfault_args[6]);
        stacked_psr = ((unsigned long) hardfault_args[7]);
        //control = __get_CONTROL();
  
        // TODO 2: Eliminate printf
  
        puts("\n\n[Hard fault]\n");
        printf("R0 = 0x%08x\n", stacked_r0);
        printf("R1 = 0x%08x\n", stacked_r1);
        printf("R2 = 0x%08x\n", stacked_r2);
        printf("R3 = 0x%08x\n", stacked_r3);
        printf("R12 = 0x%08x\n", stacked_r12);
        printf("LR [R14] = 0x%08x  subroutine call return address.\n", stacked_lr);
        printf("PC [R15] = 0x%08x  program counter\n", stacked_pc);
  
        // PSR
        printf("PSR = 0x%04x ", stacked_psr);
        if (stacked_psr &amp; NFLG) printf("N");
        if (stacked_psr &amp; ZFLG) printf("Z");
        if (stacked_psr &amp; CFLG) printf("C");
        if (stacked_psr &amp; VFLG) printf("V");
        if (stacked_psr &amp; QFLG) printf("Q");
        puts(" ");
        unsigned int isrnum = (stacked_psr &amp; 0xff);
        switch (isrnum) {
        case ISR_THREADMODE:
            puts("Thread mode ");
            break;
        case ISR_NMI:
            puts("NMI ");
            break;
        case ISR_HARDFAULT:
            puts("HardFault ");
            break;
        case ISR_MEMMANAGE:
            puts("MemManage ");
            break;
        case ISR_BUSFAULT:
            puts("BusFault ");
            break;
        case ISR_USAGEFAULT:
            puts("UsageFault ");
            break;
        case ISR_SVCALL:
            puts("SVCall ");
            break;
        case ISR_PENDSV:
            puts("PendSV ");
            break;
        case ISR_SYSTICK:
            puts("SysTick ");
            break;
        case ISR_IRQ0:
            puts("IRQ0 ");
            break;
        }
        printf(" ");
        if (stacked_psr &amp; TFLG)
            printf("thumb");
        else
            printf("non-thumb");
        puts("\n");
  
        // CONTROL (not sure this works...)
        //printf("CONTROL = 0x%04x ", control);
        //printf("\n");
  
        // HFSR
        printf("HFSR = 0x%08x ", SCB-&gt;HFSR);
        if (SCB-&gt;HFSR &amp; DEBUGEVT) printf("DEBUGEVT ");
        if (SCB-&gt;HFSR &amp; FORCED) printf("Forced Hard fault ");
        if (SCB-&gt;HFSR &amp; VECTTBL) printf("VECTTBL ");
        puts("\n");
        // CFSR
        printf("CFSR = 0x%08x\n", SCB-&gt;CFSR);
        cfsr = SCB-&gt;CFSR;
        ufsr = (cfsr&gt;&gt;16);
        printf("UFSR = 0x%04x ", ufsr);
        if (ufsr &amp; DIVBYZERO) printf("Divide by zero UsageFault ");
        if (ufsr &amp; UNALIGNED) printf("Unaligned access UsageFault ");
        if (ufsr &amp; NOCP) printf("No coprocessor UsageFault ");
        if (ufsr &amp; INVPC) printf("Invalid PC load UsageFault ");
        if (ufsr &amp; INVSTATE) printf("Invalid state UsageFault ");
        if (ufsr &amp; UNDEFINSTR) printf("Undefined instruction UsageFault ");
        puts("\n");
  
        // BFSR
        bfsr = ((cfsr &gt;&gt; 8) &amp; 0xff);
        printf("BFSR = 0x%02x ", bfsr);
        if ((bfsr &amp; IBUSERR) != 0) printf("IBUSERR ");
        if ((bfsr &amp; PRECISERR) != 0) printf("Precise Data Bus Error ");
        if ((bfsr &amp; IMPRECISERR) != 0) printf("Imprecise Data Bus Error ");
        if (bfsr &amp; UNSTKERR) printf("Unstacking Error ");
        if (bfsr &amp; STKERR) printf("Stacking error ");
        if (bfsr &amp; BFARVALID) printf("Bus Fault Address Register Valid ");
        printf("\n");
        // BFAR
        //The value of SCB-&gt;BFAR indicates the memory address that caused a Bus Fault and is valid if the bit BFARVALID in the
        //SCB-&gt;CFSR register is set.
        puts("BFAR = ");
        if (bfsr &amp; BFARVALID) {
            printf("0x%08x\n", SCB-&gt;BFAR);
        } else {
            puts("invalid\n");
        }
  
        // MMFSR
        mmfsr = (cfsr &amp; 0xff);
        printf("MMFSR = 0x%02x ", mmfsr);
        if (mmfsr &amp; IACCVIOL) printf("Instruction Access Violation ");
        if (mmfsr &amp; DACCVIOL) printf("Data Access Violation ");
        if (mmfsr &amp; MUNSTKERR) printf("Memory Unstacking Error ");
        if (mmfsr &amp; MSTKERR) printf("Memory Stacking Error ");
        if (mmfsr &amp; MMARVALID) printf("MMARVALID ");
        puts("\n");
        // MMFAR
        // The value of SCB-&gt;MMFAR indicates the memory address that caused a Memory Management Fault and is valid if the bit
        // MMARVALID in the SCB-&gt;CFSR register is set.
        puts("MMFAR = ");
        if (mmfsr &amp; MMARVALID) {
            printf("0x%08x ", SCB-&gt;MMFAR);
        } else {
            printf("invalid\n");
        }
  
        // DFSR
        printf("DFSR = 0x%08lx ", SCB-&gt;DFSR);
        if (SCB-&gt;DFSR &amp; EXTERNAL) printf("EXTERNAL ");
        if (SCB-&gt;DFSR &amp; VCATCH) printf("VCATCH ");
        if (SCB-&gt;DFSR &amp; DWTTRAP) printf("DWTTRAP ");
        if (SCB-&gt;DFSR &amp; BKPT) printf("BKPT ");
        if (SCB-&gt;DFSR &amp; HALTED) printf("HALTED ");
        puts("\n");
  
        printf("AFSR = 0x%08lx\n", SCB-&gt;AFSR);
        printf("SHCSR = 0x%08lx\n", SCB-&gt;SHCSR);
        __asm volatile("BKPT #01\n"); // &lt;-- **I want to return here**
        while (1); 
  }
  
  /*
  void HardFault_Handler(void) {
      while(1);
      error("\n\n%% Hard Fault %%\n");
  }
  */
  
  void UsageFault_Handler(void) {
      error("\n\n%% Usage Fault %%\n");
  }
  
  void BusFault_Handler() {
      error("\n\n%% Bus Fault %%\n");
  }
  
  void MemMang_Handler() {
      error("\n\n%% MemMang Fault %%\n");
  }
  </code></pre>
  
  <p>I have marked the line I want to return at. I currently have the Usage/Bus/Memory faults disabled but can enable them if required.</p>
  
  <p>Help would be appreciated.</p>