From 3193f6fa59af972e2d9a06a80da5d6601185b75b Mon Sep 17 00:00:00 2001 From: Lefucjusz Date: Mon, 5 Jun 2023 19:19:21 +0200 Subject: [PATCH] [MOS-230] Print last instruction address before RTWDOG reset Added mechanism that stores address of last executed instruction before RTWDOG timeout to enable some basic debugging in such cases, as such resets do not create crashdumps and leave no information in logs. --- module-bsp/board/rt1051/bellpx/irq_gpio.cpp | 36 ++++++++++++++- module-bsp/board/rt1051/common/board.cpp | 8 +++- module-bsp/board/rt1051/puretx/irq_gpio.cpp | 51 +++++++++++++++++---- 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/module-bsp/board/rt1051/bellpx/irq_gpio.cpp b/module-bsp/board/rt1051/bellpx/irq_gpio.cpp index 0c9ee7b9952c69487a0f5fc3c75f38a2597de3d1..b7dde338a32be533869dc0d286f26beae7ca0a59 100644 --- a/module-bsp/board/rt1051/bellpx/irq_gpio.cpp +++ b/module-bsp/board/rt1051/bellpx/irq_gpio.cpp @@ -188,11 +188,43 @@ namespace bsp * be power reset. * * The simplest way to do it is to configure the pin as WDOG_B and use WDOG1 built-in - * assertion. */ - void RTWDOG_IRQHandler(void) + * assertion. + * + * Before proceeding to exception handler, CPU pushes the following registers + * to the active stack: + * r0, offset 0 (in words), + * r1 offset 1, + * r2, offset 2, + * r3, offset 3, + * r12, offset 4, + * r14 (LR), offset 5, + * r15 (PC), offset 6, + * xPSR, offset 7. + * Get the value of last PC state and store in non-volatile SNVS register + * to have any data that can be used to debug if program died in IRQ or + * critical section and neither log nor crashdump was created. */ + __attribute__((used, noreturn)) void RTWDOG_Handler(const uint32_t *sp) { RTWDOG_ClearStatusFlags(RTWDOG, kRTWDOG_InterruptFlag); + + const uint32_t pc = sp[6]; + SNVS->LPGPR[1] = pc; + WDOG1->WCR &= ~WDOG_WCR_WDA_MASK; + while (true) {}; // Execution should never reach this point, but just in case + } + + /* This has to be done as naked function to be able to easily extract last + * PC value before RTWDOG handler was called without having to deal with + * function prologue. */ + __attribute__((naked)) void RTWDOG_IRQHandler(void) + { + __asm__ __volatile__("tst lr, #4\n" // Determine which stack was used + "ite eq\n" + "mrseq r0, msp\n" + "mrsne r0, psp\n" + "b RTWDOG_Handler\n" // Jump to real handler + ); } // Enable PMU brownout interrupt diff --git a/module-bsp/board/rt1051/common/board.cpp b/module-bsp/board/rt1051/common/board.cpp index 5ee631d825a1328e76b9451db3d5651996eeb728..586eedbd46e7259f30c94feebb6b664f3087d758 100644 --- a/module-bsp/board/rt1051/common/board.cpp +++ b/module-bsp/board/rt1051/common/board.cpp @@ -20,7 +20,7 @@ extern "C" #include "board/brownout.hpp" #include -#include +#include extern std::uint32_t __sdram_cached_start[]; @@ -187,6 +187,12 @@ namespace bsp PrintSystemClocks(); clearAndPrintBootReason(); + + if (SNVS->LPGPR[1] != 0) { + LOG_INFO("Device seems to have been reset by RTWDOG! Last instruction address: 0x%08lX", + SNVS->LPGPR[1]); + SNVS->LPGPR[1] = 0; + } } //! Board PowerOff function by cutdown power diff --git a/module-bsp/board/rt1051/puretx/irq_gpio.cpp b/module-bsp/board/rt1051/puretx/irq_gpio.cpp index e8ac32b1200292bed222f446f1576c00fd915023..170d974d553fff032abec10523bc0808707af42d 100644 --- a/module-bsp/board/rt1051/puretx/irq_gpio.cpp +++ b/module-bsp/board/rt1051/puretx/irq_gpio.cpp @@ -1,12 +1,12 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "board/irq_gpio.hpp" #include "board.h" #include "FreeRTOS.h" -#include "queue.h" -#include "fsl_common.h" +#include +#include #include "board/rt1051/bsp/eink/bsp_eink.h" #include @@ -14,13 +14,9 @@ #include #include "bsp/cellular/bsp_cellular.hpp" #include "bsp/headset/headset.hpp" -#include "board/BoardDefinitions.hpp" -#include "bsp/magnetometer/magnetometer.hpp" -#include "bsp/light_sensor/light_sensor.hpp" namespace bsp { - void irq_gpio_Init(void) { DisableIRQ(GPIO1_Combined_0_15_IRQn); @@ -28,6 +24,7 @@ namespace bsp DisableIRQ(GPIO2_Combined_0_15_IRQn); DisableIRQ(GPIO2_Combined_16_31_IRQn); DisableIRQ(GPIO3_Combined_16_31_IRQn); + DisableIRQ(RTWDOG_IRQn); GPIO_PortDisableInterrupts(GPIO1, UINT32_MAX); GPIO_PortDisableInterrupts(GPIO2, UINT32_MAX); @@ -52,11 +49,13 @@ namespace bsp EnableIRQ(GPIO3_Combined_16_31_IRQn); NVIC_SetPriority(GPIO3_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); + + NVIC_ClearPendingIRQ(RTWDOG_IRQn); + NVIC_EnableIRQ(RTWDOG_IRQn); } extern "C" { - void GPIO1_Combined_0_15_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = 0; @@ -163,5 +162,41 @@ namespace bsp // Switch context if necessary portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } + + /* Before proceeding to exception handler, CPU pushes the following registers + * to the active stack: + * r0, offset 0 (in words), + * r1 offset 1, + * r2, offset 2, + * r3, offset 3, + * r12, offset 4, + * r14 (LR), offset 5, + * r15 (PC), offset 6, + * xPSR, offset 7. + * Get the value of last PC state and store in non-volatile SNVS register + * to have any data that can be used to debug if program died in IRQ or + * critical section and neither log nor crashdump was created. */ + __attribute__((used, noreturn)) void RTWDOG_Handler(const uint32_t *sp) + { + RTWDOG_ClearStatusFlags(RTWDOG, kRTWDOG_InterruptFlag); + + const uint32_t pc = sp[6]; + SNVS->LPGPR[1] = pc; + + while (true) {}; // Wait for RTWDOG to reset the board + } + + /* This has to be done as naked function to be able to easily extract last + * PC value before RTWDOG handler was called without having to deal with + * function prologue. */ + __attribute__((naked)) void RTWDOG_IRQHandler(void) + { + __asm__ __volatile__("tst lr, #4\n" // Determine which stack was used + "ite eq\n" + "mrseq r0, msp\n" + "mrsne r0, psp\n" + "b RTWDOG_Handler\n" // Jump to real handler + ); + } } } // namespace bsp