KVM: Save/resume support
cover KVM: Save/resume support
The following patchset adds the missing bits that allow kvm virtual machines to be suspended and resumed, with appropriate userspace support.
The changes are:
- expose the pending interrupt bitmap to userspace
- tsc save/restore
- msr save/restore
Signature · 8 lines
Do not meddle in the internals of kernels, for they are subtle and quick to panic. ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
PATCH 1/3 KVM: Expose interrupt bitmap
From: Uri Lublin <uril-atKUWr5tajBWk0Htik3J/[email protected]>
Expose all not-yet-delivered interrupts to userspace. This allows a guest to be saved and resumed even if some interrupts are yet pending.
drivers/kvm/kvm.h +2 -1
@@ -13,6 +13,7 @@#include <linux/mm.h> #include "vmx.h" +#include <linux/kvm.h> #define CR0_PE_MASK (1ULL << 0)#define CR0_TS_MASK (1ULL << 3)
@@ -164,7 +165,7 @@ struct kvm_vcpu {int cpu;int launched;unsigned long irq_summary;/* bit vector: 1 per word in irq_pending */ -#define NR_IRQ_WORDS (256 / BITS_PER_LONG) +#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)unsigned long irq_pending[NR_IRQ_WORDS ];unsigned long regs[NR_VCPU_REGS ];/* for rsp: vcpu_load_rsp_rip() */ unsigned long rip;/* needs vcpu_load_rsp_rip() */
drivers/kvm/kvm_main.c +11 -1
@@ -3000,7 +3000,8 @@ static int kvm_dev_ioctl_get_sregs(struc sregs->efer = vcpu->shadow_efer; sregs->apic_base = vcpu->apic_base; - sregs->pending_int = vcpu->irq_summary !=0 ; +memcpy (sregs->interrupt_bitmap, vcpu->irq_pending, +sizeof sregs->interrupt_bitmap);vcpu_put (vcpu);
@@ -3034,6 +3035,7 @@ static int kvm_dev_ioctl_set_sregs(struc {struct kvm_vcpu *vcpu;int mmu_reset_needed =0 ; +int i;if (sregs->vcpu <0 || sregs->vcpu >=KVM_MAX_VCPUS )return -EINVAL ;
@@ -3083,6 +3085,14 @@ static int kvm_dev_ioctl_set_sregs(strucif (mmu_reset_needed)kvm_mmu_reset_context (vcpu); + +memcpy (vcpu->irq_pending, sregs->interrupt_bitmap, +sizeof vcpu->irq_pending); + vcpu->irq_summary =0 ; +for (i =0 ; i <NR_IRQ_WORDS ; ++i) +if (vcpu->irq_pending[i]) +__set_bit (i, &vcpu->irq_summary); +vcpu_put (vcpu);return 0 ;
include/linux/kvm.h +10 -4
@@ -11,6 +11,15 @@#include <asm/types.h> #include <linux/ioctl.h> +/* +* Architectural interrupt line count, and the size of the bitmap needed +* to hold them. +*/ +#define KVM_NR_INTERRUPTS 256 +#define KVM_IRQ_BITMAP_SIZE_BYTES ((KVM_NR_INTERRUPTS + 7) / 8) +#define KVM_IRQ_BITMAP_SIZE (type) (KVM_IRQ_BITMAP_SIZE_BYTES / sizeof(type)) + +/* for KVM_CREATE_MEMORY_REGION */ struct kvm_memory_region {__u32 slot;
@@ -129,10 +138,7 @@ struct kvm_sregs {__u64 cr0, cr2, cr3, cr4, cr8;__u64 efer;__u64 apic_base; - -/* out (KVM_GET_SREGS) */ -__u32 pending_int; -__u32 padding2; +__u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE (__u64)]; };/* for KVM_TRANSLATE */
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
PATCH 2/3 KVM: Add time stamp counter msr and accessors
In reply to Avi KivityFrom: Uri Lublin <uril-atKUWr5tajBWk0Htik3J/[email protected]>
Add a couple of accessors for the time stamp counter, and expose the tsc msr.
drivers/kvm/kvm_main.c +31 -9
@@ -121,6 +121,7 @@ static const u32 vmx_msr_index[] = {#define TSS_REDIRECTION_SIZE (256 / 8)#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) +#define MSR_IA32_TIME_STAMP_COUNTER 0x010#define MSR_IA32_FEATURE_CONTROL 0x03a#define MSR_IA32_VMX_BASIC_MSR 0x480#define MSR_IA32_VMX_PINBASED_CTLS_MSR 0x481
@@ -716,6 +717,31 @@ static void inject_gp(struct kvm_vcpu *v INTR_INFO_VALID_MASK); } +/* +* reads and returns guest's timestamp counter "register" +* guest_tsc = host_tsc + tsc_offset -- 21.3 +*/ +static u64 guest_read_tsc (void ) +{ +u64 host_tsc, tsc_offset; + +rdtscll (host_tsc); + tsc_offset =vmcs_read64 (TSC_OFFSET ); +return host_tsc + tsc_offset; +} + +/* +* writes 'guest_tsc' into guest's timestamp counter "register" +* guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc +*/ +static void guest_write_tsc (u64 guest_tsc) +{ +u64 host_tsc; + +rdtscll (host_tsc); +vmcs_write64 (TSC_OFFSET , guest_tsc - host_tsc); +} +static void update_exception_bitmap (struct kvm_vcpu *vcpu) {if (vcpu->rmode.active)
@@ -1177,7 +1204,6 @@ static int kvm_vcpu_setup(struct kvm_vcpstruct descriptor_table dt;int i;int ret; -u64 tsc;int nr_good_msrs;
@@ -1247,8 +1273,7 @@ static int kvm_vcpu_setup(struct kvm_vcpvmcs_write64 (IO_BITMAP_A ,0 );vmcs_write64 (IO_BITMAP_B ,0 ); -rdtscll (tsc); -vmcs_write64 (TSC_OFFSET , -tsc); +guest_write_tsc (0 );vmcs_write64 (VMCS_LINK_POINTER ,-1ull );/* 22.3.1.5 */
@@ -2297,6 +2322,9 @@ static int handle_rdmsr(struct kvm_vcpu data =vmcs_readl (GUEST_GS_BASE );break ;#endif +case MSR_IA32_TIME_STAMP_COUNTER : + data =guest_read_tsc (); +break ;case MSR_IA32_SYSENTER_CS : data =vmcs_read32 (GUEST_SYSENTER_CS );break ;
@@ -2374,8 +2402,6 @@ static void set_efer(struct kvm_vcpu *vc#endif -#define MSR_IA32_TIME_STAMP_COUNTER 0x10 -static int handle_wrmsr (struct kvm_vcpu *vcpu,struct kvm_run *kvm_run) {u32 ecx = vcpu->regs[VCPU_REGS_RCX ];
@@ -2419,10 +2445,7 @@ static int handle_wrmsr(struct kvm_vcpubreak ;#endif case MSR_IA32_TIME_STAMP_COUNTER : { -u64 tsc; - -rdtscll (tsc); -vmcs_write64 (TSC_OFFSET , data - tsc); +guest_write_tsc (data);break ; }case MSR_IA32_UCODE_REV :
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
PATCH 3/3 KVM: Expose MSRs to userspace
In reply to Avi KivityFrom: Uri Lublin <uril-atKUWr5tajBWk0Htik3J/[email protected]>
Expose the model-specific registers to userspace. Primarily useful for save/resume.
drivers/kvm/kvm.h +1 -5
@@ -106,11 +106,7 @@ struct vmcs {char data[0 ]; }; -struct vmx_msr_entry { -u32 index; -u32 reserved; -u64 data; -}; +#define vmx_msr_entry kvm_msr_entrystruct kvm_vcpu ;
drivers/kvm/kvm_main.c +205 -35
294 lines not on this page · raw message
include/linux/kvm.h +19 -0
@@ -141,6 +141,23 @@ struct kvm_sregs {__u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE (__u64)]; }; +struct kvm_msr_entry { +__u32 index; +__u32 reserved; +__u64 data; +}; + +/* for KVM_GET_MSRS and KVM_SET_MSRS */ +struct kvm_msrs { +__u32 vcpu; +__u32 nmsrs;/* number of msrs in entries */ + +union { +struct kvm_msr_entry __user *entries; +__u64 padding; + }; +}; +/* for KVM_TRANSLATE */ struct kvm_translation {/* in */
@@ -200,5 +217,7 @@ struct kvm_dirty_log {#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 10, struct kvm_memory_region) #define KVM_CREATE_VCPU _IOW(KVMIO, 11, int /* vcpu_slot */)#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 12, struct kvm_dirty_log) +#define KVM_GET_MSRS _IOWR(KVMIO, 13, struct kvm_msrs) +#define KVM_SET_MSRS _IOW(KVMIO, 14, struct kvm_msrs)#endif
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
Re: [kvm-devel] [PATCH 3/3] KVM: Expose MSRs to userspace
Quoted 6 lines · Avi Kivity
include/linux/kvm.h +6
-0+struct kvm_msr_entry { + __u32 index; + __u32 reserved; + __u64 data; +}; +
include/linux/kvm.h struct kvm_sregs { · line 159
Quoted 10 lines
include/linux/kvm.h +10
-0+/* for KVM_GET_MSRS and KVM_SET_MSRS */ +struct kvm_msrs { + __u32 vcpu; + __u32 nmsrs; /* number of msrs in entries */ + + union { + struct kvm_msr_entry __user *entries; + __u64 padding; + }; +};
ioctl interfaces with pointers in them are generally a bad idea, though you handle most of the points against them fine here (endianess doesn't matter, padding is correct).
Still, it might be better not to set a bad example. Is accessing the MSRs actually performance critical? If not, you could define the ioctl to take only a single entry argument.
A possible alternative could also be to have a variable length argument like below, but that creates other problems:
+struct kvm_msrs {
+ __u32 vcpu; + __u32 nmsrs; /* number of msrs in entries */ + struct kvm_msr_entry entries[0]; /* followed by actual msrs */
+};
This would mean that you can't tell the transfer size from the ioctl number, but you can't do that in your code either, because you do two separate transfers.
Arnd <><
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
Re: [kvm-devel] [PATCH 3/3] KVM: Expose MSRs to userspace
Quoted 24 lines · Arnd Bergmann
Quoted 7 lines · Avi Kivity
include/linux/kvm.h +6
-0+struct kvm_msr_entry { +__u32 index; +__u32 reserved; +__u64 data; +}; +include/linux/kvm.h struct kvm_sregs { · line 159
Quoted 10 lines
include/linux/kvm.h +10
-0+/* for KVM_GET_MSRS and KVM_SET_MSRS */ +struct kvm_msrs { +__u32 vcpu; +__u32 nmsrs;/* number of msrs in entries */ + +union { +struct kvm_msr_entry __user *entries; +__u64 padding; + }; +};ioctl interfaces with pointers in them are generally a bad idea, though you handle most of the points against them fine here (endianess doesn't matter, padding is correct).
Quoted 5 lines
Still, it might be better not to set a bad example. Is accessing the MSRs actually performance critical? If not, you could define the ioctl to take only a single entry argument.
But then you can't dynamically determine which MSRs are available.
And no, reading/setting MSRs isn't performance critical for the current use cases.
Quoted 9 lines
A possible alternative could also be to have a variable length argument like below, but that creates other problems:
include/linux/kvm.h +5
-0+struct kvm_msrs { +__u32 vcpu; +__u32 nmsrs;/* number of msrs in entries */ +struct kvm_msr_entry entries[0 ];/* followed by actual msrs */ +};
Quoted 5 lines
This would mean that you can't tell the transfer size from the ioctl number, but you can't do that in your code either, because you do two separate transfers.
Heh. That was the original implementation by Uri. I felt that was wrong because _IOW() encodes the size in the ioctl number, bit the actual size is different.
Quoted 2 lines
Arnd <><
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Re: [PATCH 3/3] KVM: Expose MSRs to userspace
In reply to Avi KivityQuoted 14 lines · On Thu, 16 Nov 2006 18:04:22 -0000 Avi Kivity <[email protected]> wrote:
drivers/kvm/kvm_main.c +14
-0+static int kvm_dev_ioctl_set_msrs (struct kvm *kvm,struct kvm_msrs *msrs) +{ +struct kvm_vcpu *vcpu; +struct kvm_msr_entry *entry, *entries; +int rc; +u32 size, num_entries, i; + +if (msrs->vcpu <0 || msrs->vcpu >=KVM_MAX_VCPUS ) +return -EINVAL ; + + num_entries =ARRAY_SIZE (msrs_to_save); +if (msrs->nmsrs < num_entries) { + msrs->nmsrs = num_entries;/* inform actual size */ +return -EINVAL ;
drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 3238
Quoted 10 lines
drivers/kvm/kvm_main.c +10
-0+ } + + vcpu =vcpu_load (kvm, msrs->vcpu); +if (!vcpu) +return -ENOENT ; + + size = msrs->nmsrs *sizeof (struct kvm_msr_entry ); + rc = -E2BIG ; +if (size >4096 ) + goto out_vcpu;
Classic mutiplicative overflow bug. Only msrs->nmsrs doesn't get used again, so there is no bug here. Yet.
Quoted 15 lines
drivers/kvm/kvm_main.c +15
-0+ rc = -ENOMEM ; + entries =vmalloc (size); +if (entries ==NULL ) + goto out_vcpu; + + rc = -EFAULT ; +if (copy_from_user (entries, msrs->entries, size)) + goto out_free; + + rc = -EINVAL ; +for (i=0 ; i<num_entries; i++) { + entry = &entries[i]; +if (set_msr (vcpu, entry->index, entry->data)) + goto out_free; + }
drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 3264
Quoted 10 lines
drivers/kvm/kvm_main.c +10
-0+ + rc =0 ; +out_free: +vfree (entries); + +out_vcpu: +vcpu_put (vcpu); + +return rc; +}
This function returns no indication of how many msrs it actually did set. Should it?
Re: [PATCH 3/3] KVM: Expose MSRs to userspace
Quoted 23 lines · Andrew Morton
Quoted 19 lines · On Thu, 16 Nov 2006 18:04:22 -0000 Avi Kivity…
drivers/kvm/kvm_main.c +19
-0+static int kvm_dev_ioctl_set_msrs (struct kvm *kvm,struct kvm_msrs *msrs) +{ +struct kvm_vcpu *vcpu; +struct kvm_msr_entry *entry, *entries; +int rc; +u32 size, num_entries, i; + +if (msrs->vcpu <0 || msrs->vcpu >=KVM_MAX_VCPUS ) +return -EINVAL ; + + num_entries =ARRAY_SIZE (msrs_to_save); +if (msrs->nmsrs < num_entries) { + msrs->nmsrs = num_entries;/* inform actual size */ +return -EINVAL ; + } + + vcpu =vcpu_load (kvm, msrs->vcpu); +if (!vcpu) +return -ENOENT ;
Quoted 8 lines
drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 3185
Quoted 6 lines
drivers/kvm/kvm_main.c +5
-0+ + size = msrs->nmsrs *sizeof (struct kvm_msr_entry ); + rc = -E2BIG ; +if (size >4096 ) + goto out_vcpu;Classic mutiplicative overflow bug.
Right, will fix. The 4096 limit is arbitrary anyway, and can be replaced by an arbitrary limit on nmsrs.
Quoted 4 lines
Only
msrs->nmsrsdoesn't get used
again, so there is no bug here. Yet.
But why isn't it used again? Looks like the kernel is forcing the user to send at least num_entries for no good reason, and ignoring any entries beyond num_entries.
Quoted 21 lines
Quoted 21 lines
drivers/kvm/kvm_main.c +21
-0+ rc = -ENOMEM ; + entries =vmalloc (size); +if (entries ==NULL ) + goto out_vcpu; + + rc = -EFAULT ; +if (copy_from_user (entries, msrs->entries, size)) + goto out_free; + + rc = -EINVAL ; +for (i=0 ; i<num_entries; i++) { + entry = &entries[i]; +if (set_msr (vcpu, entry->index, entry->data)) + goto out_free; + } + + rc =0 ; +out_free: +vfree (entries); + +out_vcpu:
Quoted 9 lines
drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 3213
Quoted 5 lines
drivers/kvm/kvm_main.c +4
-0+vcpu_put (vcpu); + +return rc; +}This function returns no indication of how many msrs it actually did set. Should it?
It can't hurt. Is returning the number of msrs set in the return code (ala short write) acceptable, or do I need to make this a read/write ioctl?
Signature · 8 lines
Do not meddle in the internals of kernels, for they are subtle and quick to panic. ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
Re: [kvm-devel] [PATCH 3/3] KVM: Expose MSRs to userspace
In reply to Avi KivityQuoted 3 lines · Avi Kivity
Heh. That was the original implementation by Uri. I felt that was wrong because
_IOW()encodes the size in the ioctl number, bit the actual size is different.
That really shouldn't be a problem. After all the pointer approach doesn't encode the transfered size either. Given that the variable sized array gives a much cleaner interface you should use it.
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
Re: [PATCH 3/3] KVM: Expose MSRs to userspace
In reply to Avi KivityQuoted 11 lines · On Fri, 17 Nov 2006 09:20:49 +0200 Avi Kivity…
Quoted 10 lines
drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 3213
Quoted 6 lines
drivers/kvm/kvm_main.c +5
-0+out_vcpu: +vcpu_put (vcpu); + +return rc; +}This function returns no indication of how many msrs it actually did set. Should it?
Quoted 3 lines
It can't hurt. Is returning the number of msrs set in the return code (ala short write) acceptable, or do I need to make this a read/write ioctl?
I'd have thought that you'd just copy the number written into msrs->nmsrs via
msrs->nmsrs = num_entries;
like kvm_dev_ioctl_set_msrs() does. Dunno...
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
Re: [PATCH 3/3] KVM: Expose MSRs to userspace
Quoted 20 lines · Andrew Morton
Quoted 11 lines · On Fri, 17 Nov 2006 09:20:49 +0200 Avi Kivity…
Quoted 11 lines
drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 3213
Quoted 7 lines
drivers/kvm/kvm_main.c +5
-0+out_vcpu: +vcpu_put (vcpu); + +return rc; +}This function returns no indication of how many msrs it actually did set. Should it?
Quoted 4 lines
It can't hurt. Is returning the number of msrs set in the return code (ala short write) acceptable, or do I need to make this a read/write ioctl?
Quoted 6 lines
I'd have thought that you'd just copy the number written into
msrs->nmsrsviamsrs->nmsrs = num_entries;like
kvm_dev_ioctl_set_msrs()does. Dunno...
It means making it an _IOWR() ioctl, but no matter.
Signature · 8 lines
Do not meddle in the internals of kernels, for they are subtle and quick to panic. ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV