Most of the modern platforms supported by linux kernel have already
been cleaned up of old bootmem allocator by moving to nobootmem
interface wrapping up the memblock. This patchset is the first
attempt to do the similar improvement for MIPS for UMA systems
only.
Even though the porting was performed as much careful as possible
there still might be problem with support of some platforms,
especially Loonson3 or SGI IP27, which perform early memory manager
initialization by their self.
The patchset is split so individual patch being consistent in
functional and buildable ways. But the MIPS early memory manager
will work correctly only either with or without the whole set being
applied. For the same reason a reviewer should not pay much attention
to methods bootmem_init(), arch_mem_init(), paging_init() and
mem_init() until they are fully refactored.
The patchset is applied on top of kernel v4.9.
Signed-off-by: Serge Semin <[email protected]>
Serge Semin (21):
MIPS memblock: Unpin dts memblock sanity check method
MIPS memblock: Add dts mem and reserved-mem callbacks
MIPS memblock: Alter traditional add_memory_region() method
MIPS memblock: Alter user-defined memory parameter parser
MIPS memblock: Alter initrd memory reservation method
MIPS memblock: Alter kexec-crashkernel parameters parser
MIPS memblock: Alter elfcorehdr parameters parser
MIPS memblock: Move kernel parameters parser into individual method
MIPS memblock: Move kernel memory reservation to individual method
MIPS memblock: Discard bootmem allocator initialization
MIPS memblock: Add memblock sanity check method
MIPS memblock: Add memblock print outs in debug
MIPS memblock: Add memblock allocator initialization
MIPS memblock: Alter IO resources initialization method
MIPS memblock: Alter weakened MAAR initialization method
MIPS memblock: Alter paging initialization method
MIPS memblock: Alter high memory freeing method
MIPS memblock: Slightly improve buddy allocator init method
MIPS memblock: Add print out method of kernel virtual memory layout
MIPS memblock: Add free low memory test method call
MIPS memblock: Deactivate old bootmem allocator
arch/mips/Kconfig | 2 +-
arch/mips/kernel/prom.c | 32 +-
arch/mips/kernel/setup.c | 958 +++++++++++++++--------------
arch/mips/mm/init.c | 234 ++++---
drivers/of/fdt.c | 47 +-
include/linux/of_fdt.h | 1 +
6 files changed, 739 insertions(+), 535 deletions(-)
--
2.6.6
The whole kernel text/data/bss must be reserved to prevent sudden
kernel crashes, for instance, due to unexpected non-zero default static
variables initializations.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 117 +++++++++++++++--------------
1 file changed, 59 insertions(+), 58 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 9c1a60d..e746793 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -472,6 +472,62 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
/*
+ * Reserve kernel code and data within memblock allocator
+ */
+static void __init mips_reserve_kernel_mem(void)
+{
+ phys_addr_t start, size;
+
+ /*
+ * Add kernel _text, _data, _bss, __init*, upto __end sections to
+ * boot_mem_map and memblock. We must reserve all of them!
+ */
+ start = __pa_symbol(&_text);
+ size = __pa_symbol(&_end) - start;
+ add_memory_region(start, size, BOOT_MEM_RAM);
+ /*
+ * It needs to be reserved within memblock as well. It's ok if memory
+ * has already been reserved with previous method
+ */
+ memblock_reserve(start, size);
+
+ /* Reserve nosave region for hibernation */
+ start = __pa_symbol(&__nosave_begin);
+ size = __pa_symbol(&__nosave_end) - start;
+ add_memory_region(start, size, BOOT_MEM_RAM);
+ memblock_reserve(start, size);
+
+ /* Initialize some init_mm fieldis. We may not need this? */
+ init_mm.start_code = (unsigned long)&_text;
+ init_mm.end_code = (unsigned long)&_etext;
+ init_mm.end_data = (unsigned long)&_edata;
+ init_mm.brk = (unsigned long)&_end;
+
+ /*
+ * The kernel reserves all memory below its _end symbol as bootmem,
+ * but the kernel may now be at a much higher address. The memory
+ * between the original and new locations may be returned to the system.
+ */
+#ifdef CONFIG_RELOCATABLE
+ if (__pa_symbol(&_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) {
+ phys_addr_t offset;
+ extern void show_kernel_relocation(const char *level);
+
+ offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS);
+ memblock_free(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset);
+
+#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
+ /*
+ * This information is necessary when debugging the kernel
+ * But is a security vulnerability otherwise!
+ */
+ show_kernel_relocation(KERN_INFO);
+#endif
+ }
+#endif
+}
+
+/*
* Reserve memory occupied by elfcorehdr
*/
static void __init mips_reserve_elfcorehdr(void)
@@ -590,6 +646,9 @@ static void __init bootmem_init(void)
unsigned long bootmap_size;
int i;
+ /* Reserve kernel code/data memory */
+ mips_reserve_kernel_mem();
+
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
@@ -766,29 +825,6 @@ static void __init bootmem_init(void)
* Reserve the bootmap memory.
*/
reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
-
-#ifdef CONFIG_RELOCATABLE
- /*
- * The kernel reserves all memory below its _end symbol as bootmem,
- * but the kernel may now be at a much higher address. The memory
- * between the original and new locations may be returned to the system.
- */
- if (__pa_symbol(_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) {
- unsigned long offset;
- extern void show_kernel_relocation(const char *level);
-
- offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS);
- free_bootmem(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset);
-
-#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
- /*
- * This information is necessary when debugging the kernel
- * But is a security vulnerability otherwise!
- */
- show_kernel_relocation(KERN_INFO);
-#endif
- }
-#endif
}
#endif /* CONFIG_SGI_IP27 */
@@ -816,25 +852,6 @@ static void __init bootmem_init(void)
* initialization hook for anything else was introduced.
*/
-static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
-{
- phys_addr_t size;
- int i;
-
- size = end - mem;
- if (!size)
- return;
-
- /* Make sure it is in the boot_mem_map */
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- if (mem >= boot_mem_map.map[i].addr &&
- mem < (boot_mem_map.map[i].addr +
- boot_mem_map.map[i].size))
- return;
- }
- add_memory_region(mem, size, type);
-}
-
static void __init arch_mem_init(char **cmdline_p)
{
struct memblock_region *reg;
@@ -846,19 +863,6 @@ static void __init arch_mem_init(char **cmdline_p)
/* Parse passed parameters */
mips_parse_param(cmdline_p);
- /*
- * Make sure all kernel memory is in the maps. The "UP" and
- * "DOWN" are opposite for initdata since if it crosses over
- * into another memory section you don't want that to be
- * freed when the initdata is freed.
- */
- arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
- PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
- BOOT_MEM_RAM);
- arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
- PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
- BOOT_MEM_INIT_RAM);
-
pr_info("Determined physical RAM map:\n");
print_memory_map();
@@ -873,9 +877,6 @@ static void __init arch_mem_init(char **cmdline_p)
for_each_memblock(reserved, reg)
if (reg->size != 0)
reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
-
- reserve_bootmem_region(__pa_symbol(&__nosave_begin),
- __pa_symbol(&__nosave_end)); /* Reserve for hibernation */
}
static void __init resource_init(void)
--
2.6.6
Bootmem allocator initialization needs to be discarded.
PFN limit constants are still in use by some subsystems, so they
need to be properly initialized. The initialization is moved into
a separate method and performed with help of commonly used
platform-specific constants. It might me too simplified, but most
of the kernel platforms do it the same way. Moreover it's much
easier to debug it, when it's not that complicated.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 193 ++++-------------------------
1 file changed, 21 insertions(+), 172 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index e746793..6562f55 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -626,6 +626,25 @@ static void __init request_crashkernel(struct resource *res) { }
#endif /* !CONFIG_KEXEC */
/*
+ * Calcualte PFN limits with respect to the defined memory layout
+ */
+static void __init find_pfn_limits(void)
+{
+ phys_addr_t ram_end = memblock_end_of_DRAM();
+
+ min_low_pfn = ARCH_PFN_OFFSET;
+ max_low_pfn = PFN_UP(HIGHMEM_START);
+ max_pfn = PFN_UP(ram_end);
+#ifdef CONFIG_HIGHMEM
+ highstart_pfn = max_low_pfn;
+ highend_pfn = max_pfn <= highstart_pfn ? highstart_pfn : max_pfn;
+#endif
+ pr_info("PFNs: low min %lu, low max %lu, high start %lu, high end %lu,"
+ "max %lu\n",
+ min_low_pfn, max_low_pfn, highstart_pfn, highend_pfn, max_pfn);
+}
+
+/*
* Initialize the bootmem allocator. It also setup initrd related data
* if needed.
*/
@@ -641,11 +660,6 @@ static void __init bootmem_init(void)
static void __init bootmem_init(void)
{
- unsigned long reserved_end;
- unsigned long mapstart = ~0UL;
- unsigned long bootmap_size;
- int i;
-
/* Reserve kernel code/data memory */
mips_reserve_kernel_mem();
@@ -658,173 +672,8 @@ static void __init bootmem_init(void)
/* Parse crashkernel parameter */
mips_parse_crashkernel();
- reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
-
- /*
- * max_low_pfn is not a number of pages. The number of pages
- * of the system is given by 'max_low_pfn - min_low_pfn'.
- */
- min_low_pfn = ~0UL;
- max_low_pfn = 0;
-
- /*
- * Find the highest page frame number we have available.
- */
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start, end;
-
- if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
- continue;
-
- start = PFN_UP(boot_mem_map.map[i].addr);
- end = PFN_DOWN(boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size);
-
-#ifndef CONFIG_HIGHMEM
- /*
- * Skip highmem here so we get an accurate max_low_pfn if low
- * memory stops short of high memory.
- * If the region overlaps HIGHMEM_START, end is clipped so
- * max_pfn excludes the highmem portion.
- */
- if (start >= PFN_DOWN(HIGHMEM_START))
- continue;
- if (end > PFN_DOWN(HIGHMEM_START))
- end = PFN_DOWN(HIGHMEM_START);
-#endif
-
- if (end > max_low_pfn)
- max_low_pfn = end;
- if (start < min_low_pfn)
- min_low_pfn = start;
- if (end <= reserved_end)
- continue;
-#ifdef CONFIG_BLK_DEV_INITRD
- /* Skip zones before initrd and initrd itself */
- if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end)))
- continue;
-#endif
- if (start >= mapstart)
- continue;
- mapstart = max(reserved_end, start);
- }
-
- if (min_low_pfn >= max_low_pfn)
- panic("Incorrect memory mapping !!!");
- if (min_low_pfn > ARCH_PFN_OFFSET) {
- pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
- (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
- min_low_pfn - ARCH_PFN_OFFSET);
- } else if (min_low_pfn < ARCH_PFN_OFFSET) {
- pr_info("%lu free pages won't be used\n",
- ARCH_PFN_OFFSET - min_low_pfn);
- }
- min_low_pfn = ARCH_PFN_OFFSET;
-
- /*
- * Determine low and high memory ranges
- */
- max_pfn = max_low_pfn;
- if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
-#ifdef CONFIG_HIGHMEM
- highstart_pfn = PFN_DOWN(HIGHMEM_START);
- highend_pfn = max_low_pfn;
-#endif
- max_low_pfn = PFN_DOWN(HIGHMEM_START);
- }
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /*
- * mapstart should be after initrd_end
- */
- if (initrd_end)
- mapstart = max(mapstart, (unsigned long)PFN_UP(__pa(initrd_end)));
-#endif
-
- /*
- * Initialize the boot-time allocator with low memory only.
- */
- bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
- min_low_pfn, max_low_pfn);
-
-
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start, end;
-
- start = PFN_UP(boot_mem_map.map[i].addr);
- end = PFN_DOWN(boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size);
-
- if (start <= min_low_pfn)
- start = min_low_pfn;
- if (start >= end)
- continue;
-
-#ifndef CONFIG_HIGHMEM
- if (end > max_low_pfn)
- end = max_low_pfn;
-
- /*
- * ... finally, is the area going away?
- */
- if (end <= start)
- continue;
-#endif
-
- memblock_add_node(PFN_PHYS(start), PFN_PHYS(end - start), 0);
- }
-
- /*
- * Register fully available low RAM pages with the bootmem allocator.
- */
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start, end, size;
-
- start = PFN_UP(boot_mem_map.map[i].addr);
- end = PFN_DOWN(boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size);
-
- /*
- * Reserve usable memory.
- */
- switch (boot_mem_map.map[i].type) {
- case BOOT_MEM_RAM:
- break;
- case BOOT_MEM_INIT_RAM:
- memory_present(0, start, end);
- continue;
- default:
- /* Not usable memory */
- continue;
- }
-
- /*
- * We are rounding up the start address of usable memory
- * and at the end of the usable range downwards.
- */
- if (start >= max_low_pfn)
- continue;
- if (start < reserved_end)
- start = reserved_end;
- if (end > max_low_pfn)
- end = max_low_pfn;
-
- /*
- * ... finally, is the area going away?
- */
- if (end <= start)
- continue;
- size = end - start;
-
- /* Register lowmem ranges */
- free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);
- memory_present(0, start, end);
- }
-
- /*
- * Reserve the bootmap memory.
- */
- reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
+ /* Find memory PFN limits */
+ find_pfn_limits();
}
#endif /* CONFIG_SGI_IP27 */
--
2.6.6
Perform memory sanity check right after basic memory is added.
It makes sure there is low memory available and there is no high
memory if one isn't supported. Additionally low memory limit needs
to be calculated so memblock would have a proper upper boundary for
memory allocations.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 83 ++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 6562f55..d2f410d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -472,6 +472,86 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
/*
+ * Check initialized memory.
+ */
+static void __init sanity_check_meminfo(void)
+{
+ phys_addr_t physmem_start = PFN_PHYS(ARCH_PFN_OFFSET);
+ phys_addr_t size_limit = 0;
+ struct memblock_region *reg;
+ bool highmem = false;
+ bool should_use_highmem = false;
+
+ /*
+ * Walk over all memory ranges discarding highmem if it's disabled and
+ * calculating the memblock allocator limit
+ */
+ for_each_memblock(memory, reg) {
+ phys_addr_t block_start = reg->base;
+ phys_addr_t block_end = reg->base + reg->size;
+ phys_addr_t block_size = reg->size;
+
+ if (block_start >= HIGHMEM_START) {
+ highmem = true;
+ size_limit = block_size;
+ } else {
+ size_limit = HIGHMEM_START - block_start;
+ }
+
+ /* Discard highmem physical memory if it isn't supported */
+ if (!IS_BUILTIN(CONFIG_HIGHMEM)) {
+ /* Discard the whole highmem memory block */
+ if (highmem) {
+ pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
+ &block_start, &block_end);
+ memblock_remove(block_start, block_size);
+ should_use_highmem = true;
+ continue;
+ }
+ /* Truncate memory block */
+ if (block_size > size_limit) {
+ phys_addr_t overlap_size = block_size - size_limit;
+ phys_addr_t highmem_start = HIGHMEM_START;
+
+ pr_notice("Truncate highmem %pa-%pa to -%pa\n",
+ &block_start, &block_end, &highmem_start);
+ memblock_remove(highmem_start, overlap_size);
+ block_end = highmem_start;
+ should_use_highmem = true;
+ }
+ }
+ /* Truncate region if it starts below ARCH_PFN_OFFSET */
+ if (block_start < physmem_start) {
+ phys_addr_t overlap_size = physmem_start - block_start;
+
+ pr_notice("Truncate lowmem %pa-%pa to %pa-\n",
+ &block_start, &block_end, &physmem_start);
+ memblock_remove(block_start, overlap_size);
+ }
+
+ /* Calculate actual lowmem limit for memblock allocator */
+ if (!highmem) {
+ if (block_end > mips_lowmem_limit) {
+ if (block_size > size_limit)
+ mips_lowmem_limit = HIGHMEM_START;
+ else
+ mips_lowmem_limit = block_end;
+ }
+ }
+ }
+
+ /* Panic if no lowmem has been determined */
+ if (!mips_lowmem_limit)
+ panic("Oops, where is low memory? 0_o\n");
+
+ if (should_use_highmem)
+ pr_notice("Consider using HIGHMEM enabled kernel\n");
+
+ /* Set memblock allocator limit */
+ memblock_set_current_limit(mips_lowmem_limit);
+}
+
+/*
* Reserve kernel code and data within memblock allocator
*/
static void __init mips_reserve_kernel_mem(void)
@@ -712,6 +792,9 @@ static void __init arch_mem_init(char **cmdline_p)
/* Parse passed parameters */
mips_parse_param(cmdline_p);
+ /* Sanity check the specified memory */
+ sanity_check_meminfo();
+
pr_info("Determined physical RAM map:\n");
print_memory_map();
--
2.6.6
When debugging it is useful to have a list of all memory regions
added and reserved in the system. Ones are printed right from
memblock if memblock_debug is enabled.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index d2f410d..409d23d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -200,11 +200,16 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
add_memory_region(start, size, BOOT_MEM_RAM);
}
+/*
+ * Print declared memory layout
+ */
static void __init print_memory_map(void)
{
int i;
const int field = 2 * sizeof(unsigned long);
+ /* Print the added memory map */
+ pr_info("Determined physical RAM map:\n");
for (i = 0; i < boot_mem_map.nr_map; i++) {
printk(KERN_INFO " memory: %0*Lx @ %0*Lx ",
field, (unsigned long long) boot_mem_map.map[i].size,
@@ -228,6 +233,9 @@ static void __init print_memory_map(void)
break;
}
}
+
+ /* Print memblocks if memblock_debug is set */
+ memblock_dump_all();
}
/*
@@ -795,11 +803,11 @@ static void __init arch_mem_init(char **cmdline_p)
/* Sanity check the specified memory */
sanity_check_meminfo();
- pr_info("Determined physical RAM map:\n");
- print_memory_map();
-
bootmem_init();
+ /* Print memory map initialized by arch-specific code and params */
+ print_memory_map();
+
device_tree_init();
sparse_init();
plat_swiotlb_setup();
--
2.6.6
Initialization is done by subsequent performing of the following
steps:
1) Call platform-specific call adding memory regions
2) Parse kernel parameters looking (they may change memory layout)
3) Check whether declared memory is in sane
4) Reserve memory for kernel, initrd, crashdump, fdt, devices and CMA
5) Find PFN limits of the memory regions
6) Allow memblocks resize
7) Perform basic paging subsystem initialization: nodes, zones, page
tables (if necessary), kernel mapping and so on.
Sparse sections initialization is moved into mem_init() method
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 93 +++++++++++++++++++++++-------
1 file changed, 71 insertions(+), 22 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 409d23d..b18d38c 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -9,6 +9,7 @@
* Copyright (C) 1996 Stoned Elipot
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2000, 2001, 2002, 2007 Maciej W. Rozycki
+ * Copyright (C) 2016 T-platforms
*/
#include <linux/init.h>
#include <linux/ioport.h>
@@ -27,6 +28,7 @@
#include <linux/device.h>
#include <linux/dma-contiguous.h>
#include <linux/decompress/generic.h>
+#include <linux/of_fdt.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
@@ -733,20 +735,34 @@ static void __init find_pfn_limits(void)
}
/*
- * Initialize the bootmem allocator. It also setup initrd related data
- * if needed.
+ * Initialize the memblock allocator
*/
#if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_NUMA))
-static void __init bootmem_init(void)
+static void __init mips_bootmem_init(void)
{
+ /* Reserve kernel code/data memory */
+ mips_reserve_kernel_mem();
+
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
+
+ /* Reserve memory for elfcorehdr */
+ mips_reserve_elfcorehdr();
+
+ /* Parse crashkernel parameter */
+ mips_parse_crashkernel();
+
+ /* Reserve memory for DMA contiguous allocator */
+ dma_contiguous_reserve(mips_lowmem_limit);
+
+ /* Allow memblock resize from now */
+ memblock_allow_resize();
}
#else /* !CONFIG_SGI_IP27 */
-static void __init bootmem_init(void)
+static void __init mips_bootmem_init(void)
{
/* Reserve kernel code/data memory */
mips_reserve_kernel_mem();
@@ -760,8 +776,23 @@ static void __init bootmem_init(void)
/* Parse crashkernel parameter */
mips_parse_crashkernel();
+ /*
+ * Platform code usually copies fdt, but still lets reserve its memory
+ * in case if it doesn't
+ */
+ early_init_fdt_reserve_self();
+
+ /* Scan reserved-memory nodes of fdt */
+ early_init_fdt_scan_reserved_mem();
+
+ /* Reserve memory for DMA contiguous allocator */
+ dma_contiguous_reserve(mips_lowmem_limit);
+
/* Find memory PFN limits */
find_pfn_limits();
+
+ /* Allow memblock resize from now */
+ memblock_allow_resize();
}
#endif /* CONFIG_SGI_IP27 */
@@ -770,30 +801,51 @@ static void __init bootmem_init(void)
* arch_mem_init - initialize memory management subsystem
*
* o plat_mem_setup() detects the memory configuration and will record detected
- * memory areas using add_memory_region.
+ * memory areas using add_memory_region, which in addition preinitializes
+ * memblock ranges.
*
* At this stage the memory configuration of the system is known to the
* kernel but generic memory management system is still entirely uninitialized.
*
- * o bootmem_init()
- * o sparse_init()
- * o paging_init()
- * o dma_contiguous_reserve()
+ * o mips_parse_param() parses parameters passed to the kernel in accordance
+ * with CMDLINE configs.
+ * o sanity_check_meminfo() performs memory ranges sanity checks, for
+ * example, drop high mem regions if it's not supported, set memblock limit
+ * of low memory allocations
+ * o mips_bootmem_init() performs memblock further initializations,
+ * particularly reserve crucial regions, including kernel segments, initrd,
+ * elfcorehdrm, crashkernel, fdt, DMA contiguous allocator, set PFN-related
+ * global variables.
+ * o print_memory_map() prints initialized and verified memory map
+ * o device_tree_init() calls platform-specific method to perform some
+ * device tree related operations
+ * o plat_swiotlb_setup() - platform-specific SWIOTLB setup method
+ *
+ * Basic setup of page allocator is done in setup_arch():
+ * o paging_init() performs initialization of paging subsystem, in particular
+ * setup page tables (PGD, PMD, etc), kernel mapping, sparse memory segments
+ * if supported. It performs memory test if one is enabled. Finally it
+ * calculates memory zone limits and calls free_area_init_node()
+ * initializing pages memory maps, nodes, nodes free areas - basis of the
+ * buddy allocator.
*
* At this stage the bootmem allocator is ready to use.
*
* NOTE: historically plat_mem_setup did the entire platform initialization.
- * This was rather impractical because it meant plat_mem_setup had to
+ * This was rather impractical because it meant plat_mem_setup had to
* get away without any kind of memory allocator. To keep old code from
* breaking plat_setup was just renamed to plat_mem_setup and a second platform
* initialization hook for anything else was introduced.
+ * Additionally boot_mem_map structure used to keep base memory layout so
+ * then ancient bootmem allocator would be properly initialized. Since memblock
+ * allocator is used for early memory management now, the boot_mem_map is
+ * conserved just for compatibility.
+ */
+/*
+ * MIPS early memory manager setup
*/
-
static void __init arch_mem_init(char **cmdline_p)
{
- struct memblock_region *reg;
- extern void plat_mem_setup(void);
-
/* call board setup routine */
plat_mem_setup();
@@ -803,20 +855,17 @@ static void __init arch_mem_init(char **cmdline_p)
/* Sanity check the specified memory */
sanity_check_meminfo();
- bootmem_init();
+ /* Initialize memblock allocator */
+ mips_bootmem_init();
/* Print memory map initialized by arch-specific code and params */
print_memory_map();
+ /* Perform platform-specific device tree scanning */
device_tree_init();
- sparse_init();
- plat_swiotlb_setup();
- dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
- /* Tell bootmem about cma reserved memblock section */
- for_each_memblock(reserved, reg)
- if (reg->size != 0)
- reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+ /* Perform platform-specific SWIOTLB setup */
+ plat_swiotlb_setup();
}
static void __init resource_init(void)
--
2.6.6
Replace resource initialization method with one using memblocks.
It fully reflects all available system RAM within memory regions.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 40 +++++++++---------------------
1 file changed, 12 insertions(+), 28 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index b18d38c..8bef2d3 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -868,46 +868,30 @@ static void __init arch_mem_init(char **cmdline_p)
plat_swiotlb_setup();
}
+/*
+ * Declare memory within system resources
+ */
static void __init resource_init(void)
{
- int i;
+ struct memblock_region *reg;
if (UNCAC_BASE != IO_BASE)
return;
+ /* Kernel code and data need to be registered within proper regions */
code_resource.start = __pa_symbol(&_text);
code_resource.end = __pa_symbol(&_etext) - 1;
data_resource.start = __pa_symbol(&_etext);
data_resource.end = __pa_symbol(&_edata) - 1;
- for (i = 0; i < boot_mem_map.nr_map; i++) {
+ /* Register RAM resources */
+ for_each_memblock(memory, reg) {
struct resource *res;
- unsigned long start, end;
-
- start = boot_mem_map.map[i].addr;
- end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
- if (start >= HIGHMEM_START)
- continue;
- if (end >= HIGHMEM_START)
- end = HIGHMEM_START - 1;
-
- res = alloc_bootmem(sizeof(struct resource));
-
- res->start = start;
- res->end = end;
- res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-
- switch (boot_mem_map.map[i].type) {
- case BOOT_MEM_RAM:
- case BOOT_MEM_INIT_RAM:
- case BOOT_MEM_ROM_DATA:
- res->name = "System RAM";
- res->flags |= IORESOURCE_SYSRAM;
- break;
- case BOOT_MEM_RESERVED:
- default:
- res->name = "reserved";
- }
+ res = memblock_virt_alloc(sizeof(*res), 0);
+ res->name = "System RAM";
+ res->start = PFN_PHYS(memblock_region_memory_base_pfn(reg));
+ res->end = PFN_PHYS(memblock_region_memory_end_pfn(reg)) - 1;
+ res->flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM;
request_resource(&iomem_resource, res);
--
2.6.6
MAAR initialization method can be slightly simplified, since
memblock allocator is fully available.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/mm/init.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index a4f49c7..49db909 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -22,6 +22,7 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/memblock.h>
#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <linux/swap.h>
@@ -245,28 +246,26 @@ void __init fixrange_init(unsigned long start, unsigned long end,
#endif
}
-unsigned __weak platform_maar_init(unsigned num_pairs)
+/*
+ * Platform-specific method of MAAR registers initialization
+ */
+unsigned int __weak platform_maar_init(unsigned int num_pairs)
{
struct maar_config cfg[BOOT_MEM_MAP_MAX];
- unsigned i, num_configured, num_cfg = 0;
+ struct memblock_region *reg;
+ unsigned int num_configured, num_cfg = 0;
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- switch (boot_mem_map.map[i].type) {
- case BOOT_MEM_RAM:
- case BOOT_MEM_INIT_RAM:
+ /* Collect RAM regions within MAAR config array */
+ for_each_memblock(memory, reg) {
+ if (num_cfg >= BOOT_MEM_MAP_MAX) {
+ pr_info("Too many memory regions to init MAARs");
break;
- default:
- continue;
}
-
/* Round lower up */
- cfg[num_cfg].lower = boot_mem_map.map[i].addr;
- cfg[num_cfg].lower = (cfg[num_cfg].lower + 0xffff) & ~0xffff;
+ cfg[num_cfg].lower = (reg->base + 0xffff) & ~0xffff;
/* Round upper down */
- cfg[num_cfg].upper = boot_mem_map.map[i].addr +
- boot_mem_map.map[i].size;
- cfg[num_cfg].upper = (cfg[num_cfg].upper & ~0xffff) - 1;
+ cfg[num_cfg].upper = ((reg->base + reg->size) & ~0xffff) - 1;
cfg[num_cfg].attrs = MIPS_MAAR_S;
num_cfg++;
--
2.6.6
Apart from the actions it did before, it initializes sparsemem
if one activated. Memory zones size calculation is moved into an
individual method.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/mm/init.c | 79 +++++++++++++++++++++++++----------
1 file changed, 56 insertions(+), 23 deletions(-)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 49db909..6f186c7 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -58,6 +58,53 @@ EXPORT_SYMBOL_GPL(empty_zero_page);
EXPORT_SYMBOL(zero_page_mask);
/*
+ * Initialize sparse memory sections setting node ids and indexes
+ */
+static void __init mips_memory_present(void)
+{
+#ifdef CONFIG_SPARSEMEM
+ struct memblock_region *reg;
+
+ for_each_memblock(memory, reg)
+ memory_present(0, memblock_region_memory_base_pfn(reg),
+ memblock_region_memory_end_pfn(reg));
+#endif /* CONFIG_SPARSEMEM */
+}
+
+/*
+ * Setup nodes zone areas
+ */
+static void __init zone_sizes_init(void)
+{
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+ /* Clean zone boundaries array */
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
+ /* Setup determined boundaries */
+#ifdef CONFIG_ZONE_DMA
+ max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
+#endif
+#ifdef CONFIG_ZONE_DMA32
+ max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
+#endif
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+#ifdef CONFIG_HIGHMEM
+ max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
+
+ /* Make sure the processor supports highmem */
+ if (cpu_has_dc_aliases && max_low_pfn != highend_pfn) {
+ pr_warn("CPU doesn't support highmem. %ldk highmem ignored\n",
+ (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
+ max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
+ }
+#endif
+
+ /* Finally initialize nodes and page maps using memblock info */
+ free_area_init_nodes(max_zone_pfns);
+}
+
+/*
* Not static inline because used by IP27 special magic initialization code
*/
void setup_zero_pages(void)
@@ -386,36 +433,22 @@ int page_is_ram(unsigned long pagenr)
void __init paging_init(void)
{
- unsigned long max_zone_pfns[MAX_NR_ZONES];
- unsigned long lastpfn __maybe_unused;
-
+ /* Initialize page tables */
pagetable_init();
+ /* Initialize highmem mapping */
#ifdef CONFIG_HIGHMEM
kmap_init();
#endif
-#ifdef CONFIG_ZONE_DMA
- max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
-#endif
-#ifdef CONFIG_ZONE_DMA32
- max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
-#endif
- max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
- lastpfn = max_low_pfn;
-#ifdef CONFIG_HIGHMEM
- max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
- lastpfn = highend_pfn;
- if (cpu_has_dc_aliases && max_low_pfn != highend_pfn) {
- printk(KERN_WARNING "This processor doesn't support highmem."
- " %ldk highmem ignored\n",
- (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
- max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
- lastpfn = max_low_pfn;
- }
-#endif
+ /* Mark present RAM memory */
+ mips_memory_present();
- free_area_init_nodes(max_zone_pfns);
+ /* Initialize memory maps within sparse memory sections */
+ sparse_init();
+
+ /* Initialize free areas of nodes */
+ zone_sizes_init();
}
#ifdef CONFIG_64BIT
--
2.6.6
Memblock regions are used to find all available high memory
and to set it free into buddy allocator.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/mm/init.c | 54 ++++++++++++++---------------------
1 file changed, 21 insertions(+), 33 deletions(-)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 6f186c7..98680fb 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -404,32 +404,6 @@ void maar_init(void)
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
-int page_is_ram(unsigned long pagenr)
-{
- int i;
-
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long addr, end;
-
- switch (boot_mem_map.map[i].type) {
- case BOOT_MEM_RAM:
- case BOOT_MEM_INIT_RAM:
- break;
- default:
- /* not usable memory */
- continue;
- }
-
- addr = PFN_UP(boot_mem_map.map[i].addr);
- end = PFN_DOWN(boot_mem_map.map[i].addr +
- boot_mem_map.map[i].size);
-
- if (pagenr >= addr && pagenr < end)
- return 1;
- }
-
- return 0;
-}
void __init paging_init(void)
{
@@ -458,18 +432,32 @@ static struct kcore_list kcore_kseg0;
static inline void mem_init_free_highmem(void)
{
#ifdef CONFIG_HIGHMEM
- unsigned long tmp;
+ struct memblock_region *reg;
+ unsigned long pfn;
if (cpu_has_dc_aliases)
return;
- for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
- struct page *page = pfn_to_page(tmp);
+ /* Walk through all memory regions freeing highmem pages only */
+ for_each_memblock(memory, reg) {
+ unsigned long start = memblock_region_memory_base_pfn(reg);
+ unsigned long end = memblock_region_memory_end_pfn(reg);
+
+ /* Ignore complete lowmem entries */
+ if (end <= max_low_pfn)
+ continue;
- if (!page_is_ram(tmp))
- SetPageReserved(page);
- else
- free_highmem_page(page);
+ /* Truncate partial highmem entries */
+ if (start < max_low_pfn)
+ start = max_low_pfn;
+
+ /*
+ * MIPS memblock allocator doesn't allocate regions from high
+ * memory (see mips_lowmem_limit variable initialization), so
+ * just set corresponding pages free
+ */
+ for (pfn = start; pfn < end; pfn++)
+ free_highmem_page(pfn_to_page(pfn));
}
#endif
}
--
2.6.6
Just add some minor changes into buddy allocator initialization.
After all the alterations it shall work just fine from now.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/mm/init.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 98680fb..13a032f 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -7,6 +7,7 @@
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Kevin D. Kissell, [email protected] and Carsten Langgaard, [email protected]
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
*/
#include <linux/bug.h>
#include <linux/init.h>
@@ -462,22 +463,36 @@ static inline void mem_init_free_highmem(void)
#endif
}
+/*
+ * Let buddy allocator run
+ */
void __init mem_init(void)
{
+ /* Setup maximum number of pages of memory map array */
#ifdef CONFIG_HIGHMEM
#ifdef CONFIG_DISCONTIGMEM
#error "CONFIG_HIGHMEM and CONFIG_DISCONTIGMEM dont work together yet"
#endif
- max_mapnr = highend_pfn ? highend_pfn : max_low_pfn;
+ set_max_mapnr(highend_pfn);
#else
- max_mapnr = max_low_pfn;
+ set_max_mapnr(max_low_pfn);
#endif
- high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
+ /* Highmem starts right after lowmem */
+ high_memory = __va(PFN_PHYS(max_low_pfn));
+ /* Initialize speculative access registers - MAAR */
maar_init();
+
+ /* Free low memory registered within memblock allocator */
free_all_bootmem();
- setup_zero_pages(); /* Setup zeroed pages. */
+
+ /* Allocate zeroed pages */
+ setup_zero_pages();
+
+ /* Free highmemory registered in memblocks */
mem_init_free_highmem();
+
+ /* Print out memory areas statistics */
mem_init_print_info(NULL);
#ifdef CONFIG_64BIT
--
2.6.6
It's useful to have some printed map of the kernel virtual memory,
at least for debugging purpose.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/mm/init.c | 47 +++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 13a032f..35e7ba8 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -32,6 +32,7 @@
#include <linux/hardirq.h>
#include <linux/gfp.h>
#include <linux/kcore.h>
+#include <linux/sizes.h>
#include <asm/asm-offsets.h>
#include <asm/bootinfo.h>
@@ -106,6 +107,49 @@ static void __init zone_sizes_init(void)
}
/*
+ * Print out kernel memory layout
+ */
+#define MLK(b, t) b, t, ((t) - (b)) >> 10
+#define MLM(b, t) b, t, ((t) - (b)) >> 20
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+static void __init mem_print_kmap_info(void)
+{
+ pr_notice("Virtual kernel memory layout:\n"
+ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
+ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
+#ifdef CONFIG_HIGHMEM
+ " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
+#endif
+ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
+ " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
+ " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
+ " .init : 0x%p" " - 0x%p" " (%4td kB)\n",
+ MLM(PAGE_OFFSET, (unsigned long)high_memory),
+ MLM(VMALLOC_START, VMALLOC_END),
+#ifdef CONFIG_HIGHMEM
+ MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE)),
+#endif
+ MLK(FIXADDR_START, FIXADDR_TOP),
+ MLK_ROUNDUP(_text, _etext),
+ MLK_ROUNDUP(_sdata, _edata),
+ MLK_ROUNDUP(__init_begin, __init_end));
+
+ /* Check some fundamental inconsistencies. May add something else? */
+#ifdef CONFIG_HIGHMEM
+ BUILD_BUG_ON(VMALLOC_END < PAGE_OFFSET);
+ BUG_ON(VMALLOC_END < (unsigned long)high_memory);
+#endif
+ BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
+ BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) <
+ (unsigned long)high_memory);
+ BUILD_BUG_ON(FIXADDR_TOP < PAGE_OFFSET);
+ BUG_ON(FIXADDR_TOP < (unsigned long)high_memory);
+}
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
+
+/*
* Not static inline because used by IP27 special magic initialization code
*/
void setup_zero_pages(void)
@@ -492,6 +536,9 @@ void __init mem_init(void)
/* Free highmemory registered in memblocks */
mem_init_free_highmem();
+ /* Print out kernel memory layout */
+ mem_print_kmap_info();
+
/* Print out memory areas statistics */
mem_init_print_info(NULL);
--
2.6.6
Right after all the necessary reservations are done, free memory
regions can be tested if it is activated with "memtest" parameter.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/mm/init.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 35e7ba8..ccc0e96 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -452,6 +452,12 @@ void maar_init(void)
void __init paging_init(void)
{
+ /*
+ * Test low memory registered within memblock. The method shall test
+ * valid and free memory only
+ */
+ early_memtest(PFN_PHYS(min_low_pfn), PFN_PHYS(max_low_pfn));
+
/* Initialize page tables */
pagetable_init();
--
2.6.6
Memblock allocator can be successfully used from now for early
memory management.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2ef1e2d..527f2fe 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -40,9 +40,9 @@ config MIPS
select HAVE_ARCH_JUMP_LABEL
select ARCH_WANT_IPC_PARSE_VERSION
select IRQ_FORCED_THREADING
+ select NO_BOOTMEM
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
- select ARCH_DISCARD_MEMBLOCK
select GENERIC_SMP_IDLE_THREAD
select BUILDTIME_EXTABLE_SORT
select GENERIC_CLOCKEVENTS
--
2.6.6
Since memblock is used, initrd memory region can be easily
verified and reserved if looks ok. Verification method will be
useful for other reservation methods.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 157 ++++++++++++++++-------------
1 file changed, 87 insertions(+), 70 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 789aafe..d2f38ac 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -82,6 +82,8 @@ static struct resource data_resource = { .name = "Kernel data", };
static void *detect_magic __initdata = detect_memory_region;
+static phys_addr_t __initdata mips_lowmem_limit;
+
/*
* General method to add RAM regions to the system
*
@@ -266,6 +268,38 @@ static int __init early_parse_mem(char *p)
early_param("mem", early_parse_mem);
/*
+ * Helper method checking whether passed lowmem region is valid
+ */
+static bool __init is_lowmem_and_valid(const char *name, phys_addr_t base,
+ phys_addr_t size)
+{
+ phys_addr_t end = base + size;
+
+ /* Check whether region belongs to actual memory */
+ if (!memblock_is_region_memory(base, size)) {
+ pr_err("%s %08zx @ %pa is not a memory region", name,
+ (size_t)size, &base);
+ return false;
+ }
+
+ /* Check whether region belongs to low memory */
+ if (end > mips_lowmem_limit) {
+ pr_err("%s %08zx @ %pa is out of low memory", name,
+ (size_t)size, &base);
+ return false;
+ }
+
+ /* Check whether region is free */
+ if (memblock_is_region_reserved(base, size)) {
+ pr_err("%s %08zx @ %pa overlaps in-use memory", name,
+ (size_t)size, &base);
+ return false;
+ }
+
+ return true;
+}
+
+/*
* Manage initrd
*/
#ifdef CONFIG_BLK_DEV_INITRD
@@ -292,47 +326,6 @@ static int __init rd_size_early(char *p)
}
early_param("rd_size", rd_size_early);
-/* it returns the next free pfn after initrd */
-static unsigned long __init init_initrd(void)
-{
- unsigned long end;
-
- /*
- * Board specific code or command line parser should have
- * already set up initrd_start and initrd_end. In these cases
- * perfom sanity checks and use them if all looks good.
- */
- if (!initrd_start || initrd_end <= initrd_start)
- goto disable;
-
- if (initrd_start & ~PAGE_MASK) {
- pr_err("initrd start must be page aligned\n");
- goto disable;
- }
- if (initrd_start < PAGE_OFFSET) {
- pr_err("initrd start < PAGE_OFFSET\n");
- goto disable;
- }
-
- /*
- * Sanitize initrd addresses. For example firmware
- * can't guess if they need to pass them through
- * 64-bits values if the kernel has been built in pure
- * 32-bit. We need also to switch from KSEG0 to XKPHYS
- * addresses now, so the code can now safely use __pa().
- */
- end = __pa(initrd_end);
- initrd_end = (unsigned long)__va(end);
- initrd_start = (unsigned long)__va(__pa(initrd_start));
-
- ROOT_DEV = Root_RAM0;
- return PFN_UP(end);
-disable:
- initrd_start = 0;
- initrd_end = 0;
- return 0;
-}
-
/* In some conditions (e.g. big endian bootloader with a little endian
kernel), the initrd might appear byte swapped. Try to detect this and
byte swap it if needed. */
@@ -362,26 +355,64 @@ static void __init maybe_bswap_initrd(void)
#endif
}
-static void __init finalize_initrd(void)
+/*
+ * Check and reserve memory occupied by initrd
+ */
+static void __init mips_reserve_initrd_mem(void)
{
- unsigned long size = initrd_end - initrd_start;
+ phys_addr_t phys_initrd_start, phys_initrd_end, phys_initrd_size;
- if (size == 0) {
- printk(KERN_INFO "Initrd not found or empty");
+ /*
+ * Board specific code or command line parser should have already set
+ * up initrd_start and initrd_end. In these cases perform sanity checks
+ * and use them if all looks good.
+ */
+ if (!initrd_start || initrd_end <= initrd_start) {
+ pr_info("No initrd found");
goto disable;
}
- if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
- printk(KERN_ERR "Initrd extends beyond end of memory");
+ if (initrd_start & ~PAGE_MASK) {
+ pr_err("Initrd start must be page aligned");
goto disable;
}
+ if (initrd_start < PAGE_OFFSET) {
+ pr_err("Initrd start < PAGE_OFFSET");
+ goto disable;
+ }
+
+ /*
+ * Sanitize initrd addresses. For example firmware can't guess if they
+ * need to pass them through 64-bits values if the kernel has been
+ * built in pure 32-bit. We need also to switch from KSEG0 to XKPHYS
+ * addresses now, so the code can now safely use __pa().
+ */
+ phys_initrd_start = __pa(initrd_start);
+ phys_initrd_end = __pa(initrd_end);
+ phys_initrd_size = phys_initrd_end - phys_initrd_start;
+ /* Check whether initrd region is within available lowmem and free */
+ if (!is_lowmem_and_valid("Initrd", phys_initrd_start, phys_initrd_size))
+ goto disable;
+
+ /* Initrd may be byteswapped in Octeon */
maybe_bswap_initrd();
- reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
+ /* Memory for initrd can be reserved now */
+ memblock_reserve(phys_initrd_start, phys_initrd_size);
+
+ /* Convert initrd to virtual addresses back (needed for x32 -> x64) */
+ initrd_start = (unsigned long)__va(phys_initrd_start);
+ initrd_end = (unsigned long)__va(phys_initrd_end);
+
+ /* It's OK to have initrd below actual memory start. Really? */
initrd_below_start_ok = 1;
- pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n",
- initrd_start, size);
+ pr_info("Initial ramdisk at: 0x%lx (%zu bytes)\n",
+ initrd_start, (size_t)phys_initrd_size);
+
+ /* Set root device to be first ram disk */
+ ROOT_DEV = Root_RAM0;
+
return;
disable:
printk(KERN_CONT " - disabling initrd\n");
@@ -391,12 +422,7 @@ disable:
#else /* !CONFIG_BLK_DEV_INITRD */
-static unsigned long __init init_initrd(void)
-{
- return 0;
-}
-
-#define finalize_initrd() do {} while (0)
+static void __init mips_reserve_initrd_mem(void) { }
#endif
@@ -408,8 +434,8 @@ static unsigned long __init init_initrd(void)
static void __init bootmem_init(void)
{
- init_initrd();
- finalize_initrd();
+ /* Check and reserve memory occupied by initrd */
+ mips_reserve_initrd_mem();
}
#else /* !CONFIG_SGI_IP27 */
@@ -421,13 +447,9 @@ static void __init bootmem_init(void)
unsigned long bootmap_size;
int i;
- /*
- * Sanity check any INITRD first. We don't take it into account
- * for bootmem setup initially, rely on the end-of-kernel-code
- * as our memory range starting point. Once bootmem is inited we
- * will reserve the area used for the initrd.
- */
- init_initrd();
+ /* Check and reserve memory occupied by initrd */
+ mips_reserve_initrd_mem();
+
reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
/*
@@ -618,11 +640,6 @@ static void __init bootmem_init(void)
#endif
}
#endif
-
- /*
- * Reserve initrd memory if needed.
- */
- finalize_initrd();
}
#endif /* CONFIG_SGI_IP27 */
--
2.6.6
Memblock API can be successfully used to verify whether crashkernel
memory region belongs to low memory, then it can be reserved within
memblock allocator.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 105 ++++++++++++++---------------
1 file changed, 52 insertions(+), 53 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index d2f38ac..cc6d06b 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -426,6 +426,55 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
+#ifdef CONFIG_KEXEC
+/*
+ * Parse passed crashkernel parameter and reserve corresponding memory
+ */
+static void __init mips_parse_crashkernel(void)
+{
+ unsigned long long total_mem;
+ unsigned long long crash_size, crash_base;
+ int ret;
+
+ /* Parse crachkernel parameter */
+ total_mem = memblock_phys_mem_size();
+ ret = parse_crashkernel(boot_command_line, total_mem,
+ &crash_size, &crash_base);
+ if (ret != 0 || crash_size <= 0)
+ return;
+
+ crashk_res.start = crash_base;
+ crashk_res.end = crash_base + crash_size - 1;
+
+ /* Check whether the region belogs to lowmem and valid */
+ if (!is_lowmem_and_valid("Crashkernel", crash_base, crash_size))
+ return;
+
+ /* Reserve crashkernel resource */
+ memblock_reserve(crash_base, crash_size);
+}
+
+/*
+ * Reserve crashkernel memory within passed RAM resource
+ */
+static void __init request_crashkernel(struct resource *res)
+{
+ int ret;
+
+ ret = request_resource(res, &crashk_res);
+ if (!ret)
+ pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
+ (unsigned long)((crashk_res.end -
+ crashk_res.start + 1) >> 20),
+ (unsigned long)(crashk_res.start >> 20));
+}
+#else /* !CONFIG_KEXEC */
+
+static void __init mips_parse_crashkernel(void) { }
+static void __init request_crashkernel(struct resource *res) { }
+
+#endif /* !CONFIG_KEXEC */
+
/*
* Initialize the bootmem allocator. It also setup initrd related data
* if needed.
@@ -450,6 +499,9 @@ static void __init bootmem_init(void)
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
+ /* Parse crashkernel parameter */
+ mips_parse_crashkernel();
+
reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
/*
@@ -717,52 +769,6 @@ static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
add_memory_region(mem, size, type);
}
-#ifdef CONFIG_KEXEC
-static inline unsigned long long get_total_mem(void)
-{
- unsigned long long total;
-
- total = max_pfn - min_low_pfn;
- return total << PAGE_SHIFT;
-}
-
-static void __init mips_parse_crashkernel(void)
-{
- unsigned long long total_mem;
- unsigned long long crash_size, crash_base;
- int ret;
-
- total_mem = get_total_mem();
- ret = parse_crashkernel(boot_command_line, total_mem,
- &crash_size, &crash_base);
- if (ret != 0 || crash_size <= 0)
- return;
-
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
- int ret;
-
- ret = request_resource(res, &crashk_res);
- if (!ret)
- pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
- (unsigned long)((crashk_res.end -
- crashk_res.start + 1) >> 20),
- (unsigned long)(crashk_res.start >> 20));
-}
-#else /* !defined(CONFIG_KEXEC) */
-static void __init mips_parse_crashkernel(void)
-{
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
-}
-#endif /* !defined(CONFIG_KEXEC) */
-
#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
@@ -836,13 +842,6 @@ static void __init arch_mem_init(char **cmdline_p)
}
#endif
- mips_parse_crashkernel();
-#ifdef CONFIG_KEXEC
- if (crashk_res.start != crashk_res.end)
- reserve_bootmem(crashk_res.start,
- crashk_res.end - crashk_res.start + 1,
- BOOTMEM_DEFAULT);
-#endif
device_tree_init();
sparse_init();
plat_swiotlb_setup();
--
2.6.6
Memblock API can be successfully used to verify whether elfcorehdr
memory region belongs to lowmemory, then it can be reserved within
memblock allocator. There is also available default method for
early parameters parser in kernel/crash_dump.c: setup_elfcorehdr(),
so it's wise to use one instead of creating our own doing actually
the same thing.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 91 +++++++++++++++++-------------
1 file changed, 52 insertions(+), 39 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index cc6d06b..52205fb 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -426,6 +426,55 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
+/*
+ * Reserve memory occupied by elfcorehdr
+ */
+static void __init mips_reserve_elfcorehdr(void)
+{
+#ifdef CONFIG_PROC_VMCORE
+ /*
+ * Don't reserve anything if kernel isn't booting after a panic and
+ * vmcore is usable (see linux/crash_dump.h for details)
+ */
+ if (!is_vmcore_usable())
+ return;
+
+ /* Check whether the passed address belongs to low memory */
+ if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
+ pr_err("Elfcorehdr %08zx @ %pa doesn't belong to low memory",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+ return;
+ }
+
+ /*
+ * If elfcorehdr_size hasn't been specified, then try to reserve upto
+ * low memory limit
+ */
+ if (!elfcorehdr_size)
+ elfcorehdr_size = mips_lowmem_limit - elfcorehdr_addr;
+
+ /* Check the region belongs to actual memory (size can be zero) */
+ if (!memblock_is_region_memory(elfcorehdr_addr, elfcorehdr_size)) {
+ pr_err("Elfcorehdr %08zx @ %pa is not a memory region",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+ return;
+ }
+
+ /* Check whether elfcorehdr region is free */
+ if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
+ pr_err("Elfcorehdr %08zx @ %pa overlaps in-use memory",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+ return;
+ }
+
+ /* Reserve elfcorehdr within memblock */
+ memblock_reserve(elfcorehdr_addr, PAGE_ALIGN(elfcorehdr_size));
+
+ pr_info("Reserved memory for kdump at %08zx @ %pa\n",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+#endif /* CONFIG_PROC_VMCORE */
+}
+
#ifdef CONFIG_KEXEC
/*
* Parse passed crashkernel parameter and reserve corresponding memory
@@ -499,6 +548,9 @@ static void __init bootmem_init(void)
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
+ /* Reserve memory for elfcorehdr */
+ mips_reserve_elfcorehdr();
+
/* Parse crashkernel parameter */
mips_parse_crashkernel();
@@ -719,37 +771,6 @@ static void __init bootmem_init(void)
* initialization hook for anything else was introduced.
*/
-#ifdef CONFIG_PROC_VMCORE
-unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
-static int __init early_parse_elfcorehdr(char *p)
-{
- int i;
-
- setup_elfcorehdr = memparse(p, &p);
-
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start = boot_mem_map.map[i].addr;
- unsigned long end = (boot_mem_map.map[i].addr +
- boot_mem_map.map[i].size);
- if (setup_elfcorehdr >= start && setup_elfcorehdr < end) {
- /*
- * Reserve from the elf core header to the end of
- * the memory segment, that should all be kdump
- * reserved memory.
- */
- setup_elfcorehdr_size = end - setup_elfcorehdr;
- break;
- }
- }
- /*
- * If we don't find it in the memory map, then we shouldn't
- * have to worry about it, as the new kernel won't use it.
- */
- return 0;
-}
-early_param("elfcorehdr", early_parse_elfcorehdr);
-#endif
-
static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
{
phys_addr_t size;
@@ -833,14 +854,6 @@ static void __init arch_mem_init(char **cmdline_p)
parse_early_param();
bootmem_init();
-#ifdef CONFIG_PROC_VMCORE
- if (setup_elfcorehdr && setup_elfcorehdr_size) {
- printk(KERN_INFO "kdump reserved memory at %lx-%lx\n",
- setup_elfcorehdr, setup_elfcorehdr_size);
- reserve_bootmem(setup_elfcorehdr, setup_elfcorehdr_size,
- BOOTMEM_DEFAULT);
- }
-#endif
device_tree_init();
sparse_init();
--
2.6.6
Main memory initialization method looks messy with cmd line parser
built-in. So it's better for readability to put it into a separated
method.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 87 ++++++++++++++++--------------
1 file changed, 48 insertions(+), 39 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 52205fb..9c1a60d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -231,6 +231,51 @@ static void __init print_memory_map(void)
}
/*
+ * Parse passed cmdline
+ */
+#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
+#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
+#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_EXTEND)
+#define BUILTIN_EXTEND_WITH_PROM \
+ IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND)
+
+static void __init mips_parse_param(char **cmdline_p)
+{
+#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+ if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
+ (USE_DTB_CMDLINE && !boot_command_line[0]))
+ strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+
+ if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
+ if (boot_command_line[0])
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+ }
+
+#if defined(CONFIG_CMDLINE_BOOL)
+ if (builtin_cmdline[0]) {
+ if (boot_command_line[0])
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+ }
+
+ if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) {
+ if (boot_command_line[0])
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+ }
+#endif
+#endif
+ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+
+ *cmdline_p = command_line;
+
+ parse_early_param();
+}
+
+/*
* Parse "mem=size@start" parameter rewriting a defined memory map
* We look for mem=size@start, where start and size are "value[KkMm]"
*/
@@ -790,12 +835,6 @@ static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
add_memory_region(mem, size, type);
}
-#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
-#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
-#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
-#define BUILTIN_EXTEND_WITH_PROM \
- IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND)
-
static void __init arch_mem_init(char **cmdline_p)
{
struct memblock_region *reg;
@@ -804,6 +843,9 @@ static void __init arch_mem_init(char **cmdline_p)
/* call board setup routine */
plat_mem_setup();
+ /* Parse passed parameters */
+ mips_parse_param(cmdline_p);
+
/*
* Make sure all kernel memory is in the maps. The "UP" and
* "DOWN" are opposite for initdata since if it crosses over
@@ -820,39 +862,6 @@ static void __init arch_mem_init(char **cmdline_p)
pr_info("Determined physical RAM map:\n");
print_memory_map();
-#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
- strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-#else
- if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
- (USE_DTB_CMDLINE && !boot_command_line[0]))
- strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
-
- if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
- if (boot_command_line[0])
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
- strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
- }
-
-#if defined(CONFIG_CMDLINE_BOOL)
- if (builtin_cmdline[0]) {
- if (boot_command_line[0])
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
- strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
- }
-
- if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) {
- if (boot_command_line[0])
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
- strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
- }
-#endif
-#endif
- strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-
- *cmdline_p = command_line;
-
- parse_early_param();
-
bootmem_init();
device_tree_init();
--
2.6.6
In order to get a structured table of platform devices, it is
widespread amongst modern systems to use fdt'es.
MIPS should support one as well. Particularly /memory/ and
/reserved-memory/ should be analyzed and corresponding regions
registered with memblock subsystem.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/prom.c | 32 ++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index 5fcec30..f21eb8c 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -17,6 +17,7 @@
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
+#include <linux/memblock.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
@@ -41,7 +42,36 @@ char *mips_get_machine_name(void)
#ifdef CONFIG_USE_OF
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
- return add_memory_region(base, size, BOOT_MEM_RAM);
+ /* Check whether specified region is well formed */
+ if (sanity_check_dt_memory(&base, &size))
+ return;
+
+ /* Memory region should be in boot_mem_map, so use the old method */
+ add_memory_region(base, size, BOOT_MEM_RAM);
+}
+
+int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ /*
+ * NOTE We don't use add_memory_region() method here, since fdt
+ * reserved-memory regions are declared within already added memory,
+ * while boot_mem_map consists of unique regions
+ */
+
+ /* Check whether region is free. If so just ignore it */
+ if (memblock_is_region_reserved(base, size)) {
+ pr_err("FDT reserve-node %08zx @ %pa overlaps in-use memory\n",
+ (size_t)size, &base);
+ return -EBUSY;
+ }
+
+ /* If it can be mapped, then just reserve the region */
+ if (!nomap)
+ return memblock_reserve(base, size);
+
+ /* Completely remove region if it shouldn't be mapped */
+ return memblock_remove(base, size);
}
void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
--
2.6.6
Both new memblock and boot_mem_map subsystems need to be fully
cleared before a new memory region is added. So the early parser is
correspondingly modified.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 67 +++++++++++++++++-------------
1 file changed, 37 insertions(+), 30 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 9da6f8a..789aafe 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -229,6 +229,43 @@ static void __init print_memory_map(void)
}
/*
+ * Parse "mem=size@start" parameter rewriting a defined memory map
+ * We look for mem=size@start, where start and size are "value[KkMm]"
+ */
+static int __init early_parse_mem(char *p)
+{
+ static int usermem;
+ phys_addr_t start, size;
+
+ start = PHYS_OFFSET;
+ size = memparse(p, &p);
+ if (*p == '@')
+ start = memparse(p + 1, &p);
+
+ /*
+ * If a user specifies memory size, we blow away any automatically
+ * generated regions.
+ */
+ if (usermem == 0) {
+ phys_addr_t ram_start = memblock_start_of_DRAM();
+ phys_addr_t ram_end = memblock_end_of_DRAM() - ram_start;
+
+ pr_notice("Discard memory layout %pa - %pa",
+ &ram_start, &ram_end);
+
+ memblock_remove(ram_start, ram_end - ram_start);
+ boot_mem_map.nr_map = 0;
+ usermem = 1;
+ }
+ pr_notice("Add userdefined memory region %08zx @ %pa",
+ (size_t)size, &start);
+
+ add_memory_region(start, size, BOOT_MEM_RAM);
+ return 0;
+}
+early_param("mem", early_parse_mem);
+
+/*
* Manage initrd
*/
#ifdef CONFIG_BLK_DEV_INITRD
@@ -613,31 +650,6 @@ static void __init bootmem_init(void)
* initialization hook for anything else was introduced.
*/
-static int usermem __initdata;
-
-static int __init early_parse_mem(char *p)
-{
- phys_addr_t start, size;
-
- /*
- * If a user specifies memory size, we
- * blow away any automatically generated
- * size.
- */
- if (usermem == 0) {
- boot_mem_map.nr_map = 0;
- usermem = 1;
- }
- start = 0;
- size = memparse(p, &p);
- if (*p == '@')
- start = memparse(p + 1, &p);
-
- add_memory_region(start, size, BOOT_MEM_RAM);
- return 0;
-}
-early_param("mem", early_parse_mem);
-
#ifdef CONFIG_PROC_VMCORE
unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
static int __init early_parse_elfcorehdr(char *p)
@@ -797,11 +809,6 @@ static void __init arch_mem_init(char **cmdline_p)
parse_early_param();
- if (usermem) {
- pr_info("User-defined physical RAM map:\n");
- print_memory_map();
- }
-
bootmem_init();
#ifdef CONFIG_PROC_VMCORE
if (setup_elfcorehdr && setup_elfcorehdr_size) {
--
2.6.6
There is no safe and fast way to get rid of boot_mem_map usage in
the wide set of platform code. But it's luck, that the architecture
specific code doesn't make any direct changes in the boot_mem_map
structure. Additionally the platform specific code registers the
available memory using traditional add_memory_region() method.
It's obvious, that one needs to be modified adding regions to both
new memblock allocator and old boot_mem_map subsystem. In this way
most of architecture specific code won't be broken.
Signed-off-by: Serge Semin <[email protected]>
---
arch/mips/kernel/setup.c | 51 ++++++++++++++++++++++++++++--
1 file changed, 48 insertions(+), 3 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 084ba6c..9da6f8a 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -82,10 +82,19 @@ static struct resource data_resource = { .name = "Kernel data", };
static void *detect_magic __initdata = detect_memory_region;
+/*
+ * General method to add RAM regions to the system
+ *
+ * NOTE Historically this method has been used to register memory blocks within
+ * MIPS kernel code in the boot_mem_map array. So we need to support it
+ * up until it's discarded from platform-depended code.
+ * On the other hand it might be good to have it, since we can check regions
+ * before actually adding them
+ */
void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
{
int x = boot_mem_map.nr_map;
- int i;
+ int ret, i;
/*
* If the region reaches the top of the physical address space, adjust
@@ -94,15 +103,51 @@ void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
if (start + size - 1 == (phys_addr_t)ULLONG_MAX)
--size;
- /* Sanity check */
+ /* Sanity check the region */
if (start + size < start) {
pr_warn("Trying to add an invalid memory region, skipped\n");
return;
}
+ /* Make sure the type is supported */
+ if (type != BOOT_MEM_RAM && type != BOOT_MEM_INIT_RAM &&
+ type != BOOT_MEM_ROM_DATA && type != BOOT_MEM_RESERVED) {
+ pr_warn("Invalid type of memory region, skipped\n");
+ return;
+ }
+
/*
- * Try to merge with existing entry, if any.
+ * According to the request_resource logic RAM, INIT and ROM shouldn't
+ * intersect each other but being subset of one memory space
*/
+ if (type != BOOT_MEM_RESERVED && memblock_is_memory(start)) {
+ pr_warn("Drop already added memory region %08zx @ %pa\n",
+ (size_t)size, &start);
+ return;
+ }
+
+ /*
+ * Add the region to the memblock allocator. Reserved regions should be
+ * in the memory as well to be actually reserved.
+ */
+ ret = memblock_add_node(start, size, 0);
+ if (ret < 0) {
+ pr_err("Could't add memblock %08zx @ %pa\n",
+ (size_t)size, &start);
+ return;
+ }
+
+ /* Reserve memory region passed with the corresponding flags */
+ if (type != BOOT_MEM_RAM) {
+ ret = memblock_reserve(start, size);
+ if (ret < 0) {
+ pr_err("Could't reserve memblock %08zx @ %pa\n",
+ (size_t)size, &start);
+ return;
+ }
+ }
+
+ /* Try to combine with existing entry, if any. */
for (i = 0; i < boot_mem_map.nr_map; i++) {
struct boot_mem_map_entry *entry = boot_mem_map.map + i;
unsigned long top;
--
2.6.6
It's necessary to check whether retrieved from dts memory regions
fits to page alignment and limits restrictions. Sometimes it is
necessary to perform the same checks, but ito add the memory regions
into a different subsystem. MIPS is going to be that case.
Signed-off-by: Serge Semin <[email protected]>
---
drivers/of/fdt.c | 47 +++++++++++++++++++++++---------
include/linux/of_fdt.h | 1 +
2 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 1f98156..1ee958f 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -983,44 +983,65 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
#define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0)
#endif
-void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+int __init sanity_check_dt_memory(phys_addr_t *out_base,
+ phys_addr_t *out_size)
{
+ phys_addr_t base = *out_base, size = *out_size;
const u64 phys_offset = MIN_MEMBLOCK_ADDR;
if (!PAGE_ALIGNED(base)) {
if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
- pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
+ pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
base, base + size);
- return;
+ return -EINVAL;
}
+ pr_warn("Memblock 0x%llx - 0x%llx shifted to ",
+ base, base + size);
size -= PAGE_SIZE - (base & ~PAGE_MASK);
base = PAGE_ALIGN(base);
+ pr_cont("0x%llx - 0x%llx\n", base, base + size);
}
size &= PAGE_MASK;
if (base > MAX_MEMBLOCK_ADDR) {
- pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
- base, base + size);
- return;
+ pr_err("Memblock 0x%llx - 0x%llx exceeds max address\n",
+ base, base + size);
+ return -EINVAL;
}
if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
- pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
- ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
+ pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
+ base, base + size);
size = MAX_MEMBLOCK_ADDR - base + 1;
+ pr_cont("0x%llx - 0x%llx\n", base, base + size);
}
if (base + size < phys_offset) {
- pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
- base, base + size);
- return;
+ pr_err("Memblock 0x%llx - 0x%llx is below phys offset\n",
+ base, base + size);
+ return -EINVAL;
}
+
if (base < phys_offset) {
- pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
- base, phys_offset);
+ pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
+ base, base + size);
size -= phys_offset - base;
base = phys_offset;
+ pr_cont("0x%llx - 0x%llx\n", base, base + size);
}
+
+ /* Set the output base address and size */
+ *out_base = base;
+ *out_size = size;
+
+ return 0;
+}
+
+void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+ if (sanity_check_dt_memory(&base, &size))
+ return;
+
memblock_add(base, size);
}
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index df9ef38..ddf93c5 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -84,6 +84,7 @@ extern const void *of_flat_dt_match_machine(const void *default_match,
const void * (*get_next_compat)(const char * const**));
/* Other Prototypes */
+extern int sanity_check_dt_memory(phys_addr_t *base, phys_addr_t *size);
extern void unflatten_device_tree(void);
extern void unflatten_and_copy_device_tree(void);
extern void early_init_devtree(void *);
--
2.6.6
Hi Serge,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9 next-20161216]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Serge-Semin/MIPS-memblock-Remove-bootmem-code-and-switch-to-NO_BOOTMEM/20161219-105045
config: mips-allyesconfig (attached as .config)
compiler: mips-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=mips
All error/warnings (new ones prefixed by >>):
In file included from arch/mips/include/asm/bug.h:4:0,
from include/linux/bug.h:4,
from arch/mips/mm/init.c:12:
arch/mips/mm/init.c: In function 'mem_print_kmap_info':
>> arch/mips/mm/init.c:143:31: error: 'LAST_PKMAP' undeclared (first use in this function)
BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
^
include/linux/compiler.h:498:19: note: in definition of macro '__compiletime_assert'
bool __cond = !(condition); \
^~~~~~~~~
include/linux/compiler.h:518:2: note: in expansion of macro '_compiletime_assert'
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
^~~~~~~~~~~~~~~~~~~
include/linux/bug.h:54:37: note: in expansion of macro 'compiletime_assert'
#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
^~~~~~~~~~~~~~~~~~
include/linux/bug.h:78:2: note: in expansion of macro 'BUILD_BUG_ON_MSG'
BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
^~~~~~~~~~~~~~~~
>> arch/mips/mm/init.c:143:2: note: in expansion of macro 'BUILD_BUG_ON'
BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
^~~~~~~~~~~~
arch/mips/mm/init.c:143:31: note: each undeclared identifier is reported only once for each function it appears in
BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
^
include/linux/compiler.h:498:19: note: in definition of macro '__compiletime_assert'
bool __cond = !(condition); \
^~~~~~~~~
include/linux/compiler.h:518:2: note: in expansion of macro '_compiletime_assert'
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
^~~~~~~~~~~~~~~~~~~
include/linux/bug.h:54:37: note: in expansion of macro 'compiletime_assert'
#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
^~~~~~~~~~~~~~~~~~
include/linux/bug.h:78:2: note: in expansion of macro 'BUILD_BUG_ON_MSG'
BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
^~~~~~~~~~~~~~~~
>> arch/mips/mm/init.c:143:2: note: in expansion of macro 'BUILD_BUG_ON'
BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
^~~~~~~~~~~~
vim +/LAST_PKMAP +143 arch/mips/mm/init.c
6 * Copyright (C) 1994 - 2000 Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 * Kevin D. Kissell, [email protected] and Carsten Langgaard, [email protected]
9 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
10 * Copyright (C) 2016 T-Platforms. All Rights Reserved.
11 */
> 12 #include <linux/bug.h>
13 #include <linux/init.h>
14 #include <linux/export.h>
15 #include <linux/signal.h>
16 #include <linux/sched.h>
17 #include <linux/smp.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/string.h>
21 #include <linux/types.h>
22 #include <linux/pagemap.h>
23 #include <linux/ptrace.h>
24 #include <linux/mman.h>
25 #include <linux/mm.h>
26 #include <linux/memblock.h>
27 #include <linux/bootmem.h>
28 #include <linux/highmem.h>
29 #include <linux/swap.h>
30 #include <linux/proc_fs.h>
31 #include <linux/pfn.h>
32 #include <linux/hardirq.h>
33 #include <linux/gfp.h>
34 #include <linux/kcore.h>
35 #include <linux/sizes.h>
36
37 #include <asm/asm-offsets.h>
38 #include <asm/bootinfo.h>
39 #include <asm/cachectl.h>
40 #include <asm/cpu.h>
41 #include <asm/dma.h>
42 #include <asm/kmap_types.h>
43 #include <asm/maar.h>
44 #include <asm/mmu_context.h>
45 #include <asm/sections.h>
46 #include <asm/pgtable.h>
47 #include <asm/pgalloc.h>
48 #include <asm/tlb.h>
49 #include <asm/fixmap.h>
50 #include <asm/maar.h>
51
52 /*
53 * We have up to 8 empty zeroed pages so we can map one of the right colour
54 * when needed. This is necessary only on R4000 / R4400 SC and MC versions
55 * where we have to avoid VCED / VECI exceptions for good performance at
56 * any price. Since page is never written to after the initialization we
57 * don't have to care about aliases on other CPUs.
58 */
59 unsigned long empty_zero_page, zero_page_mask;
60 EXPORT_SYMBOL_GPL(empty_zero_page);
61 EXPORT_SYMBOL(zero_page_mask);
62
63 /*
64 * Initialize sparse memory sections setting node ids and indexes
65 */
66 static void __init mips_memory_present(void)
67 {
68 #ifdef CONFIG_SPARSEMEM
69 struct memblock_region *reg;
70
71 for_each_memblock(memory, reg)
72 memory_present(0, memblock_region_memory_base_pfn(reg),
73 memblock_region_memory_end_pfn(reg));
74 #endif /* CONFIG_SPARSEMEM */
75 }
76
77 /*
78 * Setup nodes zone areas
79 */
80 static void __init zone_sizes_init(void)
81 {
82 unsigned long max_zone_pfns[MAX_NR_ZONES];
83
84 /* Clean zone boundaries array */
85 memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
86
87 /* Setup determined boundaries */
88 #ifdef CONFIG_ZONE_DMA
89 max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
90 #endif
91 #ifdef CONFIG_ZONE_DMA32
92 max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
93 #endif
94 max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
95 #ifdef CONFIG_HIGHMEM
96 max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
97
98 /* Make sure the processor supports highmem */
99 if (cpu_has_dc_aliases && max_low_pfn != highend_pfn) {
100 pr_warn("CPU doesn't support highmem. %ldk highmem ignored\n",
101 (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
102 max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
103 }
104 #endif
105
106 /* Finally initialize nodes and page maps using memblock info */
107 free_area_init_nodes(max_zone_pfns);
108 }
109
110 /*
111 * Print out kernel memory layout
112 */
113 #define MLK(b, t) b, t, ((t) - (b)) >> 10
114 #define MLM(b, t) b, t, ((t) - (b)) >> 20
115 #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
116 static void __init mem_print_kmap_info(void)
117 {
118 pr_notice("Virtual kernel memory layout:\n"
119 " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
120 " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
121 #ifdef CONFIG_HIGHMEM
122 " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
123 #endif
124 " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
125 " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
126 " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
127 " .init : 0x%p" " - 0x%p" " (%4td kB)\n",
128 MLM(PAGE_OFFSET, (unsigned long)high_memory),
129 MLM(VMALLOC_START, VMALLOC_END),
130 #ifdef CONFIG_HIGHMEM
131 MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE)),
132 #endif
133 MLK(FIXADDR_START, FIXADDR_TOP),
134 MLK_ROUNDUP(_text, _etext),
135 MLK_ROUNDUP(_sdata, _edata),
136 MLK_ROUNDUP(__init_begin, __init_end));
137
138 /* Check some fundamental inconsistencies. May add something else? */
139 #ifdef CONFIG_HIGHMEM
140 BUILD_BUG_ON(VMALLOC_END < PAGE_OFFSET);
141 BUG_ON(VMALLOC_END < (unsigned long)high_memory);
142 #endif
> 143 BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
144 BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) <
145 (unsigned long)high_memory);
146 BUILD_BUG_ON(FIXADDR_TOP < PAGE_OFFSET);
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Serge,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9 next-20161216]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Serge-Semin/MIPS-memblock-Remove-bootmem-code-and-switch-to-NO_BOOTMEM/20161219-105045
config: mips-allyesconfig (attached as .config)
compiler: mips-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=mips
All errors (new ones prefixed by >>):
arch/mips/kernel/setup.c: In function 'mips_reserve_elfcorehdr':
>> arch/mips/kernel/setup.c:439:7: error: implicit declaration of function 'is_vmcore_usable' [-Werror=implicit-function-declaration]
if (!is_vmcore_usable())
^~~~~~~~~~~~~~~~
>> arch/mips/kernel/setup.c:443:6: error: 'elfcorehdr_addr' undeclared (first use in this function)
if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
^~~~~~~~~~~~~~~
arch/mips/kernel/setup.c:443:6: note: each undeclared identifier is reported only once for each function it appears in
>> arch/mips/kernel/setup.c:443:24: error: 'elfcorehdr_size' undeclared (first use in this function)
if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
^~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/is_vmcore_usable +439 arch/mips/kernel/setup.c
433 {
434 #ifdef CONFIG_PROC_VMCORE
435 /*
436 * Don't reserve anything if kernel isn't booting after a panic and
437 * vmcore is usable (see linux/crash_dump.h for details)
438 */
> 439 if (!is_vmcore_usable())
440 return;
441
442 /* Check whether the passed address belongs to low memory */
> 443 if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
444 pr_err("Elfcorehdr %08zx @ %pa doesn't belong to low memory",
445 (size_t)elfcorehdr_size, &elfcorehdr_addr);
446 return;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Serge,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9 next-20161216]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Serge-Semin/MIPS-memblock-Remove-bootmem-code-and-switch-to-NO_BOOTMEM/20161219-105045
config: mips-rt305x_defconfig (attached as .config)
compiler: mipsel-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=mips
All errors (new ones prefixed by >>):
arch/mips/kernel/prom.c: In function 'early_init_dt_add_memory_arch':
>> arch/mips/kernel/prom.c:46:29: error: passing argument 1 of 'sanity_check_dt_memory' from incompatible pointer type [-Werror=incompatible-pointer-types]
if (sanity_check_dt_memory(&base, &size))
^
In file included from arch/mips/kernel/prom.c:18:0:
include/linux/of_fdt.h:93:12: note: expected 'phys_addr_t * {aka unsigned int *}' but argument is of type 'u64 * {aka long long unsigned int *}'
extern int sanity_check_dt_memory(phys_addr_t *base, phys_addr_t *size);
^~~~~~~~~~~~~~~~~~~~~~
arch/mips/kernel/prom.c:46:36: error: passing argument 2 of 'sanity_check_dt_memory' from incompatible pointer type [-Werror=incompatible-pointer-types]
if (sanity_check_dt_memory(&base, &size))
^
In file included from arch/mips/kernel/prom.c:18:0:
include/linux/of_fdt.h:93:12: note: expected 'phys_addr_t * {aka unsigned int *}' but argument is of type 'u64 * {aka long long unsigned int *}'
extern int sanity_check_dt_memory(phys_addr_t *base, phys_addr_t *size);
^~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/sanity_check_dt_memory +46 arch/mips/kernel/prom.c
40 }
41
42 #ifdef CONFIG_USE_OF
43 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
44 {
45 /* Check whether specified region is well formed */
> 46 if (sanity_check_dt_memory(&base, &size))
47 return;
48
49 /* Memory region should be in boot_mem_map, so use the old method */
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Serge,
[auto build test WARNING on linus/master]
[also build test WARNING on v4.9 next-20161216]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Serge-Semin/MIPS-memblock-Remove-bootmem-code-and-switch-to-NO_BOOTMEM/20161219-105045
config: i386-randconfig-i0-201651 (attached as .config)
compiler: gcc-4.8 (Debian 4.8.4-1) 4.8.4
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All warnings (new ones prefixed by >>):
drivers/of/fdt.c: In function 'sanity_check_dt_memory':
>> drivers/of/fdt.c:1125:4: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
^
drivers/of/fdt.c:1125:4: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1129:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_warn("Memblock 0x%llx - 0x%llx shifted to ",
^
drivers/of/fdt.c:1129:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1133:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_cont("0x%llx - 0x%llx\n", base, base + size);
^
drivers/of/fdt.c:1133:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1138:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_err("Memblock 0x%llx - 0x%llx exceeds max address\n",
^
drivers/of/fdt.c:1138:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1144:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
^
drivers/of/fdt.c:1144:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1147:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_cont("0x%llx - 0x%llx\n", base, base + size);
^
drivers/of/fdt.c:1147:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1151:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_err("Memblock 0x%llx - 0x%llx is below phys offset\n",
^
drivers/of/fdt.c:1151:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1157:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
^
drivers/of/fdt.c:1157:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c:1161:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat=]
pr_cont("0x%llx - 0x%llx\n", base, base + size);
^
drivers/of/fdt.c:1161:3: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'phys_addr_t' [-Wformat=]
drivers/of/fdt.c: In function 'early_init_dt_add_memory_arch':
>> drivers/of/fdt.c:1173:2: warning: passing argument 1 of 'sanity_check_dt_memory' from incompatible pointer type [enabled by default]
if (sanity_check_dt_memory(&base, &size))
^
drivers/of/fdt.c:1117:12: note: expected 'phys_addr_t *' but argument is of type 'u64 *'
int __init sanity_check_dt_memory(phys_addr_t *out_base,
^
drivers/of/fdt.c:1173:2: warning: passing argument 2 of 'sanity_check_dt_memory' from incompatible pointer type [enabled by default]
if (sanity_check_dt_memory(&base, &size))
^
drivers/of/fdt.c:1117:12: note: expected 'phys_addr_t *' but argument is of type 'u64 *'
int __init sanity_check_dt_memory(phys_addr_t *out_base,
^
vim +1125 drivers/of/fdt.c
1119 {
1120 phys_addr_t base = *out_base, size = *out_size;
1121 const u64 phys_offset = MIN_MEMBLOCK_ADDR;
1122
1123 if (!PAGE_ALIGNED(base)) {
1124 if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
> 1125 pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
1126 base, base + size);
1127 return -EINVAL;
1128 }
1129 pr_warn("Memblock 0x%llx - 0x%llx shifted to ",
1130 base, base + size);
1131 size -= PAGE_SIZE - (base & ~PAGE_MASK);
1132 base = PAGE_ALIGN(base);
1133 pr_cont("0x%llx - 0x%llx\n", base, base + size);
1134 }
1135 size &= PAGE_MASK;
1136
1137 if (base > MAX_MEMBLOCK_ADDR) {
1138 pr_err("Memblock 0x%llx - 0x%llx exceeds max address\n",
1139 base, base + size);
1140 return -EINVAL;
1141 }
1142
1143 if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
1144 pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
1145 base, base + size);
1146 size = MAX_MEMBLOCK_ADDR - base + 1;
1147 pr_cont("0x%llx - 0x%llx\n", base, base + size);
1148 }
1149
1150 if (base + size < phys_offset) {
1151 pr_err("Memblock 0x%llx - 0x%llx is below phys offset\n",
1152 base, base + size);
1153 return -EINVAL;
1154 }
1155
1156 if (base < phys_offset) {
> 1157 pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
1158 base, base + size);
1159 size -= phys_offset - base;
1160 base = phys_offset;
1161 pr_cont("0x%llx - 0x%llx\n", base, base + size);
1162 }
1163
1164 /* Set the output base address and size */
1165 *out_base = base;
1166 *out_size = size;
1167
1168 return 0;
1169 }
1170
1171 void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
1172 {
> 1173 if (sanity_check_dt_memory(&base, &size))
1174 return;
1175
1176 memblock_add(base, size);
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Serge,
[auto build test WARNING on linus/master]
[also build test WARNING on v4.9 next-20161216]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Serge-Semin/MIPS-memblock-Remove-bootmem-code-and-switch-to-NO_BOOTMEM/20161219-105045
config: openrisc-or1ksim_defconfig (attached as .config)
compiler: or32-linux-gcc (GCC) 4.5.1-or32-1.0rc1
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=openrisc
All warnings (new ones prefixed by >>):
drivers/of/fdt.c: In function 'sanity_check_dt_memory':
>> drivers/of/fdt.c:1125:4: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1125:4: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1129:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1129:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1133:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1133:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1138:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1138:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1144:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1144:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1147:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1147:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1151:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1151:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1157:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1157:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c:1161:3: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'phys_addr_t'
drivers/of/fdt.c:1161:3: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'phys_addr_t'
drivers/of/fdt.c: In function 'early_init_dt_add_memory_arch':
drivers/of/fdt.c:1173:2: warning: passing argument 1 of 'sanity_check_dt_memory' from incompatible pointer type
drivers/of/fdt.c:1117:12: note: expected 'phys_addr_t *' but argument is of type 'u64 *'
drivers/of/fdt.c:1173:2: warning: passing argument 2 of 'sanity_check_dt_memory' from incompatible pointer type
drivers/of/fdt.c:1117:12: note: expected 'phys_addr_t *' but argument is of type 'u64 *'
vim +1125 drivers/of/fdt.c
1109 #ifdef CONFIG_HAVE_MEMBLOCK
1110 #ifndef MIN_MEMBLOCK_ADDR
1111 #define MIN_MEMBLOCK_ADDR __pa(PAGE_OFFSET)
1112 #endif
1113 #ifndef MAX_MEMBLOCK_ADDR
1114 #define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0)
1115 #endif
1116
1117 int __init sanity_check_dt_memory(phys_addr_t *out_base,
1118 phys_addr_t *out_size)
1119 {
1120 phys_addr_t base = *out_base, size = *out_size;
1121 const u64 phys_offset = MIN_MEMBLOCK_ADDR;
1122
1123 if (!PAGE_ALIGNED(base)) {
1124 if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
> 1125 pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
1126 base, base + size);
1127 return -EINVAL;
1128 }
1129 pr_warn("Memblock 0x%llx - 0x%llx shifted to ",
1130 base, base + size);
1131 size -= PAGE_SIZE - (base & ~PAGE_MASK);
1132 base = PAGE_ALIGN(base);
1133 pr_cont("0x%llx - 0x%llx\n", base, base + size);
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Serge,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9 next-20161216]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Serge-Semin/MIPS-memblock-Remove-bootmem-code-and-switch-to-NO_BOOTMEM/20161219-105045
config: mips-allyesconfig (attached as .config)
compiler: mips-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=mips
All errors (new ones prefixed by >>):
arch/mips/kernel/setup.c: In function 'mips_reserve_elfcorehdr':
arch/mips/kernel/setup.c:540:7: error: implicit declaration of function 'is_vmcore_usable' [-Werror=implicit-function-declaration]
if (!is_vmcore_usable())
^~~~~~~~~~~~~~~~
arch/mips/kernel/setup.c:544:6: error: 'elfcorehdr_addr' undeclared (first use in this function)
if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
^~~~~~~~~~~~~~~
arch/mips/kernel/setup.c:544:6: note: each undeclared identifier is reported only once for each function it appears in
arch/mips/kernel/setup.c:544:24: error: 'elfcorehdr_size' undeclared (first use in this function)
if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
^~~~~~~~~~~~~~~
In file included from include/linux/kernel.h:13:0,
from include/asm-generic/bug.h:13,
from arch/mips/include/asm/bug.h:41,
from include/linux/bug.h:4,
from include/linux/mmdebug.h:4,
from include/linux/mm.h:8,
from include/linux/memblock.h:18,
from arch/mips/kernel/setup.c:17:
arch/mips/kernel/setup.c: In function 'find_pfn_limits':
>> arch/mips/kernel/setup.c:644:29: error: 'highstart_pfn' undeclared (first use in this function)
min_low_pfn, max_low_pfn, highstart_pfn, highend_pfn, max_pfn);
^
include/linux/printk.h:299:34: note: in definition of macro 'pr_info'
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
>> arch/mips/kernel/setup.c:644:44: error: 'highend_pfn' undeclared (first use in this function)
min_low_pfn, max_low_pfn, highstart_pfn, highend_pfn, max_pfn);
^
include/linux/printk.h:299:34: note: in definition of macro 'pr_info'
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/highstart_pfn +644 arch/mips/kernel/setup.c
638 #ifdef CONFIG_HIGHMEM
639 highstart_pfn = max_low_pfn;
640 highend_pfn = max_pfn <= highstart_pfn ? highstart_pfn : max_pfn;
641 #endif
642 pr_info("PFNs: low min %lu, low max %lu, high start %lu, high end %lu,"
643 "max %lu\n",
> 644 min_low_pfn, max_low_pfn, highstart_pfn, highend_pfn, max_pfn);
645 }
646
647 /*
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Serge,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9 next-20161216]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Serge-Semin/MIPS-memblock-Remove-bootmem-code-and-switch-to-NO_BOOTMEM/20161219-105045
config: mips-jazz_defconfig (attached as .config)
compiler: mipsel-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=mips
All errors (new ones prefixed by >>):
>> arch/mips/kernel/setup.c:273:20: error: 'is_lowmem_and_valid' defined but not used [-Werror=unused-function]
static bool __init is_lowmem_and_valid(const char *name, phys_addr_t base,
^~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
vim +/is_lowmem_and_valid +273 arch/mips/kernel/setup.c
267 }
268 early_param("mem", early_parse_mem);
269
270 /*
271 * Helper method checking whether passed lowmem region is valid
272 */
> 273 static bool __init is_lowmem_and_valid(const char *name, phys_addr_t base,
274 phys_addr_t size)
275 {
276 phys_addr_t end = base + size;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Serge,
On 19/12/16 02:07, Serge Semin wrote:
> It's useful to have some printed map of the kernel virtual memory,
> at least for debugging purpose.
>
> Signed-off-by: Serge Semin <[email protected]>
> ---
> arch/mips/mm/init.c | 47 +++++++++++++++++++++++++++++++++++
> 1 file changed, 47 insertions(+)
>
> diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
> index 13a032f..35e7ba8 100644
> --- a/arch/mips/mm/init.c
> +++ b/arch/mips/mm/init.c
> @@ -32,6 +32,7 @@
> #include <linux/hardirq.h>
> #include <linux/gfp.h>
> #include <linux/kcore.h>
> +#include <linux/sizes.h>
>
> #include <asm/asm-offsets.h>
> #include <asm/bootinfo.h>
> @@ -106,6 +107,49 @@ static void __init zone_sizes_init(void)
> }
>
> /*
> + * Print out kernel memory layout
> + */
> +#define MLK(b, t) b, t, ((t) - (b)) >> 10
> +#define MLM(b, t) b, t, ((t) - (b)) >> 20
> +#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
> +static void __init mem_print_kmap_info(void)
> +{
> + pr_notice("Virtual kernel memory layout:\n"
> + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
> + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
> +#ifdef CONFIG_HIGHMEM
> + " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
> +#endif
> + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
> + " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
> + " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
> + " .init : 0x%p" " - 0x%p" " (%4td kB)\n",
> + MLM(PAGE_OFFSET, (unsigned long)high_memory),
> + MLM(VMALLOC_START, VMALLOC_END),
> +#ifdef CONFIG_HIGHMEM
> + MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE)),
> +#endif
> + MLK(FIXADDR_START, FIXADDR_TOP),
> + MLK_ROUNDUP(_text, _etext),
> + MLK_ROUNDUP(_sdata, _edata),
> + MLK_ROUNDUP(__init_begin, __init_end));
Please drop printing the kernel addresses, or at least only do it if
KASLR is not turned on, otherwise you're removing the advantage of
KASLR, that critical kernel addresses cannot be determined easily from
userspace.
It may be better to merge the functionality of show_kernel_relocation
http://lxr.free-electrons.com/source/arch/mips/kernel/relocate.c#L354
into this function, but only print it under the same conditions as
currently, i.e.
#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
http://lxr.free-electrons.com/source/arch/mips/kernel/setup.c#L530
Thanks,
Matt
> +
> + /* Check some fundamental inconsistencies. May add something else? */
> +#ifdef CONFIG_HIGHMEM
> + BUILD_BUG_ON(VMALLOC_END < PAGE_OFFSET);
> + BUG_ON(VMALLOC_END < (unsigned long)high_memory);
> +#endif
> + BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
> + BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) <
> + (unsigned long)high_memory);
> + BUILD_BUG_ON(FIXADDR_TOP < PAGE_OFFSET);
> + BUG_ON(FIXADDR_TOP < (unsigned long)high_memory);
> +}
> +#undef MLK
> +#undef MLM
> +#undef MLK_ROUNDUP
> +
> +/*
> * Not static inline because used by IP27 special magic initialization code
> */
> void setup_zero_pages(void)
> @@ -492,6 +536,9 @@ void __init mem_init(void)
> /* Free highmemory registered in memblocks */
> mem_init_free_highmem();
>
> + /* Print out kernel memory layout */
> + mem_print_kmap_info();
> +
> /* Print out memory areas statistics */
> mem_init_print_info(NULL);
>
On Mon, Dec 19, 2016 at 12:04:54PM +0000, Matt Redfearn <[email protected]> wrote:
Hello Matt.
> Hi Serge,
>
>
> On 19/12/16 02:07, Serge Semin wrote:
> >It's useful to have some printed map of the kernel virtual memory,
> >at least for debugging purpose.
> >
> >Signed-off-by: Serge Semin <[email protected]>
> >---
> > arch/mips/mm/init.c | 47 +++++++++++++++++++++++++++++++++++
> > 1 file changed, 47 insertions(+)
> >
> >diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
> >index 13a032f..35e7ba8 100644
> >--- a/arch/mips/mm/init.c
> >+++ b/arch/mips/mm/init.c
> >@@ -32,6 +32,7 @@
> > #include <linux/hardirq.h>
> > #include <linux/gfp.h>
> > #include <linux/kcore.h>
> >+#include <linux/sizes.h>
> > #include <asm/asm-offsets.h>
> > #include <asm/bootinfo.h>
> >@@ -106,6 +107,49 @@ static void __init zone_sizes_init(void)
> > }
> > /*
> >+ * Print out kernel memory layout
> >+ */
> >+#define MLK(b, t) b, t, ((t) - (b)) >> 10
> >+#define MLM(b, t) b, t, ((t) - (b)) >> 20
> >+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
> >+static void __init mem_print_kmap_info(void)
> >+{
> >+ pr_notice("Virtual kernel memory layout:\n"
> >+ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
> >+ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
> >+#ifdef CONFIG_HIGHMEM
> >+ " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
> >+#endif
> >+ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
> >+ " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
> >+ " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
> >+ " .init : 0x%p" " - 0x%p" " (%4td kB)\n",
> >+ MLM(PAGE_OFFSET, (unsigned long)high_memory),
> >+ MLM(VMALLOC_START, VMALLOC_END),
> >+#ifdef CONFIG_HIGHMEM
> >+ MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE)),
> >+#endif
> >+ MLK(FIXADDR_START, FIXADDR_TOP),
> >+ MLK_ROUNDUP(_text, _etext),
> >+ MLK_ROUNDUP(_sdata, _edata),
> >+ MLK_ROUNDUP(__init_begin, __init_end));
>
> Please drop printing the kernel addresses, or at least only do it if KASLR
> is not turned on, otherwise you're removing the advantage of KASLR, that
> critical kernel addresses cannot be determined easily from userspace.
>
> It may be better to merge the functionality of show_kernel_relocation
> http://lxr.free-electrons.com/source/arch/mips/kernel/relocate.c#L354
> into this function, but only print it under the same conditions as
> currently, i.e.
> #if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
> http://lxr.free-electrons.com/source/arch/mips/kernel/setup.c#L530
>
> Thanks,
> Matt
>
Understood. Will be fixed within the next patchset.
> >+
> >+ /* Check some fundamental inconsistencies. May add something else? */
> >+#ifdef CONFIG_HIGHMEM
> >+ BUILD_BUG_ON(VMALLOC_END < PAGE_OFFSET);
> >+ BUG_ON(VMALLOC_END < (unsigned long)high_memory);
> >+#endif
> >+ BUILD_BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) < PAGE_OFFSET);
> >+ BUG_ON((PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE) <
> >+ (unsigned long)high_memory);
> >+ BUILD_BUG_ON(FIXADDR_TOP < PAGE_OFFSET);
> >+ BUG_ON(FIXADDR_TOP < (unsigned long)high_memory);
> >+}
> >+#undef MLK
> >+#undef MLM
> >+#undef MLK_ROUNDUP
> >+
> >+/*
> > * Not static inline because used by IP27 special magic initialization code
> > */
> > void setup_zero_pages(void)
> >@@ -492,6 +536,9 @@ void __init mem_init(void)
> > /* Free highmemory registered in memblocks */
> > mem_init_free_highmem();
> >+ /* Print out kernel memory layout */
> >+ mem_print_kmap_info();
> >+
> > /* Print out memory areas statistics */
> > mem_init_print_info(NULL);
>
Hi Matt,
On Mon, Dec 19, 2016 at 12:04:54PM +0000, Matt Redfearn wrote:
> On 19/12/16 02:07, Serge Semin wrote:
> > It's useful to have some printed map of the kernel virtual memory,
> > at least for debugging purpose.
> >
> > Signed-off-by: Serge Semin <[email protected]>
> > ---
> > @@ -106,6 +107,49 @@ static void __init zone_sizes_init(void)
> > }
> >
> > /*
> > + * Print out kernel memory layout
> > + */
> > +#define MLK(b, t) b, t, ((t) - (b)) >> 10
> > +#define MLM(b, t) b, t, ((t) - (b)) >> 20
> > +#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
> > +static void __init mem_print_kmap_info(void)
> > +{
> > + pr_notice("Virtual kernel memory layout:\n"
> > + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
> > + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
> > +#ifdef CONFIG_HIGHMEM
> > + " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
> > +#endif
> > + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
> > + " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
> > + " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
> > + " .init : 0x%p" " - 0x%p" " (%4td kB)\n",
> > + MLM(PAGE_OFFSET, (unsigned long)high_memory),
> > + MLM(VMALLOC_START, VMALLOC_END),
> > +#ifdef CONFIG_HIGHMEM
> > + MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE)),
> > +#endif
> > + MLK(FIXADDR_START, FIXADDR_TOP),
> > + MLK_ROUNDUP(_text, _etext),
> > + MLK_ROUNDUP(_sdata, _edata),
> > + MLK_ROUNDUP(__init_begin, __init_end));
>
> Please drop printing the kernel addresses, or at least only do it if
> KASLR is not turned on, otherwise you're removing the advantage of
> KASLR, that critical kernel addresses cannot be determined easily from
> userspace.
According to Documentation/printk-formats.txt, this is what %pK is for.
Better to use that instead?
Cheers
James
>
> It may be better to merge the functionality of show_kernel_relocation
> http://lxr.free-electrons.com/source/arch/mips/kernel/relocate.c#L354
> into this function, but only print it under the same conditions as
> currently, i.e.
> #if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
> http://lxr.free-electrons.com/source/arch/mips/kernel/setup.c#L530
>
> Thanks,
> Matt
On Mon, Dec 19, 2016 at 01:02:37PM +0000, James Hogan <[email protected]> wrote:
> Hi Matt,
>
> On Mon, Dec 19, 2016 at 12:04:54PM +0000, Matt Redfearn wrote:
> > On 19/12/16 02:07, Serge Semin wrote:
> > > It's useful to have some printed map of the kernel virtual memory,
> > > at least for debugging purpose.
> > >
> > > Signed-off-by: Serge Semin <[email protected]>
> > > ---
>
> > > @@ -106,6 +107,49 @@ static void __init zone_sizes_init(void)
> > > }
> > >
> > > /*
> > > + * Print out kernel memory layout
> > > + */
> > > +#define MLK(b, t) b, t, ((t) - (b)) >> 10
> > > +#define MLM(b, t) b, t, ((t) - (b)) >> 20
> > > +#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
> > > +static void __init mem_print_kmap_info(void)
> > > +{
> > > + pr_notice("Virtual kernel memory layout:\n"
> > > + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
> > > + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
> > > +#ifdef CONFIG_HIGHMEM
> > > + " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
> > > +#endif
> > > + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
> > > + " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
> > > + " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
> > > + " .init : 0x%p" " - 0x%p" " (%4td kB)\n",
> > > + MLM(PAGE_OFFSET, (unsigned long)high_memory),
> > > + MLM(VMALLOC_START, VMALLOC_END),
> > > +#ifdef CONFIG_HIGHMEM
> > > + MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP)*(PAGE_SIZE)),
> > > +#endif
> > > + MLK(FIXADDR_START, FIXADDR_TOP),
> > > + MLK_ROUNDUP(_text, _etext),
> > > + MLK_ROUNDUP(_sdata, _edata),
> > > + MLK_ROUNDUP(__init_begin, __init_end));
> >
> > Please drop printing the kernel addresses, or at least only do it if
> > KASLR is not turned on, otherwise you're removing the advantage of
> > KASLR, that critical kernel addresses cannot be determined easily from
> > userspace.
>
> According to Documentation/printk-formats.txt, this is what %pK is for.
> Better to use that instead?
>
> Cheers
> James
>
The function is called from the kernel directly, which is privileged
enough to do the printing. So I suppose Matt is right, to hide this
prints out unless debug is enabled.
Thanks,
-Sergey
> >
> > It may be better to merge the functionality of show_kernel_relocation
> > http://lxr.free-electrons.com/source/arch/mips/kernel/relocate.c#L354
> > into this function, but only print it under the same conditions as
> > currently, i.e.
> > #if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
> > http://lxr.free-electrons.com/source/arch/mips/kernel/setup.c#L530
> >
> > Thanks,
> > Matt
On Sun, Dec 18, 2016 at 8:07 PM, Serge Semin <[email protected]> wrote:
> It's necessary to check whether retrieved from dts memory regions
> fits to page alignment and limits restrictions. Sometimes it is
> necessary to perform the same checks, but ito add the memory regions
s/ito/to/
> into a different subsystem. MIPS is going to be that case.
>
> Signed-off-by: Serge Semin <[email protected]>
> ---
> drivers/of/fdt.c | 47 +++++++++++++++++++++++---------
> include/linux/of_fdt.h | 1 +
> 2 files changed, 35 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> index 1f98156..1ee958f 100644
> --- a/drivers/of/fdt.c
> +++ b/drivers/of/fdt.c
> @@ -983,44 +983,65 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
> #define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0)
> #endif
>
> -void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
> +int __init sanity_check_dt_memory(phys_addr_t *out_base,
> + phys_addr_t *out_size)
As kbuild robot found, you don't want to use phys_addr_t here.
phys_addr_t varies with kernel config such as LPAE on ARM and the DT
does not.
> {
> + phys_addr_t base = *out_base, size = *out_size;
> const u64 phys_offset = MIN_MEMBLOCK_ADDR;
>
> if (!PAGE_ALIGNED(base)) {
> if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
> - pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
> + pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
These are not errors. The page alignment is an OS restriction. h/w
(which the DT describes) generally has little concept of page size
outside the MMUs.
Too many unrelated changes in this patch. Add the error return only
and make anything else a separate patch (though I would just drop
everything else).
I've not looked at the rest of the series, but why can't MIPS migrate
to using memblock directly and using the default DT functions using
memblock?
Rob
On Thu, Dec 22, 2016 at 02:57:07PM -0600, Rob Herring <[email protected]> wrote:
> On Sun, Dec 18, 2016 at 8:07 PM, Serge Semin <[email protected]> wrote:
> > It's necessary to check whether retrieved from dts memory regions
> > fits to page alignment and limits restrictions. Sometimes it is
> > necessary to perform the same checks, but ito add the memory regions
>
> s/ito/to/
>
> > into a different subsystem. MIPS is going to be that case.
> >
> > Signed-off-by: Serge Semin <[email protected]>
> > ---
> > drivers/of/fdt.c | 47 +++++++++++++++++++++++---------
> > include/linux/of_fdt.h | 1 +
> > 2 files changed, 35 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> > index 1f98156..1ee958f 100644
> > --- a/drivers/of/fdt.c
> > +++ b/drivers/of/fdt.c
> > @@ -983,44 +983,65 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
> > #define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0)
> > #endif
> >
> > -void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
> > +int __init sanity_check_dt_memory(phys_addr_t *out_base,
> > + phys_addr_t *out_size)
>
> As kbuild robot found, you don't want to use phys_addr_t here.
> phys_addr_t varies with kernel config such as LPAE on ARM and the DT
> does not.
>
Ok, thanks. I'll fix it. I figured it out when got kbuild notification.
> > {
> > + phys_addr_t base = *out_base, size = *out_size;
> > const u64 phys_offset = MIN_MEMBLOCK_ADDR;
> >
> > if (!PAGE_ALIGNED(base)) {
> > if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
> > - pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
> > + pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
>
> These are not errors. The page alignment is an OS restriction. h/w
> (which the DT describes) generally has little concept of page size
> outside the MMUs.
>
Ok. Understood. I'll get back the pr_warn() method call.
> Too many unrelated changes in this patch. Add the error return only
> and make anything else a separate patch (though I would just drop
> everything else).
>
There is no much changes actually. I just unpicked the check function
and switched pr_warn's to pr_error's. Since the last thing is going to
be discarded, then it's not necessary to make any separation.
> I've not looked at the rest of the series, but why can't MIPS migrate
> to using memblock directly and using the default DT functions using
> memblock?
>
> Rob
Of course there is a reason. Otherwise I wouldn't do it.
A lot of platforms dependent code use MIPS-specific boot_mem_map
structure. So in order to prevent a lot of code modifications MIPS
architecture code needs to support that structure as reflection of
available memory regions. For this purpose I've modified
add_memory_region() method (see patch 0003), which adds a passed
memory region to memblock and boot_mem_map simultaneously.
So in order to simplify the MIPS architecture code, I unpicked the
parameters check function from the default
early_init_dt_add_memory_arch() method, and used it in my callback
method together with MIPS-specific add_memory_region().
Another approach would be to leave the early_init_dt_add_memory_arch()
alone with no modification, and add some new MIPS-specific function,
which would be called right after, for instance, plat_mem_setup().
But in this way we can come up with some errors, since we can't be
absolutely sure, that dts memory nodes scan is performed only there.
The method early_init_dt_scan() can be called from some other places
like device_tree_init() or some place else. It can be fixed by moving
early_init_dt_scan() invocations from chip-specific code to MIPS-
architecture code. But in this case We would have to make
modification at __dt_setup_arch(), which is widely used at the
soc-specific code.
Another option would be to leave early_init_dt_add_memory_arch() alone,
but to develop MIPS-specific parameters check function, or just leave
my callback method without it. But in the first case I would duplicate
the code and in the second case it would leave a window for errors,
since it's wrong to have unaligned memory regions. It may lead to
problems with further buddy allocator initialization.
So to speak I've chosen the easiest option of ones I came up to. If
you have any better suggestion, I would gladly get rid of this patch.
The lesser code modifications the better.
-Sergey
On 01/22/2017 11:55 PM, Marcin Nowakowski wrote:
> Hi Serge,
>
> Thanks for this patch series, it's really useful. I've tested it on
> Malta and Ci40 and it seems to work well (I've posted a few small
> comments separately).
I have not tested this yet, but this is definitively a very useful patch
series, thanks a lot for doing this Serge!
One thing that was not obvious to me is that you may have to take care
of the "NOMAP" memblock type and avoid mapping these regions, which may
or may not be relevant on MIPS due to the different virtual memory
model. On ARM it's done in arch/arm/mm/mmu.c::map_lowmem.
Please respin, this is very helpful!
>
>
> On 19.12.2016 03:07, Serge Semin wrote:
>> Most of the modern platforms supported by linux kernel have already
>> been cleaned up of old bootmem allocator by moving to nobootmem
>> interface wrapping up the memblock. This patchset is the first
>> attempt to do the similar improvement for MIPS for UMA systems
>> only.
>>
>> Even though the porting was performed as much careful as possible
>> there still might be problem with support of some platforms,
>> especially Loonson3 or SGI IP27, which perform early memory manager
>> initialization by their self.
>
>> The patchset is split so individual patch being consistent in
>> functional and buildable ways. But the MIPS early memory manager
>> will work correctly only either with or without the whole set being
>> applied. For the same reason a reviewer should not pay much attention
>> to methods bootmem_init(), arch_mem_init(), paging_init() and
>> mem_init() until they are fully refactored.
>
> I'm not sure this can be merged that way? It would be up to Ralf to
> decide, but it is generally expected that all intermediate patches not
> only build, but also work correctly. I understand that this might be
> difficult to achieve given the scale of changes required here.
>
>> The patchset is applied on top of kernel v4.9.
>
> Can you please work on cleaning up the issues discussed in the comments
> so far as well as rebasing (and updating) the changes onto linux-next?
> There are a few patches I made related to kexec and kernel relocation
> that will force changes in your code (although I admit that the changes
> I did for kexec/relocation were in some places unnecessarily complex
> because of the mess in the bootmem handling in MIPS that you are now
> trying to clean up).
>
>
> Thanks,
> Marcin
>
>> Signed-off-by: Serge Semin <[email protected]>
>>
>> Serge Semin (21):
>> MIPS memblock: Unpin dts memblock sanity check method
>> MIPS memblock: Add dts mem and reserved-mem callbacks
>> MIPS memblock: Alter traditional add_memory_region() method
>> MIPS memblock: Alter user-defined memory parameter parser
>> MIPS memblock: Alter initrd memory reservation method
>> MIPS memblock: Alter kexec-crashkernel parameters parser
>> MIPS memblock: Alter elfcorehdr parameters parser
>> MIPS memblock: Move kernel parameters parser into individual method
>> MIPS memblock: Move kernel memory reservation to individual method
>> MIPS memblock: Discard bootmem allocator initialization
>> MIPS memblock: Add memblock sanity check method
>> MIPS memblock: Add memblock print outs in debug
>> MIPS memblock: Add memblock allocator initialization
>> MIPS memblock: Alter IO resources initialization method
>> MIPS memblock: Alter weakened MAAR initialization method
>> MIPS memblock: Alter paging initialization method
>> MIPS memblock: Alter high memory freeing method
>> MIPS memblock: Slightly improve buddy allocator init method
>> MIPS memblock: Add print out method of kernel virtual memory layout
>> MIPS memblock: Add free low memory test method call
>> MIPS memblock: Deactivate old bootmem allocator
>>
>> arch/mips/Kconfig | 2 +-
>> arch/mips/kernel/prom.c | 32 +-
>> arch/mips/kernel/setup.c | 958 +++++++++++++++--------------
>> arch/mips/mm/init.c | 234 ++++---
>> drivers/of/fdt.c | 47 +-
>> include/linux/of_fdt.h | 1 +
>> 6 files changed, 739 insertions(+), 535 deletions(-)
>>
>
--
Florian