|
@@ -303,18 +303,15 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
|
|
|
ref->pfn = pfn;
|
|
|
ref->flags = E500_TLB_VALID;
|
|
|
|
|
|
- if (tlbe_is_writable(gtlbe))
|
|
|
+ if (tlbe_is_writable(gtlbe)) {
|
|
|
ref->flags |= E500_TLB_DIRTY;
|
|
|
+ kvm_set_pfn_dirty(pfn);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
|
|
|
{
|
|
|
if (ref->flags & E500_TLB_VALID) {
|
|
|
- if (ref->flags & E500_TLB_DIRTY)
|
|
|
- kvm_release_pfn_dirty(ref->pfn);
|
|
|
- else
|
|
|
- kvm_release_pfn_clean(ref->pfn);
|
|
|
-
|
|
|
ref->flags = 0;
|
|
|
}
|
|
|
}
|
|
@@ -357,6 +354,13 @@ static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
|
|
|
clear_tlb_privs(vcpu_e500);
|
|
|
}
|
|
|
|
|
|
+void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
+ clear_tlb_refs(vcpu_e500);
|
|
|
+ clear_tlb1_bitmap(vcpu_e500);
|
|
|
+}
|
|
|
+
|
|
|
static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
|
|
|
unsigned int eaddr, int as)
|
|
|
{
|
|
@@ -541,6 +545,9 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
|
|
|
|
|
|
/* Clear i-cache for new pages */
|
|
|
kvmppc_mmu_flush_icache(pfn);
|
|
|
+
|
|
|
+ /* Drop refcount on page, so that mmu notifiers can clear it */
|
|
|
+ kvm_release_pfn_clean(pfn);
|
|
|
}
|
|
|
|
|
|
/* XXX only map the one-one case, for now use TLB0 */
|
|
@@ -1064,6 +1071,47 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
|
|
|
write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
|
|
|
}
|
|
|
|
|
|
+/************* MMU Notifiers *************/
|
|
|
+
|
|
|
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Flush all shadow tlb entries everywhere. This is slow, but
|
|
|
+ * we are 100% sure that we catch the to be unmapped page
|
|
|
+ */
|
|
|
+ kvm_flush_remote_tlbs(kvm);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
|
|
|
+{
|
|
|
+ /* kvm_unmap_hva flushes everything anyways */
|
|
|
+ kvm_unmap_hva(kvm, start);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
|
|
|
+{
|
|
|
+ /* XXX could be more clever ;) */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
|
|
|
+{
|
|
|
+ /* XXX could be more clever ;) */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
|
|
|
+{
|
|
|
+ /* The page will get remapped properly on its next fault */
|
|
|
+ kvm_unmap_hva(kvm, hva);
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************/
|
|
|
+
|
|
|
static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500)
|
|
|
{
|
|
|
int i;
|