ia64/xen-unstable

view xen/common/domain.c @ 14697:9695cc13c48c

xen: Remove two incorrect assertions.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Mon Apr 02 16:26:23 2007 +0100 (2007-04-02)
parents 36ff129dbd8b
children a1b17c48fb40
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 <xen/rcupdate.h>
28 #include <asm/debugger.h>
29 #include <public/sched.h>
30 #include <public/vcpu.h>
32 /* Protect updates/reads (resp.) of domain_list and domain_hash. */
33 DEFINE_SPINLOCK(domlist_update_lock);
34 DEFINE_RCU_READ_LOCK(domlist_read_lock);
36 #define DOMAIN_HASH_SIZE 256
37 #define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
38 static struct domain *domain_hash[DOMAIN_HASH_SIZE];
39 struct domain *domain_list;
41 struct domain *dom0;
43 struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
45 int current_domain_id(void)
46 {
47 return current->domain->domain_id;
48 }
50 struct domain *alloc_domain(domid_t domid)
51 {
52 struct domain *d;
54 if ( (d = xmalloc(struct domain)) == NULL )
55 return NULL;
57 memset(d, 0, sizeof(*d));
58 d->domain_id = domid;
59 atomic_set(&d->refcnt, 1);
60 spin_lock_init(&d->big_lock);
61 spin_lock_init(&d->page_alloc_lock);
62 INIT_LIST_HEAD(&d->page_list);
63 INIT_LIST_HEAD(&d->xenpage_list);
65 return d;
66 }
68 void free_domain(struct domain *d)
69 {
70 struct vcpu *v;
71 int i;
73 for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
74 {
75 if ( (v = d->vcpu[i]) == NULL )
76 continue;
77 vcpu_destroy(v);
78 sched_destroy_vcpu(v);
79 free_vcpu_struct(v);
80 }
82 sched_destroy_domain(d);
83 xfree(d);
84 }
86 struct vcpu *alloc_vcpu(
87 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
88 {
89 struct vcpu *v;
91 BUG_ON(d->vcpu[vcpu_id] != NULL);
93 if ( (v = alloc_vcpu_struct()) == NULL )
94 return NULL;
96 v->domain = d;
97 v->vcpu_id = vcpu_id;
99 v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
100 v->runstate.state_entry_time = NOW();
102 if ( !is_idle_domain(d) )
103 {
104 set_bit(_VPF_down, &v->pause_flags);
105 v->vcpu_info = shared_info_addr(d, vcpu_info[vcpu_id]);
106 }
108 if ( sched_init_vcpu(v, cpu_id) != 0 )
109 {
110 free_vcpu_struct(v);
111 return NULL;
112 }
114 if ( vcpu_initialise(v) != 0 )
115 {
116 sched_destroy_vcpu(v);
117 free_vcpu_struct(v);
118 return NULL;
119 }
121 d->vcpu[vcpu_id] = v;
122 if ( vcpu_id != 0 )
123 d->vcpu[v->vcpu_id-1]->next_in_list = v;
125 return v;
126 }
128 struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
129 {
130 struct domain *d;
131 struct vcpu *v;
132 unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
134 if ( (v = idle_vcpu[cpu_id]) != NULL )
135 return v;
137 d = (vcpu_id == 0) ?
138 domain_create(IDLE_DOMAIN_ID, 0) :
139 idle_vcpu[cpu_id - vcpu_id]->domain;
140 BUG_ON(d == NULL);
142 v = alloc_vcpu(d, vcpu_id, cpu_id);
143 idle_vcpu[cpu_id] = v;
145 return v;
146 }
148 struct domain *domain_create(domid_t domid, unsigned int domcr_flags)
149 {
150 struct domain *d, **pd;
152 if ( (d = alloc_domain(domid)) == NULL )
153 return NULL;
155 if ( domcr_flags & DOMCRF_hvm )
156 d->is_hvm = 1;
158 rangeset_domain_initialise(d);
160 if ( !is_idle_domain(d) )
161 {
162 d->is_paused_by_controller = 1;
163 atomic_inc(&d->pause_count);
165 if ( evtchn_init(d) != 0 )
166 goto fail1;
168 if ( grant_table_create(d) != 0 )
169 goto fail2;
170 }
172 if ( arch_domain_create(d) != 0 )
173 goto fail3;
175 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
176 d->irq_caps = rangeset_new(d, "Interrupts", 0);
177 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
178 goto fail4;
180 if ( sched_init_domain(d) != 0 )
181 goto fail4;
183 if ( !is_idle_domain(d) )
184 {
185 spin_lock(&domlist_update_lock);
186 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
187 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
188 if ( (*pd)->domain_id > d->domain_id )
189 break;
190 d->next_in_list = *pd;
191 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
192 /* Two rcu assignments are not atomic
193 * Readers may see inconsistent domlist and hash table
194 * That is OK as long as each RCU reader-side critical section uses
195 * only one or them */
196 rcu_assign_pointer(*pd, d);
197 rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d);
198 spin_unlock(&domlist_update_lock);
199 }
201 return d;
203 fail4:
204 arch_domain_destroy(d);
205 fail3:
206 if ( !is_idle_domain(d) )
207 grant_table_destroy(d);
208 fail2:
209 if ( !is_idle_domain(d) )
210 evtchn_destroy(d);
211 fail1:
212 rangeset_domain_destroy(d);
213 free_domain(d);
214 return NULL;
215 }
218 struct domain *get_domain_by_id(domid_t dom)
219 {
220 struct domain *d;
222 rcu_read_lock(&domlist_read_lock);
224 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
225 d != NULL;
226 d = rcu_dereference(d->next_in_hashbucket) )
227 {
228 if ( d->domain_id == dom )
229 {
230 if ( unlikely(!get_domain(d)) )
231 d = NULL;
232 break;
233 }
234 }
236 rcu_read_unlock(&domlist_read_lock);
238 return d;
239 }
242 struct domain *rcu_lock_domain_by_id(domid_t dom)
243 {
244 struct domain *d;
246 rcu_read_lock(&domlist_read_lock);
248 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
249 d != NULL;
250 d = rcu_dereference(d->next_in_hashbucket) )
251 {
252 if ( d->domain_id == dom )
253 return d;
254 }
256 rcu_read_unlock(&domlist_read_lock);
258 return NULL;
259 }
262 void domain_kill(struct domain *d)
263 {
264 domain_pause(d);
266 /* Already dying? Then bail. */
267 if ( xchg(&d->is_dying, 1) )
268 {
269 domain_unpause(d);
270 return;
271 }
273 /* Tear down state /after/ setting the dying flag. */
274 smp_wmb();
276 gnttab_release_mappings(d);
277 domain_relinquish_resources(d);
278 put_domain(d);
280 /* Kick page scrubbing after domain_relinquish_resources(). */
281 page_scrub_kick();
283 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
284 }
287 void __domain_crash(struct domain *d)
288 {
289 if ( d->is_shutdown )
290 {
291 /* Print nothing: the domain is already shutting down. */
292 }
293 else if ( d == current->domain )
294 {
295 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
296 d->domain_id, current->vcpu_id, smp_processor_id());
297 show_execution_state(guest_cpu_user_regs());
298 }
299 else
300 {
301 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
302 d->domain_id, current->domain->domain_id, smp_processor_id());
303 }
305 domain_shutdown(d, SHUTDOWN_crash);
306 }
309 void __domain_crash_synchronous(void)
310 {
311 __domain_crash(current->domain);
313 /*
314 * Flush multicall state before dying if a multicall is in progress.
315 * This shouldn't be necessary, but some architectures are calling
316 * domain_crash_synchronous() when they really shouldn't (i.e., from
317 * within hypercall context).
318 */
319 if ( this_cpu(mc_state).flags != 0 )
320 {
321 dprintk(XENLOG_ERR,
322 "FIXME: synchronous domain crash during a multicall!\n");
323 this_cpu(mc_state).flags = 0;
324 }
326 for ( ; ; )
327 do_softirq();
328 }
331 void domain_shutdown(struct domain *d, u8 reason)
332 {
333 struct vcpu *v;
335 if ( d->domain_id == 0 )
336 dom0_shutdown(reason);
338 atomic_inc(&d->pause_count);
339 if ( !xchg(&d->is_shutdown, 1) )
340 d->shutdown_code = reason;
341 else
342 domain_unpause(d);
344 for_each_vcpu ( d, v )
345 vcpu_sleep_nosync(v);
347 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
348 }
350 void domain_pause_for_debugger(void)
351 {
352 struct domain *d = current->domain;
353 struct vcpu *v;
355 atomic_inc(&d->pause_count);
356 if ( xchg(&d->is_paused_by_controller, 1) )
357 domain_unpause(d); /* race-free atomic_dec(&d->pause_count) */
359 for_each_vcpu ( d, v )
360 vcpu_sleep_nosync(v);
362 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
363 }
365 /* Complete domain destroy after RCU readers are not holding old references. */
366 static void complete_domain_destroy(struct rcu_head *head)
367 {
368 struct domain *d = container_of(head, struct domain, rcu);
370 rangeset_domain_destroy(d);
372 evtchn_destroy(d);
373 grant_table_destroy(d);
375 arch_domain_destroy(d);
377 free_domain(d);
379 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
380 }
382 /* Release resources belonging to task @p. */
383 void domain_destroy(struct domain *d)
384 {
385 struct domain **pd;
386 atomic_t old, new;
388 BUG_ON(!d->is_dying);
390 /* May be already destroyed, or get_domain() can race us. */
391 _atomic_set(old, 0);
392 _atomic_set(new, DOMAIN_DESTROYED);
393 old = atomic_compareandswap(old, new, &d->refcnt);
394 if ( _atomic_read(old) != 0 )
395 return;
397 /* Delete from task list and task hashtable. */
398 spin_lock(&domlist_update_lock);
399 pd = &domain_list;
400 while ( *pd != d )
401 pd = &(*pd)->next_in_list;
402 rcu_assign_pointer(*pd, d->next_in_list);
403 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
404 while ( *pd != d )
405 pd = &(*pd)->next_in_hashbucket;
406 rcu_assign_pointer(*pd, d->next_in_hashbucket);
407 spin_unlock(&domlist_update_lock);
409 /* Schedule RCU asynchronous completion of domain destroy. */
410 call_rcu(&d->rcu, complete_domain_destroy);
411 }
413 void vcpu_pause(struct vcpu *v)
414 {
415 ASSERT(v != current);
416 atomic_inc(&v->pause_count);
417 vcpu_sleep_sync(v);
418 }
420 void vcpu_pause_nosync(struct vcpu *v)
421 {
422 atomic_inc(&v->pause_count);
423 vcpu_sleep_nosync(v);
424 }
426 void vcpu_unpause(struct vcpu *v)
427 {
428 if ( atomic_dec_and_test(&v->pause_count) )
429 vcpu_wake(v);
430 }
432 void domain_pause(struct domain *d)
433 {
434 struct vcpu *v;
436 ASSERT(d != current->domain);
438 atomic_inc(&d->pause_count);
440 for_each_vcpu( d, v )
441 vcpu_sleep_sync(v);
442 }
444 void domain_unpause(struct domain *d)
445 {
446 struct vcpu *v;
448 if ( atomic_dec_and_test(&d->pause_count) )
449 for_each_vcpu( d, v )
450 vcpu_wake(v);
451 }
453 void domain_pause_by_systemcontroller(struct domain *d)
454 {
455 domain_pause(d);
456 if ( xchg(&d->is_paused_by_controller, 1) )
457 domain_unpause(d);
458 }
460 void domain_unpause_by_systemcontroller(struct domain *d)
461 {
462 if ( xchg(&d->is_paused_by_controller, 0) )
463 domain_unpause(d);
464 }
466 int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
467 {
468 struct vcpu *v = d->vcpu[vcpuid];
470 BUG_ON(v->is_initialised);
472 return arch_set_info_guest(v, ctxt);
473 }
475 int vcpu_reset(struct vcpu *v)
476 {
477 struct domain *d = v->domain;
478 int rc;
480 domain_pause(d);
481 LOCK_BIGLOCK(d);
483 rc = arch_vcpu_reset(v);
484 if ( rc != 0 )
485 goto out;
487 set_bit(_VPF_down, &v->pause_flags);
489 v->fpu_initialised = 0;
490 v->fpu_dirtied = 0;
491 v->is_polling = 0;
492 v->is_initialised = 0;
493 v->nmi_pending = 0;
494 v->nmi_masked = 0;
495 clear_bit(_VPF_blocked, &v->pause_flags);
497 out:
498 UNLOCK_BIGLOCK(v->domain);
499 domain_unpause(d);
501 return rc;
502 }
505 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
506 {
507 struct domain *d = current->domain;
508 struct vcpu *v;
509 struct vcpu_guest_context *ctxt;
510 long rc = 0;
512 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
513 return -EINVAL;
515 if ( (v = d->vcpu[vcpuid]) == NULL )
516 return -ENOENT;
518 switch ( cmd )
519 {
520 case VCPUOP_initialise:
521 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
522 return -ENOMEM;
524 if ( copy_from_guest(ctxt, arg, 1) )
525 {
526 xfree(ctxt);
527 return -EFAULT;
528 }
530 LOCK_BIGLOCK(d);
531 rc = -EEXIST;
532 if ( !v->is_initialised )
533 rc = boot_vcpu(d, vcpuid, ctxt);
534 UNLOCK_BIGLOCK(d);
536 xfree(ctxt);
537 break;
539 case VCPUOP_up:
540 if ( !v->is_initialised )
541 return -EINVAL;
543 if ( test_and_clear_bit(_VPF_down, &v->pause_flags) )
544 vcpu_wake(v);
546 break;
548 case VCPUOP_down:
549 if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
550 vcpu_sleep_nosync(v);
551 break;
553 case VCPUOP_is_up:
554 rc = !test_bit(_VPF_down, &v->pause_flags);
555 break;
557 case VCPUOP_get_runstate_info:
558 {
559 struct vcpu_runstate_info runstate;
560 vcpu_runstate_get(v, &runstate);
561 if ( copy_to_guest(arg, &runstate, 1) )
562 rc = -EFAULT;
563 break;
564 }
566 case VCPUOP_set_periodic_timer:
567 {
568 struct vcpu_set_periodic_timer set;
570 if ( copy_from_guest(&set, arg, 1) )
571 return -EFAULT;
573 if ( set.period_ns < MILLISECS(1) )
574 return -EINVAL;
576 v->periodic_period = set.period_ns;
577 vcpu_force_reschedule(v);
579 break;
580 }
582 case VCPUOP_stop_periodic_timer:
583 {
584 v->periodic_period = 0;
585 vcpu_force_reschedule(v);
586 break;
587 }
589 case VCPUOP_set_singleshot_timer:
590 {
591 struct vcpu_set_singleshot_timer set;
593 if ( v != current )
594 return -EINVAL;
596 if ( copy_from_guest(&set, arg, 1) )
597 return -EFAULT;
599 if ( (set.flags & VCPU_SSHOTTMR_future) &&
600 (set.timeout_abs_ns < NOW()) )
601 return -ETIME;
603 if ( v->singleshot_timer.cpu != smp_processor_id() )
604 {
605 stop_timer(&v->singleshot_timer);
606 v->singleshot_timer.cpu = smp_processor_id();
607 }
609 set_timer(&v->singleshot_timer, set.timeout_abs_ns);
611 break;
612 }
614 case VCPUOP_stop_singleshot_timer:
615 {
616 if ( v != current )
617 return -EINVAL;
619 stop_timer(&v->singleshot_timer);
620 break;
621 }
623 default:
624 rc = arch_do_vcpu_op(cmd, v, arg);
625 break;
626 }
628 return rc;
629 }
631 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
632 {
633 if ( type > MAX_VMASST_TYPE )
634 return -EINVAL;
636 switch ( cmd )
637 {
638 case VMASST_CMD_enable:
639 set_bit(type, &p->vm_assist);
640 return 0;
641 case VMASST_CMD_disable:
642 clear_bit(type, &p->vm_assist);
643 return 0;
644 }
646 return -ENOSYS;
647 }
649 /*
650 * Local variables:
651 * mode: C
652 * c-set-style: "BSD"
653 * c-basic-offset: 4
654 * tab-width: 4
655 * indent-tabs-mode: nil
656 * End:
657 */