ia64/xen-unstable

view xen/common/domain.c @ 6501:946ea528fc79

Raise VIRQ_DOM_EXC when a domain is destroyed from dom0.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Aug 30 20:01:23 2005 +0000 (2005-08-30)
parents 83c73802f02a
children 1fc6473ecc01
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 <asm/debugger.h>
20 #include <public/dom0_ops.h>
22 /* Both these structures are protected by the domlist_lock. */
23 rwlock_t domlist_lock = RW_LOCK_UNLOCKED;
24 struct domain *domain_hash[DOMAIN_HASH_SIZE];
25 struct domain *domain_list;
27 struct domain *dom0;
29 struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
30 {
31 struct domain *d, **pd;
32 struct vcpu *v;
34 if ( (d = alloc_domain_struct()) == NULL )
35 return NULL;
37 v = d->vcpu[0];
39 atomic_set(&d->refcnt, 1);
40 atomic_set(&v->pausecnt, 0);
42 d->domain_id = dom_id;
43 v->processor = cpu;
45 spin_lock_init(&d->big_lock);
47 spin_lock_init(&d->page_alloc_lock);
48 INIT_LIST_HEAD(&d->page_list);
49 INIT_LIST_HEAD(&d->xenpage_list);
51 if ( d->domain_id == IDLE_DOMAIN_ID )
52 set_bit(_DOMF_idle_domain, &d->domain_flags);
54 if ( !is_idle_task(d) &&
55 ((evtchn_init(d) != 0) || (grant_table_create(d) != 0)) )
56 {
57 evtchn_destroy(d);
58 free_domain_struct(d);
59 return NULL;
60 }
62 arch_do_createdomain(v);
64 sched_add_domain(v);
66 if ( !is_idle_task(d) )
67 {
68 write_lock(&domlist_lock);
69 pd = &domain_list; /* NB. domain_list maintained in order of dom_id. */
70 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
71 if ( (*pd)->domain_id > d->domain_id )
72 break;
73 d->next_in_list = *pd;
74 *pd = d;
75 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(dom_id)];
76 domain_hash[DOMAIN_HASH(dom_id)] = d;
77 write_unlock(&domlist_lock);
78 }
80 return d;
81 }
84 struct domain *find_domain_by_id(domid_t dom)
85 {
86 struct domain *d;
88 read_lock(&domlist_lock);
89 d = domain_hash[DOMAIN_HASH(dom)];
90 while ( d != NULL )
91 {
92 if ( d->domain_id == dom )
93 {
94 if ( unlikely(!get_domain(d)) )
95 d = NULL;
96 break;
97 }
98 d = d->next_in_hashbucket;
99 }
100 read_unlock(&domlist_lock);
102 return d;
103 }
106 void domain_kill(struct domain *d)
107 {
108 struct vcpu *v;
110 domain_pause(d);
111 if ( !test_and_set_bit(_DOMF_dying, &d->domain_flags) )
112 {
113 for_each_vcpu(d, v)
114 sched_rem_domain(v);
115 domain_relinquish_resources(d);
116 put_domain(d);
118 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
119 }
120 }
123 void domain_crash(void)
124 {
125 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
126 current->domain->domain_id, current->vcpu_id, smp_processor_id());
127 show_registers(guest_cpu_user_regs());
128 domain_shutdown(SHUTDOWN_crash);
129 }
132 void domain_crash_synchronous(void)
133 {
134 domain_crash();
135 for ( ; ; )
136 do_softirq();
137 }
140 static struct domain *domain_shuttingdown[NR_CPUS];
142 static void domain_shutdown_finalise(void)
143 {
144 struct domain *d;
145 struct vcpu *v;
147 d = domain_shuttingdown[smp_processor_id()];
148 domain_shuttingdown[smp_processor_id()] = NULL;
150 BUG_ON(d == NULL);
151 BUG_ON(d == current->domain);
152 BUG_ON(!test_bit(_DOMF_shuttingdown, &d->domain_flags));
153 BUG_ON(test_bit(_DOMF_shutdown, &d->domain_flags));
155 /* Make sure that every vcpu is descheduled before we finalise. */
156 for_each_vcpu ( d, v )
157 vcpu_sleep_sync(v);
158 BUG_ON(!cpus_empty(d->cpumask));
160 sync_pagetable_state(d);
162 set_bit(_DOMF_shutdown, &d->domain_flags);
163 clear_bit(_DOMF_shuttingdown, &d->domain_flags);
165 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
166 }
168 static __init int domain_shutdown_finaliser_init(void)
169 {
170 open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
171 return 0;
172 }
173 __initcall(domain_shutdown_finaliser_init);
176 void domain_shutdown(u8 reason)
177 {
178 struct domain *d = current->domain;
179 struct vcpu *v;
181 if ( d->domain_id == 0 )
182 {
183 extern void machine_restart(char *);
184 extern void machine_halt(void);
186 debugger_trap_immediate();
188 if ( reason == SHUTDOWN_poweroff )
189 {
190 printk("Domain 0 halted: halting machine.\n");
191 machine_halt();
192 }
193 else
194 {
195 printk("Domain 0 shutdown: rebooting machine.\n");
196 machine_restart(0);
197 }
198 }
200 /* Mark the domain as shutting down. */
201 d->shutdown_code = reason;
202 if ( !test_and_set_bit(_DOMF_shuttingdown, &d->domain_flags) )
203 {
204 /* This vcpu won the race to finalise the shutdown. */
205 domain_shuttingdown[smp_processor_id()] = d;
206 raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
207 }
209 /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
210 for_each_vcpu ( d, v )
211 vcpu_sleep_nosync(v);
212 }
215 void domain_pause_for_debugger(void)
216 {
217 struct domain *d = current->domain;
218 struct vcpu *v;
220 /*
221 * NOTE: This does not synchronously pause the domain. The debugger
222 * must issue a PAUSEDOMAIN command to ensure that all execution
223 * has ceased and guest state is committed to memory.
224 */
225 for_each_vcpu ( d, v )
226 {
227 set_bit(_VCPUF_ctrl_pause, &v->vcpu_flags);
228 vcpu_sleep_nosync(v);
229 }
231 send_guest_virq(dom0->vcpu[0], VIRQ_DEBUGGER);
232 }
235 /* Release resources belonging to task @p. */
236 void domain_destruct(struct domain *d)
237 {
238 struct domain **pd;
239 atomic_t old, new;
241 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
243 /* May be already destructed, or get_domain() can race us. */
244 _atomic_set(old, 0);
245 _atomic_set(new, DOMAIN_DESTRUCTED);
246 old = atomic_compareandswap(old, new, &d->refcnt);
247 if ( _atomic_read(old) != 0 )
248 return;
250 /* Delete from task list and task hashtable. */
251 write_lock(&domlist_lock);
252 pd = &domain_list;
253 while ( *pd != d )
254 pd = &(*pd)->next_in_list;
255 *pd = d->next_in_list;
256 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
257 while ( *pd != d )
258 pd = &(*pd)->next_in_hashbucket;
259 *pd = d->next_in_hashbucket;
260 write_unlock(&domlist_lock);
262 evtchn_destroy(d);
263 grant_table_destroy(d);
265 free_perdomain_pt(d);
266 free_xenheap_page(d->shared_info);
268 free_domain_struct(d);
270 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
271 }
273 void vcpu_pause(struct vcpu *v)
274 {
275 BUG_ON(v == current);
276 atomic_inc(&v->pausecnt);
277 vcpu_sleep_sync(v);
278 }
280 void domain_pause(struct domain *d)
281 {
282 struct vcpu *v;
284 for_each_vcpu( d, v )
285 {
286 BUG_ON(v == current);
287 atomic_inc(&v->pausecnt);
288 vcpu_sleep_sync(v);
289 }
290 }
292 void vcpu_unpause(struct vcpu *v)
293 {
294 BUG_ON(v == current);
295 if ( atomic_dec_and_test(&v->pausecnt) )
296 vcpu_wake(v);
297 }
299 void domain_unpause(struct domain *d)
300 {
301 struct vcpu *v;
303 for_each_vcpu( d, v )
304 vcpu_unpause(v);
305 }
307 void domain_pause_by_systemcontroller(struct domain *d)
308 {
309 struct vcpu *v;
311 for_each_vcpu ( d, v )
312 {
313 BUG_ON(v == current);
314 if ( !test_and_set_bit(_VCPUF_ctrl_pause, &v->vcpu_flags) )
315 vcpu_sleep_sync(v);
316 }
317 }
319 void domain_unpause_by_systemcontroller(struct domain *d)
320 {
321 struct vcpu *v;
323 for_each_vcpu ( d, v )
324 {
325 if ( test_and_clear_bit(_VCPUF_ctrl_pause, &v->vcpu_flags) )
326 vcpu_wake(v);
327 }
328 }
331 /*
332 * set_info_guest is used for final setup, launching, and state modification
333 * of domains other than domain 0. ie. the domains that are being built by
334 * the userspace dom0 domain builder.
335 */
336 int set_info_guest(struct domain *d, dom0_setdomaininfo_t *setdomaininfo)
337 {
338 int rc = 0;
339 struct vcpu_guest_context *c = NULL;
340 unsigned long vcpu = setdomaininfo->vcpu;
341 struct vcpu *v;
343 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
344 return -EINVAL;
346 if (test_bit(_DOMF_constructed, &d->domain_flags) &&
347 !test_bit(_VCPUF_ctrl_pause, &v->vcpu_flags))
348 return -EINVAL;
350 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
351 return -ENOMEM;
353 if ( copy_from_user(c, setdomaininfo->ctxt, sizeof(*c)) )
354 {
355 rc = -EFAULT;
356 goto out;
357 }
359 if ( (rc = arch_set_info_guest(v, c)) != 0 )
360 goto out;
362 set_bit(_DOMF_constructed, &d->domain_flags);
364 out:
365 xfree(c);
366 return rc;
367 }
369 /*
370 * final_setup_guest is used for final setup and launching of domains other
371 * than domain 0. ie. the domains that are being built by the userspace dom0
372 * domain builder.
373 */
374 long do_boot_vcpu(unsigned long vcpu, struct vcpu_guest_context *ctxt)
375 {
376 struct domain *d = current->domain;
377 struct vcpu *v;
378 int rc = 0;
379 struct vcpu_guest_context *c;
381 if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] != NULL) )
382 return -EINVAL;
384 if ( alloc_vcpu_struct(d, vcpu) == NULL )
385 return -ENOMEM;
387 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
388 {
389 rc = -ENOMEM;
390 goto out;
391 }
393 if ( copy_from_user(c, ctxt, sizeof(*c)) )
394 {
395 rc = -EFAULT;
396 goto out;
397 }
399 v = d->vcpu[vcpu];
401 atomic_set(&v->pausecnt, 0);
402 v->cpumap = CPUMAP_RUNANYWHERE;
404 memcpy(&v->arch, &idle0_vcpu.arch, sizeof(v->arch));
406 arch_do_boot_vcpu(v);
408 if ( (rc = arch_set_info_guest(v, c)) != 0 )
409 goto out;
411 sched_add_domain(v);
413 /* domain_unpause_by_systemcontroller */
414 if ( test_and_clear_bit(_VCPUF_ctrl_pause, &v->vcpu_flags) )
415 vcpu_wake(v);
417 xfree(c);
418 return 0;
420 out:
421 xfree(c);
422 arch_free_vcpu_struct(d->vcpu[vcpu]);
423 d->vcpu[vcpu] = NULL;
424 return rc;
425 }
427 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
428 {
429 if ( type > MAX_VMASST_TYPE )
430 return -EINVAL;
432 switch ( cmd )
433 {
434 case VMASST_CMD_enable:
435 set_bit(type, &p->vm_assist);
436 return 0;
437 case VMASST_CMD_disable:
438 clear_bit(type, &p->vm_assist);
439 return 0;
440 }
442 return -ENOSYS;
443 }
445 /*
446 * Local variables:
447 * mode: C
448 * c-set-style: "BSD"
449 * c-basic-offset: 4
450 * tab-width: 4
451 * indent-tabs-mode: nil
452 * End:
453 */