From: Peng Liu liupeng256@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NYPZ CVE: NA
-------------------------------------------------
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.
Signed-off-by: Peng Liu liupeng256@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../admin-guide/kernel-parameters.txt | 9 ++- arch/arm64/mm/init.c | 59 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index de8f7d447295..64be32ba4373 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2794,8 +2794,8 @@ 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. Such memmap=exactmap lines can be constructed based on BIOS output or other requirements. See the memmap=nn@ss option description. @@ -2806,7 +2806,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
@@ -2817,6 +2818,8 @@ 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. 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 e8d446164c76..f59546d3b0de 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -404,6 +404,65 @@ static int __init reserve_park_mem(void) } #endif
+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); + memblock_reserve(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) { const s64 linear_region_size = BIT(vabits_actual - 1);
From: Peng Liu liupeng256@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NYPZ CVE: NA
-------------------------------------------------
A new flag MEMBLOCK_MEMMAP is added into memblock_flags, which is used to identify reserved memory for memmap. This flag is limited for arm64. When memmap memory is reserved by memblock_reserve, it is subsequently marked with flag MEMBLOCK_MEMMAP. Therefore, for_each_mem_region can find memmap memory and request resources for it.
Signed-off-by: Peng Liu liupeng256@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- arch/arm64/kernel/setup.c | 19 +++++++++++++++++++ arch/arm64/mm/init.c | 1 + include/linux/memblock.h | 7 +++++++ mm/memblock.c | 12 ++++++++++++ 4 files changed, 39 insertions(+)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 7cd042536d3b..92d75e381bb1 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -215,6 +215,22 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) dump_stack_set_arch_desc("%s (DT)", name); }
+static void __init request_memmap_resources(struct resource *res) +{ + struct resource *memmap_res; + + 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; + + request_resource(res, memmap_res); +} + static void __init request_standard_resources(void) { struct memblock_region *region; @@ -253,6 +269,9 @@ 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); + #ifdef CONFIG_KEXEC_CORE /* * Userspace will find "Crash kernel" or "Crash kernel (low)" diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index f59546d3b0de..6ebfabde16f3 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -441,6 +441,7 @@ static int __init parse_memmap_one(char *p) } else if (*p == '$') { start_at = memparse(p + 1, &p); memblock_reserve(start_at, mem_size); + memblock_mark_memmap(start_at, mem_size); } else pr_info("Unrecognized memmap option, please check the parameter.\n");
diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 1a8d25f2e041..629bf7de021b 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -37,6 +37,7 @@ enum memblock_flags { MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */ MEMBLOCK_MIRROR = 0x2, /* mirrored region */ MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */ + MEMBLOCK_MEMMAP = 0x8, /* memmap reserved region */ };
/** @@ -116,6 +117,7 @@ int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); int memblock_mark_nomap(phys_addr_t base, phys_addr_t size); int memblock_clear_nomap(phys_addr_t base, phys_addr_t size); +int memblock_mark_memmap(phys_addr_t base, phys_addr_t size);
unsigned long memblock_free_all(void); void reset_node_managed_pages(pg_data_t *pgdat); @@ -248,6 +250,11 @@ static inline bool memblock_is_nomap(struct memblock_region *m) return m->flags & MEMBLOCK_NOMAP; }
+static inline bool memblock_is_memmap(struct memblock_region *m) +{ + return m->flags & MEMBLOCK_MEMMAP; +} + int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn, unsigned long *end_pfn); void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, diff --git a/mm/memblock.c b/mm/memblock.c index 2a6d1fa13280..d85893ab2f22 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -925,6 +925,18 @@ int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size) return memblock_setclr_flag(base, size, 0, MEMBLOCK_NOMAP); }
+/** + * memblock_mark_memmap - Mark a memory region with flag MEMBLOCK_MEMMAP. + * @base: the base phys addr of the region + * @size: the size of the region + * + * Return: 0 on success, -errno on failure. + */ +int __init_memblock memblock_mark_memmap(phys_addr_t base, phys_addr_t size) +{ + return memblock_setclr_flag(base, size, 1, MEMBLOCK_MEMMAP); +} + static bool should_skip_region(struct memblock_type *type, struct memblock_region *m, int nid, int flags)