| Submitter | Gleb Natapov |
|---|---|
| Date | 2009-11-01 11:56:20 |
| Message ID | <1257076590-29559-2-git-send-email-gleb@redhat.com> |
| Download | mbox | patch |
| Permalink | /patch/56846/ |
| State | New |
| Headers | show |
Comments
On 11/01/2009 06:56 AM, Gleb Natapov wrote: > Add hypercall that allows guest and host to setup per cpu shared > memory. While it is pretty obvious that we should implement the asynchronous pagefaults for KVM, so a swap-in of a page the host swapped out does not stall the entire virtual CPU, I believe that adding extra data accesses at context switch time may not be the best tradeoff. It may be better to simply tell the guest what address is faulting (or give the guest some other random unique number as a token). Then, once the host brings that page into memory, we can send a signal to the guest with that same token. The problem of finding the task(s) associated with that token can be left to the guest. A little more complexity on the guest side, but probably worth it if we can avoid adding cost to the context switch path. > +static void kvm_end_context_switch(struct task_struct *next) > +{ > + struct kvm_vcpu_pv_shm *pv_shm = > + per_cpu(kvm_vcpu_pv_shm, smp_processor_id()); > + > + if (!pv_shm) > + return; > + > + pv_shm->current_task = (u64)next; > +} > +
On Sun, Nov 01, 2009 at 11:27:15PM -0500, Rik van Riel wrote: > On 11/01/2009 06:56 AM, Gleb Natapov wrote: > >Add hypercall that allows guest and host to setup per cpu shared > >memory. > > While it is pretty obvious that we should implement > the asynchronous pagefaults for KVM, so a swap-in > of a page the host swapped out does not stall the > entire virtual CPU, I believe that adding extra > data accesses at context switch time may not be > the best tradeoff. > > It may be better to simply tell the guest what > address is faulting (or give the guest some other > random unique number as a token). Then, once the > host brings that page into memory, we can send a > signal to the guest with that same token. > > The problem of finding the task(s) associated with > that token can be left to the guest. A little more > complexity on the guest side, but probably worth it > if we can avoid adding cost to the context switch > path. > This is precisely what this series implements. The function below is leftover from previous implementation, not used by the rest of the patch and removed by a later patch. Just a left over from rebase. Sorry about that. Will be fixed for future submissions. > >+static void kvm_end_context_switch(struct task_struct *next) > >+{ > >+ struct kvm_vcpu_pv_shm *pv_shm = > >+ per_cpu(kvm_vcpu_pv_shm, smp_processor_id()); > >+ > >+ if (!pv_shm) > >+ return; > >+ > >+ pv_shm->current_task = (u64)next; > >+} > >+ > > > > -- > All rights reversed. -- Gleb. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/01/2009 01:56 PM, Gleb Natapov wrote: > Add hypercall that allows guest and host to setup per cpu shared > memory. > > Better to set this up as an MSR (with bit zero enabling, bits 1-5 features, and 64-byte alignment). This allows auto-reset on INIT and live migration using the existing MSR save/restore infrastructure. > arch/x86/include/asm/kvm_host.h | 3 + > arch/x86/include/asm/kvm_para.h | 11 +++++ > arch/x86/kernel/kvm.c | 82 +++++++++++++++++++++++++++++++++++++++ > arch/x86/kernel/setup.c | 1 + > arch/x86/kernel/smpboot.c | 3 + > arch/x86/kvm/x86.c | 70 +++++++++++++++++++++++++++++++++ > include/linux/kvm.h | 1 + > include/linux/kvm_para.h | 4 ++ > 8 files changed, 175 insertions(+), 0 deletions(-) > Please separate into guest and host patches. > +#define KVM_PV_SHM_VERSION 1 > versions = bad, feature bits = good > + > +#define KVM_PV_SHM_FEATURES_ASYNC_PF (1<< 0) > + > +struct kvm_vcpu_pv_shm { > + __u64 features; > + __u64 reason; > + __u64 param; > +}; > + > Some documentation for this? Also, the name should reflect the pv pagefault use. For other uses we can register other areas. > #define MMU_QUEUE_SIZE 1024 > > @@ -37,6 +41,7 @@ struct kvm_para_state { > }; > > static DEFINE_PER_CPU(struct kvm_para_state, para_state); > +static DEFINE_PER_CPU(struct kvm_vcpu_pv_shm *, kvm_vcpu_pv_shm); > Easier to put the entire structure here, not a pointer. > + > +static int kvm_pv_reboot_notify(struct notifier_block *nb, > + unsigned long code, void *unused) > +{ > + if (code == SYS_RESTART) > + on_each_cpu(kvm_pv_unregister_shm, NULL, 1); > + return NOTIFY_DONE; > +} > + > +static struct notifier_block kvm_pv_reboot_nb = { > + .notifier_call = kvm_pv_reboot_notify, > +}; > Is this called on kexec, or do we need another hook? > +static int kvm_pv_setup_shm(struct kvm_vcpu *vcpu, unsigned long gpa, > + unsigned long size, unsigned long version, > + unsigned long *ret) > +{ > + addr = gfn_to_hva(vcpu->kvm, gfn); > + if (kvm_is_error_hva(addr)) > + return -EFAULT; > + > + /* pin page with pv shared memory */ > + down_read(&mm->mmap_sem); > + r = get_user_pages(current, mm, addr, 1, 1, 0,&vcpu->arch.pv_shm_page, > + NULL); > + up_read(&mm->mmap_sem); > This fails if the memory area straddles a page boundary. Aligning would solve this. I prefer using put_user() though than a permanent get_user_pages().
On Mon, Nov 02, 2009 at 02:18:54PM +0200, Avi Kivity wrote: > On 11/01/2009 01:56 PM, Gleb Natapov wrote: > >Add hypercall that allows guest and host to setup per cpu shared > >memory. > > > > Better to set this up as an MSR (with bit zero enabling, bits 1-5 > features, and 64-byte alignment). This allows auto-reset on INIT > and live migration using the existing MSR save/restore > infrastructure. > Hmm. Will do. > > arch/x86/include/asm/kvm_host.h | 3 + > > arch/x86/include/asm/kvm_para.h | 11 +++++ > > arch/x86/kernel/kvm.c | 82 +++++++++++++++++++++++++++++++++++++++ > > arch/x86/kernel/setup.c | 1 + > > arch/x86/kernel/smpboot.c | 3 + > > arch/x86/kvm/x86.c | 70 +++++++++++++++++++++++++++++++++ > > include/linux/kvm.h | 1 + > > include/linux/kvm_para.h | 4 ++ > > 8 files changed, 175 insertions(+), 0 deletions(-) > > Please separate into guest and host patches. > OK. > >+#define KVM_PV_SHM_VERSION 1 > > versions = bad, feature bits = good > I have both! Do you want me to drop version? > >+ > >+#define KVM_PV_SHM_FEATURES_ASYNC_PF (1<< 0) > >+ > >+struct kvm_vcpu_pv_shm { > >+ __u64 features; > >+ __u64 reason; > >+ __u64 param; > >+}; > >+ > > Some documentation for this? > > Also, the name should reflect the pv pagefault use. For other uses > we can register other areas. > I wanted it to be generic, but I am fine with making it apf specific. It will allow to make it smaller too. > > #define MMU_QUEUE_SIZE 1024 > > > >@@ -37,6 +41,7 @@ struct kvm_para_state { > > }; > > > > static DEFINE_PER_CPU(struct kvm_para_state, para_state); > >+static DEFINE_PER_CPU(struct kvm_vcpu_pv_shm *, kvm_vcpu_pv_shm); > > Easier to put the entire structure here, not a pointer. OK. > > >+ > >+static int kvm_pv_reboot_notify(struct notifier_block *nb, > >+ unsigned long code, void *unused) > >+{ > >+ if (code == SYS_RESTART) > >+ on_each_cpu(kvm_pv_unregister_shm, NULL, 1); > >+ return NOTIFY_DONE; > >+} > >+ > >+static struct notifier_block kvm_pv_reboot_nb = { > >+ .notifier_call = kvm_pv_reboot_notify, > >+}; > > Is this called on kexec, or do we need another hook? > This was added specifically for kexec to work. It was called in my test, > >+static int kvm_pv_setup_shm(struct kvm_vcpu *vcpu, unsigned long gpa, > >+ unsigned long size, unsigned long version, > >+ unsigned long *ret) > >+{ > >+ addr = gfn_to_hva(vcpu->kvm, gfn); > >+ if (kvm_is_error_hva(addr)) > >+ return -EFAULT; > >+ > >+ /* pin page with pv shared memory */ > >+ down_read(&mm->mmap_sem); > >+ r = get_user_pages(current, mm, addr, 1, 1, 0,&vcpu->arch.pv_shm_page, > >+ NULL); > >+ up_read(&mm->mmap_sem); > > This fails if the memory area straddles a page boundary. Aligning Good point. > would solve this. I prefer using put_user() though than a permanent > get_user_pages(). > I want to prevent it from been swapped out. -- Gleb. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/02/2009 06:18 PM, Gleb Natapov wrote: >>> +#define KVM_PV_SHM_VERSION 1 >>> >> versions = bad, feature bits = good >> >> > I have both! Do you want me to drop version? > Yes. Once a kernel is released you can't realistically change the version. >> Some documentation for this? >> >> Also, the name should reflect the pv pagefault use. For other uses >> we can register other areas. >> >> > I wanted it to be generic, but I am fine with making it apf specific. > It will allow to make it smaller too. > Maybe we can squeeze it into the page-fault error code? >> would solve this. I prefer using put_user() though than a permanent >> get_user_pages(). >> >> > I want to prevent it from been swapped out. > Since you don't prevent the page fault handler or code from being swapped out, you don't get anything out of it.
On Tue, Nov 03, 2009 at 07:15:10AM +0200, Avi Kivity wrote: > On 11/02/2009 06:18 PM, Gleb Natapov wrote: > >>>+#define KVM_PV_SHM_VERSION 1 > >>versions = bad, feature bits = good > >> > >I have both! Do you want me to drop version? > > Yes. Once a kernel is released you can't realistically change the version. > Why not? If version doesn't match apf will not be used. > >>Some documentation for this? > >> > >>Also, the name should reflect the pv pagefault use. For other uses > >>we can register other areas. > >> > >I wanted it to be generic, but I am fine with making it apf specific. > >It will allow to make it smaller too. > > Maybe we can squeeze it into the page-fault error code? > apf has to pass two things into a guest kernel: - event type (page not present/wake up) - unique token Error code has 32 bits and at least 1 of them should indicate that this is apf another one should indicate event type so this leaves us 30 bits for a token. 12 bits of a token is used to store vcpu id this leaves 18 bits for unique per vcpu id. Yes this may be enough. I don't think it is realistic to have more then 200000 outstanding apfs per vcpu. Alternately we can use CR2 to pass a token. > >>would solve this. I prefer using put_user() though than a permanent > >>get_user_pages(). > >> > >I want to prevent it from been swapped out. > > Since you don't prevent the page fault handler or code from being > swapped out, you don't get anything out of it. > Performance. Currently it is accessed on each page fault and to access it gup+kmap should be done each and every time. -- Gleb. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/03/2009 09:16 AM, Gleb Natapov wrote: >>> >>> I have both! Do you want me to drop version? >>> >> Yes. Once a kernel is released you can't realistically change the version. >> >> > Why not? If version doesn't match apf will not be used. > Then you cause a large performance regression (assuming apf is any good). So there will be a lot of pressure to modify things incrementally via feature bits. > >>>> Some documentation for this? >>>> >>>> Also, the name should reflect the pv pagefault use. For other uses >>>> we can register other areas. >>>> >>>> >>> I wanted it to be generic, but I am fine with making it apf specific. >>> It will allow to make it smaller too. >>> >> Maybe we can squeeze it into the page-fault error code? >> >> > apf has to pass two things into a guest kernel: > - event type (page not present/wake up) > - unique token > Error code has 32 bits and at least 1 of them should indicate that this > is apf another one should indicate event type so this leaves us 30 bits > for a token. 12 bits of a token is used to store vcpu id this leaves 18 > bits for unique per vcpu id. Yes this may be enough. I don't think it is > realistic to have more then 200000 outstanding apfs per vcpu. Alternately > we can use CR2 to pass a token. > Or a combination of pfec and cr2, yes. >>>> would solve this. I prefer using put_user() though than a permanent >>>> get_user_pages(). >>>> >>>> >>> I want to prevent it from been swapped out. >>> >> Since you don't prevent the page fault handler or code from being >> swapped out, you don't get anything out of it. >> >> > Performance. Currently it is accessed on each page fault and to access > it gup+kmap should be done each and every time. > put_user() is just as fast as a kmap, and don't prevent page migration or defragmentation. Note we still have to mark_page_dirty() unless we want to chase live migration bugs.
Patch
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 26a74b7..2d1f526 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -374,6 +374,9 @@ struct kvm_vcpu_arch { /* used for guest single stepping over the given code position */ u16 singlestep_cs; unsigned long singlestep_rip; + + struct kvm_vcpu_pv_shm *pv_shm; + struct page *pv_shm_page; }; struct kvm_mem_alias { diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h index c584076..90708b7 100644 --- a/arch/x86/include/asm/kvm_para.h +++ b/arch/x86/include/asm/kvm_para.h @@ -15,6 +15,7 @@ #define KVM_FEATURE_CLOCKSOURCE 0 #define KVM_FEATURE_NOP_IO_DELAY 1 #define KVM_FEATURE_MMU_OP 2 +#define KVM_FEATURE_ASYNC_PF 3 #define MSR_KVM_WALL_CLOCK 0x11 #define MSR_KVM_SYSTEM_TIME 0x12 @@ -47,6 +48,16 @@ struct kvm_mmu_op_release_pt { __u64 pt_phys; }; +#define KVM_PV_SHM_VERSION 1 + +#define KVM_PV_SHM_FEATURES_ASYNC_PF (1 << 0) + +struct kvm_vcpu_pv_shm { + __u64 features; + __u64 reason; + __u64 param; +}; + #ifdef __KERNEL__ #include <asm/processor.h> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 63b0ec8..d03f33c 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -27,7 +27,11 @@ #include <linux/mm.h> #include <linux/highmem.h> #include <linux/hardirq.h> +#include <linux/bootmem.h> +#include <linux/notifier.h> +#include <linux/reboot.h> #include <asm/timer.h> +#include <asm/cpu.h> #define MMU_QUEUE_SIZE 1024 @@ -37,6 +41,7 @@ struct kvm_para_state { }; static DEFINE_PER_CPU(struct kvm_para_state, para_state); +static DEFINE_PER_CPU(struct kvm_vcpu_pv_shm *, kvm_vcpu_pv_shm); static struct kvm_para_state *kvm_para_state(void) { @@ -50,6 +55,17 @@ static void kvm_io_delay(void) { } +static void kvm_end_context_switch(struct task_struct *next) +{ + struct kvm_vcpu_pv_shm *pv_shm = + per_cpu(kvm_vcpu_pv_shm, smp_processor_id()); + + if (!pv_shm) + return; + + pv_shm->current_task = (u64)next; +} + static void kvm_mmu_op(void *buffer, unsigned len) { int r; @@ -231,10 +247,76 @@ static void __init paravirt_ops_setup(void) #endif } +static void kvm_pv_unregister_shm(void *unused) +{ + if (per_cpu(kvm_vcpu_pv_shm, smp_processor_id()) == NULL) + return; + + kvm_hypercall3(KVM_HC_SETUP_SHM, 0, 0, KVM_PV_SHM_VERSION); + printk(KERN_INFO"Unregister pv shared memory for cpu %d\n", + smp_processor_id()); + +} + +static int kvm_pv_reboot_notify(struct notifier_block *nb, + unsigned long code, void *unused) +{ + if (code == SYS_RESTART) + on_each_cpu(kvm_pv_unregister_shm, NULL, 1); + return NOTIFY_DONE; +} + +static struct notifier_block kvm_pv_reboot_nb = { + .notifier_call = kvm_pv_reboot_notify, +}; + void __init kvm_guest_init(void) { if (!kvm_para_available()) return; paravirt_ops_setup(); + register_reboot_notifier(&kvm_pv_reboot_nb); +} + +void __cpuinit kvm_guest_cpu_init(void) +{ + int r; + unsigned long a0, a1, a2; + struct kvm_vcpu_pv_shm *pv_shm; + + if (!kvm_para_available()) + return; + + if (smp_processor_id() == boot_cpu_id) + pv_shm = alloc_bootmem(sizeof(*pv_shm)); + else + pv_shm = kmalloc(sizeof(*pv_shm), GFP_ATOMIC); + + if (!pv_shm) + return; + + memset(pv_shm, 0, sizeof(*pv_shm)); + + if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF)) + pv_shm->features |= KVM_PV_SHM_FEATURES_ASYNC_PF; + + per_cpu(kvm_vcpu_pv_shm, smp_processor_id()) = pv_shm; + a0 = __pa(pv_shm); + a1 = sizeof(*pv_shm); + a2 = KVM_PV_SHM_VERSION; + r = kvm_hypercall3(KVM_HC_SETUP_SHM, a0, a1, a2); + + if (!r) { + printk(KERN_INFO"Setup pv shared memory for cpu %d\n", + smp_processor_id()); + return; + } + + if (smp_processor_id() == boot_cpu_id) + free_bootmem(__pa(pv_shm), sizeof(*pv_shm)); + else + kfree(pv_shm); + + per_cpu(kvm_vcpu_pv_shm, smp_processor_id()) = NULL; } diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index e09f0e2..1c2f8dd 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1007,6 +1007,7 @@ void __init setup_arch(char **cmdline_p) probe_nr_irqs_gsi(); kvm_guest_init(); + kvm_guest_cpu_init(); e820_reserve_resources(); e820_mark_nosave_regions(max_low_pfn); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 565ebc6..5599098 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -65,6 +65,7 @@ #include <asm/setup.h> #include <asm/uv/uv.h> #include <linux/mc146818rtc.h> +#include <linux/kvm_para.h> #include <asm/smpboot_hooks.h> @@ -321,6 +322,8 @@ notrace static void __cpuinit start_secondary(void *unused) ipi_call_unlock(); per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; + kvm_guest_cpu_init(); + /* enable local interrupts */ local_irq_enable(); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2ef3906..c177933 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1342,6 +1342,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_SET_IDENTITY_MAP_ADDR: case KVM_CAP_XEN_HVM: case KVM_CAP_ADJUST_CLOCK: + case KVM_CAP_ASYNC_PF: r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -3371,6 +3372,68 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_emulate_halt); +static void kvm_pv_release_shm(struct kvm_vcpu *vcpu) +{ + if (!vcpu->arch.pv_shm_page) + return; + + kunmap(vcpu->arch.pv_shm_page); + put_page(vcpu->arch.pv_shm_page); + vcpu->arch.pv_shm_page = NULL; + vcpu->arch.pv_shm = NULL; +} + +static int kvm_pv_setup_shm(struct kvm_vcpu *vcpu, unsigned long gpa, + unsigned long size, unsigned long version, + unsigned long *ret) +{ + int r; + unsigned long addr; + gfn_t gfn = gpa >> PAGE_SHIFT; + int offset = offset_in_page(gpa); + struct mm_struct *mm = current->mm; + void *p; + + *ret = -KVM_EINVAL; + + if (size == 0 && vcpu->arch.pv_shm != NULL && + version == KVM_PV_SHM_VERSION) { + kvm_pv_release_shm(vcpu); + goto out; + } + + if (vcpu->arch.pv_shm != NULL || size != sizeof(*vcpu->arch.pv_shm) || + size > PAGE_SIZE || version != KVM_PV_SHM_VERSION) + return -EINVAL; + + *ret = -KVM_EFAULT; + + addr = gfn_to_hva(vcpu->kvm, gfn); + if (kvm_is_error_hva(addr)) + return -EFAULT; + + /* pin page with pv shared memory */ + down_read(&mm->mmap_sem); + r = get_user_pages(current, mm, addr, 1, 1, 0, &vcpu->arch.pv_shm_page, + NULL); + up_read(&mm->mmap_sem); + if (r != 1) + return -EFAULT; + + p = kmap(vcpu->arch.pv_shm_page); + if (!p) { + put_page(vcpu->arch.pv_shm_page); + vcpu->arch.pv_shm_page = NULL; + return -ENOMEM; + } + + vcpu->arch.pv_shm = p + offset; + +out: + *ret = 0; + return 0; +} + static inline gpa_t hc_gpa(struct kvm_vcpu *vcpu, unsigned long a0, unsigned long a1) { @@ -3413,6 +3476,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) case KVM_HC_MMU_OP: r = kvm_pv_mmu_op(vcpu, a0, hc_gpa(vcpu, a1, a2), &ret); break; + case KVM_HC_SETUP_SHM: + r = kvm_pv_setup_shm(vcpu, a0, a1, a2, &ret); + break; default: ret = -KVM_ENOSYS; break; @@ -4860,6 +4926,8 @@ free_vcpu: void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { + kvm_pv_release_shm(vcpu); + vcpu_load(vcpu); kvm_mmu_unload(vcpu); vcpu_put(vcpu); @@ -4877,6 +4945,8 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) vcpu->arch.dr6 = DR6_FIXED_1; vcpu->arch.dr7 = DR7_FIXED_1; + kvm_pv_release_shm(vcpu); + return kvm_x86_ops->vcpu_reset(vcpu); } diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 6ed1a12..2fec4a2 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -440,6 +440,7 @@ struct kvm_ioeventfd { #define KVM_CAP_XEN_HVM 38 #endif #define KVM_CAP_ADJUST_CLOCK 39 +#define KVM_CAP_ASYNC_PF 40 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h index d731092..1c37495 100644 --- a/include/linux/kvm_para.h +++ b/include/linux/kvm_para.h @@ -14,9 +14,11 @@ #define KVM_EFAULT EFAULT #define KVM_E2BIG E2BIG #define KVM_EPERM EPERM +#define KVM_EINVAL EINVAL #define KVM_HC_VAPIC_POLL_IRQ 1 #define KVM_HC_MMU_OP 2 +#define KVM_HC_SETUP_SHM 3 /* * hypercalls use architecture specific @@ -26,8 +28,10 @@ #ifdef __KERNEL__ #ifdef CONFIG_KVM_GUEST void __init kvm_guest_init(void); +void __cpuinit kvm_guest_cpu_init(void); #else #define kvm_guest_init() do { } while (0) +#define kvm_guest_cpu_init() do { } while (0) #endif static inline int kvm_para_has_feature(unsigned int feature)
Add hypercall that allows guest and host to setup per cpu shared memory. Signed-off-by: Gleb Natapov <gleb@redhat.com> --- arch/x86/include/asm/kvm_host.h | 3 + arch/x86/include/asm/kvm_para.h | 11 +++++ arch/x86/kernel/kvm.c | 82 +++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/setup.c | 1 + arch/x86/kernel/smpboot.c | 3 + arch/x86/kvm/x86.c | 70 +++++++++++++++++++++++++++++++++ include/linux/kvm.h | 1 + include/linux/kvm_para.h | 4 ++ 8 files changed, 175 insertions(+), 0 deletions(-)