mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #12824 from kjbracey-arm/faultasm
Optimise fault handler assemblypull/13152/head
commit
62c2431344
|
|
@ -36,7 +36,7 @@ static mbed_error_ctx saved_error_ctx = {0};
|
||||||
void mbed_error_reboot_callback(mbed_error_ctx *error_context)
|
void mbed_error_reboot_callback(mbed_error_ctx *error_context)
|
||||||
{
|
{
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_UINT((uint32_t)error_context, ERROR_CONTEXT_LOCATION);
|
TEST_ASSERT_EQUAL_PTR(error_context, &MBED_CRASH_DATA);
|
||||||
memcpy(&saved_error_ctx, error_context, sizeof(mbed_error_ctx));
|
memcpy(&saved_error_ctx, error_context, sizeof(mbed_error_ctx));
|
||||||
mbed_reset_reboot_error_info();
|
mbed_reset_reboot_error_info();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,15 @@
|
||||||
#ifndef MBED_FAULT_HANDLER_H
|
#ifndef MBED_FAULT_HANDLER_H
|
||||||
#define MBED_FAULT_HANDLER_H
|
#define MBED_FAULT_HANDLER_H
|
||||||
|
|
||||||
|
#include "mbed_toolchain.h"
|
||||||
|
#include "mbed_error.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Fault context struct
|
//Fault context struct
|
||||||
|
#ifdef TARGET_CORTEX_M
|
||||||
//WARNING: DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
|
//WARNING: DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
|
||||||
//Offset of these registers are used by fault handler in except.S
|
//Offset of these registers are used by fault handler in except.S
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -48,24 +52,55 @@ typedef struct {
|
||||||
uint32_t EXC_RETURN;
|
uint32_t EXC_RETURN;
|
||||||
uint32_t CONTROL;
|
uint32_t CONTROL;
|
||||||
} mbed_fault_context_t;
|
} mbed_fault_context_t;
|
||||||
|
#elif defined TARGET_CORTEX_A
|
||||||
|
// This is not currently used, but would be a plausible implementation
|
||||||
|
typedef struct {
|
||||||
|
uint32_t R0_reg;
|
||||||
|
uint32_t R1_reg;
|
||||||
|
uint32_t R2_reg;
|
||||||
|
uint32_t R3_reg;
|
||||||
|
uint32_t R4_reg;
|
||||||
|
uint32_t R5_reg;
|
||||||
|
uint32_t R6_reg;
|
||||||
|
uint32_t R7_reg;
|
||||||
|
uint32_t R8_reg;
|
||||||
|
uint32_t R9_reg;
|
||||||
|
uint32_t R10_reg;
|
||||||
|
uint32_t R11_reg;
|
||||||
|
uint32_t R12_reg;
|
||||||
|
uint32_t SP_reg;
|
||||||
|
uint32_t LR_reg;
|
||||||
|
uint32_t PC_reg;
|
||||||
|
uint32_t CPSR;
|
||||||
|
uint32_t SP_usr;
|
||||||
|
uint32_t LR_usr;
|
||||||
|
} mbed_fault_context_t;
|
||||||
|
#else
|
||||||
|
// Dummy for mbed_crash_data_t
|
||||||
|
typedef struct {
|
||||||
|
} mbed_fault_context_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//Fault type definitions
|
//Fault type definitions
|
||||||
|
#ifdef TARGET_CORTEX_M
|
||||||
//WARNING: DO NOT CHANGE THESE VALUES WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
|
//WARNING: DO NOT CHANGE THESE VALUES WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
|
||||||
#define HARD_FAULT_EXCEPTION (0x10) //Keep some gap between values for any future insertion/expansion
|
#define HARD_FAULT_EXCEPTION (0x10) //Keep some gap between values for any future insertion/expansion
|
||||||
#define MEMMANAGE_FAULT_EXCEPTION (0x20)
|
#define MEMMANAGE_FAULT_EXCEPTION (0x20)
|
||||||
#define BUS_FAULT_EXCEPTION (0x30)
|
#define BUS_FAULT_EXCEPTION (0x30)
|
||||||
#define USAGE_FAULT_EXCEPTION (0x40)
|
#define USAGE_FAULT_EXCEPTION (0x40)
|
||||||
|
#endif
|
||||||
|
|
||||||
//This is a handler function called from Fault handler to print the error information out.
|
//This is a handler function called from Fault handler to print the error information out.
|
||||||
//This runs in fault context and uses special functions(defined in mbed_fault_handler.c) to print the information without using C-lib support.
|
//This runs in fault context and uses special functions(defined in mbed_fault_handler.c) to print the information without using C-lib support.
|
||||||
void mbed_fault_handler(uint32_t fault_type, const mbed_fault_context_t *mbed_fault_context_in);
|
MBED_NORETURN void mbed_fault_handler(uint32_t fault_type, const mbed_fault_context_t *mbed_fault_context_in);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this function to retrieve the fault context after a fatal exception which triggered a system reboot. The function retrieves the fault context stored in crash-report ram area which is preserved over reboot.
|
* Call this function to retrieve the fault context after a fatal exception which triggered a system reboot. The function retrieves the fault context stored in crash-report ram area which is preserved over reboot.
|
||||||
* @param fault_context Pointer to mbed_fault_context_t struct allocated by the caller. This is the mbed_fault_context_t info captured as part of the fatal exception which triggered the reboot.
|
* @param fault_context Pointer to mbed_fault_context_t struct allocated by the caller. This is the mbed_fault_context_t info captured as part of the fatal exception which triggered the reboot.
|
||||||
* @return 0 or MBED_SUCCESS on success.
|
* @return 0 or MBED_SUCCESS on success.
|
||||||
* MBED_ERROR_INVALID_ARGUMENT in case of invalid error_info pointer
|
* MBED_ERROR_INVALID_ARGUMENT in case of invalid error_info pointer
|
||||||
* MBED_ERROR_ITEM_NOT_FOUND if no reboot context is currently captured by teh system
|
* MBED_ERROR_ITEM_NOT_FOUND if no reboot context is currently captured by the system
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
mbed_error_status_t mbed_get_reboot_fault_context(mbed_fault_context_t *fault_context);
|
mbed_error_status_t mbed_get_reboot_fault_context(mbed_fault_context_t *fault_context);
|
||||||
|
|
@ -27,136 +27,98 @@
|
||||||
#define DOMAIN_NS 1
|
#define DOMAIN_NS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FAULT_TYPE_HARD_FAULT EQU 0x10
|
FAULT_TYPE_HARD_FAULT EQU 0x10
|
||||||
FAULT_TYPE_MEMMANAGE_FAULT EQU 0x20
|
FAULT_TYPE_MEMMANAGE_FAULT EQU 0x20
|
||||||
FAULT_TYPE_BUS_FAULT EQU 0x30
|
FAULT_TYPE_BUS_FAULT EQU 0x30
|
||||||
FAULT_TYPE_USAGE_FAULT EQU 0x40
|
FAULT_TYPE_USAGE_FAULT EQU 0x40
|
||||||
|
|
||||||
PRESERVE8
|
PRESERVE8
|
||||||
THUMB
|
THUMB
|
||||||
|
|
||||||
AREA |.text|, CODE, READONLY
|
AREA |.text|, CODE, READONLY
|
||||||
|
|
||||||
HardFault_Handler\
|
HardFault_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT HardFault_Handler
|
EXPORT HardFault_Handler
|
||||||
LDR R3,=FAULT_TYPE_HARD_FAULT
|
MOVS R3,#FAULT_TYPE_HARD_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
MemManage_Handler\
|
MemManage_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT MemManage_Handler
|
EXPORT MemManage_Handler
|
||||||
LDR R3,=FAULT_TYPE_MEMMANAGE_FAULT
|
MOVS R3,#FAULT_TYPE_MEMMANAGE_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
BusFault_Handler\
|
BusFault_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT BusFault_Handler
|
EXPORT BusFault_Handler
|
||||||
LDR R3,=FAULT_TYPE_BUS_FAULT
|
MOVS R3,#FAULT_TYPE_BUS_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
UsageFault_Handler\
|
UsageFault_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT UsageFault_Handler
|
EXPORT UsageFault_Handler
|
||||||
LDR R3,=FAULT_TYPE_USAGE_FAULT
|
MOVS R3,#FAULT_TYPE_USAGE_FAULT
|
||||||
B Fault_Handler
|
; Fall into Fault_Handler
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
Fault_Handler PROC
|
Fault_Handler\
|
||||||
EXPORT Fault_Handler
|
PROC
|
||||||
|
EXPORT Fault_Handler
|
||||||
#if (DOMAIN_NS == 1)
|
#if (DOMAIN_NS == 1)
|
||||||
IMPORT mbed_fault_handler
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
IMPORT mbed_fault_context
|
#define mbed_fault_context |Image$$RW_m_crash_data$$ZI$$Base|
|
||||||
|
#endif
|
||||||
|
IMPORT mbed_fault_context
|
||||||
|
IMPORT mbed_fault_handler
|
||||||
|
|
||||||
MRS R0,MSP
|
MOV R12,R3
|
||||||
LDR R1,=0x4
|
PUSH {R4-R7}
|
||||||
MOV R2,LR
|
ADD R6,SP,#16
|
||||||
TST R2,R1 ; Check EXC_RETURN for bit 2
|
MOV R5,LR
|
||||||
BEQ Fault_Handler_Continue
|
LSRS R0,R5,#3 ; Check EXC_RETURN for bit 2
|
||||||
MRS R0,PSP
|
BCC Fault_Handler_Continue
|
||||||
|
MRS R6,PSP
|
||||||
|
|
||||||
Fault_Handler_Continue
|
Fault_Handler_Continue
|
||||||
MOV R12,R3
|
LDR R7,=mbed_fault_context
|
||||||
LDR R3,=mbed_fault_context
|
LDMIA R6!,{R0-R3}
|
||||||
LDR R1,[R3]
|
STMIA R7!,{R0-R3} ; Capture R0..R3
|
||||||
LDR R2,[R0] ; Capture R0
|
POP {R0-R3}
|
||||||
STR R2,[R1]
|
STMIA R7!,{R0-R3} ; Capture R4..R7
|
||||||
ADDS R1,#4
|
MOV R0,R8
|
||||||
LDR R2,[R0,#4] ; Capture R1
|
MOV R1,R9
|
||||||
STR R2,[R1]
|
MOV R2,R10
|
||||||
ADDS R1,#4
|
MOV R3,R11
|
||||||
LDR R2,[R0,#8] ; Capture R2
|
STMIA R7!,{R0-R3} ; Capture R8..R11
|
||||||
STR R2,[R1]
|
LDMIA R6!,{R0,R2-R4} ; Load R12,LR,PC,xPSR
|
||||||
ADDS R1,#4
|
; Adjust stack pointer to its original value
|
||||||
LDR R2,[R0,#12] ; Capture R3
|
MOVS R1,R6
|
||||||
STR R2,[R1]
|
LSRS R6,R4,#10 ; Check for if STK was aligned by checking bit-9 in xPSR value
|
||||||
ADDS R1,#4
|
BCC Fault_Handler_Continue1
|
||||||
STMIA R1!,{R4-R7} ; Capture R4..R7
|
ADDS R1,#0x4
|
||||||
MOV R7,R8 ; Capture R8
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R9 ; Capture R9
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R10 ; Capture R10
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R11 ; Capture R11
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#16] ; Capture R12
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#8 ; Add 8 here to capture LR next, we will capture SP later
|
|
||||||
LDR R2,[R0,#20] ; Capture LR
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#24] ; Capture PC
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#28] ; Capture xPSR
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
; Adjust stack pointer to its original value and capture it
|
|
||||||
MOV R3,R0
|
|
||||||
ADDS R3,#0x20 ; Add 0x20 to get the SP value prior to exception
|
|
||||||
LDR R6,=0x200
|
|
||||||
TST R2,R6 ; Check for if STK was aligned by checking bit-9 in xPSR value
|
|
||||||
BEQ Fault_Handler_Continue1
|
|
||||||
ADDS R3,#0x4
|
|
||||||
|
|
||||||
Fault_Handler_Continue1
|
Fault_Handler_Continue1
|
||||||
MOV R5,LR
|
LSRS R6,R5,#5 ; Check EXC_RETURN bit-4 to see if FP context was saved
|
||||||
LDR R6,=0x10 ; Check for bit-4 to see if FP context was saved
|
BCS Fault_Handler_Continue2
|
||||||
TST R5,R6
|
ADDS R1,#0x48 ; 16 FP regs + FPCSR + 1 Reserved
|
||||||
BNE Fault_Handler_Continue2
|
|
||||||
ADDS R3,#0x48 ; 16 FP regs + FPCSR + 1 Reserved
|
|
||||||
|
|
||||||
Fault_Handler_Continue2
|
Fault_Handler_Continue2
|
||||||
MOV R4,R1
|
STMIA R7!,{R0-R4} ; Capture R12,SP,LR,PC,xPSR
|
||||||
SUBS R4,#0x10 ; Set the location of SP in ctx
|
MRS R0,PSP
|
||||||
STR R3,[R4] ; Capture the adjusted SP
|
MOV R1,SP
|
||||||
MRS R2,PSP ; Get PSP
|
MRS R6,CONTROL
|
||||||
STR R2,[R1]
|
STMIA R7!,{R0,R1,R5,R6} ; Capture PSP,MSP,EXC_RETURN,CONTROL
|
||||||
ADDS R1,#4
|
MOV R0,R12
|
||||||
MRS R2,MSP ; Get MSP
|
LDR R1,=mbed_fault_context
|
||||||
STR R2,[R1]
|
BL mbed_fault_handler ; mbed_fault_handler does not return
|
||||||
ADDS R1,#4
|
#else
|
||||||
MOV R2,LR ; Get current LR(EXC_RETURN)
|
B .
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MRS R2,CONTROL ; Get CONTROL Reg
|
|
||||||
STR R2,[R1]
|
|
||||||
MOV R0,R12
|
|
||||||
LDR R3,=mbed_fault_context
|
|
||||||
LDR R1,[R3]
|
|
||||||
BL mbed_fault_handler
|
|
||||||
#endif
|
#endif
|
||||||
B . ; Just in case we come back here
|
ENDP
|
||||||
ENDP
|
ALIGN
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
|
||||||
|
|
@ -23,17 +23,17 @@
|
||||||
*/
|
*/
|
||||||
#ifndef MBED_FAULT_HANDLER_DISABLED
|
#ifndef MBED_FAULT_HANDLER_DISABLED
|
||||||
|
|
||||||
.file "except.S"
|
.file "except.S"
|
||||||
.syntax unified
|
.syntax unified
|
||||||
|
|
||||||
#ifndef DOMAIN_NS
|
#ifndef DOMAIN_NS
|
||||||
#define DOMAIN_NS 1
|
#define DOMAIN_NS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.equ FAULT_TYPE_HARD_FAULT, 0x10
|
.equ FAULT_TYPE_HARD_FAULT, 0x10
|
||||||
.equ FAULT_TYPE_MEMMANAGE_FAULT, 0x20
|
.equ FAULT_TYPE_MEMMANAGE_FAULT, 0x20
|
||||||
.equ FAULT_TYPE_BUS_FAULT, 0x30
|
.equ FAULT_TYPE_BUS_FAULT, 0x30
|
||||||
.equ FAULT_TYPE_USAGE_FAULT, 0x40
|
.equ FAULT_TYPE_USAGE_FAULT, 0x40
|
||||||
|
|
||||||
.thumb
|
.thumb
|
||||||
.section ".text"
|
.section ".text"
|
||||||
|
|
@ -41,159 +41,120 @@
|
||||||
|
|
||||||
//HardFault_Handler
|
//HardFault_Handler
|
||||||
.thumb_func
|
.thumb_func
|
||||||
.type HardFault_Handler, %function
|
.type HardFault_Handler, %function
|
||||||
.global HardFault_Handler
|
.global HardFault_Handler
|
||||||
.fnstart
|
.fnstart
|
||||||
.cantunwind
|
.cantunwind
|
||||||
|
|
||||||
HardFault_Handler:
|
HardFault_Handler:
|
||||||
LDR R3,=FAULT_TYPE_HARD_FAULT
|
MOVS R3,#FAULT_TYPE_HARD_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
|
|
||||||
.fnend
|
.fnend
|
||||||
.size HardFault_Handler, .-HardFault_Handler
|
.size HardFault_Handler, .-HardFault_Handler
|
||||||
|
|
||||||
//MemManage_Handler
|
//MemManage_Handler
|
||||||
.thumb_func
|
.thumb_func
|
||||||
.type MemManage_Handler, %function
|
.type MemManage_Handler, %function
|
||||||
.global MemManage_Handler
|
.global MemManage_Handler
|
||||||
.fnstart
|
.fnstart
|
||||||
.cantunwind
|
.cantunwind
|
||||||
|
|
||||||
MemManage_Handler:
|
MemManage_Handler:
|
||||||
LDR R3,=FAULT_TYPE_MEMMANAGE_FAULT
|
MOVS R3,#FAULT_TYPE_MEMMANAGE_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
|
|
||||||
.fnend
|
.fnend
|
||||||
.size MemManage_Handler, .-MemManage_Handler
|
.size MemManage_Handler, .-MemManage_Handler
|
||||||
|
|
||||||
//BusFault_Handler
|
//BusFault_Handler
|
||||||
.thumb_func
|
.thumb_func
|
||||||
.type BusFault_Handler, %function
|
.type BusFault_Handler, %function
|
||||||
.global BusFault_Handler
|
.global BusFault_Handler
|
||||||
.fnstart
|
.fnstart
|
||||||
.cantunwind
|
.cantunwind
|
||||||
|
|
||||||
BusFault_Handler:
|
BusFault_Handler:
|
||||||
LDR R3,=FAULT_TYPE_BUS_FAULT
|
MOVS R3,#FAULT_TYPE_BUS_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
|
|
||||||
.fnend
|
.fnend
|
||||||
.size BusFault_Handler, .-BusFault_Handler
|
.size BusFault_Handler, .-BusFault_Handler
|
||||||
|
|
||||||
//UsageFault_Handler
|
//UsageFault_Handler
|
||||||
.thumb_func
|
.thumb_func
|
||||||
.type UsageFault_Handler, %function
|
.type UsageFault_Handler, %function
|
||||||
.global UsageFault_Handler
|
.global UsageFault_Handler
|
||||||
.fnstart
|
.fnstart
|
||||||
.cantunwind
|
.cantunwind
|
||||||
|
|
||||||
UsageFault_Handler:
|
UsageFault_Handler:
|
||||||
LDR R3,=FAULT_TYPE_USAGE_FAULT
|
MOVS R3,#FAULT_TYPE_USAGE_FAULT
|
||||||
B Fault_Handler
|
// Fall into Fault_Handler
|
||||||
|
|
||||||
.fnend
|
.fnend
|
||||||
.size UsageFault_Handler, .-UsageFault_Handler
|
.size UsageFault_Handler, .-UsageFault_Handler
|
||||||
|
|
||||||
//Common Fault_Handler to capture the context
|
//Common Fault_Handler to capture the context
|
||||||
.thumb_func
|
.thumb_func
|
||||||
.type Fault_Handler, %function
|
.type Fault_Handler, %function
|
||||||
.global Fault_Handler
|
.global Fault_Handler
|
||||||
.fnstart
|
.fnstart
|
||||||
.cantunwind
|
.cantunwind
|
||||||
|
|
||||||
Fault_Handler:
|
Fault_Handler:
|
||||||
#if (DOMAIN_NS == 1)
|
#if (DOMAIN_NS == 1)
|
||||||
MRS R0,MSP
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
LDR R1,=0x4
|
#define mbed_fault_context __CRASH_DATA_RAM_START__
|
||||||
MOV R2,LR
|
#endif
|
||||||
TST R2,R1 // Check EXC_RETURN for bit 2
|
|
||||||
BEQ Fault_Handler_Continue
|
MOV R12,R3
|
||||||
MRS R0,PSP
|
PUSH {R4-R7}
|
||||||
|
ADD R6,SP,#16
|
||||||
|
MOV R5,LR
|
||||||
|
LSRS R0,R5,#3 // Check EXC_RETURN for bit 2
|
||||||
|
BCC Fault_Handler_Continue
|
||||||
|
MRS R6,PSP
|
||||||
|
|
||||||
Fault_Handler_Continue:
|
Fault_Handler_Continue:
|
||||||
MOV R12,R3
|
LDR R7,=mbed_fault_context
|
||||||
LDR R3,=mbed_fault_context
|
LDMIA R6!,{R0-R3}
|
||||||
LDR R1,[R3]
|
STMIA R7!,{R0-R3} // Capture R0..R3
|
||||||
LDR R2,[R0] // Capture R0
|
POP {R0-R3}
|
||||||
STR R2,[R1]
|
STMIA R7!,{R0-R3} // Capture R4..R7
|
||||||
ADDS R1,#4
|
MOV R0,R8
|
||||||
LDR R2,[R0,#4] // Capture R1
|
MOV R1,R9
|
||||||
STR R2,[R1]
|
MOV R2,R10
|
||||||
ADDS R1,#4
|
MOV R3,R11
|
||||||
LDR R2,[R0,#8] // Capture R2
|
STMIA R7!,{R0-R3} // Capture R8..R11
|
||||||
STR R2,[R1]
|
LDMIA R6!,{R0,R2-R4} // Load R12,LR,PC,xPSR
|
||||||
ADDS R1,#4
|
// Adjust stack pointer to its original value
|
||||||
LDR R2,[R0,#12] // Capture R3
|
MOVS R1,R6
|
||||||
STR R2,[R1]
|
LSRS R6,R4,#10 // Check for if STK was aligned by checking bit-9 in xPSR value
|
||||||
ADDS R1,#4
|
BCC Fault_Handler_Continue1
|
||||||
STMIA R1!,{R4-R7} // Capture R4..R7
|
ADDS R1,#0x4
|
||||||
MOV R7,R8 // Capture R8
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R9 // Capture R9
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R10 // Capture R10
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R11 // Capture R11
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#16] // Capture R12
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#8 // Add 8 here to capture LR next, we will capture SP later
|
|
||||||
LDR R2,[R0,#20] // Capture LR
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#24] // Capture PC
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#28] // Capture xPSR
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
// Adjust stack pointer to its original value and capture it
|
|
||||||
MOV R3,R0
|
|
||||||
ADDS R3,#0x20 // Add 0x20 to get the SP value prior to exception
|
|
||||||
LDR R6,=0x200
|
|
||||||
TST R2,R6 // Check for if STK was aligned by checking bit-9 in xPSR value
|
|
||||||
BEQ Fault_Handler_Continue1
|
|
||||||
ADDS R3,#0x4
|
|
||||||
|
|
||||||
Fault_Handler_Continue1:
|
Fault_Handler_Continue1:
|
||||||
MOV R5,LR
|
LSRS R6,R5,#5 // Check EXC_RETURN bit-4 to see if FP context was saved
|
||||||
LDR R6,=0x10 // Check for bit-4 to see if FP context was saved
|
BCS Fault_Handler_Continue2
|
||||||
TST R5,R6
|
ADDS R1,#0x48 // 16 FP regs + FPCSR + 1 Reserved
|
||||||
BNE Fault_Handler_Continue2
|
|
||||||
ADDS R3,#0x48 // 16 FP regs + FPCSR + 1 Reserved
|
|
||||||
|
|
||||||
Fault_Handler_Continue2:
|
Fault_Handler_Continue2:
|
||||||
MOV R4,R1
|
STMIA R7!,{R0-R4} // Capture R12,SP,LR,PC,xPSR
|
||||||
SUBS R4,#0x10 // Set the location of SP in ctx
|
MRS R0,PSP
|
||||||
STR R3,[R4] // Capture the adjusted SP
|
MOV R1,SP
|
||||||
MRS R2,PSP // Get PSP
|
MRS R6,CONTROL
|
||||||
STR R2,[R1]
|
STMIA R7!,{R0,R1,R5,R6} // Capture PSP,MSP,EXC_RETURN,CONTROL
|
||||||
ADDS R1,#4
|
MOV R0,R12
|
||||||
MRS R2,MSP // Get MSP
|
LDR R1,=mbed_fault_context
|
||||||
STR R2,[R1]
|
BL mbed_fault_handler // mbed_fault_handler does not return
|
||||||
ADDS R1,#4
|
#else
|
||||||
MOV R2,LR // Get current LR(EXC_RETURN)
|
B .
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MRS R2,CONTROL // Get CONTROL Reg
|
|
||||||
STR R2,[R1]
|
|
||||||
MOV R0,R12
|
|
||||||
LDR R3,=mbed_fault_context
|
|
||||||
LDR R1,[R3]
|
|
||||||
BL mbed_fault_handler
|
|
||||||
#endif
|
#endif
|
||||||
B . // Just in case we come back here
|
|
||||||
|
|
||||||
.fnend
|
.fnend
|
||||||
.size Fault_Handler, .-Fault_Handler
|
.size Fault_Handler, .-Fault_Handler
|
||||||
|
.align
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.end
|
.end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,139 +17,101 @@
|
||||||
; *
|
; *
|
||||||
; * -----------------------------------------------------------------------------
|
; * -----------------------------------------------------------------------------
|
||||||
; *
|
; *
|
||||||
; * Title: Cortex-M Fault Exception handlers ( Common for both ARMv7M and ARMV6M );
|
; * Title: Cortex-M Fault Exception handlers ( Common for both ARMv7M and ARMV6M )
|
||||||
; *
|
; *
|
||||||
; * -----------------------------------------------------------------------------
|
; * -----------------------------------------------------------------------------
|
||||||
; */
|
; */
|
||||||
|
|
||||||
NAME except.S
|
NAME except.S
|
||||||
|
|
||||||
FAULT_TYPE_HARD_FAULT EQU 0x10
|
|
||||||
FAULT_TYPE_MEMMANAGE_FAULT EQU 0x20
|
|
||||||
FAULT_TYPE_BUS_FAULT EQU 0x30
|
|
||||||
FAULT_TYPE_USAGE_FAULT EQU 0x40
|
|
||||||
|
|
||||||
#ifndef MBED_FAULT_HANDLER_DISABLED
|
#ifndef MBED_FAULT_HANDLER_DISABLED
|
||||||
|
|
||||||
#ifndef DOMAIN_NS
|
#ifndef DOMAIN_NS
|
||||||
#define DOMAIN_NS 1
|
#define DOMAIN_NS 1
|
||||||
#endif
|
#endif
|
||||||
PRESERVE8
|
|
||||||
SECTION .rodata:DATA:NOROOT(2)
|
|
||||||
|
|
||||||
THUMB
|
FAULT_TYPE_HARD_FAULT EQU 0x10
|
||||||
SECTION .text:CODE:NOROOT(2)
|
FAULT_TYPE_MEMMANAGE_FAULT EQU 0x20
|
||||||
|
FAULT_TYPE_BUS_FAULT EQU 0x30
|
||||||
|
FAULT_TYPE_USAGE_FAULT EQU 0x40
|
||||||
|
|
||||||
|
PRESERVE8
|
||||||
|
THUMB
|
||||||
|
|
||||||
|
SECTION .text:CODE:NOROOT(2)
|
||||||
|
|
||||||
HardFault_Handler
|
HardFault_Handler
|
||||||
EXPORT HardFault_Handler
|
EXPORT HardFault_Handler
|
||||||
LDR R3,=FAULT_TYPE_HARD_FAULT
|
MOVS R3,#FAULT_TYPE_HARD_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
|
|
||||||
MemManage_Handler
|
MemManage_Handler
|
||||||
EXPORT MemManage_Handler
|
EXPORT MemManage_Handler
|
||||||
LDR R3,=FAULT_TYPE_MEMMANAGE_FAULT
|
MOVS R3,#FAULT_TYPE_MEMMANAGE_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
|
|
||||||
BusFault_Handler
|
BusFault_Handler
|
||||||
EXPORT BusFault_Handler
|
EXPORT BusFault_Handler
|
||||||
LDR R3,=FAULT_TYPE_BUS_FAULT
|
MOVS R3,#FAULT_TYPE_BUS_FAULT
|
||||||
B Fault_Handler
|
B Fault_Handler
|
||||||
|
|
||||||
UsageFault_Handler
|
UsageFault_Handler
|
||||||
EXPORT UsageFault_Handler
|
EXPORT UsageFault_Handler
|
||||||
LDR R3,=FAULT_TYPE_USAGE_FAULT
|
MOVS R3,#FAULT_TYPE_USAGE_FAULT
|
||||||
B Fault_Handler
|
; Fall into Fault_Handler
|
||||||
|
|
||||||
Fault_Handler
|
Fault_Handler
|
||||||
EXPORT Fault_Handler
|
EXPORT Fault_Handler
|
||||||
#if (DOMAIN_NS == 1)
|
#if (DOMAIN_NS == 1)
|
||||||
IMPORT mbed_fault_context
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
IMPORT mbed_fault_handler
|
#define mbed_fault_context __CRASH_DATA_RAM_START__
|
||||||
|
#endif
|
||||||
|
IMPORT mbed_fault_context
|
||||||
|
IMPORT mbed_fault_handler
|
||||||
|
|
||||||
MRS R0,MSP
|
MOV R12,R3
|
||||||
LDR R1,=0x4
|
PUSH {R4-R7}
|
||||||
MOV R2,LR
|
ADD R6,SP,#16
|
||||||
TST R2,R1 ; Check EXC_RETURN for bit 2
|
MOV R5,LR
|
||||||
BEQ Fault_Handler_Continue
|
LSRS R0,R5,#3 ; Check EXC_RETURN for bit 2
|
||||||
MRS R0,PSP
|
BCC Fault_Handler_Continue
|
||||||
|
MRS R6,PSP
|
||||||
|
|
||||||
Fault_Handler_Continue
|
Fault_Handler_Continue
|
||||||
MOV R12,R3
|
LDR R7,=mbed_fault_context
|
||||||
LDR R3,=mbed_fault_context
|
LDMIA R6!,{R0-R3}
|
||||||
LDR R1,[R3]
|
STMIA R7!,{R0-R3} ; Capture R0..R3
|
||||||
LDR R2,[R0] ; Capture R0
|
POP {R0-R3}
|
||||||
STR R2,[R1]
|
STMIA R7!,{R0-R3} ; Capture R4..R7
|
||||||
ADDS R1,#4
|
MOV R0,R8
|
||||||
LDR R2,[R0,#4] ; Capture R1
|
MOV R1,R9
|
||||||
STR R2,[R1]
|
MOV R2,R10
|
||||||
ADDS R1,#4
|
MOV R3,R11
|
||||||
LDR R2,[R0,#8] ; Capture R2
|
STMIA R7!,{R0-R3} ; Capture R8..R11
|
||||||
STR R2,[R1]
|
LDMIA R6!,{R0,R2-R4} ; Load R12,LR,PC,xPSR
|
||||||
ADDS R1,#4
|
; Adjust stack pointer to its original value
|
||||||
LDR R2,[R0,#12] ; Capture R3
|
MOVS R1,R6
|
||||||
STR R2,[R1]
|
LSRS R6,R4,#10 ; Check for if STK was aligned by checking bit-9 in xPSR value
|
||||||
ADDS R1,#4
|
BCC Fault_Handler_Continue1
|
||||||
STMIA R1!,{R4-R7} ; Capture R4..R7
|
ADDS R1,#0x4
|
||||||
MOV R7,R8 ; Capture R8
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R9 ; Capture R9
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R10 ; Capture R10
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
MOV R7,R11 ; Capture R11
|
|
||||||
STR R7,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#16] ; Capture R12
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#8 ; Add 8 here to capture LR next, we will capture SP later
|
|
||||||
LDR R2,[R0,#20] ; Capture LR
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#24] ; Capture PC
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
LDR R2,[R0,#28] ; Capture xPSR
|
|
||||||
STR R2,[R1]
|
|
||||||
ADDS R1,#4
|
|
||||||
; Adjust stack pointer to its original value and capture it
|
|
||||||
MOV R3,R0
|
|
||||||
ADDS R3,#0x20 ; Add 0x20 to get the SP value prior to exception
|
|
||||||
LDR R6,=0x200
|
|
||||||
TST R2,R6 ; Check for if STK was aligned by checking bit-9 in xPSR value
|
|
||||||
BEQ Fault_Handler_Continue1
|
|
||||||
ADDS R3,#0x4
|
|
||||||
|
|
||||||
Fault_Handler_Continue1
|
Fault_Handler_Continue1
|
||||||
MOV R5,LR
|
LSRS R6,R5,#5 ; Check EXC_RETURN bit-4 to see if FP context was saved
|
||||||
LDR R6,=0x10 ; Check for bit-4 to see if FP context was saved
|
BCS Fault_Handler_Continue2
|
||||||
TST R5,R6
|
ADDS R1,#0x48 ; 16 FP regs + FPCSR + 1 Reserved
|
||||||
BNE Fault_Handler_Continue2
|
|
||||||
ADDS R3,#0x48 ; 16 FP regs + FPCSR + 1 Reserved
|
|
||||||
|
|
||||||
Fault_Handler_Continue2
|
Fault_Handler_Continue2
|
||||||
MOV R4,R1
|
STMIA R7!,{R0-R4} ; Capture R12,SP,LR,PC,xPSR
|
||||||
SUBS R4,#0x10 ; Set the location of SP in ctx
|
MRS R0,PSP
|
||||||
STR R3,[R4] ; Capture the adjusted SP
|
MOV R1,SP
|
||||||
MRS R2,PSP ; Get PSP
|
MRS R6,CONTROL
|
||||||
STR R2,[R1]
|
STMIA R7!,{R0,R1,R5,R6} ; Capture PSP,MSP,EXC_RETURN,CONTROL
|
||||||
ADDS R1,#4
|
MOV R0,R12
|
||||||
MRS R2,MSP ; Get MSP
|
LDR R1,=mbed_fault_context
|
||||||
STR R2,[R1]
|
BL mbed_fault_handler ; mbed_fault_handler does not return
|
||||||
ADDS R1,#4
|
#else
|
||||||
MOV R2,LR ; Get current LR(EXC_RETURN)
|
B .
|
||||||
STR R2,[R1]
|
#endif
|
||||||
ADDS R1,#4
|
ALIGN
|
||||||
MRS R2,CONTROL ; Get CONTROL Reg
|
|
||||||
STR R2,[R1]
|
|
||||||
MOV R0,R12
|
|
||||||
LDR R3,=mbed_fault_context
|
|
||||||
LDR R1,[R3]
|
|
||||||
BL mbed_fault_handler
|
|
||||||
#endif
|
#endif
|
||||||
B . ; Just in case we come back here
|
|
||||||
#endif ; #if (MBED_FAULT_HANDLER_SUPPORT == 1)
|
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
|
||||||
|
|
@ -34,18 +34,16 @@
|
||||||
void print_context_info(void);
|
void print_context_info(void);
|
||||||
|
|
||||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
//Global for populating the context in exception handler
|
#define mbed_fault_context MBED_CRASH_DATA.fault.context
|
||||||
mbed_fault_context_t *const mbed_fault_context = (mbed_fault_context_t *)(FAULT_CONTEXT_LOCATION);
|
|
||||||
#else
|
#else
|
||||||
mbed_fault_context_t fault_context;
|
mbed_fault_context_t mbed_fault_context;
|
||||||
mbed_fault_context_t *const mbed_fault_context = &fault_context;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern bool mbed_error_in_progress;
|
extern bool mbed_error_in_progress;
|
||||||
|
|
||||||
//This is a handler function called from Fault handler to print the error information out.
|
//This is a handler function called from Fault handler to print the error information out.
|
||||||
//This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support.
|
//This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support.
|
||||||
void mbed_fault_handler(uint32_t fault_type, const mbed_fault_context_t *mbed_fault_context_in)
|
MBED_NORETURN void mbed_fault_handler(uint32_t fault_type, const mbed_fault_context_t *mbed_fault_context_in)
|
||||||
{
|
{
|
||||||
mbed_error_status_t faultStatus = MBED_SUCCESS;
|
mbed_error_status_t faultStatus = MBED_SUCCESS;
|
||||||
|
|
||||||
|
|
@ -94,7 +92,7 @@ MBED_NOINLINE void print_context_info(void)
|
||||||
{
|
{
|
||||||
//Context Regs
|
//Context Regs
|
||||||
for (int i = 0; i < 13; i++) {
|
for (int i = 0; i < 13; i++) {
|
||||||
mbed_error_printf("\nR%-4d: %08" PRIX32, i, ((uint32_t *)(mbed_fault_context))[i]);
|
mbed_error_printf("\nR%-4d: %08" PRIX32, i, (&mbed_fault_context.R0_reg)[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mbed_error_printf("\nSP : %08" PRIX32
|
mbed_error_printf("\nSP : %08" PRIX32
|
||||||
|
|
@ -102,8 +100,8 @@ MBED_NOINLINE void print_context_info(void)
|
||||||
"\nPC : %08" PRIX32
|
"\nPC : %08" PRIX32
|
||||||
"\nxPSR : %08" PRIX32
|
"\nxPSR : %08" PRIX32
|
||||||
"\nPSP : %08" PRIX32
|
"\nPSP : %08" PRIX32
|
||||||
"\nMSP : %08" PRIX32, mbed_fault_context->SP_reg, mbed_fault_context->LR_reg, mbed_fault_context->PC_reg,
|
"\nMSP : %08" PRIX32, mbed_fault_context.SP_reg, mbed_fault_context.LR_reg, mbed_fault_context.PC_reg,
|
||||||
mbed_fault_context->xPSR, mbed_fault_context->PSP, mbed_fault_context->MSP);
|
mbed_fault_context.xPSR, mbed_fault_context.PSP, mbed_fault_context.MSP);
|
||||||
|
|
||||||
//Capture CPUID to get core/cpu info
|
//Capture CPUID to get core/cpu info
|
||||||
mbed_error_printf("\nCPUID: %08" PRIX32, SCB->CPUID);
|
mbed_error_printf("\nCPUID: %08" PRIX32, SCB->CPUID);
|
||||||
|
|
@ -129,12 +127,12 @@ MBED_NOINLINE void print_context_info(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Print Mode
|
//Print Mode
|
||||||
if (mbed_fault_context->EXC_RETURN & 0x8) {
|
if (mbed_fault_context.EXC_RETURN & 0x8) {
|
||||||
mbed_error_printf("\nMode : Thread");
|
mbed_error_printf("\nMode : Thread");
|
||||||
//Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege.
|
//Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege.
|
||||||
//Note that the CONTROL register captured still reflects the privilege status of the
|
//Note that the CONTROL register captured still reflects the privilege status of the
|
||||||
//thread mode eventhough we are in Handler mode by the time we capture it.
|
//thread mode eventhough we are in Handler mode by the time we capture it.
|
||||||
if (mbed_fault_context->CONTROL & 0x1) {
|
if (mbed_fault_context.CONTROL & 0x1) {
|
||||||
mbed_error_printf("\nPriv : User");
|
mbed_error_printf("\nPriv : User");
|
||||||
} else {
|
} else {
|
||||||
mbed_error_printf("\nPriv : Privileged");
|
mbed_error_printf("\nPriv : Privileged");
|
||||||
|
|
@ -144,7 +142,7 @@ MBED_NOINLINE void print_context_info(void)
|
||||||
mbed_error_printf("\nPriv : Privileged");
|
mbed_error_printf("\nPriv : Privileged");
|
||||||
}
|
}
|
||||||
//Print Return Stack
|
//Print Return Stack
|
||||||
if (mbed_fault_context->EXC_RETURN & 0x4) {
|
if (mbed_fault_context.EXC_RETURN & 0x4) {
|
||||||
mbed_error_printf("\nStack: PSP");
|
mbed_error_printf("\nStack: PSP");
|
||||||
} else {
|
} else {
|
||||||
mbed_error_printf("\nStack: MSP");
|
mbed_error_printf("\nStack: MSP");
|
||||||
|
|
@ -158,7 +156,7 @@ mbed_error_status_t mbed_get_reboot_fault_context(mbed_fault_context_t *fault_co
|
||||||
if (fault_context == NULL) {
|
if (fault_context == NULL) {
|
||||||
return MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT);
|
return MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT);
|
||||||
}
|
}
|
||||||
memcpy(fault_context, mbed_fault_context, sizeof(mbed_fault_context_t));
|
*fault_context = mbed_fault_context;
|
||||||
status = MBED_SUCCESS;
|
status = MBED_SUCCESS;
|
||||||
#endif
|
#endif
|
||||||
return status;
|
return status;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
#ifndef MBED_CRASH_DATA_INFO_H
|
#ifndef MBED_CRASH_DATA_INFO_H
|
||||||
#define MBED_CRASH_DATA_INFO_H
|
#define MBED_CRASH_DATA_INFO_H
|
||||||
|
|
||||||
|
#include "platform/internal/mbed_fault_handler.h"
|
||||||
|
#include "platform/mbed_error.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -25,25 +28,28 @@ extern "C" {
|
||||||
/** \ingroup mbed-os-internal */
|
/** \ingroup mbed-os-internal */
|
||||||
/** \addtogroup platform-internal-api */
|
/** \addtogroup platform-internal-api */
|
||||||
/** @{*/
|
/** @{*/
|
||||||
#if defined(__ARMCC_VERSION)
|
// Any changes here must be reflected in except.S if they affect the fault handler.
|
||||||
extern uint32_t Image$$RW_m_crash_data$$ZI$$Base[];
|
// The fault context is first to keep it simple for the assembler.
|
||||||
extern uint32_t Image$$RW_m_crash_data$$ZI$$Size;
|
typedef struct mbed_crash_data {
|
||||||
#define __CRASH_DATA_RAM_START__ Image$$RW_m_crash_data$$ZI$$Base
|
union {
|
||||||
#elif defined(__ICCARM__)
|
mbed_fault_context_t context;
|
||||||
extern uint32_t __CRASH_DATA_RAM_START__[];
|
int pad[32];
|
||||||
extern uint32_t __CRASH_DATA_RAM_END__[];
|
} fault;
|
||||||
#elif defined(__GNUC__)
|
union {
|
||||||
extern uint32_t __CRASH_DATA_RAM_START__[];
|
mbed_error_ctx context;
|
||||||
extern uint32_t __CRASH_DATA_RAM_END__[];
|
int pad[32];
|
||||||
#endif /* defined(__CC_ARM) */
|
} error;
|
||||||
|
} mbed_crash_data_t;
|
||||||
|
|
||||||
/* Offset definitions for context capture */
|
#if defined(__ARMCC_VERSION)
|
||||||
#define FAULT_CONTEXT_OFFSET (0x0)
|
#define MBED_CRASH_DATA Image$$RW_m_crash_data$$ZI$$Base
|
||||||
#define FAULT_CONTEXT_SIZE (0x80 / 4) //32 words(128 bytes) for Fault Context
|
#elif defined(__ICCARM__)
|
||||||
#define ERROR_CONTEXT_OFFSET (FAULT_CONTEXT_OFFSET + FAULT_CONTEXT_SIZE)
|
#define MBED_CRASH_DATA __CRASH_DATA_RAM_START__
|
||||||
#define ERROR_CONTEXT_SIZE (0x80 / 4) //32 words(128 bytes) bytes for Error Context
|
#elif defined(__GNUC__)
|
||||||
#define FAULT_CONTEXT_LOCATION (__CRASH_DATA_RAM_START__ + FAULT_CONTEXT_OFFSET)
|
#define MBED_CRASH_DATA __CRASH_DATA_RAM_START__
|
||||||
#define ERROR_CONTEXT_LOCATION (__CRASH_DATA_RAM_START__ + ERROR_CONTEXT_OFFSET)
|
#endif
|
||||||
|
|
||||||
|
extern mbed_crash_data_t MBED_CRASH_DATA;
|
||||||
/**@}*/
|
/**@}*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include "platform/mbed_interface.h"
|
#include "platform/mbed_interface.h"
|
||||||
#include "platform/mbed_power_mgmt.h"
|
#include "platform/mbed_power_mgmt.h"
|
||||||
#include "platform/mbed_stats.h"
|
#include "platform/mbed_stats.h"
|
||||||
#include "platform/source/TARGET_CORTEX_M/mbed_fault_handler.h"
|
#include "platform/internal/mbed_fault_handler.h"
|
||||||
#include "drivers/MbedCRC.h"
|
#include "drivers/MbedCRC.h"
|
||||||
#include "mbed_rtx.h"
|
#include "mbed_rtx.h"
|
||||||
#ifdef MBED_CONF_RTOS_PRESENT
|
#ifdef MBED_CONF_RTOS_PRESENT
|
||||||
|
|
@ -62,8 +62,7 @@ static mbed_error_hook_t error_hook = NULL;
|
||||||
static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller);
|
static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller);
|
||||||
|
|
||||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
//Global for populating the context in exception handler
|
#define report_error_ctx MBED_CRASH_DATA.error.context
|
||||||
static mbed_error_ctx *const report_error_ctx = (mbed_error_ctx *)(ERROR_CONTEXT_LOCATION);
|
|
||||||
static bool is_reboot_error_valid = false;
|
static bool is_reboot_error_valid = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -122,9 +121,15 @@ static bool mbed_error_is_handler(const mbed_error_ctx *ctx)
|
||||||
bool is_handler = false;
|
bool is_handler = false;
|
||||||
if (ctx && mbed_error_is_hw_fault(ctx->error_status)) {
|
if (ctx && mbed_error_is_hw_fault(ctx->error_status)) {
|
||||||
mbed_fault_context_t *mfc = (mbed_fault_context_t *)ctx->error_value;
|
mbed_fault_context_t *mfc = (mbed_fault_context_t *)ctx->error_value;
|
||||||
|
#ifdef TARGET_CORTEX_M
|
||||||
if (mfc && !(mfc->EXC_RETURN & 0x8)) {
|
if (mfc && !(mfc->EXC_RETURN & 0x8)) {
|
||||||
is_handler = true;
|
is_handler = true;
|
||||||
}
|
}
|
||||||
|
#elif defined TARGET_CORTEX_A
|
||||||
|
if (mfc && (mfc->CPSR & 0x1F) != 0x10) {
|
||||||
|
is_handler = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return is_handler;
|
return is_handler;
|
||||||
}
|
}
|
||||||
|
|
@ -183,11 +188,11 @@ static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsign
|
||||||
|
|
||||||
//Capture the first system error and store it
|
//Capture the first system error and store it
|
||||||
if (error_count == 1) { //first error
|
if (error_count == 1) { //first error
|
||||||
memcpy(&first_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx));
|
first_error_ctx = current_error_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
//copy this error to last error
|
//copy this error to last error
|
||||||
memcpy(&last_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx));
|
last_error_ctx = current_error_ctx;
|
||||||
|
|
||||||
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
|
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
|
||||||
//Log the error with error log
|
//Log the error with error log
|
||||||
|
|
@ -223,25 +228,25 @@ mbed_error_status_t mbed_error_initialize(void)
|
||||||
uint32_t crc_val = 0;
|
uint32_t crc_val = 0;
|
||||||
|
|
||||||
//Just check if we have valid value for error_status, if error_status is positive(which is not valid), no need to check crc
|
//Just check if we have valid value for error_status, if error_status is positive(which is not valid), no need to check crc
|
||||||
if (report_error_ctx->error_status < 0) {
|
if (report_error_ctx.error_status < 0) {
|
||||||
crc_val = mbed_tiny_compute_crc32(report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
crc_val = mbed_tiny_compute_crc32(&report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
||||||
//Read report_error_ctx and check if CRC is correct, and with valid status code
|
//Read report_error_ctx and check if CRC is correct, and with valid status code
|
||||||
if ((report_error_ctx->crc_error_ctx == crc_val) && (report_error_ctx->is_error_processed == 0)) {
|
if ((report_error_ctx.crc_error_ctx == crc_val) && (report_error_ctx.is_error_processed == 0)) {
|
||||||
is_reboot_error_valid = true;
|
is_reboot_error_valid = true;
|
||||||
|
|
||||||
//Call the mbed_error_reboot_callback, this enables applications to do some handling before we do the handling
|
//Call the mbed_error_reboot_callback, this enables applications to do some handling before we do the handling
|
||||||
mbed_error_reboot_callback(report_error_ctx);
|
mbed_error_reboot_callback(&report_error_ctx);
|
||||||
|
|
||||||
//We let the callback reset the error info, so check if its still valid and do the rest only if its still valid.
|
//We let the callback reset the error info, so check if its still valid and do the rest only if its still valid.
|
||||||
if (report_error_ctx->error_reboot_count > 0) {
|
if (report_error_ctx.error_reboot_count > 0) {
|
||||||
|
|
||||||
report_error_ctx->is_error_processed = 1;//Set the flag that we already processed this error
|
report_error_ctx.is_error_processed = 1;//Set the flag that we already processed this error
|
||||||
crc_val = mbed_tiny_compute_crc32(report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
crc_val = mbed_tiny_compute_crc32(&report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
||||||
report_error_ctx->crc_error_ctx = crc_val;
|
report_error_ctx.crc_error_ctx = crc_val;
|
||||||
|
|
||||||
//Enforce max-reboot only if auto reboot is enabled
|
//Enforce max-reboot only if auto reboot is enabled
|
||||||
#if MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED
|
#if MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED
|
||||||
if (report_error_ctx->error_reboot_count >= MBED_CONF_PLATFORM_ERROR_REBOOT_MAX) {
|
if (report_error_ctx.error_reboot_count >= MBED_CONF_PLATFORM_ERROR_REBOOT_MAX) {
|
||||||
mbed_halt_system();
|
mbed_halt_system();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -299,10 +304,10 @@ WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_stat
|
||||||
|
|
||||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
uint32_t crc_val = 0;
|
uint32_t crc_val = 0;
|
||||||
crc_val = mbed_tiny_compute_crc32(report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
crc_val = mbed_tiny_compute_crc32(&report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
||||||
//Read report_error_ctx and check if CRC is correct for report_error_ctx
|
//Read report_error_ctx and check if CRC is correct for report_error_ctx
|
||||||
if (report_error_ctx->crc_error_ctx == crc_val) {
|
if (report_error_ctx.crc_error_ctx == crc_val) {
|
||||||
uint32_t current_reboot_count = report_error_ctx->error_reboot_count;
|
uint32_t current_reboot_count = report_error_ctx.error_reboot_count;
|
||||||
last_error_ctx.error_reboot_count = current_reboot_count + 1;
|
last_error_ctx.error_reboot_count = current_reboot_count + 1;
|
||||||
} else {
|
} else {
|
||||||
last_error_ctx.error_reboot_count = 1;
|
last_error_ctx.error_reboot_count = 1;
|
||||||
|
|
@ -312,15 +317,15 @@ WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_stat
|
||||||
last_error_ctx.crc_error_ctx = mbed_tiny_compute_crc32(&last_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
last_error_ctx.crc_error_ctx = mbed_tiny_compute_crc32(&last_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
||||||
//Protect report_error_ctx while we update it
|
//Protect report_error_ctx while we update it
|
||||||
core_util_critical_section_enter();
|
core_util_critical_section_enter();
|
||||||
memcpy(report_error_ctx, &last_error_ctx, sizeof(mbed_error_ctx));
|
report_error_ctx = last_error_ctx;
|
||||||
core_util_critical_section_exit();
|
core_util_critical_section_exit();
|
||||||
//We need not call delete_mbed_crc(crc_obj) here as we are going to reset the system anyway, and calling delete while handling a fatal error may cause nested exception
|
//We need not call delete_mbed_crc(crc_obj) here as we are going to reset the system anyway, and calling delete while handling a fatal error may cause nested exception
|
||||||
#if MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED && (MBED_CONF_PLATFORM_ERROR_REBOOT_MAX > 0)
|
#if MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED && (MBED_CONF_PLATFORM_ERROR_REBOOT_MAX > 0)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
mbed_error_printf("\n= System will be rebooted due to a fatal error =\n");
|
mbed_error_printf("\n= System will be rebooted due to a fatal error =\n");
|
||||||
if (report_error_ctx->error_reboot_count >= MBED_CONF_PLATFORM_ERROR_REBOOT_MAX) {
|
if (report_error_ctx.error_reboot_count >= MBED_CONF_PLATFORM_ERROR_REBOOT_MAX) {
|
||||||
//We have rebooted more than enough, hold the system here.
|
//We have rebooted more than enough, hold the system here.
|
||||||
mbed_error_printf("= Reboot count(=%" PRIi32") reached maximum, system will halt after rebooting =\n", report_error_ctx->error_reboot_count);
|
mbed_error_printf("= Reboot count(=%" PRIi32") reached maximum, system will halt after rebooting =\n", report_error_ctx.error_reboot_count);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
system_reset();//do a system reset to get the system rebooted
|
system_reset();//do a system reset to get the system rebooted
|
||||||
|
|
@ -348,7 +353,7 @@ mbed_error_status_t mbed_reset_reboot_error_info()
|
||||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
//Protect for thread safety
|
//Protect for thread safety
|
||||||
core_util_critical_section_enter();
|
core_util_critical_section_enter();
|
||||||
memset(report_error_ctx, 0, sizeof(mbed_error_ctx));
|
memset(&report_error_ctx, 0, sizeof(mbed_error_ctx));
|
||||||
core_util_critical_section_exit();
|
core_util_critical_section_exit();
|
||||||
#endif
|
#endif
|
||||||
return MBED_SUCCESS;
|
return MBED_SUCCESS;
|
||||||
|
|
@ -361,10 +366,10 @@ mbed_error_status_t mbed_reset_reboot_count()
|
||||||
if (is_reboot_error_valid) {
|
if (is_reboot_error_valid) {
|
||||||
uint32_t crc_val = 0;
|
uint32_t crc_val = 0;
|
||||||
core_util_critical_section_enter();
|
core_util_critical_section_enter();
|
||||||
report_error_ctx->error_reboot_count = 0;//Set reboot count to 0
|
report_error_ctx.error_reboot_count = 0;//Set reboot count to 0
|
||||||
//Update CRC
|
//Update CRC
|
||||||
crc_val = mbed_tiny_compute_crc32(report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
crc_val = mbed_tiny_compute_crc32(&report_error_ctx, offsetof(mbed_error_ctx, crc_error_ctx));
|
||||||
report_error_ctx->crc_error_ctx = crc_val;
|
report_error_ctx.crc_error_ctx = crc_val;
|
||||||
core_util_critical_section_exit();
|
core_util_critical_section_exit();
|
||||||
return MBED_SUCCESS;
|
return MBED_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -379,7 +384,7 @@ mbed_error_status_t mbed_get_reboot_error_info(mbed_error_ctx *error_info)
|
||||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||||
if (is_reboot_error_valid) {
|
if (is_reboot_error_valid) {
|
||||||
if (error_info != NULL) {
|
if (error_info != NULL) {
|
||||||
memcpy(error_info, report_error_ctx, sizeof(mbed_error_ctx));
|
*error_info = report_error_ctx;
|
||||||
status = MBED_SUCCESS;
|
status = MBED_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
status = MBED_ERROR_INVALID_ARGUMENT;
|
status = MBED_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
@ -392,14 +397,14 @@ mbed_error_status_t mbed_get_reboot_error_info(mbed_error_ctx *error_info)
|
||||||
//Retrieve the first error context from error log
|
//Retrieve the first error context from error log
|
||||||
mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info)
|
mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info)
|
||||||
{
|
{
|
||||||
memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx));
|
*error_info = first_error_ctx;
|
||||||
return MBED_SUCCESS;
|
return MBED_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Retrieve the last error context from error log
|
//Retrieve the last error context from error log
|
||||||
mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info)
|
mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info)
|
||||||
{
|
{
|
||||||
memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx));
|
*error_info = last_error_ctx;
|
||||||
return MBED_SUCCESS;
|
return MBED_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue