简体   繁体   English

如何从Cortex-M3硬/使用/总线故障中返回?

[英]How to return from a Cortex-M3 Hard/Usage/Bus Fault?

I am working on a microkernel for cortex-m3. 我正在为cortex-m3开发微内核。 I have created a small test application that intentionally causes a fault. 我创建了一个小型测试应用程序,有意导致故障。

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. 我也理解从错误中恢复可能在某些情况下是个坏主意,但我的内核是按照相应的方式编写的。

Here's some sample code: 这是一些示例代码:

#include "core_cm3.h"

// PSR flags

// EPSR flags
#define TFLG (1<<24)
#define puts printk
#define printf printk
#define error printk
// APSR flags
#define NFLG (1<<31)
#define ZFLG (1<<30)
#define CFLG (1<<29)
#define VFLG (1<<28)
#define QFLG (1<<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<<1)
#define FORCED      (1<<30)
#define DEBUGEVT    (1<<31)

// CFSR flags

// BFSR flags
#define IBUSERR     (1<<0)
#define PRECISERR   (1<<1)
#define IMPRECISERR (1<<2)
#define UNSTKERR    (1<<3)
#define STKERR      (1<<4)
#define BFARVALID   (1<<7)

// UFSR flags
#define UNDEFINSTR  (1<<0)
#define INVSTATE    (1<<1)
#define INVPC       (1<<2)
#define NOCP        (1<<3)
#define UNALIGNED   (1<<8)
#define DIVBYZERO   (1<<9)

// MMFSR flags
#define IACCVIOL    (1<<0)
#define DACCVIOL    (1<<1)
#define MUNSTKERR   (1<<3)
#define MSTKERR     (1<<4)
#define MMARVALID   (1<<7)

// DFSR
#define EXTERNAL    (1<<4)
#define VCATCH      (1<<3)
#define DWTTRAP     (1<<2)
#define BKPT        (1<<1)
#define HALTED      (1<<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 & NFLG) printf("N");
      if (stacked_psr & ZFLG) printf("Z");
      if (stacked_psr & CFLG) printf("C");
      if (stacked_psr & VFLG) printf("V");
      if (stacked_psr & QFLG) printf("Q");
      puts(" ");
      unsigned int isrnum = (stacked_psr & 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 & 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->HFSR);
      if (SCB->HFSR & DEBUGEVT) printf("DEBUGEVT ");
      if (SCB->HFSR & FORCED) printf("Forced Hard fault ");
      if (SCB->HFSR & VECTTBL) printf("VECTTBL ");
      puts("\n");
      // CFSR
      printf("CFSR = 0x%08x\n", SCB->CFSR);
      cfsr = SCB->CFSR;
      ufsr = (cfsr>>16);
      printf("UFSR = 0x%04x ", ufsr);
      if (ufsr & DIVBYZERO) printf("Divide by zero UsageFault ");
      if (ufsr & UNALIGNED) printf("Unaligned access UsageFault ");
      if (ufsr & NOCP) printf("No coprocessor UsageFault ");
      if (ufsr & INVPC) printf("Invalid PC load UsageFault ");
      if (ufsr & INVSTATE) printf("Invalid state UsageFault ");
      if (ufsr & UNDEFINSTR) printf("Undefined instruction UsageFault ");
      puts("\n");

      // BFSR
      bfsr = ((cfsr >> 8) & 0xff);
      printf("BFSR = 0x%02x ", bfsr);
      if ((bfsr & IBUSERR) != 0) printf("IBUSERR ");
      if ((bfsr & PRECISERR) != 0) printf("Precise Data Bus Error ");
      if ((bfsr & IMPRECISERR) != 0) printf("Imprecise Data Bus Error ");
      if (bfsr & UNSTKERR) printf("Unstacking Error ");
      if (bfsr & STKERR) printf("Stacking error ");
      if (bfsr & BFARVALID) printf("Bus Fault Address Register Valid ");
      printf("\n");
      // BFAR
      //The value of SCB->BFAR indicates the memory address that caused a Bus Fault and is valid if the bit BFARVALID in the
      //SCB->CFSR register is set.
      puts("BFAR = ");
      if (bfsr & BFARVALID) {
          printf("0x%08x\n", SCB->BFAR);
      } else {
          puts("invalid\n");
      }

      // MMFSR
      mmfsr = (cfsr & 0xff);
      printf("MMFSR = 0x%02x ", mmfsr);
      if (mmfsr & IACCVIOL) printf("Instruction Access Violation ");
      if (mmfsr & DACCVIOL) printf("Data Access Violation ");
      if (mmfsr & MUNSTKERR) printf("Memory Unstacking Error ");
      if (mmfsr & MSTKERR) printf("Memory Stacking Error ");
      if (mmfsr & MMARVALID) printf("MMARVALID ");
      puts("\n");
      // MMFAR
      // The value of SCB->MMFAR indicates the memory address that caused a Memory Management Fault and is valid if the bit
      // MMARVALID in the SCB->CFSR register is set.
      puts("MMFAR = ");
      if (mmfsr & MMARVALID) {
          printf("0x%08x ", SCB->MMFAR);
      } else {
          printf("invalid\n");
      }

      // DFSR
      printf("DFSR = 0x%08lx ", SCB->DFSR);
      if (SCB->DFSR & EXTERNAL) printf("EXTERNAL ");
      if (SCB->DFSR & VCATCH) printf("VCATCH ");
      if (SCB->DFSR & DWTTRAP) printf("DWTTRAP ");
      if (SCB->DFSR & BKPT) printf("BKPT ");
      if (SCB->DFSR & HALTED) printf("HALTED ");
      puts("\n");

      printf("AFSR = 0x%08lx\n", SCB->AFSR);
      printf("SHCSR = 0x%08lx\n", SCB->SHCSR);
      __asm volatile("BKPT #01\n"); // <-- **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");
}

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. 我目前已禁用“用法/总线/内存”故障,但可以根据需要启用它们。

Help would be appreciated. 帮助将不胜感激。

All the information you need is found in ARM cortex M3 technical reference manual. 您需要的所有信息都可以在《 ARM cortex M3技术参考手册》中找到。

You are able to query the PC that gave issued the instruction that caused the fault, the fetch address that caused the fault, the reason, etc. You can reconstruct the exact processor state prior to the fault occurring. 您可以查询发出了引起故障的指令的PC,引起故障的读取地址,原因等。您可以在发生故障之前重建确切的处理器状态。 This is how on-demand paging is accomplished, for example. 例如,这就是完成按需寻呼的方式。

HOWEVER, if you're at "hard fault", there's no guarantee the rest of the system (hardware peripherals and bus infrastructure included) is capable of continuing in any meaningful way. 但是,如果您遇到“硬故障”,则不能保证系统的其余部分(包括硬件外围设备和总线基础结构)都能够以任何有意义的方式继续运行。 Your bus arbiter may be locked up; 您的总线仲裁器可能被锁定; your memory controller may be fubarred, your code memory may be corrupted. 您的内存控制器可能被锁定,您的代码内存可能已损坏。 You may have experienced a brownout and some logic has gone south. 您可能经历了电力不足的情况,并且有些逻辑已经失效。 There's an endless list of things that may be wrong that you can't know and can't really recover from. 有不计其数的事情可能是错误的,您不知道并且无法真正从中恢复。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM