Merge tag 'cris-for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jesper...
[cascardo/linux.git] / arch / arm64 / kernel / head.S
index 3e7b050..427f6d3 100644 (file)
@@ -208,13 +208,23 @@ efi_header_end:
 
        __INIT
 
+       /*
+        * The following callee saved general purpose registers are used on the
+        * primary lowlevel boot path:
+        *
+        *  Register   Scope                      Purpose
+        *  x21        stext() .. start_kernel()  FDT pointer passed at boot in x0
+        *  x23        stext() .. start_kernel()  physical misalignment/KASLR offset
+        *  x28        __create_page_tables()     callee preserved temp register
+        *  x19/x20    __primary_switch()         callee preserved temp registers
+        */
 ENTRY(stext)
        bl      preserve_boot_args
-       bl      el2_setup                       // Drop to EL1, w20=cpu_boot_mode
-       adrp    x24, __PHYS_OFFSET
-       and     x23, x24, MIN_KIMG_ALIGN - 1    // KASLR offset, defaults to 0
+       bl      el2_setup                       // Drop to EL1, w0=cpu_boot_mode
+       adrp    x23, __PHYS_OFFSET
+       and     x23, x23, MIN_KIMG_ALIGN - 1    // KASLR offset, defaults to 0
        bl      set_cpu_boot_mode_flag
-       bl      __create_page_tables            // x25=TTBR0, x26=TTBR1
+       bl      __create_page_tables
        /*
         * The following calls CPU setup code, see arch/arm64/mm/proc.S for
         * details.
@@ -222,9 +232,7 @@ ENTRY(stext)
         * the TCR will have been set.
         */
        bl      __cpu_setup                     // initialise processor
-       adr_l   x27, __primary_switch           // address to jump to after
-                                               // MMU has been enabled
-       b       __enable_mmu
+       b       __primary_switch
 ENDPROC(stext)
 
 /*
@@ -311,23 +319,21 @@ ENDPROC(preserve_boot_args)
  *     been enabled
  */
 __create_page_tables:
-       adrp    x25, idmap_pg_dir
-       adrp    x26, swapper_pg_dir
        mov     x28, lr
 
        /*
         * Invalidate the idmap and swapper page tables to avoid potential
         * dirty cache lines being evicted.
         */
-       mov     x0, x25
-       add     x1, x26, #SWAPPER_DIR_SIZE
+       adrp    x0, idmap_pg_dir
+       adrp    x1, swapper_pg_dir + SWAPPER_DIR_SIZE
        bl      __inval_cache_range
 
        /*
         * Clear the idmap and swapper page tables.
         */
-       mov     x0, x25
-       add     x6, x26, #SWAPPER_DIR_SIZE
+       adrp    x0, idmap_pg_dir
+       adrp    x6, swapper_pg_dir + SWAPPER_DIR_SIZE
 1:     stp     xzr, xzr, [x0], #16
        stp     xzr, xzr, [x0], #16
        stp     xzr, xzr, [x0], #16
@@ -340,7 +346,7 @@ __create_page_tables:
        /*
         * Create the identity mapping.
         */
-       mov     x0, x25                         // idmap_pg_dir
+       adrp    x0, idmap_pg_dir
        adrp    x3, __idmap_text_start          // __pa(__idmap_text_start)
 
 #ifndef CONFIG_ARM64_VA_BITS_48
@@ -390,7 +396,7 @@ __create_page_tables:
        /*
         * Map the kernel image (starting with PHYS_OFFSET).
         */
-       mov     x0, x26                         // swapper_pg_dir
+       adrp    x0, swapper_pg_dir
        mov_q   x5, KIMAGE_VADDR + TEXT_OFFSET  // compile time __va(_text)
        add     x5, x5, x23                     // add KASLR displacement
        create_pgd_entry x0, x5, x3, x6
@@ -405,8 +411,8 @@ __create_page_tables:
         * accesses (MMU disabled), invalidate the idmap and swapper page
         * tables again to remove any speculatively loaded cache lines.
         */
