aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Swierk <eswierk@aristanetworks.com>2009-10-15 18:21:43 -0400
committerAvi Kivity <avi@redhat.com>2009-12-03 02:32:18 -0500
commitffde22ac53b6d6b1d7206f1172176a667eead778 (patch)
tree16ab77d364ba26928136e6d18463845941b6dd2c
parent94c30d9ca6fd00a69e367b91b6e13572c41938c5 (diff)
KVM: Xen PV-on-HVM guest support
Support for Xen PV-on-HVM guests can be implemented almost entirely in userspace, except for handling one annoying MSR that maps a Xen hypercall blob into guest address space. A generic mechanism to delegate MSR writes to userspace seems overkill and risks encouraging similar MSR abuse in the future. Thus this patch adds special support for the Xen HVM MSR. I implemented a new ioctl, KVM_XEN_HVM_CONFIG, that lets userspace tell KVM which MSR the guest will write to, as well as the starting address and size of the hypercall blobs (one each for 32-bit and 64-bit) that userspace has loaded from files. When the guest writes to the MSR, KVM copies one page of the blob from userspace to the guest. I've tested this patch with a hacked-up version of Gerd's userspace code, booting a number of guests (CentOS 5.3 i386 and x86_64, and FreeBSD 8.0-RC1 amd64) and exercising PV network and block devices. [jan: fix i386 build warning] [avi: future proof abi with a flags field] Signed-off-by: Ed Swierk <eswierk@aristanetworks.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--Documentation/kvm/api.txt24
-rw-r--r--arch/x86/include/asm/kvm.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h2
-rw-r--r--arch/x86/kvm/x86.c46
-rw-r--r--include/linux/kvm.h16
5 files changed, 89 insertions, 0 deletions
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index 5a4bc8cf6d04..3e8684e48506 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -593,6 +593,30 @@ struct kvm_irqchip {
593 } chip; 593 } chip;
594}; 594};
595 595
5964.27 KVM_XEN_HVM_CONFIG
597
598Capability: KVM_CAP_XEN_HVM
599Architectures: x86
600Type: vm ioctl
601Parameters: struct kvm_xen_hvm_config (in)
602Returns: 0 on success, -1 on error
603
604Sets the MSR that the Xen HVM guest uses to initialize its hypercall
605page, and provides the starting address and size of the hypercall
606blobs in userspace. When the guest writes the MSR, kvm copies one
607page of a blob (32- or 64-bit, depending on the vcpu mode) to guest
608memory.
609
610struct kvm_xen_hvm_config {
611 __u32 flags;
612 __u32 msr;
613 __u64 blob_addr_32;
614 __u64 blob_addr_64;
615 __u8 blob_size_32;
616 __u8 blob_size_64;
617 __u8 pad2[30];
618};
619
5965. The kvm_run structure 6205. The kvm_run structure
597 621
598Application code obtains a pointer to the kvm_run structure by 622Application code obtains a pointer to the kvm_run structure by
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index f02e87a5206f..ef9b4b73cce4 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -19,6 +19,7 @@
19#define __KVM_HAVE_MSIX 19#define __KVM_HAVE_MSIX
20#define __KVM_HAVE_MCE 20#define __KVM_HAVE_MCE
21#define __KVM_HAVE_PIT_STATE2 21#define __KVM_HAVE_PIT_STATE2
22#define __KVM_HAVE_XEN_HVM
22 23
23/* Architectural interrupt line count. */ 24/* Architectural interrupt line count. */
24#define KVM_NR_INTERRUPTS 256 25#define KVM_NR_INTERRUPTS 256
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 179a919f53a4..36f3b53f5c27 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -410,6 +410,8 @@ struct kvm_arch{
410 410
411 unsigned long irq_sources_bitmap; 411 unsigned long irq_sources_bitmap;
412 u64 vm_init_tsc; 412 u64 vm_init_tsc;
413
414 struct kvm_xen_hvm_config xen_hvm_config;
413}; 415};
414 416
415struct kvm_vm_stat { 417struct kvm_vm_stat {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5d450cc6f841..bb842db3ee7c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -857,6 +857,38 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 data)
857 return 0; 857 return 0;
858} 858}
859 859
860static int xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
861{
862 struct kvm *kvm = vcpu->kvm;
863 int lm = is_long_mode(vcpu);
864 u8 *blob_addr = lm ? (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_64
865 : (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_32;
866 u8 blob_size = lm ? kvm->arch.xen_hvm_config.blob_size_64
867 : kvm->arch.xen_hvm_config.blob_size_32;
868 u32 page_num = data & ~PAGE_MASK;
869 u64 page_addr = data & PAGE_MASK;
870 u8 *page;
871 int r;
872
873 r = -E2BIG;
874 if (page_num >= blob_size)
875 goto out;
876 r = -ENOMEM;
877 page = kzalloc(PAGE_SIZE, GFP_KERNEL);
878 if (!page)
879 goto out;
880 r = -EFAULT;
881 if (copy_from_user(page, blob_addr + (page_num * PAGE_SIZE), PAGE_SIZE))
882 goto out_free;
883 if (kvm_write_guest(kvm, page_addr, page, PAGE_SIZE))
884 goto out_free;
885 r = 0;
886out_free:
887 kfree(page);
888out:
889 return r;
890}
891
860int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) 892int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
861{ 893{
862 switch (msr) { 894 switch (msr) {
@@ -972,6 +1004,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
972 "0x%x data 0x%llx\n", msr, data); 1004 "0x%x data 0x%llx\n", msr, data);
973 break; 1005 break;
974 default: 1006 default:
1007 if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
1008 return xen_hvm_config(vcpu, data);
975 if (!ignore_msrs) { 1009 if (!ignore_msrs) {
976 pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n", 1010 pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
977 msr, data); 1011 msr, data);
@@ -1246,6 +1280,7 @@ int kvm_dev_ioctl_check_extension(long ext)
1246 case KVM_CAP_PIT2: 1280 case KVM_CAP_PIT2:
1247 case KVM_CAP_PIT_STATE2: 1281 case KVM_CAP_PIT_STATE2:
1248 case KVM_CAP_SET_IDENTITY_MAP_ADDR: 1282 case KVM_CAP_SET_IDENTITY_MAP_ADDR:
1283 case KVM_CAP_XEN_HVM:
1249 r = 1; 1284 r = 1;
1250 break; 1285 break;
1251 case KVM_CAP_COALESCED_MMIO: 1286 case KVM_CAP_COALESCED_MMIO:
@@ -2441,6 +2476,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
2441 r = 0; 2476 r = 0;
2442 break; 2477 break;
2443 } 2478 }
2479 case KVM_XEN_HVM_CONFIG: {
2480 r = -EFAULT;
2481 if (copy_from_user(&kvm->arch.xen_hvm_config, argp,
2482 sizeof(struct kvm_xen_hvm_config)))
2483 goto out;
2484 r = -EINVAL;
2485 if (kvm->arch.xen_hvm_config.flags)
2486 goto out;
2487 r = 0;
2488 break;
2489 }
2444 default: 2490 default:
2445 ; 2491 ;
2446 } 2492 }
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index f8f8900fc5ec..b694c1d2f918 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -436,6 +436,9 @@ struct kvm_ioeventfd {
436#endif 436#endif
437#define KVM_CAP_IOEVENTFD 36 437#define KVM_CAP_IOEVENTFD 36
438#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37 438#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
439#ifdef __KVM_HAVE_XEN_HVM
440#define KVM_CAP_XEN_HVM 38
441#endif
439 442
440#ifdef KVM_CAP_IRQ_ROUTING 443#ifdef KVM_CAP_IRQ_ROUTING
441 444
@@ -488,6 +491,18 @@ struct kvm_x86_mce {
488}; 491};
489#endif 492#endif
490 493
494#ifdef KVM_CAP_XEN_HVM
495struct kvm_xen_hvm_config {
496 __u32 flags;
497 __u32 msr;
498 __u64 blob_addr_32;
499 __u64 blob_addr_64;
500 __u8 blob_size_32;
501 __u8 blob_size_64;
502 __u8 pad2[30];
503};
504#endif
505
491#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0) 506#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
492 507
493struct kvm_irqfd { 508struct kvm_irqfd {
@@ -546,6 +561,7 @@ struct kvm_irqfd {
546#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config) 561#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config)
547#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78) 562#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78)
548#define KVM_IOEVENTFD _IOW(KVMIO, 0x79, struct kvm_ioeventfd) 563#define KVM_IOEVENTFD _IOW(KVMIO, 0x79, struct kvm_ioeventfd)
564#define KVM_XEN_HVM_CONFIG _IOW(KVMIO, 0x7a, struct kvm_xen_hvm_config)
549 565
550/* 566/*
551 * ioctls for vcpu fds 567 * ioctls for vcpu fds