ia64/xen-unstable

view xen/common/domain.c @ 9706:3c05406f5e0a

In some cases, say for instance for some bizzare reason
the tree was checked out of CVS, which doens't neccessarily
store file permissions, mkbuildtree may not be executable.
So run them explicitly via bash.

Signed-Off-By: Horms <horms@verge.net.au>
author kaf24@firebug.cl.cam.ac.uk
date Thu Apr 13 11:24:00 2006 +0100 (2006-04-13)
parents 8f7aad20b4a5
children 4e1b8be54311
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 <asm/debugger.h>
24 #include <public/dom0_ops.h>
25 #include <public/sched.h>
26 #include <public/vcpu.h>
28 /* Both these structures are protected by the domlist_lock. */
29 rwlock_t domlist_lock = RW_LOCK_UNLOCKED;
30 struct domain *domain_hash[DOMAIN_HASH_SIZE];
31 struct domain *domain_list;
33 struct domain *dom0;
35 struct domain *domain_create(domid_t dom_id, unsigned int cpu)
36 {
37 struct domain *d, **pd;
38 struct vcpu *v;
40 if ( (d = alloc_domain()) == NULL )
41 return NULL;
43 d->domain_id = dom_id;
45 atomic_set(&d->refcnt, 1);
47 spin_lock_init(&d->big_lock);
48 spin_lock_init(&d->page_alloc_lock);
49 INIT_LIST_HEAD(&d->page_list);
50 INIT_LIST_HEAD(&d->xenpage_list);
52 rangeset_domain_initialise(d);
54 if ( !is_idle_domain(d) )
55 {
56 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
57 if ( evtchn_init(d) != 0 )
58 goto fail1;
59 if ( grant_table_create(d) != 0 )
60 goto fail2;
61 }
63 if ( arch_domain_create(d) != 0 )
64 goto fail3;
66 if ( (v = alloc_vcpu(d, 0, cpu)) == NULL )
67 goto fail4;
69 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
70 d->irq_caps = rangeset_new(d, "Interrupts", 0);
71 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
72 goto fail4; /* NB. alloc_vcpu() is undone in free_domain() */
74 if ( !is_idle_domain(d) )
75 {
76 write_lock(&domlist_lock);
77 pd = &domain_list; /* NB. domain_list maintained in order of dom_id. */
78 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
79 if ( (*pd)->domain_id > d->domain_id )
80 break;
81 d->next_in_list = *pd;
82 *pd = d;
83 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(dom_id)];
84 domain_hash[DOMAIN_HASH(dom_id)] = d;
85 write_unlock(&domlist_lock);
86 }
88 return d;
90 fail4:
91 arch_domain_destroy(d);
92 fail3:
93 if ( !is_idle_domain(d) )
94 grant_table_destroy(d);
95 fail2:
96 if ( !is_idle_domain(d) )
97 evtchn_destroy(d);
98 fail1:
99 rangeset_domain_destroy(d);
100 free_domain(d);
101 return NULL;
102 }
105 struct domain *find_domain_by_id(domid_t dom)
106 {
107 struct domain *d;
109 read_lock(&domlist_lock);
110 d = domain_hash[DOMAIN_HASH(dom)];
111 while ( d != NULL )
112 {
113 if ( d->domain_id == dom )
114 {
115 if ( unlikely(!get_domain(d)) )
116 d = NULL;
117 break;
118 }
119 d = d->next_in_hashbucket;
120 }
121 read_unlock(&domlist_lock);
123 return d;
124 }
127 void domain_kill(struct domain *d)
128 {
129 struct vcpu *v;
131 domain_pause(d);
132 if ( !test_and_set_bit(_DOMF_dying, &d->domain_flags) )
133 {
134 for_each_vcpu(d, v)
135 sched_rem_domain(v);
136 gnttab_release_mappings(d);
137 domain_relinquish_resources(d);
138 put_domain(d);
140 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
141 }
142 }
145 void __domain_crash(struct domain *d)
146 {
147 if ( d == current->domain )
148 {
149 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
150 d->domain_id, current->vcpu_id, smp_processor_id());
151 show_registers(guest_cpu_user_regs());
152 }
153 else
154 {
155 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
156 d->domain_id, current->domain->domain_id, smp_processor_id());
157 }
159 domain_shutdown(d, SHUTDOWN_crash);
160 }
163 void __domain_crash_synchronous(void)
164 {
165 __domain_crash(current->domain);
166 for ( ; ; )
167 do_softirq();
168 }
171 static struct domain *domain_shuttingdown[NR_CPUS];
173 static void domain_shutdown_finalise(void)
174 {
175 struct domain *d;
176 struct vcpu *v;
178 d = domain_shuttingdown[smp_processor_id()];
179 domain_shuttingdown[smp_processor_id()] = NULL;
181 BUG_ON(d == NULL);
182 BUG_ON(d == current->domain);
184 LOCK_BIGLOCK(d);
186 /* Make sure that every vcpu is descheduled before we finalise. */
187 for_each_vcpu ( d, v )
188 vcpu_sleep_sync(v);
189 BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
191 sync_pagetable_state(d);
193 /* Don't set DOMF_shutdown until execution contexts are sync'ed. */
194 if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
195 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
197 UNLOCK_BIGLOCK(d);
199 put_domain(d);
200 }
202 static __init int domain_shutdown_finaliser_init(void)
203 {
204 open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
205 return 0;
206 }
207 __initcall(domain_shutdown_finaliser_init);
210 void domain_shutdown(struct domain *d, u8 reason)
211 {
212 struct vcpu *v;
214 if ( d->domain_id == 0 )
215 {
216 extern void machine_restart(char *);
217 extern void machine_halt(void);
219 debugger_trap_immediate();
221 if ( reason == SHUTDOWN_poweroff )
222 {
223 printk("Domain 0 halted: halting machine.\n");
224 machine_halt();
225 }
226 else if ( reason == SHUTDOWN_crash )
227 {
228 printk("Domain 0 crashed: rebooting machine in 5 seconds.\n");
229 watchdog_disable();
230 mdelay(5000);
231 machine_restart(0);
232 }
233 else
234 {
235 printk("Domain 0 shutdown: rebooting machine.\n");
236 machine_restart(0);
237 }
238 }
240 /* Mark the domain as shutting down. */
241 d->shutdown_code = reason;
243 /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
244 for_each_vcpu ( d, v )
245 {
246 atomic_inc(&v->pausecnt);
247 vcpu_sleep_nosync(v);
248 }
250 get_knownalive_domain(d);
251 domain_shuttingdown[smp_processor_id()] = d;
252 raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
253 }
256 void domain_pause_for_debugger(void)
257 {
258 struct domain *d = current->domain;
259 struct vcpu *v;
261 /*
262 * NOTE: This does not synchronously pause the domain. The debugger
263 * must issue a PAUSEDOMAIN command to ensure that all execution
264 * has ceased and guest state is committed to memory.
265 */
266 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
267 for_each_vcpu ( d, v )
268 vcpu_sleep_nosync(v);
270 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
271 }
274 /* Release resources belonging to task @p. */
275 void domain_destroy(struct domain *d)
276 {
277 struct domain **pd;
278 atomic_t old, new;
280 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
282 /* May be already destroyed, or get_domain() can race us. */
283 _atomic_set(old, 0);
284 _atomic_set(new, DOMAIN_DESTROYED);
285 old = atomic_compareandswap(old, new, &d->refcnt);
286 if ( _atomic_read(old) != 0 )
287 return;
289 /* Delete from task list and task hashtable. */
290 write_lock(&domlist_lock);
291 pd = &domain_list;
292 while ( *pd != d )
293 pd = &(*pd)->next_in_list;
294 *pd = d->next_in_list;
295 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
296 while ( *pd != d )
297 pd = &(*pd)->next_in_hashbucket;
298 *pd = d->next_in_hashbucket;
299 write_unlock(&domlist_lock);
301 rangeset_domain_destroy(d);
303 evtchn_destroy(d);
304 grant_table_destroy(d);
306 arch_domain_destroy(d);
308 free_domain(d);
310 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
311 }
313 void vcpu_pause(struct vcpu *v)
314 {
315 BUG_ON(v == current);
316 atomic_inc(&v->pausecnt);
317 vcpu_sleep_sync(v);
318 }
320 void domain_pause(struct domain *d)
321 {
322 struct vcpu *v;
324 for_each_vcpu( d, v )
325 vcpu_pause(v);
327 sync_pagetable_state(d);
328 }
330 void vcpu_unpause(struct vcpu *v)
331 {
332 BUG_ON(v == current);
333 if ( atomic_dec_and_test(&v->pausecnt) )
334 vcpu_wake(v);
335 }
337 void domain_unpause(struct domain *d)
338 {
339 struct vcpu *v;
341 for_each_vcpu( d, v )
342 vcpu_unpause(v);
343 }
345 void domain_pause_by_systemcontroller(struct domain *d)
346 {
347 struct vcpu *v;
349 BUG_ON(current->domain == d);
351 if ( !test_and_set_bit(_DOMF_ctrl_pause, &d->domain_flags) )
352 {
353 for_each_vcpu ( d, v )
354 vcpu_sleep_sync(v);
355 }
357 sync_pagetable_state(d);
358 }
360 void domain_unpause_by_systemcontroller(struct domain *d)
361 {
362 struct vcpu *v;
364 if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
365 {
366 for_each_vcpu ( d, v )
367 vcpu_wake(v);
368 }
369 }
372 /*
373 * set_info_guest is used for final setup, launching, and state modification
374 * of domains other than domain 0. ie. the domains that are being built by
375 * the userspace dom0 domain builder.
376 */
377 int set_info_guest(struct domain *d, dom0_setvcpucontext_t *setvcpucontext)
378 {
379 int rc = 0;
380 struct vcpu_guest_context *c = NULL;
381 unsigned long vcpu = setvcpucontext->vcpu;
382 struct vcpu *v;
384 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
385 return -EINVAL;
387 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
388 return -ENOMEM;
390 domain_pause(d);
392 rc = -EFAULT;
393 if ( copy_from_guest(c, setvcpucontext->ctxt, 1) == 0 )
394 rc = arch_set_info_guest(v, c);
396 domain_unpause(d);
398 xfree(c);
399 return rc;
400 }
402 int boot_vcpu(struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt)
403 {
404 struct vcpu *v = d->vcpu[vcpuid];
406 BUG_ON(test_bit(_VCPUF_initialised, &v->vcpu_flags));
408 return arch_set_info_guest(v, ctxt);
409 }
411 long do_vcpu_op(int cmd, int vcpuid, GUEST_HANDLE(void) arg)
412 {
413 struct domain *d = current->domain;
414 struct vcpu *v;
415 struct vcpu_guest_context *ctxt;
416 long rc = 0;
418 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
419 return -EINVAL;
421 if ( (v = d->vcpu[vcpuid]) == NULL )
422 return -ENOENT;
424 switch ( cmd )
425 {
426 case VCPUOP_initialise:
427 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
428 {
429 rc = -ENOMEM;
430 break;
431 }
433 if ( copy_from_guest(ctxt, arg, 1) )
434 {
435 xfree(ctxt);
436 rc = -EFAULT;
437 break;
438 }
440 LOCK_BIGLOCK(d);
441 rc = -EEXIST;
442 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
443 rc = boot_vcpu(d, vcpuid, ctxt);
444 UNLOCK_BIGLOCK(d);
446 xfree(ctxt);
447 break;
449 case VCPUOP_up:
450 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
451 rc = -EINVAL;
452 else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) )
453 vcpu_wake(v);
454 break;
456 case VCPUOP_down:
457 if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
458 vcpu_sleep_nosync(v);
459 break;
461 case VCPUOP_is_up:
462 rc = !test_bit(_VCPUF_down, &v->vcpu_flags);
463 break;
465 case VCPUOP_get_runstate_info:
466 {
467 struct vcpu_runstate_info runstate;
468 vcpu_runstate_get(v, &runstate);
469 if ( copy_to_guest(arg, &runstate, 1) )
470 rc = -EFAULT;
471 break;
472 }
474 default:
475 rc = arch_do_vcpu_op(cmd, v, arg);
476 break;
477 }
479 return rc;
480 }
482 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
483 {
484 if ( type > MAX_VMASST_TYPE )
485 return -EINVAL;
487 switch ( cmd )
488 {
489 case VMASST_CMD_enable:
490 set_bit(type, &p->vm_assist);
491 return 0;
492 case VMASST_CMD_disable:
493 clear_bit(type, &p->vm_assist);
494 return 0;
495 }
497 return -ENOSYS;
498 }
500 /*
501 * Local variables:
502 * mode: C
503 * c-set-style: "BSD"
504 * c-basic-offset: 4
505 * tab-width: 4
506 * indent-tabs-mode: nil
507 * End:
508 */