@@ -1077,31 +1077,56 @@ static int stage2_set_pud_huge(struct kvm *kvm, struct kvm_mmu_memory_cache *cac
return 0;
}
-static bool stage2_is_exec(struct kvm *kvm, phys_addr_t addr)
+static bool stage2_get_leaf_entry(struct kvm *kvm, phys_addr_t addr, pud_t **pudp,
+ pmd_t **pmdp, pte_t **ptep)
{
- pud_t *pudp;
- pmd_t *pmdp;
- pte_t *ptep;
+ pud_t *lpudp;
+ pmd_t *lpmdp;
+ pte_t *lptep;
- pudp = stage2_get_pud(kvm, NULL, addr);
- if (!pudp || pud_none(*pudp) || !pud_present(*pudp))
+ lpudp = stage2_get_pud(kvm, NULL, addr);
+ if (!lpudp || pud_none(*lpudp) || !pud_present(*lpudp))
return false;
- if (pud_huge(*pudp))
- return kvm_s2pud_exec(pudp);
+ if (pud_huge(*lpudp)) {
+ *pudp = lpudp;
+ return true;
+ }
- pmdp = stage2_pmd_offset(pudp, addr);
- if (!pmdp || pmd_none(*pmdp) || !pmd_present(*pmdp))
+ lpmdp = stage2_pmd_offset(lpudp, addr);
+ if (!lpmdp || pmd_none(*lpmdp) || !pmd_present(*lpmdp))
return false;
- if (pmd_thp_or_huge(*pmdp))
- return kvm_s2pmd_exec(pmdp);
+ if (pmd_thp_or_huge(*lpmdp)) {
+ *pmdp = lpmdp;
+ return true;
+ }
- ptep = pte_offset_kernel(pmdp, addr);
- if (!ptep || pte_none(*ptep) || !pte_present(*ptep))
+ lptep = pte_offset_kernel(lpmdp, addr);
+ if (!lptep || pte_none(*lptep) || !pte_present(*lptep))
return false;
- return kvm_s2pte_exec(ptep);
+ *ptep = lptep;
+ return true;
+}
+
+static bool stage2_is_exec(struct kvm *kvm, phys_addr_t addr)
+{
+ pud_t *pudp = NULL;
+ pmd_t *pmdp = NULL;
+ pte_t *ptep = NULL;
+ bool found;
+
+ found = stage2_get_leaf_entry(kvm, addr, &pudp, &pmdp, &ptep);
+ if (!found)
+ return false;
+
+ if (pudp)
+ return kvm_s2pud_exec(pudp);
+ else if (pmdp)
+ return kvm_s2pmd_exec(pmdp);
+ else
+ return kvm_s2pte_exec(ptep);
}
static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
@@ -1681,45 +1706,36 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
*/
static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
{
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
+ pud_t *pud = NULL;
+ pmd_t *pmd = NULL;
+ pte_t *pte = NULL;
kvm_pfn_t pfn;
- bool pfn_valid = false;
+ bool found, pfn_valid = false;
trace_kvm_access_fault(fault_ipa);
spin_lock(&vcpu->kvm->mmu_lock);
- pud = stage2_get_pud(vcpu->kvm, NULL, fault_ipa);
- if (!pud || pud_none(*pud))
- goto out; /* Nothing there */
+ found = stage2_get_leaf_entry(kvm, fault_ipa, &pud, &pmd, &pte);
+ if (!found)
+ goto out;
- if (pud_huge(*pud)) { /* HugeTLB */
+ if (pud) { /* HugeTLB */
*pud = kvm_s2pud_mkyoung(*pud);
pfn = kvm_pud_pfn(*pud);
pfn_valid = true;
goto out;
- }
-
- pmd = stage2_pmd_offset(pud, fault_ipa);
- if (!pmd || pmd_none(*pmd)) /* Nothing there */
- goto out;
-
- if (pmd_thp_or_huge(*pmd)) { /* THP, HugeTLB */
+ } else if (pmd) { /* THP, HugeTLB */
*pmd = pmd_mkyoung(*pmd);
pfn = pmd_pfn(*pmd);
pfn_valid = true;
goto out;
+ } else {
+ *pte = pte_mkyoung(*pte); /* Just a page... */
+ pfn = pte_pfn(*pte);
+ pfn_valid = true;
}
- pte = pte_offset_kernel(pmd, fault_ipa);
- if (pte_none(*pte)) /* Nothing there either */
- goto out;
-
- *pte = pte_mkyoung(*pte); /* Just a page... */
- pfn = pte_pfn(*pte);
- pfn_valid = true;
out:
spin_unlock(&vcpu->kvm->mmu_lock);
if (pfn_valid)
@@ -1932,58 +1948,42 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
static int kvm_age_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *data)
{
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
+ pud_t *pud = NULL;
+ pmd_t *pmd = NULL;
+ pte_t *pte = NULL;
+ bool found;
WARN_ON(size != PAGE_SIZE && size != PMD_SIZE && size != PUD_SIZE);
- pud = stage2_get_pud(kvm, NULL, gpa);
- if (!pud || pud_none(*pud)) /* Nothing there */
+ found = stage2_get_leaf_entry(kvm, gpa, &pud, &pmd, &pte);
+ if (!found)
return 0;
- if (pud_huge(*pud)) /* HugeTLB */
+ if (pud)
return stage2_pudp_test_and_clear_young(pud);
-
- pmd = stage2_pmd_offset(pud, gpa);
- if (!pmd || pmd_none(*pmd)) /* Nothing there */
- return 0;
-
- if (pmd_thp_or_huge(*pmd)) /* THP, HugeTLB */
+ else if (pmd)
return stage2_pmdp_test_and_clear_young(pmd);
-
- pte = pte_offset_kernel(pmd, gpa);
- if (pte_none(*pte))
- return 0;
-
- return stage2_ptep_test_and_clear_young(pte);
+ else
+ return stage2_ptep_test_and_clear_young(pte);
}
static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *data)
{
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
+ pud_t *pud = NULL;
+ pmd_t *pmd = NULL;
+ pte_t *pte = NULL;
+ bool found;
WARN_ON(size != PAGE_SIZE && size != PMD_SIZE && size != PUD_SIZE);
- pud = stage2_get_pud(kvm, NULL, gpa);
- if (!pud || pud_none(*pud)) /* Nothing there */
+ found = stage2_get_leaf_entry(kvm, gpa, &pud, &pmd, &pte);
+ if (!found)
return 0;
- if (pud_huge(*pud)) /* HugeTLB */
+ if (pud)
return kvm_s2pud_young(*pud);
-
- pmd = stage2_pmd_offset(pud, gpa);
- if (!pmd || pmd_none(*pmd)) /* Nothing there */
- return 0;
-
- if (pmd_thp_or_huge(*pmd)) /* THP, HugeTLB */
+ else if (pmd)
return pmd_young(*pmd);
-
- pte = pte_offset_kernel(pmd, gpa);
- if (!pte_none(*pte)) /* Just a page... */
+ else
return pte_young(*pte);
-
- return 0;
}
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)