|
@@ -107,23 +107,39 @@ void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(kvmppc_add_revmap_chain);
|
|
|
|
|
|
-/* Update the changed page order field of an rmap entry */
|
|
|
-void kvmppc_update_rmap_change(unsigned long *rmap, unsigned long psize)
|
|
|
+/* Update the dirty bitmap of a memslot */
|
|
|
+void kvmppc_update_dirty_map(struct kvm_memory_slot *memslot,
|
|
|
+ unsigned long gfn, unsigned long psize)
|
|
|
{
|
|
|
- unsigned long order;
|
|
|
+ unsigned long npages;
|
|
|
|
|
|
- if (!psize)
|
|
|
+ if (!psize || !memslot->dirty_bitmap)
|
|
|
return;
|
|
|
- order = ilog2(psize);
|
|
|
- order <<= KVMPPC_RMAP_CHG_SHIFT;
|
|
|
- if (order > (*rmap & KVMPPC_RMAP_CHG_ORDER))
|
|
|
- *rmap = (*rmap & ~KVMPPC_RMAP_CHG_ORDER) | order;
|
|
|
+ npages = (psize + PAGE_SIZE - 1) / PAGE_SIZE;
|
|
|
+ gfn -= memslot->base_gfn;
|
|
|
+ set_dirty_bits_atomic(memslot->dirty_bitmap, gfn, npages);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(kvmppc_update_dirty_map);
|
|
|
+
|
|
|
+static void kvmppc_set_dirty_from_hpte(struct kvm *kvm,
|
|
|
+ unsigned long hpte_v, unsigned long hpte_gr)
|
|
|
+{
|
|
|
+ struct kvm_memory_slot *memslot;
|
|
|
+ unsigned long gfn;
|
|
|
+ unsigned long psize;
|
|
|
+
|
|
|
+ psize = kvmppc_actual_pgsz(hpte_v, hpte_gr);
|
|
|
+ gfn = hpte_rpn(hpte_gr, psize);
|
|
|
+ memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
|
|
|
+ if (memslot && memslot->dirty_bitmap)
|
|
|
+ kvmppc_update_dirty_map(memslot, gfn, psize);
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(kvmppc_update_rmap_change);
|
|
|
|
|
|
/* Returns a pointer to the revmap entry for the page mapped by a HPTE */
|
|
|
static unsigned long *revmap_for_hpte(struct kvm *kvm, unsigned long hpte_v,
|
|
|
- unsigned long hpte_gr)
|
|
|
+ unsigned long hpte_gr,
|
|
|
+ struct kvm_memory_slot **memslotp,
|
|
|
+ unsigned long *gfnp)
|
|
|
{
|
|
|
struct kvm_memory_slot *memslot;
|
|
|
unsigned long *rmap;
|
|
@@ -131,6 +147,10 @@ static unsigned long *revmap_for_hpte(struct kvm *kvm, unsigned long hpte_v,
|
|
|
|
|
|
gfn = hpte_rpn(hpte_gr, kvmppc_actual_pgsz(hpte_v, hpte_gr));
|
|
|
memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
|
|
|
+ if (memslotp)
|
|
|
+ *memslotp = memslot;
|
|
|
+ if (gfnp)
|
|
|
+ *gfnp = gfn;
|
|
|
if (!memslot)
|
|
|
return NULL;
|
|
|
|
|
@@ -147,10 +167,12 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
|
|
|
unsigned long ptel, head;
|
|
|
unsigned long *rmap;
|
|
|
unsigned long rcbits;
|
|
|
+ struct kvm_memory_slot *memslot;
|
|
|
+ unsigned long gfn;
|
|
|
|
|
|
rcbits = hpte_r & (HPTE_R_R | HPTE_R_C);
|
|
|
ptel = rev->guest_rpte |= rcbits;
|
|
|
- rmap = revmap_for_hpte(kvm, hpte_v, ptel);
|
|
|
+ rmap = revmap_for_hpte(kvm, hpte_v, ptel, &memslot, &gfn);
|
|
|
if (!rmap)
|
|
|
return;
|
|
|
lock_rmap(rmap);
|
|
@@ -169,8 +191,8 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
|
|
|
}
|
|
|
*rmap |= rcbits << KVMPPC_RMAP_RC_SHIFT;
|
|
|
if (rcbits & HPTE_R_C)
|
|
|
- kvmppc_update_rmap_change(rmap,
|
|
|
- kvmppc_actual_pgsz(hpte_v, hpte_r));
|
|
|
+ kvmppc_update_dirty_map(memslot, gfn,
|
|
|
+ kvmppc_actual_pgsz(hpte_v, hpte_r));
|
|
|
unlock_rmap(rmap);
|
|
|
}
|
|
|
|
|
@@ -798,7 +820,7 @@ long kvmppc_h_clear_ref(struct kvm_vcpu *vcpu, unsigned long flags,
|
|
|
gr |= r & (HPTE_R_R | HPTE_R_C);
|
|
|
if (r & HPTE_R_R) {
|
|
|
kvmppc_clear_ref_hpte(kvm, hpte, pte_index);
|
|
|
- rmap = revmap_for_hpte(kvm, v, gr);
|
|
|
+ rmap = revmap_for_hpte(kvm, v, gr, NULL, NULL);
|
|
|
if (rmap) {
|
|
|
lock_rmap(rmap);
|
|
|
*rmap |= KVMPPC_RMAP_REFERENCED;
|
|
@@ -820,7 +842,6 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
|
|
|
__be64 *hpte;
|
|
|
unsigned long v, r, gr;
|
|
|
struct revmap_entry *rev;
|
|
|
- unsigned long *rmap;
|
|
|
long ret = H_NOT_FOUND;
|
|
|
|
|
|
if (kvm_is_radix(kvm))
|
|
@@ -849,16 +870,9 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
|
|
|
r = be64_to_cpu(hpte[1]);
|
|
|
gr |= r & (HPTE_R_R | HPTE_R_C);
|
|
|
if (r & HPTE_R_C) {
|
|
|
- unsigned long psize = kvmppc_actual_pgsz(v, r);
|
|
|
hpte[1] = cpu_to_be64(r & ~HPTE_R_C);
|
|
|
eieio();
|
|
|
- rmap = revmap_for_hpte(kvm, v, gr);
|
|
|
- if (rmap) {
|
|
|
- lock_rmap(rmap);
|
|
|
- *rmap |= KVMPPC_RMAP_CHANGED;
|
|
|
- kvmppc_update_rmap_change(rmap, psize);
|
|
|
- unlock_rmap(rmap);
|
|
|
- }
|
|
|
+ kvmppc_set_dirty_from_hpte(kvm, v, gr);
|
|
|
}
|
|
|
}
|
|
|
vcpu->arch.gpr[4] = gr;
|