From: Kefeng Wang wangkefeng.wang@huawei.com
hulk inclusion category: bugfix bugzilla: 187483, https://gitee.com/openeuler/kernel/issues/I5MH9N CVE: NA
--------------------------------
When support memmap=nn[KMG]$ss[KMG], it will request resource to show reserved memory in iomem, but with memblock_setclr_flag() called memblock_mark_memmap() leads to split memblock region and then request_resource() could return -EBUSY when passed unaligned address.
Let's directly use memblock_reserve() and drop membloc_setclr_flag() and show error if request_resource() in request_memmap_resource() return error code.
Signed-off-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Liu Shixin liushixin2@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- arch/arm64/kernel/setup.c | 37 +++++++++++++++++++++++++++---------- arch/arm64/mm/init.c | 30 +++++++++++++++--------------- arch/arm64/mm/internal.h | 4 ++++ 3 files changed, 46 insertions(+), 25 deletions(-)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index ddca8d27fca6..940e237009e9 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -219,17 +219,34 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) static void __init request_memmap_resources(struct resource *res) { struct resource *memmap_res; + phys_addr_t base, size; + int i; + + for (i = 0; i < MAX_RES_REGIONS; i++) { + base = mbk_memmap_regions[i].base; + size = mbk_memmap_regions[i].size; + if (!size) + continue; + + if ((base < res->start) || (base + size - 1 > res->end)) + continue;
- memmap_res = memblock_alloc(sizeof(*memmap_res), SMP_CACHE_BYTES); - if (!memmap_res) - panic("%s: Failed to allocate memmap_res\n", __func__); + memmap_res = memblock_alloc(sizeof(*memmap_res), SMP_CACHE_BYTES); + if (!memmap_res) + panic("%s: Failed to allocate memmap_res\n", __func__);
- memmap_res->name = "memmap reserved"; - memmap_res->flags = IORESOURCE_MEM; - memmap_res->start = res->start; - memmap_res->end = res->end; + memmap_res->name = "memmap reserved"; + memmap_res->flags = IORESOURCE_MEM; + memmap_res->start = base; + memmap_res->end = base + size - 1;
- request_resource(res, memmap_res); + if (request_resource(res, memmap_res)) { + pr_warn("memmap reserve: [%llx, %llx] request resource fail\n", + memmap_res->start, memmap_res->end); + memblock_free_early(virt_to_phys(memmap_res), + sizeof(*memmap_res)); + } + } }
static void __init request_standard_resources(void) @@ -270,8 +287,8 @@ static void __init request_standard_resources(void) if (kernel_data.start >= res->start && kernel_data.end <= res->end) request_resource(res, &kernel_data); - if (memblock_is_memmap(region)) - request_memmap_resources(res); + + request_memmap_resources(res);
#ifdef CONFIG_KEXEC_CORE /* Userspace will find "Crash kernel" region in /proc/iomem. */ diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 5023c7e1f754..7ef7c0e7ee7c 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -297,10 +297,8 @@ static void __init fdt_enforce_memory_region(void) memblock_add(usable_rgns[1].base, usable_rgns[1].size); }
-#define MAX_RES_REGIONS 32 - -static struct memblock_region mbk_memmap_regions[MAX_RES_REGIONS] __initdata_memblock; -static int mbk_memmap_cnt __initdata; +struct memblock_region mbk_memmap_regions[MAX_RES_REGIONS] __initdata_memblock; +int mbk_memmap_cnt __initdata;
static void __init setup_mbk_memmap_regions(phys_addr_t base, phys_addr_t size) { @@ -317,6 +315,7 @@ static void __init setup_mbk_memmap_regions(phys_addr_t base, phys_addr_t size) static void __init reserve_memmap_regions(void) { phys_addr_t base, size; + const char *str; int i;
for (i = 0; i < mbk_memmap_cnt; i++) { @@ -324,26 +323,27 @@ static void __init reserve_memmap_regions(void) size = mbk_memmap_regions[i].size;
if (!memblock_is_region_memory(base, size)) { - pr_warn("memmap reserve: 0x%08llx - 0x%08llx is not a memory region - ignore\n", - base, base + size); - continue; + str = "is not a memory region - ignore"; + goto err; }
if (memblock_is_region_reserved(base, size)) { - pr_warn("memmap reserve: 0x%08llx - 0x%08llx overlaps in-use memory region - ignore\n", - base, base + size); - continue; + str = "overlaps in-use memory region - ignore"; + goto err; }
if (memblock_reserve(base, size)) { - pr_warn("memmap reserve: 0x%08llx - 0x%08llx failed\n", - base, base + size); - continue; + str = "failed"; + goto err; }
pr_info("memmap reserved: 0x%08llx - 0x%08llx (%lld MB)", - base, base + size, size >> 20); - memblock_mark_memmap(base, size); + base, base + size - 1, size >> 20); + continue; +err: + mbk_memmap_regions[i].size = 0; + pr_warn("memmap reserve: 0x%08llx - 0x%08llx %s\n", + base, base + size - 1, str); } }
diff --git a/arch/arm64/mm/internal.h b/arch/arm64/mm/internal.h index 9b8e20d87172..2af98d110668 100644 --- a/arch/arm64/mm/internal.h +++ b/arch/arm64/mm/internal.h @@ -22,4 +22,8 @@ static inline void __init reserve_quick_kexec(void) {} static inline void __init request_quick_kexec_res(struct resource *res) {} #endif
+#define MAX_RES_REGIONS 32 +extern struct memblock_region mbk_memmap_regions[MAX_RES_REGIONS]; +extern int mbk_memmap_cnt; + #endif /* ifndef _ARM64_MM_INTERNAL_H */