ia64/xen-unstable

view xen/common/domain.c @ 6552:a9873d384da4

Merge.
author adsharma@los-vmm.sc.intel.com
date Thu Aug 25 12:24:48 2005 -0700 (2005-08-25)
parents 112d44270733 fa0754a9f64f
children dfaf788ab18c
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);
117 }
118 }
121 void domain_crash(void)
122 {
123 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
124 current->domain->domain_id, current->vcpu_id, smp_processor_id());
125 show_registers(guest_cpu_user_regs());
126 domain_shutdown(SHUTDOWN_crash);
127 }
130 void domain_crash_synchronous(void)
131 {
132 domain_crash();
133 for ( ; ; )
134 do_softirq();
135 }
138 static struct domain *domain_shuttingdown[NR_CPUS];
140 static void domain_shutdown_finalise(void)
141 {
142 struct domain *d;
143 struct vcpu *v;
145 d = domain_shuttingdown[smp_processor_id()];
146 domain_shuttingdown[smp_processor_id()] = NULL;
148 BUG_ON(d == NULL);
149 BUG_ON(d == current->domain);
150 BUG_ON(!test_bit(_DOMF_shuttingdown, &d->domain_flags));
151 BUG_ON(test_bit(_DOMF_shutdown, &d->domain_flags));
153 /* Make sure that every vcpu is descheduled before we finalise. */
154 for_each_vcpu ( d, v )
155 while ( test_bit(_VCPUF_running, &v->vcpu_flags) )
156 cpu_relax();
158 sync_lazy_execstate_mask(d->cpumask);
159 BUG_ON(!cpus_empty(d->cpumask));
161 sync_pagetable_state(d);
163 set_bit(_DOMF_shutdown, &d->domain_flags);
164 clear_bit(_DOMF_shuttingdown, &d->domain_flags);
166 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
167 }
169 static __init int domain_shutdown_finaliser_init(void)
170 {
171 open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
172 return 0;
173 }
174 __initcall(domain_shutdown_finaliser_init);
177 void domain_shutdown(u8 reason)
178 {
179 struct domain *d = current->domain;
180 struct vcpu *v;
182 if ( d->domain_id == 0 )
183 {
184 extern void machine_restart(char *);
185 extern void machine_halt(void);
187 debugger_trap_immediate();
189 if ( reason == SHUTDOWN_poweroff )
190 {
191 printk("Domain 0 halted: halting machine.\n");
192 machine_halt();
193 }
194 else
195 {
196 printk("Domain 0 shutdown: rebooting machine.\n");
197 machine_restart(0);
198 }
199 }
201 /* Mark the domain as shutting down. */
202 d->shutdown_code = reason;
203 if ( !test_and_set_bit(_DOMF_shuttingdown, &d->domain_flags) )
204 {
205 /* This vcpu won the race to finalise the shutdown. */
206 domain_shuttingdown[smp_processor_id()] = d;
207 raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
208 }
210 /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
211 for_each_vcpu ( d, v )
212 domain_sleep_nosync(v);
213 }
216 void domain_pause_for_debugger(void)
217 {
218 struct domain *d = current->domain;
219 struct vcpu *v;
221 /*
222 * NOTE: This does not synchronously pause the domain. The debugger
223 * must issue a PAUSEDOMAIN command to ensure that all execution
224 * has ceased and guest state is committed to memory.
225 */
226 for_each_vcpu ( d, v )
227 {
228 set_bit(_VCPUF_ctrl_pause, &v->vcpu_flags);
229 domain_sleep_nosync(v);
230 }
232 send_guest_virq(dom0->vcpu[0], VIRQ_DEBUGGER);
233 }
236 /* Release resources belonging to task @p. */
237 void domain_destruct(struct domain *d)
238 {
239 struct domain **pd;
240 atomic_t old, new;
242 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
244 /* May be already destructed, or get_domain() can race us. */
245 _atomic_set(old, 0);
246 _atomic_set(new, DOMAIN_DESTRUCTED);
247 old = atomic_compareandswap(old, new, &d->refcnt);
248 if ( _atomic_read(old) != 0 )
249 return;
251 /* Delete from task list and task hashtable. */
252 write_lock(&domlist_lock);
253 pd = &domain_list;
254 while ( *pd != d )
255 pd = &(*pd)->next_in_list;
256 *pd = d->next_in_list;
257 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
258 while ( *pd != d )
259 pd = &(*pd)->next_in_hashbucket;
260 *pd = d->next_in_hashbucket;
261 write_unlock(&domlist_lock);
263 evtchn_destroy(d);
264 grant_table_destroy(d);
266 free_perdomain_pt(d);
267 free_xenheap_page(d->shared_info);
269 free_domain_struct(d);
271 send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
272 }
274 void vcpu_pause(struct vcpu *v)
275 {
276 BUG_ON(v == current);
277 atomic_inc(&v->pausecnt);
278 domain_sleep_sync(v);
279 }
281 void domain_pause(struct domain *d)
282 {
283 struct vcpu *v;
285 for_each_vcpu( d, v )
286 {
287 BUG_ON(v == current);
288 atomic_inc(&v->pausecnt);
289 domain_sleep_sync(v);
290 }
291 }
293 void vcpu_unpause(struct vcpu *v)
294 {
295 BUG_ON(v == current);
296 if ( atomic_dec_and_test(&v->pausecnt) )
297 domain_wake(v);
298 }
300 void domain_unpause(struct domain *d)
301 {
302 struct vcpu *v;
304 for_each_vcpu( d, v )
305 vcpu_unpause(v);
306 }
308 void domain_pause_by_systemcontroller(struct domain *d)
309 {
310 struct vcpu *v;
312 for_each_vcpu ( d, v )
313 {
314 BUG_ON(v == current);
315 if ( !test_and_set_bit(_VCPUF_ctrl_pause, &v->vcpu_flags) )
316 domain_sleep_sync(v);
317 }
318 }
320 void domain_unpause_by_systemcontroller(struct domain *d)
321 {
322 struct vcpu *v;
324 for_each_vcpu ( d, v )
325 {
326 if ( test_and_clear_bit(_VCPUF_ctrl_pause, &v->vcpu_flags) )
327 domain_wake(v);
328 }
329 }
332 /*
333 * set_info_guest is used for final setup, launching, and state modification
334 * of domains other than domain 0. ie. the domains that are being built by
335 * the userspace dom0 domain builder.
336 */
337 int set_info_guest(struct domain *d, dom0_setdomaininfo_t *setdomaininfo)
338 {
339 int rc = 0;
340 struct vcpu_guest_context *c = NULL;
341 unsigned long vcpu = setdomaininfo->vcpu;
342 struct vcpu *v;
344 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
345 return -EINVAL;
347 if (test_bit(_DOMF_constructed, &d->domain_flags) &&
348 !test_bit(_VCPUF_ctrl_pause, &v->vcpu_flags))
349 return -EINVAL;
351 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
352 return -ENOMEM;
354 if ( copy_from_user(c, setdomaininfo->ctxt, sizeof(*c)) )
355 {
356 rc = -EFAULT;
357 goto out;
358 }
360 if ( (rc = arch_set_info_guest(v, c)) != 0 )
361 goto out;
363 set_bit(_DOMF_constructed, &d->domain_flags);
365 out:
366 xfree(c);
367 return rc;
368 }
370 /*
371 * final_setup_guest is used for final setup and launching of domains other
372 * than domain 0. ie. the domains that are being built by the userspace dom0
373 * domain builder.
374 */
375 long do_boot_vcpu(unsigned long vcpu, struct vcpu_guest_context *ctxt)
376 {
377 struct domain *d = current->domain;
378 struct vcpu *v;
379 int rc = 0;
380 struct vcpu_guest_context *c;
382 if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] != NULL) )
383 return -EINVAL;
385 if ( alloc_vcpu_struct(d, vcpu) == NULL )
386 return -ENOMEM;
388 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
389 {
390 rc = -ENOMEM;
391 goto out;
392 }
394 if ( copy_from_user(c, ctxt, sizeof(*c)) )
395 {
396 rc = -EFAULT;
397 goto out;
398 }
400 v = d->vcpu[vcpu];
402 atomic_set(&v->pausecnt, 0);
403 v->cpumap = CPUMAP_RUNANYWHERE;
405 memcpy(&v->arch, &idle0_vcpu.arch, sizeof(v->arch));
407 arch_do_boot_vcpu(v);
409 if ( (rc = arch_set_info_guest(v, c)) != 0 )
410 goto out;
412 sched_add_domain(v);
414 /* domain_unpause_by_systemcontroller */
415 if ( test_and_clear_bit(_VCPUF_ctrl_pause, &v->vcpu_flags) )
416 domain_wake(v);
418 xfree(c);
419 return 0;
421 out:
422 xfree(c);
423 arch_free_vcpu_struct(d->vcpu[vcpu]);
424 d->vcpu[vcpu] = NULL;
425 return rc;
426 }
428 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
429 {
430 if ( type > MAX_VMASST_TYPE )
431 return -EINVAL;
433 switch ( cmd )
434 {
435 case VMASST_CMD_enable:
436 set_bit(type, &p->vm_assist);
437 return 0;
438 case VMASST_CMD_disable:
439 clear_bit(type, &p->vm_assist);
440 return 0;
441 }
443 return -ENOSYS;
444 }
446 /*
447 * Local variables:
448 * mode: C
449 * c-set-style: "BSD"
450 * c-basic-offset: 4
451 * tab-width: 4
452 * indent-tabs-mode: nil
453 * End:
454 */