123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- #include <linux/kvm_host.h>
- #include <asm/kvm_emulate.h>
- #include <asm/esr.h>
- static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
- {
- unsigned long cpsr = *vcpu_cpsr(vcpu);
- bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
- u64 esr = 0;
- kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC);
- vcpu_write_sys_reg(vcpu, addr, FAR_EL1);
-
- if (kvm_vcpu_trap_il_is32bit(vcpu))
- esr |= ESR_ELx_IL;
-
- if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t)
- esr |= (ESR_ELx_EC_IABT_LOW << ESR_ELx_EC_SHIFT);
- else
- esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT);
- if (!is_iabt)
- esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
- vcpu_write_sys_reg(vcpu, esr | ESR_ELx_FSC_EXTABT, ESR_EL1);
- }
- static void inject_undef64(struct kvm_vcpu *vcpu)
- {
- u64 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
- kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC);
-
- if (kvm_vcpu_trap_il_is32bit(vcpu))
- esr |= ESR_ELx_IL;
- vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
- }
- #define DFSR_FSC_EXTABT_LPAE 0x10
- #define DFSR_FSC_EXTABT_nLPAE 0x08
- #define DFSR_LPAE BIT(9)
- #define TTBCR_EAE BIT(31)
- static void inject_undef32(struct kvm_vcpu *vcpu)
- {
- kvm_pend_exception(vcpu, EXCEPT_AA32_UND);
- }
- static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt, u32 addr)
- {
- u64 far;
- u32 fsr;
-
- if (vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE) {
- fsr = DFSR_LPAE | DFSR_FSC_EXTABT_LPAE;
- } else {
-
- fsr = DFSR_FSC_EXTABT_nLPAE;
- }
- far = vcpu_read_sys_reg(vcpu, FAR_EL1);
- if (is_pabt) {
- kvm_pend_exception(vcpu, EXCEPT_AA32_IABT);
- far &= GENMASK(31, 0);
- far |= (u64)addr << 32;
- vcpu_write_sys_reg(vcpu, fsr, IFSR32_EL2);
- } else {
- kvm_pend_exception(vcpu, EXCEPT_AA32_DABT);
- far &= GENMASK(63, 32);
- far |= addr;
- vcpu_write_sys_reg(vcpu, fsr, ESR_EL1);
- }
- vcpu_write_sys_reg(vcpu, far, FAR_EL1);
- }
- void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
- {
- if (vcpu_el1_is_32bit(vcpu))
- inject_abt32(vcpu, false, addr);
- else
- inject_abt64(vcpu, false, addr);
- }
- void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
- {
- if (vcpu_el1_is_32bit(vcpu))
- inject_abt32(vcpu, true, addr);
- else
- inject_abt64(vcpu, true, addr);
- }
- void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
- {
- unsigned long addr, esr;
- addr = kvm_vcpu_get_fault_ipa(vcpu);
- addr |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
- if (kvm_vcpu_trap_is_iabt(vcpu))
- kvm_inject_pabt(vcpu, addr);
- else
- kvm_inject_dabt(vcpu, addr);
-
- if (vcpu_el1_is_32bit(vcpu) &&
- !(vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE))
- return;
- esr = vcpu_read_sys_reg(vcpu, ESR_EL1);
- esr &= ~GENMASK_ULL(5, 0);
- vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
- }
- void kvm_inject_undefined(struct kvm_vcpu *vcpu)
- {
- if (vcpu_el1_is_32bit(vcpu))
- inject_undef32(vcpu);
- else
- inject_undef64(vcpu);
- }
- void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 esr)
- {
- vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK);
- *vcpu_hcr(vcpu) |= HCR_VSE;
- }
- void kvm_inject_vabt(struct kvm_vcpu *vcpu)
- {
- kvm_set_sei_esr(vcpu, ESR_ELx_ISV);
- }
|