Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: arm64: Handle DABT caused by LS64* instructions on unsupported memory

If FEAT_LS64WB not supported, FEAT_LS64* instructions only support
to access Device/Uncacheable memory, otherwise a data abort for
unsupported Exclusive or atomic access (0x35, UAoEF) is generated
per spec. It's implementation defined whether the target exception
level is routed and is possible to implemented as route to EL2 on a
VHE VM according to DDI0487L.b Section C3.2.6 Single-copy atomic
64-byte load/store.

If it's implemented as generate the DABT to the final enabled stage
(stage-2), inject the UAoEF back to the guest after checking the
memslot is valid.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Oliver Upton <oupton@kernel.org>
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com>
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Yicong Yang and committed by
Will Deacon
2937aeec 902eebac

+56 -1
+8
arch/arm64/include/asm/esr.h
··· 124 124 #define ESR_ELx_FSC_SEA_TTW(n) (0x14 + (n)) 125 125 #define ESR_ELx_FSC_SECC (0x18) 126 126 #define ESR_ELx_FSC_SECC_TTW(n) (0x1c + (n)) 127 + #define ESR_ELx_FSC_EXCL_ATOMIC (0x35) 127 128 #define ESR_ELx_FSC_ADDRSZ (0x00) 128 129 129 130 /* ··· 487 486 (esr == ESR_ELx_FSC_ACCESS_L(2)) || 488 487 (esr == ESR_ELx_FSC_ACCESS_L(1)) || 489 488 (esr == ESR_ELx_FSC_ACCESS_L(0)); 489 + } 490 + 491 + static inline bool esr_fsc_is_excl_atomic_fault(unsigned long esr) 492 + { 493 + esr = esr & ESR_ELx_FSC; 494 + 495 + return esr == ESR_ELx_FSC_EXCL_ATOMIC; 490 496 } 491 497 492 498 static inline bool esr_fsc_is_addr_sz_fault(unsigned long esr)
+1
arch/arm64/include/asm/kvm_emulate.h
··· 47 47 void kvm_inject_undefined(struct kvm_vcpu *vcpu); 48 48 int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr); 49 49 int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr); 50 + int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr); 50 51 void kvm_inject_size_fault(struct kvm_vcpu *vcpu); 51 52 52 53 static inline int kvm_inject_sea_dabt(struct kvm_vcpu *vcpu, u64 addr)
+34
arch/arm64/kvm/inject_fault.c
··· 253 253 return 1; 254 254 } 255 255 256 + static int kvm_inject_nested_excl_atomic(struct kvm_vcpu *vcpu, u64 addr) 257 + { 258 + u64 esr = FIELD_PREP(ESR_ELx_EC_MASK, ESR_ELx_EC_DABT_LOW) | 259 + FIELD_PREP(ESR_ELx_FSC, ESR_ELx_FSC_EXCL_ATOMIC) | 260 + ESR_ELx_IL; 261 + 262 + vcpu_write_sys_reg(vcpu, addr, FAR_EL2); 263 + return kvm_inject_nested_sync(vcpu, esr); 264 + } 265 + 266 + /** 267 + * kvm_inject_dabt_excl_atomic - inject a data abort for unsupported exclusive 268 + * or atomic access 269 + * @vcpu: The VCPU to receive the data abort 270 + * @addr: The address to report in the DFAR 271 + * 272 + * It is assumed that this code is called from the VCPU thread and that the 273 + * VCPU therefore is not currently executing guest code. 274 + */ 275 + int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr) 276 + { 277 + u64 esr; 278 + 279 + if (is_nested_ctxt(vcpu) && (vcpu_read_sys_reg(vcpu, HCR_EL2) & HCR_VM)) 280 + return kvm_inject_nested_excl_atomic(vcpu, addr); 281 + 282 + __kvm_inject_sea(vcpu, false, addr); 283 + esr = vcpu_read_sys_reg(vcpu, exception_esr_elx(vcpu)); 284 + esr &= ~ESR_ELx_FSC; 285 + esr |= ESR_ELx_FSC_EXCL_ATOMIC; 286 + vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu)); 287 + return 1; 288 + } 289 + 256 290 void kvm_inject_size_fault(struct kvm_vcpu *vcpu) 257 291 { 258 292 unsigned long addr, esr;
+13 -1
arch/arm64/kvm/mmu.c
··· 1845 1845 return ret; 1846 1846 } 1847 1847 1848 + /* 1849 + * Guest performs atomic/exclusive operations on memory with unsupported 1850 + * attributes (e.g. ld64b/st64b on normal memory when no FEAT_LS64WB) 1851 + * and trigger the exception here. Since the memslot is valid, inject 1852 + * the fault back to the guest. 1853 + */ 1854 + if (esr_fsc_is_excl_atomic_fault(kvm_vcpu_get_esr(vcpu))) { 1855 + kvm_inject_dabt_excl_atomic(vcpu, kvm_vcpu_get_hfar(vcpu)); 1856 + return 1; 1857 + } 1858 + 1848 1859 if (nested) 1849 1860 adjust_nested_fault_perms(nested, &prot, &writable); 1850 1861 ··· 2093 2082 /* Check the stage-2 fault is trans. fault or write fault */ 2094 2083 if (!esr_fsc_is_translation_fault(esr) && 2095 2084 !esr_fsc_is_permission_fault(esr) && 2096 - !esr_fsc_is_access_flag_fault(esr)) { 2085 + !esr_fsc_is_access_flag_fault(esr) && 2086 + !esr_fsc_is_excl_atomic_fault(esr)) { 2097 2087 kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n", 2098 2088 kvm_vcpu_trap_get_class(vcpu), 2099 2089 (unsigned long)kvm_vcpu_trap_get_fault(vcpu),