[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/10][RESEND] Add HVM support
Add HVM hardware feature suspend/resume. Signed-off-by Ke Yu <ke.yu@xxxxxxxxx> Signed-off-by Kevin Tian <kevin.tian@xxxxxxxxx> diff -r a06fadc24250 xen/arch/x86/acpi/power.c --- a/xen/arch/x86/acpi/power.c Tue Jul 10 14:23:46 2007 -0400 +++ b/xen/arch/x86/acpi/power.c Tue Jul 10 21:20:12 2007 -0400 @@ -80,10 +80,27 @@ static void device_power_up(void) console_resume(); } +static void freeze_domains(void) +{ + struct domain *d; + + for_each_domain(d) + if (d->domain_id != 0) + domain_pause(d); +} + +static void thaw_domains(void) +{ + struct domain *d; + + for_each_domain(d) + if (d->domain_id != 0) + domain_unpause(d); +} + /* Main interface to do xen specific suspend/resume */ int enter_state(u32 state) { - struct domain *d; unsigned long flags; int error; @@ -97,9 +114,9 @@ int enter_state(u32 state) if (!spin_trylock(&pm_lock)) return -EBUSY; - for_each_domain(d) - if (d->domain_id != 0) - domain_pause(d); + freeze_domains(); + + hvm_disable(); pmprintk(XENLOG_INFO, "PM: Preparing system for %s sleep\n", acpi_states[state]); @@ -133,13 +150,12 @@ int enter_state(u32 state) Done: local_irq_restore(flags); - for_each_domain(d) - if (d->domain_id!=0) - domain_unpause(d); - + if (hvm_enabled) + hvm_resume_cpu(); + + thaw_domains(); spin_unlock(&pm_lock); return error; - } /* diff -r a06fadc24250 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Tue Jul 10 14:23:46 2007 -0400 +++ b/xen/arch/x86/hvm/hvm.c Tue Jul 10 20:12:08 2007 -0400 @@ -79,7 +79,10 @@ void hvm_disable(void) void hvm_disable(void) { if ( hvm_enabled ) + { + hvm_funcs.suspend_cpu(); hvm_funcs.disable(); + } } void hvm_stts(struct vcpu *v) diff -r a06fadc24250 xen/arch/x86/hvm/vmx/vmcs.c --- a/xen/arch/x86/hvm/vmx/vmcs.c Tue Jul 10 14:23:46 2007 -0400 +++ b/xen/arch/x86/hvm/vmx/vmcs.c Tue Jul 10 21:19:54 2007 -0400 @@ -45,7 +45,7 @@ u32 vmx_vmentry_control __read_mostly; u32 vmx_vmentry_control __read_mostly; bool_t cpu_has_vmx_ins_outs_instr_info __read_mostly; -static DEFINE_PER_CPU(struct vmcs_struct *, current_vmcs); +DEFINE_PER_CPU(struct active_vmcs_info, cpu_active_vmcs); static u32 vmcs_revision_id __read_mostly; @@ -161,10 +161,17 @@ void vmx_init_vmcs_config(void) BUG_ON(((vmx_msr_high >> 18) & 15) != 6); } +void vmx_init_percpu_vmcs_info(void) +{ + current_vmcs = NULL; + current_host_vmcs = NULL; + INIT_LIST_HEAD(&this_cpu(cpu_active_vmcs).node); + spin_lock_init(&this_cpu(cpu_active_vmcs).lock); +} + static struct vmcs_struct *vmx_alloc_vmcs(void) { struct vmcs_struct *vmcs; - if ( (vmcs = alloc_xenheap_page()) == NULL ) { gdprintk(XENLOG_WARNING, "Failed to allocate VMCS.\n"); @@ -184,15 +191,26 @@ static void vmx_free_vmcs(struct vmcs_st static void __vmx_clear_vmcs(void *info) { - struct vcpu *v = info; - - __vmpclear(virt_to_maddr(v->arch.hvm_vmx.vmcs)); - - v->arch.hvm_vmx.active_cpu = -1; - v->arch.hvm_vmx.launched = 0; - - if ( v->arch.hvm_vmx.vmcs == this_cpu(current_vmcs) ) - this_cpu(current_vmcs) = NULL; + struct arch_vmx_struct *arch_vmx = info; + unsigned long flags; + + /* disable irq since this may be invoked in nested context */ + spin_lock_irqsave(&this_cpu(cpu_active_vmcs).lock, flags); + if (list_empty(&arch_vmx->list)) + { + spin_unlock_irqrestore(&this_cpu(cpu_active_vmcs).lock, flags); + return; + } + list_del(&arch_vmx->list); + spin_unlock_irqrestore(&this_cpu(cpu_active_vmcs).lock, flags); + + __vmpclear(virt_to_maddr(arch_vmx->vmcs)); + + arch_vmx->active_cpu = -1; + arch_vmx->launched = 0; + + if ( arch_vmx->vmcs == current_vmcs ) + current_vmcs = NULL; } static void vmx_clear_vmcs(struct vcpu *v) @@ -203,16 +221,43 @@ static void vmx_clear_vmcs(struct vcpu * return; if ( cpu == smp_processor_id() ) - return __vmx_clear_vmcs(v); - - on_selected_cpus(cpumask_of_cpu(cpu), __vmx_clear_vmcs, v, 1, 1); + return __vmx_clear_vmcs(&v->arch.hvm_vmx); + + on_selected_cpus(cpumask_of_cpu(cpu), __vmx_clear_vmcs, + &v->arch.hvm_vmx, 1, 1); } static void vmx_load_vmcs(struct vcpu *v) { + unsigned long flags; + __vmptrld(virt_to_maddr(v->arch.hvm_vmx.vmcs)); v->arch.hvm_vmx.active_cpu = smp_processor_id(); - this_cpu(current_vmcs) = v->arch.hvm_vmx.vmcs; + current_vmcs = v->arch.hvm_vmx.vmcs; + + spin_lock_irqsave(&this_cpu(cpu_active_vmcs).lock, flags); + list_add(&v->arch.hvm_vmx.list, &this_cpu(cpu_active_vmcs).node); + spin_unlock_irqrestore(&this_cpu(cpu_active_vmcs).lock, flags); +} + +/* Clear all active VMCS on this cpu before going down */ +int vmx_suspend_cpu(void) +{ + struct arch_vmx_struct *arch_vmx; + struct list_head *head = &this_cpu(cpu_active_vmcs).node; + int cpu = smp_processor_id(); + + while (!list_empty(head)) + { + arch_vmx = list_entry(head->next, struct arch_vmx_struct, list); + + spin_lock(&arch_vmx->vmcs_lock); + if (arch_vmx->active_cpu == cpu) + __vmx_clear_vmcs(arch_vmx); + spin_unlock(&arch_vmx->vmcs_lock); + } + + return 0; } void vmx_vmcs_enter(struct vcpu *v) @@ -456,7 +501,8 @@ int vmx_create_vmcs(struct vcpu *v) if ( (v->arch.hvm_vmx.vmcs = vmx_alloc_vmcs()) == NULL ) return -ENOMEM; - __vmx_clear_vmcs(v); + INIT_LIST_HEAD(&v->arch.hvm_vmx.list); + __vmx_clear_vmcs(&v->arch.hvm_vmx); } construct_vmcs(v); @@ -497,7 +543,7 @@ void vmx_do_resume(struct vcpu *v) if ( v->arch.hvm_vmx.active_cpu == smp_processor_id() ) { - if ( v->arch.hvm_vmx.vmcs != this_cpu(current_vmcs) ) + if ( v->arch.hvm_vmx.vmcs != current_vmcs ) vmx_load_vmcs(v); } else diff -r a06fadc24250 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Tue Jul 10 14:23:46 2007 -0400 +++ b/xen/arch/x86/hvm/vmx/vmx.c Tue Jul 10 20:10:27 2007 -0400 @@ -55,6 +55,8 @@ enum handler_return { HNDL_done, HNDL_un char *vmx_msr_bitmap; +static int vmx_resume_cpu(void); + static void vmx_ctxt_switch_from(struct vcpu *v); static void vmx_ctxt_switch_to(struct vcpu *v); @@ -1271,7 +1273,9 @@ static struct hvm_function_table vmx_fun .inject_exception = vmx_inject_exception, .init_ap_context = vmx_init_ap_context, .init_hypercall_page = vmx_init_hypercall_page, - .event_injection_faulted = vmx_event_injection_faulted + .event_injection_faulted = vmx_event_injection_faulted, + .suspend_cpu = vmx_suspend_cpu, + .resume_cpu = vmx_resume_cpu, }; int start_vmx(void) @@ -1308,6 +1312,8 @@ int start_vmx(void) vmx_init_vmcs_config(); + vmx_init_percpu_vmcs_info(); + if ( smp_processor_id() == 0 ) setup_vmcs_dump(); @@ -1325,6 +1331,8 @@ int start_vmx(void) vmx_free_host_vmcs(vmcs); return 0; } + + current_host_vmcs = vmcs; vmx_save_host_msrs(); @@ -3160,6 +3168,25 @@ asmlinkage void vmx_trace_vmentry(void) HVMTRACE_0D(VMENTRY, v); } +/* Resume vmx feature on the given cpu */ +static int vmx_resume_cpu(void) +{ + /* mmu_cr4_features may be changed by hvm_disable() */ + if (!(read_cr4() & X86_CR4_VMXE)) + set_in_cr4(X86_CR4_VMXE); + + if ( __vmxon(virt_to_maddr(current_host_vmcs)) ) + { + clear_in_cr4(X86_CR4_VMXE); + printk("VMXON failed\n"); + vmx_free_host_vmcs(current_host_vmcs); + return 0; + } + + printk("VMXON is done\n"); + return 1; +} + /* * Local variables: * mode: C diff -r a06fadc24250 xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Tue Jul 10 14:23:46 2007 -0400 +++ b/xen/include/asm-x86/hvm/hvm.h Tue Jul 10 19:43:41 2007 -0400 @@ -160,6 +160,10 @@ struct hvm_function_table { void (*init_hypercall_page)(struct domain *d, void *hypercall_page); int (*event_injection_faulted)(struct vcpu *v); + + int (*suspend_cpu)(void); + + int (*resume_cpu)(void); }; extern struct hvm_function_table hvm_funcs; @@ -316,4 +320,26 @@ static inline int hvm_event_injection_fa /* These exceptions must always be intercepted. */ #define HVM_TRAP_MASK (1U << TRAP_machine_check) +static inline int +hvm_suspend_cpu(void) +{ + int ret = 1; + + if (hvm_funcs.suspend_cpu) + ret = hvm_funcs.suspend_cpu(); + + return ret; +} + +static inline int +hvm_resume_cpu(void) +{ + int ret = 1; + + if (hvm_funcs.resume_cpu) + ret = hvm_funcs.resume_cpu(); + + return ret; +} + #endif /* __ASM_X86_HVM_HVM_H__ */ diff -r a06fadc24250 xen/include/asm-x86/hvm/vmx/vmcs.h --- a/xen/include/asm-x86/hvm/vmx/vmcs.h Tue Jul 10 14:23:46 2007 -0400 +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h Tue Jul 10 20:09:33 2007 -0400 @@ -28,11 +28,24 @@ extern void vmcs_dump_vcpu(void); extern void vmcs_dump_vcpu(void); extern void vmx_init_vmcs_config(void); extern void setup_vmcs_dump(void); +extern int vmx_suspend_cpu(void); +extern void vmx_init_percpu_vmcs_info(void); struct vmcs_struct { u32 vmcs_revision_id; unsigned char data [0]; /* vmcs size is read from MSR */ }; + +/* Record per-cpu vmcs information */ +struct active_vmcs_info { + struct vmcs_struct *host; + struct vmcs_struct *curr; + struct list_head node; /* Active VMCS on this cpu */ + spinlock_t lock; +}; +DECLARE_PER_CPU(struct active_vmcs_info, cpu_active_vmcs); +#define current_vmcs this_cpu(cpu_active_vmcs).curr +#define current_host_vmcs this_cpu(cpu_active_vmcs).host enum { VMX_INDEX_MSR_LSTAR = 0, @@ -80,6 +93,7 @@ struct arch_vmx_struct { #endif unsigned long efer; + struct list_head list; /* Link to active cpu */ /* Following fields are all specific to vmxassist. */ unsigned long vmxassist_enabled:1; unsigned long irqbase_mode:1; Attachment:
hvm_context.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |