From 76d861ed70da4459351b827009d2757a7c36e46f Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 6 Apr 2025 18:12:49 +0100 Subject: [PATCH 1/3] Update app and boot linker scripts to new SDK version --- linker_common/app2040.ld | 249 +++++++++++++++++++++++++++++++ linker_common/boot2040.ld | 305 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 554 insertions(+) create mode 100644 linker_common/app2040.ld create mode 100644 linker_common/boot2040.ld diff --git a/linker_common/app2040.ld b/linker_common/app2040.ld new file mode 100644 index 0000000..c33d2c5 --- /dev/null +++ b/linker_common/app2040.ld @@ -0,0 +1,249 @@ +/* Based on pico-sdk/src/rp2_common/pico_crt0/rp2040/memmap_default.ld */ + +INCLUDE linker_definitions.ld + +MEMORY +{ + FLASH(rx) : ORIGIN = __FLASH_APP_START, LENGTH = __FLASH_SLOT_LENGTH + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k + SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_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 (COPY): { + *(.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*)) + /* Align binary size to 256 bytes */ + . = . + 1; + . = ALIGN(256) - 1; + BYTE(0); + __flash_binary_end = .; + 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/linker_common/boot2040.ld b/linker_common/boot2040.ld new file mode 100644 index 0000000..9a7cf9e --- /dev/null +++ b/linker_common/boot2040.ld @@ -0,0 +1,305 @@ +/* Based on pico-sdk/src/rp2_common/pico_crt0/rp2040/memmap_default.ld */ + +INCLUDE linker_definitions.ld + +MEMORY +{ + BOOTLOADER_FLASH(rx) : ORIGIN = __FLASH_START, LENGTH = __BOOTLOADER_LENGTH + FLASH_INFO(rx) : ORIGIN = __FLASH_INFO_START, LENGTH = __FLASH_INFO_LENGTH + /* + FLASH_APP(rx) : ORIGIN = __FLASH_APP_START, LENGTH = __FLASH_SLOT_LENGTH + FLASH_DOWNLOAD_SLOT(rx) : ORIGIN = __FLASH_DOWNLOAD_SLOT_START, LENGTH = __FLASH_SLOT_LENGTH + */ + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k + SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Raspberry Pi Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > BOOTLOADER_FLASH + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > BOOTLOADER_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 (*(.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) + + *(.eh_frame*) + . = ALIGN(4); + } > BOOTLOADER_FLASH + + .flash_info : { + __flash_info_app_vtor = .; + LONG(__FLASH_APP_START) + __flash_info_download_slot_vtor = .; + LONG(__FLASH_DOWNLOAD_SLOT_START) + __flash_info_is_download_slot_valid = .; + /* after flashing bootloader, download slot is invalid */ + LONG(0x00000000) + __flash_info_is_firmware_is_swapped = .; + /* after flashing bootloader, firmware has not yet been swapped */ + LONG(0x00000000) + __flash_info_is_after_rollback = .; + /* after flashing bootloader, app is not affter a rollback */ + LONG(0x00000000) + __flash_info_should_rollback = .; + /* after flashing bootloader, rollback shouldn't be performed */ + LONG(0x00000000) + } > FLASH_INFO + + ASSERT(__flash_info_app_vtor == __FLASH_INFO_APP_HEADER, + "__FLASH_INFO_APP_HEADER definition in linker_definitions.ld file is not valid") + ASSERT(__flash_info_download_slot_vtor == __FLASH_INFO_DOWNLOAD_HEADER, + "__FLASH_INFO_DOWNLOAD_HEADER definition in linker_definitions.ld file is not valid") + ASSERT(__flash_info_is_download_slot_valid == __FLASH_INFO_IS_DOWNLOAD_SLOT_VALID, + "__FLASH_INFO_IS_DOWNLOAD_SLOT_VALID definition in linker_definitions.ld file is not valid") + ASSERT(__flash_info_is_firmware_is_swapped == __FLASH_INFO_IS_FIRMWARE_SWAPPED, + "__FLASH_INFO_IS_FIRMWARE_SWAPPED definition in linker_definitions.ld file is not valid") + ASSERT(__flash_info_is_after_rollback == __FLASH_INFO_IS_AFTER_ROLLBACK, + "__FLASH_INFO_IS_AFTER_ROLLBACK definition in linker_definitions.ld file is not valid") + ASSERT(__flash_info_should_rollback == __FLASH_INFO_SHOULD_ROLLBACK, + "__FLASH_INFO_SHOULD_ROLLBACK definition in linker_definitions.ld file is not valid") + + .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); + } > BOOTLOADER_FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > BOOTLOADER_FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > BOOTLOADER_FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > BOOTLOADER_FLASH + __binary_info_end = .; + . = ALIGN(4); + + __etext = .; + + .ram_vector_table (COPY): { + *(.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); + /* 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); + __data_end__ = .; + } > RAM AT> BOOTLOADER_FLASH + + .uninitialized_data (COPY): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> BOOTLOADER_FLASH + PROVIDE(__data_end__ = .); + + .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 > BOOTLOADER_FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > BOOTLOADER_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 : { + PROVIDE(__flash_binary_end = .); + } > BOOTLOADER_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 */ +} + From 4cf352f3b755ad577ec19516e1a22662ac2dbb3a Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 6 Apr 2025 23:32:25 +0100 Subject: [PATCH 2/3] Add rp2350 support, add support for dynamic flash size. --- CMakeLists.txt | 31 +++- bootloader.c | 5 + linker_common/app2040.ld | 1 - linker_common/{application.ld => app2350.ld} | 146 ++++++++++------ linker_common/{bootloader.ld => boot2350.ld} | 163 +++++++++++------- ...r_definitions.ld => linker_definitions.in} | 7 +- 6 files changed, 231 insertions(+), 122 deletions(-) rename linker_common/{application.ld => app2350.ld} (71%) rename linker_common/{bootloader.ld => boot2350.ld} (66%) rename linker_common/{linker_definitions.ld => linker_definitions.in} (92%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47f760a..ace5ac5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,12 @@ cmake_minimum_required(VERSION 3.13) +if(${PICO_PLATFORM} STREQUAL "rp2350-arm-s") + set(CPU "2350") +else() + set(CPU "2040") +endif() + ######################################## # CMake options ######################################## @@ -30,6 +36,14 @@ option(PFB_WITH_IMAGE_ENCRYPTION "Enables image encryption using AES ECB algorit option(PFB_AES_KEY "AES key used for image encryption and decryption") option(PFB_WITH_SHA256_HASHING "Enables image SHA256 appending and checking" ON) +######################################## +# Build linker definitions +######################################## +# PICO_FLASH_SIZE_BYTES +execute_process( + COMMAND cat ${CMAKE_CURRENT_LIST_DIR}/linker_common/linker_definitions.in + COMMAND ${CMAKE_C_COMPILER} -DFLASH_SIZE=${PICO_FLASH_SIZE_BYTES} -E -P -o ${CMAKE_BINARY_DIR}/linker_definitions.ld - + ) ######################################## # Check and set AES key ######################################## @@ -66,7 +80,7 @@ target_link_libraries(pico_fota_bootloader_lib PUBLIC target_link_libraries(pico_fota_bootloader_lib PRIVATE pico_mbedtls) target_link_options(pico_fota_bootloader_lib PRIVATE - "-T${CMAKE_CURRENT_SOURCE_DIR}/linker_common/linker_definitions.ld") + "-T${CMAKE_CURRENT_BINARY_DIR}/linker_definitions.ld") if (PFB_WITH_IMAGE_ENCRYPTION) target_compile_definitions(pico_fota_bootloader_lib PRIVATE PFB_WITH_IMAGE_ENCRYPTION) @@ -82,8 +96,14 @@ set(BOOTLOADER_DIR_GLOBAL ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) # Manage application binary ######################################## function(pfb_compile_with_bootloader Target) - target_link_options(${Target} PRIVATE "-L${BOOTLOADER_DIR_GLOBAL}/linker_common") - pico_set_linker_script(${Target} ${BOOTLOADER_DIR_GLOBAL}/linker_common/application.ld) + if(${PICO_PLATFORM} STREQUAL "rp2350-arm-s") + set(CPU "2350") + else() + set(CPU "2040") + endif() + + target_link_options(${Target} PRIVATE "-L${BOOTLOADER_DIR_GLOBAL}/linker_common" "-L${CMAKE_CURRENT_BINARY_DIR}") + pico_set_linker_script(${Target} ${BOOTLOADER_DIR_GLOBAL}/linker_common/app${CPU}.ld) if (PFB_WITH_SHA256_HASHING OR PFB_WITH_IMAGE_ENCRYPTION) find_package(Python COMPONENTS Interpreter REQUIRED) @@ -134,13 +154,14 @@ function (target_compile_link_options Name Option) target_link_options(${Name} PRIVATE ${Option}) endfunction () +target_compile_definitions(pico_fota_bootloader PRIVATE -DPICO_PLATFORM=${PICO_PLATFORM}) target_compile_link_options(pico_fota_bootloader "-Os") target_compile_link_options(pico_fota_bootloader "-ffunction-sections") target_compile_link_options(pico_fota_bootloader "-fdata-sections") -target_compile_link_options(pico_fota_bootloader "-L${CMAKE_CURRENT_SOURCE_DIR}/linker_common") +target_compile_link_options(pico_fota_bootloader "-L${CMAKE_CURRENT_SOURCE_DIR}/linker_common" "-L${CMAKE_CURRENT_BINARY_DIR}") target_link_options(pico_fota_bootloader PRIVATE "LINKER:--gc-sections") -pico_set_linker_script(pico_fota_bootloader ${CMAKE_CURRENT_SOURCE_DIR}/linker_common/bootloader.ld) +pico_set_linker_script(pico_fota_bootloader ${CMAKE_CURRENT_SOURCE_DIR}/linker_common/boot${CPU}.ld) pico_add_extra_outputs(pico_fota_bootloader) ######################################## diff --git a/bootloader.c b/bootloader.c index 0cb4016..5fbd75c 100644 --- a/bootloader.c +++ b/bootloader.c @@ -23,7 +23,12 @@ #include #include +#if PICO_PLATFORM == rp2350-arm-s +#include +#else #include +#endif + #include #include #include diff --git a/linker_common/app2040.ld b/linker_common/app2040.ld index c33d2c5..cf1ccaf 100644 --- a/linker_common/app2040.ld +++ b/linker_common/app2040.ld @@ -217,7 +217,6 @@ SECTIONS . = . + 1; . = ALIGN(256) - 1; BYTE(0); - __flash_binary_end = .; PROVIDE(__flash_binary_end = .); } > FLASH diff --git a/linker_common/application.ld b/linker_common/app2350.ld similarity index 71% rename from linker_common/application.ld rename to linker_common/app2350.ld index 0d1f27d..4a06078 100644 --- a/linker_common/application.ld +++ b/linker_common/app2350.ld @@ -1,13 +1,13 @@ -/* Based on pico-sdk/src/rp2_common/pico_standard_link/memmap_default.ld file */ +/* Based on pico-sdk/src/rp2_common/pico_crt0/rp2350/memmap_default.ld */ INCLUDE linker_definitions.ld MEMORY { FLASH(rx) : ORIGIN = __FLASH_APP_START, LENGTH = __FLASH_SLOT_LENGTH - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k } ENTRY(_entry_point) @@ -23,11 +23,14 @@ SECTIONS 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 */ @@ -43,12 +46,34 @@ SECTIONS *(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*) + *(.srodata*) . = ALIGN(4); *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) . = ALIGN(4); @@ -77,13 +102,15 @@ SECTIONS __binary_info_end = .; . = ALIGN(4); - /* End of .text-like segments */ - __etext = .; - - .ram_vector_table (COPY): { + .ram_vector_table (NOLOAD): { *(.ram_vector_table) } > RAM + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + .data : { __data_start__ = .; *(vtable) @@ -97,6 +124,7 @@ SECTIONS . = ALIGN(4); *(.data*) + *(.sdata*) . = ALIGN(4); *(.after_data.*) @@ -107,39 +135,53 @@ SECTIONS KEEP(*(.mutex_array)) PROVIDE_HIDDEN (__mutex_array_end = .); + *(.jcr) . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); + } > RAM AT> FLASH + .tdata : { . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); + *(.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); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) - *(.jcr) + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { . = ALIGN(4); - /* All data end */ - __data_end__ = .; - } > RAM AT> FLASH - __data_source__ = LOADADDR(.data); + __tbss_end = .; - .uninitialized_data (COPY): { + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) . = ALIGN(4); - *(.uninitialized_data*) + __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__ = .; @@ -157,23 +199,6 @@ SECTIONS } > SCRATCH_Y AT > FLASH __scratch_y_source__ = LOADADDR(.scratch_y); - .bss : { - . = ALIGN(4); - __bss_start__ = .; - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (COPY): - { - __end__ = .; - end = __end__; - *(.heap*) - __HeapLimit = .; - } > RAM - /* .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 @@ -183,22 +208,23 @@ SECTIONS /* 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 (COPY): + .stack1_dummy (NOLOAD): { *(.stack1*) } > SCRATCH_X - .stack_dummy (COPY): + .stack_dummy (NOLOAD): { - *(.stack*) + KEEP(*(.stack*)) } > SCRATCH_Y .flash_end : { + KEEP(*(.embedded_end_block*)) /* Align binary size to 256 bytes */ . = . + 1; . = ALIGN(256) - 1; BYTE(0); - __flash_binary_end = .; - } > FLASH + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa /* stack limit is poorly named, but historically is maximum heap ptr */ __StackLimit = ORIGIN(RAM) + LENGTH(RAM); @@ -208,9 +234,23 @@ SECTIONS __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") + 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/linker_common/bootloader.ld b/linker_common/boot2350.ld similarity index 66% rename from linker_common/bootloader.ld rename to linker_common/boot2350.ld index 883e351..ed6ada0 100644 --- a/linker_common/bootloader.ld +++ b/linker_common/boot2350.ld @@ -1,4 +1,4 @@ -/* Based on pico-sdk/src/rp2_common/pico_standard_link/memmap_default.ld file */ +/* Based on pico-sdk/src/rp2_common/pico_crt0/rp2350/memmap_default.ld */ INCLUDE linker_definitions.ld @@ -10,38 +10,27 @@ MEMORY FLASH_APP(rx) : ORIGIN = __FLASH_APP_START, LENGTH = __FLASH_SLOT_LENGTH FLASH_DOWNLOAD_SLOT(rx) : ORIGIN = __FLASH_DOWNLOAD_SLOT_START, LENGTH = __FLASH_SLOT_LENGTH */ - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k - SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k } ENTRY(_entry_point) SECTIONS { - /* Second stage bootloader is prepended to the image. It must be 256 bytes big - and checksummed. It is usually built by the boot_stage2 target - in the Raspberry Pi Pico SDK - */ - .flash_begin : { __flash_binary_start = .; } > BOOTLOADER_FLASH - .boot2 : { - __boot2_start__ = .; - KEEP (*(.boot2)) - __boot2_end__ = .; - } > BOOTLOADER_FLASH - - ASSERT(__boot2_end__ - __boot2_start__ == 256, - "ERROR: Pico second stage bootloader must be 256 bytes in size") + /* 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 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. + 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 : { @@ -49,11 +38,14 @@ SECTIONS 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 */ @@ -92,21 +84,30 @@ SECTIONS LONG(0x00000000) } > FLASH_INFO - ASSERT(__flash_info_app_vtor == __FLASH_INFO_APP_HEADER, - "__FLASH_INFO_APP_HEADER definition in linker_definitions.ld file is not valid") - ASSERT(__flash_info_download_slot_vtor == __FLASH_INFO_DOWNLOAD_HEADER, - "__FLASH_INFO_DOWNLOAD_HEADER definition in linker_definitions.ld file is not valid") - ASSERT(__flash_info_is_download_slot_valid == __FLASH_INFO_IS_DOWNLOAD_SLOT_VALID, - "__FLASH_INFO_IS_DOWNLOAD_SLOT_VALID definition in linker_definitions.ld file is not valid") - ASSERT(__flash_info_is_firmware_is_swapped == __FLASH_INFO_IS_FIRMWARE_SWAPPED, - "__FLASH_INFO_IS_FIRMWARE_SWAPPED definition in linker_definitions.ld file is not valid") - ASSERT(__flash_info_is_after_rollback == __FLASH_INFO_IS_AFTER_ROLLBACK, - "__FLASH_INFO_IS_AFTER_ROLLBACK definition in linker_definitions.ld file is not valid") - ASSERT(__flash_info_should_rollback == __FLASH_INFO_SHOULD_ROLLBACK, - "__FLASH_INFO_SHOULD_ROLLBACK definition in linker_definitions.ld file is not valid") + /* 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__ = .; + } > BOOTLOADER_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); @@ -135,13 +136,15 @@ SECTIONS __binary_info_end = .; . = ALIGN(4); - /* End of .text-like segments */ - __etext = .; - - .ram_vector_table (COPY): { + .ram_vector_table (COPY): { *(.ram_vector_table) } > RAM + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + .data : { __data_start__ = .; *(vtable) @@ -155,6 +158,7 @@ SECTIONS . = ALIGN(4); *(.data*) + *(.sdata*) . = ALIGN(4); *(.after_data.*) @@ -188,15 +192,56 @@ SECTIONS *(.jcr) . = ALIGN(4); + } > RAM AT> BOOTLOADER_FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) /* All data end */ - __data_end__ = .; + __tdata_end = .; } > RAM AT> BOOTLOADER_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 .uninitialized_data (COPY): { . = ALIGN(4); *(.uninitialized_data*) } > 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__ = .; @@ -214,23 +259,6 @@ SECTIONS } > SCRATCH_Y AT > BOOTLOADER_FLASH __scratch_y_source__ = LOADADDR(.scratch_y); - .bss : { - . = ALIGN(4); - __bss_start__ = .; - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (COPY): - { - __end__ = .; - end = __end__; - *(.heap*) - __HeapLimit = .; - } > RAM - /* .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 @@ -240,17 +268,18 @@ SECTIONS /* 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 (COPY): + .stack1_dummy (NOLOAD): { *(.stack1*) } > SCRATCH_X - .stack_dummy (COPY): + .stack_dummy (NOLOAD): { - *(.stack*) + KEEP(*(.stack*)) } > SCRATCH_Y .flash_end : { - __flash_binary_end = .; + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); } > BOOTLOADER_FLASH /* stack limit is poorly named, but historically is maximum heap ptr */ @@ -261,9 +290,23 @@ SECTIONS __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") + + 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/linker_common/linker_definitions.ld b/linker_common/linker_definitions.in similarity index 92% rename from linker_common/linker_definitions.ld rename to linker_common/linker_definitions.in index 43d46be..a0b1eda 100644 --- a/linker_common/linker_definitions.ld +++ b/linker_common/linker_definitions.in @@ -45,6 +45,7 @@ */ __FLASH_START = 0x10000000; +__FLASH_SIZE = FLASH_SIZE; __BOOTLOADER_LENGTH = 36k; __FLASH_INFO_START = __FLASH_START + __BOOTLOADER_LENGTH; @@ -60,7 +61,7 @@ __FLASH_INFO_SHOULD_ROLLBACK = __FLASH_INFO_IS_AFTER_ROLLBACK + 4; __FLASH_APP_START = __FLASH_INFO_START + __FLASH_INFO_LENGTH; /* (2048k - __BOOTLOADER_LENGTH - __FLASH_INFO_LENGTH) / 2 */ -__FLASH_SWAP_SPACE_LENGTH = 1004k; +__FLASH_SWAP_SPACE_LENGTH = (__FLASH_SIZE - __BOOTLOADER_LENGTH - __FLASH_INFO_LENGTH) / 2; /* (max binary size) == (.text .rodata .big_const .binary_info) + (possible .data) @@ -73,8 +74,8 @@ happen. Assume 128k max, but can be easily lowered depending on the application. __FLASH_SLOT_LENGTH = __FLASH_SWAP_SPACE_LENGTH - 128k; __FLASH_DOWNLOAD_SLOT_START = __FLASH_APP_START + __FLASH_SWAP_SPACE_LENGTH; -ASSERT(__FLASH_SWAP_SPACE_LENGTH == (2048k - __BOOTLOADER_LENGTH - __FLASH_INFO_LENGTH) / 2, +ASSERT(__FLASH_SWAP_SPACE_LENGTH == (__FLASH_SIZE - __BOOTLOADER_LENGTH - __FLASH_INFO_LENGTH) / 2, "__FLASH_SWAP_SPACE_LENGTH has incorrect length") ASSERT((__FLASH_SWAP_SPACE_LENGTH%4k) == 0, "__FLASH_SWAP_SPACE_LENGTH should be multiple of 4k") -ASSERT(2048k >= __BOOTLOADER_LENGTH + __FLASH_INFO_LENGTH + 2*__FLASH_SWAP_SPACE_LENGTH, +ASSERT(__FLASH_SIZE >= __BOOTLOADER_LENGTH + __FLASH_INFO_LENGTH + 2*__FLASH_SWAP_SPACE_LENGTH, "Flash partitions defined incorrectly"); From 84899036cc12376f3a9680ff4fcdebcbebb01f84 Mon Sep 17 00:00:00 2001 From: Melanie Date: Mon, 7 Apr 2025 14:48:13 +0100 Subject: [PATCH 3/3] Allow reserving an area at the end of flash for a filesystem --- CMakeLists.txt | 6 +++++- bootloader.c | 3 +++ linker_common/linker_definitions.h | 2 +- linker_common/linker_definitions.in | 3 ++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ace5ac5..1d46ee3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,13 +36,17 @@ option(PFB_WITH_IMAGE_ENCRYPTION "Enables image encryption using AES ECB algorit option(PFB_AES_KEY "AES key used for image encryption and decryption") option(PFB_WITH_SHA256_HASHING "Enables image SHA256 appending and checking" ON) +if ( NOT PFB_RESERVED_FILESYSTEM_SIZE_KB ) + set(PFB_RESERVED_FILESYSTEM_SIZE_KB 0) +endif() + ######################################## # Build linker definitions ######################################## # PICO_FLASH_SIZE_BYTES execute_process( COMMAND cat ${CMAKE_CURRENT_LIST_DIR}/linker_common/linker_definitions.in - COMMAND ${CMAKE_C_COMPILER} -DFLASH_SIZE=${PICO_FLASH_SIZE_BYTES} -E -P -o ${CMAKE_BINARY_DIR}/linker_definitions.ld - + COMMAND ${CMAKE_C_COMPILER} -DFLASH_SIZE=${PICO_FLASH_SIZE_BYTES} -DFILESYSTEM_SIZE=${PFB_RESERVED_FILESYSTEM_SIZE_KB} -E -P -o ${CMAKE_BINARY_DIR}/linker_definitions.ld - ) ######################################## # Check and set AES key diff --git a/bootloader.c b/bootloader.c index 5fbd75c..3d4a97d 100644 --- a/bootloader.c +++ b/bootloader.c @@ -35,6 +35,7 @@ #include #include +#include #include "linker_common/linker_definitions.h" @@ -120,6 +121,7 @@ static void jump_to_vtor(uint32_t vtor) { static void print_welcome_message(void) { #ifdef PFB_WITH_BOOTLOADER_LOGS + uint32_t space = PFB_ADDR_AS_U32(__FLASH_SWAP_SPACE_LENGTH) / 1024; puts(""); puts("***********************************************************"); puts("* *"); @@ -128,6 +130,7 @@ static void print_welcome_message(void) { puts("* *"); puts("***********************************************************"); puts(""); + printf("Maximum code length: %luK\r\n", space); #endif // PFB_WITH_BOOTLOADER_LOGS } diff --git a/linker_common/linker_definitions.h b/linker_common/linker_definitions.h index c5bf099..9f76c2b 100644 --- a/linker_common/linker_definitions.h +++ b/linker_common/linker_definitions.h @@ -29,7 +29,7 @@ extern "C" { #endif -#define PFB_ADDR_AS_U32(Data) (uint32_t) & (Data) +#define PFB_ADDR_AS_U32(Data) ((uint32_t) & (Data)) #define PFB_ADDR_WITH_XIP_OFFSET_AS_U32(Data) \ (PFB_ADDR_AS_U32(Data) - (XIP_BASE)) diff --git a/linker_common/linker_definitions.in b/linker_common/linker_definitions.in index a0b1eda..8a46338 100644 --- a/linker_common/linker_definitions.in +++ b/linker_common/linker_definitions.in @@ -45,7 +45,8 @@ */ __FLASH_START = 0x10000000; -__FLASH_SIZE = FLASH_SIZE; +__FILESYSTEM_SIZE = (FILESYSTEM_SIZE * 1024); +__FLASH_SIZE = FLASH_SIZE - __FILESYSTEM_SIZE; __BOOTLOADER_LENGTH = 36k; __FLASH_INFO_START = __FLASH_START + __BOOTLOADER_LENGTH;