diff options
author | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2006-11-06 11:03:04 +0000 |
---|---|---|
committer | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2006-11-06 11:03:04 +0000 |
commit | 1ad5dad74cdec8818fa47c6b6c8652d532fb87c8 (patch) | |
tree | 391e9a242988b98c0d4357034ec57081079ff13f | |
parent | 5c445c2f6dbd4e48712a5b6298c56df45f1ff158 (diff) | |
download | xen-1ad5dad74cdec8818fa47c6b6c8652d532fb87c8.tar.gz xen-1ad5dad74cdec8818fa47c6b6c8652d532fb87c8.tar.bz2 xen-1ad5dad74cdec8818fa47c6b6c8652d532fb87c8.zip |
[XEN] Re-jig VCPU initialisation -- VMX init requires generic VCPU
fields to already be allocated. This has led to a general cleanup of
domain and vcpu initialisation and destruction.
Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r-- | xen/arch/ia64/xen/domain.c | 95 | ||||
-rw-r--r-- | xen/arch/powerpc/domain.c | 23 | ||||
-rw-r--r-- | xen/arch/x86/domain.c | 34 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmcs.c | 161 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmx.c | 10 | ||||
-rw-r--r-- | xen/common/domain.c | 26 | ||||
-rw-r--r-- | xen/common/sched_credit.c | 81 | ||||
-rw-r--r-- | xen/common/sched_sedf.c | 35 | ||||
-rw-r--r-- | xen/common/schedule.c | 19 | ||||
-rw-r--r-- | xen/include/xen/domain.h | 14 | ||||
-rw-r--r-- | xen/include/xen/sched-if.h | 5 | ||||
-rw-r--r-- | xen/include/xen/sched.h | 4 |
12 files changed, 239 insertions, 268 deletions
diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 7aada5b9bb..a482bdc9e1 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -275,40 +275,61 @@ void hlt_timer_fn(void *data) vcpu_unblock(v); } -struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) +void relinquish_vcpu_resources(struct vcpu *v) +{ + if (HAS_PERVCPU_VHPT(v->domain)) + pervcpu_vhpt_free(v); + if (v->arch.privregs != NULL) { + free_xenheap_pages(v->arch.privregs, + get_order_from_shift(XMAPPEDREGS_SHIFT)); + v->arch.privregs = NULL; + } + kill_timer(&v->arch.hlt_timer); +} + +struct vcpu *alloc_vcpu_struct(void) { struct vcpu *v; struct thread_info *ti; + static int first_allocation = 1; - /* Still keep idle vcpu0 static allocated at compilation, due - * to some code from Linux still requires it in early phase. - */ - if (is_idle_domain(d) && !vcpu_id) - v = idle_vcpu[0]; - else { - if ((v = alloc_xenheap_pages(KERNEL_STACK_SIZE_ORDER)) == NULL) - return NULL; - memset(v, 0, sizeof(*v)); - - ti = alloc_thread_info(v); - /* Clear thread_info to clear some important fields, like - * preempt_count - */ - memset(ti, 0, sizeof(struct thread_info)); - init_switch_stack(v); + if (first_allocation) { + first_allocation = 0; + /* Still keep idle vcpu0 static allocated at compilation, due + * to some code from Linux still requires it in early phase. + */ + return idle_vcpu[0]; } + if ((v = alloc_xenheap_pages(KERNEL_STACK_SIZE_ORDER)) == NULL) + return NULL; + memset(v, 0, sizeof(*v)); + + ti = alloc_thread_info(v); + /* Clear thread_info to clear some important fields, like + * preempt_count + */ + memset(ti, 0, sizeof(struct thread_info)); + init_switch_stack(v); + + return v; +} + +void free_vcpu_struct(struct vcpu *v) +{ + free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER); +} + +int vcpu_initialise(struct vcpu *v) +{ + struct domain *d = v->domain; + int rc, order, i; + if (!is_idle_domain(d)) { if (!d->arch.is_vti) { - int order; - int i; - // vti domain has its own vhpt policy. - if (HAS_PERVCPU_VHPT(d)) { - if (pervcpu_vhpt_alloc(v) < 0) { - free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER); - return NULL; - } - } + if (HAS_PERVCPU_VHPT(d)) + if ((rc = pervcpu_vhpt_alloc(v)) != 0) + return rc; /* Create privregs page only if not VTi. */ order = get_order_from_shift(XMAPPEDREGS_SHIFT); @@ -344,34 +365,20 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) v->arch.breakimm = d->arch.breakimm; v->arch.last_processor = INVALID_PROCESSOR; } - if (!VMX_DOMAIN(v)){ + + if (!VMX_DOMAIN(v)) init_timer(&v->arch.hlt_timer, hlt_timer_fn, v, first_cpu(cpu_online_map)); - } - - return v; -} -void relinquish_vcpu_resources(struct vcpu *v) -{ - if (HAS_PERVCPU_VHPT(v->domain)) - pervcpu_vhpt_free(v); - if (v->arch.privregs != NULL) { - free_xenheap_pages(v->arch.privregs, - get_order_from_shift(XMAPPEDREGS_SHIFT)); - v->arch.privregs = NULL; - } - kill_timer(&v->arch.hlt_timer); + return 0; } -void free_vcpu_struct(struct vcpu *v) +void vcpu_destroy(struct vcpu *v) { if (v->domain->arch.is_vti) vmx_relinquish_vcpu_resources(v); else relinquish_vcpu_resources(v); - - free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER); } static void init_switch_stack(struct vcpu *v) diff --git a/xen/arch/powerpc/domain.c b/xen/arch/powerpc/domain.c index c3c4420dec..636713a8b7 100644 --- a/xen/arch/powerpc/domain.c +++ b/xen/arch/powerpc/domain.c @@ -109,27 +109,28 @@ void machine_restart(char * __unused) while(1); } -struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) +struct vcpu *alloc_vcpu_struct(void) { struct vcpu *v; - - if ( (v = xmalloc(struct vcpu)) == NULL ) - return NULL; - - memset(v, 0, sizeof(*v)); - v->vcpu_id = vcpu_id; - + if ( (v = xmalloc(struct vcpu)) != NULL ) + memset(v, 0, sizeof(*v)); return v; } void free_vcpu_struct(struct vcpu *v) { - BUG_ON(v->next_in_list != NULL); - if ( v->vcpu_id != 0 ) - v->domain->vcpu[v->vcpu_id - 1]->next_in_list = NULL; xfree(v); } +int vcpu_initialise(struct vcpu *v) +{ + return 0; +} + +void vcpu_destroy(struct vcpu *v) +{ +} + int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_t *c) { memcpy(&v->arch.ctxt, &c->user_regs, sizeof(c->user_regs)); diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index da2e29f772..a5f89e70ef 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -114,27 +114,30 @@ void dump_pageframe_info(struct domain *d) } } -struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) +struct vcpu *alloc_vcpu_struct(void) { struct vcpu *v; + if ( (v = xmalloc(struct vcpu)) != NULL ) + memset(v, 0, sizeof(*v)); + return v; +} - if ( (v = xmalloc(struct vcpu)) == NULL ) - return NULL; - - memset(v, 0, sizeof(*v)); +void free_vcpu_struct(struct vcpu *v) +{ + xfree(v); +} - v->vcpu_id = vcpu_id; - v->domain = d; +int vcpu_initialise(struct vcpu *v) +{ + struct domain *d = v->domain; + int rc; v->arch.flags = TF_kernel_mode; if ( is_hvm_domain(d) ) { - if ( hvm_vcpu_initialise(v) != 0 ) - { - xfree(v); - return NULL; - } + if ( (rc = hvm_vcpu_initialise(v)) != 0 ) + return rc; } else { @@ -150,16 +153,15 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) } v->arch.perdomain_ptes = - d->arch.mm_perdomain_pt + (vcpu_id << GDT_LDT_VCPU_SHIFT); + d->arch.mm_perdomain_pt + (v->vcpu_id << GDT_LDT_VCPU_SHIFT); pae_l3_cache_init(&v->arch.pae_l3_cache); - return v; + return 0; } -void free_vcpu_struct(struct vcpu *v) +void vcpu_destroy(struct vcpu *v) { - xfree(v); } int arch_domain_create(struct domain *d) diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 65be8a3494..882220926b 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -193,11 +193,9 @@ void vmx_vmcs_enter(struct vcpu *v) { /* * NB. We must *always* run an HVM VCPU on its own VMCS, except for - * vmx_vmcs_enter/exit critical regions. This leads to some XXX TODOs XXX: - * 1. Move construct_vmcs() much earlier, to domain creation or - * context initialisation. - * 2. VMPTRLD as soon as we context-switch to a HVM VCPU. - * 3. VMCS destruction needs to happen later (from domain_destroy()). + * vmx_vmcs_enter/exit critical regions. This leads to some TODOs: + * 1. VMPTRLD as soon as we context-switch to a HVM VCPU. + * 2. VMCS destruction needs to happen later (from domain_destroy()). * We can relax this a bit if a paused VCPU always commits its * architectural state to a software structure. */ @@ -235,17 +233,6 @@ void vmx_free_host_vmcs(struct vmcs_struct *vmcs) vmx_free_vmcs(vmcs); } -static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx) -{ - int error = 0; - - error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_control); - error |= __vmwrite(VM_EXIT_CONTROLS, vmx_vmexit_control); - error |= __vmwrite(VM_ENTRY_CONTROLS, vmx_vmentry_control); - - return error; -} - #define GUEST_LAUNCH_DS 0x08 #define GUEST_LAUNCH_CS 0x10 #define GUEST_SEGMENT_LIMIT 0xffffffff @@ -366,17 +353,40 @@ static void vmx_do_launch(struct vcpu *v) v->arch.schedule_tail = arch_vmx_do_resume; } -/* - * Initially set the same environement as host. - */ -static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs) +static int construct_vmcs(struct vcpu *v, cpu_user_regs_t *regs) { int error = 0; + unsigned long tmp, eflags; union vmcs_arbytes arbytes; - unsigned long dr7; - unsigned long eflags; - /* MSR */ + /* VMCS controls. */ + error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_control); + error |= __vmwrite(VM_EXIT_CONTROLS, vmx_vmexit_control); + error |= __vmwrite(VM_ENTRY_CONTROLS, vmx_vmentry_control); + + /* Host data selectors. */ + error |= __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS); + error |= __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS); + error |= __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS); +#if defined(__i386__) + error |= __vmwrite(HOST_FS_SELECTOR, __HYPERVISOR_DS); + error |= __vmwrite(HOST_GS_SELECTOR, __HYPERVISOR_DS); + error |= __vmwrite(HOST_FS_BASE, 0); + error |= __vmwrite(HOST_GS_BASE, 0); +#elif defined(__x86_64__) + rdmsrl(MSR_FS_BASE, tmp); error |= __vmwrite(HOST_FS_BASE, tmp); + rdmsrl(MSR_GS_BASE, tmp); error |= __vmwrite(HOST_GS_BASE, tmp); +#endif + + /* Host control registers. */ + error |= __vmwrite(HOST_CR0, read_cr0()); + error |= __vmwrite(HOST_CR4, read_cr4()); + + /* Host CS:RIP. */ + error |= __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS); + error |= __vmwrite(HOST_RIP, (unsigned long)vmx_asm_vmexit_handler); + + /* MSR intercepts. */ error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0); error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0); error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0); @@ -395,7 +405,7 @@ static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs) error |= __vmwrite(GUEST_ACTIVITY_STATE, 0); - /* Guest Selectors */ + /* Guest selectors. */ error |= __vmwrite(GUEST_ES_SELECTOR, GUEST_LAUNCH_DS); error |= __vmwrite(GUEST_SS_SELECTOR, GUEST_LAUNCH_DS); error |= __vmwrite(GUEST_DS_SELECTOR, GUEST_LAUNCH_DS); @@ -403,7 +413,7 @@ static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs) error |= __vmwrite(GUEST_GS_SELECTOR, GUEST_LAUNCH_DS); error |= __vmwrite(GUEST_CS_SELECTOR, GUEST_LAUNCH_CS); - /* Guest segment bases */ + /* Guest segment bases. */ error |= __vmwrite(GUEST_ES_BASE, 0); error |= __vmwrite(GUEST_SS_BASE, 0); error |= __vmwrite(GUEST_DS_BASE, 0); @@ -411,7 +421,7 @@ static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs) error |= __vmwrite(GUEST_GS_BASE, 0); error |= __vmwrite(GUEST_CS_BASE, 0); - /* Guest segment Limits */ + /* Guest segment limits. */ error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT); error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT); error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT); @@ -419,7 +429,7 @@ static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs) error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT); error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT); - /* Guest segment AR bytes */ + /* Guest segment AR bytes. */ arbytes.bytes = 0; arbytes.fields.seg_type = 0x3; /* type = 3 */ arbytes.fields.s = 1; /* code or data, i.e. not system */ @@ -428,131 +438,54 @@ static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs) arbytes.fields.default_ops_size = 1; /* 32-bit */ arbytes.fields.g = 1; arbytes.fields.null_bit = 0; /* not null */ - error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes); error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes); error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes); error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes); error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes); - arbytes.fields.seg_type = 0xb; /* type = 0xb */ error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes); - /* Guest GDT */ + /* Guest GDT. */ error |= __vmwrite(GUEST_GDTR_BASE, 0); error |= __vmwrite(GUEST_GDTR_LIMIT, 0); - /* Guest IDT */ + /* Guest IDT. */ error |= __vmwrite(GUEST_IDTR_BASE, 0); error |= __vmwrite(GUEST_IDTR_LIMIT, 0); - /* Guest LDT & TSS */ + /* Guest LDT and TSS. */ arbytes.fields.s = 0; /* not code or data segement */ arbytes.fields.seg_type = 0x2; /* LTD */ arbytes.fields.default_ops_size = 0; /* 16-bit */ arbytes.fields.g = 0; error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes); - arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */ error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes); - /* CR3 is set in vmx_final_setup_guest */ error |= __vmwrite(GUEST_RSP, 0); error |= __vmwrite(GUEST_RIP, regs->eip); - /* Guest EFLAGS */ + /* Guest EFLAGS. */ eflags = regs->eflags & ~HVM_EFLAGS_RESERVED_0; /* clear 0s */ eflags |= HVM_EFLAGS_RESERVED_1; /* set 1s */ error |= __vmwrite(GUEST_RFLAGS, eflags); error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); - __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7)); - error |= __vmwrite(GUEST_DR7, dr7); + __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (tmp)); + error |= __vmwrite(GUEST_DR7, tmp); error |= __vmwrite(VMCS_LINK_POINTER, ~0UL); #if defined(__i386__) error |= __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL); #endif - return error; -} - -static inline int construct_vmcs_host(void) -{ - int error = 0; -#ifdef __x86_64__ - unsigned long fs_base; - unsigned long gs_base; -#endif - unsigned long crn; - - /* Host Selectors */ - error |= __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS); - error |= __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS); - error |= __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS); -#if defined(__i386__) - error |= __vmwrite(HOST_FS_SELECTOR, __HYPERVISOR_DS); - error |= __vmwrite(HOST_GS_SELECTOR, __HYPERVISOR_DS); - error |= __vmwrite(HOST_FS_BASE, 0); - error |= __vmwrite(HOST_GS_BASE, 0); - -#else - rdmsrl(MSR_FS_BASE, fs_base); - rdmsrl(MSR_GS_BASE, gs_base); - error |= __vmwrite(HOST_FS_BASE, fs_base); - error |= __vmwrite(HOST_GS_BASE, gs_base); - -#endif - error |= __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS); - - __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : ); - error |= __vmwrite(HOST_CR0, crn); /* same CR0 */ - - /* CR3 is set in vmx_final_setup_hostos */ - __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : ); - error |= __vmwrite(HOST_CR4, crn); - - error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler); - - return error; -} - -/* - * the working VMCS pointer has been set properly - * just before entering this function. - */ -static int construct_vmcs(struct vcpu *v, - cpu_user_regs_t *regs) -{ - struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx; - int error; - - if ( (error = construct_vmcs_controls(arch_vmx)) ) { - printk("construct_vmcs: construct_vmcs_controls failed.\n"); - return error; - } - - /* host selectors */ - if ( (error = construct_vmcs_host()) ) { - printk("construct_vmcs: construct_vmcs_host failed.\n"); - return error; - } - - /* guest selectors */ - if ( (error = construct_init_vmcs_guest(regs)) ) { - printk("construct_vmcs: construct_vmcs_guest failed.\n"); - return error; - } - - if ( (error = __vmwrite(EXCEPTION_BITMAP, - MONITOR_DEFAULT_EXCEPTION_BITMAP)) ) { - printk("construct_vmcs: setting exception bitmap failed.\n"); - return error; - } + error |= __vmwrite(EXCEPTION_BITMAP, + MONITOR_DEFAULT_EXCEPTION_BITMAP); if ( regs->eflags & EF_TF ) - error = __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); + error |= __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); else - error = __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); + error |= __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); return error; } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index e91bb58d6a..a220d30fcc 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -566,8 +566,6 @@ static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) return 0; /* dummy */ } - - /* Make sure that xen intercepts any FP accesses from current */ static void vmx_stts(struct vcpu *v) { @@ -591,20 +589,16 @@ static void vmx_stts(struct vcpu *v) } } - static void vmx_set_tsc_offset(struct vcpu *v, u64 offset) { - /* VMX depends on operating on the current vcpu */ - ASSERT(v == current); - + vmx_vmcs_enter(v); __vmwrite(TSC_OFFSET, offset); #if defined (__i386__) __vmwrite(TSC_OFFSET_HIGH, offset >> 32); #endif + vmx_vmcs_exit(v); } - - /* SMP VMX guest support */ static void vmx_init_ap_context(struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector) diff --git a/xen/common/domain.c b/xen/common/domain.c index 0d63c46395..08327a37fd 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -64,12 +64,16 @@ void free_domain(struct domain *d) struct vcpu *v; int i; - sched_destroy_domain(d); - for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- ) - if ( (v = d->vcpu[i]) != NULL ) - free_vcpu_struct(v); + { + if ( (v = d->vcpu[i]) == NULL ) + continue; + vcpu_destroy(v); + sched_destroy_vcpu(v); + free_vcpu_struct(v); + } + sched_destroy_domain(d); xfree(d); } @@ -80,7 +84,7 @@ struct vcpu *alloc_vcpu( BUG_ON(d->vcpu[vcpu_id] != NULL); - if ( (v = alloc_vcpu_struct(d, vcpu_id)) == NULL ) + if ( (v = alloc_vcpu_struct()) == NULL ) return NULL; v->domain = d; @@ -94,12 +98,19 @@ struct vcpu *alloc_vcpu( if ( (vcpu_id != 0) && !is_idle_domain(d) ) set_bit(_VCPUF_down, &v->vcpu_flags); - if ( sched_init_vcpu(v, cpu_id) < 0 ) + if ( sched_init_vcpu(v, cpu_id) != 0 ) { free_vcpu_struct(v); return NULL; } + if ( vcpu_initialise(v) != 0 ) + { + sched_destroy_vcpu(v); + free_vcpu_struct(v); + return NULL; + } + d->vcpu[vcpu_id] = v; if ( vcpu_id != 0 ) d->vcpu[v->vcpu_id-1]->next_in_list = v; @@ -153,6 +164,9 @@ struct domain *domain_create(domid_t domid, unsigned int domcr_flags) if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) ) goto fail4; + if ( sched_init_domain(d) != 0 ) + goto fail4; + if ( !is_idle_domain(d) ) { write_lock(&domlist_lock); diff --git a/xen/common/sched_credit.c b/xen/common/sched_credit.c index 9dec930b80..984ef277c0 100644 --- a/xen/common/sched_credit.c +++ b/xen/common/sched_credit.c @@ -115,8 +115,10 @@ _MACRO(steal_peer_idle) \ _MACRO(steal_peer_running) \ _MACRO(steal_peer_pinned) \ + _MACRO(dom_init) \ + _MACRO(dom_destroy) \ _MACRO(vcpu_init) \ - _MACRO(dom_destroy) + _MACRO(vcpu_destroy) #ifndef NDEBUG #define CSCHED_STATS_EXPAND_CHECKS(_MACRO) \ @@ -454,43 +456,14 @@ static int csched_vcpu_init(struct vcpu *vc) { struct domain * const dom = vc->domain; - struct csched_dom *sdom; + struct csched_dom *sdom = CSCHED_DOM(dom); struct csched_vcpu *svc; - int16_t pri; CSCHED_STAT_CRANK(vcpu_init); - /* Allocate, if appropriate, per-domain info */ - if ( is_idle_vcpu(vc) ) - { - sdom = NULL; - pri = CSCHED_PRI_IDLE; - } - else if ( CSCHED_DOM(dom) ) - { - sdom = CSCHED_DOM(dom); - pri = CSCHED_PRI_TS_UNDER; - } - else - { - sdom = xmalloc(struct csched_dom); - if ( !sdom ) - return -1; - - /* Initialize credit and weight */ - INIT_LIST_HEAD(&sdom->active_vcpu); - sdom->active_vcpu_count = 0; - INIT_LIST_HEAD(&sdom->active_sdom_elem); - sdom->dom = dom; - sdom->weight = CSCHED_DEFAULT_WEIGHT; - sdom->cap = 0U; - dom->sched_priv = sdom; - pri = CSCHED_PRI_TS_UNDER; - } - /* Allocate per-VCPU info */ svc = xmalloc(struct csched_vcpu); - if ( !svc ) + if ( svc == NULL ) return -1; INIT_LIST_HEAD(&svc->runq_elem); @@ -498,7 +471,7 @@ csched_vcpu_init(struct vcpu *vc) svc->sdom = sdom; svc->vcpu = vc; atomic_set(&svc->credit, 0); - svc->pri = pri; + svc->pri = is_idle_domain(dom) ? CSCHED_PRI_IDLE : CSCHED_PRI_TS_UNDER; memset(&svc->stats, 0, sizeof(svc->stats)); vc->sched_priv = svc; @@ -521,12 +494,14 @@ csched_vcpu_init(struct vcpu *vc) } static void -csched_vcpu_free(struct vcpu *vc) +csched_vcpu_destroy(struct vcpu *vc) { struct csched_vcpu * const svc = CSCHED_VCPU(vc); struct csched_dom * const sdom = svc->sdom; unsigned long flags; + CSCHED_STAT_CRANK(vcpu_destroy); + BUG_ON( sdom == NULL ); BUG_ON( !list_empty(&svc->runq_elem) ); @@ -641,20 +616,39 @@ csched_dom_cntl( return 0; } +static int +csched_dom_init(struct domain *dom) +{ + struct csched_dom *sdom; + + CSCHED_STAT_CRANK(dom_init); + + if ( is_idle_domain(dom) ) + return 0; + + sdom = xmalloc(struct csched_dom); + if ( sdom == NULL ) + return -ENOMEM; + + /* Initialize credit and weight */ + INIT_LIST_HEAD(&sdom->active_vcpu); + sdom->active_vcpu_count = 0; + INIT_LIST_HEAD(&sdom->active_sdom_elem); + sdom->dom = dom; + sdom->weight = CSCHED_DEFAULT_WEIGHT; + sdom->cap = 0U; + dom->sched_priv = sdom; + + return 0; +} + static void csched_dom_destroy(struct domain *dom) { struct csched_dom * const sdom = CSCHED_DOM(dom); - int i; CSCHED_STAT_CRANK(dom_destroy); - for ( i = 0; i < MAX_VIRT_CPUS; i++ ) - { - if ( dom->vcpu[i] ) - csched_vcpu_free(dom->vcpu[i]); - } - xfree(sdom); } @@ -1226,9 +1220,12 @@ struct scheduler sched_credit_def = { .opt_name = "credit", .sched_id = XEN_SCHEDULER_CREDIT, - .init_vcpu = csched_vcpu_init, + .init_domain = csched_dom_init, .destroy_domain = csched_dom_destroy, + .init_vcpu = csched_vcpu_init, + .destroy_vcpu = csched_vcpu_destroy, + .sleep = csched_vcpu_sleep, .wake = csched_vcpu_wake, diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index 3e041d860e..5b0029575f 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -333,14 +333,6 @@ static int sedf_init_vcpu(struct vcpu *v) { struct sedf_vcpu_info *inf; - if ( v->domain->sched_priv == NULL ) - { - v->domain->sched_priv = xmalloc(struct sedf_dom_info); - if ( v->domain->sched_priv == NULL ) - return -1; - memset(v->domain->sched_priv, 0, sizeof(struct sedf_dom_info)); - } - if ( (v->sched_priv = xmalloc(struct sedf_vcpu_info)) == NULL ) return -1; memset(v->sched_priv, 0, sizeof(struct sedf_vcpu_info)); @@ -398,15 +390,25 @@ static int sedf_init_vcpu(struct vcpu *v) return 0; } -static void sedf_destroy_domain(struct domain *d) +static void sedf_destroy_vcpu(struct vcpu *v) { - int i; + xfree(v->sched_priv); +} +static int sedf_init_domain(struct domain *d) +{ + d->sched_priv = xmalloc(struct sedf_dom_info); + if ( d->sched_priv == NULL ) + return -ENOMEM; + + memset(d->sched_priv, 0, sizeof(struct sedf_dom_info)); + + return 0; +} + +static void sedf_destroy_domain(struct domain *d) +{ xfree(d->sched_priv); - - for ( i = 0; i < MAX_VIRT_CPUS; i++ ) - if ( d->vcpu[i] ) - xfree(d->vcpu[i]->sched_priv); } /* @@ -1427,9 +1429,12 @@ struct scheduler sched_sedf_def = { .opt_name = "sedf", .sched_id = XEN_SCHEDULER_SEDF, - .init_vcpu = sedf_init_vcpu, + .init_domain = sedf_init_domain, .destroy_domain = sedf_destroy_domain, + .init_vcpu = sedf_init_vcpu, + .destroy_vcpu = sedf_destroy_vcpu, + .do_schedule = sedf_do_schedule, .dump_cpu_state = sedf_dump_cpu_state, .sleep = sedf_sleep, diff --git a/xen/common/schedule.c b/xen/common/schedule.c index e85f0846e7..920afde256 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -132,17 +132,20 @@ int sched_init_vcpu(struct vcpu *v, unsigned int processor) return SCHED_OP(init_vcpu, v); } -void sched_destroy_domain(struct domain *d) +void sched_destroy_vcpu(struct vcpu *v) { - struct vcpu *v; + kill_timer(&v->timer); + kill_timer(&v->poll_timer); + SCHED_OP(destroy_vcpu, v); +} - for_each_vcpu ( d, v ) - { - kill_timer(&v->timer); - kill_timer(&v->poll_timer); - TRACE_2D(TRC_SCHED_DOM_REM, v->domain->domain_id, v->vcpu_id); - } +int sched_init_domain(struct domain *d) +{ + return SCHED_OP(init_domain, d); +} +void sched_destroy_domain(struct domain *d) +{ SCHED_OP(destroy_domain, d); } diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h index 40103e7df5..70e8902a73 100644 --- a/xen/include/xen/domain.h +++ b/xen/include/xen/domain.h @@ -15,10 +15,20 @@ void free_domain(struct domain *d); * Arch-specifics. */ -struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id); - +/* Allocate/free a VCPU structure. */ +struct vcpu *alloc_vcpu_struct(void); void free_vcpu_struct(struct vcpu *v); +/* + * Initialise/destroy arch-specific details of a VCPU. + * - vcpu_initialise() is called after the basic generic fields of the + * VCPU structure are initialised. Many operations can be applied to the + * VCPU at this point (e.g., vcpu_pause()). + * - vcpu_destroy() is called only if vcpu_initialise() previously succeeded. + */ +int vcpu_initialise(struct vcpu *v); +void vcpu_destroy(struct vcpu *v); + int arch_domain_create(struct domain *d); void arch_domain_destroy(struct domain *d); diff --git a/xen/include/xen/sched-if.h b/xen/include/xen/sched-if.h index dc3b04fa22..410358cc48 100644 --- a/xen/include/xen/sched-if.h +++ b/xen/include/xen/sched-if.h @@ -63,9 +63,12 @@ struct scheduler { void (*init) (void); void (*tick) (unsigned int cpu); - int (*init_vcpu) (struct vcpu *); + int (*init_domain) (struct domain *); void (*destroy_domain) (struct domain *); + int (*init_vcpu) (struct vcpu *); + void (*destroy_vcpu) (struct vcpu *); + void (*sleep) (struct vcpu *); void (*wake) (struct vcpu *); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 42c1d39946..d08959cab1 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -291,7 +291,9 @@ void new_thread(struct vcpu *d, void scheduler_init(void); void schedulers_start(void); int sched_init_vcpu(struct vcpu *v, unsigned int processor); -void sched_destroy_domain(struct domain *); +void sched_destroy_vcpu(struct vcpu *v); +int sched_init_domain(struct domain *d); +void sched_destroy_domain(struct domain *d); long sched_adjust(struct domain *, struct xen_domctl_scheduler_op *); int sched_id(void); void vcpu_wake(struct vcpu *d); |