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)
482
482
(esr == ESR_ELx_FSC_ADDRSZ_L (-1 ));
483
483
}
484
484
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
+
485
507
/* Indicate whether ESR.EC==0x1A is for an ERETAx instruction */
486
508
static inline bool esr_iss_is_eretax (unsigned long esr )
487
509
{
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
307
307
{
308
308
u64 hpfar = vcpu -> arch .fault .hpfar_el2 ;
309
309
310
+ if (unlikely (!(hpfar & HPFAR_EL2_NS )))
311
+ return INVALID_GPA ;
312
+
310
313
return FIELD_GET (HPFAR_EL2_FIPA , hpfar ) << 12 ;
311
314
}
312
315
Original file line number Diff line number Diff line change 14
14
* Was this synchronous external abort a RAS notification?
15
15
* Returns '0' for errors handled by some RAS subsystem, or -ENOENT.
16
16
*/
17
- static inline int kvm_handle_guest_sea (phys_addr_t addr , u64 esr )
17
+ static inline int kvm_handle_guest_sea (void )
18
18
{
19
19
/* apei_claim_sea(NULL) expects to mask interrupts itself */
20
20
lockdep_assert_irqs_enabled ();
Original file line number Diff line number Diff line change 12
12
#include <asm/kvm_hyp.h>
13
13
#include <asm/kvm_mmu.h>
14
14
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
+
15
25
static inline bool __translate_far_to_hpfar (u64 far , u64 * hpfar )
16
26
{
17
27
int ret ;
@@ -71,17 +81,23 @@ static inline bool __hpfar_valid(u64 esr)
71
81
72
82
static inline bool __get_fault_info (u64 esr , struct kvm_vcpu_fault_info * fault )
73
83
{
74
- u64 hpfar , far ;
84
+ u64 hpfar ;
75
85
76
- far = read_sysreg_el2 (SYS_FAR );
86
+ fault -> far_el2 = read_sysreg_el2 (SYS_FAR );
87
+ fault -> hpfar_el2 = 0 ;
77
88
78
89
if (__hpfar_valid (esr ))
79
90
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 ))
81
94
return false;
82
95
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 ;
85
101
return true;
86
102
}
87
103
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)
578
578
return ;
579
579
}
580
580
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 ));
581
587
addr = FIELD_GET (HPFAR_EL2_FIPA , fault .hpfar_el2 ) << 12 ;
588
+
582
589
ret = host_stage2_idmap (addr );
583
590
BUG_ON (ret && ret != - EAGAIN );
584
591
}
Original file line number Diff line number Diff line change @@ -1794,9 +1794,28 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
1794
1794
gfn_t gfn ;
1795
1795
int ret , idx ;
1796
1796
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
+
1797
1809
esr = kvm_vcpu_get_esr (vcpu );
1798
1810
1811
+ /*
1812
+ * The fault IPA should be reliable at this point as we're not dealing
1813
+ * with an SEA.
1814
+ */
1799
1815
ipa = fault_ipa = kvm_vcpu_get_fault_ipa (vcpu );
1816
+ if (KVM_BUG_ON (ipa == INVALID_GPA , vcpu -> kvm ))
1817
+ return - EFAULT ;
1818
+
1800
1819
is_iabt = kvm_vcpu_trap_is_iabt (vcpu );
1801
1820
1802
1821
if (esr_fsc_is_translation_fault (esr )) {
@@ -1818,18 +1837,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
1818
1837
}
1819
1838
}
1820
1839
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
-
1833
1840
trace_kvm_guest_fault (* vcpu_pc (vcpu ), kvm_vcpu_get_esr (vcpu ),
1834
1841
kvm_vcpu_get_hfar (vcpu ), fault_ipa );
1835
1842
You can’t perform that action at this time.
0 commit comments