KVM: PPC: Book3S HV: Introduce kvmhv_update_nest_rmap_rc_list()
authorSuraj Jitindar Singh <sjitindarsingh@gmail.com>
Fri, 21 Dec 2018 03:28:42 +0000 (14:28 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 21 Dec 2018 03:39:35 +0000 (14:39 +1100)
Introduce a function kvmhv_update_nest_rmap_rc_list() which for a given
nest_rmap list will traverse it, find the corresponding pte in the shadow
page tables, and if it still maps the same host page update the rc bits
accordingly.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/kvm/book3s_64_mmu_radix.c
arch/powerpc/kvm/book3s_hv_nested.c

index 82a0a9f3c39c3379b289c92684ecd5eff40e019e..38f1b879f569eb0dcdcd639b7e387bbe1cb3ad92 100644 (file)
@@ -203,6 +203,8 @@ extern int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr,
                        int table_index, u64 *pte_ret_p);
 extern int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
                        struct kvmppc_pte *gpte, bool data, bool iswrite);
+extern void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
+                                   unsigned int pshift, unsigned int lpid);
 extern void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, unsigned long gpa,
                        unsigned int shift,
                        const struct kvm_memory_slot *memslot,
index 34968fd2de240dcb2f439e15690aa5393e318cb5..21b1ed5df88825765ab706b8829e3619c52a6cd3 100644 (file)
@@ -637,6 +637,9 @@ extern int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
                             unsigned long *rmapp, struct rmap_nested **n_rmap);
 extern void kvmhv_insert_nest_rmap(struct kvm *kvm, unsigned long *rmapp,
                                   struct rmap_nested **n_rmap);
+extern void kvmhv_update_nest_rmap_rc_list(struct kvm *kvm, unsigned long *rmapp,
+                                          unsigned long clr, unsigned long set,
+                                          unsigned long hpa, unsigned long nbytes);
 extern void kvmhv_remove_nest_rmap_range(struct kvm *kvm,
                                const struct kvm_memory_slot *memslot,
                                unsigned long gpa, unsigned long hpa,
index 870ef9d5eee69c146dc3dedbfbe0a004fb594ca5..53630f0e74690f2165ea680ed0ca553ccb82385f 100644 (file)
@@ -294,8 +294,8 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
        return 0;
 }
 
-static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
-                                   unsigned int pshift, unsigned int lpid)
+void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
+                            unsigned int pshift, unsigned int lpid)
 {
        unsigned long psize = PAGE_SIZE;
        int psi;
index 0bd676ac38fe84999ca67195137e8cf8cabb72d4..735e0ac6f5b27a8259a7a2b4a6540184809bd9ed 100644 (file)
@@ -788,6 +788,57 @@ void kvmhv_insert_nest_rmap(struct kvm *kvm, unsigned long *rmapp,
        *n_rmap = NULL;
 }
 
+static void kvmhv_update_nest_rmap_rc(struct kvm *kvm, u64 n_rmap,
+                                     unsigned long clr, unsigned long set,
+                                     unsigned long hpa, unsigned long mask)
+{
+       struct kvm_nested_guest *gp;
+       unsigned long gpa;
+       unsigned int shift, lpid;
+       pte_t *ptep;
+
+       gpa = n_rmap & RMAP_NESTED_GPA_MASK;
+       lpid = (n_rmap & RMAP_NESTED_LPID_MASK) >> RMAP_NESTED_LPID_SHIFT;
+       gp = kvmhv_find_nested(kvm, lpid);
+       if (!gp)
+               return;
+
+       /* Find the pte */
+       ptep = __find_linux_pte(gp->shadow_pgtable, gpa, NULL, &shift);
+       /*
+        * If the pte is present and the pfn is still the same, update the pte.
+        * If the pfn has changed then this is a stale rmap entry, the nested
+        * gpa actually points somewhere else now, and there is nothing to do.
+        * XXX A future optimisation would be to remove the rmap entry here.
+        */
+       if (ptep && pte_present(*ptep) && ((pte_val(*ptep) & mask) == hpa)) {
+               __radix_pte_update(ptep, clr, set);
+               kvmppc_radix_tlbie_page(kvm, gpa, shift, lpid);
+       }
+}
+
+/*
+ * For a given list of rmap entries, update the rc bits in all ptes in shadow
+ * page tables for nested guests which are referenced by the rmap list.
+ */
+void kvmhv_update_nest_rmap_rc_list(struct kvm *kvm, unsigned long *rmapp,
+                                   unsigned long clr, unsigned long set,
+                                   unsigned long hpa, unsigned long nbytes)
+{
+       struct llist_node *entry = ((struct llist_head *) rmapp)->first;
+       struct rmap_nested *cursor;
+       unsigned long rmap, mask;
+
+       if ((clr | set) & ~(_PAGE_DIRTY | _PAGE_ACCESSED))
+               return;
+
+       mask = PTE_RPN_MASK & ~(nbytes - 1);
+       hpa &= mask;
+
+       for_each_nest_rmap_safe(cursor, entry, &rmap)
+               kvmhv_update_nest_rmap_rc(kvm, rmap, clr, set, hpa, mask);
+}
+
 static void kvmhv_remove_nest_rmap(struct kvm *kvm, u64 n_rmap,
                                   unsigned long hpa, unsigned long mask)
 {