Allow multiple IO bitmap pages and provide an interface for userspace
to control which ports are open for a particular guest.

Only tested on Intel VMX.

Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]>

Index: kvm/arch/x86/kvm/kvm_svm.h
===================================================================
--- kvm.orig/arch/x86/kvm/kvm_svm.h
+++ kvm/arch/x86/kvm/kvm_svm.h
@@ -41,6 +41,7 @@ struct vcpu_svm {
        unsigned long host_dr7;
 
        u32 *msrpm;
+       struct kvm_io_bitmap_page *io_bitmap_page;
 };
 
 #endif
Index: kvm/arch/x86/kvm/svm.c
===================================================================
--- kvm.orig/arch/x86/kvm/svm.c
+++ kvm/arch/x86/kvm/svm.c
@@ -24,6 +24,7 @@
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
 #include <linux/sched.h>
+#include <linux/kref.h>
 
 #include <asm/desc.h>
 
@@ -68,7 +69,10 @@ static inline struct vcpu_svm *to_svm(st
        return container_of(vcpu, struct vcpu_svm, vcpu);
 }
 
-static unsigned long iopm_base;
+static LIST_HEAD(io_bitmap_pages);
+static DEFINE_MUTEX(io_bitmap_mutex);
+
+static struct kvm_io_bitmap_page *main_iopm_page;
 
 struct kvm_ldttss_desc {
        u16 limit0;
@@ -413,18 +417,28 @@ static __init int svm_hardware_setup(voi
 {
        int cpu;
        struct page *iopm_pages;
+       struct kvm_io_bitmap_page *bitmap_page;
        void *iopm_va;
        int r;
 
-       iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
+       bitmap_page = kmalloc(sizeof(struct kvm_io_bitmap_page), GFP_KERNEL);
+       if (!bitmap_page)
+               return -ENOMEM;
+       kref_init(&bitmap_page->ref);
+       INIT_LIST_HEAD(&bitmap_page->io_bitmap_list);
 
-       if (!iopm_pages)
+       iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
+       if (!iopm_pages) {
+               kfree(bitmap_page);
                return -ENOMEM;
+       }
 
        iopm_va = page_address(iopm_pages);
        memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
        clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */
-       iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
+       bitmap_page->page = iopm_pages;
+       list_add(&bitmap_page->io_bitmap_list, &io_bitmap_pages);
+       main_iopm_page = bitmap_page;
 
        if (boot_cpu_has(X86_FEATURE_NX))
                kvm_enable_efer_bits(EFER_NX);
@@ -454,14 +468,16 @@ static __init int svm_hardware_setup(voi
 
 err:
        __free_pages(iopm_pages, IOPM_ALLOC_ORDER);
-       iopm_base = 0;
+       list_del(&bitmap_page->io_bitmap_list);
+       kfree(bitmap_page);
        return r;
 }
 
 static __exit void svm_hardware_unsetup(void)
 {
-       __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
-       iopm_base = 0;
+       __free_pages(main_iopm_page->page, IOPM_ALLOC_ORDER);
+       list_del(&main_iopm_page->io_bitmap_list);
+       kfree(main_iopm_page);
 }
 
 static void init_seg(struct vmcb_seg *seg)
@@ -534,7 +550,7 @@ static void init_vmcb(struct vcpu_svm *s
                                (1ULL << INTERCEPT_MONITOR) |
                                (1ULL << INTERCEPT_MWAIT);
 
-       control->iopm_base_pa = iopm_base;
+       control->iopm_base_pa = page_to_pfn(svm->io_bitmap_page->page) << 
PAGE_SHIFT;
        control->msrpm_base_pa = __pa(svm->msrpm);
        control->tsc_offset = 0;
        control->int_ctl = V_INTR_MASKING_MASK;
@@ -641,6 +657,8 @@ static struct kvm_vcpu *svm_create_vcpu(
        svm->msrpm = page_address(msrpm_pages);
        svm_vcpu_init_msrpm(svm->msrpm);
 
+       svm->io_bitmap_page = kvm->arch.io_bitmap_a;
+
        svm->vmcb = page_address(page);
        clear_page(svm->vmcb);
        svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
@@ -1912,6 +1930,98 @@ static int get_npt_level(void)
 #endif
 }
 
+static struct kvm_io_bitmap_page *svm_find_io_bitmap_page(void *va)
+{
+       struct kvm_io_bitmap_page *bitmap_page;
+       struct page *iopm_pages;
+
+       list_for_each_entry(bitmap_page, &io_bitmap_pages, io_bitmap_list) {
+               bool found;
+               found = !memcmp(va, page_address(bitmap_page->page),
+                               PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+               if (found) {
+                       kref_get(&bitmap_page->ref);
+                       return bitmap_page;
+               }
+       }
+
+       bitmap_page = kmalloc(sizeof(struct kvm_io_bitmap_page), GFP_KERNEL);
+       if (!bitmap_page)
+               return NULL;
+
+       iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
+       if (!iopm_pages) {
+               kfree(bitmap_page);
+               return NULL;
+       }
+       memcpy(page_address(iopm_pages), va, (1 << IOPM_ALLOC_ORDER));
+       bitmap_page->page = iopm_pages;
+       kref_init(&bitmap_page->ref);
+       INIT_LIST_HEAD(&bitmap_page->io_bitmap_list);
+       list_add(&bitmap_page->io_bitmap_list, &io_bitmap_pages);
+
+       return bitmap_page;
+}
+
+static void svm_build_io_bitmap(void *va, struct kvm_ioport_list *ioports)
+{
+       int i;
+
+       memset(va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+       for (i = 0; i < ioports->nranges; i++) {
+               struct kvm_ioport *ioport = &ioports->ioports[i];
+               __u32 addr, n;
+
+               addr = ioport->addr;
+               for (n = addr; n < addr + ioport->len; n++)
+                       clear_bit(n, va);
+       }
+}
+
+static int svm_open_io_ports(struct kvm *kvm, struct kvm_ioport_list *ioports)
+{
+       void *area;
+       struct kvm_io_bitmap_page *bitmap_page;
+       int ret = -ENOMEM;
+
+       mutex_lock(&io_bitmap_mutex);
+       area = vmalloc(PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+       if (!area)
+               goto out_unlock;
+       svm_build_io_bitmap(area, ioports);
+       bitmap_page = svm_find_io_bitmap_page(area);
+       vfree(area);
+       if (!bitmap_page)
+               goto out_unlock;
+
+       kvm->arch.io_bitmap_a = bitmap_page;
+       ret = 0;
+out_unlock:
+       mutex_unlock(&io_bitmap_mutex);
+       return ret;
+}
+
+static void svm_io_bitmap_kref_put(struct kref *kref)
+{
+       struct kvm_io_bitmap_page *page =
+               container_of(kref, struct kvm_io_bitmap_page, ref);
+
+       mutex_lock(&io_bitmap_mutex);
+       list_del(&page->io_bitmap_list);
+       __free_pages(page->page, IOPM_ALLOC_ORDER);
+       kfree(page);
+       mutex_unlock(&io_bitmap_mutex);
+}
+
+static void svm_release_io_bitmaps(struct kvm *kvm)
+{
+       struct kvm_io_bitmap_page *io_bitmap;
+
+       io_bitmap = kvm->arch.io_bitmap_a;
+       if (io_bitmap)
+               kref_put(&io_bitmap->ref, svm_io_bitmap_kref_put);
+}
+
 static struct kvm_x86_ops svm_x86_ops = {
        .cpu_has_kvm_support = has_svm,
        .disabled_by_bios = is_disabled,
@@ -1969,6 +2079,8 @@ static struct kvm_x86_ops svm_x86_ops = 
 
        .set_tss_addr = svm_set_tss_addr,
        .get_tdp_level = get_npt_level,
+       .open_io_ports = svm_open_io_ports,
+       .release_io_bitmaps = svm_release_io_bitmaps,
 };
 
 static int __init svm_init(void)
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
--- kvm.orig/arch/x86/kvm/vmx.c
+++ kvm/arch/x86/kvm/vmx.c
@@ -26,6 +26,7 @@
 #include <linux/highmem.h>
 #include <linux/sched.h>
 #include <linux/moduleparam.h>
+#include <linux/kref.h>
 
 #include <asm/io.h>
 #include <asm/desc.h>
@@ -47,6 +48,10 @@ module_param(flexpriority_enabled, bool,
 static int enable_ept = 1;
 module_param(enable_ept, bool, 0);
 
+static LIST_HEAD(io_bitmap_pages_a);
+static LIST_HEAD(io_bitmap_pages_b);
+static DEFINE_MUTEX(io_bitmap_mutex);
+
 struct vmcs {
        u32 revision_id;
        u32 abort;
@@ -83,6 +88,8 @@ struct vcpu_vmx {
                } irq;
        } rmode;
        int vpid;
+       struct kvm_io_bitmap_page *io_bitmap_a;
+       struct kvm_io_bitmap_page *io_bitmap_b;
 };
 
 static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
@@ -96,8 +103,6 @@ static DEFINE_PER_CPU(struct vmcs *, vmx
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu);
 
-static struct page *vmx_io_bitmap_a;
-static struct page *vmx_io_bitmap_b;
 static struct page *vmx_msr_bitmap;
 
 static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS);
@@ -1875,8 +1880,8 @@ static int vmx_vcpu_setup(struct vcpu_vm
        u32 exec_control;
 
        /* I/O */
-       vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
-       vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
+       vmcs_write64(IO_BITMAP_A, page_to_phys(vmx->io_bitmap_a->page));
+       vmcs_write64(IO_BITMAP_B, page_to_phys(vmx->io_bitmap_b->page));
 
        if (cpu_has_vmx_msr_bitmap())
                vmcs_write64(MSR_BITMAP, page_to_phys(vmx_msr_bitmap));
@@ -3126,6 +3131,9 @@ static struct kvm_vcpu *vmx_create_vcpu(
 
        vmcs_clear(vmx->vmcs);
 
+       vmx->io_bitmap_a = kvm->arch.io_bitmap_a;
+       vmx->io_bitmap_b = kvm->arch.io_bitmap_b;
+
        cpu = get_cpu();
        vmx_vcpu_load(&vmx->vcpu, cpu);
        err = vmx_vcpu_setup(vmx);
@@ -3175,6 +3183,131 @@ static int get_ept_level(void)
        return VMX_EPT_DEFAULT_GAW + 1;
 }
 
+
+static struct kvm_io_bitmap_page *
+vmx_find_io_bitmap_page(struct list_head *list, struct page *page,
+                       void *va_new_pg)
+{
+       struct kvm_io_bitmap_page *bitmap_page;
+
+       list_for_each_entry(bitmap_page, list, io_bitmap_list) {
+               bool found;
+               void *va;
+
+               va = kmap(bitmap_page->page);
+               found = !memcmp(va_new_pg, va, PAGE_SIZE);
+               kunmap(bitmap_page->page);
+               if (found) {
+                       kref_get(&bitmap_page->ref);
+                       return bitmap_page;
+               }
+       }
+
+       bitmap_page = kmalloc(sizeof(struct kvm_io_bitmap_page), GFP_KERNEL);
+       if (!bitmap_page)
+               return NULL;
+
+       get_page(page);
+       bitmap_page->page = page;
+       kref_init(&bitmap_page->ref);
+       INIT_LIST_HEAD(&bitmap_page->io_bitmap_list);
+       list_add(&bitmap_page->io_bitmap_list, list);
+
+       return bitmap_page;
+}
+
+static void vmx_build_io_bitmap(void *va, struct kvm_ioport_list *ioports,
+                               unsigned int start, unsigned int limit)
+{
+       int i;
+
+       memset(va, 0xff, PAGE_SIZE);
+       for (i = 0; i < ioports->nranges; i++) {
+               struct kvm_ioport *ioport = &ioports->ioports[i];
+               __u32 addr, n;
+
+               addr = ioport->addr;
+               for (n = addr; n < addr + ioport->len; n++) {
+                       if (n < start)
+                               continue;
+                       if (n > limit)
+                               goto out;
+                       clear_bit(n - start, va);
+               }
+       }
+out:
+       return;
+}
+
+static int vmx_open_io_ports(struct kvm *kvm, struct kvm_ioport_list *ioports)
+{
+       struct page *page;
+       struct kvm_io_bitmap_page *bitmap_page_a, *bitmap_page_b;
+       void *va;
+       int ret = -ENOMEM;
+
+       mutex_lock(&io_bitmap_mutex);
+       page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+       if (!page)
+               goto out_unlock;
+
+       va = kmap(page);
+       vmx_build_io_bitmap(va, ioports, 0, 0x7fff);
+       bitmap_page_a = vmx_find_io_bitmap_page(&io_bitmap_pages_a, page, va);
+       kunmap(page);
+       __free_page(page);
+
+       page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+       if (!page)
+               goto out_unlock;
+
+       va = kmap(page);
+       vmx_build_io_bitmap(va, ioports, 0x8000, 0xffff);
+       bitmap_page_b = vmx_find_io_bitmap_page(&io_bitmap_pages_b, page, va);
+       kunmap(page);
+       __free_page(page);
+
+       if (!bitmap_page_a || !bitmap_page_b)
+               goto out_unlock;
+
+       kvm->arch.io_bitmap_a = bitmap_page_a;
+       kvm->arch.io_bitmap_b = bitmap_page_b;
+
+       ret = 0;
+out_unlock:
+       mutex_unlock(&io_bitmap_mutex);
+       return ret;
+
+}
+
+static void vmx_io_bitmap_kref_put(struct kref *kref)
+{
+       struct kvm_io_bitmap_page *page =
+               container_of(kref, struct kvm_io_bitmap_page, ref);
+
+       mutex_lock(&io_bitmap_mutex);
+       list_del(&page->io_bitmap_list);
+       __free_page(page->page);
+       kfree(page);
+       mutex_unlock(&io_bitmap_mutex);
+}
+
+static void vmx_release_io_bitmaps(struct kvm *kvm)
+{
+       struct kvm_io_bitmap_page *io_bitmap_a, *io_bitmap_b;
+
+       io_bitmap_a = kvm->arch.io_bitmap_a;
+       io_bitmap_b = kvm->arch.io_bitmap_b;
+
+       WARN_ON(!kvm->arch.io_bitmap_a);
+       WARN_ON(!kvm->arch.io_bitmap_b);
+
+       if (io_bitmap_a)
+               kref_put(&io_bitmap_a->ref, vmx_io_bitmap_kref_put);
+       if (io_bitmap_b)
+               kref_put(&io_bitmap_b->ref, vmx_io_bitmap_kref_put);
+}
+
 static struct kvm_x86_ops vmx_x86_ops = {
        .cpu_has_kvm_support = cpu_has_kvm_support,
        .disabled_by_bios = vmx_disabled_by_bios,
@@ -3231,6 +3364,9 @@ static struct kvm_x86_ops vmx_x86_ops = 
 
        .set_tss_addr = vmx_set_tss_addr,
        .get_tdp_level = get_ept_level,
+
+       .open_io_ports = vmx_open_io_ports,
+       .release_io_bitmaps = vmx_release_io_bitmaps,
 };
 
 static int __init vmx_init(void)
@@ -3238,35 +3374,12 @@ static int __init vmx_init(void)
        void *va;
        int r;
 
-       vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-       if (!vmx_io_bitmap_a)
-               return -ENOMEM;
-
-       vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-       if (!vmx_io_bitmap_b) {
-               r = -ENOMEM;
-               goto out;
-       }
-
        vmx_msr_bitmap = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
        if (!vmx_msr_bitmap) {
                r = -ENOMEM;
-               goto out1;
+               goto out;
        }
 
-       /*
-        * Allow direct access to the PC debug port (it is often used for I/O
-        * delays, but the vmexits simply slow things down).
-        */
-       va = kmap(vmx_io_bitmap_a);
-       memset(va, 0xff, PAGE_SIZE);
-       clear_bit(0x80, va);
-       kunmap(vmx_io_bitmap_a);
-
-       va = kmap(vmx_io_bitmap_b);
-       memset(va, 0xff, PAGE_SIZE);
-       kunmap(vmx_io_bitmap_b);
-
        va = kmap(vmx_msr_bitmap);
        memset(va, 0xff, PAGE_SIZE);
        kunmap(vmx_msr_bitmap);
@@ -3275,7 +3388,7 @@ static int __init vmx_init(void)
 
        r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
        if (r)
-               goto out2;
+               goto out1;
 
        vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_FS_BASE);
        vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_GS_BASE);
@@ -3293,20 +3406,15 @@ static int __init vmx_init(void)
 
        return 0;
 
-out2:
-       __free_page(vmx_msr_bitmap);
 out1:
-       __free_page(vmx_io_bitmap_b);
+       __free_page(vmx_msr_bitmap);
 out:
-       __free_page(vmx_io_bitmap_a);
        return r;
 }
 
 static void __exit vmx_exit(void)
 {
        __free_page(vmx_msr_bitmap);
-       __free_page(vmx_io_bitmap_b);
-       __free_page(vmx_io_bitmap_a);
 
        kvm_exit();
 }
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -447,6 +447,8 @@ static u32 emulated_msrs[] = {
        MSR_IA32_MISC_ENABLE,
 };
 
+static struct kvm_ioport_list *allowed_open_ioports;
+
 static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
        if (efer & efer_reserved_bits) {
@@ -790,6 +792,7 @@ int kvm_dev_ioctl_check_extension(long e
        case KVM_CAP_PIT:
        case KVM_CAP_NOP_IO_DELAY:
        case KVM_CAP_MP_STATE:
+       case KVM_CAP_OPEN_IOPORT:
                r = 1;
                break;
        case KVM_CAP_VAPIC:
@@ -1494,6 +1497,56 @@ static int kvm_vm_ioctl_set_pit(struct k
        return r;
 }
 
+static int kvm_vm_ioctl_set_ioport(struct kvm *kvm, __u32 nranges,
+                                  struct kvm_ioport_list __user *ioports)
+{
+       struct kvm_ioport_list *ioport_entries;
+       int r, i, nr_ports_ok = 0;
+
+       r = -E2BIG;
+       if (nranges > KVM_MAX_IOPORT_RANGES)
+               goto out;
+       r = -ENOMEM;
+       ioport_entries = vmalloc(nranges * sizeof(struct kvm_ioport) +
+                                sizeof(struct kvm_ioport_list));
+       if (!ioport_entries)
+               goto out;
+       r = -EFAULT;
+       if (copy_from_user(ioport_entries, ioports,
+                          nranges * sizeof(struct kvm_ioport) +
+                          sizeof(struct kvm_ioport_list)))
+               goto out_free;
+       r = -EPERM;
+       if (ioport_entries->nranges != nranges)
+               goto out_free;
+
+       for (i = 0; i < ioport_entries->nranges; i++) {
+               int n;
+               struct kvm_ioport *user_ioport = &ioport_entries->ioports[i];
+
+               for (n = 0; n < allowed_open_ioports->nranges; n++) {
+                       struct kvm_ioport *allowed_ioport;
+                       allowed_ioport = &allowed_open_ioports->ioports[n];
+                       if (user_ioport->addr != allowed_ioport->addr ||
+                           user_ioport->len > allowed_ioport->len)
+                               continue;
+                       else {
+                               nr_ports_ok++;
+                               break;
+                       }
+               }
+       }
+       if (nr_ports_ok != ioport_entries->nranges)
+               goto out_free;
+
+       r = kvm_x86_ops->open_io_ports(kvm, ioport_entries);
+
+out_free:
+       vfree(ioport_entries);
+out:
+       return r;
+}
+
 /*
  * Get (and clear) the dirty memory log for a memory slot.
  */
@@ -1678,6 +1731,16 @@ long kvm_arch_vm_ioctl(struct file *filp
                r = 0;
                break;
        }
+       case KVM_SET_OPEN_IOPORT: {
+               struct kvm_ioport_list ioport_list;
+               r = -EFAULT;
+               if (copy_from_user(&ioport_list, argp, sizeof ioport_list))
+                       goto out;
+               r = kvm_vm_ioctl_set_ioport(kvm, ioport_list.nranges, argp);
+               if (r)
+                       goto out;
+               break;
+       }
        default:
                ;
        }
@@ -1700,6 +1763,25 @@ static void kvm_init_msr_list(void)
        num_msrs_to_save = j;
 }
 
+static int kvm_init_ioport_list(void)
+{
+       allowed_open_ioports = kmalloc(sizeof(struct kvm_ioport) +
+                                      sizeof(struct kvm_ioport_list), 
GFP_KERNEL);
+       if (!allowed_open_ioports)
+               return -ENOMEM;
+       allowed_open_ioports->nranges = 1;
+       allowed_open_ioports->ioports[0].addr = 0x80;
+       allowed_open_ioports->ioports[0].len = 1;
+
+       return 0;
+}
+
+static void kvm_exit_ioport_list(void)
+{
+       kfree(allowed_open_ioports);
+       allowed_open_ioports = NULL;
+}
+
 /*
  * Only apic need an MMIO device hook, so shortcut now..
  */
@@ -2384,6 +2466,9 @@ int kvm_arch_init(void *opaque)
        r = kvm_mmu_module_init();
        if (r)
                goto out;
+       r = kvm_init_ioport_list();
+       if (r)
+               goto out_exit_mmu;
 
        kvm_init_msr_list();
 
@@ -2394,6 +2479,8 @@ int kvm_arch_init(void *opaque)
                        PT_DIRTY_MASK, PT64_NX_MASK, 0);
        return 0;
 
+out_exit_mmu:
+       kvm_mmu_module_exit();
 out:
        return r;
 }
@@ -2402,6 +2489,7 @@ void kvm_arch_exit(void)
 {
        kvm_x86_ops = NULL;
        kvm_mmu_module_exit();
+       kvm_exit_ioport_list();
 }
 
 int kvm_emulate_halt(struct kvm_vcpu *vcpu)
@@ -3859,14 +3947,43 @@ void kvm_arch_vcpu_uninit(struct kvm_vcp
        free_page((unsigned long)vcpu->arch.pio_data);
 }
 
+static int kvm_open_def_ioports(struct kvm *kvm)
+{
+       struct kvm_ioport_list *ioports;
+       int ret;
+
+       ioports = kzalloc(sizeof(struct kvm_ioport) +
+                         sizeof(struct kvm_ioport_list), GFP_KERNEL);
+       if (!ioports)
+               return -ENOMEM;
+
+       /*
+        * Allow direct access to the PC debug port (it is often used for I/O
+        * delays, but the vmexits simply slow things down).
+        */
+       ioports->nranges = 1;
+       ioports->ioports[0].addr = 0x80;
+       ioports->ioports[0].len = 1;
+
+       ret = kvm_x86_ops->open_io_ports(kvm, ioports);
+       kfree(ioports);
+       return ret;
+}
+
 struct  kvm *kvm_arch_create_vm(void)
 {
+       int ret;
        struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
 
        if (!kvm)
                return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
+       ret = kvm_open_def_ioports(kvm);
+       if (ret) {
+               kfree(kvm);
+               kvm = ERR_PTR(ret);
+       }
 
        return kvm;
 }
@@ -3908,6 +4025,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm
                put_page(kvm->arch.apic_access_page);
        if (kvm->arch.ept_identity_pagetable)
                put_page(kvm->arch.ept_identity_pagetable);
+       kvm_x86_ops->release_io_bitmaps(kvm);
        kfree(kvm);
 }
 
Index: kvm/include/asm-x86/kvm.h
===================================================================
--- kvm.orig/include/asm-x86/kvm.h
+++ kvm/include/asm-x86/kvm.h
@@ -209,6 +209,17 @@ struct kvm_pit_state {
        struct kvm_pit_channel_state channels[3];
 };
 
+/* for KVM_SET_OPEN_IOPORT */
+struct kvm_ioport {
+       __u32 addr;
+       __u32 len;
+};
+
+struct kvm_ioport_list {
+       __u32 nranges;
+       struct kvm_ioport ioports[0];
+};
+
 #define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
 #define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
 #define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)
Index: kvm/include/asm-x86/kvm_host.h
===================================================================
--- kvm.orig/include/asm-x86/kvm_host.h
+++ kvm/include/asm-x86/kvm_host.h
@@ -78,6 +78,7 @@
 #define KVM_MIN_FREE_MMU_PAGES 5
 #define KVM_REFILL_PAGES 25
 #define KVM_MAX_CPUID_ENTRIES 40
+#define KVM_MAX_IOPORT_RANGES 100
 
 extern spinlock_t kvm_lock;
 extern struct list_head vm_list;
@@ -296,6 +297,12 @@ struct kvm_mem_alias {
        gfn_t target_gfn;
 };
 
+struct kvm_io_bitmap_page {
+       struct page *page;
+       struct list_head io_bitmap_list;
+       struct kref ref;
+};
+
 struct kvm_arch{
        int naliases;
        struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
@@ -320,6 +327,9 @@ struct kvm_arch{
 
        struct page *ept_identity_pagetable;
        bool ept_identity_pagetable_done;
+
+       struct kvm_io_bitmap_page *io_bitmap_a;
+       struct kvm_io_bitmap_page *io_bitmap_b;
 };
 
 struct kvm_vm_stat {
@@ -429,6 +439,9 @@ struct kvm_x86_ops {
 
        int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
        int (*get_tdp_level)(void);
+
+       int (*open_io_ports)(struct kvm *kvm, struct kvm_ioport_list *ioports);
+       void (*release_io_bitmaps)(struct kvm *kvm);
 };
 
 extern struct kvm_x86_ops *kvm_x86_ops;
Index: kvm/include/linux/kvm.h
===================================================================
--- kvm.orig/include/linux/kvm.h
+++ kvm/include/linux/kvm.h
@@ -346,6 +346,7 @@ struct kvm_trace_rec {
 #define KVM_CAP_NOP_IO_DELAY 12
 #define KVM_CAP_PV_MMU 13
 #define KVM_CAP_MP_STATE 14
+#define KVM_CAP_OPEN_IOPORT 15
 
 /*
  * ioctls for VM fds
@@ -371,6 +372,7 @@ struct kvm_trace_rec {
 #define KVM_CREATE_PIT           _IO(KVMIO,  0x64)
 #define KVM_GET_PIT              _IOWR(KVMIO, 0x65, struct kvm_pit_state)
 #define KVM_SET_PIT              _IOR(KVMIO,  0x66, struct kvm_pit_state)
+#define KVM_SET_OPEN_IOPORT      _IOR(KVMIO,  0x67, struct kvm_ioport_list)
 
 /*
  * ioctls for vcpu fds

-- 

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to