# Base git commit: 29b4817d4018 # (Linux 4.8-rc1) # # Author: Russell King (Wed 3 Aug 10:33:35 BST 2016) # Committer: Russell King (Tue 9 Aug 22:57:59 BST 2016) # # ARM: fix address limit restoration for undefined instructions # # During boot, sometimes the kernel will test to see if an instruction # causes an undefined instruction exception. Unfortunately, the exit # path for these exceptions did not restore the address limit, which # causes the rootfs mount code to fail. Fix the missing address limit # restoration. # # Tested-by: Guenter Roeck # Signed-off-by: Russell King # # 87eed3c74d7c65556f744230a90bf9556dd29146 # arch/arm/kernel/entry-armv.S | 1 + # 1 file changed, 1 insertion(+) # # Author: Ard Biesheuvel (Thu 28 Jul 19:48:44 BST 2016) # Committer: Russell King (Tue 9 Aug 22:57:41 BST 2016) # # ARM: 8591/1: mm: use fully constructed struct pages for EFI pgd allocations # # The late_alloc() PTE allocation function used by create_mapping_late() # does not call pgtable_page_ctor() on PTE pages it allocates, leaving # the per-page spinlock uninitialized. # # Since generic page table manipulation code may assume that translation # table pages that are not owned by init_mm are covered by fully # constructed struct pages, the following crash may occur with the new # UEFI memory attributes table code. # # efi: memattr: Processing EFI Memory Attributes table: # efi: memattr: 0x0000ffa16000-0x0000ffa82fff [Runtime Code |RUN| | |XP| | | | | | | | ] # Unable to handle kernel NULL pointer dereference at virtual address 00000010 # pgd = c0204000 # [00000010] *pgd=00000000 # Internal error: Oops: 5 [#1] SMP ARM # Modules linked in: # CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.7.0-rc4-00063-g3882aa7b340b #361 # Hardware name: Generic DT based system # task: ed858000 ti: ed842000 task.ti: ed842000 # PC is at __lock_acquire+0xa0/0x19a8 # ... # [] (__lock_acquire) from [] (lock_acquire+0x6c/0x88) # [] (lock_acquire) from [] (_raw_spin_lock+0x2c/0x3c) # [] (_raw_spin_lock) from [] (apply_to_page_range+0xe8/0x238) # [] (apply_to_page_range) from [] (efi_set_mapping_permissions+0x54/0x5c) # [] (efi_set_mapping_permissions) from [] (efi_memattr_apply_permissions+0x2b8/0x378) # [] (efi_memattr_apply_permissions) from [] (arm_enable_runtime_services+0x1f0/0x22c) # [] (arm_enable_runtime_services) from [] (do_one_initcall+0x44/0x174) # [] (do_one_initcall) from [] (kernel_init_freeable+0x90/0x1e8) # [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) # [] (kernel_init) from [] (ret_from_fork+0x14/0x24) # # The crash is due to the fact that the UEFI page tables are not owned by # init_mm, but are not covered by fully constructed struct pages. # # Given that the UEFI subsystem is currently the only user of # create_mapping_late(), add an unconditional call to pgtable_page_ctor() to # late_alloc(). # # Fixes: 9fc68b717c24 ("ARM/efi: Apply strict permissions for UEFI Runtime Services regions") # Signed-off-by: Ard Biesheuvel # Signed-off-by: Russell King # # 61444cde9170e256c238a02c9a4861930db04f5f # arch/arm/mm/mmu.c | 3 ++- # 1 file changed, 2 insertions(+), 1 deletion(-) # # Author: Nicolas Pitre (Thu 28 Jul 19:38:07 BST 2016) # Committer: Russell King (Tue 9 Aug 22:57:40 BST 2016) # # 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 # Signed-off-by: Nicolas Pitre # Tested-by: Emil Renner Berthing # Signed-off-by: Russell King # # b9a019899f61acca18df5fb5e38a8fcdfea86fcd # arch/arm/mm/mmu.c | 18 ++++++++++++++---- # 1 file changed, 14 insertions(+), 4 deletions(-) # diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index bc5f50799d75..9f157e7c51e7 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -295,6 +295,7 @@ __und_svc_fault: bl __und_fault __und_svc_finish: + get_thread_info tsk ldr r5, [sp, #S_PSR] @ Get SVC cpsr svc_exit r5 @ return from exception UNWIND(.fnend ) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 62f4d01941f7..6344913f0804 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -728,7 +728,8 @@ static void *__init late_alloc(unsigned long sz) { void *ptr = (void *)__get_free_pages(PGALLOC_GFP, get_order(sz)); - BUG_ON(!ptr); + if (!ptr || !pgtable_page_ctor(virt_to_page(ptr))) + BUG(); return ptr; } @@ -1155,10 +1156,19 @@ void __init sanity_check_meminfo(void) { phys_addr_t memblock_limit = 0; int highmem = 0; - phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1; + u64 vmalloc_limit; struct memblock_region *reg; bool should_use_highmem = false; + /* + * Let's use our own (unoptimized) equivalent of __pa() that is + * not affected by wrap-arounds when sizeof(phys_addr_t) == 4. + * The result is used as the upper bound on physical memory address + * and may itself be outside the valid range for which phys_addr_t + * and therefore __pa() is defined. + */ + vmalloc_limit = (u64)(uintptr_t)vmalloc_min - PAGE_OFFSET + PHYS_OFFSET; + for_each_memblock(memory, reg) { phys_addr_t block_start = reg->base; phys_addr_t block_end = reg->base + reg->size; @@ -1183,10 +1193,11 @@ void __init sanity_check_meminfo(void) if (reg->size > size_limit) { phys_addr_t overlap_size = reg->size - size_limit; - pr_notice("Truncating RAM at %pa-%pa to -%pa", - &block_start, &block_end, &vmalloc_limit); - memblock_remove(vmalloc_limit, overlap_size); + pr_notice("Truncating RAM at %pa-%pa", + &block_start, &block_end); block_end = vmalloc_limit; + pr_cont(" to -%pa", &block_end); + memblock_remove(vmalloc_limit, overlap_size); should_use_highmem = true; } }