mbed-os/rtos/TARGET_CORTEX/mbed_rtx_fault_handler.c

214 lines
6.6 KiB
C

/* mbed Microcontroller Library
* Copyright (c) 2006-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "rtx_os.h"
#include "mbed_rtx.h"
#include "mbed_rtx_fault_handler.h"
#include "hal/serial_api.h"
//Global for populating the context in exception handler
mbed_fault_context_t mbed_fault_context;
//Structure to capture the context
void fault_print_init(void);
void fault_print_str(char *fmtstr, uint32_t *values);
void hex_to_str(uint32_t value, char *hex_star);
void print_context_info(void);
void print_threads_info(osRtxThread_t *);
void print_thread(osRtxThread_t *thread);
void print_register(char *regtag, uint32_t regval);
#if DEVICE_SERIAL
extern int stdio_uart_inited;
extern serial_t stdio_uart;
#endif
__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn)
{
fault_print_init();
fault_print_str("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL);
switch( fault_type ) {
case HARD_FAULT_EXCEPTION: fault_print_str("HardFault",NULL); break;
case MEMMANAGE_FAULT_EXCEPTION: fault_print_str("MemManageFault",NULL); break;
case BUS_FAULT_EXCEPTION: fault_print_str("BusFault",NULL); break;
case USAGE_FAULT_EXCEPTION: fault_print_str("UsageFault",NULL); break;
default: fault_print_str("Unknown Fault",NULL); break;
}
fault_print_str("\n\nContext:",NULL);
print_context_info();
fault_print_str("\n\nThread Info:\nCurrent:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr);
fault_print_str("\nNext:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next);
fault_print_str("\nWait Threads:",NULL);
osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list;
print_threads_info(threads);
fault_print_str("\nDelay Threads:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list;
print_threads_info(threads);
fault_print_str("\nIdle Thread:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle;
print_threads_info(threads);
fault_print_str("\n\n-- MbedOS Fault Handler --\n\n",NULL);
/* Just spin here, we have alrady crashed */
for (;;) {}
}
void print_context_info()
{
//Context Regs
fault_print_str( "\nR0 : %"
"\nR1 : %"
"\nR2 : %"
"\nR3 : %"
"\nR4 : %"
"\nR5 : %"
"\nR6 : %"
"\nR7 : %"
"\nR8 : %"
"\nR9 : %"
"\nR10 : %"
"\nR11 : %"
"\nR12 : %"
"\nSP : %"
"\nLR : %"
"\nPC : %"
"\nxPSR : %"
"\nPSP : %"
"\nMSP : %", (uint32_t *)&mbed_fault_context);
//Capture CPUID to get core/cpu info
fault_print_str("\nCPUID: %",(uint32_t *)&SCB->CPUID);
#if !defined(TARGET_M0) && !defined(TARGET_M0P)
//Capture fault information registers to infer the cause of exception
uint32_t FSR[7] = {0};
FSR[0] = SCB->HFSR;
//Split/Capture CFSR into MMFSR, BFSR, UFSR
FSR[1] = 0xFF & SCB->CFSR;//MMFSR
FSR[2] = (0xFF00 & SCB->CFSR) >> 8;//BFSR
FSR[3] = (0xFFFF0000 & SCB->CFSR) >> 16;//UFSR
FSR[4] = SCB->DFSR;
FSR[5] = SCB->AFSR;
FSR[6] = SCB->SHCSR;
fault_print_str("\nHFSR : %"
"\nMMFSR: %"
"\nBFSR : %"
"\nUFSR : %"
"\nDFSR : %"
"\nAFSR : %"
"\nSHCSR: %",FSR);
//Print MMFAR only if its valid as indicated by MMFSR
if(FSR[1] & 0x80) {
fault_print_str("\nMMFAR: %",(uint32_t *)&SCB->MMFAR);
}
//Print BFAR only if its valid as indicated by BFSR
if(FSR[2] & 0x80) {
fault_print_str("\nBFAR : %",(uint32_t *)&SCB->BFAR);
}
#endif
}
/* Prints thread info from a list */
void print_threads_info(osRtxThread_t *threads)
{
while(threads != NULL) {
print_thread( threads );
threads = threads->thread_next;
}
}
/* Prints info of a thread(using osRtxThread_t struct)*/
void print_thread(osRtxThread_t *thread)
{
uint32_t data[5];
data[0]=thread->state;
data[1]=thread->thread_addr;
data[2]=thread->stack_size;
data[3]=(uint32_t)thread->stack_mem;
data[4]=thread->sp;
fault_print_str("\nState: % EntryFn: % Stack Size: % Mem: % SP: %", data);
}
/* Initializes std uart for spitting the info out */
void fault_print_init()
{
#if DEVICE_SERIAL
if (!stdio_uart_inited) {
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
}
#endif
}
/* Limited print functionality which prints the string out to
stdout/uart without using stdlib by directly calling serial-api
and also uses less resources
The fmtstr contains the format string for printing and for every %
found in that it fetches a uint32 value from values buffer
and prints it in hex format.
*/
void fault_print_str(char *fmtstr, uint32_t *values)
{
#if DEVICE_SERIAL
int i = 0;
int idx = 0;
int vidx = 0;
char hex_str[9]={0};
while(fmtstr[i] != '\0') {
if(fmtstr[i] == '\n' || fmtstr[i] == '\r') {
serial_putc(&stdio_uart, '\r');
} else {
if(fmtstr[i]=='%') {
hex_to_str(values[vidx++],hex_str);
for(idx=7; idx>=0; idx--) {
serial_putc(&stdio_uart, hex_str[idx]);
}
} else {
serial_putc(&stdio_uart, fmtstr[i]);
}
}
i++;
}
#endif
}
/* Converts a uint32 to hex char string */
void hex_to_str(uint32_t value, char *hex_str)
{
char hex_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
int i = 0;
//Return without converting if hex_str is not provided
if(hex_str == NULL) return;
for(i=7; i>=0; i--) {
hex_str[i] = hex_char_map[(value & (0xf << (i * 4))) >> (i * 4)];
}
}