Loading arch/x86/include/asm/kvm_host.h +4 −0 Original line number Diff line number Diff line Loading @@ -368,8 +368,12 @@ struct kvm_mem_alias { gfn_t base_gfn; unsigned long npages; gfn_t target_gfn; #define KVM_ALIAS_INVALID 1UL unsigned long flags; }; #define KVM_ARCH_HAS_UNALIAS_INSTANTIATION struct kvm_mem_aliases { struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; int naliases; Loading arch/x86/kvm/x86.c +51 −9 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ #include <linux/intel-iommu.h> #include <linux/cpufreq.h> #include <linux/user-return-notifier.h> #include <linux/srcu.h> #include <trace/events/kvm.h> #undef TRACE_INCLUDE_FILE #define CREATE_TRACE_POINTS Loading Loading @@ -2223,11 +2224,32 @@ static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm) return kvm->arch.n_alloc_mmu_pages; } gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn) { int i; struct kvm_mem_alias *alias; struct kvm_mem_aliases *aliases; aliases = rcu_dereference(kvm->arch.aliases); for (i = 0; i < aliases->naliases; ++i) { alias = &aliases->aliases[i]; if (alias->flags & KVM_ALIAS_INVALID) continue; if (gfn >= alias->base_gfn && gfn < alias->base_gfn + alias->npages) return alias->target_gfn + gfn - alias->base_gfn; } return gfn; } gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) { int i; struct kvm_mem_alias *alias; struct kvm_mem_aliases *aliases = kvm->arch.aliases; struct kvm_mem_aliases *aliases; aliases = rcu_dereference(kvm->arch.aliases); for (i = 0; i < aliases->naliases; ++i) { alias = &aliases->aliases[i]; Loading @@ -2248,7 +2270,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, { int r, n; struct kvm_mem_alias *p; struct kvm_mem_aliases *aliases; struct kvm_mem_aliases *aliases, *old_aliases; r = -EINVAL; /* General sanity checks */ Loading @@ -2265,28 +2287,48 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, < alias->target_phys_addr) goto out; r = -ENOMEM; aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL); if (!aliases) goto out; down_write(&kvm->slots_lock); spin_lock(&kvm->mmu_lock); aliases = kvm->arch.aliases; /* invalidate any gfn reference in case of deletion/shrinking */ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases)); aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID; old_aliases = kvm->arch.aliases; rcu_assign_pointer(kvm->arch.aliases, aliases); synchronize_srcu_expedited(&kvm->srcu); kvm_mmu_zap_all(kvm); kfree(old_aliases); r = -ENOMEM; aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL); if (!aliases) goto out_unlock; memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases)); p = &aliases->aliases[alias->slot]; p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; p->npages = alias->memory_size >> PAGE_SHIFT; p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; p->flags &= ~(KVM_ALIAS_INVALID); for (n = KVM_ALIAS_SLOTS; n > 0; --n) if (aliases->aliases[n - 1].npages) break; aliases->naliases = n; spin_unlock(&kvm->mmu_lock); kvm_mmu_zap_all(kvm); old_aliases = kvm->arch.aliases; rcu_assign_pointer(kvm->arch.aliases, aliases); synchronize_srcu_expedited(&kvm->srcu); kfree(old_aliases); r = 0; out_unlock: up_write(&kvm->slots_lock); return 0; out: return r; } Loading include/linux/kvm_host.h +6 −0 Original line number Diff line number Diff line Loading @@ -266,6 +266,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, void kvm_disable_largepages(void); void kvm_arch_flush_shadow(struct kvm *kvm); gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn); gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); void kvm_release_page_clean(struct page *page); Loading Loading @@ -539,6 +541,10 @@ static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_se } #endif #ifndef KVM_ARCH_HAS_UNALIAS_INSTANTIATION #define unalias_gfn_instantiation unalias_gfn #endif #ifdef CONFIG_HAVE_KVM_IRQCHIP #define KVM_MAX_IRQ_ROUTES 1024 Loading virt/kvm/kvm_main.c +2 −2 Original line number Diff line number Diff line Loading @@ -859,7 +859,7 @@ int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) int i; struct kvm_memslots *slots = rcu_dereference(kvm->memslots); gfn = unalias_gfn(kvm, gfn); gfn = unalias_gfn_instantiation(kvm, gfn); for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { struct kvm_memory_slot *memslot = &slots->memslots[i]; Loading Loading @@ -896,7 +896,7 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) { struct kvm_memory_slot *slot; gfn = unalias_gfn(kvm, gfn); gfn = unalias_gfn_instantiation(kvm, gfn); slot = gfn_to_memslot_unaliased(kvm, gfn); if (!slot || slot->flags & KVM_MEMSLOT_INVALID) return bad_hva(); Loading Loading
arch/x86/include/asm/kvm_host.h +4 −0 Original line number Diff line number Diff line Loading @@ -368,8 +368,12 @@ struct kvm_mem_alias { gfn_t base_gfn; unsigned long npages; gfn_t target_gfn; #define KVM_ALIAS_INVALID 1UL unsigned long flags; }; #define KVM_ARCH_HAS_UNALIAS_INSTANTIATION struct kvm_mem_aliases { struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; int naliases; Loading
arch/x86/kvm/x86.c +51 −9 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ #include <linux/intel-iommu.h> #include <linux/cpufreq.h> #include <linux/user-return-notifier.h> #include <linux/srcu.h> #include <trace/events/kvm.h> #undef TRACE_INCLUDE_FILE #define CREATE_TRACE_POINTS Loading Loading @@ -2223,11 +2224,32 @@ static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm) return kvm->arch.n_alloc_mmu_pages; } gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn) { int i; struct kvm_mem_alias *alias; struct kvm_mem_aliases *aliases; aliases = rcu_dereference(kvm->arch.aliases); for (i = 0; i < aliases->naliases; ++i) { alias = &aliases->aliases[i]; if (alias->flags & KVM_ALIAS_INVALID) continue; if (gfn >= alias->base_gfn && gfn < alias->base_gfn + alias->npages) return alias->target_gfn + gfn - alias->base_gfn; } return gfn; } gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) { int i; struct kvm_mem_alias *alias; struct kvm_mem_aliases *aliases = kvm->arch.aliases; struct kvm_mem_aliases *aliases; aliases = rcu_dereference(kvm->arch.aliases); for (i = 0; i < aliases->naliases; ++i) { alias = &aliases->aliases[i]; Loading @@ -2248,7 +2270,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, { int r, n; struct kvm_mem_alias *p; struct kvm_mem_aliases *aliases; struct kvm_mem_aliases *aliases, *old_aliases; r = -EINVAL; /* General sanity checks */ Loading @@ -2265,28 +2287,48 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, < alias->target_phys_addr) goto out; r = -ENOMEM; aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL); if (!aliases) goto out; down_write(&kvm->slots_lock); spin_lock(&kvm->mmu_lock); aliases = kvm->arch.aliases; /* invalidate any gfn reference in case of deletion/shrinking */ memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases)); aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID; old_aliases = kvm->arch.aliases; rcu_assign_pointer(kvm->arch.aliases, aliases); synchronize_srcu_expedited(&kvm->srcu); kvm_mmu_zap_all(kvm); kfree(old_aliases); r = -ENOMEM; aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL); if (!aliases) goto out_unlock; memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases)); p = &aliases->aliases[alias->slot]; p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; p->npages = alias->memory_size >> PAGE_SHIFT; p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; p->flags &= ~(KVM_ALIAS_INVALID); for (n = KVM_ALIAS_SLOTS; n > 0; --n) if (aliases->aliases[n - 1].npages) break; aliases->naliases = n; spin_unlock(&kvm->mmu_lock); kvm_mmu_zap_all(kvm); old_aliases = kvm->arch.aliases; rcu_assign_pointer(kvm->arch.aliases, aliases); synchronize_srcu_expedited(&kvm->srcu); kfree(old_aliases); r = 0; out_unlock: up_write(&kvm->slots_lock); return 0; out: return r; } Loading
include/linux/kvm_host.h +6 −0 Original line number Diff line number Diff line Loading @@ -266,6 +266,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, void kvm_disable_largepages(void); void kvm_arch_flush_shadow(struct kvm *kvm); gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn); gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); void kvm_release_page_clean(struct page *page); Loading Loading @@ -539,6 +541,10 @@ static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_se } #endif #ifndef KVM_ARCH_HAS_UNALIAS_INSTANTIATION #define unalias_gfn_instantiation unalias_gfn #endif #ifdef CONFIG_HAVE_KVM_IRQCHIP #define KVM_MAX_IRQ_ROUTES 1024 Loading
virt/kvm/kvm_main.c +2 −2 Original line number Diff line number Diff line Loading @@ -859,7 +859,7 @@ int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) int i; struct kvm_memslots *slots = rcu_dereference(kvm->memslots); gfn = unalias_gfn(kvm, gfn); gfn = unalias_gfn_instantiation(kvm, gfn); for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { struct kvm_memory_slot *memslot = &slots->memslots[i]; Loading Loading @@ -896,7 +896,7 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) { struct kvm_memory_slot *slot; gfn = unalias_gfn(kvm, gfn); gfn = unalias_gfn_instantiation(kvm, gfn); slot = gfn_to_memslot_unaliased(kvm, gfn); if (!slot || slot->flags & KVM_MEMSLOT_INVALID) return bad_hva(); Loading