-       mov     x0, x25
-       add     x1, x26, #SWAPPER_DIR_SIZE
+       adrp    x0, idmap_pg_dir
+       adrp    x1, swapper_pg_dir + SWAPPER_DIR_SIZE
        dmb     sy
        bl      __inval_cache_range
 
@@ -416,14 +422,27 @@ ENDPROC(__create_page_tables)
 
 /*
  * The following fragment of code is executed with the MMU enabled.
+ *
+ *   x0 = __PHYS_OFFSET
  */
-       .set    initial_sp, init_thread_union + THREAD_START_SP
 __primary_switched:
-       mov     x28, lr                         // preserve LR
+       adrp    x4, init_thread_union
+       add     sp, x4, #THREAD_SIZE
+       msr     sp_el0, x4                      // Save thread_info
+
        adr_l   x8, vectors                     // load VBAR_EL1 with virtual
        msr     vbar_el1, x8                    // vector table address
        isb
 
+       stp     xzr, x30, [sp, #-16]!
+       mov     x29, sp
+
+       str_l   x21, __fdt_pointer, x5          // Save FDT pointer
+
+       ldr_l   x4, kimage_vaddr                // Save the offset between
+       sub     x4, x4, x0                      // the kernel virtual and
+       str_l   x4, kimage_voffset, x5          // physical mappings
+
        // Clear BSS
        adr_l   x0, __bss_start
        mov     x1, xzr
@@ -432,17 +451,6 @@ __primary_switched:
        bl      __pi_memset
        dsb     ishst                           // Make zero page visible to PTW
 
-       adr_l   sp, initial_sp, x4
-       mov     x4, sp
-       and     x4, x4, #~(THREAD_SIZE - 1)
-       msr     sp_el0, x4                      // Save thread_info
-       str_l   x21, __fdt_pointer, x5          // Save FDT pointer
-
-       ldr_l   x4, kimage_vaddr                // Save the offset between
-       sub     x4, x4, x24                     // the kernel virtual and
-       str_l   x4, kimage_voffset, x5          // physical mappings
-
-       mov     x29, #0
 #ifdef CONFIG_KASAN
        bl      kasan_early_init
 #endif
@@ -454,8 +462,8 @@ __primary_switched:
        bl      kaslr_early_init                // parse FDT for KASLR options
        cbz     x0, 0f                          // KASLR disabled? just proceed
        orr     x23, x23, x0                    // record KASLR offset
-       ret     x28                             // we must enable KASLR, return
-                                               // to __enable_mmu()
+       ldp     x29, x30, [sp], #16             // we must enable KASLR, return
+       ret                                     // to __primary_switch()
 0:
 #endif
        b       start_kernel
@@ -465,7 +473,7 @@ ENDPROC(__primary_switched)
  * end early head section, begin head code that is also used for
  * hotplug and needs to have the same protections as the text region
  */
-       .section ".text","ax"
+       .section ".idmap.text","ax"
 
 ENTRY(kimage_vaddr)
        .quad           _text - TEXT_OFFSET
@@ -490,7 +498,7 @@ CPU_LE(     bic     x0, x0, #(1 << 25)      )       // Clear the EE bit for EL2
 CPU_BE(        orr     x0, x0, #(3 << 24)      )       // Set the EE and E0E bits for EL1
 CPU_LE(        bic     x0, x0, #(3 << 24)      )       // Clear the EE and E0E bits for EL1
        msr     sctlr_el1, x0
-       mov     w20, #BOOT_CPU_MODE_EL1         // This cpu booted in EL1
+       mov     w0, #BOOT_CPU_MODE_EL1          // This cpu booted in EL1
        isb
        ret
 
@@ -586,7 +594,7 @@ CPU_LE(     movk    x0, #0x30d0, lsl #16    )       // Clear EE and E0E on LE systems
 
        cbz     x2, install_el2_stub
 
-       mov     w20, #BOOT_CPU_MODE_EL2         // This CPU booted in EL2
+       mov     w0, #BOOT_CPU_MODE_EL2          // This CPU booted in EL2
        isb
        ret
 
@@ -601,7 +609,7 @@ install_el2_stub:
                      PSR_MODE_EL1h)
        msr     spsr_el2, x0
        msr     elr_el2, lr
-       mov     w20, #BOOT_CPU_MODE_EL2         // This CPU booted in EL2
+       mov     w0, #BOOT_CPU_MODE_EL2          // This CPU booted in EL2
        eret
 ENDPROC(el2_setup)
 
@@ -611,15 +619,22 @@ ENDPROC(el2_setup)
  */
 set_cpu_boot_mode_flag:
        adr_l   x1, __boot_cpu_mode
-       cmp     w20, #BOOT_CPU_MODE_EL2
+       cmp     w0, #BOOT_CPU_MODE_EL2
        b.ne    1f
        add     x1, x1, #4
-1:     str     w20, [x1]                       // This CPU has booted in EL1
+1:     str     w0, [x1]                        // This CPU has booted in EL1
        dmb     sy
        dc      ivac, x1                        // Invalidate potentially stale cache line
        ret
 ENDPROC(set_cpu_boot_mode_flag)
 
+/*
+ * These values are written with the MMU off, but read with the MMU on.
+ * Writers will invalidate the corresponding address, discarding up to a
+ * 'Cache Writeback Granule' (CWG) worth of data. The linker script ensures
+ * sufficient alignment that the CWG doesn't overlap another section.
+ */
+       .pushsection ".mmuoff.data.write", "aw"
 /*
  * We need to find out the CPU boot mode long after boot, so we need to
  * store it in a writable variable.
@@ -627,11 +642,16 @@ ENDPROC(set_cpu_boot_mode_flag)
  * This is not in .bss, because we set it sufficiently early that the boot-time
  * zeroing of .bss would clobber it.
  */
-       .pushsection    .data..cacheline_aligned
-       .align  L1_CACHE_SHIFT
 ENTRY(__boot_cpu_mode)
        .long   BOOT_CPU_MODE_EL2
        .long   BOOT_CPU_MODE_EL1
+/*
+ * The booting CPU updates the failed status @__early_cpu_boot_status,
+ * with MMU turned off.
+ */
+ENTRY(__early_cpu_boot_status)
+       .long   0
+
        .popsection
 
        /*
@@ -639,7 +659,7 @@ ENTRY(__boot_cpu_mode)
         * cores are held until we're ready for them to initialise.
         */
 ENTRY(secondary_holding_pen)
-       bl      el2_setup                       // Drop to EL1, w20=cpu_boot_mode
+       bl      el2_setup                       // Drop to EL1, w0=cpu_boot_mode
        bl      set_cpu_boot_mode_flag
        mrs     x0, mpidr_el1
        mov_q   x1, MPIDR_HWID_BITMASK
@@ -666,12 +686,10 @@ secondary_startup:
        /*
         * Common entry point for secondary CPUs.
         */
-       adrp    x25, idmap_pg_dir
-       adrp    x26, swapper_pg_dir
        bl      __cpu_setup                     // initialise processor
-
-       adr_l   x27, __secondary_switch         // address to jump to after enabling the MMU
-       b       __enable_mmu
+       bl      __enable_mmu
+       ldr     x8, =__secondary_switched
+       br      x8
 ENDPROC(secondary_startup)
 
 __secondary_switched:
@@ -706,33 +724,27 @@ ENDPROC(__secondary_switched)
        dc      ivac, \tmp1                     // Invalidate potentially stale cache line
        .endm
 
-       .pushsection    .data..cacheline_aligned
-       .align  L1_CACHE_SHIFT
-ENTRY(__early_cpu_boot_status)
-       .long   0
-       .popsection
-
 /*
  * Enable the MMU.
  *
  *  x0  = SCTLR_EL1 value for turning on the MMU.
- *  x27 = *virtual* address to jump to upon completion
  *
- * Other registers depend on the function called upon completion.
+ * Returns to the caller via x30/lr. This requires the caller to be covered
+ * by the .idmap.text section.
  *
  * Checks if the selected granule size is supported by the CPU.
  * If it isn't, park the CPU
  */
-       .section        ".idmap.text", "ax"
 ENTRY(__enable_mmu)
-       mrs     x22, sctlr_el1                  // preserve old SCTLR_EL1 value
        mrs     x1, ID_AA64MMFR0_EL1
        ubfx    x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4
        cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
        b.ne    __no_granule_support
        update_early_cpu_boot_status 0, x1, x2
-       msr     ttbr0_el1, x25                  // load TTBR0
-       msr     ttbr1_el1, x26                  // load TTBR1
+       adrp    x1, idmap_pg_dir
+       adrp    x2, swapper_pg_dir
+       msr     ttbr0_el1, x1                   // load TTBR0
+       msr     ttbr1_el1, x2                   // load TTBR1
        isb
        msr     sctlr_el1, x0
        isb
@@ -744,29 +756,7 @@ ENTRY(__enable_mmu)
        ic      iallu
        dsb     nsh
        isb
-#ifdef CONFIG_RANDOMIZE_BASE
-       mov     x19, x0                         // preserve new SCTLR_EL1 value
-       blr     x27
-
-       /*
-        * If we return here, we have a KASLR displacement in x23 which we need
-        * to take into account by discarding the current kernel mapping and
-        * creating a new one.
-        */
-       msr     sctlr_el1, x22                  // disable the MMU
-       isb
-       bl      __create_page_tables            // recreate kernel mapping
-
-       tlbi    vmalle1                         // Remove any stale TLB entries
-       dsb     nsh
-
-       msr     sctlr_el1, x19                  // re-enable the MMU
-       isb
-       ic      iallu                           // flush instructions fetched
-       dsb     nsh                             // via old mapping
-       isb
-#endif
-       br      x27
+       ret
 ENDPROC(__enable_mmu)
 
 __no_granule_support:
@@ -775,11 +765,11 @@ __no_granule_support:
 1:
        wfe
        wfi
-       b 1b
+       b       1b
 ENDPROC(__no_granule_support)
 
-__primary_switch:
 #ifdef CONFIG_RELOCATABLE
+__relocate_kernel:
        /*
         * Iterate over each entry in the relocation table, and apply the
         * relocations in place.
@@ -801,14 +791,46 @@ __primary_switch:
        add     x13, x13, x23                   // relocate
        str     x13, [x11, x23]
        b       0b
+1:     ret
+ENDPROC(__relocate_kernel)
+#endif
 
-1:
+__primary_switch:
+#ifdef CONFIG_RANDOMIZE_BASE
+       mov     x19, x0                         // preserve new SCTLR_EL1 value
+       mrs     x20, sctlr_el1                  // preserve old SCTLR_EL1 value
 #endif
+
+       bl      __enable_mmu
+#ifdef CONFIG_RELOCATABLE
+       bl      __relocate_kernel
+#ifdef CONFIG_RANDOMIZE_BASE
        ldr     x8, =__primary_switched
-       br      x8
-ENDPROC(__primary_switch)
+       adrp    x0, __PHYS_OFFSET
+       blr     x8
 
-__secondary_switch:
-       ldr     x8, =__secondary_switched
+       /*
+        * If we return here, we have a KASLR displacement in x23 which we need
+        * to take into account by discarding the current kernel mapping and
+        * creating a new one.
+        */
+       msr     sctlr_el1, x20                  // disable the MMU
+       isb
+       bl      __create_page_tables            // recreate kernel mapping
+
+       tlbi    vmalle1                         // Remove any stale TLB entries
+       dsb     nsh
+
+       msr     sctlr_el1, x19                  // re-enable the MMU
+       isb
+       ic      iallu                           // flush instructions fetched
+       dsb     nsh                             // via old mapping
+       isb
+
+       bl      __relocate_kernel
+#endif
+#endif
+       ldr     x8, =__primary_switched
+       adrp    x0, __PHYS_OFFSET
        br      x8
-ENDPROC(__secondary_switch)
+ENDPROC(__primary_switch)