ia64/xen-unstable

view xen/common/domain.c @ 10293:4122e88b6c75

Move idle-vcpu allocation logic to a common function.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Jun 02 09:31:35 2006 +0100 (2006-06-02)
parents 6993a0f91efc
children f3561b1ee7a3
line source
1 /******************************************************************************
2 * domain.c
3 *
4 * Generic domain-handling functions.
5 */
7 #include <xen/config.h>
8 #include <xen/init.h>
9 #include <xen/lib.h>
10 #include <xen/errno.h>
11 #include <xen/sched.h>
12 #include <xen/domain.h>
13 #include <xen/mm.h>
14 #include <xen/event.h>
15 #include <xen/time.h>
16 #include <xen/console.h>
17 #include <xen/softirq.h>
18 #include <xen/domain_page.h>
19 #include <xen/rangeset.h>
20 #include <xen/guest_access.h>
21 #include <xen/hypercall.h>
22 #include <xen/delay.h>
23 #include <asm/debugger.h>
24 #include <public/dom0_ops.h>
25 #include <public/sched.h>
26 #include <public/vcpu.h>
28 /* Both these structures are protected by the domlist_lock. */
29 rwlock_t domlist_lock = RW_LOCK_UNLOCKED;
30 struct domain *domain_hash[DOMAIN_HASH_SIZE];
31 struct domain *domain_list;
33 struct domain *dom0;
35 struct vcpu *idle_vcpu[NR_CPUS];
37 struct domain *alloc_domain(domid_t domid)
38 {
39 struct domain *d;
41 if ( (d = xmalloc(struct domain)) == NULL )
42 return NULL;
44 memset(d, 0, sizeof(*d));
45 d->domain_id = domid;
46 atomic_set(&d->refcnt, 1);
47 spin_lock_init(&d->big_lock);
48 spin_lock_init(&d->page_alloc_lock);
49 INIT_LIST_HEAD(&d->page_list);
50 INIT_LIST_HEAD(&d->xenpage_list);
52 return d;
53 }
56 void free_domain(struct domain *d)
57 {
58 struct vcpu *v;
59 int i;
61 sched_destroy_domain(d);
63 for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
64 if ( (v = d->vcpu[i]) != NULL )
65 free_vcpu_struct(v);
67 xfree(d);
68 }
71 struct vcpu *alloc_vcpu(
72 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
73 {
74 struct vcpu *v;
76 BUG_ON(d->vcpu[vcpu_id] != NULL);
78 if ( (v = alloc_vcpu_struct(d, vcpu_id)) == NULL )
79 return NULL;
81 v->domain = d;
82 v->vcpu_id = vcpu_id;
83 v->processor = cpu_id;
84 atomic_set(&v->pausecnt, 0);
85 v->vcpu_info = &d->shared_info->vcpu_info[vcpu_id];
87 v->cpu_affinity = is_idle_domain(d) ?
88 cpumask_of_cpu(cpu_id) : CPU_MASK_ALL;
90 v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
91 v->runstate.state_entry_time = NOW();
93 if ( (vcpu_id != 0) && !is_idle_domain(d) )
94 set_bit(_VCPUF_down, &v->vcpu_flags);
96 if ( sched_init_vcpu(v) < 0 )
97 {
98 free_vcpu_struct(v);
99 return NULL;
100 }
102 d->vcpu[vcpu_id] = v;
103 if ( vcpu_id != 0 )
104 d->vcpu[v->vcpu_id-1]->next_in_list = v;
106 return v;
107 }
109 struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
110 {
111 struct domain *d;
112 struct vcpu *v;
113 unsigned int vcpu_id;
115 if ((vcpu_id = cpu_id % MAX_VIRT_CPUS) == 0)
116 {
117 d = domain_create(IDLE_DOMAIN_ID, cpu_id);
118 BUG_ON(d == NULL);
119 v = d->vcpu[0];
120 }
121 else
122 {
123 d = idle_vcpu[cpu_id - vcpu_id]->domain;
124 BUG_ON(d == NULL);
125 v = alloc_vcpu(d, vcpu_id, cpu_id);
126 }
128 idle_vcpu[cpu_id] = v;
130 return v;
131 }
133 struct domain *domain_create(domid_t domid, unsigned int cpu)
134 {
135 struct domain *d, **pd;
136 struct vcpu *v;
138 if ( (d = alloc_domain(domid)) == NULL )
139 return NULL;
141 rangeset_domain_initialise(d);
143 if ( !is_idle_domain(d) )
144 {
145 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
146 if ( evtchn_init(d) != 0 )
147 goto fail1;
148 if ( grant_table_create(d) != 0 )
149 goto fail2;
150 }
152 if ( arch_domain_create(d) != 0 )
153 goto fail3;
155 if ( (v = alloc_vcpu(d, 0, cpu)) == NULL )
156 goto fail4;
158 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
159 d->irq_caps = rangeset_new(d, "Interrupts", 0);
160 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
161 goto fail4; /* NB. alloc_vcpu() is undone in free_domain() */
163 if ( !is_idle_domain(d) )
164 {
165 write_lock(&domlist_lock);
166 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
167 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
168 if ( (*pd)->domain_id > d->domain_id )
169 break;
170 d->next_in_list = *pd;
171 *pd = d;
172 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
173 domain_hash[DOMAIN_HASH(domid)] = d;
174 write_unlock(&domlist_lock);
175 }
177 return d;
179 fail4:
180 arch_domain_destroy(d);
181 fail3:
182 if ( !is_idle_domain(d) )
183 grant_table_destroy(d);
184 fail2:
185 if ( !is_idle_domain(d) )
186 evtchn_destroy(d);
187 fail1:
188 rangeset_domain_destroy(d);
189 free_domain(d);
190 return NULL;
191 }
194 struct domain *find_domain_by_id(domid_t dom)
195 {
196 struct domain *d;
198 read_lock(&domlist_lock);
199 d = domain_hash[DOMAIN_HASH(dom)];
200 while ( d != NULL )
201 {
202 if ( d->domain_id == dom )
203 {
204 if ( unlikely(!get_domain(d)) )
205 d = NULL;
206 break;
207 }
208 d = d->next_in_hashbucket;
209 }
210 read_unlock(&domlist_lock);
212 return d;
213 }
216 void domain_kill(struct domain *d)
217 {
218 domain_pause(d);
220 if ( test_and_set_bit(_DOMF_dying, &d->domain_flags) )
221 return;
223 gnttab_release_mappings(d);
224 domain_relinquish_resources(d);
225 put_domain(d);
227 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
228 }
231 void __domain_crash(struct domain *d)
232 {
233 if ( d == current->domain )
234 {
235 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
236 d->domain_id, current->vcpu_id, smp_processor_id());
237 show_registers(guest_cpu_user_regs());
238 }
239 else
240 {
241 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
242 d->domain_id, current->domain->domain_id, smp_processor_id());
243 }
245 domain_shutdown(d, SHUTDOWN_crash);
246 }
249 void __domain_crash_synchronous(void)
250 {
251 __domain_crash(current->domain);
252 for ( ; ; )
253 do_softirq();
254 }
257 static struct domain *domain_shuttingdown[NR_CPUS];
259 static void domain_shutdown_finalise(void)
260 {
261 struct domain *d;
262 struct vcpu *v;
264 d = domain_shuttingdown[smp_processor_id()];
265 domain_shuttingdown[smp_processor_id()] = NULL;
267 BUG_ON(d == NULL);
268 BUG_ON(d == current->domain);
270 LOCK_BIGLOCK(d);
272 /* Make sure that every vcpu is descheduled before we finalise. */
273 for_each_vcpu ( d, v )
274 vcpu_sleep_sync(v);
275 BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
277 sync_pagetable_state(d);
279 /* Don't set DOMF_shutdown until execution contexts are sync'ed. */
280 if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
281 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
283 UNLOCK_BIGLOCK(d);
285 put_domain(d);
286 }
288 static __init int domain_shutdown_finaliser_init(void)
289 {
290 open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
291 return 0;
292 }
293 __initcall(domain_shutdown_finaliser_init);
296 void domain_shutdown(struct domain *d, u8 reason)
297 {
298 struct vcpu *v;
300 if ( d->domain_id == 0 )
301 {
302 extern void machine_restart(char *);
303 extern void machine_halt(void);
305 debugger_trap_immediate();
307 if ( reason == SHUTDOWN_poweroff )
308 {
309 printk("Domain 0 halted: halting machine.\n");
310 machine_halt();
311 }
312 else if ( reason == SHUTDOWN_crash )
313 {
314 printk("Domain 0 crashed: rebooting machine in 5 seconds.\n");
315 watchdog_disable();
316 mdelay(5000);
317 machine_restart(0);
318 }
319 else
320 {
321 printk("Domain 0 shutdown: rebooting machine.\n");
322 machine_restart(0);
323 }
324 }
326 /* Mark the domain as shutting down. */
327 d->shutdown_code = reason;
329 /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
330 for_each_vcpu ( d, v )
331 {
332 atomic_inc(&v->pausecnt);
333 vcpu_sleep_nosync(v);
334 }
336 get_knownalive_domain(d);
337 domain_shuttingdown[smp_processor_id()] = d;
338 raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
339 }
342 void domain_pause_for_debugger(void)
343 {
344 struct domain *d = current->domain;
345 struct vcpu *v;
347 /*
348 * NOTE: This does not synchronously pause the domain. The debugger
349 * must issue a PAUSEDOMAIN command to ensure that all execution
350 * has ceased and guest state is committed to memory.
351 */
352 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
353 for_each_vcpu ( d, v )
354 vcpu_sleep_nosync(v);
356 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
357 }
360 /* Release resources belonging to task @p. */
361 void domain_destroy(struct domain *d)
362 {
363 struct domain **pd;
364 atomic_t old, new;
366 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
368 /* May be already destroyed, or get_domain() can race us. */
369 _atomic_set(old, 0);
370 _atomic_set(new, DOMAIN_DESTROYED);
371 old = atomic_compareandswap(old, new, &d->refcnt);
372 if ( _atomic_read(old) != 0 )
373 return;
375 /* Delete from task list and task hashtable. */
376 write_lock(&domlist_lock);
377 pd = &domain_list;
378 while ( *pd != d )
379 pd = &(*pd)->next_in_list;
380 *pd = d->next_in_list;
381 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
382 while ( *pd != d )
383 pd = &(*pd)->next_in_hashbucket;
384 *pd = d->next_in_hashbucket;
385 write_unlock(&domlist_lock);
387 rangeset_domain_destroy(d);
389 evtchn_destroy(d);
390 grant_table_destroy(d);
392 arch_domain_destroy(d);
394 free_domain(d);
396 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
397 }
399 void vcpu_pause(struct vcpu *v)
400 {
401 BUG_ON(v == current);
402 atomic_inc(&v->pausecnt);
403 vcpu_sleep_sync(v);
404 }
406 void domain_pause(struct domain *d)
407 {
408 struct vcpu *v;
410 for_each_vcpu( d, v )
411 vcpu_pause(v);
413 sync_pagetable_state(d);
414 }
416 void vcpu_unpause(struct vcpu *v)
417 {
418 BUG_ON(v == current);
419 if ( atomic_dec_and_test(&v->pausecnt) )
420 vcpu_wake(v);
421 }
423 void domain_unpause(struct domain *d)
424 {
425 struct vcpu *v;
427 for_each_vcpu( d, v )
428 vcpu_unpause(v);
429 }
431 void domain_pause_by_systemcontroller(struct domain *d)
432 {
433 struct vcpu *v;
435 BUG_ON(current->domain == d);
437 if ( !test_and_set_bit(_DOMF_ctrl_pause, &d->domain_flags) )
438 {
439 for_each_vcpu ( d, v )
440 vcpu_sleep_sync(v);
441 }
443 sync_pagetable_state(d);
444 }
446 void domain_unpause_by_systemcontroller(struct domain *d)
447 {
448 struct vcpu *v;
450 if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
451 {
452 for_each_vcpu ( d, v )
453 vcpu_wake(v);
454 }
455 }
458 /*
459 * set_info_guest is used for final setup, launching, and state modification
460 * of domains other than domain 0. ie. the domains that are being built by
461 * the userspace dom0 domain builder.
462 */
463 int set_info_guest(struct domain *d, dom0_setvcpucontext_t *setvcpucontext)
464 {
465 int rc = 0;
466 struct vcpu_guest_context *c = NULL;
467 unsigned long vcpu = setvcpucontext->vcpu;
468 struct vcpu *v;
470 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
471 return -EINVAL;
473 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
474 return -ENOMEM;
476 domain_pause(d);
478 rc = -EFAULT;
479 if ( copy_from_guest(c, setvcpucontext->ctxt, 1) == 0 )
480 rc = arch_set_info_guest(v, c);
482 domain_unpause(d);
484 xfree(c);
485 return rc;
486 }
488 int boot_vcpu(struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt)
489 {
490 struct vcpu *v = d->vcpu[vcpuid];
492 BUG_ON(test_bit(_VCPUF_initialised, &v->vcpu_flags));
494 return arch_set_info_guest(v, ctxt);
495 }
497 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
498 {
499 struct domain *d = current->domain;
500 struct vcpu *v;
501 struct vcpu_guest_context *ctxt;
502 long rc = 0;
504 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
505 return -EINVAL;
507 if ( (v = d->vcpu[vcpuid]) == NULL )
508 return -ENOENT;
510 switch ( cmd )
511 {
512 case VCPUOP_initialise:
513 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
514 {
515 rc = -ENOMEM;
516 break;
517 }
519 if ( copy_from_guest(ctxt, arg, 1) )
520 {
521 xfree(ctxt);
522 rc = -EFAULT;
523 break;
524 }
526 LOCK_BIGLOCK(d);
527 rc = -EEXIST;
528 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
529 rc = boot_vcpu(d, vcpuid, ctxt);
530 UNLOCK_BIGLOCK(d);
532 xfree(ctxt);
533 break;
535 case VCPUOP_up:
536 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
537 rc = -EINVAL;
538 else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) )
539 vcpu_wake(v);
540 break;
542 case VCPUOP_down:
543 if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
544 vcpu_sleep_nosync(v);
545 break;
547 case VCPUOP_is_up:
548 rc = !test_bit(_VCPUF_down, &v->vcpu_flags);
549 break;
551 case VCPUOP_get_runstate_info:
552 {
553 struct vcpu_runstate_info runstate;
554 vcpu_runstate_get(v, &runstate);
555 if ( copy_to_guest(arg, &runstate, 1) )
556 rc = -EFAULT;
557 break;
558 }
560 default:
561 rc = arch_do_vcpu_op(cmd, v, arg);
562 break;
563 }
565 return rc;
566 }
568 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
569 {
570 if ( type > MAX_VMASST_TYPE )
571 return -EINVAL;
573 switch ( cmd )
574 {
575 case VMASST_CMD_enable:
576 set_bit(type, &p->vm_assist);
577 return 0;
578 case VMASST_CMD_disable:
579 clear_bit(type, &p->vm_assist);
580 return 0;
581 }
583 return -ENOSYS;
584 }
586 /*
587 * Local variables:
588 * mode: C
589 * c-set-style: "BSD"
590 * c-basic-offset: 4
591 * tab-width: 4
592 * indent-tabs-mode: nil
593 * End:
594 */