Skip to content

Commit d91680e

Browse files
committed
arm64: Fix /proc/iomem for reserved but not memory regions
We describe ranges of 'reserved' memory to userspace via /proc/iomem. Commit 50d7ba3 ("arm64: export memblock_reserve()d regions via /proc/iomem") updated the logic to export regions that were reserved because their contents should be preserved. This allowed kexec-tools to tell the difference between 'reserved' memory that must be preserved and not overwritten, (e.g. the ACPI tables), and 'nomap' memory that must not be touched without knowing the memory-attributes (e.g. RAS CPER regions). The above commit wrongly assumed that memblock_reserve() would not be used to reserve regions that aren't memory. It turns out this is exactly what early_init_dt_reserve_memory_arch() will do if it finds a DT reserved-memory that was also carved out of the memory node, which results in a WARN_ON_ONCE() and the region being reserved instead of ignored. The ramoops description on hikey and dragonboard-410c both do this, so we can't simply write this configuration off as "buggy firmware". Avoid this issue by rewriting reserve_memblock_reserved_regions() so that only the portions of reserved regions which overlap with mapped memory are actually reserved. Fixes: 50d7ba3 ("arm64: export memblock_reserve()d regions via /proc/iomem") Reported-by: John Stultz <[email protected]> Reported-by: Paolo Pisati <[email protected]> CC: Akashi Takahiro <[email protected]> CC: Ard Biesheuvel <[email protected]> Reviewed-by: James Morse <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent 0238df6 commit d91680e

File tree

1 file changed

+27
-29
lines changed

1 file changed

+27
-29
lines changed

arch/arm64/kernel/setup.c

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
#include <asm/xen/hypervisor.h>
6565
#include <asm/mmu_context.h>
6666

67+
static int num_standard_resources;
68+
static struct resource *standard_resources;
69+
6770
phys_addr_t __fdt_pointer __initdata;
6871

6972
/*
@@ -206,14 +209,19 @@ static void __init request_standard_resources(void)
206209
{
207210
struct memblock_region *region;
208211
struct resource *res;
212+
unsigned long i = 0;
209213

210214
kernel_code.start = __pa_symbol(_text);
211215
kernel_code.end = __pa_symbol(__init_begin - 1);
212216
kernel_data.start = __pa_symbol(_sdata);
213217
kernel_data.end = __pa_symbol(_end - 1);
214218

219+
num_standard_resources = memblock.memory.cnt;
220+
standard_resources = alloc_bootmem_low(num_standard_resources *
221+
sizeof(*standard_resources));
222+
215223
for_each_memblock(memory, region) {
216-
res = alloc_bootmem_low(sizeof(*res));
224+
res = &standard_resources[i++];
217225
if (memblock_is_nomap(region)) {
218226
res->name = "reserved";
219227
res->flags = IORESOURCE_MEM;
@@ -243,36 +251,26 @@ static void __init request_standard_resources(void)
243251

244252
static int __init reserve_memblock_reserved_regions(void)
245253
{
246-
phys_addr_t start, end, roundup_end = 0;
247-
struct resource *mem, *res;
248-
u64 i;
249-
250-
for_each_reserved_mem_region(i, &start, &end) {
251-
if (end <= roundup_end)
252-
continue; /* done already */
253-
254-
start = __pfn_to_phys(PFN_DOWN(start));
255-
end = __pfn_to_phys(PFN_UP(end)) - 1;
256-
roundup_end = end;
257-
258-
res = kzalloc(sizeof(*res), GFP_ATOMIC);
259-
if (WARN_ON(!res))
260-
return -ENOMEM;
261-
res->start = start;
262-
res->end = end;
263-
res->name = "reserved";
264-
res->flags = IORESOURCE_MEM;
265-
266-
mem = request_resource_conflict(&iomem_resource, res);
267-
/*
268-
* We expected memblock_reserve() regions to conflict with
269-
* memory created by request_standard_resources().
270-
*/
271-
if (WARN_ON_ONCE(!mem))
254+
u64 i, j;
255+
256+
for (i = 0; i < num_standard_resources; ++i) {
257+
struct resource *mem = &standard_resources[i];
258+
phys_addr_t r_start, r_end, mem_size = resource_size(mem);
259+
260+
if (!memblock_is_region_reserved(mem->start, mem_size))
272261
continue;
273-
kfree(res);
274262

275-
reserve_region_with_split(mem, start, end, "reserved");
263+
for_each_reserved_mem_region(j, &r_start, &r_end) {
264+
resource_size_t start, end;
265+
266+
start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start);
267+
end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end);
268+
269+
if (start > mem->end || end < mem->start)
270+
continue;
271+
272+
reserve_region_with_split(mem, start, end, "reserved");
273+
}
276274
}
277275

278276
return 0;

0 commit comments

Comments
 (0)