// **************************************************************************** | |
// semihost_hardfault.c | |
// - Provides hard fault handler to allow semihosting code not | |
// to hang application when debugger not connected. | |
// | |
// **************************************************************************** | |
// Copyright 2017-2019 NXP | |
// All rights reserved. | |
// | |
// Software that is described herein is for illustrative purposes only | |
// which provides customers with programming information regarding the | |
// NXP Cortex-M based MCUs. This software is supplied "AS IS" without any | |
// warranties of any kind, and NXP Semiconductors and its licensor disclaim any | |
// and all warranties, express or implied, including all implied warranties of | |
// merchantability, fitness for a particular purpose and non-infringement of | |
// intellectual property rights. NXP Semiconductors assumes no responsibility | |
// or liability for the use of the software, conveys no license or rights under | |
// any patent, copyright, mask work right, or any other intellectual property | |
// rights in or to any products. NXP Semiconductors reserves the right to make | |
// changes in the software without notification. NXP Semiconductors also makes | |
// no representation or warranty that such application will be suitable for the | |
// specified use without further testing or modification. | |
// | |
// Permission to use, copy, modify, and distribute this software and its | |
// documentation is hereby granted, under NXP Semiconductors' and its | |
// licensor's relevant copyrights in the software, without fee, provided that it | |
// is used in conjunction with NXP Semiconductors microcontrollers. This | |
// copyright, permission, and disclaimer notice must appear in all copies of | |
// this code. | |
// **************************************************************************** | |
// | |
// ===== DESCRIPTION ===== | |
// | |
// One of the issues with applications that make use of semihosting operations | |
// (such as printf calls) is that the code will not execute correctly when the | |
// debugger is not connected. Generally this will show up with the application | |
// appearing to just hang. This may include the application running from reset | |
// or powering up the board (with the application already in FLASH), and also | |
// as the application failing to continue to execute after a debug session is | |
// terminated. | |
// | |
// The problem here is that the "bottom layer" of the semihosted variants of | |
// the C library, semihosting is implemented by a "BKPT 0xAB" instruction. | |
// When the debug tools are not connected, this instruction triggers a hard | |
// fault - and the default hard fault handler within an application will | |
// typically just contains an infinite loop - causing the application to | |
// appear to have hang when no debugger is connected. | |
// | |
// The below code provides an example hard fault handler which instead looks | |
// to see what the instruction that caused the hard fault was - and if it | |
// was a "BKPT 0xAB", then it instead returns back to the user application. | |
// | |
// In most cases this will allow applications containing semihosting | |
// operations to execute (to some degree) when the debugger is not connected. | |
// | |
// == NOTE == | |
// | |
// Correct execution of the application containing semihosted operations | |
// which are vectored onto this hard fault handler cannot be guaranteed. This | |
// is because the handler may not return data or return codes that the higher | |
// level C library code or application code expects. This hard fault handler | |
// is meant as a development aid, and it is not recommended to leave | |
// semihosted code in a production build of your application! | |
// | |
// **************************************************************************** | |
// Allow handler to be removed by setting a define (via command line) | |
#if !defined (__SEMIHOST_HARDFAULT_DISABLE) | |
__attribute__((naked)) | |
void HardFault_Handler(void){ | |
__asm( ".syntax unified\n" | |
// Check which stack is in use | |
"MOVS R0, #4 \n" | |
"MOV R1, LR \n" | |
"TST R0, R1 \n" | |
"BEQ _MSP \n" | |
"MRS R0, PSP \n" | |
"B _process \n" | |
"_MSP: \n" | |
"MRS R0, MSP \n" | |
// Load the instruction that triggered hard fault | |
"_process: \n" | |
"LDR R1,[R0,#24] \n" | |
"LDRH R2,[r1] \n" | |
// Semihosting instruction is "BKPT 0xAB" (0xBEAB) | |
"LDR R3,=0xBEAB \n" | |
"CMP R2,R3 \n" | |
"BEQ _semihost_return \n" | |
// Wasn't semihosting instruction so enter infinite loop | |
"B . \n" | |
// Was semihosting instruction, so adjust location to | |
// return to by 1 instruction (2 bytes), then exit function | |
"_semihost_return: \n" | |
"ADDS R1,#2 \n" | |
"STR R1,[R0,#24] \n" | |
// Set a return value from semihosting operation. | |
// 32 is slightly arbitrary, but appears to allow most | |
// C Library IO functions sitting on top of semihosting to | |
// continue to operate to some degree | |
"MOVS R1,#32 \n" | |
"STR R1,[ R0,#0 ] \n" // R0 is at location 0 on stack | |
// Return from hard fault handler to application | |
"BX LR \n" | |
".syntax divided\n") ; | |
} | |
#endif | |