riscv: Properly export reserved regions in /proc/iomem
[ Upstream commit e94eb7ea6f206e229791761a5fdf9389f8dbd183 ] 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: commitd91680e687("arm64: Fix /proc/iomem for reserved but not memory regions") commit50d7ba36b9("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:ffe0e52612("RISC-V: Improve init_resources()") Signed-off-by: Björn Töpel <bjorn@rivosinc.com> Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com> Link: https://lore.kernel.org/r/20250409182129.634415-1-bjorn@kernel.org Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
c8c3f8e7a7
commit
1d5a8e1fec
@@ -66,6 +66,9 @@ static struct resource bss_res = { .name = "Kernel bss", };
|
|||||||
static struct resource elfcorehdr_res = { .name = "ELF Core hdr", };
|
static struct resource elfcorehdr_res = { .name = "ELF Core hdr", };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int num_standard_resources;
|
||||||
|
static struct resource *standard_resources;
|
||||||
|
|
||||||
static int __init add_resource(struct resource *parent,
|
static int __init add_resource(struct resource *parent,
|
||||||
struct resource *res)
|
struct resource *res)
|
||||||
{
|
{
|
||||||
@@ -139,7 +142,7 @@ static void __init init_resources(void)
|
|||||||
struct resource *res = NULL;
|
struct resource *res = NULL;
|
||||||
struct resource *mem_res = NULL;
|
struct resource *mem_res = NULL;
|
||||||
size_t mem_res_sz = 0;
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
/* + 1 as memblock_alloc() might increase memblock.reserved.cnt */
|
/* + 1 as memblock_alloc() might increase memblock.reserved.cnt */
|
||||||
@@ -195,6 +198,7 @@ static void __init init_resources(void)
|
|||||||
/* Add /memory regions to the resource tree */
|
/* Add /memory regions to the resource tree */
|
||||||
for_each_mem_region(region) {
|
for_each_mem_region(region) {
|
||||||
res = &mem_res[res_idx--];
|
res = &mem_res[res_idx--];
|
||||||
|
non_resv_res++;
|
||||||
|
|
||||||
if (unlikely(memblock_is_nomap(region))) {
|
if (unlikely(memblock_is_nomap(region))) {
|
||||||
res->name = "Reserved";
|
res->name = "Reserved";
|
||||||
@@ -212,6 +216,9 @@ static void __init init_resources(void)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
num_standard_resources = non_resv_res;
|
||||||
|
standard_resources = &mem_res[res_idx + 1];
|
||||||
|
|
||||||
/* Clean-up any unused pre-allocated resources */
|
/* Clean-up any unused pre-allocated resources */
|
||||||
if (res_idx >= 0)
|
if (res_idx >= 0)
|
||||||
memblock_free(mem_res, (res_idx + 1) * sizeof(*mem_res));
|
memblock_free(mem_res, (res_idx + 1) * sizeof(*mem_res));
|
||||||
@@ -223,6 +230,33 @@ static void __init init_resources(void)
|
|||||||
memblock_free(mem_res, mem_res_sz);
|
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)
|
static void __init parse_dtb(void)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user