diff options
author | Avi Kivity <avi@qumranet.com> | 2007-02-22 05:58:31 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:23 -0400 |
commit | 9a2bb7f486dc639a1cf2ad803bf2227f0dc0809d (patch) | |
tree | db323e11ae5a5286a1e344b444162be53bc4d9fc | |
parent | 1ea252afcd4b264b71d9c3f55358ff5ba4c04f1b (diff) |
KVM: Use a shared page for kernel/user communication when runing a vcpu
Instead of passing a 'struct kvm_run' back and forth between the kernel and
userspace, allocate a page and allow the user to mmap() it. This reduces
needless copying and makes the interface expandable by providing lots of
free space.
Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r-- | drivers/kvm/kvm.h | 1 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 54 | ||||
-rw-r--r-- | include/linux/kvm.h | 6 |
3 files changed, 44 insertions, 17 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 0d122bf889db..901b8d917b55 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -228,6 +228,7 @@ struct kvm_vcpu { | |||
228 | struct mutex mutex; | 228 | struct mutex mutex; |
229 | int cpu; | 229 | int cpu; |
230 | int launched; | 230 | int launched; |
231 | struct kvm_run *run; | ||
231 | int interrupt_window_open; | 232 | int interrupt_window_open; |
232 | unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ | 233 | unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ |
233 | #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) | 234 | #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 946ed86a0595..42be8a8f299d 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -355,6 +355,8 @@ static void kvm_free_vcpu(struct kvm_vcpu *vcpu) | |||
355 | kvm_mmu_destroy(vcpu); | 355 | kvm_mmu_destroy(vcpu); |
356 | vcpu_put(vcpu); | 356 | vcpu_put(vcpu); |
357 | kvm_arch_ops->vcpu_free(vcpu); | 357 | kvm_arch_ops->vcpu_free(vcpu); |
358 | free_page((unsigned long)vcpu->run); | ||
359 | vcpu->run = NULL; | ||
358 | } | 360 | } |
359 | 361 | ||
360 | static void kvm_free_vcpus(struct kvm *kvm) | 362 | static void kvm_free_vcpus(struct kvm *kvm) |
@@ -1887,6 +1889,33 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, | |||
1887 | return r; | 1889 | return r; |
1888 | } | 1890 | } |
1889 | 1891 | ||
1892 | static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, | ||
1893 | unsigned long address, | ||
1894 | int *type) | ||
1895 | { | ||
1896 | struct kvm_vcpu *vcpu = vma->vm_file->private_data; | ||
1897 | unsigned long pgoff; | ||
1898 | struct page *page; | ||
1899 | |||
1900 | *type = VM_FAULT_MINOR; | ||
1901 | pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; | ||
1902 | if (pgoff != 0) | ||
1903 | return NOPAGE_SIGBUS; | ||
1904 | page = virt_to_page(vcpu->run); | ||
1905 | get_page(page); | ||
1906 | return page; | ||
1907 | } | ||
1908 | |||
1909 | static struct vm_operations_struct kvm_vcpu_vm_ops = { | ||
1910 | .nopage = kvm_vcpu_nopage, | ||
1911 | }; | ||
1912 | |||
1913 | static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma) | ||
1914 | { | ||
1915 | vma->vm_ops = &kvm_vcpu_vm_ops; | ||
1916 | return 0; | ||
1917 | } | ||
1918 | |||
1890 | static int kvm_vcpu_release(struct inode *inode, struct file *filp) | 1919 | static int kvm_vcpu_release(struct inode *inode, struct file *filp) |
1891 | { | 1920 | { |
1892 | struct kvm_vcpu *vcpu = filp->private_data; | 1921 | struct kvm_vcpu *vcpu = filp->private_data; |
@@ -1899,6 +1928,7 @@ static struct file_operations kvm_vcpu_fops = { | |||
1899 | .release = kvm_vcpu_release, | 1928 | .release = kvm_vcpu_release, |
1900 | .unlocked_ioctl = kvm_vcpu_ioctl, | 1929 | .unlocked_ioctl = kvm_vcpu_ioctl, |
1901 | .compat_ioctl = kvm_vcpu_ioctl, | 1930 | .compat_ioctl = kvm_vcpu_ioctl, |
1931 | .mmap = kvm_vcpu_mmap, | ||
1902 | }; | 1932 | }; |
1903 | 1933 | ||
1904 | /* | 1934 | /* |
@@ -1947,6 +1977,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) | |||
1947 | { | 1977 | { |
1948 | int r; | 1978 | int r; |
1949 | struct kvm_vcpu *vcpu; | 1979 | struct kvm_vcpu *vcpu; |
1980 | struct page *page; | ||
1950 | 1981 | ||
1951 | r = -EINVAL; | 1982 | r = -EINVAL; |
1952 | if (!valid_vcpu(n)) | 1983 | if (!valid_vcpu(n)) |
@@ -1961,6 +1992,12 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) | |||
1961 | return -EEXIST; | 1992 | return -EEXIST; |
1962 | } | 1993 | } |
1963 | 1994 | ||
1995 | page = alloc_page(GFP_KERNEL | __GFP_ZERO); | ||
1996 | r = -ENOMEM; | ||
1997 | if (!page) | ||
1998 | goto out_unlock; | ||
1999 | vcpu->run = page_address(page); | ||
2000 | |||
1964 | vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, | 2001 | vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, |
1965 | FX_IMAGE_ALIGN); | 2002 | FX_IMAGE_ALIGN); |
1966 | vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; | 2003 | vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; |
@@ -1990,6 +2027,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) | |||
1990 | 2027 | ||
1991 | out_free_vcpus: | 2028 | out_free_vcpus: |
1992 | kvm_free_vcpu(vcpu); | 2029 | kvm_free_vcpu(vcpu); |
2030 | out_unlock: | ||
1993 | mutex_unlock(&vcpu->mutex); | 2031 | mutex_unlock(&vcpu->mutex); |
1994 | out: | 2032 | out: |
1995 | return r; | 2033 | return r; |
@@ -2003,21 +2041,9 @@ static long kvm_vcpu_ioctl(struct file *filp, | |||
2003 | int r = -EINVAL; | 2041 | int r = -EINVAL; |
2004 | 2042 | ||
2005 | switch (ioctl) { | 2043 | switch (ioctl) { |
2006 | case KVM_RUN: { | 2044 | case KVM_RUN: |
2007 | struct kvm_run kvm_run; | 2045 | r = kvm_vcpu_ioctl_run(vcpu, vcpu->run); |
2008 | |||
2009 | r = -EFAULT; | ||
2010 | if (copy_from_user(&kvm_run, argp, sizeof kvm_run)) | ||
2011 | goto out; | ||
2012 | r = kvm_vcpu_ioctl_run(vcpu, &kvm_run); | ||
2013 | if (r < 0 && r != -EINTR) | ||
2014 | goto out; | ||
2015 | if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) { | ||
2016 | r = -EFAULT; | ||
2017 | goto out; | ||
2018 | } | ||
2019 | break; | 2046 | break; |
2020 | } | ||
2021 | case KVM_GET_REGS: { | 2047 | case KVM_GET_REGS: { |
2022 | struct kvm_regs kvm_regs; | 2048 | struct kvm_regs kvm_regs; |
2023 | 2049 | ||
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 275354ffa1cb..d88e7508ee0a 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -11,7 +11,7 @@ | |||
11 | #include <asm/types.h> | 11 | #include <asm/types.h> |
12 | #include <linux/ioctl.h> | 12 | #include <linux/ioctl.h> |
13 | 13 | ||
14 | #define KVM_API_VERSION 4 | 14 | #define KVM_API_VERSION 5 |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * Architectural interrupt line count, and the size of the bitmap needed | 17 | * Architectural interrupt line count, and the size of the bitmap needed |
@@ -49,7 +49,7 @@ enum kvm_exit_reason { | |||
49 | KVM_EXIT_SHUTDOWN = 8, | 49 | KVM_EXIT_SHUTDOWN = 8, |
50 | }; | 50 | }; |
51 | 51 | ||
52 | /* for KVM_RUN */ | 52 | /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ |
53 | struct kvm_run { | 53 | struct kvm_run { |
54 | /* in */ | 54 | /* in */ |
55 | __u32 emulated; /* skip current instruction */ | 55 | __u32 emulated; /* skip current instruction */ |
@@ -233,7 +233,7 @@ struct kvm_dirty_log { | |||
233 | /* | 233 | /* |
234 | * ioctls for vcpu fds | 234 | * ioctls for vcpu fds |
235 | */ | 235 | */ |
236 | #define KVM_RUN _IOWR(KVMIO, 2, struct kvm_run) | 236 | #define KVM_RUN _IO(KVMIO, 16) |
237 | #define KVM_GET_REGS _IOR(KVMIO, 3, struct kvm_regs) | 237 | #define KVM_GET_REGS _IOR(KVMIO, 3, struct kvm_regs) |
238 | #define KVM_SET_REGS _IOW(KVMIO, 4, struct kvm_regs) | 238 | #define KVM_SET_REGS _IOW(KVMIO, 4, struct kvm_regs) |
239 | #define KVM_GET_SREGS _IOR(KVMIO, 5, struct kvm_sregs) | 239 | #define KVM_GET_SREGS _IOR(KVMIO, 5, struct kvm_sregs) |