Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add copy_flash_sram modified binary type, and allow data_cpy in no_fl…
…ash builds

Also modify linker scripts to add templating additional regions, and callback to pico_set_modified_binary_type to set additional variables
  • Loading branch information
will-v-pi committed Sep 11, 2025
commit eb6524078635b1d48efecc319ac6f20b091cec0d
21 changes: 18 additions & 3 deletions src/rp2_common/pico_crt0/crt0.S
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#define PICO_CRT0_NEAR_CALLS 0
#endif

// PICO_CONFIG: PICO_CRT0_NO_DATA_COPY, Whether crt0 should perform the data copies - usually copying from flash into sram, default=1 for no_flash builds, 0 otherwise, type=bool, group=pico_crt0
#ifndef PICO_CRT0_NO_DATA_COPY
#define PICO_CRT0_NO_DATA_COPY PICO_NO_FLASH
#endif

#ifdef NDEBUG
#ifndef COLLAPSE_IRQS
#define COLLAPSE_IRQS
Expand Down Expand Up @@ -477,7 +482,7 @@ _call_xip_setup:

// In a NO_FLASH binary, don't perform .data etc copy, since it's loaded
// in-place by the SRAM load. Still need to clear .bss
#if !PICO_NO_FLASH
#if !PICO_CRT0_NO_DATA_COPY
adr r4, data_cpy_table

// assume there is at least one entry
Expand Down Expand Up @@ -522,11 +527,21 @@ platform_entry: // symbol for stack traces
b 1b


#if !PICO_NO_FLASH
#if !PICO_CRT0_NO_DATA_COPY
#if PICO_NO_FLASH
data_cpy:
// skip copies with same source and destination
cmp r1, r2
bne data_cpy_start
bx lr
#else
// go straight into the copy
#define data_cpy_start data_cpy
#endif
data_cpy_loop:
ldm r1!, {r0}
stm r2!, {r0}
data_cpy:
data_cpy_start:
cmp r2, r3
blo data_cpy_loop
bx lr
Expand Down
290 changes: 290 additions & 0 deletions src/rp2_common/pico_crt0/rp2040/memmap_copy_flash_sram.template.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
/* 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
{
@FLASH_REGION@
RAM(rwx) : ORIGIN = @RAM_ORIGIN@, LENGTH = @RAM_LENGTH@
SCRATCH_X(rwx) : ORIGIN = @SCRATCH_X_ORIGIN@, LENGTH = @SCRATCH_X_LENGTH@
SCRATCH_Y(rwx) : ORIGIN = @SCRATCH_Y_ORIGIN@, LENGTH = @SCRATCH_Y_LENGTH@
@ADDITIONAL_MEMORY@
}

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))
}
Copy link

@steffenyount steffenyount Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the RP2350 implementations of this and the copy_to_ram template this block is ended with

} > FLASH

should that be made the same here and in the RP2040's copy_to_ram template?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @will-v-pi

Any progress on getting these changes ready for merge? Also, did you see my comment above ^^^ ?

Thanks,
-Steffen


.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);

@ADDITIONAL_PRE_DATA@

.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 */
}

3 changes: 3 additions & 0 deletions src/rp2_common/pico_crt0/rp2040/memmap_copy_to_ram.ld
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ MEMORY
RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k

}

ENTRY(_entry_point)
Expand Down Expand Up @@ -132,6 +133,8 @@ SECTIONS
__ram_text_source__ = LOADADDR(.text);
. = ALIGN(4);



.data : {
__data_start__ = .;
*(vtable)
Expand Down
3 changes: 3 additions & 0 deletions src/rp2_common/pico_crt0/rp2040/memmap_default.ld
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ MEMORY
RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k

}

ENTRY(_entry_point)
Expand Down Expand Up @@ -149,6 +150,8 @@ SECTIONS
*(.uninitialized_data*)
} > RAM



.data : {
__data_start__ = .;
*(vtable)
Expand Down
5 changes: 4 additions & 1 deletion src/rp2_common/pico_crt0/rp2040/memmap_flash.template.ld
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@

MEMORY
{
INCLUDE "pico_flash_region.ld"
@FLASH_REGION@
RAM(rwx) : ORIGIN = @RAM_ORIGIN@, LENGTH = @RAM_LENGTH@
SCRATCH_X(rwx) : ORIGIN = @SCRATCH_X_ORIGIN@, LENGTH = @SCRATCH_X_LENGTH@
SCRATCH_Y(rwx) : ORIGIN = @SCRATCH_Y_ORIGIN@, LENGTH = @SCRATCH_Y_LENGTH@
@ADDITIONAL_MEMORY@
}

ENTRY(_entry_point)
Expand Down Expand Up @@ -149,6 +150,8 @@ SECTIONS
*(.uninitialized_data*)
} > RAM

@ADDITIONAL_PRE_DATA@

.data : {
__data_start__ = .;
*(vtable)
Expand Down
Loading