|
@@ -1159,6 +1159,78 @@ NOKPROBE(ret_from_fork)
|
|
|
#include <asm/sdei.h>
|
|
|
#include <uapi/linux/arm_sdei.h>
|
|
|
|
|
|
+.macro sdei_handler_exit exit_mode
|
|
|
+ /* On success, this call never returns... */
|
|
|
+ cmp \exit_mode, #SDEI_EXIT_SMC
|
|
|
+ b.ne 99f
|
|
|
+ smc #0
|
|
|
+ b .
|
|
|
+99: hvc #0
|
|
|
+ b .
|
|
|
+.endm
|
|
|
+
|
|
|
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
|
+/*
|
|
|
+ * The regular SDEI entry point may have been unmapped along with the rest of
|
|
|
+ * the kernel. This trampoline restores the kernel mapping to make the x1 memory
|
|
|
+ * argument accessible.
|
|
|
+ *
|
|
|
+ * This clobbers x4, __sdei_handler() will restore this from firmware's
|
|
|
+ * copy.
|
|
|
+ */
|
|
|
+.ltorg
|
|
|
+.pushsection ".entry.tramp.text", "ax"
|
|
|
+ENTRY(__sdei_asm_entry_trampoline)
|
|
|
+ mrs x4, ttbr1_el1
|
|
|
+ tbz x4, #USER_ASID_BIT, 1f
|
|
|
+
|
|
|
+ tramp_map_kernel tmp=x4
|
|
|
+ isb
|
|
|
+ mov x4, xzr
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Use reg->interrupted_regs.addr_limit to remember whether to unmap
|
|
|
+ * the kernel on exit.
|
|
|
+ */
|
|
|
+1: str x4, [x1, #(SDEI_EVENT_INTREGS + S_ORIG_ADDR_LIMIT)]
|
|
|
+
|
|
|
+#ifdef CONFIG_RANDOMIZE_BASE
|
|
|
+ adr x4, tramp_vectors + PAGE_SIZE
|
|
|
+ add x4, x4, #:lo12:__sdei_asm_trampoline_next_handler
|
|
|
+ ldr x4, [x4]
|
|
|
+#else
|
|
|
+ ldr x4, =__sdei_asm_handler
|
|
|
+#endif
|
|
|
+ br x4
|
|
|
+ENDPROC(__sdei_asm_entry_trampoline)
|
|
|
+NOKPROBE(__sdei_asm_entry_trampoline)
|
|
|
+
|
|
|
+/*
|
|
|
+ * Make the exit call and restore the original ttbr1_el1
|
|
|
+ *
|
|
|
+ * x0 & x1: setup for the exit API call
|
|
|
+ * x2: exit_mode
|
|
|
+ * x4: struct sdei_registered_event argument from registration time.
|
|
|
+ */
|
|
|
+ENTRY(__sdei_asm_exit_trampoline)
|
|
|
+ ldr x4, [x4, #(SDEI_EVENT_INTREGS + S_ORIG_ADDR_LIMIT)]
|
|
|
+ cbnz x4, 1f
|
|
|
+
|
|
|
+ tramp_unmap_kernel tmp=x4
|
|
|
+
|
|
|
+1: sdei_handler_exit exit_mode=x2
|
|
|
+ENDPROC(__sdei_asm_exit_trampoline)
|
|
|
+NOKPROBE(__sdei_asm_exit_trampoline)
|
|
|
+ .ltorg
|
|
|
+.popsection // .entry.tramp.text
|
|
|
+#ifdef CONFIG_RANDOMIZE_BASE
|
|
|
+.pushsection ".rodata", "a"
|
|
|
+__sdei_asm_trampoline_next_handler:
|
|
|
+ .quad __sdei_asm_handler
|
|
|
+.popsection // .rodata
|
|
|
+#endif /* CONFIG_RANDOMIZE_BASE */
|
|
|
+#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
|
|
|
+
|
|
|
/*
|
|
|
* Software Delegated Exception entry point.
|
|
|
*
|
|
@@ -1166,6 +1238,7 @@ NOKPROBE(ret_from_fork)
|
|
|
* x1: struct sdei_registered_event argument from registration time.
|
|
|
* x2: interrupted PC
|
|
|
* x3: interrupted PSTATE
|
|
|
+ * x4: maybe clobbered by the trampoline
|
|
|
*
|
|
|
* Firmware has preserved x0->x17 for us, we must save/restore the rest to
|
|
|
* follow SMC-CC. We save (or retrieve) all the registers as the handler may
|
|
@@ -1231,10 +1304,11 @@ ENTRY(__sdei_asm_handler)
|
|
|
|
|
|
msr sp_el0, x28
|
|
|
/* restore regs >x17 that we clobbered */
|
|
|
- ldp x28, x29, [x19, #SDEI_EVENT_INTREGS + 16 * 14]
|
|
|
- ldp lr, x4, [x19, #SDEI_EVENT_INTREGS + S_LR]
|
|
|
- mov sp, x4
|
|
|
- ldp x18, x19, [x19, #SDEI_EVENT_INTREGS + 16 * 9]
|
|
|
+ mov x4, x19 // keep x4 for __sdei_asm_exit_trampoline
|
|
|
+ ldp x28, x29, [x4, #SDEI_EVENT_INTREGS + 16 * 14]
|
|
|
+ ldp x18, x19, [x4, #SDEI_EVENT_INTREGS + 16 * 9]
|
|
|
+ ldp lr, x1, [x4, #SDEI_EVENT_INTREGS + S_LR]
|
|
|
+ mov sp, x1
|
|
|
|
|
|
mov x1, x0 // address to complete_and_resume
|
|
|
/* x0 = (x0 <= 1) ? EVENT_COMPLETE:EVENT_COMPLETE_AND_RESUME */
|
|
@@ -1243,14 +1317,16 @@ ENTRY(__sdei_asm_handler)
|
|
|
mov_q x3, SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME
|
|
|
csel x0, x2, x3, ls
|
|
|
|
|
|
- /* On success, this call never returns... */
|
|
|
ldr_l x2, sdei_exit_mode
|
|
|
- cmp x2, #SDEI_EXIT_SMC
|
|
|
- b.ne 1f
|
|
|
- smc #0
|
|
|
- b .
|
|
|
-1: hvc #0
|
|
|
- b .
|
|
|
+
|
|
|
+alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0
|
|
|
+ sdei_handler_exit exit_mode=x2
|
|
|
+alternative_else_nop_endif
|
|
|
+
|
|
|
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
|
+ tramp_alias dst=x5, sym=__sdei_asm_exit_trampoline
|
|
|
+ br x5
|
|
|
+#endif
|
|
|
ENDPROC(__sdei_asm_handler)
|
|
|
NOKPROBE(__sdei_asm_handler)
|
|
|
#endif /* CONFIG_ARM_SDE_INTERFACE */
|