Skip to content

Commit c6bfaa0

Browse files
arm64bsfrothwell
authored andcommitted
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>
1 parent cb0c54f commit c6bfaa0

File tree

2 files changed

+53
-5
lines changed

2 files changed

+53
-5
lines changed

include/linux/memblock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ phys_addr_t memblock_mem_size(unsigned long limit_pfn);
332332
phys_addr_t memblock_start_of_DRAM(void);
333333
phys_addr_t memblock_end_of_DRAM(void);
334334
void memblock_enforce_memory_limit(phys_addr_t memory_limit);
335+
void memblock_mem_limit_remove_map(phys_addr_t limit);
335336
bool memblock_is_memory(phys_addr_t addr);
336337
int memblock_is_map_memory(phys_addr_t addr);
337338
int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);

mm/memblock.c

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,15 +1465,16 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void)
14651465
return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
14661466
}
14671467

1468-
void __init memblock_enforce_memory_limit(phys_addr_t limit)
1468+
static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit)
14691469
{
14701470
phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
14711471
struct memblock_region *r;
14721472

1473-
if (!limit)
1474-
return;
1475-
1476-
/* find out max address */
1473+
/*
1474+
* translate the memory @limit size into the max address within one of
1475+
* the memory memblock regions, if the @limit exceeds the total size
1476+
* of those regions, max_addr will keep original value ULLONG_MAX
1477+
*/
14771478
for_each_memblock(memory, r) {
14781479
if (limit <= r->size) {
14791480
max_addr = r->base + limit;
@@ -1482,13 +1483,59 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
14821483
limit -= r->size;
14831484
}
14841485

1486+
return max_addr;
1487+
}
1488+
1489+
void __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+
14851502
/* truncate both memory and reserved regions */
14861503
memblock_remove_range(&memblock.memory, max_addr,
14871504
(phys_addr_t)ULLONG_MAX);
14881505
memblock_remove_range(&memblock.reserved, max_addr,
14891506
(phys_addr_t)ULLONG_MAX);
14901507
}
14911508

1509+
void __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+
14921539
static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
14931540
{
14941541
unsigned int left = 0, right = type->cnt;

0 commit comments

Comments
 (0)