[PATCH v3 6/6] common: Add an option to relocate on ram top

Ilias Apalodimas ilias.apalodimas at linaro.org
Wed Apr 29 08:12:50 CEST 2026


Hi Simon,

On Tue, 28 Apr 2026 at 20:49, Simon Glass <sjg at chromium.org> wrote:
>
> 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?

I did have the same concern and as far as I looked they were populated
in ascending order.

> 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) ?

The latter. I think it's fine for now but relying on that assumption
is dangerous. I'll just switch to max(...)

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

It does, and in the general case that won't be a problem. It will be
however if you have two non-contiguous banks and the DT somehow
reserves the second bank. You might end up relocating on a
non-existent address.

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

Yep good catch, thanks.

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

Yea, I'll add that. I just wanted to verify we got a usecase we
actually need it.

Thanks
/Ilias
>
> Regards,
> Simon


More information about the U-Boot mailing list