aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcin Nowakowski <marcin.nowakowski@imgtec.com>2016-11-23 08:43:45 -0500
committerRalf Baechle <ralf@linux-mips.org>2017-01-03 10:34:45 -0500
commitd9b5b658210f28ed9f70c757d553e679d76e2986 (patch)
tree5f12af5404507bbbee0cb5880b21744e2b0d193f
parente89ef66d7682f031f026eee6bba03c8c2248d2a9 (diff)
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: Marcin Nowakowski <marcin.nowakowski@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14609/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/kernel/setup.c74
1 files changed, 71 insertions, 3 deletions
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 8ebad247ce82..64b38d400987 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -153,6 +153,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
153 add_memory_region(start, size, BOOT_MEM_RAM); 153 add_memory_region(start, size, BOOT_MEM_RAM);
154} 154}
155 155
156bool __init memory_region_available(phys_addr_t start, phys_addr_t size)
157{
158 int i;
159 bool in_ram = false, free = true;
160
161 for (i = 0; i < boot_mem_map.nr_map; i++) {
162 phys_addr_t start_, end_;
163
164 start_ = boot_mem_map.map[i].addr;
165 end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
166
167 switch (boot_mem_map.map[i].type) {
168 case BOOT_MEM_RAM:
169 if (start >= start_ && start + size <= end_)
170 in_ram = true;
171 break;
172 case BOOT_MEM_RESERVED:
173 if ((start >= start_ && start < end_) ||
174 (start < start_ && start + size >= start_))
175 free = false;
176 break;
177 default:
178 continue;
179 }
180 }
181
182 return in_ram && free;
183}
184
156static void __init print_memory_map(void) 185static void __init print_memory_map(void)
157{ 186{
158 int i; 187 int i;
@@ -332,11 +361,19 @@ static void __init bootmem_init(void)
332 361
333#else /* !CONFIG_SGI_IP27 */ 362#else /* !CONFIG_SGI_IP27 */
334 363
364static unsigned long __init bootmap_bytes(unsigned long pages)
365{
366 unsigned long bytes = DIV_ROUND_UP(pages, 8);
367
368 return ALIGN(bytes, sizeof(long));
369}
370
335static void __init bootmem_init(void) 371static void __init bootmem_init(void)
336{ 372{
337 unsigned long reserved_end; 373 unsigned long reserved_end;
338 unsigned long mapstart = ~0UL; 374 unsigned long mapstart = ~0UL;
339 unsigned long bootmap_size; 375 unsigned long bootmap_size;
376 bool bootmap_valid = false;
340 int i; 377 int i;
341 378
342 /* 379 /*
@@ -430,11 +467,42 @@ static void __init bootmem_init(void)
430#endif 467#endif
431 468
432 /* 469 /*
433 * Initialize the boot-time allocator with low memory only. 470 * check that mapstart doesn't overlap with any of
471 * memory regions that have been reserved through eg. DTB
434 */ 472 */
435 bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart, 473 bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn);
436 min_low_pfn, max_low_pfn); 474
475 bootmap_valid = memory_region_available(PFN_PHYS(mapstart),
476 bootmap_size);
477 for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) {
478 unsigned long mapstart_addr;
479
480 switch (boot_mem_map.map[i].type) {
481 case BOOT_MEM_RESERVED:
482 mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr +
483 boot_mem_map.map[i].size);
484 if (PHYS_PFN(mapstart_addr) < mapstart)
485 break;
486
487 bootmap_valid = memory_region_available(mapstart_addr,
488 bootmap_size);
489 if (bootmap_valid)
490 mapstart = PHYS_PFN(mapstart_addr);
491 break;
492 default:
493 break;
494 }
495 }
437 496
497 if (!bootmap_valid)
498 panic("No memory area to place a bootmap bitmap");
499
500 /*
501 * Initialize the boot-time allocator with low memory only.
502 */
503 if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart,
504 min_low_pfn, max_low_pfn))
505 panic("Unexpected memory size required for bootmap");
438 506
439 for (i = 0; i < boot_mem_map.nr_map; i++) { 507 for (i = 0; i < boot_mem_map.nr_map; i++) {
440 unsigned long start, end; 508 unsigned long start, end;