On Mon, Feb 28, 2022 at 02:31:05PM +0800, Tiezhu Yang wrote: > According to Documentation/admin-guide/kernel-parameters.txt, > the kernel command-line parameter memmap= means "Force usage > of a specific region of memory", but when add "memmap=3G@64M" > to the command-line, kernel boot hangs in sparse_init(). > > In order to support memmap=limit@base, refactor the function > early_parse_memmap() and then use memblock_mem_range_remove_map() > to limit the memory region. > > With this patch, when add "memmap=3G@64M" to the command-line, > the kernel boots successfully, we can see the following messages: > > [ 0.000000] Memory limited to 64MB-3136MB > ... > [ 0.000000] Early memory node ranges > [ 0.000000] node 0: [mem 0x0000000004000000-0x000000000effffff] > [ 0.000000] node 0: [mem 0x0000000090200000-0x00000000ffffffff] > [ 0.000000] node 0: [mem 0x0000000120000000-0x00000001653fffff] > ... > [ 0.000000] Memory: 3070816K/3147776K available (...) > > When add "memmap=128M@64M nr_cpus=1 init 3" to the command-line, > the kernel also boots successfully, we can see the following messages: > > [ 0.000000] Memory limited to 64MB-192MB > ... > [ 0.000000] Early memory node ranges > [ 0.000000] node 0: [mem 0x0000000004000000-0x000000000c1fffff] > ... > [ 0.000000] Memory: 95312K/133120K available (...) > > After login, the output of free command is consistent with the > above log. > > By the way, this commit only supports memmap=limit@base format, > the other formats such as memmap=limit#base, memmap=limit$base > and memmap=limit!base can be added if they are necessary in the > future. > > Signed-off-by: Tiezhu Yang <yangtiezhu@xxxxxxxxxxx> > --- > arch/mips/kernel/setup.c | 42 +++++++++--------------------------------- > 1 file changed, 9 insertions(+), 33 deletions(-) > > diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c > index 6b6d718..e3b1f2e 100644 > --- a/arch/mips/kernel/setup.c > +++ b/arch/mips/kernel/setup.c > @@ -340,6 +340,7 @@ static void __init bootmem_init(void) > > static int usermem __initdata; > static phys_addr_t memory_limit; > +static phys_addr_t memory_base; > > static int __init early_parse_mem(char *p) > { > @@ -355,42 +356,17 @@ early_param("mem", early_parse_mem); > > static int __init early_parse_memmap(char *p) > { > - char *oldp; > - u64 start_at, mem_size; > - > if (!p) > - return -EINVAL; > + return 1; > > - if (!strncmp(p, "exactmap", 8)) { > - pr_err("\"memmap=exactmap\" invalid on MIPS\n"); > - return 0; > - } > + memory_limit = memparse(p, &p) & PAGE_MASK; > + if (*p == '@') > + memory_base = memparse(p + 1, &p) & PAGE_MASK; > > - oldp = p; > - mem_size = memparse(p, &p); > - if (p == oldp) > - return -EINVAL; > - > - if (*p == '@') { > - start_at = memparse(p+1, &p); > - memblock_add(start_at, mem_size); > - } else if (*p == '#') { > - pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on MIPS\n"); > - return -EINVAL; > - } else if (*p == '$') { > - start_at = memparse(p+1, &p); > - memblock_add(start_at, mem_size); > - memblock_reserve(start_at, mem_size); > - } else { > - pr_err("\"memmap\" invalid format!\n"); > - return -EINVAL; This breaks backward compatibility for systems that use memmap=X#Y and memmap=X$Y. For your use case it is enough to implement "memmap=exactmap" that will drop memory provided by the firmware and only use ranges supplied in memmap= > - } > + pr_notice("Memory limited to %lldMB-%lldMB\n", > + memory_base >> 20, (memory_base + memory_limit) >> 20); > > - if (*p == '\0') { > - usermem = 1; > - return 0; > - } else > - return -EINVAL; > + return 0; > } > early_param("memmap", early_parse_memmap); > > @@ -667,7 +643,7 @@ static void __init arch_mem_init(char **cmdline_p) > __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin)); > > /* Limit the memory. */ > - memblock_enforce_memory_limit(memory_limit); > + memblock_mem_range_remove_map(memory_base, memory_limit); > memblock_allow_resize(); > > early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn)); > -- > 2.1.0 > -- Sincerely yours, Mike.