Skip to content

Catch linker overrun(s) and make more RAM available for firmware. - #1806

Open
antoinevg wants to merge 6 commits into
mainfrom
antoinevg/catch-ram-overrun
Open

Catch linker overrun(s) and make more RAM available for firmware.#1806
antoinevg wants to merge 6 commits into
mainfrom
antoinevg/catch-ram-overrun

Conversation

@antoinevg

@antoinevg antoinevg commented Jul 31, 2026

Copy link
Copy Markdown
Member

This PR adds:

  • A link-time assertion to enforce size limit on ram_local1 that would otherwise not be enforced.
  • Re-jiggers ram_m0 linker script LPC43xx_M4_M0_image_from_text.ld to enforce size-check.
  • Adds -Wl,--print-memory-usage to LDFLAGS so we can keep an eye on our memory budget moving forward.
  • Adds a bit more documentation for our linker configurations.
  • Splits ram_local2 to create a new ram_rtconfig section.
  • Moves code that's configured at runtime and static assets that are unlikely to swell dramatically in future to ram_rtconfig. Currently this includes:
    • platform_gpio
    • platform_scu
    • portapack ui assets

Suggestions for more relocations are welcome, we have another ~9 kB to fill!

Memory region         Used Size  Region Size  %age Used
             rom:      272420 B         1 MB     25.98%
      ram_local1:          0 GB        64 KB      0.00%
         ram_usb:          0 GB        32 KB      0.00%
    ram_rtconfig:        6528 B        16 KB     39.84%
      ram_local2:        8968 B        16 KB     54.74%
       ram_sleep:          0 GB         8 KB      0.00%
      ram_lz4_in:          0 GB         4 KB      0.00%
     ram_lz4_out:          0 GB         4 KB      0.00%
          ram_m0:         876 B        20 KB      4.28%
      ram_shared:          0 GB         4 KB      0.00%
        ram_samp:          0 GB        32 KB      0.00%
       rom_flash:          0 GB         1 MB      0.00%

Background

Currently we are not enforcing size limits for the ram_local1 and ram_m0 sections:

  • Once upon a time the rom shadow region was a 1:1 mapping to the entirety of the first block of physical SRAM (ram_local1 @ 0x1000 0000). (96kB on LPC4320, 128kB on LPC4330)
  • The libopencm3 linker scripts (ab)use this correspondence to support both hackrf_usb.bin storing the firmware in SPI Flash (from where it is copied to RAM by the factory boot ROM) and hackrf_usb.dfu which stores the firmware directly to RAM.
  • This worked fine for a long time until rom stopped being a 1:1 mapping to ram_local1:
    • We increased the size of rom to the size of the SPI Flash (1MB) so we could add the FPGA bit-streams.
    • We carved out 32 kB from the end of ram_local1 for ram_usb.

In an ideal world, instead of an assertion, we'd probably do a similar fix for ram_local1 as I did here for ram_m0 but I'm going to leave that as a separate exercise for someone else - braver than I - to untangle.

Note: how libopencm3 generates .dfu vs .bin

# LPC4320_M4_memory.ld
MEMORY
{
    /* rom is really the shadow region that points to SPI flash or elsewhere */
    rom (rx)  : ORIGIN = 0x00000000, LENGTH =  1M
    ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH =  64K
    ram_usb (rw) : ORIGIN = 0x10010000, LENGTH = 32K
    ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH =  32K
    ram_sleep (rwx) : ORIGIN = 0x10088000, LENGTH = 8K
}

Linker setup for the different targets are:

# Target: hackrf_usb.bin

# LDSCRIPT_M4
${MCU_PARTNO}_M4_memory.ld
LPC43xx_M4_M0_image_from_text.ld
LPC43xx_M4_memory_rom_only.ld      <-
libopencm3_lpc43xx_rom_to_ram.ld   <-
# Target: hackrf_usb_dfu.bin / hackrf_usb_ram.bin

