diff options
Diffstat (limited to 'arch/arm64/kernel/entry.S')
-rw-r--r-- | arch/arm64/kernel/entry.S | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index d5bc1dbdd2fd..362ead616c9c 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -182,7 +182,11 @@ alternative_else_nop_endif #endif .endm +#ifdef CONFIG_GTI_WATCHDOG + .macro kernel_entry, el, regsize = 64, exc_el3 = 0 +#else .macro kernel_entry, el, regsize = 64 +#endif .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0 .endif @@ -232,8 +236,31 @@ alternative_else_nop_endif 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 */ + +#ifdef CONFIG_GTI_WATCHDOG + .if \exc_el3 == 0 mrs x22, elr_el1 mrs x23, spsr_el1 + .else + /* + * load elr and spsr in case of simulated exception return from + * respective percpu gti_elr and gti_spsr variables, which are shared + * with el3. EL3 gti watchdog handler store interrupted register + * context in percpu shared location and elr_el1/2 & spsr_el1/2 will be + * used for simulated return to el1/el2 by el3 nmi handler. + */ + ldr_this_cpu x22, gti_elr, x29 + ldr_this_cpu x23, gti_spsr, x29 + .if \el == 0 + mov x29, xzr + .else + ldr x29, [sp, #S_X28+8] + .endif + .endif /* \exc_el3 == 0 */ +#else + mrs x22, elr_el1 + mrs x23, spsr_el1 +#endif stp lr, x21, [sp, #S_LR] /* @@ -287,7 +314,11 @@ alternative_else_nop_endif */ .endm +#ifdef CONFIG_GTI_WATCHDOG + .macro kernel_exit, el, exc_el3 = 0 +#else .macro kernel_exit, el +#endif .if \el != 0 disable_daif @@ -359,6 +390,15 @@ alternative_else_nop_endif ldp x26, x27, [sp, #16 * 13] ldp x28, x29, [sp, #16 * 14] +#ifdef CONFIG_GTI_WATCHDOG + /* + * Cannot do an eret here as we have not + * entered from a real exception. + */ + .if \exc_el3 == 1 + b 6f + .endif +#endif .if \el == 0 alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0 ldr lr, [sp, #S_LR] @@ -383,6 +423,9 @@ alternative_else_nop_endif eret .endif +#ifdef CONFIG_GTI_WATCHDOG +6: +#endif sb .endm @@ -719,6 +762,49 @@ el0_irq_naked: b ret_to_user SYM_CODE_END(el0_irq) +#ifdef CONFIG_GTI_WATCHDOG + +/* + * Simulate an exception return at same ELx, for example, + * exception entry and pstate are loaded from ELR_ELx and SPSR_ELx. + */ +.globl el0_nmi_callback +el0_nmi_callback: + sub sp, sp, #S_FRAME_SIZE + kernel_entry 0, 64, 1 + mov x0, sp + bl nmi_kernel_callback + kernel_exit 0, 1 + b ret_back_to_el3 + +.globl el1_nmi_callback +el1_nmi_callback: + sub sp, sp, #S_FRAME_SIZE + kernel_entry 1, 64, 1 + mov x0, sp + bl nmi_kernel_callback + kernel_exit 1, 1 + +ret_back_to_el3: + /* + * We return back to the interrupted context via EL3, + * as we need to do cleanup in ATF before restoring + * interrupted context such as dropping lock and + * do interrupt completion, etc. + * Make OCTEONTX_RESTORE_WDOG_CTXT (0xc2000c04) SMC + * call. + */ + mov x0, #0xc04 // OCTEONTX_RESTORE_WDOG_CTXT + mov x7, #0x0 // #0 + movk x0, #0xc200, lsl #16 + mov x6, #0x0 // #0 + mov x5, #0x0 // #0 + mov x4, #0x0 // #0 + mov x3, #0x0 // #0 + mov x1, #0x0 // #0 + smc #0x0 +#endif + SYM_CODE_START_LOCAL(el1_error) kernel_entry 1 mrs x1, esr_el1 |