Skip to content

Commit 520bf99

Browse files
arm64bAKASHI Takahiro
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> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent a88cf70 commit 520bf99

2 files changed

Lines changed: 53 additions & 5 deletions

File tree

include/linux/memblock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ phys_addr_t memblock_mem_size(unsigned long limit_pfn);
325325
phys_addr_t memblock_start_of_DRAM(void);
326326
phys_addr_t memblock_end_of_DRAM(void);
327327
void memblock_enforce_memory_limit(phys_addr_t memory_limit);
328+
void memblock_mem_limit_remove_map(phys_addr_t limit);
328329
bool memblock_is_memory(phys_addr_t addr);
329330
int memblock_is_map_memory(phys_addr_t addr);
330331
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
@@ -1486,15 +1486,16 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void)
14861486
return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
14871487
}
14881488

1489-
void __init memblock_enforce_memory_limit(phys_addr_t limit)
1489+
static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit)
14901490
{
14911491
phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
14921492
struct memblock_region *r;
14931493

1494-
if (!limit)
1495-
return;
1496-
1497-
/* find out max address */
1494+
/*
1495+
* translate the memory @limit size into the max address within one of
1496+
* the memory memblock regions, if the @limit exceeds the total size
1497+
* of those regions, max_addr will keep original value ULLONG_MAX
1498+
*/
14981499
for_each_memblock(memory, r) {
14991500
if (limit <= r->size) {
15001501
max_addr = r->base + limit;
@@ -1503,13 +1504,59 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
15031504
limit -= r->size;
15041505
}
15051506

1507+
return max_addr;
1508+
}
1509+
1510+
void __init memblock_enforce_memory_limit(phys_addr_t limit)
1511+
{
1512+
phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
1513+
1514+
if (!limit)
1515+
return;
1516+
1517+
max_addr = __find_max_addr(limit);
1518+
1519+
/* @limit exceeds the total size of the memory, do nothing */
1520+
if (max_addr == (phys_addr_t)ULLONG_MAX)
1521+
return;
1522+
15061523
/* truncate both memory and reserved regions */
15071524
memblock_remove_range(&memblock.memory, max_addr,
15081525
(phys_addr_t)ULLONG_MAX);
15091526
memblock_remove_range(&memblock.reserved, max_addr,
15101527
(phys_addr_t)ULLONG_MAX);
15111528
}
15121529

1530+
void __init memblock_mem_limit_remove_map(phys_addr_t limit)
1531+
{
1532+
struct memblock_type *type = &memblock.memory;
1533+
phys_addr_t max_addr;
1534+
int i, ret, start_rgn, end_rgn;
1535+
1536+
if (!limit)
1537+
return;
1538+
1539+
max_addr = __find_max_addr(limit);
1540+
1541+
/* @limit exceeds the total size of the memory, do nothing */
1542+
if (max_addr == (phys_addr_t)ULLONG_MAX)
1543+
return;
1544+
1545+
ret = memblock_isolate_range(type, max_addr, (phys_addr_t)ULLONG_MAX,
1546+
&start_rgn, &end_rgn);
1547+
if (ret)
1548+
return;
1549+
1550+
/* remove all the MAP regions above the limit */
1551+
for (i = end_rgn - 1; i >= start_rgn; i--) {
1552+
if (!memblock_is_nomap(&type->regions[i]))
1553+
memblock_remove_region(type, i);
1554+
}
1555+
/* truncate the reserved regions */
1556+
memblock_remove_range(&memblock.reserved, max_addr,
1557+
(phys_addr_t)ULLONG_MAX);
1558+
}
1559+
15131560
static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
15141561
{
15151562
unsigned int left = 0, right = type->cnt;

0 commit comments

Comments
 (0)