|
@@ -28,6 +28,8 @@
|
|
|
#include <asm/errno.h>
|
|
|
#include <asm/esr.h>
|
|
|
#include <asm/irq.h>
|
|
|
+#include <asm/memory.h>
|
|
|
+#include <asm/mmu.h>
|
|
|
#include <asm/processor.h>
|
|
|
#include <asm/ptrace.h>
|
|
|
#include <asm/thread_info.h>
|
|
@@ -69,8 +71,21 @@
|
|
|
#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
|
|
|
/*
|
|
@@ -82,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:
|
|
|
/*
|
|
@@ -114,7 +129,12 @@
|
|
|
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
|
|
@@ -184,8 +204,8 @@ alternative_if ARM64_HAS_PAN
|
|
|
alternative_else_nop_endif
|
|
|
|
|
|
.if \el != 0
|
|
|
- mrs x21, ttbr0_el1
|
|
|
- tst x21, #0xffff << 48 // Check for the reserved ASID
|
|
|
+ mrs x21, ttbr1_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
|
|
@@ -248,7 +268,7 @@ alternative_else_nop_endif
|
|
|
tbnz x22, #22, 1f // Skip re-enabling TTBR0 access if the PSR_PAN_BIT is set
|
|
|
.endif
|
|
|
|
|
|
- __uaccess_ttbr0_enable x0
|
|
|
+ __uaccess_ttbr0_enable x0, x1
|
|
|
|
|
|
.if \el == 0
|
|
|
/*
|
|
@@ -257,7 +277,7 @@ alternative_else_nop_endif
|
|
|
* Cavium erratum 27456 (broadcast TLBI instructions may cause I-cache
|
|
|
* corruption).
|
|
|
*/
|
|
|
- post_ttbr0_update_workaround
|
|
|
+ post_ttbr_update_workaround
|
|
|
.endif
|
|
|
1:
|
|
|
.if \el != 0
|
|
@@ -269,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
|
|
@@ -302,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
|
|
@@ -367,31 +403,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 // 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 // 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 // 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 // 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_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_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)
|
|
|
|
|
@@ -943,6 +979,116 @@ __ni_sys_trace:
|
|
|
|
|
|
.popsection // .entry.text
|
|
|
|
|
|
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
|
+/*
|
|
|
+ * Exception vectors trampoline.
|
|
|
+ */
|
|
|
+ .pushsection ".entry.tramp.text", "ax"
|
|
|
+
|
|
|
+ .macro tramp_map_kernel, tmp
|
|
|
+ mrs \tmp, ttbr1_el1
|
|
|
+ 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
|
|
|
+ mrs \tmp, ttbr1_el1
|
|
|
+ add \tmp, \tmp, #(SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
|
|
|
+ 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.
|
|
|
+ */
|
|
|
+ .endm
|
|
|
+
|
|
|
+ .macro tramp_ventry, regsize = 64
|
|
|
+ .align 7
|
|
|
+1:
|
|
|
+ .if \regsize == 64
|
|
|
+ msr tpidrro_el0, x30 // Restored in kernel_ventry
|
|
|
+ .endif
|
|
|
+ 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
|
|
|
+ .endm
|
|
|
+
|
|
|
+ .macro tramp_exit, regsize = 64
|
|
|
+ adr x30, tramp_vectors
|
|
|
+ msr vbar_el1, x30
|
|
|
+ tramp_unmap_kernel x30
|
|
|
+ .if \regsize == 64
|
|
|
+ mrs x30, far_el1
|
|
|
+ .endif
|
|
|
+ eret
|
|
|
+ .endm
|
|
|
+
|
|
|
+ .align 11
|
|
|
+ENTRY(tramp_vectors)
|
|
|
+ .space 0x400
|
|
|
+
|
|
|
+ tramp_ventry
|
|
|
+ tramp_ventry
|
|
|
+ tramp_ventry
|
|
|
+ tramp_ventry
|
|
|
+
|
|
|
+ tramp_ventry 32
|
|
|
+ tramp_ventry 32
|
|
|
+ tramp_ventry 32
|
|
|
+ tramp_ventry 32
|
|
|
+END(tramp_vectors)
|
|
|
+
|
|
|
+ENTRY(tramp_exit_native)
|
|
|
+ tramp_exit
|
|
|
+END(tramp_exit_native)
|
|
|
+
|
|
|
+ENTRY(tramp_exit_compat)
|
|
|
+ tramp_exit 32
|
|
|
+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 */
|
|
|
+
|
|
|
/*
|
|
|
* Special system call wrappers.
|
|
|
*/
|