[PATCH v3 2/4] x86/mm: simplify calculation of max_pfn_mapped

From: Brendan Jackman

Date: Wed Jun 24 2026 - 08:37:23 EST


The phys_*_init()s return the "last physical address mapped". The exact
definition of this is pretty fiddly, but only in these conditions:

1. There is a mismatch between the alignment of the requested range and
the page sizes allowed by page_size_mask.

For init_memory_mapping(), this is guaranteed by split_mem_range(),
whose job is to set the correct page_size_mask for each returned
range.

2. The range ends in a region that was already mapped. This case is
particularly fiddly because the return value depends on what level
the existing mapping is at. This is probably a bug, see [0] for
discussion.

Luckily, the callers of init_memory_mapping() all operate on distinct
regions and only call it at most once for any given range. So, just
lean on this caller behaviour and make it a precondition for calling
init_memory_mapping(). Thus, deliberately avoid relying on the
probably-broken return value.

[0]: https://lore.kernel.org/all/84b2e7a3-7115-45fe-89ff-db8ee46729f2@xxxxxxxxx/

Reviewed-by: Marcel Busch <mbsh@xxxxxxxxxx>
Tested-by: Marcel Busch <mbsh@xxxxxxxxxx>
Signed-off-by: Brendan Jackman <jackmanb@xxxxxxxxxx>
---
arch/x86/mm/init.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index ae3e9e0820153..1c9e6d8ebb8d7 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -530,6 +530,8 @@ bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn)
* Setup the direct mapping of the physical memory at PAGE_OFFSET.
* This runs before bootmem is initialized and gets pages directly from
* the physical memory. To access them they are temporarily mapped.
+ *
+ * Call this function at most once for any given range.
*/
void __ref init_memory_mapping(unsigned long start,
unsigned long end, pgprot_t prot)
@@ -545,10 +547,10 @@ void __ref init_memory_mapping(unsigned long start,
nr_range = split_mem_range(mr, 0, start, end);

for (i = 0; i < nr_range; i++)
- paddr_last = kernel_physical_mapping_init(mr[i].start, mr[i].end,
- mr[i].page_size_mask,
- prot);
+ kernel_physical_mapping_init(mr[i].start, mr[i].end,
+ mr[i].page_size_mask, prot);

+ paddr_last = mr[nr_range - 1].end;
add_pfn_range_mapped(start >> PAGE_SHIFT, paddr_last >> PAGE_SHIFT);
}


--
2.54.0