diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index dd320df0d026900d10c26f523a87c91b81a53569..12d5bf8b8d977a273203e8e7c9ae9603fd8ce584 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -31,6 +31,16 @@ typedef struct { unsigned long flags; } mm_context_t; +#define MAX_RES_REGIONS 32 + +struct res_mem { + phys_addr_t base; + phys_addr_t size; +}; + +extern struct res_mem res_mem[MAX_RES_REGIONS]; +extern int res_mem_count; + /* * This macro is only used by the TLBI code, which cannot race with an * ASID change and therefore doesn't need to reload the counter using diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index ceceb7529f370a8c7e9c3ec7d2ab890a9ff15813..c6a473e5384a1f6b8cfc124faa5463267c38e0e9 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -63,6 +63,7 @@ #include #include #include +#include static int num_standard_resources; static struct resource *standard_resources; @@ -208,8 +209,8 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) static void __init request_standard_resources(void) { struct memblock_region *region; - struct resource *res; - unsigned long i = 0; + struct resource *res, *res_resources; + unsigned long i = 0, j = 0, res_count; kernel_code.start = __pa_symbol(_text); kernel_code.end = __pa_symbol(__init_begin - 1); @@ -219,6 +220,16 @@ static void __init request_standard_resources(void) num_standard_resources = memblock.memory.cnt; standard_resources = alloc_bootmem_low(num_standard_resources * sizeof(*standard_resources)); + res_resources = alloc_bootmem_low(res_mem_count * + sizeof(struct resource)); + + for (res_count = 0; res_count < res_mem_count; res_count++) { + res_resources[res_count].name = "memmap reserved"; + res_resources[res_count].flags = IORESOURCE_MEM; + res_resources[res_count].start = res_mem[res_count].base; + res_resources[res_count].end = res_resources[res_count].start + + res_mem[res_count].size - 1; + } for_each_memblock(memory, region) { res = &standard_resources[i++]; @@ -246,6 +257,12 @@ static void __init request_standard_resources(void) crashk_res.end <= res->end) request_resource(res, &crashk_res); #endif + + for (; j < res_mem_count; j++) { + if (res_resources[j].start >= res->start && + res_resources[j].end <= res->end) + request_resource(res, &res_resources[j]); + } } } diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 7b6278bcc87b5cbf77f7da650c56f55a39e1bb71..8a968d8e46a7cdaa0079ae2d306ee5ead558346d 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -62,6 +62,9 @@ s64 memstart_addr __ro_after_init = -1; phys_addr_t arm64_dma_phys_limit __ro_after_init; +struct res_mem res_mem[MAX_RES_REGIONS]; +int res_mem_count; + #ifdef CONFIG_BLK_DEV_INITRD static int __init early_initrd(char *p) { @@ -371,6 +374,70 @@ static void __init fdt_enforce_memory_region(void) memblock_cap_memory_range(reg.base, reg.size); } +static int __init parse_memmap_one(char *p) +{ + char *oldp; + phys_addr_t start_at, mem_size; + int ret; + + if (!p) + return -EINVAL; + + oldp = p; + mem_size = memparse(p, &p); + if (p == oldp) + return -EINVAL; + + if (!mem_size) + return -EINVAL; + + mem_size = PAGE_ALIGN(mem_size); + + if (*p == '$') { + start_at = memparse(p+1, &p); + if (!IS_ALIGNED(start_at, SZ_2M)) { + pr_warn("cannot reserve memory: bad address is not 2MB aligned\n"); + return -EINVAL; + } + + if (!memblock_is_region_memory(start_at, mem_size)) { + pr_warn("cannot reserve memory: region is not meory\n"); + return -EINVAL; + } + + if (memblock_is_region_reserved(start_at, mem_size)) { + pr_warn("cannot reserve memory: region overlaps reserved memory\n"); + return -EINVAL; + } + + ret = memblock_reserve(start_at, mem_size); + if (!ret) { + res_mem[res_mem_count].base = start_at; + res_mem[res_mem_count].size = mem_size; + res_mem_count++; + } else + pr_warn("memmap memblock_reserve failed.\n"); + } + + return *p == '\0' ? 0 : -EINVAL; +} + +static int __init parse_memmap_opt(char *str) +{ + while (str) { + char *k = strchr(str, ','); + + if (k) + *k++ = 0; + + parse_memmap_one(str); + str = k; + } + + return 0; +} +early_param("memmap", parse_memmap_opt); + void __init arm64_memblock_init(void) { const s64 linear_region_size = -(s64)PAGE_OFFSET;