[PATCH 6.12.y 1/2] x86/ioremap: Sign-extend PAGE_MASK when aligning the physical address

From: Radek Marciňa

Date: Sat Oct 31 2026 - 11:45:36 EST


From: Radek Marciňa <github.unusual340@xxxxxxxxxx>

[ Stable-only fix: mainline is not affected since v6.13, see below. ]

On x86-32 with PAE, resource_size_t is 64-bit but PAGE_MASK is an
unsigned long, so in __ioremap_caller()

phys_addr &= PAGE_MASK;

clears bits 32-63 and ioremap() of anything above 4 GiB maps the alias
at the low 32 bits instead. The RAM check runs earlier on the original
address, so the alias is mapped even when it is system RAM, and the
caller's MMIO writes land there.

Commit ffa71f33a820 ("x86, ioremap: Fix incorrect physical address
handling in PAE mode") fixed this by masking with PHYSICAL_PAGE_MASK,
which casts PAGE_MASK to signed long. Commit 4dbd6a3e90e0 ("x86/ioremap:
Fix page aligned size calculation in __ioremap_caller()") reintroduced
the plain PAGE_MASK to compute the size before the high bits are masked
off. Cast it the same way here.

Mainline lost the bug when commit efe8419ae78d ("vdso: Introduce
vdso/page.h") and commit d4a65302dd84 ("vdso: Change PAGE_MASK to
signed on all 32-bit architectures") made PAGE_MASK signed on 32-bit.
Those rework PAGE_MASK for every architecture, so they are not
backported.

Fixes: 4dbd6a3e90e0 ("x86/ioremap: Fix page aligned size calculation in __ioremap_caller()")
Assisted-by: LLM
Signed-off-by: Radek Marciňa <github.unusual340@xxxxxxxxxx>
---
arch/x86/mm/ioremap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 8d29163568a7..14529884671e 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -223,7 +223,7 @@ __ioremap_caller(resource_size_t phys_addr, unsigned long size,
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
- phys_addr &= PAGE_MASK;
+ phys_addr &= (signed long)PAGE_MASK;
size = PAGE_ALIGN(last_addr+1) - phys_addr;

/*
--
2.56.0