]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/arm64/kernel/entry.S
arm64: Move post_ttbr_update_workaround to C code
[mirror_ubuntu-artful-kernel.git] / arch / arm64 / kernel / entry.S
index 1c2f250613ea1c8d9efe50047271d40a1437012d..fd695e860ecb2370952fd5975faf3a0d10bb277a 100644 (file)
 #define BAD_FIQ                2
 #define BAD_ERROR      3
 
-       .macro kernel_ventry    label
+       .macro kernel_ventry, el, label, regsize = 64
        .align 7
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+alternative_if ARM64_UNMAP_KERNEL_AT_EL0
+       .if     \el == 0
+       .if     \regsize == 64
+       mrs     x30, tpidrro_el0
+       msr     tpidrro_el0, xzr
+       .else
+       mov     x30, xzr
+       .endif
+       .endif
+alternative_else_nop_endif
+#endif
+
        sub     sp, sp, #S_FRAME_SIZE
 #ifdef CONFIG_VMAP_STACK
        /*
@@ -84,7 +97,7 @@
        tbnz    x0, #THREAD_SHIFT, 0f
        sub     x0, sp, x0                      // x0'' = sp' - x0' = (sp + x0) - sp = x0
        sub     sp, sp, x0                      // sp'' = sp' - x0 = (sp + x0) - x0 = sp
-       b       \label
+       b       el\()\el\()_\label
 
 0:
        /*
        sub     sp, sp, x0
        mrs     x0, tpidrro_el0
 #endif
-       b       \label
+       b       el\()\el\()_\label
+       .endm
+
+       .macro tramp_alias, dst, sym
+       mov_q   \dst, TRAMP_VALIAS
+       add     \dst, \dst, #(\sym - .entry.tramp.text)
        .endm
 
        .macro  kernel_entry, el, regsize = 64
        .else
        add     x21, sp, #S_FRAME_SIZE
        get_thread_info tsk
-       /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
+       /* Save the task's original addr_limit and set USER_DS */
        ldr     x20, [tsk, #TSK_TI_ADDR_LIMIT]
        str     x20, [sp, #S_ORIG_ADDR_LIMIT]
-       mov     x20, #TASK_SIZE_64
+       mov     x20, #USER_DS
        str     x20, [tsk, #TSK_TI_ADDR_LIMIT]
        /* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */
        .endif /* \el == 0 */
@@ -186,8 +204,8 @@ alternative_if ARM64_HAS_PAN
 alternative_else_nop_endif
 
        .if     \el != 0
-       mrs     x21, ttbr1_el1
-       tst     x21, #0xffff << 48              // Check for the reserved ASID
+       mrs     x21, ttbr0_el1
+       tst     x21, #TTBR_ASID_MASK            // Check for the reserved ASID
        orr     x23, x23, #PSR_PAN_BIT          // Set the emulated PAN in the saved SPSR
        b.eq    1f                              // TTBR0 access already disabled
        and     x23, x23, #~PSR_PAN_BIT         // Clear the emulated PAN in the saved SPSR
@@ -259,7 +277,7 @@ alternative_else_nop_endif
         * Cavium erratum 27456 (broadcast TLBI instructions may cause I-cache
         * corruption).
         */
-       post_ttbr_update_workaround
+       bl      post_ttbr_update_workaround
        .endif
 1:
        .if     \el != 0
@@ -271,18 +289,20 @@ alternative_else_nop_endif
        .if     \el == 0
        ldr     x23, [sp, #S_SP]                // load return stack pointer
        msr     sp_el0, x23
+       tst     x22, #PSR_MODE32_BIT            // native task?
+       b.eq    3f
+
 #ifdef CONFIG_ARM64_ERRATUM_845719
 alternative_if ARM64_WORKAROUND_845719
-       tbz     x22, #4, 1f
 #ifdef CONFIG_PID_IN_CONTEXTIDR
        mrs     x29, contextidr_el1
        msr     contextidr_el1, x29
 #else
        msr contextidr_el1, xzr
 #endif
-1:
 alternative_else_nop_endif
 #endif
+3:
        .endif
 
        msr     elr_el1, x21                    // set up the return data
@@ -304,7 +324,21 @@ alternative_else_nop_endif
        ldp     x28, x29, [sp, #16 * 14]
        ldr     lr, [sp, #S_LR]
        add     sp, sp, #S_FRAME_SIZE           // restore sp
-       eret                                    // return to kernel
+
+       .if     \el == 0
+alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+       bne     4f
+       msr     far_el1, x30
+       tramp_alias     x30, tramp_exit_native
+       br      x30
+4:
+       tramp_alias     x30, tramp_exit_compat
+       br      x30
+#endif
+       .else
+       eret
+       .endif
        .endm
 
        .macro  irq_stack_entry
@@ -344,6 +378,7 @@ alternative_else_nop_endif
  * x7 is reserved for the system call number in 32-bit mode.
  */
 wsc_nr .req    w25             // number of system calls
+xsc_nr .req    x25             // number of system calls (zero-extended)
 wscno  .req    w26             // syscall number
 xscno  .req    x26             // syscall number (zero-extended)
 stbl   .req    x27             // syscall table pointer
@@ -369,31 +404,31 @@ tsk       .req    x28             // current thread_info
 
        .align  11
 ENTRY(vectors)
-       kernel_ventry   el1_sync_invalid                // Synchronous EL1t
-       kernel_ventry   el1_irq_invalid                 // IRQ EL1t
-       kernel_ventry   el1_fiq_invalid                 // FIQ EL1t
-       kernel_ventry   el1_error_invalid               // Error EL1t
+       kernel_ventry   1, sync_invalid                 // Synchronous EL1t
+       kernel_ventry   1, irq_invalid                  // IRQ EL1t
+       kernel_ventry   1, fiq_invalid                  // FIQ EL1t
+       kernel_ventry   1, error_invalid                // Error EL1t
 
-       kernel_ventry   el1_sync                        // Synchronous EL1h
-       kernel_ventry   el1_irq                         // IRQ EL1h
-       kernel_ventry   el1_fiq_invalid                 // FIQ EL1h
-       kernel_ventry   el1_error_invalid               // Error EL1h
+       kernel_ventry   1, sync                         // Synchronous EL1h
+       kernel_ventry   1, irq                          // IRQ EL1h
+       kernel_ventry   1, fiq_invalid                  // FIQ EL1h
+       kernel_ventry   1, error_invalid                // Error EL1h
 
-       kernel_ventry   el0_sync                        // Synchronous 64-bit EL0
-       kernel_ventry   el0_irq                         // IRQ 64-bit EL0
-       kernel_ventry   el0_fiq_invalid                 // FIQ 64-bit EL0
-       kernel_ventry   el0_error_invalid               // Error 64-bit EL0
+       kernel_ventry   0, sync                         // Synchronous 64-bit EL0
+       kernel_ventry   0, irq                          // IRQ 64-bit EL0
+       kernel_ventry   0, fiq_invalid                  // FIQ 64-bit EL0
+       kernel_ventry   0, error_invalid                // Error 64-bit EL0
 
 #ifdef CONFIG_COMPAT
-       kernel_ventry   el0_sync_compat                 // Synchronous 32-bit EL0
-       kernel_ventry   el0_irq_compat                  // IRQ 32-bit EL0
-       kernel_ventry   el0_fiq_invalid_compat          // FIQ 32-bit EL0
-       kernel_ventry   el0_error_invalid_compat        // Error 32-bit EL0
+       kernel_ventry   0, sync_compat, 32              // Synchronous 32-bit EL0
+       kernel_ventry   0, irq_compat, 32               // IRQ 32-bit EL0
+       kernel_ventry   0, fiq_invalid_compat, 32       // FIQ 32-bit EL0
+       kernel_ventry   0, error_invalid_compat, 32     // Error 32-bit EL0
 #else
-       kernel_ventry   el0_sync_invalid                // Synchronous 32-bit EL0
-       kernel_ventry   el0_irq_invalid                 // IRQ 32-bit EL0
-       kernel_ventry   el0_fiq_invalid                 // FIQ 32-bit EL0
-       kernel_ventry   el0_error_invalid               // Error 32-bit EL0
+       kernel_ventry   0, sync_invalid, 32             // Synchronous 32-bit EL0
+       kernel_ventry   0, irq_invalid, 32              // IRQ 32-bit EL0
+       kernel_ventry   0, fiq_invalid, 32              // FIQ 32-bit EL0
+       kernel_ventry   0, error_invalid, 32            // Error 32-bit EL0
 #endif
 END(vectors)
 
@@ -852,6 +887,7 @@ el0_svc_naked:                                      // compat entry point
        b.ne    __sys_trace
        cmp     wscno, wsc_nr                   // check upper syscall limit
        b.hs    ni_sys
+       mask_nospec64 xscno, xsc_nr, x19        // enforce bounds for syscall number
        ldr     x16, [stbl, xscno, lsl #3]      // address in the syscall table
        blr     x16                             // call sys_* routine
        b       ret_fast_syscall
@@ -910,6 +946,18 @@ __ni_sys_trace:
        sub     \tmp, \tmp, #(SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
        bic     \tmp, \tmp, #USER_ASID_FLAG
        msr     ttbr1_el1, \tmp
+#ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
+alternative_if ARM64_WORKAROUND_QCOM_FALKOR_E1003
+       /* ASID already in \tmp[63:48] */
+       movk    \tmp, #:abs_g2_nc:(TRAMP_VALIAS >> 12)
+       movk    \tmp, #:abs_g1_nc:(TRAMP_VALIAS >> 12)
+       /* 2MB boundary containing the vectors, so we nobble the walk cache */
+       movk    \tmp, #:abs_g0_nc:((TRAMP_VALIAS & ~(SZ_2M - 1)) >> 12)
+       isb
+       tlbi    vae1, \tmp
+       dsb     nsh
+alternative_else_nop_endif
+#endif /* CONFIG_QCOM_FALKOR_ERRATUM_1003 */
        .endm
 
        .macro tramp_unmap_kernel, tmp
@@ -918,16 +966,9 @@ __ni_sys_trace:
        orr     \tmp, \tmp, #USER_ASID_FLAG
        msr     ttbr1_el1, \tmp
        /*
-        * We avoid running the post_ttbr_update_workaround here because the
-        * user and kernel ASIDs don't have conflicting mappings, so any
-        * "blessing" as described in:
-        *
-        *   http://lkml.kernel.org/r/56BB848A.6060603@caviumnetworks.com
-        *
-        * will not hurt correctness. Whilst this may partially defeat the
-        * point of using split ASIDs in the first place, it avoids
-        * the hit of invalidating the entire I-cache on every return to
-        * userspace.
+        * We avoid running the post_ttbr_update_workaround here because
+        * it's only needed by Cavium ThunderX, which requires KPTI to be
+        * disabled.
         */
        .endm
 
@@ -937,13 +978,27 @@ __ni_sys_trace:
        .if     \regsize == 64
        msr     tpidrro_el0, x30        // Restored in kernel_ventry
        .endif
+       /*
+        * Defend against branch aliasing attacks by pushing a dummy
+        * entry onto the return stack and using a RET instruction to
+        * enter the full-fat kernel vectors.
+        */
+       bl      2f
+       b       .
+2:
        tramp_map_kernel        x30
+#ifdef CONFIG_RANDOMIZE_BASE
+       adr     x30, tramp_vectors + PAGE_SIZE
+alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
+       ldr     x30, [x30]
+#else
        ldr     x30, =vectors
+#endif
        prfm    plil1strm, [x30, #(1b - tramp_vectors)]
        msr     vbar_el1, x30
        add     x30, x30, #(1b - tramp_vectors)
        isb
-       br      x30
+       ret
        .endm
 
        .macro tramp_exit, regsize = 64
@@ -981,6 +1036,14 @@ END(tramp_exit_compat)
 
        .ltorg
        .popsection                             // .entry.tramp.text
+#ifdef CONFIG_RANDOMIZE_BASE
+       .pushsection ".rodata", "a"
+       .align PAGE_SHIFT
+       .globl  __entry_tramp_data_start
+__entry_tramp_data_start:
+       .quad   vectors
+       .popsection                             // .rodata
+#endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
 /*