blob: 27480f2cee9e30c67fdead0d51b1c801b8ce0cbe [file] [log] [blame]
#include "pico/runtime.h"
#if !PICO_RUNTIME_NO_INIT_PER_CORE_INSTALL_STACK_GUARD
#if PICO_RP2040
#include "hardware/structs/mpu.h"
#elif defined(__riscv)
#include "hardware/riscv.h"
#endif
// this is called for each thread since they have their own MPU
void runtime_init_per_core_install_stack_guard(void *stack_bottom) {
// this is called b4 runtime_init is complete, so beware printf or assert
uintptr_t addr = (uintptr_t) stack_bottom;
// the minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will
// just shorten the valid stack range a tad
addr = (addr + 31u) & ~31u;
#if PICO_RP2040
// Armv6-M MPU
// make sure no one is using the MPU yet
if (mpu_hw->ctrl) {
// Note that it would be tempting to change this to a panic, but it happens so early, printing is not a good idea
__breakpoint();
}
// mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want
uint32_t subregion_select = 0xffu ^ (1u << ((addr >> 5u) & 7u));
mpu_hw->ctrl = 5; // enable mpu with background default map
mpu_hw->rbar = (addr & (uint)~0xff) | M0PLUS_MPU_RBAR_VALID_BITS | 0;
mpu_hw->rasr = 1 // enable region
| (0x7 << 1) // size 2^(7 + 1) = 256
| (subregion_select << 8)
| 0x10000000; // XN = disable instruction fetch; no other bits means no permissions
#elif defined(__riscv)
#if !PICO_RP2350
#error "Check PMP configuration for new platform"
#endif
// RISC-V PMP, RP2350 configuration of Hazard3: 8 non-hardwired regions,
// NAPOT only, 32-byte granule, with nonstandard PMPCFGM0 register to
// apply regions to M-mode without locking them.
// Make sure no one is using the PMP yet
bool dirty_pmp =
riscv_read_csr(pmpcfg0) != 0 ||
riscv_read_csr(pmpcfg1) != 0 ||
riscv_read_csr(RVCSR_PMPCFGM0_OFFSET) != 0;
if (dirty_pmp) {
__breakpoint();
}
// Note pmpaddr is in units of 4 bytes, so right-shift 2.
riscv_write_csr(pmpaddr0, (addr | 0x0fu) >> 2);
// Make this region inaccessible in both M-mode and U-mode (but don't lock it)
riscv_write_csr(RVCSR_PMPCFGM0_OFFSET, 0x1u);
riscv_write_csr(pmpcfg0, RVCSR_PMPCFG0_R0_A_VALUE_NAPOT << RVCSR_PMPCFG0_R0_A_LSB);
#else
// // Armv8-M MPU
// // make sure no one is using the MPU yet
// if (mpu_hw->ctrl) {
// __breakpoint();
// }
// mpu_hw->rnr = 0;
// // Read-only, privileged-only, nonexecutable. (Good enough because stack
// // is usually written first, on a stack push)
// mpu_hw->rbar = addr | (2u << M33_MPU_RBAR_AP_LSB) | (M33_MPU_RBAR_XN_BITS);
// mpu_hw->rlar = addr | M33_MPU_RLAR_EN_BITS;
// // Enable MPU (and leave default attributes applied even for privileged software)
// mpu_hw->ctrl = M33_MPU_CTRL_PRIVDEFENA_BITS | M33_MPU_CTRL_ENABLE_BITS;
pico_default_asm_volatile(
"msr msplim, %0"
:
: "r" (stack_bottom));
#endif
}
#endif