File tree Expand file tree Collapse file tree 6 files changed +73
-18
lines changed Expand file tree Collapse file tree 6 files changed +73
-18
lines changed Original file line number Diff line number Diff line change @@ -482,6 +482,28 @@ static inline bool esr_fsc_is_addr_sz_fault(unsigned long esr)
482482 (esr == ESR_ELx_FSC_ADDRSZ_L (-1 ));
483483}
484484
485+ static inline bool esr_fsc_is_sea_ttw (unsigned long esr )
486+ {
487+ esr = esr & ESR_ELx_FSC ;
488+
489+ return (esr == ESR_ELx_FSC_SEA_TTW (3 )) ||
490+ (esr == ESR_ELx_FSC_SEA_TTW (2 )) ||
491+ (esr == ESR_ELx_FSC_SEA_TTW (1 )) ||
492+ (esr == ESR_ELx_FSC_SEA_TTW (0 )) ||
493+ (esr == ESR_ELx_FSC_SEA_TTW (-1 ));
494+ }
495+
496+ static inline bool esr_fsc_is_secc_ttw (unsigned long esr )
497+ {
498+ esr = esr & ESR_ELx_FSC ;
499+
500+ return (esr == ESR_ELx_FSC_SECC_TTW (3 )) ||
501+ (esr == ESR_ELx_FSC_SECC_TTW (2 )) ||
502+ (esr == ESR_ELx_FSC_SECC_TTW (1 )) ||
503+ (esr == ESR_ELx_FSC_SECC_TTW (0 )) ||
504+ (esr == ESR_ELx_FSC_SECC_TTW (-1 ));
505+ }
506+
485507/* Indicate whether ESR.EC==0x1A is for an ERETAx instruction */
486508static inline bool esr_iss_is_eretax (unsigned long esr )
487509{
Original file line number Diff line number Diff line change @@ -307,6 +307,9 @@ static __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu
307307{
308308 u64 hpfar = vcpu -> arch .fault .hpfar_el2 ;
309309
310+ if (unlikely (!(hpfar & HPFAR_EL2_NS )))
311+ return INVALID_GPA ;
312+
310313 return FIELD_GET (HPFAR_EL2_FIPA , hpfar ) << 12 ;
311314}
312315
Original file line number Diff line number Diff line change 1414 * Was this synchronous external abort a RAS notification?
1515 * Returns '0' for errors handled by some RAS subsystem, or -ENOENT.
1616 */
17- static inline int kvm_handle_guest_sea (phys_addr_t addr , u64 esr )
17+ static inline int kvm_handle_guest_sea (void )
1818{
1919 /* apei_claim_sea(NULL) expects to mask interrupts itself */
2020 lockdep_assert_irqs_enabled ();
Original file line number Diff line number Diff line change 1212#include <asm/kvm_hyp.h>
1313#include <asm/kvm_mmu.h>
1414
15+ static inline bool __fault_safe_to_translate (u64 esr )
16+ {
17+ u64 fsc = esr & ESR_ELx_FSC ;
18+
19+ if (esr_fsc_is_sea_ttw (esr ) || esr_fsc_is_secc_ttw (esr ))
20+ return false;
21+
22+ return !(fsc == ESR_ELx_FSC_EXTABT && (esr & ESR_ELx_FnV ));
23+ }
24+
1525static inline bool __translate_far_to_hpfar (u64 far , u64 * hpfar )
1626{
1727 int ret ;
@@ -71,17 +81,23 @@ static inline bool __hpfar_valid(u64 esr)
7181
7282static inline bool __get_fault_info (u64 esr , struct kvm_vcpu_fault_info * fault )
7383{
74- u64 hpfar , far ;
84+ u64 hpfar ;
7585
76- far = read_sysreg_el2 (SYS_FAR );
86+ fault -> far_el2 = read_sysreg_el2 (SYS_FAR );
87+ fault -> hpfar_el2 = 0 ;
7788
7889 if (__hpfar_valid (esr ))
7990 hpfar = read_sysreg (hpfar_el2 );
80- else if (!__translate_far_to_hpfar (far , & hpfar ))
91+ else if (unlikely (!__fault_safe_to_translate (esr )))
92+ return true;
93+ else if (!__translate_far_to_hpfar (fault -> far_el2 , & hpfar ))
8194 return false;
8295
83- fault -> far_el2 = far ;
84- fault -> hpfar_el2 = hpfar ;
96+ /*
97+ * Hijack HPFAR_EL2.NS (RES0 in Non-secure) to indicate a valid
98+ * HPFAR value.
99+ */
100+ fault -> hpfar_el2 = hpfar | HPFAR_EL2_NS ;
85101 return true;
86102}
87103
Original file line number Diff line number Diff line change @@ -578,7 +578,14 @@ void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt)
578578 return ;
579579 }
580580
581+
582+ /*
583+ * Yikes, we couldn't resolve the fault IPA. This should reinject an
584+ * abort into the host when we figure out how to do that.
585+ */
586+ BUG_ON (!(fault .hpfar_el2 & HPFAR_EL2_NS ));
581587 addr = FIELD_GET (HPFAR_EL2_FIPA , fault .hpfar_el2 ) << 12 ;
588+
582589 ret = host_stage2_idmap (addr );
583590 BUG_ON (ret && ret != - EAGAIN );
584591}
Original file line number Diff line number Diff line change @@ -1794,9 +1794,28 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
17941794 gfn_t gfn ;
17951795 int ret , idx ;
17961796
1797+ /* Synchronous External Abort? */
1798+ if (kvm_vcpu_abt_issea (vcpu )) {
1799+ /*
1800+ * For RAS the host kernel may handle this abort.
1801+ * There is no need to pass the error into the guest.
1802+ */
1803+ if (kvm_handle_guest_sea ())
1804+ kvm_inject_vabt (vcpu );
1805+
1806+ return 1 ;
1807+ }
1808+
17971809 esr = kvm_vcpu_get_esr (vcpu );
17981810
1811+ /*
1812+ * The fault IPA should be reliable at this point as we're not dealing
1813+ * with an SEA.
1814+ */
17991815 ipa = fault_ipa = kvm_vcpu_get_fault_ipa (vcpu );
1816+ if (KVM_BUG_ON (ipa == INVALID_GPA , vcpu -> kvm ))
1817+ return - EFAULT ;
1818+
18001819 is_iabt = kvm_vcpu_trap_is_iabt (vcpu );
18011820
18021821 if (esr_fsc_is_translation_fault (esr )) {
@@ -1818,18 +1837,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
18181837 }
18191838 }
18201839
1821- /* Synchronous External Abort? */
1822- if (kvm_vcpu_abt_issea (vcpu )) {
1823- /*
1824- * For RAS the host kernel may handle this abort.
1825- * There is no need to pass the error into the guest.
1826- */
1827- if (kvm_handle_guest_sea (fault_ipa , kvm_vcpu_get_esr (vcpu )))
1828- kvm_inject_vabt (vcpu );
1829-
1830- return 1 ;
1831- }
1832-
18331840 trace_kvm_guest_fault (* vcpu_pc (vcpu ), kvm_vcpu_get_esr (vcpu ),
18341841 kvm_vcpu_get_hfar (vcpu ), fault_ipa );
18351842
You can’t perform that action at this time.
0 commit comments