Bug: PHYS_OFFSET no longer points to DRAM physical starting address with CONFIG_ARM64_VA_BITS_52

Ard Biesheuvel ardb at kernel.org
Sat Aug 22 06:39:38 PDT 2026



On Sat, 22 Aug 2026, at 16:28, Chen-Yu Tsai wrote:
> On Sat, Aug 22, 2026 at 8:50 PM Ard Biesheuvel <ardb at kernel.org> wrote:
>>
>> Hello Chen-Yu,
>>
>> On Sat, 22 Aug 2026, at 15:39, Chen-Yu Tsai wrote:
>> > Hi,
>> >
>> > On the Allwinner H6 & H616 SoC (and likely others), if running a kernel
>> > compiled with CONFIG_ARM64_VA_BITS_52 and CONFIG_ARM64_PA_BITS_52,
>> > PHYS_OFFSET no longer points to the start of DRAM (0x40000000) but instead
>> > points to 0xfff1000040000000.
>> >
>> >
>> > I've observed this for quite some time but hadn't really nailed down what
>> > was going on. For context: the IOMMU on these SoCs can only do 32-bit
>> > addresses, and that's pretty fine since the SoC only supports up to 4 GB
>> > DRAM. However the DRAM starts at 1GB offset in the physical address space.
>> > We want to be able to map the highest 1GB I/O virtual address space and
>> > thus need to check if the physical address is within 4GB without the
>> > offset. Having only 32-bits addressing, the address will wrap around fine.
>> > So we check the address against PHYS_OFFSE, which breaks with the mangled
>> > address.
>> >
>> >
>> > I suspect this is the result of the following commits:
>> >
>> >     7bc1a0f9e176 arm64: mm: use single quantity to represent the PA to
>> > VA translation
>> >     9684ec186f8f arm64: Enable LPA2 at boot if supported by the system
>> >
>> > The first commit introduces a negative (wrapped around) offset to
>> > memstart_addr (PHYS_OFFSET) to work around mapping restrictions, and the
>> > second commit makes the offset dependent on hardware.
>> >
>> >
>> > I hope that Ard and the maintainers can look into it and make PHYS_OFFSET
>> > always point to the physical start of DRAM.
>> >
>>
>> On what basis are you claiming that PHYS_OFFSET must always point to the
>> start of physical, non-secure DRAM?
>
> AFAIK we've been using this since armv7 in our older drivers to deal with
> PA <-> IOVA offsets. This was then concentrated into one interconnect
> driver: drivers/soc/sunxi/sunxi_mbus.c
>
> The driver applies PHYS_OFFSET as the DMA address offset for a class of
> devices when the system is using an older device tree that lacks interconnect
> properties.
>

That sounds like a hack to me tbh.

>
> There's also Documentation/admin-guide/kdump/vmcoreinfo.rst which states:
>
> ARM64
> =====
>
> PHYS_OFFSET
> -----------
>
> Indicates the physical address of the start of memory. Similar to
> kimage_voffset, which is used to translate virtual to physical
> addresses.
>

This information is inaccurate. kimage_voffset is the offset between the
kernel mapping in the vmalloc space and the associated physical memory.
It has nothing to do with PHYS_OFFSET or with the start of memory.

>> On arm64, PHYS_OFFSET is the physical address of the start of memory,
>> where 'start of memory' == PAGE_OFFSET, i.e., the start of the linear
>> map. When running a 52-bit VA kernel on hardware that is not LPA2 capable,
>> the hardware does not support mapping memory at PAGE_OFFSET, so it is moved
>> upward in the linear map.
>
> So it held true until 52-bit VA support was introduced?
>

It still holds true.

>> I don't quite follow why you need to compare with PHYS_OFFSET in your IOMMU
>> driver: could you elaborate?
>
> Our IOMMU only supports 32-bit of address space. On our SoCs, DRAM physically
> starts at 0x40000000 (1 GB offset), meaning any physical DRAM above 3GB
> would wrap around. However putting this number in drivers was discouraged
> in the past and we were told to use PHYS_OFFSET (on ARMv7) instead. Also,
> in the past there was this one chip that put DRAM at a different offset,
> so using a fixed number in the driver won't always work.
>
> Right now we're just blocking any physical address above 32 bits. Ideally
> we want to allow up to "start of DRAM + 4GB". So we need to know the DRAM
> start address. (And we probably want to block anything below start of DRAM
> as well.)
>

Should you be using memblock_start_of_DRAM() instead perhaps?



More information about the linux-arm-kernel mailing list