From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marcelo Tosatti Subject: [patch 02/12] KVM: allow multiple IO bitmap pages, provide userspace interface Date: Thu, 29 May 2008 19:22:51 -0300 Message-ID: <20080529222828.606999090@localhost.localdomain> References: <20080529222249.563011248@localhost.localdomain> Cc: Chris Wright , Glauber Costa , Anthony Liguori , kvm@vger.kernel.org, Marcelo Tosatti To: Avi Kivity Return-path: Received: from mx1.redhat.com ([66.187.233.31]:42875 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756072AbYE2Wh5 (ORCPT ); Thu, 29 May 2008 18:37:57 -0400 Content-Disposition: inline; filename=kvm-open-pmtimer Sender: kvm-owner@vger.kernel.org List-ID: 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 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 #include #include +#include #include @@ -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 #include #include +#include #include #include @@ -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 --