ia64/xen-unstable

view xen/common/domain.c @ 8609:85d693e6f61a

Arch-specific per-vcpu info should be initialised to zero
when allocating a new vcpu structure, not copied from
CPU0's idle VCPU. Especially now that the idle VCPU itself
is dynamically allocated.

This should fix assertions people have been seeing in
getdomain_info_ctxt() relation to IOPL in eflags.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Jan 14 21:26:40 2006 +0100 (2006-01-14)
parents 1572681e4e5a
children 334dc7e6a23f
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 *do_createdomain(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 if ( !is_idle_domain(d) )
50 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
52 if ( !is_idle_domain(d) &&
53 ((evtchn_init(d) != 0) || (grant_table_create(d) != 0)) )
54 goto fail1;
56 if ( (v = alloc_vcpu(d, 0, cpu)) == NULL )
57 goto fail2;
59 rangeset_domain_initialise(d);
61 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
62 d->irq_caps = rangeset_new(d, "Interrupts", 0);
64 if ( (d->iomem_caps == NULL) ||
65 (d->irq_caps == NULL) ||
66 (arch_do_createdomain(v) != 0) )
67 goto fail3;
69 if ( !is_idle_domain(d) )
70 {
71 write_lock(&domlist_lock);
72 pd = &domain_list; /* NB. domain_list maintained in order of dom_id. */
73 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
74 if ( (*pd)->domain_id > d->domain_id )
75 break;
76 d->next_in_list = *pd;
77 *pd = d;
78 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(dom_id)];
79 domain_hash[DOMAIN_HASH(dom_id)] = d;
80 write_unlock(&domlist_lock);
81 }
83 return d;
85 fail3:
86 rangeset_domain_destroy(d);
87 fail2:
88 grant_table_destroy(d);
89 fail1:
90 evtchn_destroy(d);
91 free_domain(d);
92 return NULL;
93 }
96 struct domain *find_domain_by_id(domid_t dom)
97 {
98 struct domain *d;
100 read_lock(&domlist_lock);
101 d = domain_hash[DOMAIN_HASH(dom)];
102 while ( d != NULL )
103 {
104 if ( d->domain_id == dom )
105 {
106 if ( unlikely(!get_domain(d)) )
107 d = NULL;
108 break;
109 }
110 d = d->next_in_hashbucket;
111 }
112 read_unlock(&domlist_lock);
114 return d;
115 }
118 void domain_kill(struct domain *d)
119 {
120 struct vcpu *v;
122 domain_pause(d);
123 if ( !test_and_set_bit(_DOMF_dying, &d->domain_flags) )
124 {
125 for_each_vcpu(d, v)
126 sched_rem_domain(v);
127 domain_relinquish_resources(d);
128 gnttab_release_mappings(d);
129 put_domain(d);
131 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
132 }
133 }
136 void domain_crash(struct domain *d)
137 {
138 if ( d == current->domain )
139 {
140 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
141 d->domain_id, current->vcpu_id, smp_processor_id());
142 show_registers(guest_cpu_user_regs());
143 }
144 else
145 {
146 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
147 d->domain_id, current->domain->domain_id, smp_processor_id());
148 }
150 domain_shutdown(d, SHUTDOWN_crash);
151 }
154 void domain_crash_synchronous(void)
155 {
156 domain_crash(current->domain);
157 for ( ; ; )
158 do_softirq();
159 }
162 static struct domain *domain_shuttingdown[NR_CPUS];
164 static void domain_shutdown_finalise(void)
165 {
166 struct domain *d;
167 struct vcpu *v;
169 d = domain_shuttingdown[smp_processor_id()];
170 domain_shuttingdown[smp_processor_id()] = NULL;
172 BUG_ON(d == NULL);
173 BUG_ON(d == current->domain);
175 LOCK_BIGLOCK(d);
177 /* Make sure that every vcpu is descheduled before we finalise. */
178 for_each_vcpu ( d, v )
179 vcpu_sleep_sync(v);
180 BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
182 sync_pagetable_state(d);
184 /* Don't set DOMF_shutdown until execution contexts are sync'ed. */
185 if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
186 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
188 UNLOCK_BIGLOCK(d);
190 put_domain(d);
191 }
193 static __init int domain_shutdown_finaliser_init(void)
194 {
195 open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
196 return 0;
197 }
198 __initcall(domain_shutdown_finaliser_init);
201 void domain_shutdown(struct domain *d, u8 reason)
202 {
203 struct vcpu *v;
205 if ( d->domain_id == 0 )
206 {
207 extern void machine_restart(char *);
208 extern void machine_halt(void);
210 debugger_trap_immediate();
212 if ( reason == SHUTDOWN_poweroff )
213 {
214 printk("Domain 0 halted: halting machine.\n");
215 machine_halt();
216 }
217 else
218 {
219 printk("Domain 0 shutdown: rebooting machine.\n");
220 machine_restart(0);
221 }
222 }
224 /* Mark the domain as shutting down. */
225 d->shutdown_code = reason;
227 /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
228 for_each_vcpu ( d, v )
229 {
230 atomic_inc(&v->pausecnt);
231 vcpu_sleep_nosync(v);
232 }
234 get_knownalive_domain(d);
235 domain_shuttingdown[smp_processor_id()] = d;
236 raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
237 }
240 void domain_pause_for_debugger(void)
241 {
242 struct domain *d = current->domain;
243 struct vcpu *v;
245 /*
246 * NOTE: This does not synchronously pause the domain. The debugger
247 * must issue a PAUSEDOMAIN command to ensure that all execution
248 * has ceased and guest state is committed to memory.
249 */
250 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
251 for_each_vcpu ( d, v )
252 vcpu_sleep_nosync(v);
254 send_guest_virq(dom0->vcpu[0], VIRQ_DEBUGGER);
255 }
258 /* Release resources belonging to task @p. */
259 void domain_destruct(struct domain *d)
260 {
261 struct domain **pd;
262 atomic_t old, new;
264 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
266 /* May be already destructed, or get_domain() can race us. */
267 _atomic_set(old, 0);
268 _atomic_set(new, DOMAIN_DESTRUCTED);
269 old = atomic_compareandswap(old, new, &d->refcnt);
270 if ( _atomic_read(old) != 0 )
271 return;
273 /* Delete from task list and task hashtable. */
274 write_lock(&domlist_lock);
275 pd = &domain_list;
276 while ( *pd != d )
277 pd = &(*pd)->next_in_list;
278 *pd = d->next_in_list;
279 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
280 while ( *pd != d )
281 pd = &(*pd)->next_in_hashbucket;
282 *pd = d->next_in_hashbucket;
283 write_unlock(&domlist_lock);
285 rangeset_domain_destroy(d);
287 evtchn_destroy(d);
288 grant_table_destroy(d);
290 free_perdomain_pt(d);
291 free_xenheap_page(d->shared_info);
293 free_domain(d);
295 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
296 }
298 void vcpu_pause(struct vcpu *v)
299 {
300 BUG_ON(v == current);
301 atomic_inc(&v->pausecnt);
302 vcpu_sleep_sync(v);
303 }
305 void domain_pause(struct domain *d)
306 {
307 struct vcpu *v;
309 for_each_vcpu( d, v )
310 vcpu_pause(v);
312 sync_pagetable_state(d);
313 }
315 void vcpu_unpause(struct vcpu *v)
316 {
317 BUG_ON(v == current);
318 if ( atomic_dec_and_test(&v->pausecnt) )
319 vcpu_wake(v);
320 }
322 void domain_unpause(struct domain *d)
323 {
324 struct vcpu *v;
326 for_each_vcpu( d, v )
327 vcpu_unpause(v);
328 }
330 void domain_pause_by_systemcontroller(struct domain *d)
331 {
332 struct vcpu *v;
334 BUG_ON(current->domain == d);
336 if ( !test_and_set_bit(_DOMF_ctrl_pause, &d->domain_flags) )
337 {
338 for_each_vcpu ( d, v )
339 vcpu_sleep_sync(v);
340 }
342 sync_pagetable_state(d);
343 }
345 void domain_unpause_by_systemcontroller(struct domain *d)
346 {
347 struct vcpu *v;
349 if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
350 {
351 for_each_vcpu ( d, v )
352 vcpu_wake(v);
353 }
354 }
357 /*
358 * set_info_guest is used for final setup, launching, and state modification
359 * of domains other than domain 0. ie. the domains that are being built by
360 * the userspace dom0 domain builder.
361 */
362 int set_info_guest(struct domain *d, dom0_setvcpucontext_t *setvcpucontext)
363 {
364 int rc = 0;
365 struct vcpu_guest_context *c = NULL;
366 unsigned long vcpu = setvcpucontext->vcpu;
367 struct vcpu *v;
369 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
370 return -EINVAL;
372 if ( !test_bit(_DOMF_ctrl_pause, &d->domain_flags) )
373 return -EINVAL;
375 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
376 return -ENOMEM;
378 rc = -EFAULT;
379 if ( copy_from_user(c, setvcpucontext->ctxt, sizeof(*c)) == 0 )
380 rc = arch_set_info_guest(v, c);
382 xfree(c);
383 return rc;
384 }
386 int boot_vcpu(struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt)
387 {
388 struct vcpu *v = d->vcpu[vcpuid];
390 BUG_ON(test_bit(_VCPUF_initialised, &v->vcpu_flags));
392 return arch_set_info_guest(v, ctxt);
393 }
395 long do_vcpu_op(int cmd, int vcpuid, void *arg)
396 {
397 struct domain *d = current->domain;
398 struct vcpu *v;
399 struct vcpu_guest_context *ctxt;
400 long rc = 0;
402 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
403 return -EINVAL;
405 if ( (v = d->vcpu[vcpuid]) == NULL )
406 return -ENOENT;
408 switch ( cmd )
409 {
410 case VCPUOP_initialise:
411 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
412 {
413 rc = -ENOMEM;
414 break;
415 }
417 if ( copy_from_user(ctxt, arg, sizeof(*ctxt)) )
418 {
419 xfree(ctxt);
420 rc = -EFAULT;
421 break;
422 }
424 LOCK_BIGLOCK(d);
425 rc = -EEXIST;
426 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
427 rc = boot_vcpu(d, vcpuid, ctxt);
428 UNLOCK_BIGLOCK(d);
430 xfree(ctxt);
431 break;
433 case VCPUOP_up:
434 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
435 rc = -EINVAL;
436 else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) )
437 vcpu_wake(v);
438 break;
440 case VCPUOP_down:
441 if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
442 vcpu_sleep_nosync(v);
443 break;
445 case VCPUOP_is_up:
446 rc = !test_bit(_VCPUF_down, &v->vcpu_flags);
447 break;
448 }
450 return rc;
451 }
453 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
454 {
455 if ( type > MAX_VMASST_TYPE )
456 return -EINVAL;
458 switch ( cmd )
459 {
460 case VMASST_CMD_enable:
461 set_bit(type, &p->vm_assist);
462 return 0;
463 case VMASST_CMD_disable:
464 clear_bit(type, &p->vm_assist);
465 return 0;
466 }
468 return -ENOSYS;
469 }
471 /*
472 * Local variables:
473 * mode: C
474 * c-set-style: "BSD"
475 * c-basic-offset: 4
476 * tab-width: 4
477 * indent-tabs-mode: nil
478 * End:
479 */