12b28162cSMarc Zyngier/* 22b28162cSMarc Zyngier * Copyright (C) 2015 - ARM Ltd 32b28162cSMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com> 42b28162cSMarc Zyngier * 52b28162cSMarc Zyngier * This program is free software; you can redistribute it and/or modify 62b28162cSMarc Zyngier * it under the terms of the GNU General Public License version 2 as 72b28162cSMarc Zyngier * published by the Free Software Foundation. 82b28162cSMarc Zyngier * 92b28162cSMarc Zyngier * This program is distributed in the hope that it will be useful, 102b28162cSMarc Zyngier * but WITHOUT ANY WARRANTY; without even the implied warranty of 112b28162cSMarc Zyngier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 122b28162cSMarc Zyngier * GNU General Public License for more details. 132b28162cSMarc Zyngier * 142b28162cSMarc Zyngier * You should have received a copy of the GNU General Public License 152b28162cSMarc Zyngier * along with this program. If not, see <http://www.gnu.org/licenses/>. 162b28162cSMarc Zyngier */ 172b28162cSMarc Zyngier 182b28162cSMarc Zyngier#include <linux/linkage.h> 192b28162cSMarc Zyngier 202b28162cSMarc Zyngier#include <asm/alternative.h> 212b28162cSMarc Zyngier#include <asm/assembler.h> 222b28162cSMarc Zyngier#include <asm/asm-offsets.h> 232b28162cSMarc Zyngier#include <asm/cpufeature.h> 242b28162cSMarc Zyngier#include <asm/kvm_arm.h> 252b28162cSMarc Zyngier#include <asm/kvm_asm.h> 262b28162cSMarc Zyngier#include <asm/kvm_mmu.h> 272b28162cSMarc Zyngier 282b28162cSMarc Zyngier .text 292b28162cSMarc Zyngier .pushsection .hyp.text, "ax" 302b28162cSMarc Zyngier 312b28162cSMarc Zyngier.macro save_x0_to_x3 322b28162cSMarc Zyngier stp x0, x1, [sp, #-16]! 332b28162cSMarc Zyngier stp x2, x3, [sp, #-16]! 342b28162cSMarc Zyngier.endm 352b28162cSMarc Zyngier 362b28162cSMarc Zyngier.macro restore_x0_to_x3 372b28162cSMarc Zyngier ldp x2, x3, [sp], #16 382b28162cSMarc Zyngier ldp x0, x1, [sp], #16 392b28162cSMarc Zyngier.endm 402b28162cSMarc Zyngier 412b28162cSMarc Zyngierel1_sync: // Guest trapped into EL2 422b28162cSMarc Zyngier save_x0_to_x3 432b28162cSMarc Zyngier 442b28162cSMarc Zyngier mrs x1, esr_el2 452b28162cSMarc Zyngier lsr x2, x1, #ESR_ELx_EC_SHIFT 462b28162cSMarc Zyngier 472b28162cSMarc Zyngier cmp x2, #ESR_ELx_EC_HVC64 482b28162cSMarc Zyngier b.ne el1_trap 492b28162cSMarc Zyngier 502b28162cSMarc Zyngier mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest 512b28162cSMarc Zyngier cbnz x3, el1_trap // called HVC 522b28162cSMarc Zyngier 532b28162cSMarc Zyngier /* Here, we're pretty sure the host called HVC. */ 542b28162cSMarc Zyngier restore_x0_to_x3 552b28162cSMarc Zyngier 562b28162cSMarc Zyngier /* Check for __hyp_get_vectors */ 572b28162cSMarc Zyngier cbnz x0, 1f 582b28162cSMarc Zyngier mrs x0, vbar_el2 592b28162cSMarc Zyngier b 2f 602b28162cSMarc Zyngier 612b28162cSMarc Zyngier1: stp lr, xzr, [sp, #-16]! 622b28162cSMarc Zyngier 632b28162cSMarc Zyngier /* 642b28162cSMarc Zyngier * Compute the function address in EL2, and shuffle the parameters. 652b28162cSMarc Zyngier */ 662b28162cSMarc Zyngier kern_hyp_va x0 672b28162cSMarc Zyngier mov lr, x0 682b28162cSMarc Zyngier mov x0, x1 692b28162cSMarc Zyngier mov x1, x2 702b28162cSMarc Zyngier mov x2, x3 712b28162cSMarc Zyngier blr lr 722b28162cSMarc Zyngier 732b28162cSMarc Zyngier ldp lr, xzr, [sp], #16 742b28162cSMarc Zyngier2: eret 752b28162cSMarc Zyngier 762b28162cSMarc Zyngierel1_trap: 772b28162cSMarc Zyngier /* 782b28162cSMarc Zyngier * x1: ESR 792b28162cSMarc Zyngier * x2: ESR_EC 802b28162cSMarc Zyngier */ 812b28162cSMarc Zyngier 822b28162cSMarc Zyngier /* Guest accessed VFP/SIMD registers, save host, restore Guest */ 832b28162cSMarc Zyngier cmp x2, #ESR_ELx_EC_FP_ASIMD 842b28162cSMarc Zyngier b.eq __fpsimd_guest_restore 852b28162cSMarc Zyngier 862b28162cSMarc Zyngier cmp x2, #ESR_ELx_EC_DABT_LOW 872b28162cSMarc Zyngier mov x0, #ESR_ELx_EC_IABT_LOW 882b28162cSMarc Zyngier ccmp x2, x0, #4, ne 892b28162cSMarc Zyngier b.ne 1f // Not an abort we care about 902b28162cSMarc Zyngier 912b28162cSMarc Zyngier /* This is an abort. Check for permission fault */ 922b28162cSMarc Zyngieralternative_if_not ARM64_WORKAROUND_834220 932b28162cSMarc Zyngier and x2, x1, #ESR_ELx_FSC_TYPE 942b28162cSMarc Zyngier cmp x2, #FSC_PERM 952b28162cSMarc Zyngier b.ne 1f // Not a permission fault 962b28162cSMarc Zyngieralternative_else 972b28162cSMarc Zyngier nop // Use the permission fault path to 982b28162cSMarc Zyngier nop // check for a valid S1 translation, 992b28162cSMarc Zyngier nop // regardless of the ESR value. 1002b28162cSMarc Zyngieralternative_endif 1012b28162cSMarc Zyngier 1022b28162cSMarc Zyngier /* 1032b28162cSMarc Zyngier * Check for Stage-1 page table walk, which is guaranteed 1042b28162cSMarc Zyngier * to give a valid HPFAR_EL2. 1052b28162cSMarc Zyngier */ 1062b28162cSMarc Zyngier tbnz x1, #7, 1f // S1PTW is set 1072b28162cSMarc Zyngier 1082b28162cSMarc Zyngier /* Preserve PAR_EL1 */ 1092b28162cSMarc Zyngier mrs x3, par_el1 1102b28162cSMarc Zyngier stp x3, xzr, [sp, #-16]! 1112b28162cSMarc Zyngier 1122b28162cSMarc Zyngier /* 1132b28162cSMarc Zyngier * Permission fault, HPFAR_EL2 is invalid. 1142b28162cSMarc Zyngier * Resolve the IPA the hard way using the guest VA. 1152b28162cSMarc Zyngier * Stage-1 translation already validated the memory access rights. 1162b28162cSMarc Zyngier * As such, we can use the EL1 translation regime, and don't have 1172b28162cSMarc Zyngier * to distinguish between EL0 and EL1 access. 1182b28162cSMarc Zyngier */ 1192b28162cSMarc Zyngier mrs x2, far_el2 1202b28162cSMarc Zyngier at s1e1r, x2 1212b28162cSMarc Zyngier isb 1222b28162cSMarc Zyngier 1232b28162cSMarc Zyngier /* Read result */ 1242b28162cSMarc Zyngier mrs x3, par_el1 1252b28162cSMarc Zyngier ldp x0, xzr, [sp], #16 // Restore PAR_EL1 from the stack 1262b28162cSMarc Zyngier msr par_el1, x0 1272b28162cSMarc Zyngier tbnz x3, #0, 3f // Bail out if we failed the translation 1282b28162cSMarc Zyngier ubfx x3, x3, #12, #36 // Extract IPA 1292b28162cSMarc Zyngier lsl x3, x3, #4 // and present it like HPFAR 1302b28162cSMarc Zyngier b 2f 1312b28162cSMarc Zyngier 1322b28162cSMarc Zyngier1: mrs x3, hpfar_el2 1332b28162cSMarc Zyngier mrs x2, far_el2 1342b28162cSMarc Zyngier 1352b28162cSMarc Zyngier2: mrs x0, tpidr_el2 1362b28162cSMarc Zyngier str w1, [x0, #VCPU_ESR_EL2] 1372b28162cSMarc Zyngier str x2, [x0, #VCPU_FAR_EL2] 1382b28162cSMarc Zyngier str x3, [x0, #VCPU_HPFAR_EL2] 1392b28162cSMarc Zyngier 1402b28162cSMarc Zyngier mov x1, #ARM_EXCEPTION_TRAP 1412b28162cSMarc Zyngier b __guest_exit 1422b28162cSMarc Zyngier 1432b28162cSMarc Zyngier /* 1442b28162cSMarc Zyngier * Translation failed. Just return to the guest and 1452b28162cSMarc Zyngier * let it fault again. Another CPU is probably playing 1462b28162cSMarc Zyngier * behind our back. 1472b28162cSMarc Zyngier */ 1482b28162cSMarc Zyngier3: restore_x0_to_x3 1492b28162cSMarc Zyngier 1502b28162cSMarc Zyngier eret 1512b28162cSMarc Zyngier 1522b28162cSMarc Zyngierel1_irq: 1532b28162cSMarc Zyngier save_x0_to_x3 1542b28162cSMarc Zyngier mrs x0, tpidr_el2 1552b28162cSMarc Zyngier mov x1, #ARM_EXCEPTION_IRQ 1562b28162cSMarc Zyngier b __guest_exit 1572b28162cSMarc Zyngier 15853fd5b64SMarc ZyngierENTRY(__hyp_do_panic) 15953fd5b64SMarc Zyngier mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ 16053fd5b64SMarc Zyngier PSR_MODE_EL1h) 16153fd5b64SMarc Zyngier msr spsr_el2, lr 16253fd5b64SMarc Zyngier ldr lr, =panic 16353fd5b64SMarc Zyngier msr elr_el2, lr 16453fd5b64SMarc Zyngier eret 16553fd5b64SMarc ZyngierENDPROC(__hyp_do_panic) 16653fd5b64SMarc Zyngier 16753fd5b64SMarc Zyngier.macro invalid_vector label, target = __hyp_panic 1682b28162cSMarc Zyngier .align 2 1692b28162cSMarc Zyngier\label: 1702b28162cSMarc Zyngier b \target 1712b28162cSMarc ZyngierENDPROC(\label) 1722b28162cSMarc Zyngier.endm 1732b28162cSMarc Zyngier 1742b28162cSMarc Zyngier /* None of these should ever happen */ 1752b28162cSMarc Zyngier invalid_vector el2t_sync_invalid 1762b28162cSMarc Zyngier invalid_vector el2t_irq_invalid 1772b28162cSMarc Zyngier invalid_vector el2t_fiq_invalid 1782b28162cSMarc Zyngier invalid_vector el2t_error_invalid 1792b28162cSMarc Zyngier invalid_vector el2h_sync_invalid 1802b28162cSMarc Zyngier invalid_vector el2h_irq_invalid 1812b28162cSMarc Zyngier invalid_vector el2h_fiq_invalid 1822b28162cSMarc Zyngier invalid_vector el2h_error_invalid 1832b28162cSMarc Zyngier invalid_vector el1_sync_invalid 1842b28162cSMarc Zyngier invalid_vector el1_irq_invalid 1852b28162cSMarc Zyngier invalid_vector el1_fiq_invalid 1862b28162cSMarc Zyngier invalid_vector el1_error_invalid 1872b28162cSMarc Zyngier 1882b28162cSMarc Zyngier .ltorg 1892b28162cSMarc Zyngier 1902b28162cSMarc Zyngier .align 11 1912b28162cSMarc Zyngier 192*044ac37dSMarc Zyngier .weak __kvm_hyp_vector 193*044ac37dSMarc ZyngierENTRY(__kvm_hyp_vector) 1942b28162cSMarc ZyngierENTRY(__hyp_vector) 1952b28162cSMarc Zyngier ventry el2t_sync_invalid // Synchronous EL2t 1962b28162cSMarc Zyngier ventry el2t_irq_invalid // IRQ EL2t 1972b28162cSMarc Zyngier ventry el2t_fiq_invalid // FIQ EL2t 1982b28162cSMarc Zyngier ventry el2t_error_invalid // Error EL2t 1992b28162cSMarc Zyngier 2002b28162cSMarc Zyngier ventry el2h_sync_invalid // Synchronous EL2h 2012b28162cSMarc Zyngier ventry el2h_irq_invalid // IRQ EL2h 2022b28162cSMarc Zyngier ventry el2h_fiq_invalid // FIQ EL2h 2032b28162cSMarc Zyngier ventry el2h_error_invalid // Error EL2h 2042b28162cSMarc Zyngier 2052b28162cSMarc Zyngier ventry el1_sync // Synchronous 64-bit EL1 2062b28162cSMarc Zyngier ventry el1_irq // IRQ 64-bit EL1 2072b28162cSMarc Zyngier ventry el1_fiq_invalid // FIQ 64-bit EL1 2082b28162cSMarc Zyngier ventry el1_error_invalid // Error 64-bit EL1 2092b28162cSMarc Zyngier 2102b28162cSMarc Zyngier ventry el1_sync // Synchronous 32-bit EL1 2112b28162cSMarc Zyngier ventry el1_irq // IRQ 32-bit EL1 2122b28162cSMarc Zyngier ventry el1_fiq_invalid // FIQ 32-bit EL1 2132b28162cSMarc Zyngier ventry el1_error_invalid // Error 32-bit EL1 2142b28162cSMarc ZyngierENDPROC(__hyp_vector) 215*044ac37dSMarc ZyngierENDPROC(__kvm_hyp_vector) 216