Message ID | 20250409182129.634415-1-bjorn@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [fixes] riscv: Properly export reserved regions in /proc/iomem | expand |
Context | Check | Description |
---|---|---|
bjorn/pre-ci_am | success | Success |
bjorn/build-rv32-defconfig | success | build-rv32-defconfig |
bjorn/build-rv64-clang-allmodconfig | success | build-rv64-clang-allmodconfig |
bjorn/build-rv64-gcc-allmodconfig | success | build-rv64-gcc-allmodconfig |
bjorn/build-rv64-nommu-k210-defconfig | success | build-rv64-nommu-k210-defconfig |
bjorn/build-rv64-nommu-k210-virt | success | build-rv64-nommu-k210-virt |
bjorn/checkpatch | success | checkpatch |
bjorn/dtb-warn-rv64 | success | dtb-warn-rv64 |
bjorn/header-inline | success | header-inline |
bjorn/kdoc | success | kdoc |
bjorn/module-param | success | module-param |
bjorn/verify-fixes | success | verify-fixes |
bjorn/verify-signedoff | success | verify-signedoff |
Hi Bjorn, On 09/04/2025 20:21, Björn Töpel wrote: > From: Björn Töpel <bjorn@rivosinc.com> > > The /proc/iomem represents the kernel's memory map. Regions marked > with "Reserved" tells the user that the range should not be tampered > with. Kexec-tools, when using the older kexec_load syscall relies on > the "Reserved" regions to build the memory segments, that will be the > target of the new kexec'd kernel. > > The RISC-V port tries to expose all reserved regions to userland, but > some regions were not properly exposed: Regions that resided in both > the "regular" and reserved memory block, e.g. the EFI Memory Map. A > missing entry could result in reserved memory being overwritten. > > It turns out, that arm64, and loongarch had a similar issue a while > back: > > commit d91680e687f4 ("arm64: Fix /proc/iomem for reserved but not memory regions") > commit 50d7ba36b916 ("arm64: export memblock_reserve()d regions via /proc/iomem") > > Similar to the other ports, resolve the issue by splitting the regions > in an arch initcall, since we need a working allocator. > > Fixes: ffe0e5261268 ("RISC-V: Improve init_resources()") > Signed-off-by: Björn Töpel <bjorn@rivosinc.com> > --- > arch/riscv/kernel/setup.c | 36 +++++++++++++++++++++++++++++++++++- > 1 file changed, 35 insertions(+), 1 deletion(-) > > diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c > index c174544eefc8..f7c9a1caa83e 100644 > --- a/arch/riscv/kernel/setup.c > +++ b/arch/riscv/kernel/setup.c > @@ -66,6 +66,9 @@ static struct resource bss_res = { .name = "Kernel bss", }; > static struct resource elfcorehdr_res = { .name = "ELF Core hdr", }; > #endif > > +static int num_standard_resources; > +static struct resource *standard_resources; > + > static int __init add_resource(struct resource *parent, > struct resource *res) > { > @@ -139,7 +142,7 @@ static void __init init_resources(void) > struct resource *res = NULL; > struct resource *mem_res = NULL; > size_t mem_res_sz = 0; > - int num_resources = 0, res_idx = 0; > + int num_resources = 0, res_idx = 0, non_resv_res = 0; > int ret = 0; > > /* + 1 as memblock_alloc() might increase memblock.reserved.cnt */ > @@ -193,6 +196,7 @@ static void __init init_resources(void) > /* Add /memory regions to the resource tree */ > for_each_mem_region(region) { > res = &mem_res[res_idx--]; > + non_resv_res++; > > if (unlikely(memblock_is_nomap(region))) { > res->name = "Reserved"; > @@ -210,6 +214,9 @@ static void __init init_resources(void) > goto error; > } > > + num_standard_resources = non_resv_res; > + standard_resources = &mem_res[res_idx + 1]; > + > /* Clean-up any unused pre-allocated resources */ > if (res_idx >= 0) > memblock_free(mem_res, (res_idx + 1) * sizeof(*mem_res)); > @@ -221,6 +228,33 @@ static void __init init_resources(void) > memblock_free(mem_res, mem_res_sz); > } > > +static int __init reserve_memblock_reserved_regions(void) > +{ > + u64 i, j; > + > + for (i = 0; i < num_standard_resources; i++) { > + struct resource *mem = &standard_resources[i]; > + phys_addr_t r_start, r_end, mem_size = resource_size(mem); > + > + if (!memblock_is_region_reserved(mem->start, mem_size)) > + continue; > + > + for_each_reserved_mem_range(j, &r_start, &r_end) { > + resource_size_t start, end; > + > + start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); > + end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); > + > + if (start > mem->end || end < mem->start) > + continue; > + > + reserve_region_with_split(mem, start, end, "Reserved"); > + } > + } > + > + return 0; > +} > +arch_initcall(reserve_memblock_reserved_regions); > > static void __init parse_dtb(void) > { > > base-commit: a24588245776dafc227243a01bfbeb8a59bafba9 Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com> It will be merged with other fixes in the next rc-ish! Thanks, Alex
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index c174544eefc8..f7c9a1caa83e 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -66,6 +66,9 @@ static struct resource bss_res = { .name = "Kernel bss", }; static struct resource elfcorehdr_res = { .name = "ELF Core hdr", }; #endif +static int num_standard_resources; +static struct resource *standard_resources; + static int __init add_resource(struct resource *parent, struct resource *res) { @@ -139,7 +142,7 @@ static void __init init_resources(void) struct resource *res = NULL; struct resource *mem_res = NULL; size_t mem_res_sz = 0; - int num_resources = 0, res_idx = 0; + int num_resources = 0, res_idx = 0, non_resv_res = 0; int ret = 0; /* + 1 as memblock_alloc() might increase memblock.reserved.cnt */ @@ -193,6 +196,7 @@ static void __init init_resources(void) /* Add /memory regions to the resource tree */ for_each_mem_region(region) { res = &mem_res[res_idx--]; + non_resv_res++; if (unlikely(memblock_is_nomap(region))) { res->name = "Reserved"; @@ -210,6 +214,9 @@ static void __init init_resources(void) goto error; } + num_standard_resources = non_resv_res; + standard_resources = &mem_res[res_idx + 1]; + /* Clean-up any unused pre-allocated resources */ if (res_idx >= 0) memblock_free(mem_res, (res_idx + 1) * sizeof(*mem_res)); @@ -221,6 +228,33 @@ static void __init init_resources(void) memblock_free(mem_res, mem_res_sz); } +static int __init reserve_memblock_reserved_regions(void) +{ + u64 i, j; + + for (i = 0; i < num_standard_resources; i++) { + struct resource *mem = &standard_resources[i]; + phys_addr_t r_start, r_end, mem_size = resource_size(mem); + + if (!memblock_is_region_reserved(mem->start, mem_size)) + continue; + + for_each_reserved_mem_range(j, &r_start, &r_end) { + resource_size_t start, end; + + start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); + end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); + + if (start > mem->end || end < mem->start) + continue; + + reserve_region_with_split(mem, start, end, "Reserved"); + } + } + + return 0; +} +arch_initcall(reserve_memblock_reserved_regions); static void __init parse_dtb(void) {