diff options
author | Nicolas Pitre <nicolas.pitre@linaro.org> | 2016-07-28 14:38:07 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2016-08-09 17:57:40 -0400 |
commit | b9a019899f61acca18df5fb5e38a8fcdfea86fcd (patch) | |
tree | b82cffdfbc870cf30555cfe57459559d62a60eee | |
parent | 29b4817d4018df78086157ea3a55c1d9424a7cfc (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.c | 18 |
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 | } |