Commit d9b5b658 authored by Marcin Nowakowski's avatar Marcin Nowakowski Committed by Ralf Baechle

MIPS: init: Ensure bootmem does not corrupt reserved memory

Current init code initialises bootmem allocator with all of the low
memory that it assumes is available, but does not check for reserved
memory block, which can lead to corruption of data that may be stored
there.
Move bootmem's allocation map to a location that does not cross any
reserved regions
Signed-off-by: default avatarMarcin Nowakowski <marcin.nowakowski@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/14609/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent e89ef66d
...@@ -153,6 +153,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add ...@@ -153,6 +153,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
add_memory_region(start, size, BOOT_MEM_RAM); add_memory_region(start, size, BOOT_MEM_RAM);
} }
bool __init memory_region_available(phys_addr_t start, phys_addr_t size)
{
int i;
bool in_ram = false, free = true;
for (i = 0; i < boot_mem_map.nr_map; i++) {
phys_addr_t start_, end_;
start_ = boot_mem_map.map[i].addr;
end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
if (start >= start_ && start + size <= end_)
in_ram = true;
break;
case BOOT_MEM_RESERVED:
if ((start >= start_ && start < end_) ||
(start < start_ && start + size >= start_))
free = false;
break;
default:
continue;
}
}
return in_ram && free;
}
static void __init print_memory_map(void) static void __init print_memory_map(void)
{ {
int i; int i;
...@@ -332,11 +361,19 @@ static void __init bootmem_init(void) ...@@ -332,11 +361,19 @@ static void __init bootmem_init(void)
#else /* !CONFIG_SGI_IP27 */ #else /* !CONFIG_SGI_IP27 */
static unsigned long __init bootmap_bytes(unsigned long pages)
{
unsigned long bytes = DIV_ROUND_UP(pages, 8);
return ALIGN(bytes, sizeof(long));
}
static void __init bootmem_init(void) static void __init bootmem_init(void)
{ {
unsigned long reserved_end; unsigned long reserved_end;
unsigned long mapstart = ~0UL; unsigned long mapstart = ~0UL;
unsigned long bootmap_size; unsigned long bootmap_size;
bool bootmap_valid = false;
int i; int i;
/* /*
...@@ -430,11 +467,42 @@ static void __init bootmem_init(void) ...@@ -430,11 +467,42 @@ static void __init bootmem_init(void)
#endif #endif
/* /*
* Initialize the boot-time allocator with low memory only. * check that mapstart doesn't overlap with any of
* memory regions that have been reserved through eg. DTB
*/ */
bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart, bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn);
min_low_pfn, max_low_pfn);
bootmap_valid = memory_region_available(PFN_PHYS(mapstart),
bootmap_size);
for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) {
unsigned long mapstart_addr;
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RESERVED:
mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr +
boot_mem_map.map[i].size);
if (PHYS_PFN(mapstart_addr) < mapstart)
break;
bootmap_valid = memory_region_available(mapstart_addr,
bootmap_size);
if (bootmap_valid)
mapstart = PHYS_PFN(mapstart_addr);
break;
default:
break;
}
}
if (!bootmap_valid)
panic("No memory area to place a bootmap bitmap");
/*
* Initialize the boot-time allocator with low memory only.
*/
if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart,
min_low_pfn, max_low_pfn))
panic("Unexpected memory size required for bootmap");
for (i = 0; i < boot_mem_map.nr_map; i++) { for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end; unsigned long start, end;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment