aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/kvm_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r--virt/kvm/kvm_main.c112
1 files changed, 100 insertions, 12 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index aefdda390f5e..d9cfb782cb81 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -47,6 +47,8 @@
47#include <linux/srcu.h> 47#include <linux/srcu.h>
48#include <linux/hugetlb.h> 48#include <linux/hugetlb.h>
49#include <linux/slab.h> 49#include <linux/slab.h>
50#include <linux/sort.h>
51#include <linux/bsearch.h>
50 52
51#include <asm/processor.h> 53#include <asm/processor.h>
52#include <asm/io.h> 54#include <asm/io.h>
@@ -2391,24 +2393,92 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
2391 int i; 2393 int i;
2392 2394
2393 for (i = 0; i < bus->dev_count; i++) { 2395 for (i = 0; i < bus->dev_count; i++) {
2394 struct kvm_io_device *pos = bus->devs[i]; 2396 struct kvm_io_device *pos = bus->range[i].dev;
2395 2397
2396 kvm_iodevice_destructor(pos); 2398 kvm_iodevice_destructor(pos);
2397 } 2399 }
2398 kfree(bus); 2400 kfree(bus);
2399} 2401}
2400 2402
2403int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
2404{
2405 const struct kvm_io_range *r1 = p1;
2406 const struct kvm_io_range *r2 = p2;
2407
2408 if (r1->addr < r2->addr)
2409 return -1;
2410 if (r1->addr + r1->len > r2->addr + r2->len)
2411 return 1;
2412 return 0;
2413}
2414
2415int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
2416 gpa_t addr, int len)
2417{
2418 if (bus->dev_count == NR_IOBUS_DEVS)
2419 return -ENOSPC;
2420
2421 bus->range[bus->dev_count++] = (struct kvm_io_range) {
2422 .addr = addr,
2423 .len = len,
2424 .dev = dev,
2425 };
2426
2427 sort(bus->range, bus->dev_count, sizeof(struct kvm_io_range),
2428 kvm_io_bus_sort_cmp, NULL);
2429
2430 return 0;
2431}
2432
2433int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus,
2434 gpa_t addr, int len)
2435{
2436 struct kvm_io_range *range, key;
2437 int off;
2438
2439 key = (struct kvm_io_range) {
2440 .addr = addr,
2441 .len = len,
2442 };
2443
2444 range = bsearch(&key, bus->range, bus->dev_count,
2445 sizeof(struct kvm_io_range), kvm_io_bus_sort_cmp);
2446 if (range == NULL)
2447 return -ENOENT;
2448
2449 off = range - bus->range;
2450
2451 while (off > 0 && kvm_io_bus_sort_cmp(&key, &bus->range[off-1]) == 0)
2452 off--;
2453
2454 return off;
2455}
2456
2401/* kvm_io_bus_write - called under kvm->slots_lock */ 2457/* kvm_io_bus_write - called under kvm->slots_lock */
2402int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, 2458int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2403 int len, const void *val) 2459 int len, const void *val)
2404{ 2460{
2405 int i; 2461 int idx;
2406 struct kvm_io_bus *bus; 2462 struct kvm_io_bus *bus;
2463 struct kvm_io_range range;
2464
2465 range = (struct kvm_io_range) {
2466 .addr = addr,
2467 .len = len,
2468 };
2407 2469
2408 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); 2470 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
2409 for (i = 0; i < bus->dev_count; i++) 2471 idx = kvm_io_bus_get_first_dev(bus, addr, len);
2410 if (!kvm_iodevice_write(bus->devs[i], addr, len, val)) 2472 if (idx < 0)
2473 return -EOPNOTSUPP;
2474
2475 while (idx < bus->dev_count &&
2476 kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
2477 if (!kvm_iodevice_write(bus->range[idx].dev, addr, len, val))
2411 return 0; 2478 return 0;
2479 idx++;
2480 }
2481
2412 return -EOPNOTSUPP; 2482 return -EOPNOTSUPP;
2413} 2483}
2414 2484
@@ -2416,19 +2486,33 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2416int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, 2486int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2417 int len, void *val) 2487 int len, void *val)
2418{ 2488{
2419 int i; 2489 int idx;
2420 struct kvm_io_bus *bus; 2490 struct kvm_io_bus *bus;
2491 struct kvm_io_range range;
2492
2493 range = (struct kvm_io_range) {
2494 .addr = addr,
2495 .len = len,
2496 };
2421 2497
2422 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); 2498 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
2423 for (i = 0; i < bus->dev_count; i++) 2499 idx = kvm_io_bus_get_first_dev(bus, addr, len);
2424 if (!kvm_iodevice_read(bus->devs[i], addr, len, val)) 2500 if (idx < 0)
2501 return -EOPNOTSUPP;
2502
2503 while (idx < bus->dev_count &&
2504 kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
2505 if (!kvm_iodevice_read(bus->range[idx].dev, addr, len, val))
2425 return 0; 2506 return 0;
2507 idx++;
2508 }
2509
2426 return -EOPNOTSUPP; 2510 return -EOPNOTSUPP;
2427} 2511}
2428 2512
2429/* Caller must hold slots_lock. */ 2513/* Caller must hold slots_lock. */
2430int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, 2514int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2431 struct kvm_io_device *dev) 2515 int len, struct kvm_io_device *dev)
2432{ 2516{
2433 struct kvm_io_bus *new_bus, *bus; 2517 struct kvm_io_bus *new_bus, *bus;
2434 2518
@@ -2440,7 +2524,7 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
2440 if (!new_bus) 2524 if (!new_bus)
2441 return -ENOMEM; 2525 return -ENOMEM;
2442 memcpy(new_bus, bus, sizeof(struct kvm_io_bus)); 2526 memcpy(new_bus, bus, sizeof(struct kvm_io_bus));
2443 new_bus->devs[new_bus->dev_count++] = dev; 2527 kvm_io_bus_insert_dev(new_bus, dev, addr, len);
2444 rcu_assign_pointer(kvm->buses[bus_idx], new_bus); 2528 rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
2445 synchronize_srcu_expedited(&kvm->srcu); 2529 synchronize_srcu_expedited(&kvm->srcu);
2446 kfree(bus); 2530 kfree(bus);
@@ -2464,9 +2548,13 @@ int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
2464 2548
2465 r = -ENOENT; 2549 r = -ENOENT;
2466 for (i = 0; i < new_bus->dev_count; i++) 2550 for (i = 0; i < new_bus->dev_count; i++)
2467 if (new_bus->devs[i] == dev) { 2551 if (new_bus->range[i].dev == dev) {
2468 r = 0; 2552 r = 0;
2469 new_bus->devs[i] = new_bus->devs[--new_bus->dev_count]; 2553 new_bus->dev_count--;
2554 new_bus->range[i] = new_bus->range[new_bus->dev_count];
2555 sort(new_bus->range, new_bus->dev_count,
2556 sizeof(struct kvm_io_range),
2557 kvm_io_bus_sort_cmp, NULL);
2470 break; 2558 break;
2471 } 2559 }
2472 2560