Re: [PATCH v2 2/3] sparc32: derive phys_base from the PAGE_OFFSET mapping
From: Magnus Lindholm
Date: Sun Sep 27 2026 - 18:26:10 EST
Hi Andreas,
On Fri, Sep 25, 2026 at 5:46 PM Andreas Larsson <andreas@xxxxxxxxxxx> wrote:
>
> On 2026-08-16 09:50, Magnus Lindholm wrote:
> > setup_arch() computes phys_base as the base of the lowest sp_banks[]
> > entry, that is, where RAM starts, and assumes the kernel image was loaded
> > there. That holds for the traditional boot path, where SILO places the
> > image at physical 0x4000 and PAGE_OFFSET is mapped to physical 0.
> >
> > It stops holding once the image no longer fits there. SILO loads a kernel
> > between physical 0x4000 and its own text at 0x280000, a window of 2605056
> > bytes; a current sparc32 kernel is roughly twice that. The loader must
> > then place the image elsewhere in physical memory and map PAGE_OFFSET to
> > it, at which point phys_base describes where RAM begins rather than what
> > PAGE_OFFSET maps to, and the two disagree.
> >
> > phys_base is the offset __pa() and __va() are defined in terms of, so once
> > it is wrong every early translation is wrong by the difference, including
> > the physical addresses written into page table descriptors. The
> > tablewalker then follows pointers into pages that hold nothing while the
> > same tables read back correctly through the nocache view. The failure
> > surfaces as a hang right after the context table pointer is installed and
> > the TLB flushed, with nothing on the console to explain it, since the PROM
> > mappings the early console depends on have become just as unreachable.
> >
> > Ask the MMU what PAGE_OFFSET actually translates to and adopt that.
> > __get_phys() already implements this probe for sun4m and sun4d and returns
> > zero elsewhere, so no new low level MMU access is introduced and machines
> > without an SRMMU are unaffected.
> >
> > Memory below the kernel cannot be reached through the linear map, which
> > runs upward from PAGE_OFFSET, so drop the banks that fall below it rather
> > than leave entries that __va() would translate to below PAGE_OFFSET.
> >
> > With this a 6MB kernel loaded at physical 0x03000000 boots on sun4m: the
> > context table lands at its true physical address,
> > srmmu_inherit_prom_mappings() preserves the PROM console mappings, and
> > srmmu.c needs no change at all, since map_kernel() already handles a
> > non-zero phys_base via do_large_mapping().
> >
> > The cost is the RAM below the load address the loader chose. SILO's
> > memory_find() picks 48MB on machines with 64MB or more.
> >
> > Signed-off-by: Magnus Lindholm <linmag7@xxxxxxxxx>
> > ---
> > arch/sparc/kernel/setup_32.c | 40 ++++++++++++++++++++++++++++++++++++
> > 1 file changed, 40 insertions(+)
> >
> > diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
> > index 1b0db16cd37b..34e8f7c87685 100644
> > --- a/arch/sparc/kernel/setup_32.c
> > +++ b/arch/sparc/kernel/setup_32.c
> > @@ -254,6 +254,30 @@ static __init void leon_patch(void)
> >
> > struct tt_entry *sparc_ttable;
> >
> > +/* Drop RAM below the kernel; the linear map runs upward from phys_base
> > + * and cannot reach it.
> > + */
> > +static void __init trim_sp_banks_below(unsigned long base)
> > +{
> > + int i, j = 0;
> > +
> > + for (i = 0; sp_banks[i].num_bytes != 0; i++) {
> > + unsigned long start = sp_banks[i].base_addr;
> > + unsigned long end = start + sp_banks[i].num_bytes;
> > +
> > + if (end <= base)
> > + continue; /* wholly below - drop it */
> > + if (start < base)
> > + start = base; /* straddles - trim the front */
> > +
> > + sp_banks[j].base_addr = start;
> > + sp_banks[j].num_bytes = end - start;
> > + j++;
> > + }
> > + sp_banks[j].base_addr = 0;
> > + sp_banks[j].num_bytes = 0;
> > +}
> > +
> > /* Called from head_32.S - before we have setup anything
> > * in the kernel. Be very careful with what you do here.
> > */
> > @@ -332,6 +356,22 @@ void __init setup_arch(char **cmdline_p)
> > if (highest_paddr < top)
> > highest_paddr = top;
> > }
> > +
> > + /* phys_base must describe what PAGE_OFFSET maps to, not where RAM starts. */
> > + {
> > + unsigned long real_base = __get_phys(PAGE_OFFSET);
> > +
> > + prom_printf("phys_base: RAM starts 0x%lx, kernel is at 0x%lx\n",
> > + phys_base, real_base);
>
>
> This must not print bogus information on LEON systems.
>
> It is a pity that leon_swprobe() is not ready for use at this point or
> it could have been used in __get_phys(). It could be changed in the
> future to not do the strict checks that now depends on variables
> initialized later with, the here calculated, phys_base as input. For
> now, please refrain from printing the above on systems not supported
> by __get_phys(), or move it or parts of it back under the if below.
>
> Nit: I think it should be "...RAM starts at 0x%lx..."
>
> Apart from that, this patch, as well as the rest of the series looks
> good!
>
Hi Andreas,
Thanks for the review and feedback! A v3 is on the way restricting the
probe and diagnostic to sun4m and sun4d, so it won't print a bogus kernel
address on LEON. I'll also fix the wording to "RAM starts at".
Thanks,
Magnus