162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2020 - Google Inc 462306a36Sopenharmony_ci * Author: Andrew Scull <ascull@google.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/linkage.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/assembler.h> 1062306a36Sopenharmony_ci#include <asm/kvm_arm.h> 1162306a36Sopenharmony_ci#include <asm/kvm_asm.h> 1262306a36Sopenharmony_ci#include <asm/kvm_mmu.h> 1362306a36Sopenharmony_ci#include <asm/kvm_ptrauth.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci .text 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciSYM_FUNC_START(__host_exit) 1862306a36Sopenharmony_ci get_host_ctxt x0, x1 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci /* Store the host regs x2 and x3 */ 2162306a36Sopenharmony_ci stp x2, x3, [x0, #CPU_XREG_OFFSET(2)] 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci /* Retrieve the host regs x0-x1 from the stack */ 2462306a36Sopenharmony_ci ldp x2, x3, [sp], #16 // x0, x1 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* Store the host regs x0-x1 and x4-x17 */ 2762306a36Sopenharmony_ci stp x2, x3, [x0, #CPU_XREG_OFFSET(0)] 2862306a36Sopenharmony_ci stp x4, x5, [x0, #CPU_XREG_OFFSET(4)] 2962306a36Sopenharmony_ci stp x6, x7, [x0, #CPU_XREG_OFFSET(6)] 3062306a36Sopenharmony_ci stp x8, x9, [x0, #CPU_XREG_OFFSET(8)] 3162306a36Sopenharmony_ci stp x10, x11, [x0, #CPU_XREG_OFFSET(10)] 3262306a36Sopenharmony_ci stp x12, x13, [x0, #CPU_XREG_OFFSET(12)] 3362306a36Sopenharmony_ci stp x14, x15, [x0, #CPU_XREG_OFFSET(14)] 3462306a36Sopenharmony_ci stp x16, x17, [x0, #CPU_XREG_OFFSET(16)] 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* Store the host regs x18-x29, lr */ 3762306a36Sopenharmony_ci save_callee_saved_regs x0 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* Save the host context pointer in x29 across the function call */ 4062306a36Sopenharmony_ci mov x29, x0 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL 4362306a36Sopenharmony_cialternative_if_not ARM64_HAS_ADDRESS_AUTH 4462306a36Sopenharmony_cib __skip_pauth_save 4562306a36Sopenharmony_cialternative_else_nop_endif 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cialternative_if ARM64_KVM_PROTECTED_MODE 4862306a36Sopenharmony_ci /* Save kernel ptrauth keys. */ 4962306a36Sopenharmony_ci add x18, x29, #CPU_APIAKEYLO_EL1 5062306a36Sopenharmony_ci ptrauth_save_state x18, x19, x20 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* Use hyp keys. */ 5362306a36Sopenharmony_ci adr_this_cpu x18, kvm_hyp_ctxt, x19 5462306a36Sopenharmony_ci add x18, x18, #CPU_APIAKEYLO_EL1 5562306a36Sopenharmony_ci ptrauth_restore_state x18, x19, x20 5662306a36Sopenharmony_ci isb 5762306a36Sopenharmony_cialternative_else_nop_endif 5862306a36Sopenharmony_ci__skip_pauth_save: 5962306a36Sopenharmony_ci#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci bl handle_trap 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci__host_enter_restore_full: 6462306a36Sopenharmony_ci /* Restore kernel keys. */ 6562306a36Sopenharmony_ci#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL 6662306a36Sopenharmony_cialternative_if_not ARM64_HAS_ADDRESS_AUTH 6762306a36Sopenharmony_cib __skip_pauth_restore 6862306a36Sopenharmony_cialternative_else_nop_endif 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cialternative_if ARM64_KVM_PROTECTED_MODE 7162306a36Sopenharmony_ci add x18, x29, #CPU_APIAKEYLO_EL1 7262306a36Sopenharmony_ci ptrauth_restore_state x18, x19, x20 7362306a36Sopenharmony_cialternative_else_nop_endif 7462306a36Sopenharmony_ci__skip_pauth_restore: 7562306a36Sopenharmony_ci#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Restore host regs x0-x17 */ 7862306a36Sopenharmony_ci ldp x0, x1, [x29, #CPU_XREG_OFFSET(0)] 7962306a36Sopenharmony_ci ldp x2, x3, [x29, #CPU_XREG_OFFSET(2)] 8062306a36Sopenharmony_ci ldp x4, x5, [x29, #CPU_XREG_OFFSET(4)] 8162306a36Sopenharmony_ci ldp x6, x7, [x29, #CPU_XREG_OFFSET(6)] 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* x0-7 are use for panic arguments */ 8462306a36Sopenharmony_ci__host_enter_for_panic: 8562306a36Sopenharmony_ci ldp x8, x9, [x29, #CPU_XREG_OFFSET(8)] 8662306a36Sopenharmony_ci ldp x10, x11, [x29, #CPU_XREG_OFFSET(10)] 8762306a36Sopenharmony_ci ldp x12, x13, [x29, #CPU_XREG_OFFSET(12)] 8862306a36Sopenharmony_ci ldp x14, x15, [x29, #CPU_XREG_OFFSET(14)] 8962306a36Sopenharmony_ci ldp x16, x17, [x29, #CPU_XREG_OFFSET(16)] 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Restore host regs x18-x29, lr */ 9262306a36Sopenharmony_ci restore_callee_saved_regs x29 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Do not touch any register after this! */ 9562306a36Sopenharmony_ci__host_enter_without_restoring: 9662306a36Sopenharmony_ci eret 9762306a36Sopenharmony_ci sb 9862306a36Sopenharmony_ciSYM_FUNC_END(__host_exit) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * void __noreturn __host_enter(struct kvm_cpu_context *host_ctxt); 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ciSYM_FUNC_START(__host_enter) 10462306a36Sopenharmony_ci mov x29, x0 10562306a36Sopenharmony_ci b __host_enter_restore_full 10662306a36Sopenharmony_ciSYM_FUNC_END(__host_enter) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr, 11062306a36Sopenharmony_ci * u64 elr, u64 par); 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ciSYM_FUNC_START(__hyp_do_panic) 11362306a36Sopenharmony_ci /* Prepare and exit to the host's panic funciton. */ 11462306a36Sopenharmony_ci mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ 11562306a36Sopenharmony_ci PSR_MODE_EL1h) 11662306a36Sopenharmony_ci msr spsr_el2, lr 11762306a36Sopenharmony_ci adr_l lr, nvhe_hyp_panic_handler 11862306a36Sopenharmony_ci hyp_kimg_va lr, x6 11962306a36Sopenharmony_ci msr elr_el2, lr 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci mov x29, x0 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#ifdef CONFIG_NVHE_EL2_DEBUG 12462306a36Sopenharmony_ci /* Ensure host stage-2 is disabled */ 12562306a36Sopenharmony_ci mrs x0, hcr_el2 12662306a36Sopenharmony_ci bic x0, x0, #HCR_VM 12762306a36Sopenharmony_ci msr hcr_el2, x0 12862306a36Sopenharmony_ci isb 12962306a36Sopenharmony_ci tlbi vmalls12e1 13062306a36Sopenharmony_ci dsb nsh 13162306a36Sopenharmony_ci#endif 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Load the panic arguments into x0-7 */ 13462306a36Sopenharmony_ci mrs x0, esr_el2 13562306a36Sopenharmony_ci mov x4, x3 13662306a36Sopenharmony_ci mov x3, x2 13762306a36Sopenharmony_ci hyp_pa x3, x6 13862306a36Sopenharmony_ci get_vcpu_ptr x5, x6 13962306a36Sopenharmony_ci mrs x6, far_el2 14062306a36Sopenharmony_ci mrs x7, hpfar_el2 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Enter the host, conditionally restoring the host context. */ 14362306a36Sopenharmony_ci cbz x29, __host_enter_without_restoring 14462306a36Sopenharmony_ci b __host_enter_for_panic 14562306a36Sopenharmony_ciSYM_FUNC_END(__hyp_do_panic) 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciSYM_FUNC_START(__host_hvc) 14862306a36Sopenharmony_ci ldp x0, x1, [sp] // Don't fixup the stack yet 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* No stub for you, sonny Jim */ 15162306a36Sopenharmony_cialternative_if ARM64_KVM_PROTECTED_MODE 15262306a36Sopenharmony_ci b __host_exit 15362306a36Sopenharmony_cialternative_else_nop_endif 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Check for a stub HVC call */ 15662306a36Sopenharmony_ci cmp x0, #HVC_STUB_HCALL_NR 15762306a36Sopenharmony_ci b.hs __host_exit 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci add sp, sp, #16 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * Compute the idmap address of __kvm_handle_stub_hvc and 16262306a36Sopenharmony_ci * jump there. 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * Preserve x0-x4, which may contain stub parameters. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci adr_l x5, __kvm_handle_stub_hvc 16762306a36Sopenharmony_ci hyp_pa x5, x6 16862306a36Sopenharmony_ci br x5 16962306a36Sopenharmony_ciSYM_FUNC_END(__host_hvc) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci.macro host_el1_sync_vect 17262306a36Sopenharmony_ci .align 7 17362306a36Sopenharmony_ci.L__vect_start\@: 17462306a36Sopenharmony_ci stp x0, x1, [sp, #-16]! 17562306a36Sopenharmony_ci mrs x0, esr_el2 17662306a36Sopenharmony_ci ubfx x0, x0, #ESR_ELx_EC_SHIFT, #ESR_ELx_EC_WIDTH 17762306a36Sopenharmony_ci cmp x0, #ESR_ELx_EC_HVC64 17862306a36Sopenharmony_ci b.eq __host_hvc 17962306a36Sopenharmony_ci b __host_exit 18062306a36Sopenharmony_ci.L__vect_end\@: 18162306a36Sopenharmony_ci.if ((.L__vect_end\@ - .L__vect_start\@) > 0x80) 18262306a36Sopenharmony_ci .error "host_el1_sync_vect larger than vector entry" 18362306a36Sopenharmony_ci.endif 18462306a36Sopenharmony_ci.endm 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci.macro invalid_host_el2_vect 18762306a36Sopenharmony_ci .align 7 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Test whether the SP has overflowed, without corrupting a GPR. 19162306a36Sopenharmony_ci * nVHE hypervisor stacks are aligned so that the PAGE_SHIFT bit 19262306a36Sopenharmony_ci * of SP should always be 1. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci add sp, sp, x0 // sp' = sp + x0 19562306a36Sopenharmony_ci sub x0, sp, x0 // x0' = sp' - x0 = (sp + x0) - x0 = sp 19662306a36Sopenharmony_ci tbz x0, #PAGE_SHIFT, .L__hyp_sp_overflow\@ 19762306a36Sopenharmony_ci sub x0, sp, x0 // x0'' = sp' - x0' = (sp + x0) - sp = x0 19862306a36Sopenharmony_ci sub sp, sp, x0 // sp'' = sp' - x0 = (sp + x0) - x0 = sp 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* If a guest is loaded, panic out of it. */ 20162306a36Sopenharmony_ci stp x0, x1, [sp, #-16]! 20262306a36Sopenharmony_ci get_loaded_vcpu x0, x1 20362306a36Sopenharmony_ci cbnz x0, __guest_exit_panic 20462306a36Sopenharmony_ci add sp, sp, #16 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * The panic may not be clean if the exception is taken before the host 20862306a36Sopenharmony_ci * context has been saved by __host_exit or after the hyp context has 20962306a36Sopenharmony_ci * been partially clobbered by __host_enter. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci b hyp_panic 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci.L__hyp_sp_overflow\@: 21462306a36Sopenharmony_ci /* Switch to the overflow stack */ 21562306a36Sopenharmony_ci adr_this_cpu sp, overflow_stack + OVERFLOW_STACK_SIZE, x0 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci b hyp_panic_bad_stack 21862306a36Sopenharmony_ci ASM_BUG() 21962306a36Sopenharmony_ci.endm 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci.macro invalid_host_el1_vect 22262306a36Sopenharmony_ci .align 7 22362306a36Sopenharmony_ci mov x0, xzr /* restore_host = false */ 22462306a36Sopenharmony_ci mrs x1, spsr_el2 22562306a36Sopenharmony_ci mrs x2, elr_el2 22662306a36Sopenharmony_ci mrs x3, par_el1 22762306a36Sopenharmony_ci b __hyp_do_panic 22862306a36Sopenharmony_ci.endm 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* 23162306a36Sopenharmony_ci * The host vector does not use an ESB instruction in order to avoid consuming 23262306a36Sopenharmony_ci * SErrors that should only be consumed by the host. Guest entry is deferred by 23362306a36Sopenharmony_ci * __guest_enter if there are any pending asynchronous exceptions so hyp will 23462306a36Sopenharmony_ci * always return to the host without having consumerd host SErrors. 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * CONFIG_KVM_INDIRECT_VECTORS is not applied to the host vectors because the 23762306a36Sopenharmony_ci * host knows about the EL2 vectors already, and there is no point in hiding 23862306a36Sopenharmony_ci * them. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci .align 11 24162306a36Sopenharmony_ciSYM_CODE_START(__kvm_hyp_host_vector) 24262306a36Sopenharmony_ci invalid_host_el2_vect // Synchronous EL2t 24362306a36Sopenharmony_ci invalid_host_el2_vect // IRQ EL2t 24462306a36Sopenharmony_ci invalid_host_el2_vect // FIQ EL2t 24562306a36Sopenharmony_ci invalid_host_el2_vect // Error EL2t 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci invalid_host_el2_vect // Synchronous EL2h 24862306a36Sopenharmony_ci invalid_host_el2_vect // IRQ EL2h 24962306a36Sopenharmony_ci invalid_host_el2_vect // FIQ EL2h 25062306a36Sopenharmony_ci invalid_host_el2_vect // Error EL2h 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci host_el1_sync_vect // Synchronous 64-bit EL1/EL0 25362306a36Sopenharmony_ci invalid_host_el1_vect // IRQ 64-bit EL1/EL0 25462306a36Sopenharmony_ci invalid_host_el1_vect // FIQ 64-bit EL1/EL0 25562306a36Sopenharmony_ci invalid_host_el1_vect // Error 64-bit EL1/EL0 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci host_el1_sync_vect // Synchronous 32-bit EL1/EL0 25862306a36Sopenharmony_ci invalid_host_el1_vect // IRQ 32-bit EL1/EL0 25962306a36Sopenharmony_ci invalid_host_el1_vect // FIQ 32-bit EL1/EL0 26062306a36Sopenharmony_ci invalid_host_el1_vect // Error 32-bit EL1/EL0 26162306a36Sopenharmony_ciSYM_CODE_END(__kvm_hyp_host_vector) 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* 26462306a36Sopenharmony_ci * Forward SMC with arguments in struct kvm_cpu_context, and 26562306a36Sopenharmony_ci * store the result into the same struct. Assumes SMCCC 1.2 or older. 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * x0: struct kvm_cpu_context* 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ciSYM_CODE_START(__kvm_hyp_host_forward_smc) 27062306a36Sopenharmony_ci /* 27162306a36Sopenharmony_ci * Use x18 to keep the pointer to the host context because 27262306a36Sopenharmony_ci * x18 is callee-saved in SMCCC but not in AAPCS64. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci mov x18, x0 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ldp x0, x1, [x18, #CPU_XREG_OFFSET(0)] 27762306a36Sopenharmony_ci ldp x2, x3, [x18, #CPU_XREG_OFFSET(2)] 27862306a36Sopenharmony_ci ldp x4, x5, [x18, #CPU_XREG_OFFSET(4)] 27962306a36Sopenharmony_ci ldp x6, x7, [x18, #CPU_XREG_OFFSET(6)] 28062306a36Sopenharmony_ci ldp x8, x9, [x18, #CPU_XREG_OFFSET(8)] 28162306a36Sopenharmony_ci ldp x10, x11, [x18, #CPU_XREG_OFFSET(10)] 28262306a36Sopenharmony_ci ldp x12, x13, [x18, #CPU_XREG_OFFSET(12)] 28362306a36Sopenharmony_ci ldp x14, x15, [x18, #CPU_XREG_OFFSET(14)] 28462306a36Sopenharmony_ci ldp x16, x17, [x18, #CPU_XREG_OFFSET(16)] 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci smc #0 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci stp x0, x1, [x18, #CPU_XREG_OFFSET(0)] 28962306a36Sopenharmony_ci stp x2, x3, [x18, #CPU_XREG_OFFSET(2)] 29062306a36Sopenharmony_ci stp x4, x5, [x18, #CPU_XREG_OFFSET(4)] 29162306a36Sopenharmony_ci stp x6, x7, [x18, #CPU_XREG_OFFSET(6)] 29262306a36Sopenharmony_ci stp x8, x9, [x18, #CPU_XREG_OFFSET(8)] 29362306a36Sopenharmony_ci stp x10, x11, [x18, #CPU_XREG_OFFSET(10)] 29462306a36Sopenharmony_ci stp x12, x13, [x18, #CPU_XREG_OFFSET(12)] 29562306a36Sopenharmony_ci stp x14, x15, [x18, #CPU_XREG_OFFSET(14)] 29662306a36Sopenharmony_ci stp x16, x17, [x18, #CPU_XREG_OFFSET(16)] 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ret 29962306a36Sopenharmony_ciSYM_CODE_END(__kvm_hyp_host_forward_smc) 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* 30262306a36Sopenharmony_ci * kvm_host_psci_cpu_entry is called through br instruction, which requires 30362306a36Sopenharmony_ci * bti j instruction as compilers (gcc and llvm) doesn't insert bti j for external 30462306a36Sopenharmony_ci * functions, but bti c instead. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ciSYM_CODE_START(kvm_host_psci_cpu_entry) 30762306a36Sopenharmony_ci bti j 30862306a36Sopenharmony_ci b __kvm_host_psci_cpu_entry 30962306a36Sopenharmony_ciSYM_CODE_END(kvm_host_psci_cpu_entry) 310