# LDSCRIPT_M4_RAM
${MCU_PARTNO}_M4_memory.ld
LPC43xx_M4_M0_image_from_text.ld
libopencm3_lpc43xx.ld              <-

Works like this:

% diff -Nuwarp firmware/libopencm3/lib/libopencm3_lpc43xx.ld firmware/libopencm3/lib/libopencm3_lpc43xx_rom_to_ram.ld
--- firmware/libopencm3/lib/libopencm3_lpc43xx.ld       2026-07-31 16:05:16.126560939 +0200
+++ firmware/libopencm3/lib/libopencm3_lpc43xx_rom_to_ram.ld    2026-07-31 16:05:16.129894391 +0200
@@ -35,7 +35,8 @@ SECTIONS
 {
        .text : {
                . = ALIGN(0x400);
-               _text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+               _text_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1); /* Start of Code in RAM */
+
                *(.vectors)     /* Vector table */
                . = ALIGN(0x400);
                ASSERT(. == 0x400, "Error: attempting to place firmware information section at incorrect location");
@@ -86,8 +87,8 @@ SECTIONS

        . = ALIGN(4);
        _etext = .;
-       _etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
-       _etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+       _etext_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1);
+       _etext_rom = (. - ORIGIN(rom)) + ORIGIN(rom_flash);

        . = ORIGIN(ram_local2);

@@ -99,7 +100,7 @@ SECTIONS
        } >ram_local2 AT >rom
        _data_loadaddr = LOADADDR(.data);

-       _data_rom = LOADADDR (.data) + ORIGIN(rom);
+       _data_rom = LOADADDR (.data) + ORIGIN(rom_flash);
        _edata_rom = _data_rom + SIZEOF (.data);

        .bss : {

@antoinevg
antoinevg force-pushed the antoinevg/catch-ram-overrun branch from 8fa93e3 to 91df1d5 Compare July 31, 2026 14:39
@antoinevg
antoinevg marked this pull request as draft July 31, 2026 14:44
@antoinevg
antoinevg force-pushed the antoinevg/catch-ram-overrun branch from ad9ec50 to bb15e9c Compare August 3, 2026 08:33
@antoinevg
antoinevg marked this pull request as ready for review August 4, 2026 09:37
@martinling

Copy link
Copy Markdown
Member

@antoinevg I fixed #1807 in #1808 and merged those changes into this branch, but it's failing on Jenkins.

@antoinevg
antoinevg force-pushed the antoinevg/catch-ram-overrun branch 2 times, most recently from 35fc83b to 479c76d Compare August 6, 2026 08:41
@antoinevg
antoinevg marked this pull request as draft August 6, 2026 11:35
@antoinevg
antoinevg force-pushed the antoinevg/catch-ram-overrun branch from 479c76d to 5ca2f2f Compare August 11, 2026 15:55
@antoinevg antoinevg changed the title Enforce 64kB RAM limit in linker for DFU / RAM builds Catch linker overrun(s) and make more RAM available for firmware. Aug 11, 2026
@antoinevg
antoinevg force-pushed the antoinevg/catch-ram-overrun branch 5 times, most recently from 33a90d3 to 1144f9a Compare August 14, 2026 09:21
@antoinevg
antoinevg marked this pull request as ready for review August 17, 2026 08:13
@antoinevg
antoinevg force-pushed the antoinevg/catch-ram-overrun branch 2 times, most recently from ba432fb to 5c67a25 Compare August 17, 2026 09:27
@antoinevg
antoinevg marked this pull request as draft August 17, 2026 09:41
@antoinevg
antoinevg force-pushed the antoinevg/catch-ram-overrun branch from 5c67a25 to 310776d Compare August 17, 2026 10:18
@antoinevg
antoinevg marked this pull request as ready for review August 18, 2026 07:37
@martinling
martinling self-requested a review August 18, 2026 16:09
@martinling martinling self-assigned this Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants