debuggers.hg

view xen/common/domain.c @ 10989:16aa4b417c6b

[XEN] Clean up shutdown handling and ignore opt_noreboot if dom0
shuts down cleanly. The option is intended only to retain information
on the local console in case of a crash.

Based on a patch from Muli Ben-Yehuda <muli@il.ibm.com>

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Aug 07 15:35:06 2006 +0100 (2006-08-07)
parents 462d6e4cb29a
children b3dd6ceda9bc
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 <xen/shutdown.h>
24 #include <asm/debugger.h>
25 #include <public/dom0_ops.h>
26 #include <public/sched.h>
27 #include <public/vcpu.h>
29 /* Both these structures are protected by the domlist_lock. */
30 rwlock_t domlist_lock = RW_LOCK_UNLOCKED;
31 struct domain *domain_hash[DOMAIN_HASH_SIZE];
32 struct domain *domain_list;
34 struct domain *dom0;
36 struct vcpu *idle_vcpu[NR_CPUS];
38 struct domain *alloc_domain(domid_t domid)
39 {
40 struct domain *d;
42 if ( (d = xmalloc(struct domain)) == NULL )
43 return NULL;
45 memset(d, 0, sizeof(*d));
46 d->domain_id = domid;
47 atomic_set(&d->refcnt, 1);
48 spin_lock_init(&d->big_lock);
49 spin_lock_init(&d->page_alloc_lock);
50 spin_lock_init(&d->pause_lock);
51 INIT_LIST_HEAD(&d->page_list);
52 INIT_LIST_HEAD(&d->xenpage_list);
54 return d;
55 }
58 void free_domain(struct domain *d)
59 {
60 struct vcpu *v;
61 int i;
63 sched_destroy_domain(d);
65 for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
66 if ( (v = d->vcpu[i]) != NULL )
67 free_vcpu_struct(v);
69 xfree(d);
70 }
73 struct vcpu *alloc_vcpu(
74 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
75 {
76 struct vcpu *v;
78 BUG_ON(d->vcpu[vcpu_id] != NULL);
80 if ( (v = alloc_vcpu_struct(d, vcpu_id)) == NULL )
81 return NULL;
83 v->domain = d;
84 v->vcpu_id = vcpu_id;
85 v->processor = cpu_id;
86 v->vcpu_info = &d->shared_info->vcpu_info[vcpu_id];
87 spin_lock_init(&v->pause_lock);
89 v->cpu_affinity = is_idle_domain(d) ?
90 cpumask_of_cpu(cpu_id) : CPU_MASK_ALL;
92 v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
93 v->runstate.state_entry_time = NOW();
95 if ( (vcpu_id != 0) && !is_idle_domain(d) )
96 set_bit(_VCPUF_down, &v->vcpu_flags);
98 if ( sched_init_vcpu(v) < 0 )
99 {
100 free_vcpu_struct(v);
101 return NULL;
102 }
104 d->vcpu[vcpu_id] = v;
105 if ( vcpu_id != 0 )
106 d->vcpu[v->vcpu_id-1]->next_in_list = v;
108 return v;
109 }
111 struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
112 {
113 struct domain *d;
114 struct vcpu *v;
115 unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
117 d = (vcpu_id == 0) ?
118 domain_create(IDLE_DOMAIN_ID) :
119 idle_vcpu[cpu_id - vcpu_id]->domain;
120 BUG_ON(d == NULL);
122 v = alloc_vcpu(d, vcpu_id, cpu_id);
123 idle_vcpu[cpu_id] = v;
125 return v;
126 }
128 struct domain *domain_create(domid_t domid)
129 {
130 struct domain *d, **pd;
132 if ( (d = alloc_domain(domid)) == NULL )
133 return NULL;
135 rangeset_domain_initialise(d);
137 if ( !is_idle_domain(d) )
138 {
139 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
140 if ( evtchn_init(d) != 0 )
141 goto fail1;
142 if ( grant_table_create(d) != 0 )
143 goto fail2;
144 }
146 if ( arch_domain_create(d) != 0 )
147 goto fail3;
149 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
150 d->irq_caps = rangeset_new(d, "Interrupts", 0);
151 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
152 goto fail4;
154 if ( !is_idle_domain(d) )
155 {
156 write_lock(&domlist_lock);
157 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
158 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
159 if ( (*pd)->domain_id > d->domain_id )
160 break;
161 d->next_in_list = *pd;
162 *pd = d;
163 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
164 domain_hash[DOMAIN_HASH(domid)] = d;
165 write_unlock(&domlist_lock);
166 }
168 return d;
170 fail4:
171 arch_domain_destroy(d);
172 fail3:
173 if ( !is_idle_domain(d) )
174 grant_table_destroy(d);
175 fail2:
176 if ( !is_idle_domain(d) )
177 evtchn_destroy(d);
178 fail1:
179 rangeset_domain_destroy(d);
180 free_domain(d);
181 return NULL;
182 }
185 struct domain *find_domain_by_id(domid_t dom)
186 {
187 struct domain *d;
189 read_lock(&domlist_lock);
190 d = domain_hash[DOMAIN_HASH(dom)];
191 while ( d != NULL )
192 {
193 if ( d->domain_id == dom )
194 {
195 if ( unlikely(!get_domain(d)) )
196 d = NULL;
197 break;
198 }
199 d = d->next_in_hashbucket;
200 }
201 read_unlock(&domlist_lock);
203 return d;
204 }
207 void domain_kill(struct domain *d)
208 {
209 domain_pause(d);
211 if ( test_and_set_bit(_DOMF_dying, &d->domain_flags) )
212 return;
214 gnttab_release_mappings(d);
215 domain_relinquish_resources(d);
216 put_domain(d);
218 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
219 }
222 void __domain_crash(struct domain *d)
223 {
224 if ( d == current->domain )
225 {
226 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
227 d->domain_id, current->vcpu_id, smp_processor_id());
228 show_execution_state(guest_cpu_user_regs());
229 }
230 else
231 {
232 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
233 d->domain_id, current->domain->domain_id, smp_processor_id());
234 }
236 domain_shutdown(d, SHUTDOWN_crash);
237 }
240 void __domain_crash_synchronous(void)
241 {
242 __domain_crash(current->domain);
243 for ( ; ; )
244 do_softirq();
245 }
248 static struct domain *domain_shuttingdown[NR_CPUS];
250 static void domain_shutdown_finalise(void)
251 {
252 struct domain *d;
253 struct vcpu *v;
255 d = domain_shuttingdown[smp_processor_id()];
256 domain_shuttingdown[smp_processor_id()] = NULL;
258 BUG_ON(d == NULL);
259 BUG_ON(d == current->domain);
261 LOCK_BIGLOCK(d);
263 /* Make sure that every vcpu is descheduled before we finalise. */
264 for_each_vcpu ( d, v )
265 vcpu_sleep_sync(v);
266 BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
268 sync_pagetable_state(d);
270 /* Don't set DOMF_shutdown until execution contexts are sync'ed. */
271 if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
272 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
274 UNLOCK_BIGLOCK(d);
276 put_domain(d);
277 }
279 static __init int domain_shutdown_finaliser_init(void)
280 {
281 open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
282 return 0;
283 }
284 __initcall(domain_shutdown_finaliser_init);
286 void domain_shutdown(struct domain *d, u8 reason)
287 {
288 struct vcpu *v;
290 if ( d->domain_id == 0 )
291 dom0_shutdown(reason);
293 /* Mark the domain as shutting down. */
294 d->shutdown_code = reason;
296 /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
297 spin_lock(&d->pause_lock);
298 d->pause_count++;
299 set_bit(_DOMF_paused, &d->domain_flags);
300 spin_unlock(&d->pause_lock);
301 for_each_vcpu ( d, v )
302 vcpu_sleep_nosync(v);
304 get_knownalive_domain(d);
305 domain_shuttingdown[smp_processor_id()] = d;
306 raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
307 }
310 void domain_pause_for_debugger(void)
311 {
312 struct domain *d = current->domain;
313 struct vcpu *v;
315 /*
316 * NOTE: This does not synchronously pause the domain. The debugger
317 * must issue a PAUSEDOMAIN command to ensure that all execution
318 * has ceased and guest state is committed to memory.
319 */
320 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
321 for_each_vcpu ( d, v )
322 vcpu_sleep_nosync(v);
324 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
325 }
328 /* Release resources belonging to task @p. */
329 void domain_destroy(struct domain *d)
330 {
331 struct domain **pd;
332 atomic_t old, new;
334 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
336 /* May be already destroyed, or get_domain() can race us. */
337 _atomic_set(old, 0);
338 _atomic_set(new, DOMAIN_DESTROYED);
339 old = atomic_compareandswap(old, new, &d->refcnt);
340 if ( _atomic_read(old) != 0 )
341 return;
343 /* Delete from task list and task hashtable. */
344 write_lock(&domlist_lock);
345 pd = &domain_list;
346 while ( *pd != d )
347 pd = &(*pd)->next_in_list;
348 *pd = d->next_in_list;
349 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
350 while ( *pd != d )
351 pd = &(*pd)->next_in_hashbucket;
352 *pd = d->next_in_hashbucket;
353 write_unlock(&domlist_lock);
355 rangeset_domain_destroy(d);
357 evtchn_destroy(d);
358 grant_table_destroy(d);
360 arch_domain_destroy(d);
362 free_domain(d);
364 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
365 }
367 void vcpu_pause(struct vcpu *v)
368 {
369 ASSERT(v != current);
371 spin_lock(&v->pause_lock);
372 if ( v->pause_count++ == 0 )
373 set_bit(_VCPUF_paused, &v->vcpu_flags);
374 spin_unlock(&v->pause_lock);
376 vcpu_sleep_sync(v);
377 }
379 void vcpu_unpause(struct vcpu *v)
380 {
381 int wake;
383 ASSERT(v != current);
385 spin_lock(&v->pause_lock);
386 wake = (--v->pause_count == 0);
387 if ( wake )
388 clear_bit(_VCPUF_paused, &v->vcpu_flags);
389 spin_unlock(&v->pause_lock);
391 if ( wake )
392 vcpu_wake(v);
393 }
395 void domain_pause(struct domain *d)
396 {
397 struct vcpu *v;
399 ASSERT(d != current->domain);
401 spin_lock(&d->pause_lock);
402 if ( d->pause_count++ == 0 )
403 set_bit(_DOMF_paused, &d->domain_flags);
404 spin_unlock(&d->pause_lock);
406 for_each_vcpu( d, v )
407 vcpu_sleep_sync(v);
409 sync_pagetable_state(d);
410 }
412 void domain_unpause(struct domain *d)
413 {
414 struct vcpu *v;
415 int wake;
417 ASSERT(d != current->domain);
419 spin_lock(&d->pause_lock);
420 wake = (--d->pause_count == 0);
421 if ( wake )
422 clear_bit(_DOMF_paused, &d->domain_flags);
423 spin_unlock(&d->pause_lock);
425 if ( wake )
426 for_each_vcpu( d, v )
427 vcpu_wake(v);
428 }
430 void domain_pause_by_systemcontroller(struct domain *d)
431 {
432 struct vcpu *v;
434 BUG_ON(current->domain == d);
436 if ( !test_and_set_bit(_DOMF_ctrl_pause, &d->domain_flags) )
437 {
438 for_each_vcpu ( d, v )
439 vcpu_sleep_sync(v);
440 }
442 sync_pagetable_state(d);
443 }
445 void domain_unpause_by_systemcontroller(struct domain *d)
446 {
447 struct vcpu *v;
449 if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
450 {
451 for_each_vcpu ( d, v )
452 vcpu_wake(v);
453 }
454 }
457 /*
458 * set_info_guest is used for final setup, launching, and state modification
459 * of domains other than domain 0. ie. the domains that are being built by
460 * the userspace dom0 domain builder.
461 */
462 int set_info_guest(struct domain *d, dom0_setvcpucontext_t *setvcpucontext)
463 {
464 int rc = 0;
465 struct vcpu_guest_context *c = NULL;
466 unsigned long vcpu = setvcpucontext->vcpu;
467 struct vcpu *v;
469 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
470 return -EINVAL;
472 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
473 return -ENOMEM;
475 domain_pause(d);
477 rc = -EFAULT;
478 if ( copy_from_guest(c, setvcpucontext->ctxt, 1) == 0 )
479 rc = arch_set_info_guest(v, c);
481 domain_unpause(d);
483 xfree(c);
484 return rc;
485 }
487 int boot_vcpu(struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt)
488 {
489 struct vcpu *v = d->vcpu[vcpuid];
491 BUG_ON(test_bit(_VCPUF_initialised, &v->vcpu_flags));
493 return arch_set_info_guest(v, ctxt);
494 }
496 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
497 {
498 struct domain *d = current->domain;
499 struct vcpu *v;
500 struct vcpu_guest_context *ctxt;
501 long rc = 0;
503 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
504 return -EINVAL;
506 if ( (v = d->vcpu[vcpuid]) == NULL )
507 return -ENOENT;
509 switch ( cmd )
510 {
511 case VCPUOP_initialise:
512 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
513 {
514 rc = -ENOMEM;
515 break;
516 }
518 if ( copy_from_guest(ctxt, arg, 1) )
519 {
520 xfree(ctxt);
521 rc = -EFAULT;
522 break;
523 }
525 LOCK_BIGLOCK(d);
526 rc = -EEXIST;
527 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
528 rc = boot_vcpu(d, vcpuid, ctxt);
529 UNLOCK_BIGLOCK(d);
531 xfree(ctxt);
532 break;
534 case VCPUOP_up:
535 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
536 rc = -EINVAL;
537 else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) )
538 vcpu_wake(v);
539 break;
541 case VCPUOP_down:
542 if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
543 vcpu_sleep_nosync(v);
544 break;
546 case VCPUOP_is_up:
547 rc = !test_bit(_VCPUF_down, &v->vcpu_flags);
548 break;
550 case VCPUOP_get_runstate_info:
551 {
552 struct vcpu_runstate_info runstate;
553 vcpu_runstate_get(v, &runstate);
554 if ( copy_to_guest(arg, &runstate, 1) )
555 rc = -EFAULT;
556 break;
557 }
559 default:
560 rc = arch_do_vcpu_op(cmd, v, arg);
561 break;
562 }
564 return rc;
565 }
567 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
568 {
569 if ( type > MAX_VMASST_TYPE )
570 return -EINVAL;
572 switch ( cmd )
573 {
574 case VMASST_CMD_enable:
575 set_bit(type, &p->vm_assist);
576 return 0;
577 case VMASST_CMD_disable:
578 clear_bit(type, &p->vm_assist);
579 return 0;
580 }
582 return -ENOSYS;
583 }
585 /*
586 * Local variables:
587 * mode: C
588 * c-set-style: "BSD"
589 * c-basic-offset: 4
590 * tab-width: 4
591 * indent-tabs-mode: nil
592 * End:
593 */