mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2025-12-10 07:14:36 +01:00
Merge 2c4e1f62f3 into a76f2416ba
This commit is contained in:
commit
295a377cef
61 changed files with 2606 additions and 2017 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,2 +1,6 @@
|
|||
pico_simple_hardware_target(gpio)
|
||||
pico_mirrored_target_link_libraries(hardware_gpio INTERFACE hardware_irq)
|
||||
pico_mirrored_target_link_libraries(hardware_gpio INTERFACE hardware_irq)
|
||||
|
||||
if (PICO_RP2350)
|
||||
pico_mirrored_target_link_libraries(hardware_gpio INTERFACE pico_bootrom)
|
||||
endif()
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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[]
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
target_link_libraries(pico_bootrom INTERFACE boot_picobin_headers pico_runtime_init_headers)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
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 <stdio.h>
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#include <string.h>
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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) | \
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
109
src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld
Normal file
109
src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
121
src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld
Normal file
121
src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
14
src/rp2_common/pico_secure/BUILD.bazel
Normal file
14
src/rp2_common/pico_secure/BUILD.bazel
Normal file
|
|
@ -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",
|
||||
],
|
||||
)
|
||||
160
src/rp2_common/pico_secure/CMakeLists.txt
Normal file
160
src/rp2_common/pico_secure/CMakeLists.txt
Normal file
|
|
@ -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 <OPTIONS>...)
|
||||
# \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 <index>: 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 <OPTIONS>...)
|
||||
# \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_LENGTH> <SECURE_SCRATCH_LENGTH>: Secure using start of main SRAM, NonSecure using end of main SRAM and scratch
|
||||
# - SCRATCH_EACH <SECURE_LENGTH>: 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_LENGTH> <NONSECURE_SCRATCH_LENGTH>: 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()
|
||||
79
src/rp2_common/pico_secure/include/pico/secure.h
Normal file
79
src/rp2_common/pico_secure/include/pico/secure.h
Normal file
|
|
@ -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
|
||||
239
src/rp2_common/pico_secure/secure.c
Normal file
239
src/rp2_common/pico_secure/secure.c
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#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
|
||||
|
|
@ -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:$<JOIN:$<TARGET_PROPERTY:PICO_TARGET_LINKER_SCRIPT_VARS>,,>")
|
||||
|
||||
# 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 "$<IF:$<BOOL:$<TARGET_PROPERTY:PICO_TARGET_LINKER_SCRIPT>>,$<TARGET_PROPERTY:PICO_TARGET_LINKER_SCRIPT>,${PICO_LINKER_SCRIPT_PATH}/memmap_$<IF:$<STREQUAL:$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>,>,${PICO_DEFAULT_BINARY_TYPE},$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>>.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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
REGION_ALIAS("RAM_STORE", FLASH);
|
||||
REGION_ALIAS("SCRATCH_X_STORE", FLASH);
|
||||
REGION_ALIAS("SCRATCH_Y_STORE", FLASH);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
REGION_ALIAS("RAM_STORE", RAM);
|
||||
REGION_ALIAS("SCRATCH_X_STORE", SCRATCH_X);
|
||||
REGION_ALIAS("SCRATCH_Y_STORE", SCRATCH_Y);
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
MEMORY
|
||||
{
|
||||
INCLUDE "pico_flash_region.ld"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
MEMORY
|
||||
{
|
||||
RAM(rwx) : ORIGIN = RAM_ORIGIN, LENGTH = RAM_LENGTH
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
MEMORY
|
||||
{
|
||||
XIP_RAM(rwx) : ORIGIN = XIP_RAM_ORIGIN, LENGTH = XIP_RAM_LENGTH
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
SECTIONS
|
||||
{
|
||||
.flash_end : {
|
||||
KEEP(*(.embedded_end_block*))
|
||||
PROVIDE(__flash_binary_end = .);
|
||||
} > FLASH =0xaa
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -742,3 +742,40 @@ function(picotool_postprocess_binary TARGET)
|
|||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
# pico_concatenate_uf2_outputs(COMBINED_TARGET <TARGETS>...)
|
||||
# \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()
|
||||
Loading…
Add table
Reference in a new issue