1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Guest PC manipulation helpers 4 * 5 * Copyright (C) 2012,2013 - ARM Ltd 6 * Copyright (C) 2020 - Google LLC 7 * Author: Marc Zyngier <maz@kernel.org> 8 */ 9 10 #ifndef __ARM64_KVM_HYP_ADJUST_PC_H__ 11 #define __ARM64_KVM_HYP_ADJUST_PC_H__ 12 13 #include <asm/kvm_emulate.h> 14 #include <asm/kvm_host.h> 15 16 #ifdef __KVM_NVHE_HYPERVISOR__ 17 #include <nvhe/pkvm.h> 18 19 /* Under pKVM a host vCPU's ->kvm is host-writable. */ 20 static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu) 21 { 22 if (is_protected_kvm_enabled()) 23 return pkvm_vcpu_get_kvm(vcpu); 24 25 return kern_hyp_va(vcpu->kvm); 26 } 27 28 static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm) 29 { 30 if (is_protected_kvm_enabled()) 31 pkvm_vcpu_put_kvm(vcpu, kvm); 32 } 33 #else 34 static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu) 35 { 36 return vcpu->kvm; 37 } 38 39 static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm) 40 { 41 } 42 #endif 43 44 static inline void kvm_skip_instr(struct kvm_vcpu *vcpu) 45 { 46 if (vcpu_mode_is_32bit(vcpu)) { 47 kvm_skip_instr32(vcpu); 48 } else { 49 *vcpu_pc(vcpu) += 4; 50 *vcpu_cpsr(vcpu) &= ~PSR_BTYPE_MASK; 51 } 52 53 /* advance the singlestep state machine */ 54 *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS; 55 } 56 57 /* 58 * Skip an instruction which has been emulated at hyp while most guest sysregs 59 * are live. 60 */ 61 static inline void __kvm_skip_instr(struct kvm_vcpu *vcpu) 62 { 63 *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR); 64 *vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR); 65 66 kvm_skip_instr(vcpu); 67 68 write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR); 69 write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR); 70 } 71 72 /* 73 * Skip an instruction while host sysregs are live. 74 * Assumes host is always 64-bit. 75 */ 76 static inline void kvm_skip_host_instr(void) 77 { 78 write_sysreg_el2(read_sysreg_el2(SYS_ELR) + 4, SYS_ELR); 79 } 80 81 /* 82 * Under pKVM, the vCPU __kvm_adjust_pc() adjusts for @vcpu (NULL leaves the 83 * request on @vcpu for its next entry), and the copy of the consumed 84 * PC_UPDATE_REQ back to @vcpu. 85 */ 86 #ifdef __KVM_NVHE_HYPERVISOR__ 87 struct kvm_vcpu *kvm_adjust_pc_get(struct kvm_vcpu *vcpu); 88 void kvm_adjust_pc_put(struct kvm_vcpu *vcpu, struct kvm_vcpu *target); 89 #else 90 static inline struct kvm_vcpu *kvm_adjust_pc_get(struct kvm_vcpu *vcpu) 91 { 92 return vcpu; 93 } 94 95 static inline void kvm_adjust_pc_put(struct kvm_vcpu *vcpu, 96 struct kvm_vcpu *target) 97 { 98 } 99 #endif 100 101 #endif 102