162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015-2018 - ARM Ltd 462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/arm-smccc.h> 862306a36Sopenharmony_ci#include <linux/linkage.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/alternative.h> 1162306a36Sopenharmony_ci#include <asm/assembler.h> 1262306a36Sopenharmony_ci#include <asm/cpufeature.h> 1362306a36Sopenharmony_ci#include <asm/kvm_arm.h> 1462306a36Sopenharmony_ci#include <asm/kvm_asm.h> 1562306a36Sopenharmony_ci#include <asm/mmu.h> 1662306a36Sopenharmony_ci#include <asm/spectre.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci.macro save_caller_saved_regs_vect 1962306a36Sopenharmony_ci /* x0 and x1 were saved in the vector entry */ 2062306a36Sopenharmony_ci stp x2, x3, [sp, #-16]! 2162306a36Sopenharmony_ci stp x4, x5, [sp, #-16]! 2262306a36Sopenharmony_ci stp x6, x7, [sp, #-16]! 2362306a36Sopenharmony_ci stp x8, x9, [sp, #-16]! 2462306a36Sopenharmony_ci stp x10, x11, [sp, #-16]! 2562306a36Sopenharmony_ci stp x12, x13, [sp, #-16]! 2662306a36Sopenharmony_ci stp x14, x15, [sp, #-16]! 2762306a36Sopenharmony_ci stp x16, x17, [sp, #-16]! 2862306a36Sopenharmony_ci.endm 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci.macro restore_caller_saved_regs_vect 3162306a36Sopenharmony_ci ldp x16, x17, [sp], #16 3262306a36Sopenharmony_ci ldp x14, x15, [sp], #16 3362306a36Sopenharmony_ci ldp x12, x13, [sp], #16 3462306a36Sopenharmony_ci ldp x10, x11, [sp], #16 3562306a36Sopenharmony_ci ldp x8, x9, [sp], #16 3662306a36Sopenharmony_ci ldp x6, x7, [sp], #16 3762306a36Sopenharmony_ci ldp x4, x5, [sp], #16 3862306a36Sopenharmony_ci ldp x2, x3, [sp], #16 3962306a36Sopenharmony_ci ldp x0, x1, [sp], #16 4062306a36Sopenharmony_ci.endm 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci .text 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciel1_sync: // Guest trapped into EL2 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci mrs x0, esr_el2 4762306a36Sopenharmony_ci ubfx x0, x0, #ESR_ELx_EC_SHIFT, #ESR_ELx_EC_WIDTH 4862306a36Sopenharmony_ci cmp x0, #ESR_ELx_EC_HVC64 4962306a36Sopenharmony_ci ccmp x0, #ESR_ELx_EC_HVC32, #4, ne 5062306a36Sopenharmony_ci b.ne el1_trap 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* 5362306a36Sopenharmony_ci * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1. 5462306a36Sopenharmony_ci * The workaround has already been applied on the host, 5562306a36Sopenharmony_ci * so let's quickly get back to the guest. We don't bother 5662306a36Sopenharmony_ci * restoring x1, as it can be clobbered anyway. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci ldr x1, [sp] // Guest's x0 5962306a36Sopenharmony_ci eor w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1 6062306a36Sopenharmony_ci cbz w1, wa_epilogue 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* ARM_SMCCC_ARCH_WORKAROUND_2 handling */ 6362306a36Sopenharmony_ci eor w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \ 6462306a36Sopenharmony_ci ARM_SMCCC_ARCH_WORKAROUND_2) 6562306a36Sopenharmony_ci cbz w1, wa_epilogue 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci eor w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_2 ^ \ 6862306a36Sopenharmony_ci ARM_SMCCC_ARCH_WORKAROUND_3) 6962306a36Sopenharmony_ci cbnz w1, el1_trap 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciwa_epilogue: 7262306a36Sopenharmony_ci mov x0, xzr 7362306a36Sopenharmony_ci add sp, sp, #16 7462306a36Sopenharmony_ci eret 7562306a36Sopenharmony_ci sb 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciel1_trap: 7862306a36Sopenharmony_ci get_vcpu_ptr x1, x0 7962306a36Sopenharmony_ci mov x0, #ARM_EXCEPTION_TRAP 8062306a36Sopenharmony_ci b __guest_exit 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciel1_irq: 8362306a36Sopenharmony_ciel1_fiq: 8462306a36Sopenharmony_ci get_vcpu_ptr x1, x0 8562306a36Sopenharmony_ci mov x0, #ARM_EXCEPTION_IRQ 8662306a36Sopenharmony_ci b __guest_exit 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ciel1_error: 8962306a36Sopenharmony_ci get_vcpu_ptr x1, x0 9062306a36Sopenharmony_ci mov x0, #ARM_EXCEPTION_EL1_SERROR 9162306a36Sopenharmony_ci b __guest_exit 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciel2_sync: 9462306a36Sopenharmony_ci /* Check for illegal exception return */ 9562306a36Sopenharmony_ci mrs x0, spsr_el2 9662306a36Sopenharmony_ci tbnz x0, #20, 1f 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci save_caller_saved_regs_vect 9962306a36Sopenharmony_ci stp x29, x30, [sp, #-16]! 10062306a36Sopenharmony_ci bl kvm_unexpected_el2_exception 10162306a36Sopenharmony_ci ldp x29, x30, [sp], #16 10262306a36Sopenharmony_ci restore_caller_saved_regs_vect 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci eret 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci1: 10762306a36Sopenharmony_ci /* Let's attempt a recovery from the illegal exception return */ 10862306a36Sopenharmony_ci get_vcpu_ptr x1, x0 10962306a36Sopenharmony_ci mov x0, #ARM_EXCEPTION_IL 11062306a36Sopenharmony_ci b __guest_exit 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciel2_error: 11462306a36Sopenharmony_ci save_caller_saved_regs_vect 11562306a36Sopenharmony_ci stp x29, x30, [sp, #-16]! 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci bl kvm_unexpected_el2_exception 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci ldp x29, x30, [sp], #16 12062306a36Sopenharmony_ci restore_caller_saved_regs_vect 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci eret 12362306a36Sopenharmony_ci sb 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci.macro invalid_vector label, target = __guest_exit_panic 12662306a36Sopenharmony_ci .align 2 12762306a36Sopenharmony_ciSYM_CODE_START_LOCAL(\label) 12862306a36Sopenharmony_ci b \target 12962306a36Sopenharmony_ciSYM_CODE_END(\label) 13062306a36Sopenharmony_ci.endm 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* None of these should ever happen */ 13362306a36Sopenharmony_ci invalid_vector el2t_sync_invalid 13462306a36Sopenharmony_ci invalid_vector el2t_irq_invalid 13562306a36Sopenharmony_ci invalid_vector el2t_fiq_invalid 13662306a36Sopenharmony_ci invalid_vector el2t_error_invalid 13762306a36Sopenharmony_ci invalid_vector el2h_irq_invalid 13862306a36Sopenharmony_ci invalid_vector el2h_fiq_invalid 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci .ltorg 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci .align 11 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci.macro check_preamble_length start, end 14562306a36Sopenharmony_ci/* kvm_patch_vector_branch() generates code that jumps over the preamble. */ 14662306a36Sopenharmony_ci.if ((\end-\start) != KVM_VECTOR_PREAMBLE) 14762306a36Sopenharmony_ci .error "KVM vector preamble length mismatch" 14862306a36Sopenharmony_ci.endif 14962306a36Sopenharmony_ci.endm 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci.macro valid_vect target 15262306a36Sopenharmony_ci .align 7 15362306a36Sopenharmony_ci661: 15462306a36Sopenharmony_ci esb 15562306a36Sopenharmony_ci stp x0, x1, [sp, #-16]! 15662306a36Sopenharmony_ci662: 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * spectre vectors __bp_harden_hyp_vecs generate br instructions at runtime 15962306a36Sopenharmony_ci * that jump at offset 8 at __kvm_hyp_vector. 16062306a36Sopenharmony_ci * As hyp .text is guarded section, it needs bti j. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci bti j 16362306a36Sopenharmony_ci b \target 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cicheck_preamble_length 661b, 662b 16662306a36Sopenharmony_ci.endm 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci.macro invalid_vect target 16962306a36Sopenharmony_ci .align 7 17062306a36Sopenharmony_ci661: 17162306a36Sopenharmony_ci nop 17262306a36Sopenharmony_ci stp x0, x1, [sp, #-16]! 17362306a36Sopenharmony_ci662: 17462306a36Sopenharmony_ci /* Check valid_vect */ 17562306a36Sopenharmony_ci bti j 17662306a36Sopenharmony_ci b \target 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cicheck_preamble_length 661b, 662b 17962306a36Sopenharmony_ci.endm 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciSYM_CODE_START(__kvm_hyp_vector) 18262306a36Sopenharmony_ci invalid_vect el2t_sync_invalid // Synchronous EL2t 18362306a36Sopenharmony_ci invalid_vect el2t_irq_invalid // IRQ EL2t 18462306a36Sopenharmony_ci invalid_vect el2t_fiq_invalid // FIQ EL2t 18562306a36Sopenharmony_ci invalid_vect el2t_error_invalid // Error EL2t 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci valid_vect el2_sync // Synchronous EL2h 18862306a36Sopenharmony_ci invalid_vect el2h_irq_invalid // IRQ EL2h 18962306a36Sopenharmony_ci invalid_vect el2h_fiq_invalid // FIQ EL2h 19062306a36Sopenharmony_ci valid_vect el2_error // Error EL2h 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci valid_vect el1_sync // Synchronous 64-bit EL1 19362306a36Sopenharmony_ci valid_vect el1_irq // IRQ 64-bit EL1 19462306a36Sopenharmony_ci valid_vect el1_fiq // FIQ 64-bit EL1 19562306a36Sopenharmony_ci valid_vect el1_error // Error 64-bit EL1 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci valid_vect el1_sync // Synchronous 32-bit EL1 19862306a36Sopenharmony_ci valid_vect el1_irq // IRQ 32-bit EL1 19962306a36Sopenharmony_ci valid_vect el1_fiq // FIQ 32-bit EL1 20062306a36Sopenharmony_ci valid_vect el1_error // Error 32-bit EL1 20162306a36Sopenharmony_ciSYM_CODE_END(__kvm_hyp_vector) 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci.macro spectrev2_smccc_wa1_smc 20462306a36Sopenharmony_ci sub sp, sp, #(8 * 4) 20562306a36Sopenharmony_ci stp x2, x3, [sp, #(8 * 0)] 20662306a36Sopenharmony_ci stp x0, x1, [sp, #(8 * 2)] 20762306a36Sopenharmony_ci alternative_cb ARM64_ALWAYS_SYSTEM, spectre_bhb_patch_wa3 20862306a36Sopenharmony_ci /* Patched to mov WA3 when supported */ 20962306a36Sopenharmony_ci mov w0, #ARM_SMCCC_ARCH_WORKAROUND_1 21062306a36Sopenharmony_ci alternative_cb_end 21162306a36Sopenharmony_ci smc #0 21262306a36Sopenharmony_ci ldp x2, x3, [sp, #(8 * 0)] 21362306a36Sopenharmony_ci add sp, sp, #(8 * 2) 21462306a36Sopenharmony_ci.endm 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci.macro hyp_ventry indirect, spectrev2 21762306a36Sopenharmony_ci .align 7 21862306a36Sopenharmony_ci1: esb 21962306a36Sopenharmony_ci .if \spectrev2 != 0 22062306a36Sopenharmony_ci spectrev2_smccc_wa1_smc 22162306a36Sopenharmony_ci .else 22262306a36Sopenharmony_ci stp x0, x1, [sp, #-16]! 22362306a36Sopenharmony_ci mitigate_spectre_bhb_loop x0 22462306a36Sopenharmony_ci mitigate_spectre_bhb_clear_insn 22562306a36Sopenharmony_ci .endif 22662306a36Sopenharmony_ci .if \indirect != 0 22762306a36Sopenharmony_ci alternative_cb ARM64_ALWAYS_SYSTEM, kvm_patch_vector_branch 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * For ARM64_SPECTRE_V3A configurations, these NOPs get replaced with: 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * movz x0, #(addr & 0xffff) 23262306a36Sopenharmony_ci * movk x0, #((addr >> 16) & 0xffff), lsl #16 23362306a36Sopenharmony_ci * movk x0, #((addr >> 32) & 0xffff), lsl #32 23462306a36Sopenharmony_ci * br x0 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * Where: 23762306a36Sopenharmony_ci * addr = kern_hyp_va(__kvm_hyp_vector) + vector-offset + KVM_VECTOR_PREAMBLE. 23862306a36Sopenharmony_ci * See kvm_patch_vector_branch for details. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci nop 24162306a36Sopenharmony_ci nop 24262306a36Sopenharmony_ci nop 24362306a36Sopenharmony_ci nop 24462306a36Sopenharmony_ci alternative_cb_end 24562306a36Sopenharmony_ci .endif 24662306a36Sopenharmony_ci b __kvm_hyp_vector + (1b - 0b + KVM_VECTOR_PREAMBLE) 24762306a36Sopenharmony_ci.endm 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci.macro generate_vectors indirect, spectrev2 25062306a36Sopenharmony_ci0: 25162306a36Sopenharmony_ci .rept 16 25262306a36Sopenharmony_ci hyp_ventry \indirect, \spectrev2 25362306a36Sopenharmony_ci .endr 25462306a36Sopenharmony_ci .org 0b + SZ_2K // Safety measure 25562306a36Sopenharmony_ci.endm 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci .align 11 25862306a36Sopenharmony_ciSYM_CODE_START(__bp_harden_hyp_vecs) 25962306a36Sopenharmony_ci generate_vectors indirect = 0, spectrev2 = 1 // HYP_VECTOR_SPECTRE_DIRECT 26062306a36Sopenharmony_ci generate_vectors indirect = 1, spectrev2 = 0 // HYP_VECTOR_INDIRECT 26162306a36Sopenharmony_ci generate_vectors indirect = 1, spectrev2 = 1 // HYP_VECTOR_SPECTRE_INDIRECT 26262306a36Sopenharmony_ci1: .org __bp_harden_hyp_vecs + __BP_HARDEN_HYP_VECS_SZ 26362306a36Sopenharmony_ci .org 1b 26462306a36Sopenharmony_ciSYM_CODE_END(__bp_harden_hyp_vecs) 265