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