evgeniy1294 (03.01.2019 21:16, просмотров: 4790)
Что-то обленился я совсем. Давно хотел сделать умный обработчик для HardFault'a, тут наткнулся на решения segger'a, решил повторить функционал. Посмотрел я на их унылый ассемблер, загрустил и родил вот это:
namespace core
{
struct archregs_t
{
uint32_t r0; // Register R0
uint32_t r1; // Register R1
uint32_t r2; // Register R2
uint32_t r3; // Register R3
uint32_t r12; // Register R12
uint32_t lr; // Link register
uint32_t pc; // Program counter
union
{
uint32_t all;
struct
{
unsigned IPSR: 8; // Interrupt Program Status register (IPSR)
unsigned EPSR: 19; // Execution Program Status register (EPSR)
unsigned APSR: 5; // Application Program Status register (APSR)
} bit;
} psr; // Program status register.
};
}
void isr::HardFaultHandler()
{
uint32_t out = 0;
// Read fault information
shcsr.all = *(uint32_t*)(0xe000ed24);
hfsr.all = *(uint32_t*)(0xe000ed2c);
mfsr.all = *(uint8_t* )(0xe000ed28);
bfsr.all = *(uint8_t* )(0xe000ed29);
ufsr.all = *(uint16_t*)(0xe000ed2a);
mmar = *(uint32_t*)(0xe000ed34);
bfar = *(uint32_t*)(0xe000ed38);
// Halt execution
// If registers indicate readable memory, change the variable value to != 0 to continue execution.
while(out == 0)
{
asm("nop");
}
out = 0;
// Get context pointer
archregs = (core::archregs_t*)((&out)+1);
// Halt execution
// To step out of the HardFaultHandler, change the variable value to != 0.
while(out == 0)
{
asm("nop");
}
return;
}
Идея в том, что при вызове прерывания ядро пихает контекст, представленный archregs_t, в стек. Указатель стека при этом продавливается на следующую позицию, в которой создаётся переменная out, т.е поднявшись в стеке на 4 байта я получаю указатель на контекст.
Указатель на контекст позволяет этот контекст править, тем самым я могу вернуться к точке вылета в hardfault, встать перед ней или после (или перейти в любое место программы), задав адрес вручную.
Из минусов, потенциальная зависимость от компилятора и оптимизации. С выключенной оптимизацией clang отработал правильно, проверю на gcc и врублю оптимизацию.
Работает на ядрах M3, M4 и M4F, на M0 и M0+ пока не проверял, на F7 и H7 может не работать.