ia64/xen-unstable

view xen/common/domain.c @ 9024:d0b7281556f2

New VCPUOP_register_runstate_memory_area hypercall. Avoids
need for a hypercall in the guest timer interrupt handler.

Cleaned up stolen/blocked tick handling in Linux.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Feb 25 21:28:27 2006 +0100 (2006-02-25)
parents 2303fb4682e7
children 621d32a54e2d
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 <asm/debugger.h>
21 #include <public/dom0_ops.h>
22 #include <public/sched.h>
23 #include <public/vcpu.h>
25 /* Both these structures are protected by the domlist_lock. */
26 rwlock_t domlist_lock = RW_LOCK_UNLOCKED;
27 struct domain *domain_hash[DOMAIN_HASH_SIZE];
28 struct domain *domain_list;
30 struct domain *dom0;
32 struct domain *domain_create(domid_t dom_id, unsigned int cpu)
33 {
34 struct domain *d, **pd;
35 struct vcpu *v;
37 if ( (d = alloc_domain()) == NULL )
38 return NULL;
40 d->domain_id = dom_id;
42 atomic_set(&d->refcnt, 1);
44 spin_lock_init(&d->big_lock);
45 spin_lock_init(&d->page_alloc_lock);
46 INIT_LIST_HEAD(&d->page_list);
47 INIT_LIST_HEAD(&d->xenpage_list);
49 rangeset_domain_initialise(d);
51 if ( !is_idle_domain(d) )
52 {
53 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
54 if ( evtchn_init(d) != 0 )
55 goto fail1;
56 if ( grant_table_create(d) != 0 )
57 goto fail2;
58 }
60 if ( arch_domain_create(d) != 0 )
61 goto fail3;
63 if ( (v = alloc_vcpu(d, 0, cpu)) == NULL )
64 goto fail4;
66 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
67 d->irq_caps = rangeset_new(d, "Interrupts", 0);
68 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
69 goto fail4; /* NB. alloc_vcpu() is undone in free_domain() */
71 if ( !is_idle_domain(d) )
72 {
73 write_lock(&domlist_lock);
74 pd = &domain_list; /* NB. domain_list maintained in order of dom_id. */
75 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
76 if ( (*pd)->domain_id > d->domain_id )
77 break;
78 d->next_in_list = *pd;
79 *pd = d;
80 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(dom_id)];
81 domain_hash[DOMAIN_HASH(dom_id)] = d;
82 write_unlock(&domlist_lock);
83 }
85 return d;
87 fail4:
88 arch_domain_destroy(d);
89 fail3:
90 if ( !is_idle_domain(d) )
91 grant_table_destroy(d);
92 fail2:
93 if ( !is_idle_domain(d) )
94 evtchn_destroy(d);
95 fail1:
96 rangeset_domain_destroy(d);
97 free_domain(d);
98 return NULL;
99 }
102 struct domain *find_domain_by_id(domid_t dom)
103 {
104 struct domain *d;
106 read_lock(&domlist_lock);
107 d = domain_hash[DOMAIN_HASH(dom)];
108 while ( d != NULL )
109 {
110 if ( d->domain_id == dom )
111 {
112 if ( unlikely(!get_domain(d)) )
113 d = NULL;
114 break;
115 }
116 d = d->next_in_hashbucket;
117 }
118 read_unlock(&domlist_lock);
120 return d;
121 }
124 void domain_kill(struct domain *d)
125 {
126 struct vcpu *v;
128 domain_pause(d);
129 if ( !test_and_set_bit(_DOMF_dying, &d->domain_flags) )
130 {
131 for_each_vcpu(d, v)
132 sched_rem_domain(v);
133 gnttab_release_mappings(d);
134 domain_relinquish_resources(d);
135 put_domain(d);
137 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
138 }
139 }
142 void __domain_crash(struct domain *d)
143 {
144 if ( d == current->domain )
145 {
146 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
147 d->domain_id, current->vcpu_id, smp_processor_id());
148 show_registers(guest_cpu_user_regs());
149 }
150 else
151 {
152 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
153 d->domain_id, current->domain->domain_id, smp_processor_id());
154 }
156 domain_shutdown(d, SHUTDOWN_crash);
157 }
160 void __domain_crash_synchronous(void)
161 {
162 __domain_crash(current->domain);
163 for ( ; ; )
164 do_softirq();
165 }
168 static struct domain *domain_shuttingdown[NR_CPUS];
170 static void domain_shutdown_finalise(void)
171 {
172 struct domain *d;
173 struct vcpu *v;
175 d = domain_shuttingdown[smp_processor_id()];
176 domain_shuttingdown[smp_processor_id()] = NULL;
178 BUG_ON(d == NULL);
179 BUG_ON(d == current->domain);
181 LOCK_BIGLOCK(d);
183 /* Make sure that every vcpu is descheduled before we finalise. */
184 for_each_vcpu ( d, v )
185 vcpu_sleep_sync(v);
186 BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
188 sync_pagetable_state(d);
190 /* Don't set DOMF_shutdown until execution contexts are sync'ed. */
191 if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
192 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
194 UNLOCK_BIGLOCK(d);
196 put_domain(d);
197 }
199 static __init int domain_shutdown_finaliser_init(void)
200 {
201 open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
202 return 0;
203 }
204 __initcall(domain_shutdown_finaliser_init);
207 void domain_shutdown(struct domain *d, u8 reason)
208 {
209 struct vcpu *v;
211 if ( d->domain_id == 0 )
212 {
213 extern void machine_restart(char *);
214 extern void machine_halt(void);
216 debugger_trap_immediate();
218 if ( reason == SHUTDOWN_poweroff )
219 {
220 printk("Domain 0 halted: halting machine.\n");
221 machine_halt();
222 }
223 else
224 {
225 printk("Domain 0 shutdown: rebooting machine.\n");
226 machine_restart(0);
227 }
228 }
230 /* Mark the domain as shutting down. */
231 d->shutdown_code = reason;
233 /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
234 for_each_vcpu ( d, v )
235 {
236 atomic_inc(&v->pausecnt);
237 vcpu_sleep_nosync(v);
238 }
240 get_knownalive_domain(d);
241 domain_shuttingdown[smp_processor_id()] = d;
242 raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
243 }
246 void domain_pause_for_debugger(void)
247 {
248 struct domain *d = current->domain;
249 struct vcpu *v;
251 /*
252 * NOTE: This does not synchronously pause the domain. The debugger
253 * must issue a PAUSEDOMAIN command to ensure that all execution
254 * has ceased and guest state is committed to memory.
255 */
256 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
257 for_each_vcpu ( d, v )
258 vcpu_sleep_nosync(v);
260 send_guest_virq(dom0->vcpu[0], VIRQ_DEBUGGER);
261 }
264 /* Release resources belonging to task @p. */
265 void domain_destroy(struct domain *d)
266 {
267 struct domain **pd;
268 atomic_t old, new;
270 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
272 /* May be already destroyed, or get_domain() can race us. */
273 _atomic_set(old, 0);
274 _atomic_set(new, DOMAIN_DESTROYED);
275 old = atomic_compareandswap(old, new, &d->refcnt);
276 if ( _atomic_read(old) != 0 )
277 return;
279 /* Delete from task list and task hashtable. */
280 write_lock(&domlist_lock);
281 pd = &domain_list;
282 while ( *pd != d )
283 pd = &(*pd)->next_in_list;
284 *pd = d->next_in_list;
285 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
286 while ( *pd != d )
287 pd = &(*pd)->next_in_hashbucket;
288 *pd = d->next_in_hashbucket;
289 write_unlock(&domlist_lock);
291 rangeset_domain_destroy(d);
293 evtchn_destroy(d);
294 grant_table_destroy(d);
296 arch_domain_destroy(d);
298 free_domain(d);
300 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
301 }
303 void vcpu_pause(struct vcpu *v)
304 {
305 BUG_ON(v == current);
306 atomic_inc(&v->pausecnt);
307 vcpu_sleep_sync(v);
308 }
310 void domain_pause(struct domain *d)
311 {
312 struct vcpu *v;
314 for_each_vcpu( d, v )
315 vcpu_pause(v);
317 sync_pagetable_state(d);
318 }
320 void vcpu_unpause(struct vcpu *v)
321 {
322 BUG_ON(v == current);
323 if ( atomic_dec_and_test(&v->pausecnt) )
324 vcpu_wake(v);
325 }
327 void domain_unpause(struct domain *d)
328 {
329 struct vcpu *v;
331 for_each_vcpu( d, v )
332 vcpu_unpause(v);
333 }
335 void domain_pause_by_systemcontroller(struct domain *d)
336 {
337 struct vcpu *v;
339 BUG_ON(current->domain == d);
341 if ( !test_and_set_bit(_DOMF_ctrl_pause, &d->domain_flags) )
342 {
343 for_each_vcpu ( d, v )
344 vcpu_sleep_sync(v);
345 }
347 sync_pagetable_state(d);
348 }
350 void domain_unpause_by_systemcontroller(struct domain *d)
351 {
352 struct vcpu *v;
354 if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
355 {
356 for_each_vcpu ( d, v )
357 vcpu_wake(v);
358 }
359 }
362 /*
363 * set_info_guest is used for final setup, launching, and state modification
364 * of domains other than domain 0. ie. the domains that are being built by
365 * the userspace dom0 domain builder.
366 */
367 int set_info_guest(struct domain *d, dom0_setvcpucontext_t *setvcpucontext)
368 {
369 int rc = 0;
370 struct vcpu_guest_context *c = NULL;
371 unsigned long vcpu = setvcpucontext->vcpu;
372 struct vcpu *v;
374 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
375 return -EINVAL;
377 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
378 return -ENOMEM;
380 domain_pause(d);
382 rc = -EFAULT;
383 if ( copy_from_user(c, setvcpucontext->ctxt, sizeof(*c)) == 0 )
384 rc = arch_set_info_guest(v, c);
386 domain_unpause(d);
388 xfree(c);
389 return rc;
390 }
392 int boot_vcpu(struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt)
393 {
394 struct vcpu *v = d->vcpu[vcpuid];
396 BUG_ON(test_bit(_VCPUF_initialised, &v->vcpu_flags));
398 return arch_set_info_guest(v, ctxt);
399 }
401 long do_vcpu_op(int cmd, int vcpuid, void *arg)
402 {
403 struct domain *d = current->domain;
404 struct vcpu *v;
405 struct vcpu_guest_context *ctxt;
406 long rc = 0;
408 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
409 return -EINVAL;
411 if ( (v = d->vcpu[vcpuid]) == NULL )
412 return -ENOENT;
414 switch ( cmd )
415 {
416 case VCPUOP_initialise:
417 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
418 {
419 rc = -ENOMEM;
420 break;
421 }
423 if ( copy_from_user(ctxt, arg, sizeof(*ctxt)) )
424 {
425 xfree(ctxt);
426 rc = -EFAULT;
427 break;
428 }
430 LOCK_BIGLOCK(d);
431 rc = -EEXIST;
432 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
433 rc = boot_vcpu(d, vcpuid, ctxt);
434 UNLOCK_BIGLOCK(d);
436 xfree(ctxt);
437 break;
439 case VCPUOP_up:
440 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
441 rc = -EINVAL;
442 else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) )
443 vcpu_wake(v);
444 break;
446 case VCPUOP_down:
447 if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
448 vcpu_sleep_nosync(v);
449 break;
451 case VCPUOP_is_up:
452 rc = !test_bit(_VCPUF_down, &v->vcpu_flags);
453 break;
455 case VCPUOP_get_runstate_info:
456 {
457 struct vcpu_runstate_info runstate;
458 vcpu_runstate_get(v, &runstate);
459 if ( copy_to_user(arg, &runstate, sizeof(runstate)) )
460 rc = -EFAULT;
461 break;
462 }
464 case VCPUOP_register_runstate_memory_area:
465 {
466 struct vcpu_register_runstate_memory_area area;
468 rc = -EINVAL;
469 if ( v != current )
470 break;
472 rc = -EFAULT;
473 if ( copy_from_user(&area, arg, sizeof(area)) )
474 break;
476 if ( !access_ok(area.addr.v, sizeof(*area.addr.v)) )
477 break;
479 rc = 0;
480 v->runstate_guest = area.addr.v;
481 __copy_to_user(v->runstate_guest, &v->runstate, sizeof(v->runstate));
483 break;
484 }
486 default:
487 rc = -ENOSYS;
488 break;
489 }
491 return rc;
492 }
494 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
495 {
496 if ( type > MAX_VMASST_TYPE )
497 return -EINVAL;
499 switch ( cmd )
500 {
501 case VMASST_CMD_enable:
502 set_bit(type, &p->vm_assist);
503 return 0;
504 case VMASST_CMD_disable:
505 clear_bit(type, &p->vm_assist);
506 return 0;
507 }
509 return -ENOSYS;
510 }
512 /*
513 * Local variables:
514 * mode: C
515 * c-set-style: "BSD"
516 * c-basic-offset: 4
517 * tab-width: 4
518 * indent-tabs-mode: nil
519 * End:
520 */