From b9c20d4ab8dcad25a3b028596e78300c0e6c264c Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Mon, 1 Dec 2025 19:32:27 +0000 Subject: [PATCH 01/27] Separate linker scripts out into include files Allows for much simpler custom linker scripts --- .../pico_crt0/rp2040/memmap_blocked_ram.ld | 287 +--------------- .../pico_crt0/rp2040/memmap_copy_to_ram.ld | 288 +--------------- .../pico_crt0/rp2040/memmap_default.ld | 287 +--------------- .../pico_crt0/rp2040/memmap_no_flash.ld | 249 +------------- .../pico_crt0/rp2040/memory_blocked_ram.ld | 4 + .../pico_crt0/rp2040/memory_flash.ld | 4 + src/rp2_common/pico_crt0/rp2040/memory_ram.ld | 4 + .../pico_crt0/rp2040/memory_scratch.ld | 5 + .../pico_crt0/rp2040/sections_copy_to_ram.ld | 276 ++++++++++++++++ .../pico_crt0/rp2040/sections_default.ld | 275 ++++++++++++++++ .../pico_crt0/rp2040/sections_no_flash.ld | 239 ++++++++++++++ .../pico_crt0/rp2350/memmap_copy_to_ram.ld | 310 +----------------- .../pico_crt0/rp2350/memmap_default.ld | 303 +---------------- .../pico_crt0/rp2350/memmap_no_flash.ld | 256 +-------------- .../pico_crt0/rp2350/memory_copy_to_ram.ld | 0 .../pico_crt0/rp2350/memory_flash.ld | 4 + src/rp2_common/pico_crt0/rp2350/memory_ram.ld | 4 + .../pico_crt0/rp2350/memory_scratch.ld | 5 + .../pico_crt0/rp2350/memory_xip_ram.ld | 4 + .../pico_crt0/rp2350/sections_copy_to_ram.ld | 298 +++++++++++++++++ .../pico_crt0/rp2350/sections_default.ld | 291 ++++++++++++++++ .../pico_crt0/rp2350/sections_no_flash.ld | 246 ++++++++++++++ .../pico_standard_link/CMakeLists.txt | 5 +- 23 files changed, 1689 insertions(+), 1955 deletions(-) create mode 100644 src/rp2_common/pico_crt0/rp2040/memory_blocked_ram.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/memory_flash.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/memory_ram.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/memory_scratch.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/sections_default.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/memory_copy_to_ram.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/memory_flash.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/memory_ram.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/memory_scratch.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/memory_xip_ram.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/sections_default.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld index 6f5000566..150176eba 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld @@ -1,286 +1,7 @@ -/* 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 -} +INCLUDE "memory_flash.ld" +INCLUDE "memory_blocked_ram.ld" +INCLUDE "memory_scratch.ld" 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 "sections_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld index 842ebfd3c..7b99a7745 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld @@ -1,287 +1,7 @@ -/* 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 -} +INCLUDE "memory_flash.ld" +INCLUDE "memory_ram.ld" +INCLUDE "memory_scratch.ld" 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 "sections_copy_to_ram.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld index 51254012d..75fd340d5 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld @@ -1,286 +1,7 @@ -/* 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 -} +INCLUDE "memory_flash.ld" +INCLUDE "memory_ram.ld" +INCLUDE "memory_scratch.ld" 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 "sections_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld b/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld index dbf006a8c..cde630592 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld @@ -1,249 +1,6 @@ -/* 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 -} +INCLUDE "memory_ram.ld" +INCLUDE "memory_scratch.ld" 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 "sections_no_flash.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memory_blocked_ram.ld b/src/rp2_common/pico_crt0/rp2040/memory_blocked_ram.ld new file mode 100644 index 000000000..57cbad6b7 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/memory_blocked_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + RAM(rwx) : ORIGIN = 0x21000000, LENGTH = 256k +} diff --git a/src/rp2_common/pico_crt0/rp2040/memory_flash.ld b/src/rp2_common/pico_crt0/rp2040/memory_flash.ld new file mode 100644 index 000000000..669fe00e3 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/memory_flash.ld @@ -0,0 +1,4 @@ +MEMORY +{ + INCLUDE "pico_flash_region.ld" +} diff --git a/src/rp2_common/pico_crt0/rp2040/memory_ram.ld b/src/rp2_common/pico_crt0/rp2040/memory_ram.ld new file mode 100644 index 000000000..1e1515dd3 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/memory_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k +} diff --git a/src/rp2_common/pico_crt0/rp2040/memory_scratch.ld b/src/rp2_common/pico_crt0/rp2040/memory_scratch.ld new file mode 100644 index 000000000..a4b982b92 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/memory_scratch.ld @@ -0,0 +1,5 @@ +MEMORY +{ + SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} diff --git a/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld new file mode 100644 index 000000000..5557ee1cb --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld @@ -0,0 +1,276 @@ +/* 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 +{ + /* 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 */ +} diff --git a/src/rp2_common/pico_crt0/rp2040/sections_default.ld b/src/rp2_common/pico_crt0/rp2040/sections_default.ld new file mode 100644 index 000000000..57984e46b --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/sections_default.ld @@ -0,0 +1,275 @@ +/* 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 +{ + /* 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 */ +} diff --git a/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld b/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld new file mode 100644 index 000000000..9e082d53c --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld @@ -0,0 +1,239 @@ +/* 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 +{ + /* 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 */ +} diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld index 44c69f3b9..7b99a7745 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld @@ -1,309 +1,7 @@ -/* 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 -} +INCLUDE "memory_flash.ld" +INCLUDE "memory_ram.ld" +INCLUDE "memory_scratch.ld" 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 "sections_copy_to_ram.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld index bce316d14..75fd340d5 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld @@ -1,302 +1,7 @@ -/* 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 -} +INCLUDE "memory_flash.ld" +INCLUDE "memory_ram.ld" +INCLUDE "memory_scratch.ld" 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 "sections_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld b/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld index 5bedf6d21..cde630592 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld @@ -1,256 +1,6 @@ -/* 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 -} +INCLUDE "memory_ram.ld" +INCLUDE "memory_scratch.ld" 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 "sections_no_flash.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memory_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/memory_copy_to_ram.ld new file mode 100644 index 000000000..e69de29bb diff --git a/src/rp2_common/pico_crt0/rp2350/memory_flash.ld b/src/rp2_common/pico_crt0/rp2350/memory_flash.ld new file mode 100644 index 000000000..669fe00e3 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/memory_flash.ld @@ -0,0 +1,4 @@ +MEMORY +{ + INCLUDE "pico_flash_region.ld" +} diff --git a/src/rp2_common/pico_crt0/rp2350/memory_ram.ld b/src/rp2_common/pico_crt0/rp2350/memory_ram.ld new file mode 100644 index 000000000..434cdab97 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/memory_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k +} diff --git a/src/rp2_common/pico_crt0/rp2350/memory_scratch.ld b/src/rp2_common/pico_crt0/rp2350/memory_scratch.ld new file mode 100644 index 000000000..246bbf050 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/memory_scratch.ld @@ -0,0 +1,5 @@ +MEMORY +{ + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k +} diff --git a/src/rp2_common/pico_crt0/rp2350/memory_xip_ram.ld b/src/rp2_common/pico_crt0/rp2350/memory_xip_ram.ld new file mode 100644 index 000000000..e94479b54 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/memory_xip_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + XIP_RAM(rwx) : ORIGIN = 0x13FFC000, LENGTH = 16k +} diff --git a/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld new file mode 100644 index 000000000..9cc60b10a --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld @@ -0,0 +1,298 @@ +/* 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 +{ + /* 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 */ +} diff --git a/src/rp2_common/pico_crt0/rp2350/sections_default.ld b/src/rp2_common/pico_crt0/rp2350/sections_default.ld new file mode 100644 index 000000000..cb2c6e114 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/sections_default.ld @@ -0,0 +1,291 @@ +/* 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 +{ + .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 */ +} diff --git a/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld b/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld new file mode 100644 index 000000000..869d86436 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld @@ -0,0 +1,246 @@ +/* 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 +{ + /* 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 */ +} diff --git a/src/rp2_common/pico_standard_link/CMakeLists.txt b/src/rp2_common/pico_standard_link/CMakeLists.txt index c16968bba..5905d3da1 100644 --- a/src/rp2_common/pico_standard_link/CMakeLists.txt +++ b/src/rp2_common/pico_standard_link/CMakeLists.txt @@ -124,9 +124,12 @@ 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}") + # LINKER script will be PICO_TARGET_LINKER_SCRIPT if set on target, or ${CMAKE_CURRENT_LIST_DIR}/memmap_foo.ld # if PICO_TARGET_BINARY_TYPE is set to foo on the target, otherwise ${CMAKE_CURRENT_LIST_DIR}/memmap_${PICO_DEFAULT_BINARY_TYPE).ld set(_LINKER_SCRIPT_EXPRESSION "$>,$,${PICO_LINKER_SCRIPT_PATH}/memmap_$,>,${PICO_DEFAULT_BINARY_TYPE},$>.ld>") From d7896b82a04b4f13d86db6a9aba9093c7a2fc432 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Mon, 1 Dec 2025 20:40:45 +0000 Subject: [PATCH 02/27] Add customisable heap location, with pico_set_linker_script_var function --- .../pico_crt0/rp2040/sections_copy_to_ram.ld | 4 ++-- src/rp2_common/pico_crt0/rp2040/sections_default.ld | 4 ++-- src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld | 4 ++-- .../pico_crt0/rp2350/sections_copy_to_ram.ld | 4 ++-- src/rp2_common/pico_crt0/rp2350/sections_default.ld | 4 ++-- src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld | 4 ++-- src/rp2_common/pico_standard_link/CMakeLists.txt | 12 ++++++++++++ 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld index 5557ee1cb..1777f6604 100644 --- a/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld @@ -199,7 +199,7 @@ SECTIONS __bss_end__ = .; } > RAM - .heap (NOLOAD): + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): { __end__ = .; end = __end__; @@ -207,7 +207,7 @@ SECTIONS } > 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); + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); /* Start and end symbols must be word-aligned */ .scratch_x : { diff --git a/src/rp2_common/pico_crt0/rp2040/sections_default.ld b/src/rp2_common/pico_crt0/rp2040/sections_default.ld index 57984e46b..2e72b83b1 100644 --- a/src/rp2_common/pico_crt0/rp2040/sections_default.ld +++ b/src/rp2_common/pico_crt0/rp2040/sections_default.ld @@ -198,7 +198,7 @@ SECTIONS __bss_end__ = .; } > RAM - .heap (NOLOAD): + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): { __end__ = .; end = __end__; @@ -206,7 +206,7 @@ SECTIONS } > 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); + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); /* Start and end symbols must be word-aligned */ .scratch_x : { diff --git a/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld b/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld index 9e082d53c..c71ee3b01 100644 --- a/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld @@ -167,7 +167,7 @@ SECTIONS __bss_end__ = .; } > RAM - .heap (NOLOAD): + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): { __end__ = .; end = __end__; @@ -175,7 +175,7 @@ SECTIONS } > 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); + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); /* Start and end symbols must be word-aligned */ .scratch_x : { diff --git a/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld index 9cc60b10a..4b76bc04c 100644 --- a/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld @@ -219,7 +219,7 @@ SECTIONS __bss_end__ = .; } > RAM - .heap (NOLOAD): + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): { __end__ = .; end = __end__; @@ -227,7 +227,7 @@ SECTIONS } > 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); + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); /* Start and end symbols must be word-aligned */ .scratch_x : { diff --git a/src/rp2_common/pico_crt0/rp2350/sections_default.ld b/src/rp2_common/pico_crt0/rp2350/sections_default.ld index cb2c6e114..eaeee2723 100644 --- a/src/rp2_common/pico_crt0/rp2350/sections_default.ld +++ b/src/rp2_common/pico_crt0/rp2350/sections_default.ld @@ -212,7 +212,7 @@ SECTIONS __bss_end__ = .; } > RAM - .heap (NOLOAD): + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): { __end__ = .; end = __end__; @@ -220,7 +220,7 @@ SECTIONS } > 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); + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); /* Start and end symbols must be word-aligned */ .scratch_x : { diff --git a/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld b/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld index 869d86436..595d69778 100644 --- a/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld @@ -172,7 +172,7 @@ SECTIONS __bss_end__ = .; } > RAM - .heap (NOLOAD): + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): { __end__ = .; end = __end__; @@ -180,7 +180,7 @@ SECTIONS } > 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); + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); /* Start and end symbols must be word-aligned */ .scratch_x : { diff --git a/src/rp2_common/pico_standard_link/CMakeLists.txt b/src/rp2_common/pico_standard_link/CMakeLists.txt index 5905d3da1..5dd40909d 100644 --- a/src/rp2_common/pico_standard_link/CMakeLists.txt +++ b/src/rp2_common/pico_standard_link/CMakeLists.txt @@ -70,6 +70,15 @@ if (NOT TARGET pico_standard_link) set_target_properties(${TARGET} PROPERTIES PICO_TARGET_LINKER_SCRIPT ${LDSCRIPT}) endfunction() + # pico_set_linker_script_var(TARGET NAME VALUE) + # \brief\ Set the linker script for the target + # + # \param\ NAME Name of varAible to set + # \param\ VALUE Value of variable to set + function(pico_set_linker_script_var TARGET NAME VALUE) + set_property(TARGET ${TARGET} APPEND PROPERTY PICO_TARGET_LINKER_SCRIPT_VARS "--defsym=${NAME}=${VALUE}") + endfunction() + # pico_set_binary_type(TARGET TYPE) # \brief\ Set the binary type for the target # @@ -130,6 +139,9 @@ if (NOT TARGET pico_standard_link) # add include path for main linker script sections target_link_options(pico_standard_link INTERFACE "LINKER:-L${PICO_LINKER_SCRIPT_PATH}") + # add variables set by pico_set_linker_script_var function + target_link_options(pico_standard_link INTERFACE "LINKER:$,,>") + # LINKER script will be PICO_TARGET_LINKER_SCRIPT if set on target, or ${CMAKE_CURRENT_LIST_DIR}/memmap_foo.ld # if PICO_TARGET_BINARY_TYPE is set to foo on the target, otherwise ${CMAKE_CURRENT_LIST_DIR}/memmap_${PICO_DEFAULT_BINARY_TYPE).ld set(_LINKER_SCRIPT_EXPRESSION "$>,$,${PICO_LINKER_SCRIPT_PATH}/memmap_$,>,${PICO_DEFAULT_BINARY_TYPE},$>.ld>") From 6dd16d4d327c3f0c08db8bbd3b5144564d1073c6 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Mon, 1 Dec 2025 20:41:39 +0000 Subject: [PATCH 03/27] Add kitchen sink test of custom linker scripts --- test/kitchen_sink/CMakeLists.txt | 8 ++++++++ test/kitchen_sink/memmap_custom.ld | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/kitchen_sink/memmap_custom.ld diff --git a/test/kitchen_sink/CMakeLists.txt b/test/kitchen_sink/CMakeLists.txt index 1d6110f4c..71b8a58b6 100644 --- a/test/kitchen_sink/CMakeLists.txt +++ b/test/kitchen_sink/CMakeLists.txt @@ -214,6 +214,14 @@ 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_memmap_custom ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink.c) + # Have heap start from 0x20030000, and custom linker script + pico_set_linker_script(kitchen_sink_memmap_custom ${CMAKE_CURRENT_LIST_DIR}/memmap_custom.ld) + pico_set_linker_script_var(kitchen_sink_memmap_custom HEAP_LOC 0x20030000) + target_link_libraries(kitchen_sink_memmap_custom kitchen_sink_libs kitchen_sink_options) + pico_add_extra_outputs(kitchen_sink_memmap_custom) + target_compile_definitions(kitchen_sink_memmap_custom PRIVATE KITCHEN_SINK_ID="custom memmap binary") endif() add_executable(kitchen_sink_cpp ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink_cpp.cpp) diff --git a/test/kitchen_sink/memmap_custom.ld b/test/kitchen_sink/memmap_custom.ld new file mode 100644 index 000000000..081913e58 --- /dev/null +++ b/test/kitchen_sink/memmap_custom.ld @@ -0,0 +1,12 @@ +INCLUDE "memory_flash.ld" +INCLUDE "memory_scratch.ld" + +/* Only use 128k of SRAM, starting at 0x20020000 */ +MEMORY +{ + RAM(rwx) : ORIGIN = 0x20020000, LENGTH = 128k +} + +ENTRY(_entry_point) + +INCLUDE "sections_default.ld" From 1e865954a65893340d027d0011d69714a903e485 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 2 Dec 2025 14:48:02 +0000 Subject: [PATCH 04/27] Separate out rp2_common and platform-specific linker script sections --- .../pico_crt0/rp2040/memmap_blocked_ram.ld | 14 +- .../pico_crt0/rp2040/memmap_copy_to_ram.ld | 8 +- .../pico_crt0/rp2040/memmap_default.ld | 8 +- .../pico_crt0/rp2040/memmap_no_flash.ld | 7 +- .../{ => platform}/memory_blocked_ram.ld | 0 .../rp2040/{ => platform}/memory_ram.ld | 0 .../rp2040/{ => platform}/memory_scratch.ld | 0 .../platform/section_copy_to_ram_data.ld | 79 +++++ .../platform/section_copy_to_ram_text.ld | 101 ++++++ .../rp2040/platform/section_default_data.ld | 70 ++++ .../rp2040/platform/section_default_text.ld | 109 +++++++ .../rp2040/platform/section_no_flash_data.ld | 79 +++++ .../rp2040/platform/section_no_flash_text.ld | 71 +++++ .../rp2040/platform/section_platform_end.ld | 50 +++ .../pico_crt0/rp2040/sections_copy_to_ram.ld | 276 ---------------- .../pico_crt0/rp2040/sections_default.ld | 275 ---------------- .../pico_crt0/rp2040/sections_no_flash.ld | 239 -------------- .../pico_crt0/rp2350/memmap_copy_to_ram.ld | 8 +- .../pico_crt0/rp2350/memmap_default.ld | 8 +- .../pico_crt0/rp2350/memmap_no_flash.ld | 7 +- .../pico_crt0/rp2350/memory_copy_to_ram.ld | 0 .../pico_crt0/rp2350/memory_flash.ld | 4 - .../rp2350/{ => platform}/memory_ram.ld | 0 .../rp2350/{ => platform}/memory_scratch.ld | 0 .../rp2350/{ => platform}/memory_xip_ram.ld | 0 .../platform/section_copy_to_ram_data.ld | 83 +++++ .../platform/section_copy_to_ram_text.ld | 117 +++++++ .../rp2350/platform/section_default_data.ld | 72 +++++ .../rp2350/platform/section_default_text.ld | 121 +++++++ .../rp2350/platform/section_no_flash_data.ld | 82 +++++ .../rp2350/platform/section_no_flash_text.ld | 73 +++++ .../rp2350/platform/section_platform_end.ld | 7 + .../pico_crt0/rp2350/sections_copy_to_ram.ld | 298 ------------------ .../pico_crt0/rp2350/sections_default.ld | 291 ----------------- .../pico_crt0/rp2350/sections_no_flash.ld | 246 --------------- .../pico_standard_link/CMakeLists.txt | 1 + .../scripts/rp2_common/memmap_copy_to_ram.ld | 13 + .../scripts/rp2_common/memmap_default.ld | 13 + .../scripts/rp2_common/memmap_no_flash.ld | 12 + .../rp2_common/memory_aliases_default.ld | 3 + .../rp2_common/memory_aliases_no_flash.ld | 3 + .../scripts/rp2_common}/memory_flash.ld | 0 .../scripts/rp2_common/section_end.ld | 49 +++ .../scripts/rp2_common/section_flash_end.ld | 7 + .../scripts/rp2_common/section_heap.ld | 12 + .../scripts/rp2_common/section_scratch.ld | 37 +++ .../rp2_common/sections_copy_to_ram.ld | 7 + .../scripts/rp2_common/sections_default.ld | 7 + .../scripts/rp2_common/sections_no_flash.ld | 6 + test/kitchen_sink/memmap_custom.ld | 12 +- 50 files changed, 1309 insertions(+), 1676 deletions(-) rename src/rp2_common/pico_crt0/rp2040/{ => platform}/memory_blocked_ram.ld (100%) rename src/rp2_common/pico_crt0/rp2040/{ => platform}/memory_ram.ld (100%) rename src/rp2_common/pico_crt0/rp2040/{ => platform}/memory_scratch.ld (100%) create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_text.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_text.ld create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_platform_end.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/sections_default.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/memory_copy_to_ram.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/memory_flash.ld rename src/rp2_common/pico_crt0/rp2350/{ => platform}/memory_ram.ld (100%) rename src/rp2_common/pico_crt0/rp2350/{ => platform}/memory_scratch.ld (100%) rename src/rp2_common/pico_crt0/rp2350/{ => platform}/memory_xip_ram.ld (100%) create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_data.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_text.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/section_default_data.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_data.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_text.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/section_platform_end.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/sections_default.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_default.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_no_flash.ld rename src/rp2_common/{pico_crt0/rp2040 => pico_standard_link/scripts/rp2_common}/memory_flash.ld (100%) create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/section_end.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/section_flash_end.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/section_heap.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/section_scratch.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld index 150176eba..330e9bde3 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld @@ -1,7 +1,13 @@ -INCLUDE "memory_flash.ld" -INCLUDE "memory_blocked_ram.ld" -INCLUDE "memory_scratch.ld" +/* Include memory regions used */ +INCLUDE "rp2_common/memory_flash.ld" +INCLUDE "platform/memory_blocked_ram.ld" +INCLUDE "platform/memory_scratch.ld" +/* Include aliases for storage memory regions */ +INCLUDE "rp2_common/memory_aliases_default.ld" + +/* Define entry point symbol */ ENTRY(_entry_point) -INCLUDE "sections_default.ld" +/* Include default sections */ +INCLUDE "rp2_common/sections_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld index 7b99a7745..6a1647d4a 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld @@ -1,7 +1 @@ -INCLUDE "memory_flash.ld" -INCLUDE "memory_ram.ld" -INCLUDE "memory_scratch.ld" - -ENTRY(_entry_point) - -INCLUDE "sections_copy_to_ram.ld" +INCLUDE "rp2_common/memmap_copy_to_ram.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld index 75fd340d5..8e2073718 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld @@ -1,7 +1 @@ -INCLUDE "memory_flash.ld" -INCLUDE "memory_ram.ld" -INCLUDE "memory_scratch.ld" - -ENTRY(_entry_point) - -INCLUDE "sections_default.ld" +INCLUDE "rp2_common/memmap_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld b/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld index cde630592..b8d1dcf36 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_no_flash.ld @@ -1,6 +1 @@ -INCLUDE "memory_ram.ld" -INCLUDE "memory_scratch.ld" - -ENTRY(_entry_point) - -INCLUDE "sections_no_flash.ld" +INCLUDE "rp2_common/memmap_no_flash.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/memory_blocked_ram.ld b/src/rp2_common/pico_crt0/rp2040/platform/memory_blocked_ram.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2040/memory_blocked_ram.ld rename to src/rp2_common/pico_crt0/rp2040/platform/memory_blocked_ram.ld diff --git a/src/rp2_common/pico_crt0/rp2040/memory_ram.ld b/src/rp2_common/pico_crt0/rp2040/platform/memory_ram.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2040/memory_ram.ld rename to src/rp2_common/pico_crt0/rp2040/platform/memory_ram.ld diff --git a/src/rp2_common/pico_crt0/rp2040/memory_scratch.ld b/src/rp2_common/pico_crt0/rp2040/platform/memory_scratch.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2040/memory_scratch.ld rename to src/rp2_common/pico_crt0/rp2040/platform/memory_scratch.ld diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld new file mode 100644 index 000000000..661b4df00 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld @@ -0,0 +1,79 @@ +SECTIONS +{ + .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 +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_text.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_text.ld new file mode 100644 index 000000000..77a45941b --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_text.ld @@ -0,0 +1,101 @@ +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Raspberry Pi Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + /* The second stage will always enter the image at the start of .text. + The debugger will use the ELF entry point, which is the _entry_point + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .flashtext : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + } + + .rodata : { + /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + /* Vector table goes first in RAM, to avoid large alignment hole */ + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .text : { + __ram_text_start__ = .; + *(.init) + *(.text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + . = ALIGN(4); + __ram_text_end__ = .; + } > RAM AT> FLASH + __ram_text_source__ = LOADADDR(.text); + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld new file mode 100644 index 000000000..482c3fa5a --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld @@ -0,0 +1,70 @@ +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*) + + . = 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 +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld new file mode 100644 index 000000000..7aa5c9399 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_default_text.ld @@ -0,0 +1,109 @@ +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Raspberry Pi Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + /* The second stage will always enter the image at the start of .text. + The debugger will use the ELF entry point, which is the _entry_point + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld new file mode 100644 index 000000000..a6634f74d --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld @@ -0,0 +1,79 @@ +SECTIONS +{ + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + *(.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 +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_text.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_text.ld new file mode 100644 index 000000000..b4ad44ba7 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_text.ld @@ -0,0 +1,71 @@ +SECTIONS +{ + /* Note in NO_FLASH builds the entry point for both the bootrom, and debugger + entry (ELF entry point), are *first* in the image, and the vector table + follows immediately afterward. This is because the bootrom enters RAM + binaries directly at their lowest address (preferring main RAM over XIP + cache-as-SRAM if both are used). + */ + + .text : { + __logical_binary_start = .; + __reset_start = .; + KEEP (*(.reset)) + __reset_end = .; + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + . = ALIGN(256); + KEEP (*(.vectors)) + *(.text*) + . = ALIGN(4); + *(.init) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + } > RAM + + .rodata : { + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > RAM + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > RAM + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > RAM + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > RAM + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_platform_end.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_platform_end.ld new file mode 100644 index 000000000..2d0165aa4 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/section_platform_end.ld @@ -0,0 +1,50 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +SECTIONS +{ + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") + /* todo assert on extra code */ +} diff --git a/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld deleted file mode 100644 index 1777f6604..000000000 --- a/src/rp2_common/pico_crt0/rp2040/sections_copy_to_ram.ld +++ /dev/null @@ -1,276 +0,0 @@ -/* 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 -{ - /* 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 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); - - /* 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 */ -} diff --git a/src/rp2_common/pico_crt0/rp2040/sections_default.ld b/src/rp2_common/pico_crt0/rp2040/sections_default.ld deleted file mode 100644 index 2e72b83b1..000000000 --- a/src/rp2_common/pico_crt0/rp2040/sections_default.ld +++ /dev/null @@ -1,275 +0,0 @@ -/* 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 -{ - /* 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 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); - - /* 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 */ -} diff --git a/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld b/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld deleted file mode 100644 index c71ee3b01..000000000 --- a/src/rp2_common/pico_crt0/rp2040/sections_no_flash.ld +++ /dev/null @@ -1,239 +0,0 @@ -/* 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 -{ - /* 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 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); - - /* 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 */ -} diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld index 7b99a7745..6a1647d4a 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_copy_to_ram.ld @@ -1,7 +1 @@ -INCLUDE "memory_flash.ld" -INCLUDE "memory_ram.ld" -INCLUDE "memory_scratch.ld" - -ENTRY(_entry_point) - -INCLUDE "sections_copy_to_ram.ld" +INCLUDE "rp2_common/memmap_copy_to_ram.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld index 75fd340d5..8e2073718 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld @@ -1,7 +1 @@ -INCLUDE "memory_flash.ld" -INCLUDE "memory_ram.ld" -INCLUDE "memory_scratch.ld" - -ENTRY(_entry_point) - -INCLUDE "sections_default.ld" +INCLUDE "rp2_common/memmap_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld b/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld index cde630592..b8d1dcf36 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_no_flash.ld @@ -1,6 +1 @@ -INCLUDE "memory_ram.ld" -INCLUDE "memory_scratch.ld" - -ENTRY(_entry_point) - -INCLUDE "sections_no_flash.ld" +INCLUDE "rp2_common/memmap_no_flash.ld" diff --git a/src/rp2_common/pico_crt0/rp2350/memory_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/memory_copy_to_ram.ld deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/rp2_common/pico_crt0/rp2350/memory_flash.ld b/src/rp2_common/pico_crt0/rp2350/memory_flash.ld deleted file mode 100644 index 669fe00e3..000000000 --- a/src/rp2_common/pico_crt0/rp2350/memory_flash.ld +++ /dev/null @@ -1,4 +0,0 @@ -MEMORY -{ - INCLUDE "pico_flash_region.ld" -} diff --git a/src/rp2_common/pico_crt0/rp2350/memory_ram.ld b/src/rp2_common/pico_crt0/rp2350/platform/memory_ram.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2350/memory_ram.ld rename to src/rp2_common/pico_crt0/rp2350/platform/memory_ram.ld diff --git a/src/rp2_common/pico_crt0/rp2350/memory_scratch.ld b/src/rp2_common/pico_crt0/rp2350/platform/memory_scratch.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2350/memory_scratch.ld rename to src/rp2_common/pico_crt0/rp2350/platform/memory_scratch.ld diff --git a/src/rp2_common/pico_crt0/rp2350/memory_xip_ram.ld b/src/rp2_common/pico_crt0/rp2350/platform/memory_xip_ram.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2350/memory_xip_ram.ld rename to src/rp2_common/pico_crt0/rp2350/platform/memory_xip_ram.ld diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_data.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_data.ld new file mode 100644 index 000000000..19082589c --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_data.ld @@ -0,0 +1,83 @@ +SECTIONS +{ + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + . = ALIGN(4); + *(.rodata*) + *(.srodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_text.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_text.ld new file mode 100644 index 000000000..d35f7209e --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_text.ld @@ -0,0 +1,117 @@ +SECTIONS +{ + /* On Arm, the bootrom expects a VT at the start of the + image by default; on RISC-V, the default is to enter the image at its + lowest address, so an IMAGE_DEF item is required to specify the + nondefault entry point. */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .flashtext : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + . = ALIGN(4); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + /* Vector table goes first in RAM, to avoid large alignment hole */ + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .text : { + __ram_text_start__ = .; + *(.init) + *(.text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + . = ALIGN(4); + __ram_text_end__ = .; + } > RAM AT> FLASH + __ram_text_source__ = LOADADDR(.text); + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_default_data.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_default_data.ld new file mode 100644 index 000000000..9ffa5d163 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_default_data.ld @@ -0,0 +1,72 @@ +SECTIONS +{ + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld new file mode 100644 index 000000000..fdd963321 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_default_text.ld @@ -0,0 +1,121 @@ +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *libgcc.a:cmse_nonsecure_call.o + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_data.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_data.ld new file mode 100644 index 000000000..5658d8a4b --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_data.ld @@ -0,0 +1,82 @@ +SECTIONS +{ + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM + PROVIDE(__data_end__ = .); + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_text.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_text.ld new file mode 100644 index 000000000..833d8c42b --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_text.ld @@ -0,0 +1,73 @@ +SECTIONS +{ + /* Note unlike RP2040, we start the image with a vector table even for + NO_FLASH builds. On Arm, the bootrom expects a VT at the start of the + image by default; on RISC-V, the default is to enter the image at its + lowest address, so an IMAGE_DEF item is required to specify the + nondefault entry point. */ + + .text : { + __logical_binary_start = .; + /* Vectors require 512-byte alignment on v8-M when >48 IRQs are used, + so we would waste RAM if the vector table were not at the + start. */ + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + __reset_start = .; + KEEP (*(.reset)) + __reset_end = .; + *(.text*) + . = ALIGN(4); + *(.init) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + } > RAM + + .rodata : { + . = ALIGN(4); + *(.rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > RAM + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > RAM + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > RAM + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > RAM + __binary_info_end = .; + . = ALIGN(4); +} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_platform_end.ld b/src/rp2_common/pico_crt0/rp2350/platform/section_platform_end.ld new file mode 100644 index 000000000..43cc19ecd --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/section_platform_end.ld @@ -0,0 +1,7 @@ +SECTIONS +{ + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} diff --git a/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld b/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld deleted file mode 100644 index 4b76bc04c..000000000 --- a/src/rp2_common/pico_crt0/rp2350/sections_copy_to_ram.ld +++ /dev/null @@ -1,298 +0,0 @@ -/* 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 -{ - /* 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 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); - - /* 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 */ -} diff --git a/src/rp2_common/pico_crt0/rp2350/sections_default.ld b/src/rp2_common/pico_crt0/rp2350/sections_default.ld deleted file mode 100644 index eaeee2723..000000000 --- a/src/rp2_common/pico_crt0/rp2350/sections_default.ld +++ /dev/null @@ -1,291 +0,0 @@ -/* 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 -{ - .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 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); - - /* 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 */ -} diff --git a/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld b/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld deleted file mode 100644 index 595d69778..000000000 --- a/src/rp2_common/pico_crt0/rp2350/sections_no_flash.ld +++ /dev/null @@ -1,246 +0,0 @@ -/* 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 -{ - /* 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 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); - - /* 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 */ -} diff --git a/src/rp2_common/pico_standard_link/CMakeLists.txt b/src/rp2_common/pico_standard_link/CMakeLists.txt index 5dd40909d..8fc240346 100644 --- a/src/rp2_common/pico_standard_link/CMakeLists.txt +++ b/src/rp2_common/pico_standard_link/CMakeLists.txt @@ -138,6 +138,7 @@ if (NOT TARGET pico_standard_link) # 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 variables set by pico_set_linker_script_var function target_link_options(pico_standard_link INTERFACE "LINKER:$,,>") diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld new file mode 100644 index 000000000..88127d894 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld @@ -0,0 +1,13 @@ +/* Include memory regions used */ +INCLUDE "rp2_common/memory_flash.ld" +INCLUDE "platform/memory_ram.ld" +INCLUDE "platform/memory_scratch.ld" + +/* Include aliases for storage memory regions */ +INCLUDE "rp2_common/memory_aliases_default.ld" + +/* Define entry point symbol */ +ENTRY(_entry_point) + +/* Include default sections */ +INCLUDE "rp2_common/sections_copy_to_ram.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld new file mode 100644 index 000000000..a8de400d9 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld @@ -0,0 +1,13 @@ +/* Include memory regions used */ +INCLUDE "rp2_common/memory_flash.ld" +INCLUDE "platform/memory_ram.ld" +INCLUDE "platform/memory_scratch.ld" + +/* Include aliases for storage memory regions */ +INCLUDE "rp2_common/memory_aliases_default.ld" + +/* Define entry point symbol */ +ENTRY(_entry_point) + +/* Include default sections */ +INCLUDE "rp2_common/sections_default.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld new file mode 100644 index 000000000..61ae84dc7 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld @@ -0,0 +1,12 @@ +/* Include memory regions used */ +INCLUDE "platform/memory_ram.ld" +INCLUDE "platform/memory_scratch.ld" + +/* Include aliases for no_flash storage memory regions (alias to themselves) */ +INCLUDE "rp2_common/memory_aliases_no_flash.ld" + +/* Define entry point symbol */ +ENTRY(_entry_point) + +/* Include no_flash sections */ +INCLUDE "rp2_common/sections_no_flash.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_default.ld new file mode 100644 index 000000000..7c56254bd --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_default.ld @@ -0,0 +1,3 @@ +REGION_ALIAS("RAM_STORE", FLASH); +REGION_ALIAS("SCRATCH_X_STORE", FLASH); +REGION_ALIAS("SCRATCH_Y_STORE", FLASH); diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_no_flash.ld new file mode 100644 index 000000000..063b5b6fc --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_aliases_no_flash.ld @@ -0,0 +1,3 @@ +REGION_ALIAS("RAM_STORE", RAM); +REGION_ALIAS("SCRATCH_X_STORE", SCRATCH_X); +REGION_ALIAS("SCRATCH_Y_STORE", SCRATCH_Y); diff --git a/src/rp2_common/pico_crt0/rp2040/memory_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_flash.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2040/memory_flash.ld rename to src/rp2_common/pico_standard_link/scripts/rp2_common/memory_flash.ld diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_end.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_end.ld new file mode 100644 index 000000000..53d328174 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_end.ld @@ -0,0 +1,49 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +SECTIONS +{ + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + /* todo assert on extra code */ +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_flash_end.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_flash_end.ld new file mode 100644 index 000000000..8591406ff --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_flash_end.ld @@ -0,0 +1,7 @@ +SECTIONS +{ + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_heap.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_heap.ld new file mode 100644 index 000000000..1cc9e0de1 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_heap.ld @@ -0,0 +1,12 @@ +SECTIONS +{ + .heap DEFINED(HEAP_LOC) ? HEAP_LOC : . (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + } > RAM + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + __HeapLimit = DEFINED(HEAP_LIMIT) ? HEAP_LIMIT : ORIGIN(RAM) + LENGTH(RAM); +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/section_scratch.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_scratch.ld new file mode 100644 index 000000000..f61c39639 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_scratch.ld @@ -0,0 +1,37 @@ +SECTIONS +{ + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT> SCRATCH_X_STORE + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT> SCRATCH_Y_STORE + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld new file mode 100644 index 000000000..0017f385b --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld @@ -0,0 +1,7 @@ +INCLUDE "platform/section_copy_to_ram_text.ld" +INCLUDE "platform/section_copy_to_ram_data.ld" +INCLUDE "rp2_common/section_heap.ld" +INCLUDE "rp2_common/section_scratch.ld" +INCLUDE "rp2_common/section_flash_end.ld" +INCLUDE "rp2_common/section_end.ld" +INCLUDE "platform/section_platform_end.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld new file mode 100644 index 000000000..e0138db34 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld @@ -0,0 +1,7 @@ +INCLUDE "platform/section_default_text.ld" +INCLUDE "platform/section_default_data.ld" +INCLUDE "rp2_common/section_heap.ld" +INCLUDE "rp2_common/section_scratch.ld" +INCLUDE "rp2_common/section_flash_end.ld" +INCLUDE "rp2_common/section_end.ld" +INCLUDE "platform/section_platform_end.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld new file mode 100644 index 000000000..ebc062e6a --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld @@ -0,0 +1,6 @@ +INCLUDE "platform/section_no_flash_text.ld" +INCLUDE "platform/section_no_flash_data.ld" +INCLUDE "rp2_common/section_heap.ld" +INCLUDE "rp2_common/section_scratch.ld" +INCLUDE "rp2_common/section_end.ld" +INCLUDE "platform/section_platform_end.ld" diff --git a/test/kitchen_sink/memmap_custom.ld b/test/kitchen_sink/memmap_custom.ld index 081913e58..7fe2098f1 100644 --- a/test/kitchen_sink/memmap_custom.ld +++ b/test/kitchen_sink/memmap_custom.ld @@ -1,5 +1,6 @@ -INCLUDE "memory_flash.ld" -INCLUDE "memory_scratch.ld" +/* Include memory regions used */ +INCLUDE "rp2_common/memory_flash.ld" +INCLUDE "platform/memory_scratch.ld" /* Only use 128k of SRAM, starting at 0x20020000 */ MEMORY @@ -7,6 +8,11 @@ MEMORY RAM(rwx) : ORIGIN = 0x20020000, LENGTH = 128k } +/* Include aliases for storage memory regions */ +INCLUDE "rp2_common/memory_aliases_default.ld" + +/* Define entry point symbol */ ENTRY(_entry_point) -INCLUDE "sections_default.ld" +/* Include default sections */ +INCLUDE "rp2_common/sections_default.ld" From f6789f888ad6fda43ad04a9c20ad76c6afb1c1b6 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 2 Dec 2025 14:56:53 +0000 Subject: [PATCH 05/27] More de-duplication --- .../platform/section_copy_to_ram_data.ld | 79 ------------------- .../rp2040/platform/section_default_data.ld | 70 ---------------- .../rp2040/platform/section_no_flash_data.ld | 79 ------------------- .../rp2_common}/section_copy_to_ram_data.ld | 0 .../rp2_common}/section_default_data.ld | 0 .../rp2_common}/section_no_flash_data.ld | 0 .../rp2_common/sections_copy_to_ram.ld | 2 +- .../scripts/rp2_common/sections_default.ld | 2 +- .../scripts/rp2_common/sections_no_flash.ld | 2 +- 9 files changed, 3 insertions(+), 231 deletions(-) delete mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld rename src/rp2_common/{pico_crt0/rp2350/platform => pico_standard_link/scripts/rp2_common}/section_copy_to_ram_data.ld (100%) rename src/rp2_common/{pico_crt0/rp2350/platform => pico_standard_link/scripts/rp2_common}/section_default_data.ld (100%) rename src/rp2_common/{pico_crt0/rp2350/platform => pico_standard_link/scripts/rp2_common}/section_no_flash_data.ld (100%) diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld deleted file mode 100644 index 661b4df00..000000000 --- a/src/rp2_common/pico_crt0/rp2040/platform/section_copy_to_ram_data.ld +++ /dev/null @@ -1,79 +0,0 @@ -SECTIONS -{ - .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 -} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld deleted file mode 100644 index 482c3fa5a..000000000 --- a/src/rp2_common/pico_crt0/rp2040/platform/section_default_data.ld +++ /dev/null @@ -1,70 +0,0 @@ -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*) - - . = 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 -} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld b/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld deleted file mode 100644 index a6634f74d..000000000 --- a/src/rp2_common/pico_crt0/rp2040/platform/section_no_flash_data.ld +++ /dev/null @@ -1,79 +0,0 @@ -SECTIONS -{ - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - *(.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 -} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_data.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_copy_to_ram_data.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2350/platform/section_copy_to_ram_data.ld rename to src/rp2_common/pico_standard_link/scripts/rp2_common/section_copy_to_ram_data.ld diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_default_data.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_default_data.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2350/platform/section_default_data.ld rename to src/rp2_common/pico_standard_link/scripts/rp2_common/section_default_data.ld diff --git a/src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_data.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/section_no_flash_data.ld similarity index 100% rename from src/rp2_common/pico_crt0/rp2350/platform/section_no_flash_data.ld rename to src/rp2_common/pico_standard_link/scripts/rp2_common/section_no_flash_data.ld diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld index 0017f385b..5e86d7c0c 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_copy_to_ram.ld @@ -1,5 +1,5 @@ INCLUDE "platform/section_copy_to_ram_text.ld" -INCLUDE "platform/section_copy_to_ram_data.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" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld index e0138db34..558ec1848 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_default.ld @@ -1,5 +1,5 @@ INCLUDE "platform/section_default_text.ld" -INCLUDE "platform/section_default_data.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" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld index ebc062e6a..b9b3973b2 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/sections_no_flash.ld @@ -1,5 +1,5 @@ INCLUDE "platform/section_no_flash_text.ld" -INCLUDE "platform/section_no_flash_data.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" From c6cac63a1f6c86b5fcbf681f02e63d72b033381e Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 2 Dec 2025 17:31:49 +0000 Subject: [PATCH 06/27] Make overriding ram locations simpler --- .../pico_crt0/rp2040/memmap_blocked_ram.ld | 15 +++------------ .../rp2040/platform/default_locations.ld | 8 ++++++++ .../rp2040/platform/memory_blocked_ram.ld | 4 ---- .../pico_crt0/rp2040/platform/memory_ram.ld | 4 ---- .../rp2040/platform/memory_scratch.ld | 5 ----- .../rp2350/platform/default_locations.ld | 8 ++++++++ .../pico_crt0/rp2350/platform/memory_ram.ld | 4 ---- .../rp2350/platform/memory_scratch.ld | 5 ----- .../rp2350/platform/memory_xip_ram.ld | 4 ---- .../scripts/rp2_common/memmap_copy_to_ram.ld | 7 +++++-- .../scripts/rp2_common/memmap_default.ld | 7 +++++-- .../scripts/rp2_common/memmap_no_flash.ld | 7 +++++-- .../scripts/rp2_common/memory_ram.ld | 4 ++++ .../scripts/rp2_common/memory_scratch.ld | 5 +++++ .../scripts/rp2_common/memory_xip_ram.ld | 4 ++++ test/kitchen_sink/CMakeLists.txt | 15 ++++++++------- test/kitchen_sink/memmap_custom.ld | 18 ------------------ 17 files changed, 55 insertions(+), 69 deletions(-) create mode 100644 src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/platform/memory_blocked_ram.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/platform/memory_ram.ld delete mode 100644 src/rp2_common/pico_crt0/rp2040/platform/memory_scratch.ld create mode 100644 src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/platform/memory_ram.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/platform/memory_scratch.ld delete mode 100644 src/rp2_common/pico_crt0/rp2350/platform/memory_xip_ram.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memory_ram.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memory_scratch.ld create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/memory_xip_ram.ld delete mode 100644 test/kitchen_sink/memmap_custom.ld diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld index 330e9bde3..a4a528950 100644 --- a/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld +++ b/src/rp2_common/pico_crt0/rp2040/memmap_blocked_ram.ld @@ -1,13 +1,4 @@ -/* Include memory regions used */ -INCLUDE "rp2_common/memory_flash.ld" -INCLUDE "platform/memory_blocked_ram.ld" -INCLUDE "platform/memory_scratch.ld" +/* Use blocked ram */ +RAM_ORIGIN = 0x21000000; -/* 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" +INCLUDE "memmap_default.ld" diff --git a/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld b/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld new file mode 100644 index 000000000..684418b73 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld @@ -0,0 +1,8 @@ +RAM_ORIGIN = DEFINED(RAM_ORIGIN) ? RAM_ORIGIN : 0x20000000; +RAM_LENGTH = DEFINED(RAM_LENGTH) ? RAM_LENGTH : 256k; +SCRATCH_X_ORIGIN = DEFINED(SCRATCH_X_ORIGIN) ? SCRATCH_X_ORIGIN : 0x20040000; +SCRATCH_X_LENGTH = DEFINED(SCRATCH_X_LENGTH) ? SCRATCH_X_LENGTH : 4k; +SCRATCH_Y_ORIGIN = DEFINED(SCRATCH_Y_ORIGIN) ? SCRATCH_Y_ORIGIN : 0x20041000; +SCRATCH_Y_LENGTH = DEFINED(SCRATCH_Y_LENGTH) ? SCRATCH_Y_LENGTH : 4k; +XIP_RAM_ORIGIN = DEFINED(XIP_RAM_ORIGIN) ? XIP_RAM_ORIGIN : 0x15000000; +XIP_RAM_LENGTH = DEFINED(XIP_RAM_LENGTH) ? XIP_RAM_LENGTH : 16k; diff --git a/src/rp2_common/pico_crt0/rp2040/platform/memory_blocked_ram.ld b/src/rp2_common/pico_crt0/rp2040/platform/memory_blocked_ram.ld deleted file mode 100644 index 57cbad6b7..000000000 --- a/src/rp2_common/pico_crt0/rp2040/platform/memory_blocked_ram.ld +++ /dev/null @@ -1,4 +0,0 @@ -MEMORY -{ - RAM(rwx) : ORIGIN = 0x21000000, LENGTH = 256k -} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/memory_ram.ld b/src/rp2_common/pico_crt0/rp2040/platform/memory_ram.ld deleted file mode 100644 index 1e1515dd3..000000000 --- a/src/rp2_common/pico_crt0/rp2040/platform/memory_ram.ld +++ /dev/null @@ -1,4 +0,0 @@ -MEMORY -{ - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k -} diff --git a/src/rp2_common/pico_crt0/rp2040/platform/memory_scratch.ld b/src/rp2_common/pico_crt0/rp2040/platform/memory_scratch.ld deleted file mode 100644 index a4b982b92..000000000 --- a/src/rp2_common/pico_crt0/rp2040/platform/memory_scratch.ld +++ /dev/null @@ -1,5 +0,0 @@ -MEMORY -{ - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k -} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld b/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld new file mode 100644 index 000000000..0b1611d40 --- /dev/null +++ b/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld @@ -0,0 +1,8 @@ +RAM_ORIGIN = DEFINED(RAM_ORIGIN) ? RAM_ORIGIN : 0x20000000; +RAM_LENGTH = DEFINED(RAM_LENGTH) ? RAM_LENGTH : 512k; +SCRATCH_X_ORIGIN = DEFINED(SCRATCH_X_ORIGIN) ? SCRATCH_X_ORIGIN : 0x20080000; +SCRATCH_X_LENGTH = DEFINED(SCRATCH_X_LENGTH) ? SCRATCH_X_LENGTH : 4k; +SCRATCH_Y_ORIGIN = DEFINED(SCRATCH_Y_ORIGIN) ? SCRATCH_Y_ORIGIN : 0x20081000; +SCRATCH_Y_LENGTH = DEFINED(SCRATCH_Y_LENGTH) ? SCRATCH_Y_LENGTH : 4k; +XIP_RAM_ORIGIN = DEFINED(XIP_RAM_ORIGIN) ? XIP_RAM_ORIGIN : 0x13FFC000; +XIP_RAM_LENGTH = DEFINED(XIP_RAM_LENGTH) ? XIP_RAM_LENGTH : 16k; diff --git a/src/rp2_common/pico_crt0/rp2350/platform/memory_ram.ld b/src/rp2_common/pico_crt0/rp2350/platform/memory_ram.ld deleted file mode 100644 index 434cdab97..000000000 --- a/src/rp2_common/pico_crt0/rp2350/platform/memory_ram.ld +++ /dev/null @@ -1,4 +0,0 @@ -MEMORY -{ - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k -} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/memory_scratch.ld b/src/rp2_common/pico_crt0/rp2350/platform/memory_scratch.ld deleted file mode 100644 index 246bbf050..000000000 --- a/src/rp2_common/pico_crt0/rp2350/platform/memory_scratch.ld +++ /dev/null @@ -1,5 +0,0 @@ -MEMORY -{ - SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k -} diff --git a/src/rp2_common/pico_crt0/rp2350/platform/memory_xip_ram.ld b/src/rp2_common/pico_crt0/rp2350/platform/memory_xip_ram.ld deleted file mode 100644 index e94479b54..000000000 --- a/src/rp2_common/pico_crt0/rp2350/platform/memory_xip_ram.ld +++ /dev/null @@ -1,4 +0,0 @@ -MEMORY -{ - XIP_RAM(rwx) : ORIGIN = 0x13FFC000, LENGTH = 16k -} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld index 88127d894..12b7c85ab 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld @@ -1,7 +1,10 @@ +/* Include platform memory locations */ +INCLUDE "platform/default_locations.ld" + /* Include memory regions used */ INCLUDE "rp2_common/memory_flash.ld" -INCLUDE "platform/memory_ram.ld" -INCLUDE "platform/memory_scratch.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" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld index a8de400d9..6b1ccf827 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld @@ -1,7 +1,10 @@ +/* Include platform memory locations */ +INCLUDE "platform/default_locations.ld" + /* Include memory regions used */ INCLUDE "rp2_common/memory_flash.ld" -INCLUDE "platform/memory_ram.ld" -INCLUDE "platform/memory_scratch.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" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld index 61ae84dc7..8fb49e6bd 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld @@ -1,6 +1,9 @@ +/* Include platform memory locations */ +INCLUDE "platform/default_locations.ld" + /* Include memory regions used */ -INCLUDE "platform/memory_ram.ld" -INCLUDE "platform/memory_scratch.ld" +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" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_ram.ld new file mode 100644 index 000000000..2b8a88a06 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + RAM(rwx) : ORIGIN = RAM_ORIGIN, LENGTH = RAM_LENGTH +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_scratch.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_scratch.ld new file mode 100644 index 000000000..7ba5d2172 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_scratch.ld @@ -0,0 +1,5 @@ +MEMORY +{ + SCRATCH_X(rwx) : ORIGIN = SCRATCH_X_ORIGIN, LENGTH = SCRATCH_X_LENGTH + SCRATCH_Y(rwx) : ORIGIN = SCRATCH_Y_ORIGIN, LENGTH = SCRATCH_Y_LENGTH +} diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_xip_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_xip_ram.ld new file mode 100644 index 000000000..636e90137 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memory_xip_ram.ld @@ -0,0 +1,4 @@ +MEMORY +{ + XIP_RAM(rwx) : ORIGIN = XIP_RAM_ORIGIN, LENGTH = XIP_RAM_LENGTH +} diff --git a/test/kitchen_sink/CMakeLists.txt b/test/kitchen_sink/CMakeLists.txt index 71b8a58b6..33e5fbc24 100644 --- a/test/kitchen_sink/CMakeLists.txt +++ b/test/kitchen_sink/CMakeLists.txt @@ -215,13 +215,14 @@ if (NOT KITCHEN_SINK_NO_BINARY_TYPE_VARIANTS) target_compile_definitions(kitchen_sink_blocked_ram PRIVATE KITCHEN_SINK_ID="blocked-ram binary") endif() - add_executable(kitchen_sink_memmap_custom ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink.c) - # Have heap start from 0x20030000, and custom linker script - pico_set_linker_script(kitchen_sink_memmap_custom ${CMAKE_CURRENT_LIST_DIR}/memmap_custom.ld) - pico_set_linker_script_var(kitchen_sink_memmap_custom HEAP_LOC 0x20030000) - target_link_libraries(kitchen_sink_memmap_custom kitchen_sink_libs kitchen_sink_options) - pico_add_extra_outputs(kitchen_sink_memmap_custom) - target_compile_definitions(kitchen_sink_memmap_custom PRIVATE KITCHEN_SINK_ID="custom memmap binary") + add_executable(kitchen_sink_ram_custom ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink.c) + # Have ram start from 0x20020000 length 128k, and heap start from 0x20030000 + pico_set_linker_script_var(kitchen_sink_ram_custom RAM_ORIGIN 0x20020000) + pico_set_linker_script_var(kitchen_sink_ram_custom RAM_LENGTH 128k) + pico_set_linker_script_var(kitchen_sink_ram_custom HEAP_LOC 0x20030000) + target_link_libraries(kitchen_sink_ram_custom kitchen_sink_libs kitchen_sink_options) + pico_add_extra_outputs(kitchen_sink_ram_custom) + target_compile_definitions(kitchen_sink_ram_custom PRIVATE KITCHEN_SINK_ID="custom ram binary") endif() add_executable(kitchen_sink_cpp ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink_cpp.cpp) diff --git a/test/kitchen_sink/memmap_custom.ld b/test/kitchen_sink/memmap_custom.ld deleted file mode 100644 index 7fe2098f1..000000000 --- a/test/kitchen_sink/memmap_custom.ld +++ /dev/null @@ -1,18 +0,0 @@ -/* Include memory regions used */ -INCLUDE "rp2_common/memory_flash.ld" -INCLUDE "platform/memory_scratch.ld" - -/* Only use 128k of SRAM, starting at 0x20020000 */ -MEMORY -{ - RAM(rwx) : ORIGIN = 0x20020000, LENGTH = 128k -} - -/* 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" From d89c2d85eefa801d7922f563d50e05b0dbcc5722 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 4 Dec 2025 10:14:26 +0000 Subject: [PATCH 07/27] Make it possible to reference default locations in pico_set_linker_script_var variables Means that CMake doesn't need to know the default memory addresses for different platforms --- .../rp2040/platform/default_locations.ld | 16 ++++++++-------- .../rp2350/platform/default_locations.ld | 16 ++++++++-------- src/rp2_common/pico_standard_link/CMakeLists.txt | 3 +++ .../scripts/rp2_common/memmap_copy_to_ram.ld | 2 +- .../scripts/rp2_common/memmap_default.ld | 2 +- .../scripts/rp2_common/memmap_no_flash.ld | 2 +- .../scripts/rp2_common/set_memory_locations.ld | 8 ++++++++ 7 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 src/rp2_common/pico_standard_link/scripts/rp2_common/set_memory_locations.ld diff --git a/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld b/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld index 684418b73..03144ea07 100644 --- a/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld +++ b/src/rp2_common/pico_crt0/rp2040/platform/default_locations.ld @@ -1,8 +1,8 @@ -RAM_ORIGIN = DEFINED(RAM_ORIGIN) ? RAM_ORIGIN : 0x20000000; -RAM_LENGTH = DEFINED(RAM_LENGTH) ? RAM_LENGTH : 256k; -SCRATCH_X_ORIGIN = DEFINED(SCRATCH_X_ORIGIN) ? SCRATCH_X_ORIGIN : 0x20040000; -SCRATCH_X_LENGTH = DEFINED(SCRATCH_X_LENGTH) ? SCRATCH_X_LENGTH : 4k; -SCRATCH_Y_ORIGIN = DEFINED(SCRATCH_Y_ORIGIN) ? SCRATCH_Y_ORIGIN : 0x20041000; -SCRATCH_Y_LENGTH = DEFINED(SCRATCH_Y_LENGTH) ? SCRATCH_Y_LENGTH : 4k; -XIP_RAM_ORIGIN = DEFINED(XIP_RAM_ORIGIN) ? XIP_RAM_ORIGIN : 0x15000000; -XIP_RAM_LENGTH = DEFINED(XIP_RAM_LENGTH) ? XIP_RAM_LENGTH : 16k; +RAM_ORIGIN_DEFAULT = 0x20000000; +RAM_LENGTH_DEFAULT = 256k; +SCRATCH_X_ORIGIN_DEFAULT = 0x20040000; +SCRATCH_X_LENGTH_DEFAULT = 4k; +SCRATCH_Y_ORIGIN_DEFAULT = 0x20041000; +SCRATCH_Y_LENGTH_DEFAULT = 4k; +XIP_RAM_ORIGIN_DEFAULT = 0x15000000; +XIP_RAM_LENGTH_DEFAULT = 16k; diff --git a/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld b/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld index 0b1611d40..15ddc7374 100644 --- a/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld +++ b/src/rp2_common/pico_crt0/rp2350/platform/default_locations.ld @@ -1,8 +1,8 @@ -RAM_ORIGIN = DEFINED(RAM_ORIGIN) ? RAM_ORIGIN : 0x20000000; -RAM_LENGTH = DEFINED(RAM_LENGTH) ? RAM_LENGTH : 512k; -SCRATCH_X_ORIGIN = DEFINED(SCRATCH_X_ORIGIN) ? SCRATCH_X_ORIGIN : 0x20080000; -SCRATCH_X_LENGTH = DEFINED(SCRATCH_X_LENGTH) ? SCRATCH_X_LENGTH : 4k; -SCRATCH_Y_ORIGIN = DEFINED(SCRATCH_Y_ORIGIN) ? SCRATCH_Y_ORIGIN : 0x20081000; -SCRATCH_Y_LENGTH = DEFINED(SCRATCH_Y_LENGTH) ? SCRATCH_Y_LENGTH : 4k; -XIP_RAM_ORIGIN = DEFINED(XIP_RAM_ORIGIN) ? XIP_RAM_ORIGIN : 0x13FFC000; -XIP_RAM_LENGTH = DEFINED(XIP_RAM_LENGTH) ? XIP_RAM_LENGTH : 16k; +RAM_ORIGIN_DEFAULT = 0x20000000; +RAM_LENGTH_DEFAULT = 512k; +SCRATCH_X_ORIGIN_DEFAULT = 0x20080000; +SCRATCH_X_LENGTH_DEFAULT = 4k; +SCRATCH_Y_ORIGIN_DEFAULT = 0x20081000; +SCRATCH_Y_LENGTH_DEFAULT = 4k; +XIP_RAM_ORIGIN_DEFAULT = 0x13FFC000; +XIP_RAM_LENGTH_DEFAULT = 16k; diff --git a/src/rp2_common/pico_standard_link/CMakeLists.txt b/src/rp2_common/pico_standard_link/CMakeLists.txt index 8fc240346..69f5751ef 100644 --- a/src/rp2_common/pico_standard_link/CMakeLists.txt +++ b/src/rp2_common/pico_standard_link/CMakeLists.txt @@ -140,6 +140,9 @@ if (NOT TARGET pico_standard_link) 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:$,,>") diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld index 12b7c85ab..1cb8f7597 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_copy_to_ram.ld @@ -1,5 +1,5 @@ /* Include platform memory locations */ -INCLUDE "platform/default_locations.ld" +INCLUDE "rp2_common/set_memory_locations.ld" /* Include memory regions used */ INCLUDE "rp2_common/memory_flash.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld index 6b1ccf827..2c8f3ffa1 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_default.ld @@ -1,5 +1,5 @@ /* Include platform memory locations */ -INCLUDE "platform/default_locations.ld" +INCLUDE "rp2_common/set_memory_locations.ld" /* Include memory regions used */ INCLUDE "rp2_common/memory_flash.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld index 8fb49e6bd..2e3695ef9 100644 --- a/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/memmap_no_flash.ld @@ -1,5 +1,5 @@ /* Include platform memory locations */ -INCLUDE "platform/default_locations.ld" +INCLUDE "rp2_common/set_memory_locations.ld" /* Include memory regions used */ INCLUDE "rp2_common/memory_ram.ld" diff --git a/src/rp2_common/pico_standard_link/scripts/rp2_common/set_memory_locations.ld b/src/rp2_common/pico_standard_link/scripts/rp2_common/set_memory_locations.ld new file mode 100644 index 000000000..a9110eb59 --- /dev/null +++ b/src/rp2_common/pico_standard_link/scripts/rp2_common/set_memory_locations.ld @@ -0,0 +1,8 @@ +RAM_ORIGIN = DEFINED(RAM_ORIGIN) ? RAM_ORIGIN : RAM_ORIGIN_DEFAULT; +RAM_LENGTH = DEFINED(RAM_LENGTH) ? RAM_LENGTH : RAM_LENGTH_DEFAULT; +SCRATCH_X_ORIGIN = DEFINED(SCRATCH_X_ORIGIN) ? SCRATCH_X_ORIGIN : SCRATCH_X_ORIGIN_DEFAULT; +SCRATCH_X_LENGTH = DEFINED(SCRATCH_X_LENGTH) ? SCRATCH_X_LENGTH : SCRATCH_X_LENGTH_DEFAULT; +SCRATCH_Y_ORIGIN = DEFINED(SCRATCH_Y_ORIGIN) ? SCRATCH_Y_ORIGIN : SCRATCH_Y_ORIGIN_DEFAULT; +SCRATCH_Y_LENGTH = DEFINED(SCRATCH_Y_LENGTH) ? SCRATCH_Y_LENGTH : SCRATCH_Y_LENGTH_DEFAULT; +XIP_RAM_ORIGIN = DEFINED(XIP_RAM_ORIGIN) ? XIP_RAM_ORIGIN : XIP_RAM_ORIGIN_DEFAULT; +XIP_RAM_LENGTH = DEFINED(XIP_RAM_LENGTH) ? XIP_RAM_LENGTH : XIP_RAM_LENGTH_DEFAULT; From cad616728f80030b2fc424beef4a8621561b103e Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 2 Oct 2025 16:40:18 +0100 Subject: [PATCH 08/27] Initial non-secure support Non-secure side can successfully connect to WiFi --- .../include/boot/bootrom_constants.h | 8 + src/rp2_common/hardware_gpio/gpio.c | 16 +- .../hardware_gpio/include/hardware/gpio.h | 8 + src/rp2_common/pico_bootrom/CMakeLists.txt | 30 ++- src/rp2_common/pico_bootrom/bootrom.c | 206 +++++++++++++++++- .../pico_bootrom/include/pico/bootrom.h | 57 +++++ .../pico_cyw43_driver/cyw43_driver.c | 2 +- src/rp2_common/pico_rand/rand.c | 2 +- .../include/pico/runtime_init.h | 48 ++++ 9 files changed, 364 insertions(+), 13 deletions(-) diff --git a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h index e7fe6f63b..2d05b938d 100644 --- a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h +++ b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h @@ -341,4 +341,12 @@ typedef struct cflash_flags { #define CFLASH_OP_VALUE_READ _u(2) #define CFLASH_OP_MAX _u(2) +#ifndef __riscv +#define BOOTROM_API_CALLBACK_stdio_out_chars 0 +#define BOOTROM_API_CALLBACK_get_rand_64 1 +#define BOOTROM_API_CALLBACK_dma_allocate_unused_channel_for_nonsecure 2 +#define BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure 3 +#define BOOTROM_API_CALLBACK_clock_get_hz 4 +#endif + #endif diff --git a/src/rp2_common/hardware_gpio/gpio.c b/src/rp2_common/hardware_gpio/gpio.c index a5560bbb8..726305431 100644 --- a/src/rp2_common/hardware_gpio/gpio.c +++ b/src/rp2_common/hardware_gpio/gpio.c @@ -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; } diff --git a/src/rp2_common/hardware_gpio/include/hardware/gpio.h b/src/rp2_common/hardware_gpio/include/hardware/gpio.h index 3894acaa8..02613c99e 100644 --- a/src/rp2_common/hardware_gpio/include/hardware/gpio.h +++ b/src/rp2_common/hardware_gpio/include/hardware/gpio.h @@ -18,6 +18,14 @@ #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 diff --git a/src/rp2_common/pico_bootrom/CMakeLists.txt b/src/rp2_common/pico_bootrom/CMakeLists.txt index c7ac816f2..21b6219c0 100644 --- a/src/rp2_common/pico_bootrom/CMakeLists.txt +++ b/src/rp2_common/pico_bootrom/CMakeLists.txt @@ -9,8 +9,34 @@ 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_dma hardware_irq pico_stdio) # bootrom.c includes boot/picobin.h # bootrom_lock.c includes pico/runtime_init.h -target_link_libraries(pico_bootrom INTERFACE boot_picobin_headers pico_runtime_init_headers) \ No newline at end of file +target_link_libraries(pico_bootrom INTERFACE boot_picobin_headers pico_runtime_init_headers) + +function(pico_set_security_defines SECURE_TARGET NONSECURE_TARGET) + target_compile_definitions(${SECURE_TARGET} PRIVATE + PICO_SECURE=1 + ) + + target_compile_definitions(${NONSECURE_TARGET} PRIVATE + PICO_NONSECURE=1 + + # These all require secure access + PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET=1 + PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET=1 + PICO_RUNTIME_SKIP_INIT_EARLY_RESETS=1 + PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET=1 + PICO_RUNTIME_SKIP_INIT_BOOTROM_LOCKING_ENABLE=1 + PICO_RUNTIME_SKIP_INIT_POST_CLOCK_RESETS=1 + + # This will have been done by secure anyway + PICO_RUNTIME_SKIP_INIT_USB_POWER_DOWN=1 + ) + + foreach(arg IN LISTS ARGN) + target_compile_definitions(${SECURE_TARGET} PRIVATE ${arg}) + target_compile_definitions(${NONSECURE_TARGET} PRIVATE ${arg}) + endforeach() +endfunction() \ No newline at end of file diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index 766574802..bbcacb3db 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -10,6 +10,7 @@ #if !PICO_RP2040 #include "hardware/rcp.h" #endif +#include "pico/runtime_init.h" /// \tag::table_lookup[] @@ -196,4 +197,207 @@ int rom_pick_ab_partition_during_update(uint32_t *workarea_base, uint32_t workar return rc; } -#endif \ No newline at end of file + +#if PICO_SECURE || PICO_NONSECURE +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; +} + +#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, BOOTROM_API_CALLBACK_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, BOOTROM_API_CALLBACK_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, BOOTROM_API_CALLBACK_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, BOOTROM_API_CALLBACK_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_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK +#include +#include "hardware/clocks.h" + +int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn) { + switch (fn) { + #if PICO_ALLOW_NONSECURE_STDIO + case BOOTROM_API_CALLBACK_stdio_out_chars: { + stdio_put_string((char*)a, b, false, true); + stdio_flush(); + return 0; + } + #endif + #if PICO_ALLOW_NONSECURE_RAND + case BOOTROM_API_CALLBACK_get_rand_64: { + return get_rand_64(); + } + #endif + #if PICO_ALLOW_NONSECURE_DMA + case BOOTROM_API_CALLBACK_dma_allocate_unused_channel_for_nonsecure: { + return dma_allocate_unused_channel_for_nonsecure(); + } + #endif + #if PICO_ALLOW_NONSECURE_USER_IRQ + case BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure: { + return user_irq_claim_unused_for_nonsecure(); + } + #endif + case BOOTROM_API_CALLBACK_clock_get_hz: { + return clock_get_hz(a); + } + 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); +} +#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() { + for(uint i = 0; i < NUM_DMA_CHANNELS; i++) { + dma_channel_claim(i); + } + + for (uint i = 0; i < NUM_USER_IRQS; i++) { + user_irq_claim(FIRST_USER_IRQ + i); + } +} +#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_NONSECURE && !PICO_RUNTIME_NO_INIT_CLOCKS +#include "hardware/clocks.h" + +void runtime_init_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, BOOTROM_API_CALLBACK_clock_get_hz); + clock_set_reported_hz(i, hz); + } +} +#endif + +#endif // PICO_SECURE || PICO_NONSECURE + +#endif // !PICO_RP2040 diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index 4494ae1cf..d4447e495 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -1010,6 +1010,63 @@ 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_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, Highest number DMA channel 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 + +#endif + #define BOOT_TYPE_NORMAL 0 #define BOOT_TYPE_BOOTSEL 2 #define BOOT_TYPE_RAM_IMAGE 3 diff --git a/src/rp2_common/pico_cyw43_driver/cyw43_driver.c b/src/rp2_common/pico_cyw43_driver/cyw43_driver.c index 95e5da5e3..541033958 100644 --- a/src/rp2_common/pico_cyw43_driver/cyw43_driver.c +++ b/src/rp2_common/pico_cyw43_driver/cyw43_driver.c @@ -66,7 +66,7 @@ uint32_t cyw43_irq_init(__unused void *param) { #endif gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, cyw43_gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY); cyw43_set_irq_enabled(true); - irq_set_enabled(IO_IRQ_BANK0, true); + irq_set_enabled(DEFAULT_IO_IRQ_BANK0, true); return 0; } diff --git a/src/rp2_common/pico_rand/rand.c b/src/rp2_common/pico_rand/rand.c index 03b0e3d61..90c521bf7 100644 --- a/src/rp2_common/pico_rand/rand.c +++ b/src/rp2_common/pico_rand/rand.c @@ -325,7 +325,7 @@ static void initialise_rand(void) { spin_unlock(lock, save); } -uint64_t get_rand_64(void) { +uint64_t __weak get_rand_64(void) { if (!rng_initialised) { // Do not provide 'RNs' until the system has been initialised. Note: // The first initialisation can be quite time-consuming depending on diff --git a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h index c6ed4cf8e..22a658bc3 100644 --- a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h +++ b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h @@ -340,6 +340,54 @@ void runtime_init_boot_locks_reset(void); 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 + // 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 From 249b42287681670e756565916a93b136fd30f021 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 7 Oct 2025 11:45:25 +0100 Subject: [PATCH 09/27] Add nonsecure PIO support --- .../include/boot/bootrom_constants.h | 1 + src/rp2_common/pico_bootrom/CMakeLists.txt | 2 +- src/rp2_common/pico_bootrom/bootrom.c | 97 ++++++++++++++++++- .../pico_bootrom/include/pico/bootrom.h | 21 +++- .../pico_crt0/embedded_start_block.inc.S | 6 ++ .../include/pico/runtime_init.h | 16 +++ 6 files changed, 139 insertions(+), 4 deletions(-) diff --git a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h index 2d05b938d..000478f48 100644 --- a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h +++ b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h @@ -347,6 +347,7 @@ typedef struct cflash_flags { #define BOOTROM_API_CALLBACK_dma_allocate_unused_channel_for_nonsecure 2 #define BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure 3 #define BOOTROM_API_CALLBACK_clock_get_hz 4 +#define BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure 5 #endif #endif diff --git a/src/rp2_common/pico_bootrom/CMakeLists.txt b/src/rp2_common/pico_bootrom/CMakeLists.txt index 21b6219c0..7768005d2 100644 --- a/src/rp2_common/pico_bootrom/CMakeLists.txt +++ b/src/rp2_common/pico_bootrom/CMakeLists.txt @@ -9,7 +9,7 @@ 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 hardware_dma hardware_irq pico_stdio) +pico_mirrored_target_link_libraries(pico_bootrom INTERFACE pico_base hardware_boot_lock pico_flash hardware_dma hardware_irq pico_stdio hardware_pio) # bootrom.c includes boot/picobin.h # bootrom_lock.c includes pico/runtime_init.h diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index bbcacb3db..d5bc8d126 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -313,6 +313,62 @@ int user_irq_request_unused_from_secure(int num_irqs) { #endif // PICO_ALLOW_NONSECURE_USER_IRQ +#if PICO_ALLOW_NONSECURE_PIO +#include "hardware/pio.h" +#include "hardware/irq.h" +#include "hardware/structs/accessctrl.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, BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure); + if (pio < 0) return pio; + for (uint sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { + pio_sm_unclaim(pio_get_instance(pio), sm); + } + return pio; +} +#endif +#endif // PICO_ALLOW_NONSECURE_PIO + #if !PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK #include #include "hardware/clocks.h" @@ -340,6 +396,11 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ case BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure: { return user_irq_claim_unused_for_nonsecure(); } + #endif + #if PICO_ALLOW_NONSECURE_PIO + case BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure: { + return pio_claim_unused_pio_for_nonsecure(); + } #endif case BOOTROM_API_CALLBACK_clock_get_hz: { return clock_get_hz(a); @@ -363,6 +424,8 @@ static int __attribute__((naked)) rom_default_asm_callback() { 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 @@ -372,13 +435,23 @@ PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_rom_set_default_callback, PICO_RUNTI #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 @@ -386,10 +459,30 @@ void __weak runtime_init_nonsecure_claims() { PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_claims, PICO_RUNTIME_INIT_NONSECURE_CLAIMS); #endif +#if !PICO_RUNTIME_NO_INIT_NONSECURE_COPROCESSORS +#include "hardware/structs/m33.h" +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_NONSECURE && !PICO_RUNTIME_NO_INIT_CLOCKS #include "hardware/clocks.h" -void runtime_init_clocks() { +void runtime_init_clocks() { // override the default weak definition // 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, BOOTROM_API_CALLBACK_clock_get_hz); diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index d4447e495..8919ecf76 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -1030,7 +1030,7 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ #define PICO_ALLOW_NONSECURE_DMA 0 #endif -// PICO_CONFIG: PICO_NONSECURE_DMA_MAX_CHANNEL, Highest number DMA channel that can be allocated to non-secure use, type=int, default=NUM_DMA_CHANNELS, group=hardware_dma +// 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 @@ -1065,6 +1065,25 @@ int dma_request_unused_channels_from_secure(int num_channels); 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 + #endif #define BOOT_TYPE_NORMAL 0 diff --git a/src/rp2_common/pico_crt0/embedded_start_block.inc.S b/src/rp2_common/pico_crt0/embedded_start_block.inc.S index 4618a3a94..ace7d3b1d 100644 --- a/src/rp2_common/pico_crt0/embedded_start_block.inc.S +++ b/src/rp2_common/pico_crt0/embedded_start_block.inc.S @@ -62,6 +62,12 @@ embedded_block: PICOBIN_IMAGE_TYPE_EXE_CPU_AS_BITS(ARM) | \ PICOBIN_IMAGE_TYPE_EXE_CHIP_AS_BITS(RP2040) | \ CRT0_TBYB_FLAG +#elif PICO_NONSECURE +.hword PICOBIN_IMAGE_TYPE_IMAGE_TYPE_AS_BITS(EXE) | \ + PICOBIN_IMAGE_TYPE_EXE_SECURITY_AS_BITS(NS) | \ + PICOBIN_IMAGE_TYPE_EXE_CPU_AS_BITS(ARM) | \ + PICOBIN_IMAGE_TYPE_EXE_CHIP_AS_BITS(RP2350) | \ + CRT0_TBYB_FLAG #else .hword PICOBIN_IMAGE_TYPE_IMAGE_TYPE_AS_BITS(EXE) | \ PICOBIN_IMAGE_TYPE_EXE_SECURITY_AS_BITS(S) | \ diff --git a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h index 22a658bc3..63e6be93c 100644 --- a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h +++ b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h @@ -388,6 +388,22 @@ void runtime_init_bootrom_locking_enable(void); #define PICO_RUNTIME_NO_INIT_NONSECURE_STDIO !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 + // 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 From 25e2edd04e1248e5cd47cc09ac70c447eafaf346 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 7 Oct 2025 12:41:42 +0100 Subject: [PATCH 10/27] Add pads_bank0 helper functions for E3 --- .../include/boot/bootrom_constants.h | 4 + src/rp2_common/hardware_gpio/CMakeLists.txt | 6 +- src/rp2_common/hardware_gpio/gpio.c | 28 +++---- .../hardware_gpio/include/hardware/gpio.h | 13 +++- src/rp2_common/pico_bootrom/bootrom.c | 43 ++++++++++- .../pico_bootrom/include/pico/bootrom.h | 75 +++++++++++++++++++ .../pico_cyw43_driver/cyw43_bus_pio_spi.c | 4 +- src/rp2_common/pico_stdio_uart/stdio_uart.c | 4 +- 8 files changed, 155 insertions(+), 22 deletions(-) diff --git a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h index 000478f48..099f0c773 100644 --- a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h +++ b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h @@ -348,6 +348,10 @@ typedef struct cflash_flags { #define BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure 3 #define BOOTROM_API_CALLBACK_clock_get_hz 4 #define BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure 5 +#define BOOTROM_API_CALLBACK_pads_bank0_set_bits 6 +#define BOOTROM_API_CALLBACK_pads_bank0_clear_bits 7 +#define BOOTROM_API_CALLBACK_pads_bank0_write_masked 8 +#define BOOTROM_API_CALLBACK_pads_bank0_read 9 #endif #endif diff --git a/src/rp2_common/hardware_gpio/CMakeLists.txt b/src/rp2_common/hardware_gpio/CMakeLists.txt index 9ec04c992..6fd3f6b1c 100644 --- a/src/rp2_common/hardware_gpio/CMakeLists.txt +++ b/src/rp2_common/hardware_gpio/CMakeLists.txt @@ -1,2 +1,6 @@ pico_simple_hardware_target(gpio) -pico_mirrored_target_link_libraries(hardware_gpio INTERFACE hardware_irq) \ No newline at end of file +pico_mirrored_target_link_libraries(hardware_gpio INTERFACE hardware_irq) + +if (PICO_RP2350) + pico_mirrored_target_link_libraries(hardware_gpio INTERFACE pico_bootrom) +endif() \ No newline at end of file diff --git a/src/rp2_common/hardware_gpio/gpio.c b/src/rp2_common/hardware_gpio/gpio.c index 726305431..1ca9a0a83 100644 --- a/src/rp2_common/hardware_gpio/gpio.c +++ b/src/rp2_common/hardware_gpio/gpio.c @@ -27,7 +27,7 @@ static raw_irq_mask_type_t raw_irq_mask[NUM_CORES]; // Get the raw value from the pin, bypassing any muxing or overrides. int gpio_get_pad(uint gpio) { check_gpio_param(gpio); - hw_set_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS); + pads_bank0_set_bits(gpio, PADS_BANK0_GPIO0_IE_BITS); return (io_bank0_hw->io[gpio].status & IO_BANK0_GPIO0_STATUS_INFROMPAD_BITS) >> IO_BANK0_GPIO0_STATUS_INFROMPAD_LSB; } @@ -39,7 +39,7 @@ void gpio_set_function(uint gpio, gpio_function_t fn) { check_gpio_param(gpio); invalid_params_if(HARDWARE_GPIO, ((uint32_t)fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS); // Set input enable on, output disable off - hw_write_masked(&pads_bank0_hw->io[gpio], + pads_bank0_write_masked(gpio, PADS_BANK0_GPIO0_IE_BITS, PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS ); @@ -48,7 +48,7 @@ void gpio_set_function(uint gpio, gpio_function_t fn) { io_bank0_hw->io[gpio].ctrl = fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; #if HAS_PADS_BANK0_ISOLATION // Remove pad isolation now that the correct peripheral is in control of the pad - hw_clear_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_ISO_BITS); + pads_bank0_clear_bits(gpio, PADS_BANK0_GPIO0_ISO_BITS); #endif } /// \end::gpio_set_function[] @@ -62,8 +62,8 @@ gpio_function_t gpio_get_function(uint gpio) { // i.e. weak pull to whatever is current high/low state of GPIO. void gpio_set_pulls(uint gpio, bool up, bool down) { check_gpio_param(gpio); - hw_write_masked( - &pads_bank0_hw->io[gpio], + pads_bank0_write_masked( + gpio, (bool_to_bit(up) << PADS_BANK0_GPIO0_PUE_LSB) | (bool_to_bit(down) << PADS_BANK0_GPIO0_PDE_LSB), PADS_BANK0_GPIO0_PUE_BITS | PADS_BANK0_GPIO0_PDE_BITS ); @@ -106,20 +106,20 @@ void gpio_set_oeover(uint gpio, uint value) { void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) { check_gpio_param(gpio); if (enabled) - hw_set_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS); + pads_bank0_set_bits(gpio, PADS_BANK0_GPIO0_SCHMITT_BITS); else - hw_clear_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS); + pads_bank0_clear_bits(gpio, PADS_BANK0_GPIO0_SCHMITT_BITS); } bool gpio_is_input_hysteresis_enabled(uint gpio) { check_gpio_param(gpio); - return (pads_bank0_hw->io[gpio] & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0; + return (pads_bank0_read(gpio) & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0; } void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) { check_gpio_param(gpio); - hw_write_masked(&pads_bank0_hw->io[gpio], + pads_bank0_write_masked(gpio, (uint)slew << PADS_BANK0_GPIO0_SLEWFAST_LSB, PADS_BANK0_GPIO0_SLEWFAST_BITS ); @@ -127,7 +127,7 @@ void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) { enum gpio_slew_rate gpio_get_slew_rate(uint gpio) { check_gpio_param(gpio); - return (enum gpio_slew_rate)((pads_bank0_hw->io[gpio] + return (enum gpio_slew_rate)((pads_bank0_read(gpio) & PADS_BANK0_GPIO0_SLEWFAST_BITS) >> PADS_BANK0_GPIO0_SLEWFAST_LSB); } @@ -137,7 +137,7 @@ enum gpio_slew_rate gpio_get_slew_rate(uint gpio) { static_assert(PADS_BANK0_GPIO0_DRIVE_VALUE_8MA == GPIO_DRIVE_STRENGTH_8MA, ""); void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) { check_gpio_param(gpio); - hw_write_masked(&pads_bank0_hw->io[gpio], + pads_bank0_write_masked(gpio, (uint)drive << PADS_BANK0_GPIO0_DRIVE_LSB, PADS_BANK0_GPIO0_DRIVE_BITS ); @@ -145,7 +145,7 @@ void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) { enum gpio_drive_strength gpio_get_drive_strength(uint gpio) { check_gpio_param(gpio); - return (enum gpio_drive_strength)((pads_bank0_hw->io[gpio] + return (enum gpio_drive_strength)((pads_bank0_read(gpio) & PADS_BANK0_GPIO0_DRIVE_BITS) >> PADS_BANK0_GPIO0_DRIVE_LSB); } @@ -267,9 +267,9 @@ void gpio_debug_pins_init(void) { void gpio_set_input_enabled(uint gpio, bool enabled) { check_gpio_param(gpio); if (enabled) - hw_set_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS); + pads_bank0_set_bits(gpio, PADS_BANK0_GPIO0_IE_BITS); else - hw_clear_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS); + pads_bank0_clear_bits(gpio, PADS_BANK0_GPIO0_IE_BITS); } void gpio_init(uint gpio) { diff --git a/src/rp2_common/hardware_gpio/include/hardware/gpio.h b/src/rp2_common/hardware_gpio/include/hardware/gpio.h index 02613c99e..e6019a402 100644 --- a/src/rp2_common/hardware_gpio/include/hardware/gpio.h +++ b/src/rp2_common/hardware_gpio/include/hardware/gpio.h @@ -30,6 +30,15 @@ #include "hardware/gpio_coproc.h" #endif +#if 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 @@ -320,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. @@ -339,7 +348,7 @@ static inline void gpio_pull_down(uint gpio) { * \return true if the GPIO is pulled down */ static inline bool gpio_is_pulled_down(uint gpio) { - return (pads_bank0_hw->io[gpio] & PADS_BANK0_GPIO0_PDE_BITS) != 0; + return (pads_bank0_read(gpio) & PADS_BANK0_GPIO0_PDE_BITS) != 0; } /*! \brief Disable pulls on specified GPIO diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index d5bc8d126..a9238875b 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -199,6 +199,8 @@ int rom_pick_ab_partition_during_update(uint32_t *workarea_base, uint32_t workar } #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; @@ -316,7 +318,6 @@ int user_irq_request_unused_from_secure(int num_irqs) { #if PICO_ALLOW_NONSECURE_PIO #include "hardware/pio.h" #include "hardware/irq.h" -#include "hardware/structs/accessctrl.h" #if PICO_SECURE static int pio_claim_unused_pio_for_nonsecure(void) { @@ -369,9 +370,14 @@ int pio_request_unused_pio_from_secure(void) { #endif #endif // PICO_ALLOW_NONSECURE_PIO +#if PICO_ADD_NONSECURE_PADS_HELPER +#include "hardware/structs/pads_bank0.h" +#endif // PICO_ADD_NONSECURE_PADS_HELPER + #if !PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK #include #include "hardware/clocks.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) { switch (fn) { @@ -401,6 +407,41 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ case BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure: { return pio_claim_unused_pio_for_nonsecure(); } + #endif + #if PICO_ADD_NONSECURE_PADS_HELPER + case BOOTROM_API_CALLBACK_pads_bank0_set_bits: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + hw_set_bits(&pads_bank0_hw->io[a], b); + return 0; + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + } + case BOOTROM_API_CALLBACK_pads_bank0_clear_bits: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + hw_clear_bits(&pads_bank0_hw->io[a], b); + return 0; + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + return 0; + } + case BOOTROM_API_CALLBACK_pads_bank0_write_masked: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + hw_write_masked(&pads_bank0_hw->io[a], b, c); + return 0; + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + return 0; + } + case BOOTROM_API_CALLBACK_pads_bank0_read: { + if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { + return pads_bank0_hw->io[a]; + } else { + return BOOTROM_ERROR_NOT_PERMITTED; + } + } #endif case BOOTROM_API_CALLBACK_clock_get_hz: { return clock_get_hz(a); diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index 8919ecf76..f26b33dcb 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -1084,6 +1084,81 @@ int user_irq_request_unused_from_secure(int num_irqs); int pio_request_unused_pio_from_secure(void); #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 +#endif + +#if PICO_NONSECURE +/*! \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 +static inline int pads_bank0_set_bits(uint gpio, uint bits) { + return rom_secure_call(gpio, bits, 0, 0, BOOTROM_API_CALLBACK_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 +static inline int pads_bank0_clear_bits(uint gpio, uint bits) { + return rom_secure_call(gpio, bits, 0, 0, BOOTROM_API_CALLBACK_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 +static inline int pads_bank0_write_masked(uint gpio, uint bits, uint mask) { + return rom_secure_call(gpio, bits, mask, 0, BOOTROM_API_CALLBACK_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 +static inline int pads_bank0_read(uint gpio) { + return rom_secure_call(gpio, 0, 0, 0, BOOTROM_API_CALLBACK_pads_bank0_read); +} +#else +static inline int pads_bank0_read(uint gpio) { + return pads_bank0_hw->io[gpio]; +} +#endif +#endif + #endif #define BOOT_TYPE_NORMAL 0 diff --git a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c index 06d5beff3..5f13c76b3 100644 --- a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c +++ b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c @@ -123,11 +123,11 @@ int cyw43_spi_init(cyw43_int_t *self) { pio_sm_config config = SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC(bus_data->pio_offset); sm_config_set_clkdiv_int_frac8(&config, cyw43_pio_clock_div_int, cyw43_pio_clock_div_frac8); - hw_write_masked(&pads_bank0_hw->io[CYW43_PIN_WL_CLOCK], + pads_bank0_write_masked(CYW43_PIN_WL_CLOCK, (uint)PADS_DRIVE_STRENGTH << PADS_BANK0_GPIO0_DRIVE_LSB, PADS_BANK0_GPIO0_DRIVE_BITS ); - hw_write_masked(&pads_bank0_hw->io[CYW43_PIN_WL_CLOCK], + pads_bank0_write_masked(CYW43_PIN_WL_CLOCK, (uint)1 << PADS_BANK0_GPIO0_SLEWFAST_LSB, PADS_BANK0_GPIO0_SLEWFAST_BITS ); diff --git a/src/rp2_common/pico_stdio_uart/stdio_uart.c b/src/rp2_common/pico_stdio_uart/stdio_uart.c index 2e2619c11..0c69dbe2d 100644 --- a/src/rp2_common/pico_stdio_uart/stdio_uart.c +++ b/src/rp2_common/pico_stdio_uart/stdio_uart.c @@ -130,8 +130,8 @@ void stdio_uart_deinit_full(struct uart_inst *uart, int tx_pin, int rx_pin) { uart_deinit(uart_instance); #if HAS_PADS_BANK0_ISOLATION // Leave pads isolated - if (tx_pin >= 0) hw_set_bits(&pads_bank0_hw->io[tx_pin], PADS_BANK0_GPIO0_ISO_BITS); - if (rx_pin >= 0) hw_set_bits(&pads_bank0_hw->io[rx_pin], PADS_BANK0_GPIO0_ISO_BITS); + if (tx_pin >= 0) pads_bank0_set_bits(tx_pin, PADS_BANK0_GPIO0_ISO_BITS); + if (rx_pin >= 0) pads_bank0_set_bits(rx_pin, PADS_BANK0_GPIO0_ISO_BITS); #else ((void)tx_pin); ((void)rx_pin); From 52c22c74d13c46f7f7d1f7cca3e02a927136ce18 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 7 Oct 2025 14:55:28 +0100 Subject: [PATCH 11/27] Add pico_secure library with non-bootrom-related secure setup code --- src/cmake/rp2_common.cmake | 1 + .../hardware_gpio/include/hardware/gpio.h | 2 +- src/rp2_common/pico_bootrom/CMakeLists.txt | 26 ----- src/rp2_common/pico_bootrom/bootrom.c | 37 +----- .../pico_bootrom/include/pico/bootrom.h | 21 ++-- .../include/pico/runtime_init.h | 16 +++ src/rp2_common/pico_secure/BUILD.bazel | 14 +++ src/rp2_common/pico_secure/CMakeLists.txt | 62 +++++++++++ .../pico_secure/include/pico/secure.h | 52 +++++++++ src/rp2_common/pico_secure/secure.c | 105 ++++++++++++++++++ 10 files changed, 268 insertions(+), 68 deletions(-) create mode 100644 src/rp2_common/pico_secure/BUILD.bazel create mode 100644 src/rp2_common/pico_secure/CMakeLists.txt create mode 100644 src/rp2_common/pico_secure/include/pico/secure.h create mode 100644 src/rp2_common/pico_secure/secure.c diff --git a/src/cmake/rp2_common.cmake b/src/cmake/rp2_common.cmake index 273839f70..d947686b2 100644 --- a/src/cmake/rp2_common.cmake +++ b/src/cmake/rp2_common.cmake @@ -118,6 +118,7 @@ if (NOT PICO_BARE_METAL) if (NOT PICO_RISCV) pico_add_subdirectory(rp2_common/cmsis) + pico_add_subdirectory(rp2_common/pico_secure) endif() pico_add_subdirectory(rp2_common/tinyusb) pico_add_subdirectory(rp2_common/pico_stdio_usb) diff --git a/src/rp2_common/hardware_gpio/include/hardware/gpio.h b/src/rp2_common/hardware_gpio/include/hardware/gpio.h index e6019a402..e5816b5e3 100644 --- a/src/rp2_common/hardware_gpio/include/hardware/gpio.h +++ b/src/rp2_common/hardware_gpio/include/hardware/gpio.h @@ -30,7 +30,7 @@ #include "hardware/gpio_coproc.h" #endif -#if PICO_NONSECURE +#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) diff --git a/src/rp2_common/pico_bootrom/CMakeLists.txt b/src/rp2_common/pico_bootrom/CMakeLists.txt index 7768005d2..1c656ecb6 100644 --- a/src/rp2_common/pico_bootrom/CMakeLists.txt +++ b/src/rp2_common/pico_bootrom/CMakeLists.txt @@ -14,29 +14,3 @@ pico_mirrored_target_link_libraries(pico_bootrom INTERFACE pico_base hardware_bo # 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) - -function(pico_set_security_defines SECURE_TARGET NONSECURE_TARGET) - target_compile_definitions(${SECURE_TARGET} PRIVATE - PICO_SECURE=1 - ) - - target_compile_definitions(${NONSECURE_TARGET} PRIVATE - PICO_NONSECURE=1 - - # These all require secure access - PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET=1 - PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET=1 - PICO_RUNTIME_SKIP_INIT_EARLY_RESETS=1 - PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET=1 - PICO_RUNTIME_SKIP_INIT_BOOTROM_LOCKING_ENABLE=1 - PICO_RUNTIME_SKIP_INIT_POST_CLOCK_RESETS=1 - - # This will have been done by secure anyway - PICO_RUNTIME_SKIP_INIT_USB_POWER_DOWN=1 - ) - - foreach(arg IN LISTS ARGN) - target_compile_definitions(${SECURE_TARGET} PRIVATE ${arg}) - target_compile_definitions(${NONSECURE_TARGET} PRIVATE ${arg}) - endforeach() -endfunction() \ No newline at end of file diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index a9238875b..eee624c45 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -370,10 +370,6 @@ int pio_request_unused_pio_from_secure(void) { #endif #endif // PICO_ALLOW_NONSECURE_PIO -#if PICO_ADD_NONSECURE_PADS_HELPER -#include "hardware/structs/pads_bank0.h" -#endif // PICO_ADD_NONSECURE_PADS_HELPER - #if !PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK #include #include "hardware/clocks.h" @@ -411,33 +407,28 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ #if PICO_ADD_NONSECURE_PADS_HELPER case BOOTROM_API_CALLBACK_pads_bank0_set_bits: { if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { - hw_set_bits(&pads_bank0_hw->io[a], b); - return 0; + return pads_bank0_set_bits(a, b); } else { return BOOTROM_ERROR_NOT_PERMITTED; } } case BOOTROM_API_CALLBACK_pads_bank0_clear_bits: { if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { - hw_clear_bits(&pads_bank0_hw->io[a], b); - return 0; + return pads_bank0_clear_bits(a, b); } else { return BOOTROM_ERROR_NOT_PERMITTED; } - return 0; } case BOOTROM_API_CALLBACK_pads_bank0_write_masked: { if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { - hw_write_masked(&pads_bank0_hw->io[a], b, c); - return 0; + return pads_bank0_write_masked(a, b, c); } else { return BOOTROM_ERROR_NOT_PERMITTED; } - return 0; } case BOOTROM_API_CALLBACK_pads_bank0_read: { if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { - return pads_bank0_hw->io[a]; + return pads_bank0_read(a); } else { return BOOTROM_ERROR_NOT_PERMITTED; } @@ -500,26 +491,6 @@ void __weak runtime_init_nonsecure_claims() { PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_claims, PICO_RUNTIME_INIT_NONSECURE_CLAIMS); #endif -#if !PICO_RUNTIME_NO_INIT_NONSECURE_COPROCESSORS -#include "hardware/structs/m33.h" -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_NONSECURE && !PICO_RUNTIME_NO_INIT_CLOCKS #include "hardware/clocks.h" diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index f26b33dcb..b993e1140 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -21,6 +21,8 @@ #include #include "pico/bootrom/lock.h" #include "pico/flash.h" + +#include "hardware/structs/pads_bank0.h" // ROM FUNCTION SIGNATURES #if PICO_RP2040 @@ -1084,19 +1086,23 @@ int user_irq_request_unused_from_secure(int num_irqs); 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 +#define PICO_ADD_NONSECURE_PADS_HELPER PICO_RP2350A && PICO_RP2350_A2_SUPPORTED && PICO_ALLOW_NONSECURE_GPIO #endif -#if PICO_NONSECURE /*! \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 +#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, BOOTROM_API_CALLBACK_pads_bank0_set_bits); } @@ -1113,7 +1119,7 @@ static inline int pads_bank0_set_bits(uint gpio, uint bits) { * \param gpio the GPIO number * \param bits the bits to clear */ -#if PICO_ADD_NONSECURE_PADS_HELPER +#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, BOOTROM_API_CALLBACK_pads_bank0_clear_bits); } @@ -1131,7 +1137,7 @@ static inline int pads_bank0_clear_bits(uint gpio, uint bits) { * \param bits the bits to write * \param mask the mask */ -#if PICO_ADD_NONSECURE_PADS_HELPER +#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, BOOTROM_API_CALLBACK_pads_bank0_write_masked); } @@ -1148,7 +1154,7 @@ static inline int pads_bank0_write_masked(uint gpio, uint bits, uint mask) { * \param gpio the GPIO number * \return the bits read */ -#if PICO_ADD_NONSECURE_PADS_HELPER +#if PICO_ADD_NONSECURE_PADS_HELPER && PICO_NONSECURE static inline int pads_bank0_read(uint gpio) { return rom_secure_call(gpio, 0, 0, 0, BOOTROM_API_CALLBACK_pads_bank0_read); } @@ -1157,9 +1163,8 @@ static inline int pads_bank0_read(uint gpio) { return pads_bank0_hw->io[gpio]; } #endif -#endif -#endif +#endif // ifndef __riscv #define BOOT_TYPE_NORMAL 0 #define BOOT_TYPE_BOOTSEL 2 diff --git a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h index 63e6be93c..fab033e78 100644 --- a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h +++ b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h @@ -404,6 +404,22 @@ void runtime_init_bootrom_locking_enable(void); #define PICO_RUNTIME_NO_INIT_NONSECURE_COPROCESSORS !PICO_SECURE #endif +// ------------------------------ +// Initialise non-secure accessctrl +// ------------------------------ +// PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_NONSECURE_ACCESSCTRL_AND_IRQS, Skip calling of `runtime_init_nonsecure_accessctrl_and_irqs` function during runtime init, type=bool, default=0, group=pico_runtime_init +#ifndef PICO_RUNTIME_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +#define PICO_RUNTIME_INIT_NONSECURE_ACCESSCTRL_AND_IRQS "00220" +#endif + +#ifndef PICO_RUNTIME_SKIP_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +#define PICO_RUNTIME_SKIP_INIT_NONSECURE_ACCESSCTRL_AND_IRQS !PICO_SECURE +#endif + +#ifndef PICO_RUNTIME_NO_INIT_NONSECURE_ACCESSCTRL_AND_IRQS +#define PICO_RUNTIME_NO_INIT_NONSECURE_ACCESSCTRL_AND_IRQS !PICO_SECURE +#endif + // PICO_RUNTIME_INIT_MUTEX is registered automatically by pico_sync // PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_MUTEX, Skip calling of `runtime_init_mutex` function during runtime init, type=bool, default=0, group=pico_runtime_init // PICO_CONFIG: PICO_RUNTIME_NO_INIT_MUTEX, Do not include SDK implementation of `runtime_init_mutex` function, type=bool, default=0, group=pico_runtime_init diff --git a/src/rp2_common/pico_secure/BUILD.bazel b/src/rp2_common/pico_secure/BUILD.bazel new file mode 100644 index 000000000..cba5ac3c8 --- /dev/null +++ b/src/rp2_common/pico_secure/BUILD.bazel @@ -0,0 +1,14 @@ +load("//bazel:defs.bzl", "compatible_with_rp2") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "pico_secure", + srcs = ["secure.c"], + hdrs = ["include/pico/secure.h"], + includes = ["include"], + target_compatible_with = compatible_with_rp2(), + deps = [ + "//src/rp2_common/pico_bootrom", + ], +) diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt new file mode 100644 index 000000000..aff05ed5b --- /dev/null +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -0,0 +1,62 @@ +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 + pico_bootrom) + + function(pico_set_security_defines SECURE_TARGET NONSECURE_TARGET) + set(options + ALLOW_NONSECURE_STDIO + ALLOW_NONSECURE_RAND + ALLOW_NONSECURE_DMA + ALLOW_NONSECURE_USER_IRQ + ALLOW_NONSECURE_PIO + ALLOW_NONSECURE_GPIO + ) + set(oneValueArgs + ASSIGN_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 + + # These all require secure access + PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET=1 + PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET=1 + PICO_RUNTIME_SKIP_INIT_EARLY_RESETS=1 + PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET=1 + PICO_RUNTIME_SKIP_INIT_BOOTROM_LOCKING_ENABLE=1 + PICO_RUNTIME_SKIP_INIT_POST_CLOCK_RESETS=1 + + # This will have been done by secure anyway + PICO_RUNTIME_SKIP_INIT_USB_POWER_DOWN=1 + ) + + foreach(arg IN LISTS options) + if (OPTS_${arg}) + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_${arg}=1) + target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_${arg}=1) + endif() + endforeach() + + if (OPTS_ASSIGN_NONSECURE_TIMER) + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_ASSIGN_NONSECURE_TIMER=${OPTS_ASSIGN_NONSECURE_TIMER}) + target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_DEFAULT_TIMER=${OPTS_ASSIGN_NONSECURE_TIMER}) + endif() + endfunction() +endif() + + + diff --git a/src/rp2_common/pico_secure/include/pico/secure.h b/src/rp2_common/pico_secure/include/pico/secure.h new file mode 100644 index 000000000..7bbf442fb --- /dev/null +++ b/src/rp2_common/pico_secure/include/pico/secure.h @@ -0,0 +1,52 @@ +/* + * 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); + +/*! \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); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c new file mode 100644 index 000000000..7486241e4 --- /dev/null +++ b/src/rp2_common/pico_secure/secure.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/secure.h" +#include "pico/runtime_init.h" + +#include "hardware/timer.h" +#include "hardware/irq.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) { + __dmb(); + + if (enabled) + hw_set_bits(&sau_hw->ctrl, M33_SAU_CTRL_ENABLE_BITS); + else + hw_clear_bits(&sau_hw->ctrl, M33_SAU_CTRL_ENABLE_BITS); + + __dsb(); + __isb(); +} + + +#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() { + #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 +} +#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 From 021b00fbb585d48c7c50dbc4961538fa9bea89e3 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 7 Oct 2025 15:55:36 +0100 Subject: [PATCH 12/27] Add secure hardfault handler function --- .../pico_secure/include/pico/secure.h | 10 +++ src/rp2_common/pico_secure/secure.c | 71 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/rp2_common/pico_secure/include/pico/secure.h b/src/rp2_common/pico_secure/include/pico/secure.h index 7bbf442fb..47b7c6a64 100644 --- a/src/rp2_common/pico_secure/include/pico/secure.h +++ b/src/rp2_common/pico_secure/include/pico/secure.h @@ -46,6 +46,16 @@ void secure_sau_configure_region(uint region, uint32_t base, uint32_t limit, boo 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 diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 7486241e4..749ed25a7 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -4,11 +4,13 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include #include "pico/secure.h" #include "pico/runtime_init.h" #include "hardware/timer.h" #include "hardware/irq.h" +#include "hardware/exception.h" #include "hardware/structs/scb.h" #include "hardware/structs/sau.h" @@ -56,6 +58,75 @@ void secure_sau_set_enabled(bool enabled) { } +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 From 3d47f3e26b101a03d633a4afc8104d18345fb8b9 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 7 Oct 2025 16:52:09 +0100 Subject: [PATCH 13/27] Add rom_get_owned_partition and rom_roll_qmi_to_partition functions Make rolling XIP to the non-secure partition easier --- .../hardware_flash/include/hardware/flash.h | 9 ++- src/rp2_common/pico_bootrom/bootrom.c | 73 +++++++++++++++++++ .../pico_bootrom/include/pico/bootrom.h | 32 +++++++- 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/rp2_common/hardware_flash/include/hardware/flash.h b/src/rp2_common/hardware_flash/include/hardware/flash.h index 2bb5d5ae3..b951adae9 100644 --- a/src/rp2_common/hardware_flash/include/hardware/flash.h +++ b/src/rp2_common/hardware_flash/include/hardware/flash.h @@ -42,9 +42,12 @@ #define PARAM_ASSERTIONS_ENABLED_HARDWARE_FLASH 0 #endif #endif -#define FLASH_PAGE_SIZE (1u << 8) -#define FLASH_SECTOR_SIZE (1u << 12) -#define FLASH_BLOCK_SIZE (1u << 16) +#define FLASH_PAGE_SHIFT 8u +#define FLASH_PAGE_SIZE (1u << FLASH_PAGE_SHIFT) +#define FLASH_SECTOR_SHIFT 12u +#define FLASH_SECTOR_SIZE (1u << FLASH_SECTOR_SHIFT) +#define FLASH_BLOCK_SHIFT 16u +#define FLASH_BLOCK_SIZE (1u << FLASH_BLOCK_SHIFT) #ifndef FLASH_UNIQUE_ID_SIZE_BYTES #define FLASH_UNIQUE_ID_SIZE_BYTES 8 diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index eee624c45..2e485e731 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -9,6 +9,8 @@ #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" @@ -198,6 +200,77 @@ int rom_pick_ab_partition_during_update(uint32_t *workarea_base, uint32_t workar return rc; } +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" diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index b993e1140..19077ce8d 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -638,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 @@ -800,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 From 326e945641ef15aa8726496d788ba39cbeeeb3a2 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 7 Oct 2025 17:12:32 +0100 Subject: [PATCH 14/27] Tidy up runtime init --- src/rp2_common/pico_bootrom/bootrom.c | 9 ++++-- .../pico_runtime/include/pico/runtime.h | 5 +++ .../include/pico/runtime_init.h | 32 ++++++++++++++++--- src/rp2_common/pico_secure/CMakeLists.txt | 11 ------- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index 2e485e731..84f01065f 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -564,10 +564,10 @@ void __weak runtime_init_nonsecure_claims() { PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_claims, PICO_RUNTIME_INIT_NONSECURE_CLAIMS); #endif -#if PICO_NONSECURE && !PICO_RUNTIME_NO_INIT_CLOCKS +#if !PICO_RUNTIME_NO_INIT_NONSECURE_CLOCKS #include "hardware/clocks.h" -void runtime_init_clocks() { // override the default weak definition +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, BOOTROM_API_CALLBACK_clock_get_hz); @@ -576,6 +576,11 @@ void runtime_init_clocks() { // override the default weak definition } #endif +#if !PICO_RUNTIME_SKIP_INIT_NONSECURE_CLOCKS +PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_clocks, PICO_RUNTIME_INIT_NONSECURE_CLOCKS); +#endif + + #endif // PICO_SECURE || PICO_NONSECURE #endif // !PICO_RP2040 diff --git a/src/rp2_common/pico_runtime/include/pico/runtime.h b/src/rp2_common/pico_runtime/include/pico/runtime.h index 35d871d92..84e78a36a 100644 --- a/src/rp2_common/pico_runtime/include/pico/runtime.h +++ b/src/rp2_common/pico_runtime/include/pico/runtime.h @@ -58,7 +58,12 @@ void runtime_run_per_core_initializers(void); #define PICO_RUNTIME_INIT_FUNC(func, priority_string) __pre_init func, priority_string #endif #endif +#if PICO_NONSECURE +// hw init cannot be done by non-secure +#define PICO_RUNTIME_INIT_FUNC_HW(func, priority_string) +#else #define PICO_RUNTIME_INIT_FUNC_HW(func, priority_string) PICO_RUNTIME_INIT_FUNC(func, priority_string) +#endif #define PICO_RUNTIME_INIT_FUNC_RUNTIME(func, priority_string) PICO_RUNTIME_INIT_FUNC(func, priority_string) // priority strings are of the form 00000->99999; we want the per core stuff all at the end, so prefix with ZZZZZ which is clearly after 99999 #define PICO_RUNTIME_INIT_FUNC_PER_CORE(func, priority_string) PICO_RUNTIME_INIT_FUNC(func, "ZZZZZ." priority_string) diff --git a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h index fab033e78..533ddc9a3 100644 --- a/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h +++ b/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h @@ -64,13 +64,13 @@ extern "C" { #endif #ifndef PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET -#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) +#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) || PICO_NONSECURE #define PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET 1 #endif #endif #ifndef PICO_RUNTIME_NO_INIT_BOOTROM_RESET -#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) +#if PICO_RP2040 || (!LIB_PICO_MULTICORE && PICO_NO_FLASH) || PICO_NONSECURE #define PICO_RUNTIME_NO_INIT_BOOTROM_RESET 1 #endif #endif @@ -89,13 +89,13 @@ void runtime_init_bootrom_reset(void); // PICO_CONFIG: PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET, Skip calling of `runtime_init_per_core_bootrom_reset` function during per-core init, type=bool, default=1 on RP2040, group=pico_runtime_init // PICO_CONFIG: PICO_RUNTIME_NO_INIT_PER_CORE_BOOTROM_RESET, Do not include SDK implementation of `runtime_init_per_core_bootrom_reset` function, type=bool, default=1 on RP2040, group=pico_runtime_init #ifndef PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET -#if PICO_RP2040 +#if PICO_RP2040 || PICO_NONSECURE #define PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET 1 #endif #endif #ifndef PICO_RUNTIME_NO_INIT_PER_CORE_BOOTROM_RESET -#if PICO_RP2040 +#if PICO_RP2040 || PICO_NONSECURE #define PICO_RUNTIME_NO_INIT_PER_CORE_BOOTROM_RESET 1 #endif #endif @@ -317,8 +317,12 @@ void runtime_init_spin_locks_reset(void); #endif #ifndef PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET +#if PICO_NONSECURE +#define PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET 1 +#else #define PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET 0 #endif +#endif #ifndef __ASSEMBLER__ void runtime_init_boot_locks_reset(void); #endif @@ -333,8 +337,12 @@ 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); @@ -388,6 +396,22 @@ void runtime_init_bootrom_locking_enable(void); #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 // ------------------------------ diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index aff05ed5b..0c18c47de 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -31,17 +31,6 @@ if (NOT TARGET pico_secure) target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_NONSECURE=1 - - # These all require secure access - PICO_RUNTIME_SKIP_INIT_BOOTROM_RESET=1 - PICO_RUNTIME_SKIP_INIT_PER_CORE_BOOTROM_RESET=1 - PICO_RUNTIME_SKIP_INIT_EARLY_RESETS=1 - PICO_RUNTIME_SKIP_INIT_BOOT_LOCKS_RESET=1 - PICO_RUNTIME_SKIP_INIT_BOOTROM_LOCKING_ENABLE=1 - PICO_RUNTIME_SKIP_INIT_POST_CLOCK_RESETS=1 - - # This will have been done by secure anyway - PICO_RUNTIME_SKIP_INIT_USB_POWER_DOWN=1 ) foreach(arg IN LISTS options) From 4c3543e4e5b52f0d17ece29ea6a7e5abc3cbc843 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 7 Oct 2025 18:21:00 +0100 Subject: [PATCH 15/27] Add nonsecure USB support --- .../include/boot/bootrom_constants.h | 3 ++ .../hardware_resets/include/hardware/resets.h | 4 +++ src/rp2_common/pico_bootrom/bootrom.c | 20 ++++++++++- .../pico_bootrom/include/pico/bootrom.h | 33 +++++++++++++++++++ src/rp2_common/pico_secure/CMakeLists.txt | 7 ++++ src/rp2_common/pico_secure/secure.c | 6 ++++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h index 099f0c773..79f45e0d7 100644 --- a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h +++ b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h @@ -352,6 +352,9 @@ typedef struct cflash_flags { #define BOOTROM_API_CALLBACK_pads_bank0_clear_bits 7 #define BOOTROM_API_CALLBACK_pads_bank0_write_masked 8 #define BOOTROM_API_CALLBACK_pads_bank0_read 9 +#define BOOTROM_API_CALLBACK_reset_block_reg_mask 10 +#define BOOTROM_API_CALLBACK_unreset_block_reg_mask 11 +#define BOOTROM_API_CALLBACK_unreset_block_reg_mask_wait_blocking 12 #endif #endif diff --git a/src/rp2_common/hardware_resets/include/hardware/resets.h b/src/rp2_common/hardware_resets/include/hardware/resets.h index f75775717..d89163710 100644 --- a/src/rp2_common/hardware_resets/include/hardware/resets.h +++ b/src/rp2_common/hardware_resets/include/hardware/resets.h @@ -106,6 +106,9 @@ extern "C" { #endif +#if PICO_NONSECURE +#include "pico/bootrom.h" +#else static __force_inline void reset_block_reg_mask(io_rw_32 *reset, uint32_t mask) { hw_set_bits(reset, mask); } @@ -119,6 +122,7 @@ static __force_inline void unreset_block_reg_mask_wait_blocking(io_rw_32 *reset, while (~*reset_done & mask) tight_loop_contents(); } +#endif /// \tag::reset_funcs[] diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index 84f01065f..cc29cf7b4 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -446,6 +446,7 @@ int pio_request_unused_pio_from_secure(void) { #if !PICO_RUNTIME_NO_INIT_BOOTROM_API_CALLBACK #include #include "hardware/clocks.h" +#include "hardware/resets.h" #include "hardware/structs/accessctrl.h" int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn) { @@ -454,7 +455,7 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ case BOOTROM_API_CALLBACK_stdio_out_chars: { stdio_put_string((char*)a, b, false, true); stdio_flush(); - return 0; + return BOOTROM_OK; } #endif #if PICO_ALLOW_NONSECURE_RAND @@ -510,6 +511,23 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ case BOOTROM_API_CALLBACK_clock_get_hz: { return clock_get_hz(a); } + #if PICO_ALLOW_NONSECURE_RESETS + case BOOTROM_API_CALLBACK_reset_block_reg_mask: { + if (b & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; + reset_block_reg_mask((volatile io_rw_32 *)a, b); + return BOOTROM_OK; + } + case BOOTROM_API_CALLBACK_unreset_block_reg_mask: { + if (b & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; + unreset_block_reg_mask((volatile io_rw_32 *)a, b); + return BOOTROM_OK; + } + case BOOTROM_API_CALLBACK_unreset_block_reg_mask_wait_blocking: { + if (c & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; + unreset_block_reg_mask_wait_blocking((volatile io_rw_32 *)a, (const volatile io_ro_32 *)b, c); + return BOOTROM_OK; + } + #endif default: { printf("%d is not a supported rom function\n", fn); return BOOTROM_ERROR_INVALID_ARG; diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index 19077ce8d..ee550d06a 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -1194,6 +1194,39 @@ static inline int pads_bank0_read(uint 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(io_rw_32 *reset, uint32_t mask) { + return rom_secure_call(reset, mask, 0, 0, BOOTROM_API_CALLBACK_reset_block_reg_mask); +} +static inline int unreset_block_reg_mask(io_rw_32 *reset, uint32_t mask) { + return rom_secure_call(reset, mask, 0, 0, BOOTROM_API_CALLBACK_unreset_block_reg_mask); +} +static inline int unreset_block_reg_mask_wait_blocking(io_rw_32 *reset, io_ro_32 *reset_done, uint32_t mask) { + return rom_secure_call(reset, reset_done, mask, 0, BOOTROM_API_CALLBACK_unreset_block_reg_mask_wait_blocking); +} +#endif + #endif // ifndef __riscv #define BOOT_TYPE_NORMAL 0 diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index 0c18c47de..45ebfdb03 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -16,6 +16,8 @@ if (NOT TARGET pico_secure) ALLOW_NONSECURE_USER_IRQ ALLOW_NONSECURE_PIO ALLOW_NONSECURE_GPIO + ALLOW_NONSECURE_USB + ALLOW_NONSECURE_RESETS ) set(oneValueArgs ASSIGN_NONSECURE_TIMER @@ -32,6 +34,11 @@ if (NOT TARGET pico_secure) target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_NONSECURE=1 ) + + # Options that require resets + if ((NOT OPTS_ALLOW_NONSECURE_RESETS) AND OPTS_ALLOW_NONSECURE_USB) + set(OPTS_ALLOW_NONSECURE_RESETS 1) + endif() foreach(arg IN LISTS options) if (OPTS_${arg}) diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 749ed25a7..e34857733 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -168,6 +168,12 @@ void __weak runtime_init_nonsecure_accessctrl_and_irqs() { 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 From 3326a5fb862a1eb165b32c00571b23fb8f6f9c5c Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 8 Oct 2025 11:07:30 +0100 Subject: [PATCH 16/27] Add CMake function docs --- src/cmake/rp2_common.cmake | 2 +- src/rp2_common/pico_secure/CMakeLists.txt | 57 +++++++++++++---------- tools/CMakeLists.txt | 37 +++++++++++++++ 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/src/cmake/rp2_common.cmake b/src/cmake/rp2_common.cmake index d947686b2..dacac3879 100644 --- a/src/cmake/rp2_common.cmake +++ b/src/cmake/rp2_common.cmake @@ -110,6 +110,7 @@ if (NOT PICO_BARE_METAL) if (PICO_COMBINED_DOCS OR NOT PICO_RP2040) pico_add_subdirectory(rp2_common/pico_sha256) + pico_add_subdirectory(rp2_common/pico_secure) endif() pico_add_subdirectory(rp2_common/pico_stdio_semihosting) @@ -118,7 +119,6 @@ if (NOT PICO_BARE_METAL) if (NOT PICO_RISCV) pico_add_subdirectory(rp2_common/cmsis) - pico_add_subdirectory(rp2_common/pico_secure) endif() pico_add_subdirectory(rp2_common/tinyusb) pico_add_subdirectory(rp2_common/pico_stdio_usb) diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index 45ebfdb03..08e865d9a 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -8,20 +8,32 @@ if (NOT TARGET pico_secure) pico_mirrored_target_link_libraries(pico_secure INTERFACE pico_bootrom) - function(pico_set_security_defines SECURE_TARGET NONSECURE_TARGET) - set(options - ALLOW_NONSECURE_STDIO - ALLOW_NONSECURE_RAND - ALLOW_NONSECURE_DMA - ALLOW_NONSECURE_USER_IRQ - ALLOW_NONSECURE_PIO - ALLOW_NONSECURE_GPIO - ALLOW_NONSECURE_USB - ALLOW_NONSECURE_RESETS - ) - set(oneValueArgs - ASSIGN_NONSECURE_TIMER - ) + + # pico_set_security_options(SECURE_TARGET NONSECURE_TARGET ...) + # \brief_nodesc\ Set matching security options for a secure and non-secure target + # + # Set matching security options for a secure and non-secure target, so they have a compatible set of features. + # + # Also sets PICO_SECURE=1 and PICO_NONSECURE=1 on the secure and non-secure targets respectively, along with + # any other required defines (eg PICO_USE_STACK_GUARDS=1 on the secure target). + # + # The options are: + # - STDIO: Allow non-secure to use secure stdio + # - RAND: Allow non-secure to get random numbers + # - DMA: Allow non-secure to request DMA channels + # - USER_IRQ: Allow non-secure to request user IRQs + # - PIO: Allow non-secure to request PIOs + # - GPIO: Allow non-secure to access GPIOs assigned to non-secure (eg with gpio_assign_to_ns) + # - USB: Allow non-secure to access USB + # - RESETS: Allow non-secure to access resets specified by PICO_ALLOW_NONSECURE_RESETS_MASK (automatically set if USB is set) + # - NONSECURE_TIMER : Assign specified timer to non-secure + # + # \param\ SECURE_TARGET The secure target + # \param\ NONSECURE_TARGET The non-secure target + # \param\ OPTIONS The options to set + function(pico_set_security_options SECURE_TARGET NONSECURE_TARGET) + set(options STDIO RAND DMA USER_IRQ PIO GPIO USB RESETS) + set(oneValueArgs NONSECURE_TIMER) cmake_parse_arguments(PARSE_ARGV 2 OPTS "${options}" "${oneValueArgs}" "") target_compile_definitions(${SECURE_TARGET} PRIVATE @@ -36,23 +48,20 @@ if (NOT TARGET pico_secure) ) # Options that require resets - if ((NOT OPTS_ALLOW_NONSECURE_RESETS) AND OPTS_ALLOW_NONSECURE_USB) - set(OPTS_ALLOW_NONSECURE_RESETS 1) + 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_${arg}=1) - target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_${arg}=1) + 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_ASSIGN_NONSECURE_TIMER) - target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_ASSIGN_NONSECURE_TIMER=${OPTS_ASSIGN_NONSECURE_TIMER}) - target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_DEFAULT_TIMER=${OPTS_ASSIGN_NONSECURE_TIMER}) + 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() endif() - - - diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5a6795ef2..2b06cbb69 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -742,3 +742,40 @@ function(picotool_postprocess_binary TARGET) endif() endif() endfunction() + + +# pico_concatenate_uf2_outputs(COMBINED_TARGET ...) +# \brief_nodesc\ Concatenate UF2 outputs into a single UF2 file +# +# Concatenate UF2 outputs from multiple targets into a single UF2 file, in the order they're passed to the function +# +# This can be used in conjunction with a partition table with no_reboot_on_uf2_download set on some partitions, +# to allow loading multiple partitions with a single UF2 file. For example, with this partition table you could concatenate +# rp2350-arm-ns and rp2350-arm-s binaries into a single UF2 file for loading into the main and owned partitions in one shot: +# ``` +# partitions: +# 0(A) uf2 { 'rp2350-arm-s' } +# 1(B w/ 0) uf2 { 'rp2350-arm-s' } +# 2(A ob/ 0) uf2 { 'rp2350-arm-ns' }, no_reboot_on_uf2_download, ab_non_bootable_owner_affinity +# 3(B w/ 2) uf2 { 'rp2350-arm-ns' }, no_reboot_on_uf2_download, ab_non_bootable_owner_affinity +# ``` +# +# NOTE: This does not modify the UF2 data structures, so the chip will still see multiple UF2 files, +# this just concatenates them into a single file on the host. +# +# \param\ COMBINED_TARGET The name of the combined UF2 target +# \param\ TARGETS The targets to combine +function(pico_concatenate_uf2_outputs COMBINED_TARGET) + list(TRANSFORM ARGN PREPEND ${CMAKE_CURRENT_BINARY_DIR}/ OUTPUT_VARIABLE UF2S) + list(TRANSFORM UF2S APPEND .uf2) + + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_TARGET}.uf2 + COMMAND ${CMAKE_COMMAND} -E cat + ${UF2S} + > ${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_TARGET}.uf2 + DEPENDS ${ARGN} + COMMAND_EXPAND_LISTS) + + add_custom_target(${COMBINED_TARGET} ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_TARGET}.uf2) +endfunction() \ No newline at end of file From c606caf65e7f3e8b652d926629d68dc7b6ab8c21 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 8 Oct 2025 12:23:08 +0100 Subject: [PATCH 17/27] Fix libraries --- src/rp2_common/pico_bootrom/CMakeLists.txt | 2 +- src/rp2_common/pico_secure/CMakeLists.txt | 1 + src/rp2_common/pico_secure/secure.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/rp2_common/pico_bootrom/CMakeLists.txt b/src/rp2_common/pico_bootrom/CMakeLists.txt index 1c656ecb6..9e29fa9ca 100644 --- a/src/rp2_common/pico_bootrom/CMakeLists.txt +++ b/src/rp2_common/pico_bootrom/CMakeLists.txt @@ -9,7 +9,7 @@ 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 hardware_dma hardware_irq pico_stdio hardware_pio) +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 diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index 08e865d9a..47543cee6 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -6,6 +6,7 @@ if (NOT TARGET pico_secure) ${CMAKE_CURRENT_LIST_DIR}/secure.c) pico_mirrored_target_link_libraries(pico_secure INTERFACE + hardware_exception pico_bootrom) diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index e34857733..125cfd90a 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -46,6 +46,7 @@ void secure_sau_configure_region(uint region, uint32_t base, uint32_t limit, boo void secure_sau_set_enabled(bool enabled) { + uint32_t save = save_and_disable_interrupts(); __dmb(); if (enabled) @@ -55,6 +56,7 @@ void secure_sau_set_enabled(bool enabled) { __dsb(); __isb(); + restore_interrupts_from_disabled(save); } From 6ef5d37d9940d68beb35c26fa69a5271ceeef223 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 12 Nov 2025 10:11:51 +0000 Subject: [PATCH 18/27] Improve secure call defines --- .../include/boot/bootrom_constants.h | 48 ++++++++++++++----- src/rp2_common/pico_bootrom/bootrom.c | 38 +++++++-------- .../pico_bootrom/include/pico/bootrom.h | 14 +++--- 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h index 79f45e0d7..a538f9a4c 100644 --- a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h +++ b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h @@ -342,19 +342,41 @@ typedef struct cflash_flags { #define CFLASH_OP_MAX _u(2) #ifndef __riscv -#define BOOTROM_API_CALLBACK_stdio_out_chars 0 -#define BOOTROM_API_CALLBACK_get_rand_64 1 -#define BOOTROM_API_CALLBACK_dma_allocate_unused_channel_for_nonsecure 2 -#define BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure 3 -#define BOOTROM_API_CALLBACK_clock_get_hz 4 -#define BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure 5 -#define BOOTROM_API_CALLBACK_pads_bank0_set_bits 6 -#define BOOTROM_API_CALLBACK_pads_bank0_clear_bits 7 -#define BOOTROM_API_CALLBACK_pads_bank0_write_masked 8 -#define BOOTROM_API_CALLBACK_pads_bank0_read 9 -#define BOOTROM_API_CALLBACK_reset_block_reg_mask 10 -#define BOOTROM_API_CALLBACK_unreset_block_reg_mask 11 -#define BOOTROM_API_CALLBACK_unreset_block_reg_mask_wait_blocking 12 +/*! \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_reg_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'R', 'M') +#define SECURE_CALL_unreset_block_reg_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'M') +#define SECURE_CALL_unreset_block_reg_mask_wait_blocking SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'W') #endif #endif diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index cc29cf7b4..780f486c6 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -294,7 +294,7 @@ int __noinline rom_secure_call(uint a, uint b, uint c, uint d, uint func) { #if PICO_NONSECURE static void stdio_nonsecure_out_chars(const char *buf, int length) { - rom_secure_call((uint32_t)buf, length, 0, 0, BOOTROM_API_CALLBACK_stdio_out_chars); + rom_secure_call((uint32_t)buf, length, 0, 0, SECURE_CALL_stdio_out_chars); } int stdio_nonsecure_in_chars(char *buf, int length) { @@ -332,7 +332,7 @@ PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_stdio, PICO_RUNTIME_INIT_N #if PICO_NONSECURE // override the weak definition uint64_t get_rand_64(void) { - return rom_secure_call(0, 0, 0, 0, BOOTROM_API_CALLBACK_get_rand_64); + return rom_secure_call(0, 0, 0, 0, SECURE_CALL_get_rand_64); } #endif #endif // PICO_ALLOW_NONSECURE_RAND @@ -355,7 +355,7 @@ static int dma_allocate_unused_channel_for_nonsecure(void) { 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, BOOTROM_API_CALLBACK_dma_allocate_unused_channel_for_nonsecure); + 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); } @@ -378,7 +378,7 @@ static int user_irq_claim_unused_for_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, BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure); + 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); } @@ -433,7 +433,7 @@ static int pio_claim_unused_pio_for_nonsecure(void) { } #elif PICO_NONSECURE int pio_request_unused_pio_from_secure(void) { - int pio = rom_secure_call(0, 0, 0, 0, BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure); + 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); @@ -452,55 +452,55 @@ int pio_request_unused_pio_from_secure(void) { int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn) { switch (fn) { #if PICO_ALLOW_NONSECURE_STDIO - case BOOTROM_API_CALLBACK_stdio_out_chars: { + case SECURE_CALL_stdio_out_chars: { stdio_put_string((char*)a, b, false, true); stdio_flush(); return BOOTROM_OK; } #endif #if PICO_ALLOW_NONSECURE_RAND - case BOOTROM_API_CALLBACK_get_rand_64: { + case SECURE_CALL_get_rand_64: { return get_rand_64(); } #endif #if PICO_ALLOW_NONSECURE_DMA - case BOOTROM_API_CALLBACK_dma_allocate_unused_channel_for_nonsecure: { + case SECURE_CALL_dma_allocate_unused_channel_for_nonsecure: { return dma_allocate_unused_channel_for_nonsecure(); } #endif #if PICO_ALLOW_NONSECURE_USER_IRQ - case BOOTROM_API_CALLBACK_user_irq_claim_unused_for_nonsecure: { + case SECURE_CALL_user_irq_claim_unused_for_nonsecure: { return user_irq_claim_unused_for_nonsecure(); } #endif #if PICO_ALLOW_NONSECURE_PIO - case BOOTROM_API_CALLBACK_pio_claim_unused_pio_for_nonsecure: { + case SECURE_CALL_pio_claim_unused_pio_for_nonsecure: { return pio_claim_unused_pio_for_nonsecure(); } #endif #if PICO_ADD_NONSECURE_PADS_HELPER - case BOOTROM_API_CALLBACK_pads_bank0_set_bits: { + 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 BOOTROM_API_CALLBACK_pads_bank0_clear_bits: { + 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 BOOTROM_API_CALLBACK_pads_bank0_write_masked: { + 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 BOOTROM_API_CALLBACK_pads_bank0_read: { + case SECURE_CALL_pads_bank0_read: { if (accessctrl_hw->gpio_nsmask[a/32] & 1u << (a & 0x1fu)) { return pads_bank0_read(a); } else { @@ -508,21 +508,21 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ } } #endif - case BOOTROM_API_CALLBACK_clock_get_hz: { + case SECURE_CALL_clock_get_hz: { return clock_get_hz(a); } #if PICO_ALLOW_NONSECURE_RESETS - case BOOTROM_API_CALLBACK_reset_block_reg_mask: { + case SECURE_CALL_reset_block_reg_mask: { if (b & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; reset_block_reg_mask((volatile io_rw_32 *)a, b); return BOOTROM_OK; } - case BOOTROM_API_CALLBACK_unreset_block_reg_mask: { + case SECURE_CALL_unreset_block_reg_mask: { if (b & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; unreset_block_reg_mask((volatile io_rw_32 *)a, b); return BOOTROM_OK; } - case BOOTROM_API_CALLBACK_unreset_block_reg_mask_wait_blocking: { + case SECURE_CALL_unreset_block_reg_mask_wait_blocking: { if (c & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; unreset_block_reg_mask_wait_blocking((volatile io_rw_32 *)a, (const volatile io_ro_32 *)b, c); return BOOTROM_OK; @@ -588,7 +588,7 @@ PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_nonsecure_claims, PICO_RUNTIME_INIT_ 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, BOOTROM_API_CALLBACK_clock_get_hz); + uint32_t hz = rom_secure_call(i, 0, 0, 0, SECURE_CALL_clock_get_hz); clock_set_reported_hz(i, hz); } } diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index ee550d06a..b441348b0 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -1134,7 +1134,7 @@ int pio_request_unused_pio_from_secure(void); */ #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, BOOTROM_API_CALLBACK_pads_bank0_set_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) { @@ -1151,7 +1151,7 @@ static inline int pads_bank0_set_bits(uint gpio, uint bits) { */ #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, BOOTROM_API_CALLBACK_pads_bank0_clear_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) { @@ -1169,7 +1169,7 @@ static inline int pads_bank0_clear_bits(uint gpio, uint bits) { */ #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, BOOTROM_API_CALLBACK_pads_bank0_write_masked); + 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) { @@ -1186,7 +1186,7 @@ static inline int pads_bank0_write_masked(uint gpio, uint bits, uint mask) { */ #if PICO_ADD_NONSECURE_PADS_HELPER && PICO_NONSECURE static inline int pads_bank0_read(uint gpio) { - return rom_secure_call(gpio, 0, 0, 0, BOOTROM_API_CALLBACK_pads_bank0_read); + return rom_secure_call(gpio, 0, 0, 0, SECURE_CALL_pads_bank0_read); } #else static inline int pads_bank0_read(uint gpio) { @@ -1217,13 +1217,13 @@ static inline int pads_bank0_read(uint gpio) { #if PICO_ALLOW_NONSECURE_RESETS && PICO_NONSECURE static inline int reset_block_reg_mask(io_rw_32 *reset, uint32_t mask) { - return rom_secure_call(reset, mask, 0, 0, BOOTROM_API_CALLBACK_reset_block_reg_mask); + return rom_secure_call(reset, mask, 0, 0, SECURE_CALL_reset_block_reg_mask); } static inline int unreset_block_reg_mask(io_rw_32 *reset, uint32_t mask) { - return rom_secure_call(reset, mask, 0, 0, BOOTROM_API_CALLBACK_unreset_block_reg_mask); + return rom_secure_call(reset, mask, 0, 0, SECURE_CALL_unreset_block_reg_mask); } static inline int unreset_block_reg_mask_wait_blocking(io_rw_32 *reset, io_ro_32 *reset_done, uint32_t mask) { - return rom_secure_call(reset, reset_done, mask, 0, BOOTROM_API_CALLBACK_unreset_block_reg_mask_wait_blocking); + return rom_secure_call(reset, reset_done, mask, 0, SECURE_CALL_unreset_block_reg_mask_wait_blocking); } #endif From 0f8d15cf1326071f160414818623fa4ef55d7b9a Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 4 Dec 2025 10:11:57 +0000 Subject: [PATCH 19/27] Add pico_set_security_ram_split for simple split configuration --- src/rp2_common/pico_secure/CMakeLists.txt | 45 +++++++++++++++++++ .../pico_secure/include/pico/secure.h | 9 ++++ src/rp2_common/pico_secure/secure.c | 12 +++++ 3 files changed, 66 insertions(+) diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index 47543cee6..469d3e0f1 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -65,4 +65,49 @@ if (NOT TARGET pico_secure) target_compile_definitions(${NONSECURE_TARGET} PRIVATE PICO_DEFAULT_TIMER=${OPTS_NONSECURE_TIMER}) endif() endfunction() + + # pico_set_security_ram_split(SECURE_TARGET NONSECURE_TARGET ...) + # \brief_nodesc\ Set ram split for a secure and non-secure target + # + # Set ram split for a secure and non-secure target, so they don't use the same memory. + # + # Each split option requires arguments to specify the memory sizes + # + # The split options are: + # - SIMPLE : Secure using start of main SRAM, NonSecure using end of main SRAM and scratch + # + # \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(multiValueArgs SIMPLE) + cmake_parse_arguments(PARSE_ARGV 2 OPTS "" "" "${multiValueArgs}") + + foreach(arg IN LISTS multiValueArgs) + if (OPTS_${arg}) + endif() + endforeach() + + if (OPTS_SIMPLE) + message("OPTS_SIMPLE ${OPTS_SIMPLE}") + list(GET OPTS_SIMPLE 0 SECURE_LENGTH) + list(GET OPTS_SIMPLE 1 SECURE_SCRATCH_LENGTH) + + message("SECURE_LENGTH ${SECURE_LENGTH} SECURE_SCRATCH_LENGTH ${SECURE_SCRATCH_LENGTH}") + + 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 PICO_SECURITY_SPLIT_SIMPLE_SECURE_LENGTH=${SECURE_LENGTH}) + endif() + + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_CONFIGURED=1) + + endfunction() endif() diff --git a/src/rp2_common/pico_secure/include/pico/secure.h b/src/rp2_common/pico_secure/include/pico/secure.h index 47b7c6a64..d69a8467c 100644 --- a/src/rp2_common/pico_secure/include/pico/secure.h +++ b/src/rp2_common/pico_secure/include/pico/secure.h @@ -36,6 +36,15 @@ void secure_launch_nonsecure_binary(uint32_t vtor_address, uint32_t stack_limit) */ 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); +#endif + /*! \brief Set SAU enabled * \ingroup pico_secure * diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 125cfd90a..686f85d9b 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -60,6 +60,18 @@ void secure_sau_set_enabled(bool enabled) { } +#if defined(PICO_SECURITY_SPLIT_CONFIGURED) +void secure_sau_configure_split() { +#if defined(PICO_SECURITY_SPLIT_SIMPLE) + // XIP is NS Code + secure_sau_configure_region(0, XIP_BASE, XIP_END, true, false); + // SRAM after secure code is NS data + secure_sau_configure_region(1, SRAM_BASE + PICO_SECURITY_SPLIT_SIMPLE_SECURE_LENGTH, SRAM_END, true, false); +#endif +} +#endif + + static secure_hardfault_callback_t hardfault_callback = NULL; From 362f83ed2ce0dfe3f936027a218a7ed574265b07 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 4 Dec 2025 10:31:59 +0000 Subject: [PATCH 20/27] Make that work correctly --- src/rp2_common/pico_secure/CMakeLists.txt | 1 + src/rp2_common/pico_secure/secure.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index 469d3e0f1..00be071a6 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -95,6 +95,7 @@ if (NOT TARGET pico_secure) message("SECURE_LENGTH ${SECURE_LENGTH} SECURE_SCRATCH_LENGTH ${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}) diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 686f85d9b..67facc6a1 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -65,8 +65,9 @@ void secure_sau_configure_split() { #if defined(PICO_SECURITY_SPLIT_SIMPLE) // XIP is NS Code secure_sau_configure_region(0, XIP_BASE, XIP_END, true, false); - // SRAM after secure code is NS data - secure_sau_configure_region(1, SRAM_BASE + PICO_SECURITY_SPLIT_SIMPLE_SECURE_LENGTH, SRAM_END, true, false); + // SRAM after secure stack is NS data + extern uint32_t __StackTop; + secure_sau_configure_region(1, (uint32_t)&__StackTop, SRAM_END, true, false); #endif } #endif From cd11286868fa4d328087a93098f1ae66b021b49c Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 4 Dec 2025 12:00:30 +0000 Subject: [PATCH 21/27] Add user callbacks to rom_secure_call --- src/rp2_common/pico_bootrom/bootrom.c | 51 +++++++++++++++++++ .../pico_bootrom/include/pico/bootrom.h | 32 ++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index 780f486c6..14f270d50 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -289,6 +289,46 @@ int __noinline rom_secure_call(uint a, uint b, uint c, uint d, uint func) { 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" @@ -450,6 +490,17 @@ int pio_request_unused_pio_from_secure(void) { #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: { diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index b441348b0..69b3ad628 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -1047,6 +1047,38 @@ 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 From 044071bba4a671dd71f7b9dbb078b5b40cbac311 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 4 Dec 2025 15:33:09 +0000 Subject: [PATCH 22/27] Add scratch_each and secure_scratch splits, and secure_launch_nonsecure_binary_default function to launch default nonsecure binary --- src/rp2_common/pico_secure/CMakeLists.txt | 50 ++++++++++++++++--- .../pico_secure/include/pico/secure.h | 8 +++ src/rp2_common/pico_secure/secure.c | 30 +++++++++++ 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index 00be071a6..1e7114ae3 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -71,30 +71,39 @@ if (NOT TARGET pico_secure) # # Set ram split for a secure and non-secure target, so they don't use the same memory. # - # Each split option requires arguments to specify the memory sizes + # Each split type option requires arguments to specify the memory sizes. You can only select + # one split type # - # The split options are: + # The split types available are: # - SIMPLE : Secure using start of main SRAM, NonSecure using end of main SRAM and scratch + # - SCRATCH_EACH : Secure using start of main SRAM plus scratch X as stack, NonSecure using end of main SRAM plus scratch Y as stack + # - SECURE_SCRATCH : Secure using start of main SRAM plus all of scratch, NonSecure using end of main SRAM # # \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(multiValueArgs SIMPLE) + set(multiValueArgs SIMPLE SCRATCH_EACH SECURE_SCRATCH) cmake_parse_arguments(PARSE_ARGV 2 OPTS "" "" "${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) - message("OPTS_SIMPLE ${OPTS_SIMPLE}") list(GET OPTS_SIMPLE 0 SECURE_LENGTH) list(GET OPTS_SIMPLE 1 SECURE_SCRATCH_LENGTH) - message("SECURE_LENGTH ${SECURE_LENGTH} SECURE_SCRATCH_LENGTH ${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") @@ -105,7 +114,34 @@ if (NOT TARGET pico_secure) 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 PICO_SECURITY_SPLIT_SIMPLE_SECURE_LENGTH=${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) diff --git a/src/rp2_common/pico_secure/include/pico/secure.h b/src/rp2_common/pico_secure/include/pico/secure.h index d69a8467c..c5b9b2213 100644 --- a/src/rp2_common/pico_secure/include/pico/secure.h +++ b/src/rp2_common/pico_secure/include/pico/secure.h @@ -43,6 +43,14 @@ void secure_sau_configure_region(uint region, uint32_t base, uint32_t limit, boo * 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 diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 67facc6a1..6c6ec429b 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -68,6 +68,36 @@ void secure_sau_configure_split() { // SRAM after secure stack is NS data extern uint32_t __StackTop; secure_sau_configure_region(1, (uint32_t)&__StackTop, SRAM_END, true, false); +#elif defined(PICO_SECURITY_SPLIT_SCRATCH_EACH) + // XIP is NS Code + secure_sau_configure_region(0, XIP_BASE, XIP_END, true, false); + // 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); + // 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) + // XIP is NS Code + secure_sau_configure_region(0, XIP_BASE, XIP_END, true, false); + // 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); +#endif +} + + +void __attribute__((noreturn)) secure_launch_nonsecure_binary_default() { +#if defined(PICO_SECURITY_SPLIT_SIMPLE) + // Nonsecure running from XIP, stack limit is bottom of scratch + secure_launch_nonsecure_binary(XIP_BASE, 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(XIP_BASE, 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(XIP_BASE, (uint32_t)&__HeapLimit); #endif } #endif From 8455e64db83dcdc4cbc22a681fe8ac22576d775a Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 4 Dec 2025 17:42:52 +0000 Subject: [PATCH 23/27] Add NO_FLASH option to split, to run NonSecure from ram --- src/rp2_common/pico_secure/CMakeLists.txt | 12 ++++++++++- src/rp2_common/pico_secure/secure.c | 26 ++++++++++++++++------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/rp2_common/pico_secure/CMakeLists.txt b/src/rp2_common/pico_secure/CMakeLists.txt index 1e7114ae3..d1f426d80 100644 --- a/src/rp2_common/pico_secure/CMakeLists.txt +++ b/src/rp2_common/pico_secure/CMakeLists.txt @@ -79,12 +79,16 @@ if (NOT TARGET pico_secure) # - SCRATCH_EACH : Secure using start of main SRAM plus scratch X as stack, NonSecure using end of main SRAM plus scratch Y as stack # - SECURE_SCRATCH : Secure using start of main SRAM plus all of scratch, NonSecure using end of main SRAM # + # Additional options are: + # - NO_FLASH: Assumes NS VTOR is at start of it's SRAM region, rather than at the start of flash + # # \param\ SECURE_TARGET The secure target # \param\ NONSECURE_TARGET The non-secure target # \param\ OPTIONS The options to set function(pico_set_security_ram_split SECURE_TARGET NONSECURE_TARGET) + set(options NO_FLASH) set(multiValueArgs SIMPLE SCRATCH_EACH SECURE_SCRATCH) - cmake_parse_arguments(PARSE_ARGV 2 OPTS "" "" "${multiValueArgs}") + cmake_parse_arguments(PARSE_ARGV 2 OPTS "${options}" "" "${multiValueArgs}") set(HAS_SPLIT_TYPE FALSE) foreach(arg IN LISTS multiValueArgs) @@ -146,5 +150,11 @@ if (NOT TARGET pico_secure) target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_CONFIGURED=1) + if (OPTS_NO_FLASH) + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_NO_FLASH=1) + else() + target_compile_definitions(${SECURE_TARGET} PRIVATE PICO_SECURITY_SPLIT_NO_FLASH=0) + endif() + endfunction() endif() diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 6c6ec429b..7b447d035 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -61,43 +61,53 @@ void secure_sau_set_enabled(bool enabled) { #if defined(PICO_SECURITY_SPLIT_CONFIGURED) +static uint32_t nonsecure_ram_start = 0; + void secure_sau_configure_split() { -#if defined(PICO_SECURITY_SPLIT_SIMPLE) +#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) - // XIP is NS Code - secure_sau_configure_region(0, XIP_BASE, XIP_END, true, false); // 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) - // XIP is NS Code - secure_sau_configure_region(0, XIP_BASE, XIP_END, true, false); // 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(XIP_BASE, SRAM_SCRATCH_X_BASE); + 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(XIP_BASE, SRAM_SCRATCH_Y_BASE); + 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(XIP_BASE, (uint32_t)&__HeapLimit); + secure_launch_nonsecure_binary(nonsecure_vtor, (uint32_t)&__HeapLimit); #endif } #endif From bd8af3f829824bd8222df09a575d1997c6d9ffb3 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 5 Dec 2025 14:14:42 +0000 Subject: [PATCH 24/27] hw_set_bits doesn't work on SAU --- src/rp2_common/pico_secure/secure.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 7b447d035..3aafacb30 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -50,9 +50,9 @@ void secure_sau_set_enabled(bool enabled) { __dmb(); if (enabled) - hw_set_bits(&sau_hw->ctrl, M33_SAU_CTRL_ENABLE_BITS); + sau_hw->ctrl |= M33_SAU_CTRL_ENABLE_BITS; else - hw_clear_bits(&sau_hw->ctrl, M33_SAU_CTRL_ENABLE_BITS); + sau_hw->ctrl &= ~M33_SAU_CTRL_ENABLE_BITS; __dsb(); __isb(); From 9f7afbdb5ee48e22f415fc2cd774fe2a08c0e933 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 5 Dec 2025 14:40:42 +0000 Subject: [PATCH 25/27] Enable sys_info NS API --- src/rp2_common/pico_secure/secure.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rp2_common/pico_secure/secure.c b/src/rp2_common/pico_secure/secure.c index 3aafacb30..836a3ce90 100644 --- a/src/rp2_common/pico_secure/secure.c +++ b/src/rp2_common/pico_secure/secure.c @@ -203,6 +203,8 @@ PICO_RUNTIME_INIT_FUNC_PER_CORE(runtime_init_nonsecure_coprocessors, PICO_RUNTIM #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 From 26e397aab223784244be8b388cc84952381f4b49 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 5 Dec 2025 15:03:46 +0000 Subject: [PATCH 26/27] Only take mask for secure call reset functions --- .../include/boot/bootrom_constants.h | 6 +++--- src/rp2_common/pico_bootrom/bootrom.c | 18 +++++++++--------- .../pico_bootrom/include/pico/bootrom.h | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h index a538f9a4c..c4829cf19 100644 --- a/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h +++ b/src/rp2_common/boot_bootrom_headers/include/boot/bootrom_constants.h @@ -374,9 +374,9 @@ typedef struct cflash_flags { #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_reg_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'R', 'M') -#define SECURE_CALL_unreset_block_reg_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'M') -#define SECURE_CALL_unreset_block_reg_mask_wait_blocking SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'W') +#define SECURE_CALL_reset_block_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'R', 'M') +#define SECURE_CALL_unreset_block_mask SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'M') +#define SECURE_CALL_unreset_block_mask_wait_blocking SECURE_CALL_WELL_KNOWN_CODE('R', 'T', 'U', 'W') #endif #endif diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index 14f270d50..11e7e71e3 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -563,19 +563,19 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ return clock_get_hz(a); } #if PICO_ALLOW_NONSECURE_RESETS - case SECURE_CALL_reset_block_reg_mask: { - if (b & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; - reset_block_reg_mask((volatile io_rw_32 *)a, b); + 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_reg_mask: { - if (b & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; - unreset_block_reg_mask((volatile io_rw_32 *)a, b); + 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_reg_mask_wait_blocking: { - if (c & ~PICO_ALLOW_NONSECURE_RESETS_MASK) return BOOTROM_ERROR_NOT_PERMITTED; - unreset_block_reg_mask_wait_blocking((volatile io_rw_32 *)a, (const volatile io_ro_32 *)b, c); + 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 diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h index 69b3ad628..501a391b6 100644 --- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h +++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h @@ -1248,14 +1248,14 @@ static inline int pads_bank0_read(uint gpio) { #endif #if PICO_ALLOW_NONSECURE_RESETS && PICO_NONSECURE -static inline int reset_block_reg_mask(io_rw_32 *reset, uint32_t mask) { - return rom_secure_call(reset, mask, 0, 0, SECURE_CALL_reset_block_reg_mask); +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(io_rw_32 *reset, uint32_t mask) { - return rom_secure_call(reset, mask, 0, 0, SECURE_CALL_unreset_block_reg_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(io_rw_32 *reset, io_ro_32 *reset_done, uint32_t mask) { - return rom_secure_call(reset, reset_done, mask, 0, SECURE_CALL_unreset_block_reg_mask_wait_blocking); +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 From 2c4e1f62f3b85930e291e269b762fe160177d8bf Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 5 Dec 2025 15:23:11 +0000 Subject: [PATCH 27/27] Add buffer validation for nonsecure stdio Prevents nonsecure code printing secure data --- src/rp2_common/pico_bootrom/bootrom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c index 11e7e71e3..1b608ca63 100644 --- a/src/rp2_common/pico_bootrom/bootrom.c +++ b/src/rp2_common/pico_bootrom/bootrom.c @@ -504,6 +504,9 @@ int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_ 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;