diff --git a/src/cmake/rp2_common.cmake b/src/cmake/rp2_common.cmake index 273839f70..dacac3879 100644 --- a/src/cmake/rp2_common.cmake +++ b/src/cmake/rp2_common.cmake @@ -110,6 +110,7 @@ if (NOT PICO_BARE_METAL) if (PICO_COMBINED_DOCS OR NOT PICO_RP2040) pico_add_subdirectory(rp2_common/pico_sha256) + pico_add_subdirectory(rp2_common/pico_secure) endif() pico_add_subdirectory(rp2_common/pico_stdio_semihosting) diff --git a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h index e7fe6f63b..c4829cf19 100644 --- a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h +++ b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h @@ -341,4 +341,42 @@ typedef struct cflash_flags { #define CFLASH_OP_VALUE_READ _u(2) #define CFLASH_OP_MAX _u(2) +#ifndef __riscv +/*! \brief Return a well known secure call code based on four ASCII characters + * \ingroup pico_bootrom + * + * These codes are used to call well known secure functions from non-secure code. + * + * NOTE: ASCII characters are all < 0x80, so will always start with `0b0xxx`, as required by the rom_secure_call() documentation. + * + * \param c1 the first character + * \param c2 the second character + * \param c3 the third character + * \param c4 the fourth character + * \return the 'code' to use in rom_secure_call(), and handled by rom_default_callback() + */ +#define SECURE_CALL_WELL_KNOWN_CODE(c1, c2, c3, c4) ((c1) | ((c2) << 8) | ((c3) << 16) | ((c4) << 24)) + +#define SECURE_CALL_stdio_out_chars SECURE_CALL_WELL_KNOWN_CODE('I', 'O', 'O', 'C') + +#define SECURE_CALL_get_rand_64 SECURE_CALL_WELL_KNOWN_CODE('R', 'D', '6', '4') + +#define SECURE_CALL_dma_allocate_unused_channel_for_nonsecure SECURE_CALL_WELL_KNOWN_CODE('D', 'A', 'C', 'H') + +#define SECURE_CALL_user_irq_claim_unused_for_nonsecure SECURE_CALL_WELL_KNOWN_CODE('U', 'I', 'R', 'Q') + +#define SECURE_CALL_clock_get_hz SECURE_CALL_WELL_KNOWN_CODE('C', 'K', 'G', 'H') + +#define SECURE_CALL_pio_claim_unused_pio_for_nonsecure SECURE_CALL_WELL_KNOWN_CODE('P', 'I', 'O', 'C') + +#define SECURE_CALL_pads_bank0_set_bits SECURE_CALL_WELL_KNOWN_CODE('P', '0', 'S', 'B') +#define SECURE_CALL_pads_bank0_clear_bits SECURE_CALL_WELL_KNOWN_CODE('P', '0', 'C', 'B') +#define SECURE_CALL_pads_bank0_write_masked SECURE_CALL_WELL_KNOWN_CODE('P', '0', 'W', 'M') +#define SECURE_CALL_pads_bank0_read SECURE_CALL_WELL_KNOWN_CODE('P', '0', 'R', 'D') + +#define SECURE_CALL_reset_block_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'R', 'M') +#define SECURE_CALL_unreset_block_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'M') +#define SECURE_CALL_unreset_block_mask_wait_blocking SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'W') +#endif + #endif diff --git a/src/rp2_common/hardware_flash/include/hardware/flash.h b/src/rp2_common/hardware_flash/include/hardware/flash.h index 2bb5d5ae3..b951adae9 100644 --- a/src/rp2_common/hardware_flash/include/hardware/flash.h +++ b/src/rp2_common/hardware_flash/include/hardware/flash.h @@ -42,9 +42,12 @@ #define PARAM_ASSERTIONS_ENABLED_HARDWARE_FLASH 0 #endif #endif -#define FLASH_PAGE_SIZE (1u << 8) -#define FLASH_SECTOR_SIZE (1u << 12) -#define FLASH_BLOCK_SIZE (1u << 16) +#define FLASH_PAGE_SHIFT 8u +#define FLASH_PAGE_SIZE (1u << FLASH_PAGE_SHIFT) +#define FLASH_SECTOR_SHIFT 12u +#define FLASH_SECTOR_SIZE (1u << FLASH_SECTOR_SHIFT) +#define FLASH_BLOCK_SHIFT 16u +#define FLASH_BLOCK_SIZE (1u << FLASH_BLOCK_SHIFT) #ifndef FLASH_UNIQUE_ID_SIZE_BYTES #define FLASH_UNIQUE_ID_SIZE_BYTES 8 diff --git a/src/rp2_common/hardware_gpio/CMakeLists.txt b/src/rp2_common/hardware_gpio/CMakeLists.txt index 9ec04c992..6fd3f6b1c 100644 --- a/src/rp2_common/hardware_gpio/CMakeLists.txt +++ b/src/rp2_common/hardware_gpio/CMakeLists.txt @@ -1,2 +1,6 @@ pico_simple_hardware_target(gpio) -pico_mirrored_target_link_libraries(hardware_gpio INTERFACE hardware_irq) \ No newline at end of file +pico_mirrored_target_link_libraries(hardware_gpio INTERFACE hardware_irq) + +if (PICO_RP2350) + pico_mirrored_target_link_libraries(hardware_gpio INTERFACE pico_bootrom) +endif() \ No newline at end of file diff --git a/src/rp2_common/hardware_gpio/gpio.c b/src/rp2_common/hardware_gpio/gpio.c index a5560bbb8..1ca9a0a83 100644 --- a/src/rp2_common/hardware_gpio/gpio.c +++ b/src/rp2_common/hardware_gpio/gpio.c @@ -27,7 +27,7 @@ static raw_irq_mask_type_t raw_irq_mask[NUM_CORES]; // Get the raw value from the pin, bypassing any muxing or overrides. int gpio_get_pad(uint gpio) { check_gpio_param(gpio); - hw_set_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS); + pads_bank0_set_bits(gpio, PADS_BANK0_GPIO0_IE_BITS); return (io_bank0_hw->io[gpio].status & IO_BANK0_GPIO0_STATUS_INFROMPAD_BITS) >> IO_BANK0_GPIO0_STATUS_INFROMPAD_LSB; } @@ -39,7 +39,7 @@ void gpio_set_function(uint gpio, gpio_function_t fn) { check_gpio_param(gpio); invalid_params_if(HARDWARE_GPIO, ((uint32_t)fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS); // Set input enable on, output disable off - hw_write_masked(&pads_bank0_hw->io[gpio], + pads_bank0_write_masked(gpio, PADS_BANK0_GPIO0_IE_BITS, PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS ); @@ -48,7 +48,7 @@ void gpio_set_function(uint gpio, gpio_function_t fn) { io_bank0_hw->io[gpio].ctrl = fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; #if HAS_PADS_BANK0_ISOLATION // Remove pad isolation now that the correct peripheral is in control of the pad - hw_clear_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_ISO_BITS); + pads_bank0_clear_bits(gpio, PADS_BANK0_GPIO0_ISO_BITS); #endif } /// \end::gpio_set_function[] @@ -62,8 +62,8 @@ gpio_function_t gpio_get_function(uint gpio) { // i.e. weak pull to whatever is current high/low state of GPIO. void gpio_set_pulls(uint gpio, bool up, bool down) { check_gpio_param(gpio); - hw_write_masked( - &pads_bank0_hw->io[gpio], + pads_bank0_write_masked( + gpio, (bool_to_bit(up) << PADS_BANK0_GPIO0_PUE_LSB) | (bool_to_bit(down) << PADS_BANK0_GPIO0_PDE_LSB), PADS_BANK0_GPIO0_PUE_BITS | PADS_BANK0_GPIO0_PDE_BITS ); @@ -106,20 +106,20 @@ void gpio_set_oeover(uint gpio, uint value) { void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) { check_gpio_param(gpio); if (enabled) - hw_set_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS); + pads_bank0_set_bits(gpio, PADS_BANK0_GPIO0_SCHMITT_BITS); else - hw_clear_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS); + pads_bank0_clear_bits(gpio, PADS_BANK0_GPIO0_SCHMITT_BITS); } bool gpio_is_input_hysteresis_enabled(uint gpio) { check_gpio_param(gpio); - return (pads_bank0_hw->io[gpio] & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0; + return (pads_bank0_read(gpio) & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0; } void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) { check_gpio_param(gpio); - hw_write_masked(&pads_bank0_hw->io[gpio], + pads_bank0_write_masked(gpio, (uint)slew << PADS_BANK0_GPIO0_SLEWFAST_LSB, PADS_BANK0_GPIO0_SLEWFAST_BITS ); @@ -127,7 +127,7 @@ void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) { enum gpio_slew_rate gpio_get_slew_rate(uint gpio) { check_gpio_param(gpio); - return (enum gpio_slew_rate)((pads_bank0_hw->io[gpio] + return (enum gpio_slew_rate)((pads_bank0_read(gpio) & PADS_BANK0_GPIO0_SLEWFAST_BITS) >> PADS_BANK0_GPIO0_SLEWFAST_LSB); } @@ -137,7 +137,7 @@ enum gpio_slew_rate gpio_get_slew_rate(uint gpio) { static_assert(PADS_BANK0_GPIO0_DRIVE_VALUE_8MA == GPIO_DRIVE_STRENGTH_8MA, ""); void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) { check_gpio_param(gpio); - hw_write_masked(&pads_bank0_hw->io[gpio], + pads_bank0_write_masked(gpio, (uint)drive << PADS_BANK0_GPIO0_DRIVE_LSB, PADS_BANK0_GPIO0_DRIVE_BITS ); @@ -145,7 +145,7 @@ void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) { enum gpio_drive_strength gpio_get_drive_strength(uint gpio) { check_gpio_param(gpio); - return (enum gpio_drive_strength)((pads_bank0_hw->io[gpio] + return (enum gpio_drive_strength)((pads_bank0_read(gpio) & PADS_BANK0_GPIO0_DRIVE_BITS) >> PADS_BANK0_GPIO0_DRIVE_LSB); } @@ -186,7 +186,7 @@ static void _gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled, io_b void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled) { // either this call disables the interrupt or callback should already be set. // this protects against enabling the interrupt without callback set - assert(!enabled || irq_has_handler(IO_IRQ_BANK0)); + assert(!enabled || irq_has_handler(DEFAULT_IO_IRQ_BANK0)); // Separate mask/force/status per-core, so check which core called, and // set the relevant IRQ controls. @@ -201,32 +201,32 @@ void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled if (enabled) gpio_set_irq_callback(callback); gpio_set_irq_enabled(gpio, events, enabled); if (!enabled) gpio_set_irq_callback(callback); - if (enabled) irq_set_enabled(IO_IRQ_BANK0, true); + if (enabled) irq_set_enabled(DEFAULT_IO_IRQ_BANK0, true); } void gpio_set_irq_callback(gpio_irq_callback_t callback) { uint core = get_core_num(); if (callbacks[core]) { if (!callback) { - irq_remove_handler(IO_IRQ_BANK0, gpio_default_irq_handler); + irq_remove_handler(DEFAULT_IO_IRQ_BANK0, gpio_default_irq_handler); } callbacks[core] = callback; } else if (callback) { callbacks[core] = callback; - irq_add_shared_handler(IO_IRQ_BANK0, gpio_default_irq_handler, GPIO_IRQ_CALLBACK_ORDER_PRIORITY); + irq_add_shared_handler(DEFAULT_IO_IRQ_BANK0, gpio_default_irq_handler, GPIO_IRQ_CALLBACK_ORDER_PRIORITY); } } void gpio_add_raw_irq_handler_with_order_priority_masked(uint32_t gpio_mask, irq_handler_t handler, uint8_t order_priority) { hard_assert(!(raw_irq_mask[get_core_num()] & gpio_mask)); // should not add multiple handlers for the same event raw_irq_mask[get_core_num()] |= gpio_mask; - irq_add_shared_handler(IO_IRQ_BANK0, handler, order_priority); + irq_add_shared_handler(DEFAULT_IO_IRQ_BANK0, handler, order_priority); } void gpio_add_raw_irq_handler_with_order_priority_masked64(uint64_t gpio_mask, irq_handler_t handler, uint8_t order_priority) { hard_assert(!(raw_irq_mask[get_core_num()] & gpio_mask)); // should not add multiple handlers for the same event raw_irq_mask[get_core_num()] |= (raw_irq_mask_type_t) gpio_mask; - irq_add_shared_handler(IO_IRQ_BANK0, handler, order_priority); + irq_add_shared_handler(DEFAULT_IO_IRQ_BANK0, handler, order_priority); } void gpio_add_raw_irq_handler_masked(uint32_t gpio_mask, irq_handler_t handler) { @@ -239,13 +239,13 @@ void gpio_add_raw_irq_handler_masked64(uint64_t gpio_mask, irq_handler_t handler void gpio_remove_raw_irq_handler_masked(uint32_t gpio_mask, irq_handler_t handler) { assert(raw_irq_mask[get_core_num()] & gpio_mask); // should not remove handlers that are not added - irq_remove_handler(IO_IRQ_BANK0, handler); + irq_remove_handler(DEFAULT_IO_IRQ_BANK0, handler); raw_irq_mask[get_core_num()] &= ~gpio_mask; } void gpio_remove_raw_irq_handler_masked64(uint64_t gpio_mask, irq_handler_t handler) { assert(raw_irq_mask[get_core_num()] & gpio_mask); // should not remove handlers that are not added - irq_remove_handler(IO_IRQ_BANK0, handler); + irq_remove_handler(DEFAULT_IO_IRQ_BANK0, handler); raw_irq_mask[get_core_num()] &= (raw_irq_mask_type_t)~gpio_mask; } @@ -267,9 +267,9 @@ void gpio_debug_pins_init(void) { void gpio_set_input_enabled(uint gpio, bool enabled) { check_gpio_param(gpio); if (enabled) - hw_set_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS); + pads_bank0_set_bits(gpio, PADS_BANK0_GPIO0_IE_BITS); else - hw_clear_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS); + pads_bank0_clear_bits(gpio, PADS_BANK0_GPIO0_IE_BITS); } void gpio_init(uint gpio) { diff --git a/src/rp2_common/hardware_gpio/include/hardware/gpio.h b/src/rp2_common/hardware_gpio/include/hardware/gpio.h index 3894acaa8..e5816b5e3 100644 --- a/src/rp2_common/hardware_gpio/include/hardware/gpio.h +++ b/src/rp2_common/hardware_gpio/include/hardware/gpio.h @@ -18,10 +18,27 @@ #define PICO_USE_GPIO_COPROCESSOR 1 #endif + +#if PICO_NONSECURE +#define DEFAULT_IO_IRQ_BANK0 IO_IRQ_BANK0_NS +#else +#define DEFAULT_IO_IRQ_BANK0 IO_IRQ_BANK0 +#endif + + #if PICO_USE_GPIO_COPROCESSOR #include "hardware/gpio_coproc.h" #endif +#if PICO_SECURE || PICO_NONSECURE +#include "pico/bootrom.h" // uses helper functions due to Errata RP2350-E3 +#else +#define pads_bank0_set_bits(gpio, bits) hw_set_bits(&pads_bank0_hw->io[gpio], bits) +#define pads_bank0_clear_bits(gpio, bits) hw_clear_bits(&pads_bank0_hw->io[gpio], bits) +#define pads_bank0_write_masked(gpio, bits, mask) hw_write_masked(&pads_bank0_hw->io[gpio], bits, mask) +#define pads_bank0_read(gpio) pads_bank0_hw->io[gpio] +#endif + #ifdef __cplusplus extern "C" { #endif @@ -312,7 +329,7 @@ static inline void gpio_pull_up(uint gpio) { * \return true if the GPIO is pulled up */ static inline bool gpio_is_pulled_up(uint gpio) { - return (pads_bank0_hw->io[gpio] & PADS_BANK0_GPIO0_PUE_BITS) != 0; + return (pads_bank0_read(gpio) & PADS_BANK0_GPIO0_PUE_BITS) != 0; } /*! \brief Set specified GPIO to be pulled down. @@ -331,7 +348,7 @@ static inline void gpio_pull_down(uint gpio) { * \return true if the GPIO is pulled down */ static inline bool gpio_is_pulled_down(uint gpio) { - return (pads_bank0_hw->io[gpio] & PADS_BANK0_GPIO0_PDE_BITS) != 0; + return (pads_bank0_read(gpio) & PADS_BANK0_GPIO0_PDE_BITS) != 0; } /*! \brief Disable pulls on specified GPIO diff --git a/src/rp2_common/hardware_resets/include/hardware/resets.h b/src/rp2_common/hardware_resets/include/hardware/resets.h index f75775717..d89163710 100644 --- a/src/rp2_common/hardware_resets/include/hardware/resets.h +++ b/src/rp2_common/hardware_resets/include/hardware/resets.h @@ -106,6 +106,9 @@ extern "C" { #endif +#if PICO_NONSECURE +#include "pico/bootrom.h" +#else static __force_inline void reset_block_reg_mask(io_rw_32 *reset, uint32_t mask) { hw_set_bits(reset, mask); } @@ -119,6 +122,7 @@ static __force_inline void unreset_block_reg_mask_wait_blocking(io_rw_32 *reset, while (~*reset_done & mask) tight_loop_contents(); } +#endif /// \tag::reset_funcs[] diff --git a/src/rp2_common/pico_bootrom/CMakeLists.txt b/src/rp2_common/pico_bootrom/CMakeLists.txt index c7ac816f2..9e29fa9ca 100644 --- a/src/rp2_common/pico_bootrom/CMakeLists.txt +++ b/src/rp2_common/pico_bootrom/CMakeLists.txt @@ -9,8 +9,8 @@ target_sources(pico_bootrom INTERFACE ) target_link_libraries(pico_bootrom_headers INTERFACE boot_picoboot_headers boot_bootrom_headers) -pico_mirrored_target_link_libraries(pico_bootrom INTERFACE pico_base hardware_boot_lock pico_flash) +pico_mirrored_target_link_libraries(pico_bootrom INTERFACE pico_base hardware_boot_lock pico_flash hardware_flash pico_rand hardware_dma hardware_irq pico_stdio hardware_pio) # bootrom.c includes boot/picobin.h # bootrom_lock.c includes pico/runtime_init.h -target_link_libraries(pico_bootrom INTERFACE boot_picobin_headers pico_runtime_init_headers) \ No newline at end of file +target_link_libraries(pico_bootrom INTERFACE boot_picobin_headers pico_runtime_init_headers) diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index 766574802..1b608ca63 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -9,7 +9,10 @@ #include "boot/picobin.h" #if !PICO_RP2040 #include "hardware/rcp.h" +#include "hardware/flash.h" +#include "hardware/structs/qmi.h" #endif +#include "pico/runtime_init.h" /// \tag::table_lookup[] @@ -196,4 +199,460 @@ int rom_pick_ab_partition_during_update(uint32_t *workarea_base, uint32_t workar return rc; } -#endif \ No newline at end of file + +int rom_get_owned_partition(uint partition_num) { + int ret; + uint32_t buffer[(16 * 2) + 1] = {}; // maximum of 16 partitions, each with 2 words returned, plus 1 + // Initially assume that the partition_num is the A partition + int partition_a_num = partition_num; + ret = rom_get_b_partition(partition_num); + + if (ret < 0) { + // partition_num is actually the B partition, so read the A partition + ret = rom_get_partition_table_info(buffer, count_of(buffer), PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (partition_num << 24)); + if (ret < 0) return ret; + + uint32_t flags_and_permissions = buffer[2]; + if ((flags_and_permissions & PICOBIN_PARTITION_FLAGS_LINK_TYPE_BITS) >> PICOBIN_PARTITION_FLAGS_LINK_TYPE_LSB != PICOBIN_PARTITION_FLAGS_LINK_TYPE_A_PARTITION) return BOOTROM_ERROR_NOT_FOUND; + partition_a_num = (flags_and_permissions & PICOBIN_PARTITION_FLAGS_LINK_VALUE_BITS) >> PICOBIN_PARTITION_FLAGS_LINK_VALUE_LSB; + } + + ret = rom_get_partition_table_info(buffer, count_of(buffer), PT_INFO_PARTITION_LOCATION_AND_FLAGS); + if (ret < 0) return ret; + + int num_partitions = (ret - 1) / 2; + + int owned_a_num; + for (owned_a_num = 0; owned_a_num < num_partitions; owned_a_num++) { + uint32_t flags_and_permissions = buffer[owned_a_num * 2 + 2]; + if ( + (flags_and_permissions & PICOBIN_PARTITION_FLAGS_LINK_TYPE_BITS) >> PICOBIN_PARTITION_FLAGS_LINK_TYPE_LSB == PICOBIN_PARTITION_FLAGS_LINK_TYPE_OWNER_PARTITION && + (flags_and_permissions & PICOBIN_PARTITION_FLAGS_LINK_VALUE_BITS) >> PICOBIN_PARTITION_FLAGS_LINK_VALUE_LSB == partition_a_num + ) { + break; + } + } + + if (owned_a_num == num_partitions) return BOOTROM_ERROR_NOT_FOUND; + + if (partition_num == partition_a_num) + return owned_a_num; + else + return rom_get_b_partition(owned_a_num); +} + +int rom_roll_qmi_to_partition(uint partition_num) { + uint32_t buffer[2 + 1] = {}; // 2 words for the partition location and flags, plus 1 + int ret = rom_get_partition_table_info(buffer, count_of(buffer), PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (partition_num << 24)); + if (ret < 0) return ret; + + uint32_t location_and_permissions = buffer[1]; + uint32_t saddr = ((location_and_permissions >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB) & 0x1fffu) * FLASH_SECTOR_SIZE; + uint32_t eaddr = (((location_and_permissions >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB) & 0x1fffu) + 1) * FLASH_SECTOR_SIZE; + + int32_t roll = (int32_t)saddr; + if (roll) { + if ((uint32_t)roll & (FLASH_SECTOR_SIZE - 1u)) return BOOTROM_ERROR_BAD_ALIGNMENT; + roll >>= FLASH_SECTOR_SHIFT; + int32_t size = (int32_t)((eaddr - saddr) >> FLASH_SECTOR_SHIFT); + for (uint i = 0; i < 4; i++) { + static_assert(4 * 1024 * 1024 / FLASH_SECTOR_SIZE == 0x400, "Expected 4 MiB / FLASH_SECTOR_SIZE = 0x400"); + if (roll < 0) { + roll += 0x400; + qmi_hw->atrans[i] = 0; + } else { + int32_t this_size = MIN(size, 0x400); + qmi_hw->atrans[i] = (uint)((this_size << 16) | roll); + size -= this_size; + roll += this_size; + } + } + } + return BOOTROM_OK; +} + +#if PICO_SECURE || PICO_NONSECURE +#include "hardware/structs/accessctrl.h" + +int __noinline rom_secure_call(uint a, uint b, uint c, uint d, uint func) { + uint32_t secure_call = (uintptr_t)rom_func_lookup_inline(ROM_FUNC_SECURE_CALL); + register uint32_t r0 asm("r0") = a; + register uint32_t r1 asm("r1") = b; + register uint32_t r2 asm("r2") = c; + register uint32_t r3 asm("r3") = d; + register uint32_t r4 asm("r4") = func; + pico_default_asm_volatile( + "push {lr}\n" + "blx %0\n" + "pop {lr}\n" + : : "r" (secure_call), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)); + return (int)r0; +} + +struct rom_secure_call_user_callback_slot { + uint16_t fn_mask; + rom_secure_call_callback_t callback; +} rom_secure_call_user_callback_slots[PICO_MAX_SECURE_CALL_USER_CALLBACKS]; + +int rom_secure_call_add_user_callback(rom_secure_call_callback_t callback, uint16_t fn_mask) { + int first_unused = PICO_MAX_SECURE_CALL_USER_CALLBACKS; + for (int i=0; i < PICO_MAX_SECURE_CALL_USER_CALLBACKS; i++) { + if (!rom_secure_call_user_callback_slots[i].fn_mask) { + if (first_unused == PICO_MAX_SECURE_CALL_USER_CALLBACKS) first_unused = i; + continue; + } + + // Check new function is not an existing function mask + if (rom_secure_call_user_callback_slots[i].fn_mask == fn_mask) { + return BOOTROM_ERROR_INVALID_ARG; + } + } + + if (first_unused == PICO_MAX_SECURE_CALL_USER_CALLBACKS) { + // No free slots + return BOOTROM_ERROR_BUFFER_TOO_SMALL; + } + + rom_secure_call_user_callback_slots[first_unused].callback = callback; + rom_secure_call_user_callback_slots[first_unused].fn_mask = fn_mask; + + return BOOTROM_OK; +} + +void rom_secure_call_remove_user_callback(rom_secure_call_callback_t callback) { + for (int i=0; i < PICO_MAX_SECURE_CALL_USER_CALLBACKS; i++) { + if (rom_secure_call_user_callback_slots[i].callback == callback) { + rom_secure_call_user_callback_slots[i].callback = NULL; + rom_secure_call_user_callback_slots[i].fn_mask = 0; + return; + } + } +} + +#if PICO_ALLOW_NONSECURE_STDIO +#include "pico/stdio/driver.h" + +#if PICO_NONSECURE +static void stdio_nonsecure_out_chars(const char *buf, int length) { + rom_secure_call((uint32_t)buf, length, 0, 0, SECURE_CALL_stdio_out_chars); +} + +int stdio_nonsecure_in_chars(char *buf, int length) { + return PICO_ERROR_NO_DATA; +} + +static void stdio_nonsecure_out_flush(void) {} + + +stdio_driver_t stdio_nonsecure = { + .out_chars = stdio_nonsecure_out_chars, + .out_flush = stdio_nonsecure_out_flush, + .in_chars = stdio_nonsecure_in_chars, +#if PICO_STDIO_ENABLE_CRLF_SUPPORT + .crlf_enabled = false, // CRLF is handled by the secure side +#endif +}; + +#if !PICO_RUNTIME_NO_INIT_NONSECURE_STDIO +void __weak runtime_init_nonsecure_stdio() { + stdio_set_driver_enabled(&stdio_nonsecure, true); +} +#endif + +#if !PICO_RUNTIME_SKIP_INIT_NONSECURE_STDIO +PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_stdio, PICO_RUNTIME_INIT_NONSECURE_STDIO); +#endif + +#endif // PICO_NONSECURE +#endif // PICO_ALLOW_NONSECURE_STDIO + +#if PICO_ALLOW_NONSECURE_RAND +#include "pico/rand.h" + +#if PICO_NONSECURE +// override the weak definition +uint64_t get_rand_64(void) { + return rom_secure_call(0, 0, 0, 0, SECURE_CALL_get_rand_64); +} +#endif +#endif // PICO_ALLOW_NONSECURE_RAND + +#if PICO_ALLOW_NONSECURE_DMA +#include "hardware/dma.h" + +#if PICO_SECURE +static int dma_allocate_unused_channel_for_nonsecure(void) { + int chan = dma_claim_unused_channel(false); + if (chan < 0) return chan; + if (chan > PICO_NONSECURE_DMA_MAX_CHANNEL) { + dma_channel_unclaim(chan); + return -1; + } + hw_clear_bits(&dma_hw->seccfg_ch[chan], DMA_SECCFG_CH0_S_BITS | DMA_SECCFG_CH0_LOCK_BITS); + return chan; +} +#elif PICO_NONSECURE +int dma_request_unused_channels_from_secure(int num_channels) { + int i; + for (i = 0; i < num_channels; i++) { + int chan = rom_secure_call(0, 0, 0, 0, SECURE_CALL_dma_allocate_unused_channel_for_nonsecure); + if (chan < 0) break; + dma_channel_unclaim(chan); + } + return i; +} +#endif +#endif // PICO_ALLOW_NONSECURE_DMA + +#if PICO_ALLOW_NONSECURE_USER_IRQ +#include "hardware/irq.h" + +#if PICO_SECURE +static int user_irq_claim_unused_for_nonsecure() { + int bit = user_irq_claim_unused(false); + if (bit < 0) return bit; + irq_assign_to_ns(bit, true); + return bit; +} +#elif PICO_NONSECURE +int user_irq_request_unused_from_secure(int num_irqs) { + int i; + for (i = 0; i < num_irqs; i++) { + int irq = rom_secure_call(0, 0, 0, 0, SECURE_CALL_user_irq_claim_unused_for_nonsecure); + if (irq < 0) break; + user_irq_unclaim(irq); + } + return i; +} +#endif + +#endif // PICO_ALLOW_NONSECURE_USER_IRQ + +#if PICO_ALLOW_NONSECURE_PIO +#include "hardware/pio.h" +#include "hardware/irq.h" + +#if PICO_SECURE +static int pio_claim_unused_pio_for_nonsecure(void) { + // Find completely unused PIO + uint pio; + for (pio = 0; pio < PICO_NONSECURE_PIO_MAX; pio++) { + // We need to claim an SM on the PIO + int8_t sm_index[NUM_PIO_STATE_MACHINES]; + // on second pass, if there is one, we try and claim all the state machines so that we can change the GPIO base + uint num_claimed; + for(num_claimed = 0; num_claimed < NUM_PIO_STATE_MACHINES ; num_claimed++) { + sm_index[num_claimed] = (int8_t)pio_claim_unused_sm(pio_get_instance(pio), false); + if (sm_index[num_claimed] < 0) break; + } + + if (num_claimed != NUM_PIO_STATE_MACHINES) { + // un-claim all the SMs + for (uint i = 0; i < num_claimed; i++) { + pio_sm_unclaim(pio_get_instance(pio), (uint) sm_index[i]); + } + continue; + } + + break; + } + + if (pio == PICO_NONSECURE_PIO_MAX) { + return -1; + } + + // Accessctrl and IRQs + accessctrl_hw->pio[pio] |= 0xacce0000 | ACCESSCTRL_PIO0_NSP_BITS | ACCESSCTRL_PIO0_NSU_BITS; + + static_assert(PIO0_IRQ_0 + 2 == PIO1_IRQ_0, "Expected 2 IRQs per PIO"); + + irq_assign_to_ns(PIO0_IRQ_0 + pio * 2, true); + irq_assign_to_ns(PIO0_IRQ_1 + pio * 2, true); + + return pio; +} +#elif PICO_NONSECURE +int pio_request_unused_pio_from_secure(void) { + int pio = rom_secure_call(0, 0, 0, 0, SECURE_CALL_pio_claim_unused_pio_for_nonsecure); + if (pio < 0) return pio; + for (uint sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { + pio_sm_unclaim(pio_get_instance(pio), sm); + } + return pio; +} +#endif +#endif // PICO_ALLOW_NONSECURE_PIO + +#if !PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK +#include +#include "hardware/clocks.h" +#include "hardware/resets.h" +#include "hardware/structs/accessctrl.h" + +int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn) { + if (fn >> 31) { + // User callbacks all start with 0b1xxx, as specified by the rom_secure_call() documentation + for (int i=0; i < PICO_MAX_SECURE_CALL_USER_CALLBACKS; i++) { + if ((fn >> 16) == rom_secure_call_user_callback_slots[i].fn_mask) { + return rom_secure_call_user_callback_slots[i].callback(a, b, c, d, fn); + } + } + + return BOOTROM_ERROR_INVALID_ARG; + } + + switch (fn) { + #if PICO_ALLOW_NONSECURE_STDIO + case SECURE_CALL_stdio_out_chars: { + uint32_t ok = RCP_MASK_FALSE; + rom_validate_ns_buffer((char*)a, b, RCP_MASK_TRUE, &ok); + if (ok != RCP_MASK_TRUE) return BOOTROM_ERROR_NOT_PERMITTED; + stdio_put_string((char*)a, b, false, true); + stdio_flush(); + return BOOTROM_OK; + } + #endif + #if PICO_ALLOW_NONSECURE_RAND + case SECURE_CALL_get_rand_64: { + return get_rand_64(); + } + #endif + #if PICO_ALLOW_NONSECURE_DMA + case SECURE_CALL_dma_allocate_unused_channel_for_nonsecure: { + return dma_allocate_unused_channel_for_nonsecure(); + } + #endif + #if PICO_ALLOW_NONSECURE_USER_IRQ + case SECURE_CALL_user_irq_claim_unused_for_nonsecure: { + return user_irq_claim_unused_for_nonsecure(); + } + #endif + #if PICO_ALLOW_NONSECURE_PIO + case SECURE_CALL_pio_claim_unused_pio_for_nonsecure: { + return pio_claim_unused_pio_for_nonsecure(); + } + #endif + #if PICO_ADD_NONSECURE_PADS_HELPER + case SECURE_CALL_pads_bank0_set_bits: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + return pads_bank0_set_bits(a, b); + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + } + case SECURE_CALL_pads_bank0_clear_bits: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + return pads_bank0_clear_bits(a, b); + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + } + case SECURE_CALL_pads_bank0_write_masked: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + return pads_bank0_write_masked(a, b, c); + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + } + case SECURE_CALL_pads_bank0_read: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + return pads_bank0_read(a); + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + } + #endif + case SECURE_CALL_clock_get_hz: { + return clock_get_hz(a); + } + #if PICO_ALLOW_NONSECURE_RESETS + case SECURE_CALL_reset_block_mask: { + if (a & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; + reset_block_mask(a); + return BOOTROM_OK; + } + case SECURE_CALL_unreset_block_mask: { + if (a & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; + unreset_block_mask(a); + return BOOTROM_OK; + } + case SECURE_CALL_unreset_block_mask_wait_blocking: { + if (a & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; + unreset_block_mask_wait_blocking(a); + return BOOTROM_OK; + } + #endif + default: { + printf("%d is not a supported rom function\n", fn); + return BOOTROM_ERROR_INVALID_ARG; + } + + } +} + +static int __attribute__((naked)) rom_default_asm_callback() { + pico_default_asm_volatile( + "push {r0, lr}\n" + "str r4, [sp]\n" + "bl rom_default_callback\n" + "pop {r1, pc}\n" + ); +} + +void __weak runtime_init_rom_set_default_callback() { + rom_set_rom_callback(BOOTROM_API_CALLBACK_secure_call, (bootrom_api_callback_generic_t) rom_default_asm_callback); + + rom_set_ns_api_permission(BOOTROM_NS_API_secure_call, true); +} +#endif // !PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK + +#if !PICO_RUNTIME_SKIP_INIT_BOOTROM_API_CALLBACK +PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_rom_set_default_callback, PICO_RUNTIME_INIT_BOOTROM_API_CALLBACK); +#endif + +#if !PICO_RUNTIME_NO_INIT_NONSECURE_CLAIMS +void __weak runtime_init_nonsecure_claims() { +#if PICO_ALLOW_NONSECURE_DMA + for(uint i = 0; i < NUM_DMA_CHANNELS; i++) { + dma_channel_claim(i); + } +#endif +#if PICO_ALLOW_NONSECURE_USER_IRQ + for (uint i = 0; i < NUM_USER_IRQS; i++) { + user_irq_claim(FIRST_USER_IRQ + i); + } +#endif +#if PICO_ALLOW_NONSECURE_PIO + for (uint pio = 0; pio < NUM_PIOS; pio++) { + for (uint sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { + pio_sm_claim(pio_get_instance(pio), sm); + } + } +#endif +} +#endif + +#if !PICO_RUNTIME_SKIP_INIT_NONSECURE_CLAIMS +PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_claims, PICO_RUNTIME_INIT_NONSECURE_CLAIMS); +#endif + +#if !PICO_RUNTIME_NO_INIT_NONSECURE_CLOCKS +#include "hardware/clocks.h" + +void __weak runtime_init_nonsecure_clocks() { + // Set all clocks to the reported frequency from the secure side + for (uint i = 0; i < CLK_COUNT; i++) { + uint32_t hz = rom_secure_call(i, 0, 0, 0, SECURE_CALL_clock_get_hz); + clock_set_reported_hz(i, hz); + } +} +#endif + +#if !PICO_RUNTIME_SKIP_INIT_NONSECURE_CLOCKS +PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_clocks, PICO_RUNTIME_INIT_NONSECURE_CLOCKS); +#endif + + +#endif // PICO_SECURE || PICO_NONSECURE + +#endif // !PICO_RP2040 diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index 4494ae1cf..501a391b6 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -21,6 +21,8 @@ #include #include "pico/bootrom/lock.h" #include "pico/flash.h" + +#include "hardware/structs/pads_bank0.h" // ROM FUNCTION SIGNATURES #if PICO_RP2040 @@ -636,6 +638,21 @@ static inline int rom_flash_op(cflash_flags_t flags, uintptr_t addr, uint32_t si } } + +/*! + * \brief Roll QMI to a partition + * \ingroup pico_bootrom + * + * Rolls the QMI to the specified partition, enabling access to the partition via the translated XIP windows. + * + * This is necessary when the partition is not stored at the flash address it was linked at, e.g. when + * using A/B partitions. + * + * \param partition_num the partition number + * \return BOOTROM_OK on success, otherwise a negative error code + */ +int rom_roll_qmi_to_partition(uint partition_num); + /*! * \brief Writes data from a buffer into OTP, or reads data from OTP into a buffer * \ingroup pico_bootrom @@ -798,15 +815,30 @@ int rom_pick_ab_partition_during_update(uint32_t *workarea_base, uint32_t workar * \ingroup pico_bootrom * * Returns the index of the B partition of partition A if a partition table is present and loaded, and there is a partition A with a B partition; - * otherwise returns BOOTROM_ERROR_NOT_FOUND. + * otherwise returns a negative error code. * * \param pi_a the A partition number + * \return >= 0 the index of the B partition + * BOOTROM_ERROR_NOT_FOUND if the partition number does not have a B partition */ static inline int rom_get_b_partition(uint pi_a) { rom_get_b_partition_fn func = (rom_get_b_partition_fn) rom_func_lookup_inline(ROM_FUNC_GET_B_PARTITION); return func(pi_a); } +/*! + * \brief Get Owned Partition + * \ingroup pico_bootrom + * + * Returns the index of the matching owned partition if a partition table is present and loaded, and the partition number has an owned + * partition; otherwise returns a negative error code. + * + * \param partition_num the partition number + * \return >= 0 the index of the matching owned partition + * BOOTROM_ERROR_NOT_FOUND if the partition number does not have an owned partition + */ +int rom_get_owned_partition(uint partition_num); + // todo SECURE only /*! * \brief Get UF2 Target Partition @@ -1010,6 +1042,225 @@ static inline intptr_t rom_set_rom_callback(uint callback_num, bootrom_api_callb return func(callback_num, funcptr); } +#ifndef __riscv +int rom_secure_call(uint a, uint b, uint c, uint d, uint func); + +int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn); + +// PICO_CONFIG: PICO_MAX_SECURE_CALL_USER_CALLBACKS, Maximum number of secure call user callbacks, default=4, advanced=true, group=pico_bootrom +#ifndef PICO_MAX_SECURE_CALL_USER_CALLBACKS +#define PICO_MAX_SECURE_CALL_USER_CALLBACKS 4 +#endif + +/*! Callback function type for user handled rom_secure_call + * \ingroup pico_bootrom + */ +typedef int (*rom_secure_call_callback_t)(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn); + +/*! + * \brief Add user ROM callback function + * \ingroup pico_bootrom + * + * Add a user callback for rom_secure_call called if using a function code starting with `0b1xxx`, + * which is a "unique" or "private" function as specified by the rom_secure_call() documentation. + * + * \param callback pointer to the callback function + * \param fn_mask first 16 bits of fn codes this callback handles + */ +int rom_secure_call_add_user_callback(rom_secure_call_callback_t callback, uint16_t fn_mask); + +/*! + * \brief Remove user ROM callback function + * \ingroup pico_bootrom + * + * Remove a user callback for rom_secure_call which was previously added with rom_secure_call_add_user_callback() + * + * \param callback pointer to the callback function + */ +void rom_secure_call_remove_user_callback(rom_secure_call_callback_t callback); + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_STDIO, Allow non-secure to use stdio, type=bool, default=0, group=pico_bootrom +#ifndef PICO_ALLOW_NONSECURE_STDIO +#define PICO_ALLOW_NONSECURE_STDIO 0 +#endif + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_RAND, Allow non-secure to request random numbers, type=bool, default=0, group=pico_bootrom +#ifndef PICO_ALLOW_NONSECURE_RAND +#define PICO_ALLOW_NONSECURE_RAND 0 +#endif + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_DMA, Allow non-secure to request DMA channels, type=bool, default=0, group=hardware_dma +#ifndef PICO_ALLOW_NONSECURE_DMA +#define PICO_ALLOW_NONSECURE_DMA 0 +#endif + +// PICO_CONFIG: PICO_NONSECURE_DMA_MAX_CHANNEL, Max number of DMA channels that can be allocated to non-secure use, type=int, default=NUM_DMA_CHANNELS, group=hardware_dma +#ifndef PICO_NONSECURE_DMA_MAX_CHANNEL +#define PICO_NONSECURE_DMA_MAX_CHANNEL NUM_DMA_CHANNELS +#endif + +#if PICO_ALLOW_NONSECURE_DMA && PICO_NONSECURE +/*! \brief Request unused dma channels from secure + * \ingroup hardware_dma + * + * \param num_channels the number of channels to request + * \return the number of channels provided + */ +int dma_request_unused_channels_from_secure(int num_channels); +#endif + +// PICO_CONFIG: PICO_ALLOW_USER_IRQ, Allow non-secure to request user IRQs, type=bool, default=0, group=hardware_irq +#ifndef PICO_ALLOW_NONSECURE_USER_IRQ +#define PICO_ALLOW_NONSECURE_USER_IRQ 0 +#endif + +// PICO_CONFIG: PICO_NONSECURE_USER_IRQ_MIN, Lowest number user IRQ that can be allocated to non-secure use, type=int, default=FIRST_USER_IRQ, group=hardware_irq +#ifndef PICO_NONSECURE_USER_IRQ_MIN +#define PICO_NONSECURE_USER_IRQ_MIN FIRST_USER_IRQ +#endif + +#if PICO_ALLOW_NONSECURE_USER_IRQ && PICO_NONSECURE +/*! \brief Request unused user IRQs from secure + * \ingroup hardware_irq + * + * \param num_irqs the number of IRQs to request + * \return the number of IRQs provided + */ +int user_irq_request_unused_from_secure(int num_irqs); +#endif + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_PIO, Allow non-secure to request PIOs, type=bool, default=0, group=hardware_pio +#ifndef PICO_ALLOW_NONSECURE_PIO +#define PICO_ALLOW_NONSECURE_PIO 0 +#endif + +// PICO_CONFIG: PICO_NONSECURE_PIO_MAX, Max number of PIOs that can be allocated to non-secure use, type=int, default=NUM_PIOS, group=hardware_pio +#ifndef PICO_NONSECURE_PIO_MAX +#define PICO_NONSECURE_PIO_MAX NUM_PIOS +#endif + +#if PICO_ALLOW_NONSECURE_PIO && PICO_NONSECURE +/*! \brief Request unused PIO from secure + * \ingroup hardware_pio + * + * \return the PIO number + */ +int pio_request_unused_pio_from_secure(void); +#endif + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_GPIO, Allow non-secure to access GPIO, type=bool, default=0, group=hardware_gpio +#ifndef PICO_ALLOW_NONSECURE_GPIO +#define PICO_ALLOW_NONSECURE_GPIO 0 +#endif + +// PICO_CONFIG: PICO_ADD_NONSECURE_PADS_HELPER, Add non-secure helper functions for PADS_BANK0, type=bool, default=1 on RP2350A A2, group=hardware_pads +#ifndef PICO_ADD_NONSECURE_PADS_HELPER +#define PICO_ADD_NONSECURE_PADS_HELPER PICO_RP2350A && PICO_RP2350_A2_SUPPORTED && PICO_ALLOW_NONSECURE_GPIO +#endif + +/*! \brief Set bits in PADS_BANK0 + * \ingroup hardware_pads + * + * \param gpio the GPIO number + * \param bits the bits to set + */ +#if PICO_ADD_NONSECURE_PADS_HELPER && PICO_NONSECURE +static inline int pads_bank0_set_bits(uint gpio, uint bits) { + return rom_secure_call(gpio, bits, 0, 0, SECURE_CALL_pads_bank0_set_bits); +} +#else +static inline int pads_bank0_set_bits(uint gpio, uint bits) { + hw_set_bits(&pads_bank0_hw->io[gpio], bits); + return PICO_OK; +} +#endif + +/*! \brief Clear bits in PADS_BANK0 + * \ingroup hardware_pads + * + * \param gpio the GPIO number + * \param bits the bits to clear + */ +#if PICO_ADD_NONSECURE_PADS_HELPER && PICO_NONSECURE +static inline int pads_bank0_clear_bits(uint gpio, uint bits) { + return rom_secure_call(gpio, bits, 0, 0, SECURE_CALL_pads_bank0_clear_bits); +} +#else +static inline int pads_bank0_clear_bits(uint gpio, uint bits) { + hw_clear_bits(&pads_bank0_hw->io[gpio], bits); + return PICO_OK; +} +#endif + +/*! \brief Write masked bits in PADS_BANK0 + * \ingroup hardware_pads + * + * \param gpio the GPIO number + * \param bits the bits to write + * \param mask the mask + */ +#if PICO_ADD_NONSECURE_PADS_HELPER && PICO_NONSECURE +static inline int pads_bank0_write_masked(uint gpio, uint bits, uint mask) { + return rom_secure_call(gpio, bits, mask, 0, SECURE_CALL_pads_bank0_write_masked); +} +#else +static inline int pads_bank0_write_masked(uint gpio, uint bits, uint mask) { + hw_write_masked(&pads_bank0_hw->io[gpio], bits, mask); + return PICO_OK; +} +#endif + +/*! \brief Read bits in PADS_BANK0 + * \ingroup hardware_pads + * + * \param gpio the GPIO number + * \return the bits read + */ +#if PICO_ADD_NONSECURE_PADS_HELPER && PICO_NONSECURE +static inline int pads_bank0_read(uint gpio) { + return rom_secure_call(gpio, 0, 0, 0, SECURE_CALL_pads_bank0_read); +} +#else +static inline int pads_bank0_read(uint gpio) { + return pads_bank0_hw->io[gpio]; +} +#endif + + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_USB, Allow non-secure to access USB, type=bool, default=0, group=hardware_usb +#ifndef PICO_ALLOW_NONSECURE_USB +#define PICO_ALLOW_NONSECURE_USB 0 +#endif + + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_RESETS, Allow non-secure to access RESETS, type=bool, default=0, group=hardware_resets +#ifndef PICO_ALLOW_NONSECURE_RESETS +#define PICO_ALLOW_NONSECURE_RESETS 0 +#endif + +#if PICO_SECURE +#include "hardware/regs/resets.h" + +// PICO_CONFIG: PICO_ALLOW_NONSECURE_RESETS_MASK, Mask of RESETS that can be accessed by non-secure, type=int, default=resets needed for other PICO_ALLOW_NONSECURE_* options, group=hardware_resets +#ifndef PICO_ALLOW_NONSECURE_RESETS_MASK +#define PICO_ALLOW_NONSECURE_RESETS_MASK (PICO_ALLOW_NONSECURE_USB ? RESETS_RESET_USBCTRL_BITS : 0) +#endif +#endif + +#if PICO_ALLOW_NONSECURE_RESETS && PICO_NONSECURE +static inline int reset_block_reg_mask(__unused io_rw_32 *reset, uint32_t mask) { + return rom_secure_call(mask, 0, 0, 0, SECURE_CALL_reset_block_mask); +} +static inline int unreset_block_reg_mask(__unused io_rw_32 *reset, uint32_t mask) { + return rom_secure_call(mask, 0, 0, 0, SECURE_CALL_unreset_block_mask); +} +static inline int unreset_block_reg_mask_wait_blocking(__unused io_rw_32 *reset, __unused io_ro_32 *reset_done, uint32_t mask) { + return rom_secure_call(mask, 0, 0, 0, SECURE_CALL_unreset_block_mask_wait_blocking); +} +#endif + +#endif // ifndef __riscv + #define BOOT_TYPE_NORMAL 0 #define BOOT_TYPE_BOOTSEL 2 #define BOOT_TYPE_RAM_IMAGE 3 diff --git a/src/rp2_common/pico_crt0/embedded_start_block.inc.S b/src/rp2_common/pico_crt0/embedded_start_block.inc.S index 4618a3a94..ace7d3b1d 100644 --- a/src/rp2_common/pico_crt0/embedded_start_block.inc.S +++ b/src/rp2_common/pico_crt0/embedded_start_block.inc.S @@ -62,6 +62,12 @@ embedded_block: PICOBIN_IMAGE_TYPE_EXE_CPU_AS_BITS(ARM) | \ PICOBIN_IMAGE_TYPE_EXE_CHIP_AS_BITS(RP2040) | \ CRT0_TBYB_FLAG +#elif PICO_NONSECURE +.hword PICOBIN_IMAGE_TYPE_IMAGE_TYPE_AS_BITS(EXE) | \ + PICOBIN_IMAGE_TYPE_EXE_SECURITY_AS_BITS(NS) | \ + PICOBIN_IMAGE_TYPE_EXE_CPU_AS_BITS(ARM) | \ + PICOBIN_IMAGE_TYPE_EXE_CHIP_AS_BITS(RP2350) | \ + CRT0_TBYB_FLAG #else .hword PICOBIN_IMAGE_TYPE_IMAGE_TYPE_AS_BITS(EXE) | \ PICOBIN_IMAGE_TYPE_EXE_SECURITY_AS_BITS(S) | \ diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld index 6f5000566..a4a528950 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld @@ -1,286 +1,4 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - INCLUDE "pico_flash_region.ld" - RAM(rwx) : ORIGIN = 0x21000000, LENGTH = 256k - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k -} - -ENTRY(_entry_point) - -SECTIONS -{ - /* Second stage bootloader is prepended to the image. It must be 256 bytes big - and checksummed. It is usually built by the boot_stage2 target - in the Raspberry Pi Pico SDK - */ - - .flash_begin : { - __flash_binary_start = .; - } > FLASH - - .boot2 : { - __boot2_start__ = .; - KEEP (*(.boot2)) - __boot2_end__ = .; - } > FLASH - - ASSERT(__boot2_end__ - __boot2_start__ == 256, - "ERROR: Pico second stage bootloader must be 256 bytes in size") - - /* The second stage will always enter the image at the start of .text. - The debugger will use the ELF entry point, which is the _entry_point - symbol if present, otherwise defaults to start of .text. - This can be used to transfer control back to the bootrom on debugger - launches only, to perform proper flash setup. - */ - - .text : { - __logical_binary_start = .; - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - KEEP (*(.reset)) - /* TODO revisit this now memset/memcpy/float in ROM */ - /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from - * FLASH ... we will include any thing excluded here in .data below by default */ - *(.init) - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.eh_frame*) - . = ALIGN(4); - } > FLASH - - .rodata : { - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) - . = ALIGN(4); - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > FLASH - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > FLASH - __binary_info_end = .; - . = ALIGN(4); - - .ram_vector_table (NOLOAD): { - *(.ram_vector_table) - } > RAM - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ - *(.text*) - . = ALIGN(4); - *(.rodata*) - . = ALIGN(4); - - *(.data*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - . = ALIGN(4); - *(.jcr) - . = ALIGN(4); - } > RAM AT> FLASH - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM AT> FLASH - PROVIDE(__data_end__ = .); - - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss (NOLOAD) : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - } > RAM - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X AT > FLASH - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y AT > FLASH - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - .flash_end : { - KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); - } > FLASH - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = ORIGIN(RAM) + LENGTH(RAM); - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") - /* todo assert on extra code */ -} +/* Use blocked ram */ +RAM_ORIGIN = 0x21000000; +INCLUDE "memmap_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld index 842ebfd3c..6a1647d4a 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld @@ -1,287 +1 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - INCLUDE "pico_flash_region.ld" - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k -} - -ENTRY(_entry_point) - -SECTIONS -{ - /* Second stage bootloader is prepended to the image. It must be 256 bytes big - and checksummed. It is usually built by the boot_stage2 target - in the Raspberry Pi Pico SDK - */ - - .flash_begin : { - __flash_binary_start = .; - } > FLASH - - .boot2 : { - __boot2_start__ = .; - KEEP (*(.boot2)) - __boot2_end__ = .; - } > FLASH - - ASSERT(__boot2_end__ - __boot2_start__ == 256, - "ERROR: Pico second stage bootloader must be 256 bytes in size") - - /* The second stage will always enter the image at the start of .text. - The debugger will use the ELF entry point, which is the _entry_point - symbol if present, otherwise defaults to start of .text. - This can be used to transfer control back to the bootrom on debugger - launches only, to perform proper flash setup. - */ - - .flashtext : { - __logical_binary_start = .; - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - KEEP (*(.reset)) - } - - .rodata : { - /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > FLASH - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > FLASH - __binary_info_end = .; - . = ALIGN(4); - - /* Vector table goes first in RAM, to avoid large alignment hole */ - .ram_vector_table (NOLOAD): { - *(.ram_vector_table) - } > RAM - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - - .text : { - __ram_text_start__ = .; - *(.init) - *(.text*) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - *(.eh_frame*) - . = ALIGN(4); - __ram_text_end__ = .; - } > RAM AT> FLASH - __ram_text_source__ = LOADADDR(.text); - . = ALIGN(4); - - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - . = ALIGN(4); - *(.rodata*) - . = ALIGN(4); - - *(.data*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.jcr) - . = ALIGN(4); - } > RAM AT> FLASH - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM AT> FLASH - PROVIDE(__data_end__ = .); - - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - } > RAM - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X AT > FLASH - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y AT > FLASH - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - .flash_end : { - KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); - } > FLASH - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = ORIGIN(RAM) + LENGTH(RAM); - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") - /* todo assert on extra code */ -} - +INCLUDE "rp2_common/memmap_copy_to_ram.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld index 51254012d..8e2073718 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld @@ -1,286 +1 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - INCLUDE "pico_flash_region.ld" - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k -} - -ENTRY(_entry_point) - -SECTIONS -{ - /* Second stage bootloader is prepended to the image. It must be 256 bytes big - and checksummed. It is usually built by the boot_stage2 target - in the Raspberry Pi Pico SDK - */ - - .flash_begin : { - __flash_binary_start = .; - } > FLASH - - .boot2 : { - __boot2_start__ = .; - KEEP (*(.boot2)) - __boot2_end__ = .; - } > FLASH - - ASSERT(__boot2_end__ - __boot2_start__ == 256, - "ERROR: Pico second stage bootloader must be 256 bytes in size") - - /* The second stage will always enter the image at the start of .text. - The debugger will use the ELF entry point, which is the _entry_point - symbol if present, otherwise defaults to start of .text. - This can be used to transfer control back to the bootrom on debugger - launches only, to perform proper flash setup. - */ - - .text : { - __logical_binary_start = .; - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - KEEP (*(.reset)) - /* TODO revisit this now memset/memcpy/float in ROM */ - /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from - * FLASH ... we will include any thing excluded here in .data below by default */ - *(.init) - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.eh_frame*) - . = ALIGN(4); - } > FLASH - - .rodata : { - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) - . = ALIGN(4); - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > FLASH - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > FLASH - __binary_info_end = .; - . = ALIGN(4); - - .ram_vector_table (NOLOAD): { - *(.ram_vector_table) - } > RAM - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ - *(.text*) - . = ALIGN(4); - *(.rodata*) - . = ALIGN(4); - - *(.data*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - . = ALIGN(4); - *(.jcr) - . = ALIGN(4); - } > RAM AT> FLASH - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM AT> FLASH - PROVIDE(__data_end__ = .); - - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss (NOLOAD) : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - } > RAM - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X AT > FLASH - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y AT > FLASH - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - .flash_end : { - KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); - } > FLASH - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = ORIGIN(RAM) + LENGTH(RAM); - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") - /* todo assert on extra code */ -} - +INCLUDE "rp2_common/memmap_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld b/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld index dbf006a8c..b8d1dcf36 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld @@ -1,249 +1 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k -} - -ENTRY(_entry_point) - -SECTIONS -{ - /* Note in NO_FLASH builds the entry point for both the bootrom, and debugger - entry (ELF entry point), are *first* in the image, and the vector table - follows immediately afterward. This is because the bootrom enters RAM - binaries directly at their lowest address (preferring main RAM over XIP - cache-as-SRAM if both are used). - */ - - .text : { - __logical_binary_start = .; - __reset_start = .; - KEEP (*(.reset)) - __reset_end = .; - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - . = ALIGN(256); - KEEP (*(.vectors)) - *(.time_critical*) - *(.text*) - . = ALIGN(4); - *(.init) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - *(.eh_frame*) - } > RAM - - .rodata : { - . = ALIGN(4); - *(.rodata*) - . = ALIGN(4); - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > RAM - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > RAM - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > RAM - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > RAM - __binary_info_end = .; - . = ALIGN(4); - - .data : { - __data_start__ = .; - *(vtable) - *(.data*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.jcr) - . = ALIGN(4); - } > RAM - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM - PROVIDE(__data_end__ = .); - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss (NOLOAD) : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - } > RAM - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = ORIGIN(RAM) + LENGTH(RAM); - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") - /* todo assert on extra code */ -} - +INCLUDE "rp2_common/memmap_no_flash.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld b/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld new file mode 100644 index 000000000..03144ea07 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld @@ -0,0 +1,8 @@ +RAM_ORIGIN_DEFAULT = 0x20000000; +RAM_LENGTH_DEFAULT = 256k; +SCRATCH_X_ORIGIN_DEFAULT = 0x20040000; +SCRATCH_X_LENGTH_DEFAULT = 4k; +SCRATCH_Y_ORIGIN_DEFAULT = 0x20041000; +SCRATCH_Y_LENGTH_DEFAULT = 4k; +XIP_RAM_ORIGIN_DEFAULT = 0x15000000; +XIP_RAM_LENGTH_DEFAULT = 16k; diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_text.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_text.ld new file mode 100644 index 000000000..77a45941b --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_text.ld @@ -0,0 +1,101 @@ +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Raspberry Pi Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + /* The second stage will always enter the image at the start of .text. + The debugger will use the ELF entry point, which is the _entry_point + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .flashtext : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + } + + .rodata : { + /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + /* Vector table goes first in RAM, to avoid large alignment hole */ + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .text : { + __ram_text_start__ = .; + *(.init) + *(.text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + . = ALIGN(4); + __ram_text_end__ = .; + } > RAM AT> FLASH + __ram_text_source__ = LOADADDR(.text); + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld new file mode 100644 index 000000000..7aa5c9399 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld @@ -0,0 +1,109 @@ +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Raspberry Pi Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + /* The second stage will always enter the image at the start of .text. + The debugger will use the ELF entry point, which is the _entry_point + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_text.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_text.ld new file mode 100644 index 000000000..b4ad44ba7 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_text.ld @@ -0,0 +1,71 @@ +SECTIONS +{ + /* Note in NO_FLASH builds the entry point for both the bootrom, and debugger + entry (ELF entry point), are *first* in the image, and the vector table + follows immediately afterward. This is because the bootrom enters RAM + binaries directly at their lowest address (preferring main RAM over XIP + cache-as-SRAM if both are used). + */ + + .text : { + __logical_binary_start = .; + __reset_start = .; + KEEP (*(.reset)) + __reset_end = .; + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + . = ALIGN(256); + KEEP (*(.vectors)) + *(.text*) + . = ALIGN(4); + *(.init) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + } > RAM + + .rodata : { + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > RAM + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > RAM + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > RAM + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > RAM + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_platform_end.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_platform_end.ld new file mode 100644 index 000000000..2d0165aa4 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_platform_end.ld @@ -0,0 +1,50 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +SECTIONS +{ + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") + /* todo assert on extra code */ +} diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld index 44c69f3b9..6a1647d4a 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld @@ -1,309 +1 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - INCLUDE "pico_flash_region.ld" - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k - SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k -} - -ENTRY(_entry_point) - -SECTIONS -{ - /* On Arm, the bootrom expects a VT at the start of the - image by default; on RISC-V, the default is to enter the image at its - lowest address, so an IMAGE_DEF item is required to specify the - nondefault entry point. */ - - .flash_begin : { - __flash_binary_start = .; - } > FLASH - - /* The bootrom will enter the image at the point indicated in your - IMAGE_DEF, which is usually the reset handler of your vector table. - - The debugger will use the ELF entry point, which is the _entry_point - symbol, and in our case is *different from the bootrom's entry point.* - This is used to go back through the bootrom on debugger launches only, - to perform the same initial flash setup that would be performed on a - cold boot. - */ - - .flashtext : { - __logical_binary_start = .; - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - KEEP (*(.reset)) - . = ALIGN(4); - } > FLASH - - /* Note the boot2 section is optional, and should be discarded if there is - no reference to it *inside* the binary, as it is not called by the - bootrom. (The bootrom performs a simple best-effort XIP setup and - leaves it to the binary to do anything more sophisticated.) However - there is still a size limit of 256 bytes, to ensure the boot2 can be - stored in boot RAM. - - Really this is a "XIP setup function" -- the name boot2 is historic and - refers to its dual-purpose on RP2040, where it also handled vectoring - from the bootrom into the user image. - */ - - .boot2 : { - __boot2_start__ = .; - *(.boot2) - __boot2_end__ = .; - } > FLASH - - ASSERT(__boot2_end__ - __boot2_start__ <= 256, - "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") - - .rodata : { - /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > FLASH - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > FLASH - __binary_info_end = .; - . = ALIGN(4); - - /* Vector table goes first in RAM, to avoid large alignment hole */ - .ram_vector_table (NOLOAD): { - *(.ram_vector_table) - } > RAM - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - - .text : { - __ram_text_start__ = .; - *(.init) - *(.text*) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - *(.eh_frame*) - . = ALIGN(4); - __ram_text_end__ = .; - } > RAM AT> FLASH - __ram_text_source__ = LOADADDR(.text); - . = ALIGN(4); - - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - . = ALIGN(4); - *(.rodata*) - *(.srodata*) - . = ALIGN(4); - - *(.data*) - *(.sdata*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.jcr) - . = ALIGN(4); - } > RAM AT> FLASH - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM AT> FLASH - PROVIDE(__data_end__ = .); - - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - PROVIDE(__global_pointer$ = . + 2K); - *(.sbss*) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - } > RAM - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X AT > FLASH - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y AT > FLASH - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - .flash_end : { - KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); - } > FLASH =0xaa - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = ORIGIN(RAM) + LENGTH(RAM); - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") - ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") - - /* todo assert on extra code */ -} - +INCLUDE "rp2_common/memmap_copy_to_ram.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld index bce316d14..8e2073718 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld @@ -1,302 +1 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - INCLUDE "pico_flash_region.ld" - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k - SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k -} - -ENTRY(_entry_point) - -SECTIONS -{ - .flash_begin : { - __flash_binary_start = .; - } > FLASH - - /* The bootrom will enter the image at the point indicated in your - IMAGE_DEF, which is usually the reset handler of your vector table. - - The debugger will use the ELF entry point, which is the _entry_point - symbol, and in our case is *different from the bootrom's entry point.* - This is used to go back through the bootrom on debugger launches only, - to perform the same initial flash setup that would be performed on a - cold boot. - */ - - .text : { - __logical_binary_start = .; - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - KEEP (*(.reset)) - /* TODO revisit this now memset/memcpy/float in ROM */ - /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from - * FLASH ... we will include any thing excluded here in .data below by default */ - *(.init) - *libgcc.a:cmse_nonsecure_call.o - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.eh_frame*) - . = ALIGN(4); - } > FLASH - - /* Note the boot2 section is optional, and should be discarded if there is - no reference to it *inside* the binary, as it is not called by the - bootrom. (The bootrom performs a simple best-effort XIP setup and - leaves it to the binary to do anything more sophisticated.) However - there is still a size limit of 256 bytes, to ensure the boot2 can be - stored in boot RAM. - - Really this is a "XIP setup function" -- the name boot2 is historic and - refers to its dual-purpose on RP2040, where it also handled vectoring - from the bootrom into the user image. - */ - - .boot2 : { - __boot2_start__ = .; - *(.boot2) - __boot2_end__ = .; - } > FLASH - - ASSERT(__boot2_end__ - __boot2_start__ <= 256, - "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") - - .rodata : { - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) - *(.srodata*) - . = ALIGN(4); - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > FLASH - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > FLASH - __binary_info_end = .; - . = ALIGN(4); - - .ram_vector_table (NOLOAD): { - *(.ram_vector_table) - } > RAM - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ - *(.text*) - . = ALIGN(4); - *(.rodata*) - . = ALIGN(4); - - *(.data*) - *(.sdata*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - *(.jcr) - . = ALIGN(4); - } > RAM AT> FLASH - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM AT> FLASH - PROVIDE(__data_end__ = .); - - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss (NOLOAD) : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - PROVIDE(__global_pointer$ = . + 2K); - *(.sbss*) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - } > RAM - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X AT > FLASH - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y AT > FLASH - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - .flash_end : { - KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); - } > FLASH =0xaa - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = ORIGIN(RAM) + LENGTH(RAM); - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") - ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") - - /* todo assert on extra code */ -} - +INCLUDE "rp2_common/memmap_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld b/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld index 5bedf6d21..b8d1dcf36 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld @@ -1,256 +1 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k - SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k -} - -ENTRY(_entry_point) - -SECTIONS -{ - /* Note unlike RP2040, we start the image with a vector table even for - NO_FLASH builds. On Arm, the bootrom expects a VT at the start of the - image by default; on RISC-V, the default is to enter the image at its - lowest address, so an IMAGE_DEF item is required to specify the - nondefault entry point. */ - - .text : { - __logical_binary_start = .; - /* Vectors require 512-byte alignment on v8-M when >48 IRQs are used, - so we would waste RAM if the vector table were not at the - start. */ - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - __reset_start = .; - KEEP (*(.reset)) - __reset_end = .; - *(.time_critical*) - *(.text*) - . = ALIGN(4); - *(.init) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - *(.eh_frame*) - } > RAM - - .rodata : { - . = ALIGN(4); - *(.rodata*) - *(.srodata*) - . = ALIGN(4); - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > RAM - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > RAM - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > RAM - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > RAM - __binary_info_end = .; - . = ALIGN(4); - - .data : { - __data_start__ = .; - *(vtable) - *(.data*) - *(.sdata*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.jcr) - . = ALIGN(4); - } > RAM - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM - PROVIDE(__data_end__ = .); - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss (NOLOAD) : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - PROVIDE(__global_pointer$ = . + 2K); - *(.sbss*) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - } > RAM - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = ORIGIN(RAM) + LENGTH(RAM); - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") - ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") - - /* todo assert on extra code */ -} - +INCLUDE "rp2_common/memmap_no_flash.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld b/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld new file mode 100644 index 000000000..15ddc7374 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld @@ -0,0 +1,8 @@ +RAM_ORIGIN_DEFAULT = 0x20000000; +RAM_LENGTH_DEFAULT = 512k; +SCRATCH_X_ORIGIN_DEFAULT = 0x20080000; +SCRATCH_X_LENGTH_DEFAULT = 4k; +SCRATCH_Y_ORIGIN_DEFAULT = 0x20081000; +SCRATCH_Y_LENGTH_DEFAULT = 4k; +XIP_RAM_ORIGIN_DEFAULT = 0x13FFC000; +XIP_RAM_LENGTH_DEFAULT = 16k; diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_text.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_text.ld new file mode 100644 index 000000000..d35f7209e --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_text.ld @@ -0,0 +1,117 @@ +SECTIONS +{ + /* On Arm, the bootrom expects a VT at the start of the + image by default; on RISC-V, the default is to enter the image at its + lowest address, so an IMAGE_DEF item is required to specify the + nondefault entry point. */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .flashtext : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + . = ALIGN(4); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + /* Vector table goes first in RAM, to avoid large alignment hole */ + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .text : { + __ram_text_start__ = .; + *(.init) + *(.text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + . = ALIGN(4); + __ram_text_end__ = .; + } > RAM AT> FLASH + __ram_text_source__ = LOADADDR(.text); + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld new file mode 100644 index 000000000..fdd963321 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld @@ -0,0 +1,121 @@ +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *libgcc.a:cmse_nonsecure_call.o + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_text.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_text.ld new file mode 100644 index 000000000..833d8c42b --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_text.ld @@ -0,0 +1,73 @@ +SECTIONS +{ + /* Note unlike RP2040, we start the image with a vector table even for + NO_FLASH builds. On Arm, the bootrom expects a VT at the start of the + image by default; on RISC-V, the default is to enter the image at its + lowest address, so an IMAGE_DEF item is required to specify the + nondefault entry point. */ + + .text : { + __logical_binary_start = .; + /* Vectors require 512-byte alignment on v8-M when >48 IRQs are used, + so we would waste RAM if the vector table were not at the + start. */ + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + __reset_start = .; + KEEP (*(.reset)) + __reset_end = .; + *(.text*) + . = ALIGN(4); + *(.init) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + } > RAM + + .rodata : { + . = ALIGN(4); + *(.rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > RAM + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > RAM + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > RAM + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > RAM + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_platform_end.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_platform_end.ld new file mode 100644 index 000000000..43cc19ecd --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_platform_end.ld @@ -0,0 +1,7 @@ +SECTIONS +{ + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} diff --git a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c index 06d5beff3..5f13c76b3 100644 --- a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c +++ b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c @@ -123,11 +123,11 @@ int cyw43_spi_init(cyw43_int_t *self) { pio_sm_config config = SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC(bus_data->pio_offset); sm_config_set_clkdiv_int_frac8(&config, cyw43_pio_clock_div_int, cyw43_pio_clock_div_frac8); - hw_write_masked(&pads_bank0_hw->io[CYW43_PIN_WL_CLOCK], + pads_bank0_write_masked(CYW43_PIN_WL_CLOCK, (uint)PADS_DRIVE_STRENGTH << PADS_BANK0_GPIO0_DRIVE_LSB, PADS_BANK0_GPIO0_DRIVE_BITS ); - hw_write_masked(&pads_bank0_hw->io[CYW43_PIN_WL_CLOCK], + pads_bank0_write_masked(CYW43_PIN_WL_CLOCK, (uint)1 << PADS_BANK0_GPIO0_SLEWFAST_LSB, PADS_BANK0_GPIO0_SLEWFAST_BITS ); diff --git a/src/rp2_common/pico_cyw43_driver/cyw43_driver.c b/src/rp2_common/pico_cyw43_driver/cyw43_driver.c index 95e5da5e3..541033958 100644 --- a/src/rp2_common/pico_cyw43_driver/cyw43_driver.c +++ b/src/rp2_common/pico_cyw43_driver/cyw43_driver.c @@ -66,7 +66,7 @@ uint32_t cyw43_irq_init(__unused void *param) { #endif gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, cyw43_gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY); cyw43_set_irq_enabled(true); - irq_set_enabled(IO_IRQ_BANK0, true); + irq_set_enabled(DEFAULT_IO_IRQ_BANK0, true); return 0; } diff --git a/src/rp2_common/pico_rand/rand.c b/src/rp2_common/pico_rand/rand.c index 03b0e3d61..90c521bf7 100644 --- a/src/rp2_common/pico_rand/rand.c +++ b/src/rp2_common/pico_rand/rand.c @@ -325,7 +325,7 @@ static void initialise_rand(void) { spin_unlock(lock, save); } -uint64_t get_rand_64(void) { +uint64_t __weak get_rand_64(void) { if (!rng_initialised) { // Do not provide 'RNs' until the system has been initialised. Note: // The first initialisation can be quite time-consuming depending on diff --git a/src/rp2_common/pico_runtime/include/pico/runtime.h b/src/rp2_common/pico_runtime/include/pico/runtime.h index 35d871d92..84e78a36a 100644 --- a/src/rp2_common/pico_runtime/include/pico/runtime.h +++ b/src/rp2_common/pico_runtime/include/pico/runtime.h @@ -58,7 +58,12 @@ void runtime_run_per_core_initializers(void); #define PICO_RUNTIME_INIT_FUNC(func, priority_string) __pre_init func, priority_string #endif #endif +#if PICO_NONSECURE +// hw init cannot be done by non-secure +#define PICO_RUNTIME_INIT_FUNC_HW(func, priority_string) +#else #define PICO_RUNTIME_INIT_FUNC_HW(func, priority_string) PICO_RUNTIME_INIT_FUNC(func, priority_string) +#endif #define PICO_RUNTIME_INIT_FUNC_RUNTIME(func, priority_string) PICO_RUNTIME_INIT_FUNC(func, priority_string) // priority strings are of the form 00000->99999; we want the per core stuff all at the end, so prefix with ZZZZZ which is clearly after 99999 #define PICO_RUNTIME_INIT_FUNC_PER_CORE(func, priority_string) PICO_RUNTIME_INIT_FUNC(func, "ZZZZZ." priority_string) diff --git a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h index c6ed4cf8e..533ddc9a3 100644 --- a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h +++ b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h @@ -64,13 +64,13 @@ extern "C" { #endif #ifndef PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET -#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) +#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) || PICO_NONSECURE #define PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET 1 #endif #endif #ifndef PICO_RUNTIME_NO_INIT_BOOTROM_RESET -#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) +#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) || PICO_NONSECURE #define PICO_RUNTIME_NO_INIT_BOOTROM_RESET 1 #endif #endif @@ -89,13 +89,13 @@ void runtime_init_bootrom_reset(void); // PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET, Skip calling of `runtime_init_per_core_bootrom_reset` function during per-core init, type=bool, default=1 on RP2040, group=pico_runtime_init // PICO_CONFIG: PICO_RUNTIME_NO_INIT_PER_CORE_BOOTROM_RESET, Do not include SDK implementation of `runtime_init_per_core_bootrom_reset` function, type=bool, default=1 on RP2040, group=pico_runtime_init #ifndef PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET -#if PICO_RP2040 +#if PICO_RP2040 || PICO_NONSECURE #define PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET 1 #endif #endif #ifndef PICO_RUNTIME_NO_INIT_PER_CORE_BOOTROM_RESET -#if PICO_RP2040 +#if PICO_RP2040 || PICO_NONSECURE #define PICO_RUNTIME_NO_INIT_PER_CORE_BOOTROM_RESET 1 #endif #endif @@ -317,8 +317,12 @@ void runtime_init_spin_locks_reset(void); #endif #ifndef PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET +#if PICO_NONSECURE +#define PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET 1 +#else #define PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET 0 #endif +#endif #ifndef __ASSEMBLER__ void runtime_init_boot_locks_reset(void); #endif @@ -333,13 +337,113 @@ void runtime_init_boot_locks_reset(void); #endif #ifndef PICO_RUNTIME_SKIP_INIT_BOOTROM_LOCKING_ENABLE +#if PICO_NONSECURE +#define PICO_RUNTIME_SKIP_INIT_BOOTROM_LOCKING_ENABLE 1 +#else #define PICO_RUNTIME_SKIP_INIT_BOOTROM_LOCKING_ENABLE 0 #endif +#endif #ifndef __ASSEMBLER__ void runtime_init_bootrom_locking_enable(void); #endif +// ------------------------------ +// Set default bootrom secure callback +// ------------------------------ +// PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_BOOTROM_API_CALLBACK, Skip calling of `runtime_init_rom_set_default_callback` function during runtime init, type=bool, default=0, group=pico_runtime_init +#ifndef PICO_RUNTIME_INIT_BOOTROM_API_CALLBACK +#define PICO_RUNTIME_INIT_BOOTROM_API_CALLBACK "01020" +#endif + +#ifndef PICO_RUNTIME_SKIP_INIT_BOOTROM_API_CALLBACK +#define PICO_RUNTIME_SKIP_INIT_BOOTROM_API_CALLBACK !PICO_SECURE +#endif + +#ifndef PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK +#define PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK !PICO_SECURE +#endif + +// ------------------------------ +// Initialise non-secure claimed resources +// ------------------------------ +// PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_NONSECURE_CLAIMS, Skip calling of `runtime_init_nonsecure_claims` function during runtime init, type=bool, default=0, group=pico_runtime_init +#ifndef PICO_RUNTIME_INIT_NONSECURE_CLAIMS +#define PICO_RUNTIME_INIT_NONSECURE_CLAIMS "01020" +#endif + +#ifndef PICO_RUNTIME_SKIP_INIT_NONSECURE_CLAIMS +#define PICO_RUNTIME_SKIP_INIT_NONSECURE_CLAIMS !PICO_NONSECURE +#endif + +#ifndef PICO_RUNTIME_NO_INIT_NONSECURE_CLAIMS +#define PICO_RUNTIME_NO_INIT_NONSECURE_CLAIMS !PICO_NONSECURE +#endif + +// ------------------------------ +// Initialise non-secure stdio +// ------------------------------ +// PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_NONSECURE_STDIO, Skip calling of `runtime_init_nonsecure_stdio` function during runtime init, type=bool, default=0, group=pico_runtime_init +#ifndef PICO_RUNTIME_INIT_NONSECURE_STDIO +#define PICO_RUNTIME_INIT_NONSECURE_STDIO "20000" +#endif + +#ifndef PICO_RUNTIME_SKIP_INIT_NONSECURE_STDIO +#define PICO_RUNTIME_SKIP_INIT_NONSECURE_STDIO !PICO_NONSECURE +#endif + +#ifndef PICO_RUNTIME_NO_INIT_NONSECURE_STDIO +#define PICO_RUNTIME_NO_INIT_NONSECURE_STDIO !PICO_NONSECURE +#endif + +// ------------------------------ +// Initialise non-secure clocks +// ------------------------------ +// PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_NONSECURE_CLOCKS, Skip calling of `runtime_init_nonsecure_clocks` function during runtime init, type=bool, default=0, group=pico_runtime_init +#ifndef PICO_RUNTIME_INIT_NONSECURE_CLOCKS +#define PICO_RUNTIME_INIT_NONSECURE_CLOCKS "00500" +#endif + +#ifndef PICO_RUNTIME_SKIP_INIT_NONSECURE_CLOCKS +#define PICO_RUNTIME_SKIP_INIT_NONSECURE_CLOCKS !PICO_NONSECURE +#endif + +#ifndef PICO_RUNTIME_NO_INIT_NONSECURE_CLOCKS +#define PICO_RUNTIME_NO_INIT_NONSECURE_CLOCKS !PICO_NONSECURE +#endif + +// ------------------------------ +// Initialise non-secure coprocessors +// ------------------------------ +// PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_NONSECURE_COPROCESSORS, Skip calling of `runtime_init_nonsecure_coprocessors` function during runtime init, type=bool, default=0, group=pico_runtime_init +#ifndef PICO_RUNTIME_INIT_NONSECURE_COPROCESSORS +#define PICO_RUNTIME_INIT_NONSECURE_COPROCESSORS "00210" +#endif + +#ifndef PICO_RUNTIME_SKIP_INIT_NONSECURE_COPROCESSORS +#define PICO_RUNTIME_SKIP_INIT_NONSECURE_COPROCESSORS !PICO_SECURE +#endif + +#ifndef PICO_RUNTIME_NO_INIT_NONSECURE_COPROCESSORS +#define PICO_RUNTIME_NO_INIT_NONSECURE_COPROCESSORS !PICO_SECURE +#endif + +// ------------------------------ +// Initialise non-secure accessctrl +// ------------------------------ +// PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_NONSECURE_ACCESSCTRL_AND_IRQS, Skip calling of `runtime_init_nonsecure_accessctrl_and_irqs` function during runtime init, type=bool, default=0, group=pico_runtime_init +#ifndef PICO_RUNTIME_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +#define PICO_RUNTIME_INIT_NONSECURE_ACCESSCTRL_AND_IRQS "00220" +#endif + +#ifndef PICO_RUNTIME_SKIP_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +#define PICO_RUNTIME_SKIP_INIT_NONSECURE_ACCESSCTRL_AND_IRQS !PICO_SECURE +#endif + +#ifndef PICO_RUNTIME_NO_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +#define PICO_RUNTIME_NO_INIT_NONSECURE_ACCESSCTRL_AND_IRQS !PICO_SECURE +#endif + // PICO_RUNTIME_INIT_MUTEX is registered automatically by pico_sync // PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_MUTEX, Skip calling of `runtime_init_mutex` function during runtime init, type=bool, default=0, group=pico_runtime_init // PICO_CONFIG: PICO_RUNTIME_NO_INIT_MUTEX, Do not include SDK implementation of `runtime_init_mutex` function, type=bool, default=0, group=pico_runtime_init diff --git a/src/rp2_common/pico_secure/BUILD.bazel b/src/rp2_common/pico_secure/BUILD.bazel new file mode 100644 index 000000000..cba5ac3c8 --- /dev/null +++ b/src/rp2_common/pico_secure/BUILD.bazel @@ -0,0 +1,14 @@ +load("//bazel:defs.bzl", "compatible_with_rp2") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "pico_secure", + srcs = ["secure.c"], + hdrs = ["include/pico/secure.h"], + includes = ["include"], + target_compatible_with = compatible_with_rp2(), + deps = [ + "//src/rp2_common/pico_bootrom", + ], +) diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt new file mode 100644 index 000000000..d1f426d80 --- /dev/null +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -0,0 +1,160 @@ +if (NOT TARGET pico_secure) + pico_add_library(pico_secure) + target_include_directories(pico_secure_headers SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) + + target_sources(pico_secure INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/secure.c) + + pico_mirrored_target_link_libraries(pico_secure INTERFACE + hardware_exception + pico_bootrom) + + + # pico_set_security_options(SECURE_TARGET NONSECURE_TARGET ...) + # \brief_nodesc\ Set matching security options for a secure and non-secure target + # + # Set matching security options for a secure and non-secure target, so they have a compatible set of features. + # + # Also sets PICO_SECURE=1 and PICO_NONSECURE=1 on the secure and non-secure targets respectively, along with + # any other required defines (eg PICO_USE_STACK_GUARDS=1 on the secure target). + # + # The options are: + # - STDIO: Allow non-secure to use secure stdio + # - RAND: Allow non-secure to get random numbers + # - DMA: Allow non-secure to request DMA channels + # - USER_IRQ: Allow non-secure to request user IRQs + # - PIO: Allow non-secure to request PIOs + # - GPIO: Allow non-secure to access GPIOs assigned to non-secure (eg with gpio_assign_to_ns) + # - USB: Allow non-secure to access USB + # - RESETS: Allow non-secure to access resets specified by PICO_ALLOW_NONSECURE_RESETS_MASK (automatically set if USB is set) + # - NONSECURE_TIMER : Assign specified timer to non-secure + # + # \param\ SECURE_TARGET The secure target + # \param\ NONSECURE_TARGET The non-secure target + # \param\ OPTIONS The options to set + function(pico_set_security_options SECURE_TARGET NONSECURE_TARGET) + set(options STDIO RAND DMA USER_IRQ PIO GPIO USB RESETS) + set(oneValueArgs NONSECURE_TIMER) + cmake_parse_arguments(PARSE_ARGV 2 OPTS "${options}" "${oneValueArgs}" "") + + target_compile_definitions(${SECURE_TARGET} PRIVATE + PICO_SECURE=1 + + # Stack guards are required + PICO_USE_STACK_GUARDS=1 + ) + + target_compile_definitions(${NONSECURE_TARGET} PRIVATE + PICO_NONSECURE=1 + ) + + # Options that require resets + if ((NOT OPTS_RESETS) AND OPTS_USB) + set(OPTS_RESETS 1) + endif() + + foreach(arg IN LISTS options) + if (OPTS_${arg}) + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_ALLOW_NONSECURE_${arg}=1) + target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_ALLOW_NONSECURE_${arg}=1) + endif() + endforeach() + + if (OPTS_NONSECURE_TIMER) + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_ASSIGN_NONSECURE_TIMER=${OPTS_NONSECURE_TIMER}) + target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_DEFAULT_TIMER=${OPTS_NONSECURE_TIMER}) + endif() + endfunction() + + # pico_set_security_ram_split(SECURE_TARGET NONSECURE_TARGET ...) + # \brief_nodesc\ Set ram split for a secure and non-secure target + # + # Set ram split for a secure and non-secure target, so they don't use the same memory. + # + # Each split type option requires arguments to specify the memory sizes. You can only select + # one split type + # + # The split types available are: + # - SIMPLE : Secure using start of main SRAM, NonSecure using end of main SRAM and scratch + # - SCRATCH_EACH : Secure using start of main SRAM plus scratch X as stack, NonSecure using end of main SRAM plus scratch Y as stack + # - SECURE_SCRATCH : Secure using start of main SRAM plus all of scratch, NonSecure using end of main SRAM + # + # Additional options are: + # - NO_FLASH: Assumes NS VTOR is at start of it's SRAM region, rather than at the start of flash + # + # \param\ SECURE_TARGET The secure target + # \param\ NONSECURE_TARGET The non-secure target + # \param\ OPTIONS The options to set + function(pico_set_security_ram_split SECURE_TARGET NONSECURE_TARGET) + set(options NO_FLASH) + set(multiValueArgs SIMPLE SCRATCH_EACH SECURE_SCRATCH) + cmake_parse_arguments(PARSE_ARGV 2 OPTS "${options}" "" "${multiValueArgs}") + + set(HAS_SPLIT_TYPE FALSE) + foreach(arg IN LISTS multiValueArgs) + if (OPTS_${arg}) + if (HAS_SPLIT_TYPE) + message(FATAL_ERROR "Multiple split types passed to pico_set_security_ram_split") + endif() + set(HAS_SPLIT_TYPE TRUE) + endif() + endforeach() + + if (NOT HAS_SPLIT_TYPE) + message(FATAL_ERROR "No split type passed to pico_set_security_ram_split") + endif() + + if (OPTS_SIMPLE) + list(GET OPTS_SIMPLE 0 SECURE_LENGTH) + list(GET OPTS_SIMPLE 1 SECURE_SCRATCH_LENGTH) + + pico_set_linker_script_var(${SECURE_TARGET} RAM_ORIGIN "RAM_ORIGIN_DEFAULT") + pico_set_linker_script_var(${SECURE_TARGET} RAM_LENGTH "${SECURE_LENGTH}-(${SECURE_SCRATCH_LENGTH}*2)") + pico_set_linker_script_var(${SECURE_TARGET} SCRATCH_X_ORIGIN "RAM_ORIGIN+RAM_LENGTH") + pico_set_linker_script_var(${SECURE_TARGET} SCRATCH_X_LENGTH ${SECURE_SCRATCH_LENGTH}) + pico_set_linker_script_var(${SECURE_TARGET} SCRATCH_Y_ORIGIN "SCRATCH_X_ORIGIN+SCRATCH_X_LENGTH") + pico_set_linker_script_var(${SECURE_TARGET} SCRATCH_Y_LENGTH SCRATCH_X_LENGTH) + + pico_set_linker_script_var(${NONSECURE_TARGET} RAM_ORIGIN "RAM_ORIGIN_DEFAULT+${SECURE_LENGTH}") + pico_set_linker_script_var(${NONSECURE_TARGET} RAM_LENGTH "RAM_LENGTH_DEFAULT-${SECURE_LENGTH}") + + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_SIMPLE=1) + elseif(OPTS_SCRATCH_EACH) + list(GET OPTS_SCRATCH_EACH 0 SECURE_LENGTH) + + pico_set_linker_script_var(${SECURE_TARGET} RAM_ORIGIN "RAM_ORIGIN_DEFAULT") + pico_set_linker_script_var(${SECURE_TARGET} RAM_LENGTH "${SECURE_LENGTH}-SCRATCH_X_LENGTH_DEFAULT") + pico_set_linker_script_var(${SECURE_TARGET} SCRATCH_X_ORIGIN "RAM_ORIGIN+RAM_LENGTH") + pico_set_linker_script_var(${SECURE_TARGET} SCRATCH_Y_ORIGIN "SCRATCH_X_ORIGIN_DEFAULT") + + pico_set_linker_script_var(${NONSECURE_TARGET} RAM_ORIGIN "RAM_ORIGIN_DEFAULT+${SECURE_LENGTH}") + pico_set_linker_script_var(${NONSECURE_TARGET} RAM_LENGTH "RAM_LENGTH_DEFAULT-${SECURE_LENGTH}-SCRATCH_X_LENGTH_DEFAULT") + pico_set_linker_script_var(${NONSECURE_TARGET} SCRATCH_X_ORIGIN "RAM_ORIGIN+RAM_LENGTH") + + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_SCRATCH_EACH=1) + elseif(OPTS_SECURE_SCRATCH) + list(GET OPTS_SECURE_SCRATCH 0 SECURE_LENGTH) + list(GET OPTS_SECURE_SCRATCH 1 NONSECURE_SCRATCH_LENGTH) + + pico_set_linker_script_var(${SECURE_TARGET} RAM_LENGTH "${SECURE_LENGTH}") + + pico_set_linker_script_var(${NONSECURE_TARGET} RAM_ORIGIN "RAM_ORIGIN_DEFAULT+${SECURE_LENGTH}") + pico_set_linker_script_var(${NONSECURE_TARGET} RAM_LENGTH "RAM_LENGTH_DEFAULT-${SECURE_LENGTH}-(${NONSECURE_SCRATCH_LENGTH}*2)") + pico_set_linker_script_var(${NONSECURE_TARGET} SCRATCH_X_ORIGIN "RAM_ORIGIN+RAM_LENGTH") + pico_set_linker_script_var(${NONSECURE_TARGET} SCRATCH_X_LENGTH ${NONSECURE_SCRATCH_LENGTH}) + pico_set_linker_script_var(${NONSECURE_TARGET} SCRATCH_Y_ORIGIN "SCRATCH_X_ORIGIN+SCRATCH_X_LENGTH") + pico_set_linker_script_var(${NONSECURE_TARGET} SCRATCH_Y_LENGTH SCRATCH_X_LENGTH) + + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_SECURE_SCRATCH=1) + endif() + + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_CONFIGURED=1) + + if (OPTS_NO_FLASH) + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_NO_FLASH=1) + else() + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_NO_FLASH=0) + endif() + + endfunction() +endif() diff --git a/src/rp2_common/pico_secure/include/pico/secure.h b/src/rp2_common/pico_secure/include/pico/secure.h new file mode 100644 index 000000000..c5b9b2213 --- /dev/null +++ b/src/rp2_common/pico_secure/include/pico/secure.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _PICO_SECURE_H +#define _PICO_SECURE_H + +#include "pico.h" +#include "pico/bootrom.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \brief Launch non-secure binary + * \ingroup pico_secure + * + * \note The secure binary must have already set it's stack limits, using PICO_USE_STACK_GUARDS or similar + * + * \param vtor_address The vector table address of the non-secure binary + * \param stack_limit The stack limit of the non-secure binary + */ +void secure_launch_nonsecure_binary(uint32_t vtor_address, uint32_t stack_limit); + +/*! \brief Configure SAU region + * \ingroup pico_secure + * + * \param region The region to configure + * \param base The base address of the region + * \param limit The limit address of the region + * \param enabled Whether the region is enabled + * \param nsc Whether the region is non-secure callable + */ +void secure_sau_configure_region(uint region, uint32_t base, uint32_t limit, bool enabled, bool nsc); + +#if defined(PICO_SECURITY_SPLIT_CONFIGURED) +/*! \brief Configure default SAU regions + * \ingroup pico_secure + * + * Configures the default security split configuration, based on the split configured with pico_set_security_ram_split + */ +void secure_sau_configure_split(void); + + +/*! \brief Launch non-secure binary from default location + * \ingroup pico_secure + * + * Launches non-secure binary from the default location, based on the split configured with pico_set_security_ram_split + */ +void secure_launch_nonsecure_binary_default(void); +#endif + +/*! \brief Set SAU enabled + * \ingroup pico_secure + * + * Set SAU enabled, with appropriate memory barriers + * + * \param enabled Whether the SAU is enabled + */ +void secure_sau_set_enabled(bool enabled); + + +typedef void (*secure_hardfault_callback_t)(void); + +/*! \brief Install default hardfault handler + * \ingroup pico_secure + * + * \param callback The callback to call when a hardfault occurs after printing the information + */ +void secure_install_default_hardfault_handler(secure_hardfault_callback_t callback); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c new file mode 100644 index 000000000..836a3ce90 --- /dev/null +++ b/src/rp2_common/pico_secure/secure.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2025 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/secure.h" +#include "pico/runtime_init.h" + +#include "hardware/timer.h" +#include "hardware/irq.h" +#include "hardware/exception.h" + +#include "hardware/structs/scb.h" +#include "hardware/structs/sau.h" +#include "hardware/structs/m33.h" +#include "hardware/structs/accessctrl.h" + +void __attribute__((noreturn)) secure_launch_nonsecure_binary(uint32_t vtor_address, uint32_t stack_limit) { + uint32_t *vtor = (uint32_t*)vtor_address; + uint32_t stack_pointer = *(vtor + 0); + uint32_t entry_point = *(vtor + 1); + scb_ns_hw->vtor = vtor_address; + + pico_default_asm( + "msr msp_ns, %0\n" + "msr msplim_ns, %1\n" + "movs r1, %2\n" + "bxns r1" + : + : "r" (stack_pointer), + "r" (stack_limit), + "r" (entry_point & ~1) // make sure thumb bit is clear for blxns + ); + + __builtin_unreachable(); +} + + +void secure_sau_configure_region(uint region, uint32_t base, uint32_t limit, bool enabled, bool nsc) { + sau_hw->rnr = region; + sau_hw->rbar = base & M33_SAU_RBAR_BADDR_BITS; + sau_hw->rlar = ((limit-1) & M33_SAU_RLAR_LADDR_BITS) | (nsc ? M33_SAU_RLAR_NSC_BITS : 0) | (enabled ? M33_SAU_RLAR_ENABLE_BITS : 0); +} + + +void secure_sau_set_enabled(bool enabled) { + uint32_t save = save_and_disable_interrupts(); + __dmb(); + + if (enabled) + sau_hw->ctrl |= M33_SAU_CTRL_ENABLE_BITS; + else + sau_hw->ctrl &= ~M33_SAU_CTRL_ENABLE_BITS; + + __dsb(); + __isb(); + restore_interrupts_from_disabled(save); +} + + +#if defined(PICO_SECURITY_SPLIT_CONFIGURED) +static uint32_t nonsecure_ram_start = 0; + +void secure_sau_configure_split() { +#if !PICO_SECURITY_SPLIT_NO_FLASH + // XIP is NS Code + secure_sau_configure_region(0, XIP_BASE, XIP_END, true, false); +#endif + +#if defined(PICO_SECURITY_SPLIT_SIMPLE) + // SRAM after secure stack is NS data + extern uint32_t __StackTop; + secure_sau_configure_region(1, (uint32_t)&__StackTop, SRAM_END, true, false); + nonsecure_ram_start = (uint32_t)&__StackTop; +#elif defined(PICO_SECURITY_SPLIT_SCRATCH_EACH) + // Main SRAM after secure scratch X is NS data + extern uint32_t __StackOneTop; + secure_sau_configure_region(1, (uint32_t)&__StackOneTop, SRAM_STRIPED_END, true, false); + nonsecure_ram_start = (uint32_t)&__StackOneTop; + // Scratch after secure stack in NS stack + extern uint32_t __StackTop; + secure_sau_configure_region(2, (uint32_t)&__StackTop, SRAM_END, true, false); +#elif defined(PICO_SECURITY_SPLIT_SECURE_SCRATCH) + // Main SRAM after secure heap is NS data + extern uint32_t __HeapLimit; + secure_sau_configure_region(1, (uint32_t)&__HeapLimit, SRAM_STRIPED_END, true, false); + nonsecure_ram_start = (uint32_t)&__HeapLimit; +#endif +} + + +void __attribute__((noreturn)) secure_launch_nonsecure_binary_default() { +#if PICO_SECURITY_SPLIT_NO_FLASH + uint32_t nonsecure_vtor = nonsecure_ram_start; +#else + uint32_t nonsecure_vtor = XIP_BASE; +#endif + +#if defined(PICO_SECURITY_SPLIT_SIMPLE) + // Nonsecure running from XIP, stack limit is bottom of scratch + secure_launch_nonsecure_binary(nonsecure_vtor, SRAM_SCRATCH_X_BASE); +#elif defined(PICO_SECURITY_SPLIT_SCRATCH_EACH) + // Nonsecure running from XIP, stack limit is bottom of scratch Y + secure_launch_nonsecure_binary(nonsecure_vtor, SRAM_SCRATCH_Y_BASE); +#elif defined(PICO_SECURITY_SPLIT_SECURE_SCRATCH) + // Nonsecure running from XIP, stack limit is secure heap limit + extern uint32_t __HeapLimit; + secure_launch_nonsecure_binary(nonsecure_vtor, (uint32_t)&__HeapLimit); +#endif +} +#endif + + +static secure_hardfault_callback_t hardfault_callback = NULL; + + +static void secure_hardfault_handler(void) { + printf("Hard fault occurred\n"); + + // # First eight values on stack will always be: + // # r0, r1, r2, r3, r12, LR, pc, xPSR + + uint32_t sp; + pico_default_asm_volatile( + "mrs %0, msp_ns" + : "=r" (sp) + ); + + printf("sp: %08x\n", sp); + printf("r0: %08x\n", *((uint32_t*)sp + 0)); + printf("r1: %08x\n", *((uint32_t*)sp + 1)); + printf("r2: %08x\n", *((uint32_t*)sp + 2)); + printf("r3: %08x\n", *((uint32_t*)sp + 3)); + printf("r12: %08x\n", *((uint32_t*)sp + 4)); + printf("lr: %08x\n", *((uint32_t*)sp + 5)); + printf("pc: %08x\n", *((uint32_t*)sp + 6)); + printf("xPSR: %08x\n", *((uint32_t*)sp + 7)); + + if (scb_hw->hfsr & M33_HFSR_DEBUGEVT_BITS) printf("HardFault: Debug Event\n"); + if (scb_hw->hfsr & M33_HFSR_FORCED_BITS) printf("HardFault: Forced\n"); + if (scb_hw->hfsr & M33_HFSR_VECTTBL_BITS) printf("HardFault: Vector Table Read Error\n"); + + if (m33_hw->sfsr & M33_SFSR_LSERR_BITS) printf("SecureFault: Error occurred during lazy state activation/deactivation\n"); + if (m33_hw->sfsr & M33_SFSR_LSPERR_BITS) printf("SecureFault: Error occurred during lazy preservation of floating-point state\n"); + if (m33_hw->sfsr & M33_SFSR_INVTRAN_BITS) printf("SecureFault: Secure branched to Non-secure code\n"); + if (m33_hw->sfsr & M33_SFSR_AUVIOL_BITS) printf("SecureFault: Non-secure accessed Secure memory\n"); + if (m33_hw->sfsr & M33_SFSR_INVER_BITS) printf("SecureFault: Invalid Non-secure exception state when returning\n"); + if (m33_hw->sfsr & M33_SFSR_INVIS_BITS) printf("SecureFault: Invalid integrity signature in exception stack\n"); + if (m33_hw->sfsr & M33_SFSR_INVEP_BITS) printf("SecureFault: Non-secure branched to Secure code\n"); + if (m33_hw->sfsr & M33_SFSR_SFARVALID_BITS) printf("SecureFault address: %08x\n", m33_hw->sfar); + + if (scb_hw->cfsr & M33_CFSR_UFSR_DIVBYZERO_BITS) printf("UsageFault: Division by zero\n"); + if (scb_hw->cfsr & M33_CFSR_UFSR_UNALIGNED_BITS) printf("UsageFault: Unaligned access\n"); + if (scb_hw->cfsr & M33_CFSR_UFSR_STKOF_BITS) printf("UsageFault: Stack overflow\n"); + if (scb_hw->cfsr & M33_CFSR_UFSR_NOCP_BITS) printf("UsageFault: No Coprocessor\n"); + if (scb_hw->cfsr & M33_CFSR_UFSR_INVPC_BITS) printf("UsageFault: Invalid PC\n"); + if (scb_hw->cfsr & M33_CFSR_UFSR_INVSTATE_BITS) printf("UsageFault: Invalid state\n"); + if (scb_hw->cfsr & M33_CFSR_UFSR_UNDEFINSTR_BITS) printf("UsageFault: Undefined instruction\n"); + + if (scb_hw->cfsr & M33_CFSR_BFSR_LSPERR_BITS) printf("BusFault: Error occurred during lazy preservation of floating-point state\n"); + if (scb_hw->cfsr & M33_CFSR_BFSR_STKERR_BITS) printf("BusFault: Error occurred during exception entry stacking\n"); + if (scb_hw->cfsr & M33_CFSR_BFSR_UNSTKERR_BITS) printf("BusFault: Error occurred during exception return unstacking\n"); + if (scb_hw->cfsr & M33_CFSR_BFSR_IMPRECISERR_BITS) printf("BusFault: Imprecise data access error\n"); + if (scb_hw->cfsr & M33_CFSR_BFSR_PRECISERR_BITS) printf("BusFault: Precise data access error\n"); + if (scb_hw->cfsr & M33_CFSR_BFSR_IBUSERR_BITS) printf("BusFault: Bus fault on instruction prefetch\n"); + if (scb_hw->cfsr & M33_CFSR_BFSR_BFARVALID_BITS) printf("BusFault address: %08x\n", scb_hw->bfar); + + if (scb_hw->cfsr & M33_CFSR_MMFSR_BITS) printf("MemManageFault: %02x\n", scb_hw->cfsr & M33_CFSR_MMFSR_BITS); + if (scb_hw->cfsr & 0x80) printf("MemManageFault address: %08x\n", scb_hw->mmfar); + + if (hardfault_callback) { + hardfault_callback(); + } +} + + +void secure_install_default_hardfault_handler(secure_hardfault_callback_t callback) { + hardfault_callback = callback; + exception_set_exclusive_handler(HARDFAULT_EXCEPTION, secure_hardfault_handler); +} + + +#if !PICO_RUNTIME_NO_INIT_NONSECURE_COPROCESSORS +void __weak runtime_init_nonsecure_coprocessors() { + // Enable NS coprocessor access to anything secure has enabled + uint32_t cpacr = arm_cpu_hw->cpacr; + uint32_t nsacr = 0; + for (int i = 0; i < 16; i++) { + if (cpacr & (M33_CPACR_CP0_BITS << (i * M33_CPACR_CP1_LSB))) { + nsacr |= (0x1 << i); + } + } + arm_cpu_hw->nsacr |= nsacr; +} +#endif + +#if !PICO_RUNTIME_SKIP_INIT_NONSECURE_COPROCESSORS +PICO_RUNTIME_INIT_FUNC_PER_CORE(runtime_init_nonsecure_coprocessors, PICO_RUNTIME_INIT_NONSECURE_COPROCESSORS); +#endif + + +#if !PICO_RUNTIME_NO_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +void __weak runtime_init_nonsecure_accessctrl_and_irqs() { + rom_set_ns_api_permission(BOOTROM_NS_API_get_sys_info, true); + + #if PICO_ALLOW_NONSECURE_DMA + accessctrl_hw->dma |= 0xacce0000 | ACCESSCTRL_DMA_NSP_BITS | ACCESSCTRL_DMA_NSU_BITS; + #endif + + #ifdef PICO_ASSIGN_NONSECURE_TIMER + accessctrl_hw->timer[PICO_ASSIGN_NONSECURE_TIMER] |= 0xacce0000 | ACCESSCTRL_TIMER0_NSP_BITS | ACCESSCTRL_TIMER0_NSU_BITS; + + static_assert(TIMER0_IRQ_0 + 4 == TIMER1_IRQ_0, "Expected 4 IRQs per TIMER"); + + irq_assign_to_ns(TIMER0_IRQ_0 + PICO_ASSIGN_NONSECURE_TIMER * 4, true); + irq_assign_to_ns(TIMER0_IRQ_1 + PICO_ASSIGN_NONSECURE_TIMER * 4, true); + irq_assign_to_ns(TIMER0_IRQ_2 + PICO_ASSIGN_NONSECURE_TIMER * 4, true); + irq_assign_to_ns(TIMER0_IRQ_3 + PICO_ASSIGN_NONSECURE_TIMER * 4, true); + #endif + + #if PICO_ALLOW_NONSECURE_GPIO + accessctrl_hw->io_bank[0] |= 0xacce0000 | ACCESSCTRL_IO_BANK0_NSP_BITS | ACCESSCTRL_IO_BANK0_NSU_BITS; + + irq_assign_to_ns(IO_IRQ_BANK0_NS, true); + #endif + + #if PICO_ALLOW_NONSECURE_USB + accessctrl_hw->usbctrl |= 0xacce0000 | ACCESSCTRL_USBCTRL_NSP_BITS | ACCESSCTRL_USBCTRL_NSU_BITS; + + irq_assign_to_ns(USBCTRL_IRQ, true); + #endif +} +#endif + +#if !PICO_RUNTIME_SKIP_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +PICO_RUNTIME_INIT_FUNC_HW(runtime_init_nonsecure_accessctrl_and_irqs, PICO_RUNTIME_INIT_NONSECURE_ACCESSCTRL_AND_IRQS); +#endif diff --git a/src/rp2_common/pico_standard_link/CMakeLists.txt b/src/rp2_common/pico_standard_link/CMakeLists.txt index c16968bba..69f5751ef 100644 --- a/src/rp2_common/pico_standard_link/CMakeLists.txt +++ b/src/rp2_common/pico_standard_link/CMakeLists.txt @@ -70,6 +70,15 @@ if (NOT TARGET pico_standard_link) set_target_properties(${TARGET} PROPERTIES PICO_TARGET_LINKER_SCRIPT ${LDSCRIPT}) endfunction() + # pico_set_linker_script_var(TARGET NAME VALUE) + # \brief\ Set the linker script for the target + # + # \param\ NAME Name of varAible to set + # \param\ VALUE Value of variable to set + function(pico_set_linker_script_var TARGET NAME VALUE) + set_property(TARGET ${TARGET} APPEND PROPERTY PICO_TARGET_LINKER_SCRIPT_VARS "--defsym=${NAME}=${VALUE}") + endfunction() + # pico_set_binary_type(TARGET TYPE) # \brief\ Set the binary type for the target # @@ -124,9 +133,19 @@ if (NOT TARGET pico_standard_link) #math(EXPR PICO_FLASH_SIZE_BYTES_STRING "${PICO_FLASH_SIZE_BYTES}" OUTPUT_FORMAT HEXADECIMAL) set(PICO_FLASH_SIZE_BYTES_STRING "${PICO_FLASH_SIZE_BYTES}") configure_file(${CMAKE_CURRENT_LIST_DIR}/pico_flash_region.template.ld ${CMAKE_BINARY_DIR}/pico_flash_region.ld) - # add include path for linker scripts + # add include path for linker scripts to find it target_link_options(pico_standard_link INTERFACE "LINKER:-L${CMAKE_BINARY_DIR}") + # add include path for main linker script sections + target_link_options(pico_standard_link INTERFACE "LINKER:-L${PICO_LINKER_SCRIPT_PATH}") + target_link_options(pico_standard_link INTERFACE "LINKER:-L${CMAKE_CURRENT_LIST_DIR}/scripts") + + # add default locations script, so they can be referenced by pico_set_linker_script_var variables + target_link_options(pico_standard_link INTERFACE "LINKER:--script=${PICO_LINKER_SCRIPT_PATH}/platform/default_locations.ld") + + # add variables set by pico_set_linker_script_var function + target_link_options(pico_standard_link INTERFACE "LINKER:$,,>") + # LINKER script will be PICO_TARGET_LINKER_SCRIPT if set on target, or ${CMAKE_CURRENT_LIST_DIR}/memmap_foo.ld # if PICO_TARGET_BINARY_TYPE is set to foo on the target, otherwise ${CMAKE_CURRENT_LIST_DIR}/memmap_${PICO_DEFAULT_BINARY_TYPE).ld set(_LINKER_SCRIPT_EXPRESSION "$>,$,${PICO_LINKER_SCRIPT_PATH}/memmap_$,>,${PICO_DEFAULT_BINARY_TYPE},$>.ld>") diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld new file mode 100644 index 000000000..1cb8f7597 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld @@ -0,0 +1,16 @@ +/* Include platform memory locations */ +INCLUDE "rp2_common/set_memory_locations.ld" + +/* Include memory regions used */ +INCLUDE "rp2_common/memory_flash.ld" +INCLUDE "rp2_common/memory_ram.ld" +INCLUDE "rp2_common/memory_scratch.ld" + +/* Include aliases for storage memory regions */ +INCLUDE "rp2_common/memory_aliases_default.ld" + +/* Define entry point symbol */ +ENTRY(_entry_point) + +/* Include default sections */ +INCLUDE "rp2_common/sections_copy_to_ram.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld new file mode 100644 index 000000000..2c8f3ffa1 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld @@ -0,0 +1,16 @@ +/* Include platform memory locations */ +INCLUDE "rp2_common/set_memory_locations.ld" + +/* Include memory regions used */ +INCLUDE "rp2_common/memory_flash.ld" +INCLUDE "rp2_common/memory_ram.ld" +INCLUDE "rp2_common/memory_scratch.ld" + +/* Include aliases for storage memory regions */ +INCLUDE "rp2_common/memory_aliases_default.ld" + +/* Define entry point symbol */ +ENTRY(_entry_point) + +/* Include default sections */ +INCLUDE "rp2_common/sections_default.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld new file mode 100644 index 000000000..2e3695ef9 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld @@ -0,0 +1,15 @@ +/* Include platform memory locations */ +INCLUDE "rp2_common/set_memory_locations.ld" + +/* Include memory regions used */ +INCLUDE "rp2_common/memory_ram.ld" +INCLUDE "rp2_common/memory_scratch.ld" + +/* Include aliases for no_flash storage memory regions (alias to themselves) */ +INCLUDE "rp2_common/memory_aliases_no_flash.ld" + +/* Define entry point symbol */ +ENTRY(_entry_point) + +/* Include no_flash sections */ +INCLUDE "rp2_common/sections_no_flash.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_default.ld new file mode 100644 index 000000000..7c56254bd --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_default.ld @@ -0,0 +1,3 @@ +REGION_ALIAS("RAM_STORE", FLASH); +REGION_ALIAS("SCRATCH_X_STORE", FLASH); +REGION_ALIAS("SCRATCH_Y_STORE", FLASH); diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_no_flash.ld new file mode 100644 index 000000000..063b5b6fc --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_no_flash.ld @@ -0,0 +1,3 @@ +REGION_ALIAS("RAM_STORE", RAM); +REGION_ALIAS("SCRATCH_X_STORE", SCRATCH_X); +REGION_ALIAS("SCRATCH_Y_STORE", SCRATCH_Y); diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_flash.ld new file mode 100644 index 000000000..669fe00e3 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_flash.ld @@ -0,0 +1,4 @@ +MEMORY +{ + INCLUDE "pico_flash_region.ld" +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_ram.ld new file mode 100644 index 000000000..2b8a88a06 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + RAM(rwx) : ORIGIN = RAM_ORIGIN, LENGTH = RAM_LENGTH +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_scratch.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_scratch.ld new file mode 100644 index 000000000..7ba5d2172 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_scratch.ld @@ -0,0 +1,5 @@ +MEMORY +{ + SCRATCH_X(rwx) : ORIGIN = SCRATCH_X_ORIGIN, LENGTH = SCRATCH_X_LENGTH + SCRATCH_Y(rwx) : ORIGIN = SCRATCH_Y_ORIGIN, LENGTH = SCRATCH_Y_LENGTH +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_xip_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_xip_ram.ld new file mode 100644 index 000000000..636e90137 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_xip_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + XIP_RAM(rwx) : ORIGIN = XIP_RAM_ORIGIN, LENGTH = XIP_RAM_LENGTH +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_copy_to_ram_data.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_copy_to_ram_data.ld new file mode 100644 index 000000000..19082589c --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_copy_to_ram_data.ld @@ -0,0 +1,83 @@ +SECTIONS +{ + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + . = ALIGN(4); + *(.rodata*) + *(.srodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_default_data.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_default_data.ld new file mode 100644 index 000000000..9ffa5d163 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_default_data.ld @@ -0,0 +1,72 @@ +SECTIONS +{ + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_end.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_end.ld new file mode 100644 index 000000000..53d328174 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_end.ld @@ -0,0 +1,49 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +SECTIONS +{ + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + /* todo assert on extra code */ +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_flash_end.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_flash_end.ld new file mode 100644 index 000000000..8591406ff --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_flash_end.ld @@ -0,0 +1,7 @@ +SECTIONS +{ + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_heap.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_heap.ld new file mode 100644 index 000000000..1cc9e0de1 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_heap.ld @@ -0,0 +1,12 @@ +SECTIONS +{ + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + } > RAM + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_no_flash_data.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_no_flash_data.ld new file mode 100644 index 000000000..5658d8a4b --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_no_flash_data.ld @@ -0,0 +1,82 @@ +SECTIONS +{ + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM + PROVIDE(__data_end__ = .); + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_scratch.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_scratch.ld new file mode 100644 index 000000000..f61c39639 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_scratch.ld @@ -0,0 +1,37 @@ +SECTIONS +{ + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT> SCRATCH_X_STORE + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT> SCRATCH_Y_STORE + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld new file mode 100644 index 000000000..5e86d7c0c --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld @@ -0,0 +1,7 @@ +INCLUDE "platform/section_copy_to_ram_text.ld" +INCLUDE "rp2_common/section_copy_to_ram_data.ld" +INCLUDE "rp2_common/section_heap.ld" +INCLUDE "rp2_common/section_scratch.ld" +INCLUDE "rp2_common/section_flash_end.ld" +INCLUDE "rp2_common/section_end.ld" +INCLUDE "platform/section_platform_end.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld new file mode 100644 index 000000000..558ec1848 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld @@ -0,0 +1,7 @@ +INCLUDE "platform/section_default_text.ld" +INCLUDE "rp2_common/section_default_data.ld" +INCLUDE "rp2_common/section_heap.ld" +INCLUDE "rp2_common/section_scratch.ld" +INCLUDE "rp2_common/section_flash_end.ld" +INCLUDE "rp2_common/section_end.ld" +INCLUDE "platform/section_platform_end.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld new file mode 100644 index 000000000..b9b3973b2 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld @@ -0,0 +1,6 @@ +INCLUDE "platform/section_no_flash_text.ld" +INCLUDE "rp2_common/section_no_flash_data.ld" +INCLUDE "rp2_common/section_heap.ld" +INCLUDE "rp2_common/section_scratch.ld" +INCLUDE "rp2_common/section_end.ld" +INCLUDE "platform/section_platform_end.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/set_memory_locations.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/set_memory_locations.ld new file mode 100644 index 000000000..a9110eb59 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/set_memory_locations.ld @@ -0,0 +1,8 @@ +RAM_ORIGIN = DEFINED(RAM_ORIGIN) ? RAM_ORIGIN : RAM_ORIGIN_DEFAULT; +RAM_LENGTH = DEFINED(RAM_LENGTH) ? RAM_LENGTH : RAM_LENGTH_DEFAULT; +SCRATCH_X_ORIGIN = DEFINED(SCRATCH_X_ORIGIN) ? SCRATCH_X_ORIGIN : SCRATCH_X_ORIGIN_DEFAULT; +SCRATCH_X_LENGTH = DEFINED(SCRATCH_X_LENGTH) ? SCRATCH_X_LENGTH : SCRATCH_X_LENGTH_DEFAULT; +SCRATCH_Y_ORIGIN = DEFINED(SCRATCH_Y_ORIGIN) ? SCRATCH_Y_ORIGIN : SCRATCH_Y_ORIGIN_DEFAULT; +SCRATCH_Y_LENGTH = DEFINED(SCRATCH_Y_LENGTH) ? SCRATCH_Y_LENGTH : SCRATCH_Y_LENGTH_DEFAULT; +XIP_RAM_ORIGIN = DEFINED(XIP_RAM_ORIGIN) ? XIP_RAM_ORIGIN : XIP_RAM_ORIGIN_DEFAULT; +XIP_RAM_LENGTH = DEFINED(XIP_RAM_LENGTH) ? XIP_RAM_LENGTH : XIP_RAM_LENGTH_DEFAULT; diff --git a/src/rp2_common/pico_stdio_uart/stdio_uart.c b/src/rp2_common/pico_stdio_uart/stdio_uart.c index 2e2619c11..0c69dbe2d 100644 --- a/src/rp2_common/pico_stdio_uart/stdio_uart.c +++ b/src/rp2_common/pico_stdio_uart/stdio_uart.c @@ -130,8 +130,8 @@ void stdio_uart_deinit_full(struct uart_inst *uart, int tx_pin, int rx_pin) { uart_deinit(uart_instance); #if HAS_PADS_BANK0_ISOLATION // Leave pads isolated - if (tx_pin >= 0) hw_set_bits(&pads_bank0_hw->io[tx_pin], PADS_BANK0_GPIO0_ISO_BITS); - if (rx_pin >= 0) hw_set_bits(&pads_bank0_hw->io[rx_pin], PADS_BANK0_GPIO0_ISO_BITS); + if (tx_pin >= 0) pads_bank0_set_bits(tx_pin, PADS_BANK0_GPIO0_ISO_BITS); + if (rx_pin >= 0) pads_bank0_set_bits(rx_pin, PADS_BANK0_GPIO0_ISO_BITS); #else ((void)tx_pin); ((void)rx_pin); diff --git a/test/kitchen_sink/CMakeLists.txt b/test/kitchen_sink/CMakeLists.txt index 1d6110f4c..33e5fbc24 100644 --- a/test/kitchen_sink/CMakeLists.txt +++ b/test/kitchen_sink/CMakeLists.txt @@ -214,6 +214,15 @@ if (NOT KITCHEN_SINK_NO_BINARY_TYPE_VARIANTS) pico_add_extra_outputs(kitchen_sink_blocked_ram) target_compile_definitions(kitchen_sink_blocked_ram PRIVATE KITCHEN_SINK_ID="blocked-ram binary") endif() + + add_executable(kitchen_sink_ram_custom ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink.c) + # Have ram start from 0x20020000 length 128k, and heap start from 0x20030000 + pico_set_linker_script_var(kitchen_sink_ram_custom RAM_ORIGIN 0x20020000) + pico_set_linker_script_var(kitchen_sink_ram_custom RAM_LENGTH 128k) + pico_set_linker_script_var(kitchen_sink_ram_custom HEAP_LOC 0x20030000) + target_link_libraries(kitchen_sink_ram_custom kitchen_sink_libs kitchen_sink_options) + pico_add_extra_outputs(kitchen_sink_ram_custom) + target_compile_definitions(kitchen_sink_ram_custom PRIVATE KITCHEN_SINK_ID="custom ram binary") endif() add_executable(kitchen_sink_cpp ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink_cpp.cpp) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5a6795ef2..2b06cbb69 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -742,3 +742,40 @@ function(picotool_postprocess_binary TARGET) endif() endif() endfunction() + + +# pico_concatenate_uf2_outputs(COMBINED_TARGET ...) +# \brief_nodesc\ Concatenate UF2 outputs into a single UF2 file +# +# Concatenate UF2 outputs from multiple targets into a single UF2 file, in the order they're passed to the function +# +# This can be used in conjunction with a partition table with no_reboot_on_uf2_download set on some partitions, +# to allow loading multiple partitions with a single UF2 file. For example, with this partition table you could concatenate +# rp2350-arm-ns and rp2350-arm-s binaries into a single UF2 file for loading into the main and owned partitions in one shot: +# ``` +# partitions: +# 0(A) uf2 { 'rp2350-arm-s' } +# 1(B w/ 0) uf2 { 'rp2350-arm-s' } +# 2(A ob/ 0) uf2 { 'rp2350-arm-ns' }, no_reboot_on_uf2_download, ab_non_bootable_owner_affinity +# 3(B w/ 2) uf2 { 'rp2350-arm-ns' }, no_reboot_on_uf2_download, ab_non_bootable_owner_affinity +# ``` +# +# NOTE: This does not modify the UF2 data structures, so the chip will still see multiple UF2 files, +# this just concatenates them into a single file on the host. +# +# \param\ COMBINED_TARGET The name of the combined UF2 target +# \param\ TARGETS The targets to combine +function(pico_concatenate_uf2_outputs COMBINED_TARGET) + list(TRANSFORM ARGN PREPEND ${CMAKE_CURRENT_BINARY_DIR}/ OUTPUT_VARIABLE UF2S) + list(TRANSFORM UF2S APPEND .uf2) + + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_TARGET}.uf2 + COMMAND ${CMAKE_COMMAND} -E cat + ${UF2S} + > ${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_TARGET}.uf2 + DEPENDS ${ARGN} + COMMAND_EXPAND_LISTS) + + add_custom_target(${COMBINED_TARGET} ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_TARGET}.uf2) +endfunction() \ No newline at end of file