ia64/xen-unstable

view xen/common/domain.c @ 13589:c3b2443408f4

Fix crash if some secondary CPUs cannot be initialised.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Jan 24 11:04:22 2007 +0000 (2007-01-24)
parents 5dc5e6ba42d2
children 30af6cfdb05c
line source
1 /******************************************************************************
2 * domain.c
3 *
4 * Generic domain-handling functions.
5 */
7 #include <xen/config.h>
8 #include <xen/compat.h>
9 #include <xen/init.h>
10 #include <xen/lib.h>
11 #include <xen/errno.h>
12 #include <xen/sched.h>
13 #include <xen/domain.h>
14 #include <xen/mm.h>
15 #include <xen/event.h>
16 #include <xen/time.h>
17 #include <xen/console.h>
18 #include <xen/softirq.h>
19 #include <xen/domain_page.h>
20 #include <xen/rangeset.h>
21 #include <xen/guest_access.h>
22 #include <xen/hypercall.h>
23 #include <xen/delay.h>
24 #include <xen/shutdown.h>
25 #include <xen/percpu.h>
26 #include <xen/multicall.h>
27 #include <asm/debugger.h>
28 #include <public/sched.h>
29 #include <public/vcpu.h>
30 #ifdef CONFIG_COMPAT
31 #include <compat/domctl.h>
32 #endif
34 /* Both these structures are protected by the domlist_lock. */
35 DEFINE_RWLOCK(domlist_lock);
36 struct domain *domain_hash[DOMAIN_HASH_SIZE];
37 struct domain *domain_list;
39 struct domain *dom0;
41 struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
43 int current_domain_id(void)
44 {
45 return current->domain->domain_id;
46 }
48 struct domain *alloc_domain(domid_t domid)
49 {
50 struct domain *d;
52 if ( (d = xmalloc(struct domain)) == NULL )
53 return NULL;
55 memset(d, 0, sizeof(*d));
56 d->domain_id = domid;
57 atomic_set(&d->refcnt, 1);
58 spin_lock_init(&d->big_lock);
59 spin_lock_init(&d->page_alloc_lock);
60 spin_lock_init(&d->pause_lock);
61 INIT_LIST_HEAD(&d->page_list);
62 INIT_LIST_HEAD(&d->xenpage_list);
64 return d;
65 }
67 void free_domain(struct domain *d)
68 {
69 struct vcpu *v;
70 int i;
72 for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
73 {
74 if ( (v = d->vcpu[i]) == NULL )
75 continue;
76 vcpu_destroy(v);
77 sched_destroy_vcpu(v);
78 free_vcpu_struct(v);
79 }
81 sched_destroy_domain(d);
82 xfree(d);
83 }
85 struct vcpu *alloc_vcpu(
86 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
87 {
88 struct vcpu *v;
90 BUG_ON(d->vcpu[vcpu_id] != NULL);
92 if ( (v = alloc_vcpu_struct()) == NULL )
93 return NULL;
95 v->domain = d;
96 v->vcpu_id = vcpu_id;
97 v->vcpu_info = shared_info_addr(d, vcpu_info[vcpu_id]);
98 spin_lock_init(&v->pause_lock);
100 v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
101 v->runstate.state_entry_time = NOW();
103 if ( (vcpu_id != 0) && !is_idle_domain(d) )
104 set_bit(_VCPUF_down, &v->vcpu_flags);
106 if ( sched_init_vcpu(v, cpu_id) != 0 )
107 {
108 free_vcpu_struct(v);
109 return NULL;
110 }
112 if ( vcpu_initialise(v) != 0 )
113 {
114 sched_destroy_vcpu(v);
115 free_vcpu_struct(v);
116 return NULL;
117 }
119 d->vcpu[vcpu_id] = v;
120 if ( vcpu_id != 0 )
121 d->vcpu[v->vcpu_id-1]->next_in_list = v;
123 return v;
124 }
126 struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
127 {
128 struct domain *d;
129 struct vcpu *v;
130 unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
132 if ( (v = idle_vcpu[cpu_id]) != NULL )
133 return v;
135 d = (vcpu_id == 0) ?
136 domain_create(IDLE_DOMAIN_ID, 0) :
137 idle_vcpu[cpu_id - vcpu_id]->domain;
138 BUG_ON(d == NULL);
140 v = alloc_vcpu(d, vcpu_id, cpu_id);
141 idle_vcpu[cpu_id] = v;
143 return v;
144 }
146 struct domain *domain_create(domid_t domid, unsigned int domcr_flags)
147 {
148 struct domain *d, **pd;
150 if ( (d = alloc_domain(domid)) == NULL )
151 return NULL;
153 if ( domcr_flags & DOMCRF_hvm )
154 d->is_hvm = 1;
156 rangeset_domain_initialise(d);
158 if ( !is_idle_domain(d) )
159 {
160 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
161 if ( evtchn_init(d) != 0 )
162 goto fail1;
163 if ( grant_table_create(d) != 0 )
164 goto fail2;
165 }
167 if ( arch_domain_create(d) != 0 )
168 goto fail3;
170 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
171 d->irq_caps = rangeset_new(d, "Interrupts", 0);
172 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
173 goto fail4;
175 if ( sched_init_domain(d) != 0 )
176 goto fail4;
178 if ( !is_idle_domain(d) )
179 {
180 write_lock(&domlist_lock);
181 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
182 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
183 if ( (*pd)->domain_id > d->domain_id )
184 break;
185 d->next_in_list = *pd;
186 *pd = d;
187 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
188 domain_hash[DOMAIN_HASH(domid)] = d;
189 write_unlock(&domlist_lock);
190 }
192 return d;
194 fail4:
195 arch_domain_destroy(d);
196 fail3:
197 if ( !is_idle_domain(d) )
198 grant_table_destroy(d);
199 fail2:
200 if ( !is_idle_domain(d) )
201 evtchn_destroy(d);
202 fail1:
203 rangeset_domain_destroy(d);
204 free_domain(d);
205 return NULL;
206 }
209 struct domain *find_domain_by_id(domid_t dom)
210 {
211 struct domain *d;
213 read_lock(&domlist_lock);
214 d = domain_hash[DOMAIN_HASH(dom)];
215 while ( d != NULL )
216 {
217 if ( d->domain_id == dom )
218 {
219 if ( unlikely(!get_domain(d)) )
220 d = NULL;
221 break;
222 }
223 d = d->next_in_hashbucket;
224 }
225 read_unlock(&domlist_lock);
227 return d;
228 }
231 void domain_kill(struct domain *d)
232 {
233 domain_pause(d);
235 if ( test_and_set_bit(_DOMF_dying, &d->domain_flags) )
236 return;
238 gnttab_release_mappings(d);
239 domain_relinquish_resources(d);
240 put_domain(d);
242 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
243 }
246 void __domain_crash(struct domain *d)
247 {
248 if ( test_bit(_DOMF_shutdown, &d->domain_flags) )
249 {
250 /* Print nothing: the domain is already shutting down. */
251 }
252 else if ( d == current->domain )
253 {
254 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
255 d->domain_id, current->vcpu_id, smp_processor_id());
256 show_execution_state(guest_cpu_user_regs());
257 }
258 else
259 {
260 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
261 d->domain_id, current->domain->domain_id, smp_processor_id());
262 }
264 domain_shutdown(d, SHUTDOWN_crash);
265 }
268 void __domain_crash_synchronous(void)
269 {
270 __domain_crash(current->domain);
272 /*
273 * Flush multicall state before dying if a multicall is in progress.
274 * This shouldn't be necessary, but some architectures are calling
275 * domain_crash_synchronous() when they really shouldn't (i.e., from
276 * within hypercall context).
277 */
278 if ( this_cpu(mc_state).flags != 0 )
279 {
280 dprintk(XENLOG_ERR,
281 "FIXME: synchronous domain crash during a multicall!\n");
282 this_cpu(mc_state).flags = 0;
283 }
285 for ( ; ; )
286 do_softirq();
287 }
290 void domain_shutdown(struct domain *d, u8 reason)
291 {
292 struct vcpu *v;
294 if ( d->domain_id == 0 )
295 dom0_shutdown(reason);
297 if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
298 d->shutdown_code = reason;
300 for_each_vcpu ( d, v )
301 vcpu_sleep_nosync(v);
303 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
304 }
307 void domain_pause_for_debugger(void)
308 {
309 struct domain *d = current->domain;
310 struct vcpu *v;
312 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
314 for_each_vcpu ( d, v )
315 vcpu_sleep_nosync(v);
317 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
318 }
321 /* Release resources belonging to task @p. */
322 void domain_destroy(struct domain *d)
323 {
324 struct domain **pd;
325 atomic_t old, new;
327 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
329 /* May be already destroyed, or get_domain() can race us. */
330 _atomic_set(old, 0);
331 _atomic_set(new, DOMAIN_DESTROYED);
332 old = atomic_compareandswap(old, new, &d->refcnt);
333 if ( _atomic_read(old) != 0 )
334 return;
336 /* Delete from task list and task hashtable. */
337 write_lock(&domlist_lock);
338 pd = &domain_list;
339 while ( *pd != d )
340 pd = &(*pd)->next_in_list;
341 *pd = d->next_in_list;
342 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
343 while ( *pd != d )
344 pd = &(*pd)->next_in_hashbucket;
345 *pd = d->next_in_hashbucket;
346 write_unlock(&domlist_lock);
348 rangeset_domain_destroy(d);
350 evtchn_destroy(d);
351 grant_table_destroy(d);
353 arch_domain_destroy(d);
355 free_domain(d);
357 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
358 }
360 static void vcpu_pause_setup(struct vcpu *v)
361 {
362 spin_lock(&v->pause_lock);
363 if ( v->pause_count++ == 0 )
364 set_bit(_VCPUF_paused, &v->vcpu_flags);
365 spin_unlock(&v->pause_lock);
366 }
368 void vcpu_pause(struct vcpu *v)
369 {
370 ASSERT(v != current);
371 vcpu_pause_setup(v);
372 vcpu_sleep_sync(v);
373 }
375 void vcpu_pause_nosync(struct vcpu *v)
376 {
377 vcpu_pause_setup(v);
378 vcpu_sleep_nosync(v);
379 }
381 void vcpu_unpause(struct vcpu *v)
382 {
383 int wake;
385 ASSERT(v != current);
387 spin_lock(&v->pause_lock);
388 wake = (--v->pause_count == 0);
389 if ( wake )
390 clear_bit(_VCPUF_paused, &v->vcpu_flags);
391 spin_unlock(&v->pause_lock);
393 if ( wake )
394 vcpu_wake(v);
395 }
397 void domain_pause(struct domain *d)
398 {
399 struct vcpu *v;
401 ASSERT(d != current->domain);
403 spin_lock(&d->pause_lock);
404 if ( d->pause_count++ == 0 )
405 set_bit(_DOMF_paused, &d->domain_flags);
406 spin_unlock(&d->pause_lock);
408 for_each_vcpu( d, v )
409 vcpu_sleep_sync(v);
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 }
441 }
443 void domain_unpause_by_systemcontroller(struct domain *d)
444 {
445 struct vcpu *v;
447 if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
448 {
449 for_each_vcpu ( d, v )
450 vcpu_wake(v);
451 }
452 }
455 /*
456 * set_info_guest is used for final setup, launching, and state modification
457 * of domains other than domain 0. ie. the domains that are being built by
458 * the userspace dom0 domain builder.
459 */
460 int set_info_guest(struct domain *d,
461 xen_domctl_vcpucontext_u vcpucontext)
462 {
463 int rc = 0;
464 vcpu_guest_context_u c;
465 #ifdef CONFIG_COMPAT
466 CHECK_FIELD(domctl_vcpucontext, vcpu);
467 #endif
468 unsigned long vcpu = vcpucontext.nat->vcpu;
469 struct vcpu *v;
471 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
472 return -EINVAL;
474 if ( IS_COMPAT(v->domain)
475 ? compat_handle_is_null(vcpucontext.cmp->ctxt)
476 : guest_handle_is_null(vcpucontext.nat->ctxt) )
477 return vcpu_reset(v);
479 #ifdef CONFIG_COMPAT
480 BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
481 < sizeof(struct compat_vcpu_guest_context));
482 #endif
483 if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
484 return -ENOMEM;
486 domain_pause(d);
488 if ( !IS_COMPAT(v->domain) )
489 {
490 if ( !IS_COMPAT(current->domain)
491 ? copy_from_guest(c.nat, vcpucontext.nat->ctxt, 1)
492 #ifndef CONFIG_COMPAT
493 : 0 )
494 #else
495 : copy_from_guest(c.nat,
496 compat_handle_cast(vcpucontext.cmp->ctxt,
497 void),
498 1) )
499 #endif
500 rc = -EFAULT;
501 }
502 #ifdef CONFIG_COMPAT
503 else
504 {
505 if ( !IS_COMPAT(current->domain)
506 ? copy_from_guest(c.cmp,
507 guest_handle_cast(vcpucontext.nat->ctxt, void),
508 1)
509 : copy_from_compat(c.cmp, vcpucontext.cmp->ctxt, 1) )
510 rc = -EFAULT;
511 }
512 #endif
514 if ( rc == 0 )
515 rc = arch_set_info_guest(v, c);
517 domain_unpause(d);
519 xfree(c.nat);
520 return rc;
521 }
523 int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
524 {
525 struct vcpu *v = d->vcpu[vcpuid];
527 BUG_ON(test_bit(_VCPUF_initialised, &v->vcpu_flags));
529 return arch_set_info_guest(v, ctxt);
530 }
532 int vcpu_reset(struct vcpu *v)
533 {
534 struct domain *d = v->domain;
535 int rc;
537 domain_pause(d);
538 LOCK_BIGLOCK(d);
540 rc = arch_vcpu_reset(v);
541 if ( rc != 0 )
542 goto out;
544 set_bit(_VCPUF_down, &v->vcpu_flags);
546 clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
547 clear_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags);
548 clear_bit(_VCPUF_blocked, &v->vcpu_flags);
549 clear_bit(_VCPUF_initialised, &v->vcpu_flags);
550 clear_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
551 clear_bit(_VCPUF_nmi_masked, &v->vcpu_flags);
552 clear_bit(_VCPUF_polling, &v->vcpu_flags);
554 out:
555 UNLOCK_BIGLOCK(v->domain);
556 domain_unpause(d);
558 return rc;
559 }
562 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
563 {
564 struct domain *d = current->domain;
565 struct vcpu *v;
566 struct vcpu_guest_context *ctxt;
567 long rc = 0;
569 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
570 return -EINVAL;
572 if ( (v = d->vcpu[vcpuid]) == NULL )
573 return -ENOENT;
575 switch ( cmd )
576 {
577 case VCPUOP_initialise:
578 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
579 {
580 rc = -ENOMEM;
581 break;
582 }
584 if ( copy_from_guest(ctxt, arg, 1) )
585 {
586 xfree(ctxt);
587 rc = -EFAULT;
588 break;
589 }
591 LOCK_BIGLOCK(d);
592 rc = -EEXIST;
593 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
594 rc = boot_vcpu(d, vcpuid, ctxt);
595 UNLOCK_BIGLOCK(d);
597 xfree(ctxt);
598 break;
600 case VCPUOP_up:
601 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
602 rc = -EINVAL;
603 else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) )
604 vcpu_wake(v);
605 break;
607 case VCPUOP_down:
608 if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
609 vcpu_sleep_nosync(v);
610 break;
612 case VCPUOP_is_up:
613 rc = !test_bit(_VCPUF_down, &v->vcpu_flags);
614 break;
616 case VCPUOP_get_runstate_info:
617 {
618 struct vcpu_runstate_info runstate;
619 vcpu_runstate_get(v, &runstate);
620 if ( copy_to_guest(arg, &runstate, 1) )
621 rc = -EFAULT;
622 break;
623 }
625 default:
626 rc = arch_do_vcpu_op(cmd, v, arg);
627 break;
628 }
630 return rc;
631 }
633 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
634 {
635 if ( type > MAX_VMASST_TYPE )
636 return -EINVAL;
638 switch ( cmd )
639 {
640 case VMASST_CMD_enable:
641 set_bit(type, &p->vm_assist);
642 return 0;
643 case VMASST_CMD_disable:
644 clear_bit(type, &p->vm_assist);
645 return 0;
646 }
648 return -ENOSYS;
649 }
651 /*
652 * Local variables:
653 * mode: C
654 * c-set-style: "BSD"
655 * c-basic-offset: 4
656 * tab-width: 4
657 * indent-tabs-mode: nil
658 * End:
659 */