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 /drivers/kvm/kvm_main.c | |
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>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 54 |
1 files changed, 40 insertions, 14 deletions
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 | ||