aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDennis Chen <dennis.chen@arm.com>2016-07-28 18:48:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-28 19:07:41 -0400
commita571d4eb55d83ff538d98870fa8a8497b24d39bc (patch)
tree84435c6a620b12ebdb3fed0181ff91bc68353e93
parent8b70ca65616b3588ea1907e87f0df6d2530350df (diff)
mm/memblock.c: add new infrastructure to address the mem limit issue
In some cases, memblock is queried by kernel to determine whether a specified address is RAM or not. For example, the ACPI core needs this information to determine which attributes to use when mapping ACPI regions(acpi_os_ioremap). Use of incorrect memory types can result in faults, data corruption, or other issues. Removing memory with memblock_enforce_memory_limit() throws away this information, and so a kernel booted with 'mem=' may suffer from the issues described above. To avoid this, we need to keep those NOMAP regions instead of removing all above the limit, which preserves the information we need while preventing other use of those regions. This patch adds new infrastructure to retain all NOMAP memblock regions while removing others, to cater for this. Link: http://lkml.kernel.org/r/1468475036-5852-2-git-send-email-dennis.chen@arm.com Signed-off-by: Dennis Chen <dennis.chen@arm.com> Acked-by: Steve Capper <steve.capper@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Pekka Enberg <penberg@kernel.org> Cc: Mel Gorman <mgorman@techsingularity.net> Cc: Tang Chen <tangchen@cn.fujitsu.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Rafael J. Wysocki <rafael@kernel.org> Cc: Will Deacon <will.deacon@arm.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Matt Fleming <matt@codeblueprint.co.uk> Cc: Kaly Xin <kaly.xin@arm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/memblock.h1
-rw-r--r--mm/memblock.c57
2 files changed, 53 insertions, 5 deletions
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 6c14b6179727..2925da23505d 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -332,6 +332,7 @@ phys_addr_t memblock_mem_size(unsigned long limit_pfn);
332phys_addr_t memblock_start_of_DRAM(void); 332phys_addr_t memblock_start_of_DRAM(void);
333phys_addr_t memblock_end_of_DRAM(void); 333phys_addr_t memblock_end_of_DRAM(void);
334void memblock_enforce_memory_limit(phys_addr_t memory_limit); 334void memblock_enforce_memory_limit(phys_addr_t memory_limit);
335void memblock_mem_limit_remove_map(phys_addr_t limit);
335bool memblock_is_memory(phys_addr_t addr); 336bool memblock_is_memory(phys_addr_t addr);
336int memblock_is_map_memory(phys_addr_t addr); 337int memblock_is_map_memory(phys_addr_t addr);
337int memblock_is_region_memory(phys_addr_t base, phys_addr_t size); 338int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
diff --git a/mm/memblock.c b/mm/memblock.c
index d8a79dfbf891..4884a162e3ad 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1465,15 +1465,16 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void)
1465 return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size); 1465 return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
1466} 1466}
1467 1467
1468void __init memblock_enforce_memory_limit(phys_addr_t limit) 1468static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit)
1469{ 1469{
1470 phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX; 1470 phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
1471 struct memblock_region *r; 1471 struct memblock_region *r;
1472 1472
1473 if (!limit) 1473 /*
1474 return; 1474 * translate the memory @limit size into the max address within one of
1475 1475 * the memory memblock regions, if the @limit exceeds the total size
1476 /* find out max address */ 1476 * of those regions, max_addr will keep original value ULLONG_MAX
1477 */
1477 for_each_memblock(memory, r) { 1478 for_each_memblock(memory, r) {
1478 if (limit <= r->size) { 1479 if (limit <= r->size) {
1479 max_addr = r->base + limit; 1480 max_addr = r->base + limit;
@@ -1482,6 +1483,22 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
1482 limit -= r->size; 1483 limit -= r->size;
1483 } 1484 }
1484 1485
1486 return max_addr;
1487}
1488
1489void __init memblock_enforce_memory_limit(phys_addr_t limit)
1490{
1491 phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
1492
1493 if (!limit)
1494 return;
1495
1496 max_addr = __find_max_addr(limit);
1497
1498 /* @limit exceeds the total size of the memory, do nothing */
1499 if (max_addr == (phys_addr_t)ULLONG_MAX)
1500 return;
1501
1485 /* truncate both memory and reserved regions */ 1502 /* truncate both memory and reserved regions */
1486 memblock_remove_range(&memblock.memory, max_addr, 1503 memblock_remove_range(&memblock.memory, max_addr,
1487 (phys_addr_t)ULLONG_MAX); 1504 (phys_addr_t)ULLONG_MAX);
@@ -1489,6 +1506,36 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
1489 (phys_addr_t)ULLONG_MAX); 1506 (phys_addr_t)ULLONG_MAX);
1490} 1507}
1491 1508
1509void __init memblock_mem_limit_remove_map(phys_addr_t limit)
1510{
1511 struct memblock_type *type = &memblock.memory;
1512 phys_addr_t max_addr;
1513 int i, ret, start_rgn, end_rgn;
1514
1515 if (!limit)
1516 return;
1517
1518 max_addr = __find_max_addr(limit);
1519
1520 /* @limit exceeds the total size of the memory, do nothing */
1521 if (max_addr == (phys_addr_t)ULLONG_MAX)
1522 return;
1523
1524 ret = memblock_isolate_range(type, max_addr, (phys_addr_t)ULLONG_MAX,
1525 &start_rgn, &end_rgn);
1526 if (ret)
1527 return;
1528
1529 /* remove all the MAP regions above the limit */
1530 for (i = end_rgn - 1; i >= start_rgn; i--) {
1531 if (!memblock_is_nomap(&type->regions[i]))
1532 memblock_remove_region(type, i);
1533 }
1534 /* truncate the reserved regions */
1535 memblock_remove_range(&memblock.reserved, max_addr,
1536 (phys_addr_t)ULLONG_MAX);
1537}
1538
1492static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) 1539static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
1493{ 1540{
1494 unsigned int left = 0, right = type->cnt; 1541 unsigned int left = 0, right = type->cnt;