[PATCH v3 6/6] common: Add an option to relocate on ram top
Simon Glass
sjg at chromium.org
Tue Apr 28 19:48:47 CEST 2026
Hi Ilias,
On 2026-04-27T10:08:21, Ilias Apalodimas <ilias.apalodimas at linaro.org> wrote:
> common: Add an option to relocate on ram top
>
> Right now we only relocate u-boot to the top of the first
> memory bank unless the board specific code overwrites it.
> This is problematic when loading big binaries as it
> fragments the contiguous memory space for no apparent reason.
>
> On certain platforms, it is currently not possible to relocate U-Boot
> above the 32bit boundary, due to various dependencies on content located
> below the 32bit boundary. One such example is ethernet, where the packet
> buffer built into U-Boot binary is placed below the 32bit boundary and
> allows loading of data via ethernet even above 32bit boundary due to
> memory copy from the packet buffer to the destination location.
>
> A previous patch moves the bi_dram[] info from bd to gd and make
> the memory bank information available early. So move the
> dram_init_banksize() INITCALL before the relocation address calculation
> and use it to derive the address.
>
> Also add a Kconfig option and allow the common code to relocate U-Boot
> [...]
>
> Kconfig | 12 ++++++++++++
> common/board_f.c | 32 ++++++++++++++++++++++++++------
> 2 files changed, 38 insertions(+), 6 deletions(-)
> diff --git a/Kconfig b/Kconfig
> @@ -491,6 +491,18 @@ config SKIP_RELOCATE_CODE_DATA_OFFSET
> +config RELOC_ADDR_TOP
> + bool "Relocate to the topmost memory address"
> + depends on EXPERT
> + help
> + When U-Boot relocates, it chooses the end of the first memory bank.
> + Enable this if you have multiple banks and want U-Boot to relocate
> + to the topmost memory address. This will use the information of the
> + board memory banks configured with dram_init_banksize() to calculate
> + the relocation address.
> + Use this if you are certain all of the devices can access memory
> + above the 32bit boundary.
The help text mentions the 32-bit boundary as the hazard but never
explains why. Please spell out the DMA aspect, e.g. something like
'devices that can only DMA below 4GiB will misbehave because their
buffers may be allocated above the 32-bit boundary after relocation'
> diff --git a/common/board_f.c b/common/board_f.c
> @@ -339,7 +340,28 @@ static int setup_ram_base(void)
> + if (CONFIG_IS_ENABLED(RELOC_ADDR_TOP)) {
> + int bank;
> + phys_size_t total_size = 0;
> + phys_addr_t top;
> +
> + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
> + if (gd->ram_top <= gd->dram[bank].start)
> + gd->ram_top = gd->dram[bank].start +
> + gd->dram[bank].size;
> + total_size += gd->dram[bank].size;
> + }
> + gd->ram_size = total_size;
> +
> + top = get_mem_top(gd->ram_base, gd->ram_size, 0, (void *)gd->fdt_blob);
> + if (top)
> + gd->ram_top = top;
A few things to figure out here:
First, the loop only updates ram_top when gd->ram_top <=
gd->dram[bank].start - that assumes banks are populated in ascending
order of start address. Is that, guaranteed? If so, we should indicate
this somewhere. Or maybe use gd->ram_top = max(gd->ram_top,
gd->dram[bank].start + gd->dram[bank].size) ?
Second, summing gd->dram[bank].size into total_size and then calling
get_mem_top(gd->ram_base, gd->ram_size, 0, ...) presents the banks as
a single contiguous region from ram_base of length total_size, but if
the banks are not contiguous (the main motivation for this feature?),
holes between banks are now treated as usable RAM. See common/memtop.c
- get_mem_top() does a single add_mem_region(&free_mem, ram_start,
ram_size)
Third, the cover letter says "Use get_mem_top() instead ... That
function will account for the reserved memory regions and exclude
them". It does not seem to do that here. With size=0, find_ram_top()
computes base = rgnbase + rgnsize - size (the byte past the last RAM
byte) and region_overlap_check() with size=0 reduces to whether
rgnbase_res < base && base <= r_end, which is false for every reserved
region within the RAM extent. The call ends up being a no-op for
reserved-memory exclusion, i.e. gd->ram_top ends up at the very end of
the topmost bank regardless of /reserved-memory or /memreserve. For
exclusion you need a non-zero size - see board/xilinx/common/board.c
for example.
Lastly (as Marek mentioned) this path skips board_get_usable_ram_top()
entirely. Boards that override it to carve off secure-world regions,
framebuffer etc. will have those silently ignored when RELOC_ADDR_TOP
is enabled. After a bit more thought, we really should support it,
e.g. look at board_get_usable_ram_top() and only override if it
returns the unmodified value. Or perhaps change its function signature
so it returns an error code indicating whether anything changed.
Regards,
Simon
More information about the U-Boot
mailing list