ia64/xen-unstable

view xen/common/domain.c @ 13608:30af6cfdb05c

Make domctl/sysctl interfaces 32-/64-bit invariant.
This kills off a fair amount of unpleasant CONFIG_COMPAT shimming and
avoids needing to keep the compat paths in sync as these interfaces
continue to develop.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Jan 24 16:33:19 2007 +0000 (2007-01-24)
parents c3b2443408f4
children 271ffb1c12eb
line source
1 /******************************************************************************
2 * domain.c
3 *
4 * Generic domain-handling functions.
5 */
7 #include <xen/config.h>
8 #include <xen/compat.h>
9 #include <xen/init.h>
10 #include <xen/lib.h>
11 #include <xen/errno.h>
12 #include <xen/sched.h>
13 #include <xen/domain.h>
14 #include <xen/mm.h>
15 #include <xen/event.h>
16 #include <xen/time.h>
17 #include <xen/console.h>
18 #include <xen/softirq.h>
19 #include <xen/domain_page.h>
20 #include <xen/rangeset.h>
21 #include <xen/guest_access.h>
22 #include <xen/hypercall.h>
23 #include <xen/delay.h>
24 #include <xen/shutdown.h>
25 #include <xen/percpu.h>
26 #include <xen/multicall.h>
27 #include <asm/debugger.h>
28 #include <public/sched.h>
29 #include <public/vcpu.h>
31 /* Both these structures are protected by the domlist_lock. */
32 DEFINE_RWLOCK(domlist_lock);
33 struct domain *domain_hash[DOMAIN_HASH_SIZE];
34 struct domain *domain_list;
36 struct domain *dom0;
38 struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
40 int current_domain_id(void)
41 {
42 return current->domain->domain_id;
43 }
45 struct domain *alloc_domain(domid_t domid)
46 {
47 struct domain *d;
49 if ( (d = xmalloc(struct domain)) == NULL )
50 return NULL;
52 memset(d, 0, sizeof(*d));
53 d->domain_id = domid;
54 atomic_set(&d->refcnt, 1);
55 spin_lock_init(&d->big_lock);
56 spin_lock_init(&d->page_alloc_lock);
57 spin_lock_init(&d->pause_lock);
58 INIT_LIST_HEAD(&d->page_list);
59 INIT_LIST_HEAD(&d->xenpage_list);
61 return d;
62 }
64 void free_domain(struct domain *d)
65 {
66 struct vcpu *v;
67 int i;
69 for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
70 {
71 if ( (v = d->vcpu[i]) == NULL )
72 continue;
73 vcpu_destroy(v);
74 sched_destroy_vcpu(v);
75 free_vcpu_struct(v);
76 }
78 sched_destroy_domain(d);
79 xfree(d);
80 }
82 struct vcpu *alloc_vcpu(
83 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
84 {
85 struct vcpu *v;
87 BUG_ON(d->vcpu[vcpu_id] != NULL);
89 if ( (v = alloc_vcpu_struct()) == NULL )
90 return NULL;
92 v->domain = d;
93 v->vcpu_id = vcpu_id;
94 v->vcpu_info = shared_info_addr(d, vcpu_info[vcpu_id]);
95 spin_lock_init(&v->pause_lock);
97 v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
98 v->runstate.state_entry_time = NOW();
100 if ( (vcpu_id != 0) && !is_idle_domain(d) )
101 set_bit(_VCPUF_down, &v->vcpu_flags);
103 if ( sched_init_vcpu(v, cpu_id) != 0 )
104 {
105 free_vcpu_struct(v);
106 return NULL;
107 }
109 if ( vcpu_initialise(v) != 0 )
110 {
111 sched_destroy_vcpu(v);
112 free_vcpu_struct(v);
113 return NULL;
114 }
116 d->vcpu[vcpu_id] = v;
117 if ( vcpu_id != 0 )
118 d->vcpu[v->vcpu_id-1]->next_in_list = v;
120 return v;
121 }
123 struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
124 {
125 struct domain *d;
126 struct vcpu *v;
127 unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
129 if ( (v = idle_vcpu[cpu_id]) != NULL )
130 return v;
132 d = (vcpu_id == 0) ?
133 domain_create(IDLE_DOMAIN_ID, 0) :
134 idle_vcpu[cpu_id - vcpu_id]->domain;
135 BUG_ON(d == NULL);
137 v = alloc_vcpu(d, vcpu_id, cpu_id);
138 idle_vcpu[cpu_id] = v;
140 return v;
141 }
143 struct domain *domain_create(domid_t domid, unsigned int domcr_flags)
144 {
145 struct domain *d, **pd;
147 if ( (d = alloc_domain(domid)) == NULL )
148 return NULL;
150 if ( domcr_flags & DOMCRF_hvm )
151 d->is_hvm = 1;
153 rangeset_domain_initialise(d);
155 if ( !is_idle_domain(d) )
156 {
157 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
158 if ( evtchn_init(d) != 0 )
159 goto fail1;
160 if ( grant_table_create(d) != 0 )
161 goto fail2;
162 }
164 if ( arch_domain_create(d) != 0 )
165 goto fail3;
167 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
168 d->irq_caps = rangeset_new(d, "Interrupts", 0);
169 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
170 goto fail4;
172 if ( sched_init_domain(d) != 0 )
173 goto fail4;
175 if ( !is_idle_domain(d) )
176 {
177 write_lock(&domlist_lock);
178 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
179 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
180 if ( (*pd)->domain_id > d->domain_id )
181 break;
182 d->next_in_list = *pd;
183 *pd = d;
184 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
185 domain_hash[DOMAIN_HASH(domid)] = d;
186 write_unlock(&domlist_lock);
187 }
189 return d;
191 fail4:
192 arch_domain_destroy(d);
193 fail3:
194 if ( !is_idle_domain(d) )
195 grant_table_destroy(d);
196 fail2:
197 if ( !is_idle_domain(d) )
198 evtchn_destroy(d);
199 fail1:
200 rangeset_domain_destroy(d);
201 free_domain(d);
202 return NULL;
203 }
206 struct domain *find_domain_by_id(domid_t dom)
207 {
208 struct domain *d;
210 read_lock(&domlist_lock);
211 d = domain_hash[DOMAIN_HASH(dom)];
212 while ( d != NULL )
213 {
214 if ( d->domain_id == dom )
215 {
216 if ( unlikely(!get_domain(d)) )
217 d = NULL;
218 break;
219 }
220 d = d->next_in_hashbucket;
221 }
222 read_unlock(&domlist_lock);
224 return d;
225 }
228 void domain_kill(struct domain *d)
229 {
230 domain_pause(d);
232 if ( test_and_set_bit(_DOMF_dying, &d->domain_flags) )
233 return;
235 gnttab_release_mappings(d);
236 domain_relinquish_resources(d);
237 put_domain(d);
239 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
240 }
243 void __domain_crash(struct domain *d)
244 {
245 if ( test_bit(_DOMF_shutdown, &d->domain_flags) )
246 {
247 /* Print nothing: the domain is already shutting down. */
248 }
249 else if ( d == current->domain )
250 {
251 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
252 d->domain_id, current->vcpu_id, smp_processor_id());
253 show_execution_state(guest_cpu_user_regs());
254 }
255 else
256 {
257 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
258 d->domain_id, current->domain->domain_id, smp_processor_id());
259 }
261 domain_shutdown(d, SHUTDOWN_crash);
262 }
265 void __domain_crash_synchronous(void)
266 {
267 __domain_crash(current->domain);
269 /*
270 * Flush multicall state before dying if a multicall is in progress.
271 * This shouldn't be necessary, but some architectures are calling
272 * domain_crash_synchronous() when they really shouldn't (i.e., from
273 * within hypercall context).
274 */
275 if ( this_cpu(mc_state).flags != 0 )
276 {
277 dprintk(XENLOG_ERR,
278 "FIXME: synchronous domain crash during a multicall!\n");
279 this_cpu(mc_state).flags = 0;
280 }
282 for ( ; ; )
283 do_softirq();
284 }
287 void domain_shutdown(struct domain *d, u8 reason)
288 {
289 struct vcpu *v;
291 if ( d->domain_id == 0 )
292 dom0_shutdown(reason);
294 if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
295 d->shutdown_code = reason;
297 for_each_vcpu ( d, v )
298 vcpu_sleep_nosync(v);
300 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
301 }
304 void domain_pause_for_debugger(void)
305 {
306 struct domain *d = current->domain;
307 struct vcpu *v;
309 set_bit(_DOMF_ctrl_pause, &d->domain_flags);
311 for_each_vcpu ( d, v )
312 vcpu_sleep_nosync(v);
314 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
315 }
318 /* Release resources belonging to task @p. */
319 void domain_destroy(struct domain *d)
320 {
321 struct domain **pd;
322 atomic_t old, new;
324 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
326 /* May be already destroyed, or get_domain() can race us. */
327 _atomic_set(old, 0);
328 _atomic_set(new, DOMAIN_DESTROYED);
329 old = atomic_compareandswap(old, new, &d->refcnt);
330 if ( _atomic_read(old) != 0 )
331 return;
333 /* Delete from task list and task hashtable. */
334 write_lock(&domlist_lock);
335 pd = &domain_list;
336 while ( *pd != d )
337 pd = &(*pd)->next_in_list;
338 *pd = d->next_in_list;
339 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
340 while ( *pd != d )
341 pd = &(*pd)->next_in_hashbucket;
342 *pd = d->next_in_hashbucket;
343 write_unlock(&domlist_lock);
345 rangeset_domain_destroy(d);
347 evtchn_destroy(d);
348 grant_table_destroy(d);
350 arch_domain_destroy(d);
352 free_domain(d);
354 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
355 }
357 static void vcpu_pause_setup(struct vcpu *v)
358 {
359 spin_lock(&v->pause_lock);
360 if ( v->pause_count++ == 0 )
361 set_bit(_VCPUF_paused, &v->vcpu_flags);
362 spin_unlock(&v->pause_lock);
363 }
365 void vcpu_pause(struct vcpu *v)
366 {
367 ASSERT(v != current);
368 vcpu_pause_setup(v);
369 vcpu_sleep_sync(v);
370 }
372 void vcpu_pause_nosync(struct vcpu *v)
373 {
374 vcpu_pause_setup(v);
375 vcpu_sleep_nosync(v);
376 }
378 void vcpu_unpause(struct vcpu *v)
379 {
380 int wake;
382 ASSERT(v != current);
384 spin_lock(&v->pause_lock);
385 wake = (--v->pause_count == 0);
386 if ( wake )
387 clear_bit(_VCPUF_paused, &v->vcpu_flags);
388 spin_unlock(&v->pause_lock);
390 if ( wake )
391 vcpu_wake(v);
392 }
394 void domain_pause(struct domain *d)
395 {
396 struct vcpu *v;
398 ASSERT(d != current->domain);
400 spin_lock(&d->pause_lock);
401 if ( d->pause_count++ == 0 )
402 set_bit(_DOMF_paused, &d->domain_flags);
403 spin_unlock(&d->pause_lock);
405 for_each_vcpu( d, v )
406 vcpu_sleep_sync(v);
407 }
409 void domain_unpause(struct domain *d)
410 {
411 struct vcpu *v;
412 int wake;
414 ASSERT(d != current->domain);
416 spin_lock(&d->pause_lock);
417 wake = (--d->pause_count == 0);
418 if ( wake )
419 clear_bit(_DOMF_paused, &d->domain_flags);
420 spin_unlock(&d->pause_lock);
422 if ( wake )
423 for_each_vcpu( d, v )
424 vcpu_wake(v);
425 }
427 void domain_pause_by_systemcontroller(struct domain *d)
428 {
429 struct vcpu *v;
431 BUG_ON(current->domain == d);
433 if ( !test_and_set_bit(_DOMF_ctrl_pause, &d->domain_flags) )
434 {
435 for_each_vcpu ( d, v )
436 vcpu_sleep_sync(v);
437 }
438 }
440 void domain_unpause_by_systemcontroller(struct domain *d)
441 {
442 struct vcpu *v;
444 if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
445 {
446 for_each_vcpu ( d, v )
447 vcpu_wake(v);
448 }
449 }
451 int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
452 {
453 struct vcpu *v = d->vcpu[vcpuid];
455 BUG_ON(test_bit(_VCPUF_initialised, &v->vcpu_flags));
457 return arch_set_info_guest(v, ctxt);
458 }
460 int vcpu_reset(struct vcpu *v)
461 {
462 struct domain *d = v->domain;
463 int rc;
465 domain_pause(d);
466 LOCK_BIGLOCK(d);
468 rc = arch_vcpu_reset(v);
469 if ( rc != 0 )
470 goto out;
472 set_bit(_VCPUF_down, &v->vcpu_flags);
474 clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
475 clear_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags);
476 clear_bit(_VCPUF_blocked, &v->vcpu_flags);
477 clear_bit(_VCPUF_initialised, &v->vcpu_flags);
478 clear_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
479 clear_bit(_VCPUF_nmi_masked, &v->vcpu_flags);
480 clear_bit(_VCPUF_polling, &v->vcpu_flags);
482 out:
483 UNLOCK_BIGLOCK(v->domain);
484 domain_unpause(d);
486 return rc;
487 }
490 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
491 {
492 struct domain *d = current->domain;
493 struct vcpu *v;
494 struct vcpu_guest_context *ctxt;
495 long rc = 0;
497 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
498 return -EINVAL;
500 if ( (v = d->vcpu[vcpuid]) == NULL )
501 return -ENOENT;
503 switch ( cmd )
504 {
505 case VCPUOP_initialise:
506 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
507 {
508 rc = -ENOMEM;
509 break;
510 }
512 if ( copy_from_guest(ctxt, arg, 1) )
513 {
514 xfree(ctxt);
515 rc = -EFAULT;
516 break;
517 }
519 LOCK_BIGLOCK(d);
520 rc = -EEXIST;
521 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
522 rc = boot_vcpu(d, vcpuid, ctxt);
523 UNLOCK_BIGLOCK(d);
525 xfree(ctxt);
526 break;
528 case VCPUOP_up:
529 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
530 rc = -EINVAL;
531 else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) )
532 vcpu_wake(v);
533 break;
535 case VCPUOP_down:
536 if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
537 vcpu_sleep_nosync(v);
538 break;
540 case VCPUOP_is_up:
541 rc = !test_bit(_VCPUF_down, &v->vcpu_flags);
542 break;
544 case VCPUOP_get_runstate_info:
545 {
546 struct vcpu_runstate_info runstate;
547 vcpu_runstate_get(v, &runstate);
548 if ( copy_to_guest(arg, &runstate, 1) )
549 rc = -EFAULT;
550 break;
551 }
553 default:
554 rc = arch_do_vcpu_op(cmd, v, arg);
555 break;
556 }
558 return rc;
559 }
561 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
562 {
563 if ( type > MAX_VMASST_TYPE )
564 return -EINVAL;
566 switch ( cmd )
567 {
568 case VMASST_CMD_enable:
569 set_bit(type, &p->vm_assist);
570 return 0;
571 case VMASST_CMD_disable:
572 clear_bit(type, &p->vm_assist);
573 return 0;
574 }
576 return -ENOSYS;
577 }
579 /*
580 * Local variables:
581 * mode: C
582 * c-set-style: "BSD"
583 * c-basic-offset: 4
584 * tab-width: 4
585 * indent-tabs-mode: nil
586 * End:
587 */