arm64: mm: move pgd_cache initialisation to pgtable_cache_init
authorWill Deacon <will.deacon@arm.com>
Tue, 5 Jan 2016 15:36:59 +0000 (15:36 +0000)
committerWill Deacon <will.deacon@arm.com>
Tue, 5 Jan 2016 15:43:10 +0000 (15:43 +0000)
Initialising the suppport for EFI runtime services requires us to
allocate a pgd off the back of an early_initcall. On systems where the
PGD_SIZE is smaller than PAGE_SIZE (e.g. 64k pages and 48-bit VA), the
pgd_cache isn't initialised at this stage, and we panic with a NULL
dereference during boot:

  Unable to handle kernel NULL pointer dereference at virtual address 00000000

  __create_mapping.isra.5+0x84/0x350
  create_pgd_mapping+0x20/0x28
  efi_create_mapping+0x5c/0x6c
  arm_enable_runtime_services+0x154/0x1e4
  do_one_initcall+0x8c/0x190
  kernel_init_freeable+0x84/0x1ec
  kernel_init+0x10/0xe0
  ret_from_fork+0x10/0x50

This patch fixes the problem by initialising the pgd_cache earlier, in
the pgtable_cache_init callback, which sounds suspiciously like what it
was intended for.

Reported-by: Dennis Chen <dennis.chen@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
arch/arm64/include/asm/pgtable.h
arch/arm64/mm/pgd.c

index 35a318c2fd872ab11167fc0c1373704f44657867..a87e964d27916b94e87b5c11dff9f71d82ac1f86 100644 (file)
@@ -676,7 +676,8 @@ extern int kern_addr_valid(unsigned long addr);
 
 #include <asm-generic/pgtable.h>
 
-#define pgtable_cache_init() do { } while (0)
+void pgd_cache_init(void);
+#define pgtable_cache_init     pgd_cache_init
 
 /*
  * On AArch64, the cache coherency is handled via the set_pte_at() function.
index cb3ba1b812e74dcd1acbc167756d60da331d105f..ae11d4e03d0e68d7f0fe621f1c9d313fcab09127 100644 (file)
@@ -46,14 +46,14 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
                kmem_cache_free(pgd_cache, pgd);
 }
 
-static int __init pgd_cache_init(void)
+void __init pgd_cache_init(void)
 {
+       if (PGD_SIZE == PAGE_SIZE)
+               return;
+
        /*
         * Naturally aligned pgds required by the architecture.
         */
-       if (PGD_SIZE != PAGE_SIZE)
-               pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
-                                             SLAB_PANIC, NULL);
-       return 0;
+       pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
+                                     SLAB_PANIC, NULL);
 }
-core_initcall(pgd_cache_init);