-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
__get_current_exception is very simple and locating it in a section that is copied to RAM by copy_to_ram builds or making it inline could be justified on that basis alone. However, it goes deeper...
This is the implementation of __get_current_exception:
.section .reset, "ax"
//...
.global __get_current_exception
.thumb_func
__get_current_exception:
mrs r0, ipsr
uxtb r0, r0
bx lr
Because it is in the .reset section, it is not copied to RAM when using the copy_to_ram binary type. This means that programs built with copy_to_ram might unexpectedly access flash RAM, which could cause poor behavior if, for example, the other core is writing to flash RAM or if the program has hard real-time constraints with regard to interrupt latency or jitter.
Here is one way to reproduce. It configures the MPU to hard fault if flash RAM is accessed, as a program that writes to flash RAM or one that has hard real-time constraints might,
CMakeLists.txt:
cmake_minimum_required(VERSION 3.13)
add_executable(example
main.c
)
pico_set_binary_type(example copy_to_ram)
target_link_libraries(example
hardware_timer
pico_stdlib
)
pico_add_extra_outputs(example)
main.c:
#include "hardware/structs/mpu.h"
#include "hardware/timer.h"
// Configure MPU to cause a hard fault if flash RAM is accessed.
void protect_flash() {
mpu_hw->rbar = XIP_BASE | M0PLUS_MPU_RBAR_VALID_BITS;
mpu_hw->rasr = 0x10000000 /* XN */ | (23 << M0PLUS_MPU_RASR_SIZE_LSB) | M0PLUS_MPU_RASR_ENABLE_BITS; // 2^(23+1) = 16MB
mpu_hw->ctrl = M0PLUS_MPU_CTRL_ENABLE_BITS | M0PLUS_MPU_CTRL_PRIVDEFENA_BITS;
}
int main() {
protect_flash();
// This crashes in debug builds.
sleep_ms(1000);
// This would crash for any build type.
__get_current_exception();
}
This is the crash:
> bt
#0 isr_hardfault () at D:\src\qos\pico-sdk\src\rp2_common\pico_standard_link\crt0.S:98
#1 <signal handler called>
#2 __get_current_exception () at D:\src\qos\pico-sdk\src\rp2_common\pico_standard_link\crt0.S:331
#3 0x200010f4 in sleep_until (t=...) at D:\src\qos\pico-sdk\src\common\pico_time\time.c:347
#4 0x20001214 in sleep_us (us=<optimized out>) at D:\src\qos\pico-sdk\src\common\pico_time\include/pico/time.h:102
#5 0x2000124e in sleep_ms (ms=ms@entry=0x3e8) at D:\src\qos\pico-sdk\src\common\pico_time\time.c:393
#6 0x20000136 in main () at D:\src\qos\examples\main.c:13
void sleep_until(absolute_time_t t) {
#if PICO_ON_DEVICE && !defined(NDEBUG)
if (__get_current_exception()) { // <-- CRASH
panic("Attempted to sleep inside of an exception handler; use busy_wait if you must");
}
...
#endif