18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 - Google Inc 48c2ecf20Sopenharmony_ci * Author: Andrew Scull <ascull@google.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/linkage.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/assembler.h> 108c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h> 118c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci .text 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciSYM_FUNC_START(__host_exit) 168c2ecf20Sopenharmony_ci stp x0, x1, [sp, #-16]! 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci get_host_ctxt x0, x1 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci /* Store the host regs x2 and x3 */ 218c2ecf20Sopenharmony_ci stp x2, x3, [x0, #CPU_XREG_OFFSET(2)] 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci /* Retrieve the host regs x0-x1 from the stack */ 248c2ecf20Sopenharmony_ci ldp x2, x3, [sp], #16 // x0, x1 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci /* Store the host regs x0-x1 and x4-x17 */ 278c2ecf20Sopenharmony_ci stp x2, x3, [x0, #CPU_XREG_OFFSET(0)] 288c2ecf20Sopenharmony_ci stp x4, x5, [x0, #CPU_XREG_OFFSET(4)] 298c2ecf20Sopenharmony_ci stp x6, x7, [x0, #CPU_XREG_OFFSET(6)] 308c2ecf20Sopenharmony_ci stp x8, x9, [x0, #CPU_XREG_OFFSET(8)] 318c2ecf20Sopenharmony_ci stp x10, x11, [x0, #CPU_XREG_OFFSET(10)] 328c2ecf20Sopenharmony_ci stp x12, x13, [x0, #CPU_XREG_OFFSET(12)] 338c2ecf20Sopenharmony_ci stp x14, x15, [x0, #CPU_XREG_OFFSET(14)] 348c2ecf20Sopenharmony_ci stp x16, x17, [x0, #CPU_XREG_OFFSET(16)] 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* Store the host regs x18-x29, lr */ 378c2ecf20Sopenharmony_ci save_callee_saved_regs x0 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* Save the host context pointer in x29 across the function call */ 408c2ecf20Sopenharmony_ci mov x29, x0 418c2ecf20Sopenharmony_ci bl handle_trap 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* Restore host regs x0-x17 */ 448c2ecf20Sopenharmony_ci ldp x0, x1, [x29, #CPU_XREG_OFFSET(0)] 458c2ecf20Sopenharmony_ci ldp x2, x3, [x29, #CPU_XREG_OFFSET(2)] 468c2ecf20Sopenharmony_ci ldp x4, x5, [x29, #CPU_XREG_OFFSET(4)] 478c2ecf20Sopenharmony_ci ldp x6, x7, [x29, #CPU_XREG_OFFSET(6)] 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* x0-7 are use for panic arguments */ 508c2ecf20Sopenharmony_ci__host_enter_for_panic: 518c2ecf20Sopenharmony_ci ldp x8, x9, [x29, #CPU_XREG_OFFSET(8)] 528c2ecf20Sopenharmony_ci ldp x10, x11, [x29, #CPU_XREG_OFFSET(10)] 538c2ecf20Sopenharmony_ci ldp x12, x13, [x29, #CPU_XREG_OFFSET(12)] 548c2ecf20Sopenharmony_ci ldp x14, x15, [x29, #CPU_XREG_OFFSET(14)] 558c2ecf20Sopenharmony_ci ldp x16, x17, [x29, #CPU_XREG_OFFSET(16)] 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* Restore host regs x18-x29, lr */ 588c2ecf20Sopenharmony_ci restore_callee_saved_regs x29 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* Do not touch any register after this! */ 618c2ecf20Sopenharmony_ci__host_enter_without_restoring: 628c2ecf20Sopenharmony_ci eret 638c2ecf20Sopenharmony_ci sb 648c2ecf20Sopenharmony_ciSYM_FUNC_END(__host_exit) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* 678c2ecf20Sopenharmony_ci * void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr, 688c2ecf20Sopenharmony_ci * u64 elr, u64 par); 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ciSYM_FUNC_START(__hyp_do_panic) 718c2ecf20Sopenharmony_ci mov x29, x0 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* Load the format string into x0 and arguments into x1-7 */ 748c2ecf20Sopenharmony_ci ldr x0, =__hyp_panic_string 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci mov x6, x3 778c2ecf20Sopenharmony_ci get_vcpu_ptr x7, x3 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci mrs x3, esr_el2 808c2ecf20Sopenharmony_ci mrs x4, far_el2 818c2ecf20Sopenharmony_ci mrs x5, hpfar_el2 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Prepare and exit to the host's panic funciton. */ 848c2ecf20Sopenharmony_ci mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ 858c2ecf20Sopenharmony_ci PSR_MODE_EL1h) 868c2ecf20Sopenharmony_ci msr spsr_el2, lr 878c2ecf20Sopenharmony_ci ldr lr, =panic 888c2ecf20Sopenharmony_ci msr elr_el2, lr 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* Enter the host, conditionally restoring the host context. */ 918c2ecf20Sopenharmony_ci cbz x29, __host_enter_without_restoring 928c2ecf20Sopenharmony_ci b __host_enter_for_panic 938c2ecf20Sopenharmony_ciSYM_FUNC_END(__hyp_do_panic) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci.macro host_el1_sync_vect 968c2ecf20Sopenharmony_ci .align 7 978c2ecf20Sopenharmony_ci.L__vect_start\@: 988c2ecf20Sopenharmony_ci stp x0, x1, [sp, #-16]! 998c2ecf20Sopenharmony_ci mrs x0, esr_el2 1008c2ecf20Sopenharmony_ci ubfx x0, x0, #ESR_ELx_EC_SHIFT, #ESR_ELx_EC_WIDTH 1018c2ecf20Sopenharmony_ci cmp x0, #ESR_ELx_EC_HVC64 1028c2ecf20Sopenharmony_ci ldp x0, x1, [sp], #16 1038c2ecf20Sopenharmony_ci b.ne __host_exit 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Check for a stub HVC call */ 1068c2ecf20Sopenharmony_ci cmp x0, #HVC_STUB_HCALL_NR 1078c2ecf20Sopenharmony_ci b.hs __host_exit 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Compute the idmap address of __kvm_handle_stub_hvc and 1118c2ecf20Sopenharmony_ci * jump there. Since we use kimage_voffset, do not use the 1128c2ecf20Sopenharmony_ci * HYP VA for __kvm_handle_stub_hvc, but the kernel VA instead 1138c2ecf20Sopenharmony_ci * (by loading it from the constant pool). 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * Preserve x0-x4, which may contain stub parameters. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci ldr x5, =__kvm_handle_stub_hvc 1188c2ecf20Sopenharmony_ci ldr_l x6, kimage_voffset 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* x5 = __pa(x5) */ 1218c2ecf20Sopenharmony_ci sub x5, x5, x6 1228c2ecf20Sopenharmony_ci br x5 1238c2ecf20Sopenharmony_ci.L__vect_end\@: 1248c2ecf20Sopenharmony_ci.if ((.L__vect_end\@ - .L__vect_start\@) > 0x80) 1258c2ecf20Sopenharmony_ci .error "host_el1_sync_vect larger than vector entry" 1268c2ecf20Sopenharmony_ci.endif 1278c2ecf20Sopenharmony_ci.endm 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci.macro invalid_host_el2_vect 1308c2ecf20Sopenharmony_ci .align 7 1318c2ecf20Sopenharmony_ci /* If a guest is loaded, panic out of it. */ 1328c2ecf20Sopenharmony_ci stp x0, x1, [sp, #-16]! 1338c2ecf20Sopenharmony_ci get_loaded_vcpu x0, x1 1348c2ecf20Sopenharmony_ci cbnz x0, __guest_exit_panic 1358c2ecf20Sopenharmony_ci add sp, sp, #16 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * The panic may not be clean if the exception is taken before the host 1398c2ecf20Sopenharmony_ci * context has been saved by __host_exit or after the hyp context has 1408c2ecf20Sopenharmony_ci * been partially clobbered by __host_enter. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci b hyp_panic 1438c2ecf20Sopenharmony_ci.endm 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci.macro invalid_host_el1_vect 1468c2ecf20Sopenharmony_ci .align 7 1478c2ecf20Sopenharmony_ci mov x0, xzr /* host_ctxt = NULL */ 1488c2ecf20Sopenharmony_ci mrs x1, spsr_el2 1498c2ecf20Sopenharmony_ci mrs x2, elr_el2 1508c2ecf20Sopenharmony_ci mrs x3, par_el1 1518c2ecf20Sopenharmony_ci b __hyp_do_panic 1528c2ecf20Sopenharmony_ci.endm 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * The host vector does not use an ESB instruction in order to avoid consuming 1568c2ecf20Sopenharmony_ci * SErrors that should only be consumed by the host. Guest entry is deferred by 1578c2ecf20Sopenharmony_ci * __guest_enter if there are any pending asynchronous exceptions so hyp will 1588c2ecf20Sopenharmony_ci * always return to the host without having consumerd host SErrors. 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * CONFIG_KVM_INDIRECT_VECTORS is not applied to the host vectors because the 1618c2ecf20Sopenharmony_ci * host knows about the EL2 vectors already, and there is no point in hiding 1628c2ecf20Sopenharmony_ci * them. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci .align 11 1658c2ecf20Sopenharmony_ciSYM_CODE_START(__kvm_hyp_host_vector) 1668c2ecf20Sopenharmony_ci invalid_host_el2_vect // Synchronous EL2t 1678c2ecf20Sopenharmony_ci invalid_host_el2_vect // IRQ EL2t 1688c2ecf20Sopenharmony_ci invalid_host_el2_vect // FIQ EL2t 1698c2ecf20Sopenharmony_ci invalid_host_el2_vect // Error EL2t 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci invalid_host_el2_vect // Synchronous EL2h 1728c2ecf20Sopenharmony_ci invalid_host_el2_vect // IRQ EL2h 1738c2ecf20Sopenharmony_ci invalid_host_el2_vect // FIQ EL2h 1748c2ecf20Sopenharmony_ci invalid_host_el2_vect // Error EL2h 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci host_el1_sync_vect // Synchronous 64-bit EL1 1778c2ecf20Sopenharmony_ci invalid_host_el1_vect // IRQ 64-bit EL1 1788c2ecf20Sopenharmony_ci invalid_host_el1_vect // FIQ 64-bit EL1 1798c2ecf20Sopenharmony_ci invalid_host_el1_vect // Error 64-bit EL1 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci invalid_host_el1_vect // Synchronous 32-bit EL1 1828c2ecf20Sopenharmony_ci invalid_host_el1_vect // IRQ 32-bit EL1 1838c2ecf20Sopenharmony_ci invalid_host_el1_vect // FIQ 32-bit EL1 1848c2ecf20Sopenharmony_ci invalid_host_el1_vect // Error 32-bit EL1 1858c2ecf20Sopenharmony_ciSYM_CODE_END(__kvm_hyp_host_vector) 186