2016-11-28 39 views
-1

나는 cortex-m3 용 마이크로 커널에서 일하고있다. 의도적으로 오류를 일으키는 작은 테스트 응용 프로그램을 만들었습니다.Cortex-M3 하드/사용/버스 오류에서 복귀하는 방법?

이제 결함에서 어떻게 복귀해야할지 확신이 없습니다. 스택이 다른 기능의 주소로 업데이트 될 가능성이 있음을 이해합니다. 나는 또한 결함으로 돌아 오는 것이 나쁜 생각 일 수 있음을 이해하지만 커널은 적절하게 작성되었다.

#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"); 
} 

나는에 반환 할 행을 표시 한 :

는 여기에 몇 가지 예제 코드입니다. 현재 사용/버스/메모리 오류는 비활성화되어 있지만 필요할 경우 활성화 할 수 있습니다.

도움을 받으실 수 있습니다.

+0

'1 << 31 "은 정의되지 않은 동작을 호출합니다. 당신은 어쨌든 대부분의 레지스터에 대해 잘못된 유형이 있습니다. 너는 너무 넓고/우스꽝 스럽다. 올바른 코드 작성에 집중하십시오. 일반적으로 hardfault가 발생하면 무언가 잘못되었다가 돌아오고 싶은게 거의 없습니다. – Olaf

+0

@Olaf 알아요.하지만이 경우 RTOS의'exit()'함수로 돌아가서 끝내고 싶습니다. –

+0

@Olaf 핸들러가 완벽한 레지스터 크기를 갖도록 설계되지 않았습니다. 1. 나는 그것을 쓰지 않았다. 2. 지금은 작동 –

답변

1

필요한 모든 정보는 ARM cortex M3 기술 참조 설명서에 나와 있습니다.

오류를 유발 한 명령, 오류를 일으킨 주소 반입, 이유 등을 쿼리 할 수 ​​있습니다. 오류가 발생하기 전에 정확한 프로세서 상태를 재구성 할 수 있습니다. 예를 들어 주문형 호출이 수행되는 방식입니다.

그러나 "하드 오류"상태 인 경우 나머지 시스템 (하드웨어 주변 장치 및 버스 인프라 포함)은 의미있는 방식으로 계속 될 수 있습니다. 귀하의 버스 중재인은 잠겨있을 수 있습니다; 메모리 컨트롤러가 fubar되었을 수 있습니다, 코드 메모리가 손상되었을 수 있습니다. 당신은 절전을 경험할 수 있었고 어떤 논리는 사라졌습니다. 당신이 알 수없고 실제로 복구 할 수없는 잘못된 것일 수있는 끝없는 목록이 있습니다.

+0

그 정보를 여기에서 재현 할 수 있습니까? –

+0

@MarkYisri 단순히 자르고 붙여 넣기 만하는 것이 아닙니다. "cortex m3 technical reference manual"을 검색하면 ARM에서 쉽게 찾을 수 있고 무료로 제공됩니다. –

+0

좋아요, 저 TRM 있습니다. –