# 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
#     ...
#     [<c038c830>] (__lock_acquire) from [<c038e4f8>] (lock_acquire+0x6c/0x88)
#     [<c038e4f8>] (lock_acquire) from [<c0c06134>] (_raw_spin_lock+0x2c/0x3c)
#     [<c0c06134>] (_raw_spin_lock) from [<c0410384>] (apply_to_page_range+0xe8/0x238)
#     [<c0410384>] (apply_to_page_range) from [<c1205f34>] (efi_set_mapping_permissions+0x54/0x5c)
#     [<c1205f34>] (efi_set_mapping_permissions) from [<c1247474>] (efi_memattr_apply_permissions+0x2b8/0x378)
#     [<c1247474>] (efi_memattr_apply_permissions) from [<c1248258>] (arm_enable_runtime_services+0x1f0/0x22c)
#     [<c1248258>] (arm_enable_runtime_services) from [<c0301f0c>] (do_one_initcall+0x44/0x174)
#     [<c0301f0c>] (do_one_initcall) from [<c1200d10>] (kernel_init_freeable+0x90/0x1e8)
#     [<c1200d10>] (kernel_init_freeable) from [<c0bff690>] (kernel_init+0x8/0x114)
#     [<c0bff690>] (kernel_init) from [<c0307ed0>] (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;
 			}
 		}
