aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2016-07-28 14:38:07 -0400
committerRussell King <rmk+kernel@armlinux.org.uk>2016-08-09 17:57:40 -0400
commitb9a019899f61acca18df5fb5e38a8fcdfea86fcd (patch)
treeb82cffdfbc870cf30555cfe57459559d62a60eee
parent29b4817d4018df78086157ea3a55c1d9424a7cfc (diff)
ARM: 8590/1: sanity_check_meminfo(): avoid overflow on vmalloc_limit
To limit the amount of mapped low memory, we determine a physical address boundary based on the start of the vmalloc area using __pa(). Strictly speaking, the vmalloc area location is arbitrary and does not necessarily corresponds to a valid physical address. For example, if PAGE_OFFSET = 0x80000000 PHYS_OFFSET = 0x90000000 vmalloc_min = 0xf0000000 then __pa(vmalloc_min) overflows and returns a wrapped 0 when phys_addr_t is a 32-bit type. Then the code that follows determines that the entire physical memory is above that boundary and no low memory gets mapped at all: |[...] |Machine model: Freescale i.MX51 NA04 Board |Ignoring RAM at 0x90000000-0xb0000000 (!CONFIG_HIGHMEM) |Consider using a HIGHMEM enabled kernel. To avoid this problem let's make vmalloc_limit a 64-bit value all the time and determine that boundary explicitly without using __pa(). Reported-by: Emil Renner Berthing <kernel@esmil.dk> Signed-off-by: Nicolas Pitre <nico@linaro.org> Tested-by: Emil Renner Berthing <kernel@esmil.dk> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mm/mmu.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 62f4d01941f7..12774c8e770c 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1155,10 +1155,19 @@ void __init sanity_check_meminfo(void)
1155{ 1155{
1156 phys_addr_t memblock_limit = 0; 1156 phys_addr_t memblock_limit = 0;
1157 int highmem = 0; 1157 int highmem = 0;
1158 phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1; 1158 u64 vmalloc_limit;
1159 struct memblock_region *reg; 1159 struct memblock_region *reg;
1160 bool should_use_highmem = false; 1160 bool should_use_highmem = false;
1161 1161
1162 /*
1163 * Let's use our own (unoptimized) equivalent of __pa() that is
1164 * not affected by wrap-arounds when sizeof(phys_addr_t) == 4.
1165 * The result is used as the upper bound on physical memory address
1166 * and may itself be outside the valid range for which phys_addr_t
1167 * and therefore __pa() is defined.
1168 */
1169 vmalloc_limit = (u64)(uintptr_t)vmalloc_min - PAGE_OFFSET + PHYS_OFFSET;
1170
1162 for_each_memblock(memory, reg) { 1171 for_each_memblock(memory, reg) {
1163 phys_addr_t block_start = reg->base; 1172 phys_addr_t block_start = reg->base;
1164 phys_addr_t block_end = reg->base + reg->size; 1173 phys_addr_t block_end = reg->base + reg->size;
@@ -1183,10 +1192,11 @@ void __init sanity_check_meminfo(void)
1183 if (reg->size > size_limit) { 1192 if (reg->size > size_limit) {
1184 phys_addr_t overlap_size = reg->size - size_limit; 1193 phys_addr_t overlap_size = reg->size - size_limit;
1185 1194
1186 pr_notice("Truncating RAM at %pa-%pa to -%pa", 1195 pr_notice("Truncating RAM at %pa-%pa",
1187 &block_start, &block_end, &vmalloc_limit); 1196 &block_start, &block_end);
1188 memblock_remove(vmalloc_limit, overlap_size);
1189 block_end = vmalloc_limit; 1197 block_end = vmalloc_limit;
1198 pr_cont(" to -%pa", &block_end);
1199 memblock_remove(vmalloc_limit, overlap_size);
1190 should_use_highmem = true; 1200 should_use_highmem = true;
1191 } 1201 }
1192 } 1202 }