hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8NIMB
-------------------------------------------------
Add support for memmap kernel parameters for ARM64. The three below modes are supported:
memmap=exactmap Enable setting of an exact memory map, as specified by the user.
memmap=nn[KMG]@ss[KMG] Force usage of a specific region of memory.
memmap=nn[KMG]$ss[KMG] Region of memory to be reserved is from ss to ss+nn, the region must be in the range of existed memory, otherwise will be ignored.
If users set memmap=exactmap before memmap=nn[KMG]@ss[KMG], they will get the exact memory specified by memmap=nn[KMG]@ss[KMG]. For example, on one machine with 4GB memory, "memmap=exactmap memmap=1G@1G" will make kernel use the memory from 1GB to 2GB only.
Please note that the above functions are for debugging purposes only.
Signed-off-by: Ze Zuo zuoze1@huawei.com --- .../admin-guide/kernel-parameters.txt | 14 ++- arch/arm64/mm/init.c | 112 ++++++++++++++++++ arch/arm64/mm/internal.h | 12 ++ 3 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 arch/arm64/mm/internal.h
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index fe2dc03538fe..161297b49471 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3151,8 +3151,11 @@ option. See Documentation/admin-guide/mm/memory-hotplug.rst.
- memmap=exactmap [KNL,X86] Enable setting of an exact - E820 memory map, as specified by the user. + memmap=exactmap [KNL,X86,ARM64] Enable setting of an exact + E820 and ARM64 memory map, as specified by the user. + For ARM64, this setting is limited to dt boot mode as + exact mapping must be done after initializing membloc, + just for debugging purposes. Such memmap=exactmap lines can be constructed based on BIOS output or other requirements. See the memmap=nn@ss option description. @@ -3163,7 +3166,8 @@ If @ss[KMG] is omitted, it is equivalent to mem=nn[KMG], which limits max address to nn[KMG]. Multiple different regions can be specified, - comma delimited. + comma delimited, example as follows is not supported to + ARM64. Example: memmap=100M@2G,100M#3G,1G!1024G
@@ -3174,6 +3178,10 @@ memmap=nn[KMG]$ss[KMG] [KNL,ACPI] Mark specific memory as reserved. Region of memory to be reserved is from ss to ss+nn. + For ARM64, reserved memory must be in the range of + existed memory and do not overlap in-use memory region, + otherwise request will be ignored, just for debugging + purposes. Example: Exclude memory from 0x18690000-0x1869ffff memmap=64K$0x18690000 or diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 8a0f8604348b..8c8d7653ba84 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -46,6 +46,8 @@ #include <asm/alternative.h> #include <asm/xen/swiotlb-xen.h>
+#include "internal.h" + /* * We need to be able to catch inadvertent references to memstart_addr * that occur (potentially in generic code) before arm64_memblock_init() @@ -309,6 +311,114 @@ static int __init early_mem(char *p) } early_param("mem", early_mem);
+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) +{ + if (mbk_memmap_cnt >= MAX_RES_REGIONS) { + pr_err("Too many memmap specified, exceed %d\n", MAX_RES_REGIONS); + return; + } + + mbk_memmap_regions[mbk_memmap_cnt].base = base; + mbk_memmap_regions[mbk_memmap_cnt].size = size; + mbk_memmap_cnt++; +} + +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++) { + base = mbk_memmap_regions[i].base; + size = mbk_memmap_regions[i].size; + if (!memblock_is_region_memory(base, size)) { + str = "is not a memory region - ignore"; + goto err; + } + + if (memblock_is_region_reserved(base, size)) { + str = "overlaps in-use memory region - ignore"; + goto err; + } + + if (memblock_reserve(base, size)) { + str = "failed"; + goto err; + } + + pr_info("memmap reserved: 0x%08llx - 0x%08llx (%lld MB)", + 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); + } +} + +static int need_remove_real_memblock __initdata; + +static int __init parse_memmap_one(char *p) +{ + char *oldp; + u64 start_at, mem_size; + + if (!p) + return -EINVAL; + + if (!strncmp(p, "exactmap", 8)) { + need_remove_real_memblock = 1; + return -EINVAL; + } + + oldp = p; + mem_size = memparse(p, &p); + if (p == oldp) + return -EINVAL; + + if (!mem_size) + return -EINVAL; + + if (*p == '@') { + start_at = memparse(p + 1, &p); + /* + * use the exactmap defined by nn[KMG]@ss[KMG], remove + * memblock populated by DT etc. + */ + if (need_remove_real_memblock) { + need_remove_real_memblock = 0; + memblock_remove(0, ULLONG_MAX); + } + memblock_add(start_at, mem_size); + } else if (*p == '$') { + start_at = memparse(p + 1, &p); + setup_mbk_memmap_regions(start_at, mem_size); + } else + pr_info("Unrecognized memmap option, please check the parameter.\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) { s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual); @@ -481,6 +591,8 @@ void __init bootmem_init(void) */ reserve_crashkernel();
+ reserve_memmap_regions(); + memblock_dump_all(); }
diff --git a/arch/arm64/mm/internal.h b/arch/arm64/mm/internal.h new file mode 100644 index 000000000000..e75ad9dd656d --- /dev/null +++ b/arch/arm64/mm/internal.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ARM64_MM_INTERNAL_H +#define __ARM64_MM_INTERNAL_H + +#include <linux/types.h> + +#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 */