aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/kvm_host.h4
-rw-r--r--arch/x86/kvm/x86.c60
-rw-r--r--include/linux/kvm_host.h6
-rw-r--r--virt/kvm/kvm_main.c4
4 files changed, 63 insertions, 11 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7cdcb3d0f770..6c8c7c578c46 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -368,8 +368,12 @@ struct kvm_mem_alias {
368 gfn_t base_gfn; 368 gfn_t base_gfn;
369 unsigned long npages; 369 unsigned long npages;
370 gfn_t target_gfn; 370 gfn_t target_gfn;
371#define KVM_ALIAS_INVALID 1UL
372 unsigned long flags;
371}; 373};
372 374
375#define KVM_ARCH_HAS_UNALIAS_INSTANTIATION
376
373struct kvm_mem_aliases { 377struct kvm_mem_aliases {
374 struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; 378 struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
375 int naliases; 379 int naliases;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e7488350ca16..28127c936c3b 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -38,6 +38,7 @@
38#include <linux/intel-iommu.h> 38#include <linux/intel-iommu.h>
39#include <linux/cpufreq.h> 39#include <linux/cpufreq.h>
40#include <linux/user-return-notifier.h> 40#include <linux/user-return-notifier.h>
41#include <linux/srcu.h>
41#include <trace/events/kvm.h> 42#include <trace/events/kvm.h>
42#undef TRACE_INCLUDE_FILE 43#undef TRACE_INCLUDE_FILE
43#define CREATE_TRACE_POINTS 44#define CREATE_TRACE_POINTS
@@ -2223,11 +2224,32 @@ static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
2223 return kvm->arch.n_alloc_mmu_pages; 2224 return kvm->arch.n_alloc_mmu_pages;
2224} 2225}
2225 2226
2227gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
2228{
2229 int i;
2230 struct kvm_mem_alias *alias;
2231 struct kvm_mem_aliases *aliases;
2232
2233 aliases = rcu_dereference(kvm->arch.aliases);
2234
2235 for (i = 0; i < aliases->naliases; ++i) {
2236 alias = &aliases->aliases[i];
2237 if (alias->flags & KVM_ALIAS_INVALID)
2238 continue;
2239 if (gfn >= alias->base_gfn
2240 && gfn < alias->base_gfn + alias->npages)
2241 return alias->target_gfn + gfn - alias->base_gfn;
2242 }
2243 return gfn;
2244}
2245
2226gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) 2246gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
2227{ 2247{
2228 int i; 2248 int i;
2229 struct kvm_mem_alias *alias; 2249 struct kvm_mem_alias *alias;
2230 struct kvm_mem_aliases *aliases = kvm->arch.aliases; 2250 struct kvm_mem_aliases *aliases;
2251
2252 aliases = rcu_dereference(kvm->arch.aliases);
2231 2253
2232 for (i = 0; i < aliases->naliases; ++i) { 2254 for (i = 0; i < aliases->naliases; ++i) {
2233 alias = &aliases->aliases[i]; 2255 alias = &aliases->aliases[i];
@@ -2248,7 +2270,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
2248{ 2270{
2249 int r, n; 2271 int r, n;
2250 struct kvm_mem_alias *p; 2272 struct kvm_mem_alias *p;
2251 struct kvm_mem_aliases *aliases; 2273 struct kvm_mem_aliases *aliases, *old_aliases;
2252 2274
2253 r = -EINVAL; 2275 r = -EINVAL;
2254 /* General sanity checks */ 2276 /* General sanity checks */
@@ -2265,28 +2287,48 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
2265 < alias->target_phys_addr) 2287 < alias->target_phys_addr)
2266 goto out; 2288 goto out;
2267 2289
2290 r = -ENOMEM;
2291 aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
2292 if (!aliases)
2293 goto out;
2294
2268 down_write(&kvm->slots_lock); 2295 down_write(&kvm->slots_lock);
2269 spin_lock(&kvm->mmu_lock);
2270 2296
2271 aliases = kvm->arch.aliases; 2297 /* invalidate any gfn reference in case of deletion/shrinking */
2298 memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
2299 aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID;
2300 old_aliases = kvm->arch.aliases;
2301 rcu_assign_pointer(kvm->arch.aliases, aliases);
2302 synchronize_srcu_expedited(&kvm->srcu);
2303 kvm_mmu_zap_all(kvm);
2304 kfree(old_aliases);
2305
2306 r = -ENOMEM;
2307 aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
2308 if (!aliases)
2309 goto out_unlock;
2310
2311 memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
2272 2312
2273 p = &aliases->aliases[alias->slot]; 2313 p = &aliases->aliases[alias->slot];
2274 p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; 2314 p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
2275 p->npages = alias->memory_size >> PAGE_SHIFT; 2315 p->npages = alias->memory_size >> PAGE_SHIFT;
2276 p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; 2316 p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
2317 p->flags &= ~(KVM_ALIAS_INVALID);
2277 2318
2278 for (n = KVM_ALIAS_SLOTS; n > 0; --n) 2319 for (n = KVM_ALIAS_SLOTS; n > 0; --n)
2279 if (aliases->aliases[n - 1].npages) 2320 if (aliases->aliases[n - 1].npages)
2280 break; 2321 break;
2281 aliases->naliases = n; 2322 aliases->naliases = n;
2282 2323
2283 spin_unlock(&kvm->mmu_lock); 2324 old_aliases = kvm->arch.aliases;
2284 kvm_mmu_zap_all(kvm); 2325 rcu_assign_pointer(kvm->arch.aliases, aliases);
2326 synchronize_srcu_expedited(&kvm->srcu);
2327 kfree(old_aliases);
2328 r = 0;
2285 2329
2330out_unlock:
2286 up_write(&kvm->slots_lock); 2331 up_write(&kvm->slots_lock);
2287
2288 return 0;
2289
2290out: 2332out:
2291 return r; 2333 return r;
2292} 2334}
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 93bd30701ca7..20941c0f4045 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -266,6 +266,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
266void kvm_disable_largepages(void); 266void kvm_disable_largepages(void);
267void kvm_arch_flush_shadow(struct kvm *kvm); 267void kvm_arch_flush_shadow(struct kvm *kvm);
268gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn); 268gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
269gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn);
270
269struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); 271struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
270unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); 272unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
271void kvm_release_page_clean(struct page *page); 273void kvm_release_page_clean(struct page *page);
@@ -539,6 +541,10 @@ static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_se
539} 541}
540#endif 542#endif
541 543
544#ifndef KVM_ARCH_HAS_UNALIAS_INSTANTIATION
545#define unalias_gfn_instantiation unalias_gfn
546#endif
547
542#ifdef CONFIG_HAVE_KVM_IRQCHIP 548#ifdef CONFIG_HAVE_KVM_IRQCHIP
543 549
544#define KVM_MAX_IRQ_ROUTES 1024 550#define KVM_MAX_IRQ_ROUTES 1024
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2bb24a814fdf..c680f7b64c6f 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -859,7 +859,7 @@ int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
859 int i; 859 int i;
860 struct kvm_memslots *slots = rcu_dereference(kvm->memslots); 860 struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
861 861
862 gfn = unalias_gfn(kvm, gfn); 862 gfn = unalias_gfn_instantiation(kvm, gfn);
863 for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { 863 for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
864 struct kvm_memory_slot *memslot = &slots->memslots[i]; 864 struct kvm_memory_slot *memslot = &slots->memslots[i];
865 865
@@ -896,7 +896,7 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
896{ 896{
897 struct kvm_memory_slot *slot; 897 struct kvm_memory_slot *slot;
898 898
899 gfn = unalias_gfn(kvm, gfn); 899 gfn = unalias_gfn_instantiation(kvm, gfn);
900 slot = gfn_to_memslot_unaliased(kvm, gfn); 900 slot = gfn_to_memslot_unaliased(kvm, gfn);
901 if (!slot || slot->flags & KVM_MEMSLOT_INVALID) 901 if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
902 return bad_hva(); 902 return bad_hva();