ia64/xen-unstable

view xen/common/domain.c @ 15717:c229802cedbb

[32on64] Copy the right grant table status code back to the guest.

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
author Ian Campbell <ian.campbell@xensource.com>
date Mon Aug 06 13:19:44 2007 +0100 (2007-08-06)
parents 9fa9346e1c70
children 96f64f4c42f0
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>
31 #include <acm/acm_hooks.h>
33 /* Protect updates/reads (resp.) of domain_list and domain_hash. */
34 DEFINE_SPINLOCK(domlist_update_lock);
35 DEFINE_RCU_READ_LOCK(domlist_read_lock);
37 #define DOMAIN_HASH_SIZE 256
38 #define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
39 static struct domain *domain_hash[DOMAIN_HASH_SIZE];
40 struct domain *domain_list;
42 struct domain *dom0;
44 struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
46 int current_domain_id(void)
47 {
48 return current->domain->domain_id;
49 }
51 struct domain *alloc_domain(domid_t domid)
52 {
53 struct domain *d;
55 if ( (d = xmalloc(struct domain)) == NULL )
56 return NULL;
58 memset(d, 0, sizeof(*d));
59 d->domain_id = domid;
60 atomic_set(&d->refcnt, 1);
61 spin_lock_init(&d->big_lock);
62 spin_lock_init(&d->page_alloc_lock);
63 spin_lock_init(&d->shutdown_lock);
64 INIT_LIST_HEAD(&d->page_list);
65 INIT_LIST_HEAD(&d->xenpage_list);
67 return d;
68 }
70 void free_domain(struct domain *d)
71 {
72 xfree(d);
73 }
75 static void __domain_finalise_shutdown(struct domain *d)
76 {
77 struct vcpu *v;
79 BUG_ON(!spin_is_locked(&d->shutdown_lock));
81 if ( d->is_shut_down )
82 return;
84 for_each_vcpu ( d, v )
85 if ( !v->paused_for_shutdown )
86 return;
88 d->is_shut_down = 1;
90 for_each_vcpu ( d, v )
91 vcpu_sleep_nosync(v);
93 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
94 }
96 static void vcpu_check_shutdown(struct vcpu *v)
97 {
98 struct domain *d = v->domain;
100 spin_lock(&d->shutdown_lock);
102 if ( d->is_shutting_down )
103 {
104 if ( !v->paused_for_shutdown )
105 atomic_inc(&v->pause_count);
106 v->paused_for_shutdown = 1;
107 v->defer_shutdown = 0;
108 __domain_finalise_shutdown(d);
109 }
111 spin_unlock(&d->shutdown_lock);
112 }
114 struct vcpu *alloc_vcpu(
115 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
116 {
117 struct vcpu *v;
119 BUG_ON(d->vcpu[vcpu_id] != NULL);
121 if ( (v = alloc_vcpu_struct()) == NULL )
122 return NULL;
124 v->domain = d;
125 v->vcpu_id = vcpu_id;
127 v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
128 v->runstate.state_entry_time = NOW();
130 if ( !is_idle_domain(d) )
131 {
132 set_bit(_VPF_down, &v->pause_flags);
133 v->vcpu_info = shared_info_addr(d, vcpu_info[vcpu_id]);
134 }
136 if ( sched_init_vcpu(v, cpu_id) != 0 )
137 {
138 free_vcpu_struct(v);
139 return NULL;
140 }
142 if ( vcpu_initialise(v) != 0 )
143 {
144 sched_destroy_vcpu(v);
145 free_vcpu_struct(v);
146 return NULL;
147 }
149 d->vcpu[vcpu_id] = v;
150 if ( vcpu_id != 0 )
151 d->vcpu[v->vcpu_id-1]->next_in_list = v;
153 /* Must be called after making new vcpu visible to for_each_vcpu(). */
154 vcpu_check_shutdown(v);
156 return v;
157 }
159 struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
160 {
161 struct domain *d;
162 struct vcpu *v;
163 unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
165 if ( (v = idle_vcpu[cpu_id]) != NULL )
166 return v;
168 d = (vcpu_id == 0) ?
169 domain_create(IDLE_DOMAIN_ID, 0, 0) :
170 idle_vcpu[cpu_id - vcpu_id]->domain;
171 BUG_ON(d == NULL);
173 v = alloc_vcpu(d, vcpu_id, cpu_id);
174 idle_vcpu[cpu_id] = v;
176 return v;
177 }
179 struct domain *domain_create(
180 domid_t domid, unsigned int domcr_flags, ssidref_t ssidref)
181 {
182 struct domain *d, **pd;
183 enum { INIT_evtchn = 1, INIT_gnttab = 2, INIT_acm = 4, INIT_arch = 8 };
184 int init_status = 0;
186 if ( (d = alloc_domain(domid)) == NULL )
187 return NULL;
189 if ( domcr_flags & DOMCRF_hvm )
190 d->is_hvm = 1;
192 rangeset_domain_initialise(d);
194 if ( !is_idle_domain(d) )
195 {
196 d->is_paused_by_controller = 1;
197 atomic_inc(&d->pause_count);
199 if ( evtchn_init(d) != 0 )
200 goto fail;
201 init_status |= INIT_evtchn;
203 if ( grant_table_create(d) != 0 )
204 goto fail;
205 init_status |= INIT_gnttab;
207 if ( acm_domain_create(d, ssidref) != 0 )
208 goto fail;
209 init_status |= INIT_acm;
210 }
212 if ( arch_domain_create(d) != 0 )
213 goto fail;
214 init_status |= INIT_arch;
216 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
217 d->irq_caps = rangeset_new(d, "Interrupts", 0);
218 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
219 goto fail;
221 if ( sched_init_domain(d) != 0 )
222 goto fail;
224 if ( !is_idle_domain(d) )
225 {
226 spin_lock(&domlist_update_lock);
227 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
228 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
229 if ( (*pd)->domain_id > d->domain_id )
230 break;
231 d->next_in_list = *pd;
232 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
233 rcu_assign_pointer(*pd, d);
234 rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d);
235 spin_unlock(&domlist_update_lock);
236 }
238 return d;
240 fail:
241 d->is_dying = 1;
242 atomic_set(&d->refcnt, DOMAIN_DESTROYED);
243 if ( init_status & INIT_arch )
244 arch_domain_destroy(d);
245 if ( init_status & INIT_acm )
246 acm_domain_destroy(d);
247 if ( init_status & INIT_gnttab )
248 grant_table_destroy(d);
249 if ( init_status & INIT_evtchn )
250 evtchn_destroy(d);
251 rangeset_domain_destroy(d);
252 free_domain(d);
253 return NULL;
254 }
257 struct domain *get_domain_by_id(domid_t dom)
258 {
259 struct domain *d;
261 rcu_read_lock(&domlist_read_lock);
263 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
264 d != NULL;
265 d = rcu_dereference(d->next_in_hashbucket) )
266 {
267 if ( d->domain_id == dom )
268 {
269 if ( unlikely(!get_domain(d)) )
270 d = NULL;
271 break;
272 }
273 }
275 rcu_read_unlock(&domlist_read_lock);
277 return d;
278 }
281 struct domain *rcu_lock_domain_by_id(domid_t dom)
282 {
283 struct domain *d;
285 rcu_read_lock(&domlist_read_lock);
287 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
288 d != NULL;
289 d = rcu_dereference(d->next_in_hashbucket) )
290 {
291 if ( d->domain_id == dom )
292 return d;
293 }
295 rcu_read_unlock(&domlist_read_lock);
297 return NULL;
298 }
301 void domain_kill(struct domain *d)
302 {
303 domain_pause(d);
305 /* Already dying? Then bail. */
306 if ( test_and_set_bool(d->is_dying) )
307 {
308 domain_unpause(d);
309 return;
310 }
312 evtchn_destroy(d);
313 gnttab_release_mappings(d);
314 domain_relinquish_resources(d);
315 put_domain(d);
317 /* Kick page scrubbing after domain_relinquish_resources(). */
318 page_scrub_kick();
320 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
321 }
324 void __domain_crash(struct domain *d)
325 {
326 if ( d->is_shutting_down )
327 {
328 /* Print nothing: the domain is already shutting down. */
329 }
330 else if ( d == current->domain )
331 {
332 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
333 d->domain_id, current->vcpu_id, smp_processor_id());
334 show_execution_state(guest_cpu_user_regs());
335 }
336 else
337 {
338 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
339 d->domain_id, current->domain->domain_id, smp_processor_id());
340 }
342 domain_shutdown(d, SHUTDOWN_crash);
343 }
346 void __domain_crash_synchronous(void)
347 {
348 __domain_crash(current->domain);
350 /*
351 * Flush multicall state before dying if a multicall is in progress.
352 * This shouldn't be necessary, but some architectures are calling
353 * domain_crash_synchronous() when they really shouldn't (i.e., from
354 * within hypercall context).
355 */
356 if ( this_cpu(mc_state).flags != 0 )
357 {
358 dprintk(XENLOG_ERR,
359 "FIXME: synchronous domain crash during a multicall!\n");
360 this_cpu(mc_state).flags = 0;
361 }
363 for ( ; ; )
364 do_softirq();
365 }
368 void domain_shutdown(struct domain *d, u8 reason)
369 {
370 struct vcpu *v;
372 if ( d->domain_id == 0 )
373 dom0_shutdown(reason);
375 spin_lock(&d->shutdown_lock);
377 if ( d->is_shutting_down )
378 {
379 spin_unlock(&d->shutdown_lock);
380 return;
381 }
383 d->is_shutting_down = 1;
384 d->shutdown_code = reason;
386 smp_mb(); /* set shutdown status /then/ check for per-cpu deferrals */
388 for_each_vcpu ( d, v )
389 {
390 if ( v->defer_shutdown )
391 continue;
392 atomic_inc(&v->pause_count);
393 v->paused_for_shutdown = 1;
394 }
396 __domain_finalise_shutdown(d);
398 spin_unlock(&d->shutdown_lock);
399 }
401 void domain_resume(struct domain *d)
402 {
403 struct vcpu *v;
405 /*
406 * Some code paths assume that shutdown status does not get reset under
407 * their feet (e.g., some assertions make this assumption).
408 */
409 domain_pause(d);
411 spin_lock(&d->shutdown_lock);
413 d->is_shutting_down = d->is_shut_down = 0;
415 for_each_vcpu ( d, v )
416 {
417 if ( v->paused_for_shutdown )
418 vcpu_unpause(v);
419 v->paused_for_shutdown = 0;
420 }
422 spin_unlock(&d->shutdown_lock);
424 domain_unpause(d);
425 }
427 int vcpu_start_shutdown_deferral(struct vcpu *v)
428 {
429 v->defer_shutdown = 1;
430 smp_mb(); /* set deferral status /then/ check for shutdown */
431 if ( unlikely(v->domain->is_shutting_down) )
432 vcpu_check_shutdown(v);
433 return v->defer_shutdown;
434 }
436 void vcpu_end_shutdown_deferral(struct vcpu *v)
437 {
438 v->defer_shutdown = 0;
439 smp_mb(); /* clear deferral status /then/ check for shutdown */
440 if ( unlikely(v->domain->is_shutting_down) )
441 vcpu_check_shutdown(v);
442 }
444 void domain_pause_for_debugger(void)
445 {
446 struct domain *d = current->domain;
447 struct vcpu *v;
449 atomic_inc(&d->pause_count);
450 if ( test_and_set_bool(d->is_paused_by_controller) )
451 domain_unpause(d); /* race-free atomic_dec(&d->pause_count) */
453 for_each_vcpu ( d, v )
454 vcpu_sleep_nosync(v);
456 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
457 }
459 /* Complete domain destroy after RCU readers are not holding old references. */
460 static void complete_domain_destroy(struct rcu_head *head)
461 {
462 struct domain *d = container_of(head, struct domain, rcu);
463 struct vcpu *v;
464 int i;
466 for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
467 {
468 if ( (v = d->vcpu[i]) == NULL )
469 continue;
470 vcpu_destroy(v);
471 sched_destroy_vcpu(v);
472 }
474 acm_domain_destroy(d);
476 rangeset_domain_destroy(d);
478 grant_table_destroy(d);
480 arch_domain_destroy(d);
482 sched_destroy_domain(d);
484 for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
485 if ( (v = d->vcpu[i]) != NULL )
486 free_vcpu_struct(v);
488 free_domain(d);
490 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
491 }
493 /* Release resources belonging to task @p. */
494 void domain_destroy(struct domain *d)
495 {
496 struct domain **pd;
497 atomic_t old, new;
499 BUG_ON(!d->is_dying);
501 /* May be already destroyed, or get_domain() can race us. */
502 _atomic_set(old, 0);
503 _atomic_set(new, DOMAIN_DESTROYED);
504 old = atomic_compareandswap(old, new, &d->refcnt);
505 if ( _atomic_read(old) != 0 )
506 return;
508 /* Delete from task list and task hashtable. */
509 spin_lock(&domlist_update_lock);
510 pd = &domain_list;
511 while ( *pd != d )
512 pd = &(*pd)->next_in_list;
513 rcu_assign_pointer(*pd, d->next_in_list);
514 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
515 while ( *pd != d )
516 pd = &(*pd)->next_in_hashbucket;
517 rcu_assign_pointer(*pd, d->next_in_hashbucket);
518 spin_unlock(&domlist_update_lock);
520 /* Schedule RCU asynchronous completion of domain destroy. */
521 call_rcu(&d->rcu, complete_domain_destroy);
522 }
524 void vcpu_pause(struct vcpu *v)
525 {
526 ASSERT(v != current);
527 atomic_inc(&v->pause_count);
528 vcpu_sleep_sync(v);
529 }
531 void vcpu_pause_nosync(struct vcpu *v)
532 {
533 atomic_inc(&v->pause_count);
534 vcpu_sleep_nosync(v);
535 }
537 void vcpu_unpause(struct vcpu *v)
538 {
539 if ( atomic_dec_and_test(&v->pause_count) )
540 vcpu_wake(v);
541 }
543 void domain_pause(struct domain *d)
544 {
545 struct vcpu *v;
547 ASSERT(d != current->domain);
549 atomic_inc(&d->pause_count);
551 for_each_vcpu( d, v )
552 vcpu_sleep_sync(v);
553 }
555 void domain_unpause(struct domain *d)
556 {
557 struct vcpu *v;
559 if ( atomic_dec_and_test(&d->pause_count) )
560 for_each_vcpu( d, v )
561 vcpu_wake(v);
562 }
564 void domain_pause_by_systemcontroller(struct domain *d)
565 {
566 domain_pause(d);
567 if ( test_and_set_bool(d->is_paused_by_controller) )
568 domain_unpause(d);
569 }
571 void domain_unpause_by_systemcontroller(struct domain *d)
572 {
573 if ( test_and_clear_bool(d->is_paused_by_controller) )
574 domain_unpause(d);
575 }
577 int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
578 {
579 struct vcpu *v = d->vcpu[vcpuid];
581 BUG_ON(v->is_initialised);
583 return arch_set_info_guest(v, ctxt);
584 }
586 int vcpu_reset(struct vcpu *v)
587 {
588 struct domain *d = v->domain;
589 int rc;
591 domain_pause(d);
592 LOCK_BIGLOCK(d);
594 rc = arch_vcpu_reset(v);
595 if ( rc != 0 )
596 goto out;
598 set_bit(_VPF_down, &v->pause_flags);
600 v->fpu_initialised = 0;
601 v->fpu_dirtied = 0;
602 v->is_polling = 0;
603 v->is_initialised = 0;
604 v->nmi_pending = 0;
605 v->nmi_masked = 0;
606 clear_bit(_VPF_blocked, &v->pause_flags);
608 out:
609 UNLOCK_BIGLOCK(v->domain);
610 domain_unpause(d);
612 return rc;
613 }
616 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
617 {
618 struct domain *d = current->domain;
619 struct vcpu *v;
620 struct vcpu_guest_context *ctxt;
621 long rc = 0;
623 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
624 return -EINVAL;
626 if ( (v = d->vcpu[vcpuid]) == NULL )
627 return -ENOENT;
629 switch ( cmd )
630 {
631 case VCPUOP_initialise:
632 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
633 return -ENOMEM;
635 if ( copy_from_guest(ctxt, arg, 1) )
636 {
637 xfree(ctxt);
638 return -EFAULT;
639 }
641 LOCK_BIGLOCK(d);
642 rc = -EEXIST;
643 if ( !v->is_initialised )
644 rc = boot_vcpu(d, vcpuid, ctxt);
645 UNLOCK_BIGLOCK(d);
647 xfree(ctxt);
648 break;
650 case VCPUOP_up:
651 if ( !v->is_initialised )
652 return -EINVAL;
654 if ( test_and_clear_bit(_VPF_down, &v->pause_flags) )
655 vcpu_wake(v);
657 break;
659 case VCPUOP_down:
660 if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
661 vcpu_sleep_nosync(v);
662 break;
664 case VCPUOP_is_up:
665 rc = !test_bit(_VPF_down, &v->pause_flags);
666 break;
668 case VCPUOP_get_runstate_info:
669 {
670 struct vcpu_runstate_info runstate;
671 vcpu_runstate_get(v, &runstate);
672 if ( copy_to_guest(arg, &runstate, 1) )
673 rc = -EFAULT;
674 break;
675 }
677 case VCPUOP_set_periodic_timer:
678 {
679 struct vcpu_set_periodic_timer set;
681 if ( copy_from_guest(&set, arg, 1) )
682 return -EFAULT;
684 if ( set.period_ns < MILLISECS(1) )
685 return -EINVAL;
687 v->periodic_period = set.period_ns;
688 vcpu_force_reschedule(v);
690 break;
691 }
693 case VCPUOP_stop_periodic_timer:
694 {
695 v->periodic_period = 0;
696 vcpu_force_reschedule(v);
697 break;
698 }
700 case VCPUOP_set_singleshot_timer:
701 {
702 struct vcpu_set_singleshot_timer set;
704 if ( v != current )
705 return -EINVAL;
707 if ( copy_from_guest(&set, arg, 1) )
708 return -EFAULT;
710 if ( (set.flags & VCPU_SSHOTTMR_future) &&
711 (set.timeout_abs_ns < NOW()) )
712 return -ETIME;
714 if ( v->singleshot_timer.cpu != smp_processor_id() )
715 {
716 stop_timer(&v->singleshot_timer);
717 v->singleshot_timer.cpu = smp_processor_id();
718 }
720 set_timer(&v->singleshot_timer, set.timeout_abs_ns);
722 break;
723 }
725 case VCPUOP_stop_singleshot_timer:
726 {
727 if ( v != current )
728 return -EINVAL;
730 stop_timer(&v->singleshot_timer);
731 break;
732 }
734 default:
735 rc = arch_do_vcpu_op(cmd, v, arg);
736 break;
737 }
739 return rc;
740 }
742 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
743 {
744 if ( type > MAX_VMASST_TYPE )
745 return -EINVAL;
747 switch ( cmd )
748 {
749 case VMASST_CMD_enable:
750 set_bit(type, &p->vm_assist);
751 return 0;
752 case VMASST_CMD_disable:
753 clear_bit(type, &p->vm_assist);
754 return 0;
755 }
757 return -ENOSYS;
758 }
760 /*
761 * Local variables:
762 * mode: C
763 * c-set-style: "BSD"
764 * c-basic-offset: 4
765 * tab-width: 4
766 * indent-tabs-mode: nil
767 * End:
768 */