debuggers.hg

view xen/common/domain.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents e8acb9753ff1
children 700ac6445812
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/ctype.h>
12 #include <xen/errno.h>
13 #include <xen/sched.h>
14 #include <xen/domain.h>
15 #include <xen/mm.h>
16 #include <xen/event.h>
17 #include <xen/time.h>
18 #include <xen/console.h>
19 #include <xen/softirq.h>
20 #include <xen/tasklet.h>
21 #include <xen/domain_page.h>
22 #include <xen/rangeset.h>
23 #include <xen/guest_access.h>
24 #include <xen/hypercall.h>
25 #include <xen/delay.h>
26 #include <xen/shutdown.h>
27 #include <xen/percpu.h>
28 #include <xen/multicall.h>
29 #include <xen/rcupdate.h>
30 #include <xen/wait.h>
31 #include <acpi/cpufreq/cpufreq.h>
32 #include <asm/debugger.h>
33 #include <public/sched.h>
34 #include <public/sysctl.h>
35 #include <public/vcpu.h>
36 #include <xsm/xsm.h>
37 #include <xen/trace.h>
38 #include <xen/tmem.h>
40 /* Linux config option: propageted to domain0 */
41 /* xen_processor_pmbits: xen control Cx, Px, ... */
42 unsigned int xen_processor_pmbits = XEN_PROCESSOR_PM_PX;
44 /* opt_dom0_vcpus_pin: If true, dom0 VCPUs are pinned. */
45 static bool_t opt_dom0_vcpus_pin;
46 boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin);
48 /* set xen as default cpufreq */
49 enum cpufreq_controller cpufreq_controller = FREQCTL_xen;
51 static void __init setup_cpufreq_option(char *str)
52 {
53 char *arg;
55 if ( !strcmp(str, "dom0-kernel") )
56 {
57 xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
58 cpufreq_controller = FREQCTL_dom0_kernel;
59 opt_dom0_vcpus_pin = 1;
60 return;
61 }
63 if ( !strcmp(str, "none") )
64 {
65 xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
66 cpufreq_controller = FREQCTL_none;
67 return;
68 }
70 if ( (arg = strpbrk(str, ",:")) != NULL )
71 *arg++ = '\0';
73 if ( !strcmp(str, "xen") )
74 if ( arg && *arg )
75 cpufreq_cmdline_parse(arg);
76 }
77 custom_param("cpufreq", setup_cpufreq_option);
79 /* Protect updates/reads (resp.) of domain_list and domain_hash. */
80 DEFINE_SPINLOCK(domlist_update_lock);
81 DEFINE_RCU_READ_LOCK(domlist_read_lock);
83 #define DOMAIN_HASH_SIZE 256
84 #define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
85 static struct domain *domain_hash[DOMAIN_HASH_SIZE];
86 struct domain *domain_list;
88 struct domain *dom0;
90 struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
92 vcpu_info_t dummy_vcpu_info;
94 int current_domain_id(void)
95 {
96 return current->domain->domain_id;
97 }
99 static void __domain_finalise_shutdown(struct domain *d)
100 {
101 struct vcpu *v;
103 BUG_ON(!spin_is_locked(&d->shutdown_lock));
105 if ( d->is_shut_down )
106 return;
108 for_each_vcpu ( d, v )
109 if ( !v->paused_for_shutdown )
110 return;
112 d->is_shut_down = 1;
113 if ( (d->shutdown_code == SHUTDOWN_suspend) && d->suspend_evtchn )
114 evtchn_send(d, d->suspend_evtchn);
115 else
116 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
117 }
119 static void vcpu_check_shutdown(struct vcpu *v)
120 {
121 struct domain *d = v->domain;
123 spin_lock(&d->shutdown_lock);
125 if ( d->is_shutting_down )
126 {
127 if ( !v->paused_for_shutdown )
128 vcpu_pause_nosync(v);
129 v->paused_for_shutdown = 1;
130 v->defer_shutdown = 0;
131 __domain_finalise_shutdown(d);
132 }
134 spin_unlock(&d->shutdown_lock);
135 }
137 struct vcpu *alloc_vcpu(
138 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
139 {
140 struct vcpu *v;
142 BUG_ON((!is_idle_domain(d) || vcpu_id) && d->vcpu[vcpu_id]);
144 if ( (v = alloc_vcpu_struct()) == NULL )
145 return NULL;
147 v->domain = d;
148 v->vcpu_id = vcpu_id;
150 spin_lock_init(&v->virq_lock);
152 tasklet_init(&v->continue_hypercall_tasklet, NULL, 0);
154 if ( is_idle_domain(d) )
155 {
156 v->runstate.state = RUNSTATE_running;
157 }
158 else
159 {
160 v->runstate.state = RUNSTATE_offline;
161 v->runstate.state_entry_time = NOW();
162 set_bit(_VPF_down, &v->pause_flags);
163 v->vcpu_info = ((vcpu_id < XEN_LEGACY_MAX_VCPUS)
164 ? (vcpu_info_t *)&shared_info(d, vcpu_info[vcpu_id])
165 : &dummy_vcpu_info);
166 init_waitqueue_vcpu(v);
167 }
169 if ( sched_init_vcpu(v, cpu_id) != 0 )
170 {
171 destroy_waitqueue_vcpu(v);
172 free_vcpu_struct(v);
173 return NULL;
174 }
176 if ( vcpu_initialise(v) != 0 )
177 {
178 sched_destroy_vcpu(v);
179 destroy_waitqueue_vcpu(v);
180 free_vcpu_struct(v);
181 return NULL;
182 }
184 d->vcpu[vcpu_id] = v;
185 if ( vcpu_id != 0 )
186 {
187 int prev_id = v->vcpu_id - 1;
188 while ( (prev_id >= 0) && (d->vcpu[prev_id] == NULL) )
189 prev_id--;
190 BUG_ON(prev_id < 0);
191 v->next_in_list = d->vcpu[prev_id]->next_in_list;
192 d->vcpu[prev_id]->next_in_list = v;
193 }
195 /* Must be called after making new vcpu visible to for_each_vcpu(). */
196 vcpu_check_shutdown(v);
198 domain_update_node_affinity(d);
200 return v;
201 }
203 static unsigned int __read_mostly extra_dom0_irqs = 256;
204 static unsigned int __read_mostly extra_domU_irqs = 32;
205 static void __init parse_extra_guest_irqs(const char *s)
206 {
207 if ( isdigit(*s) )
208 extra_domU_irqs = simple_strtoul(s, &s, 0);
209 if ( *s == ',' && isdigit(*++s) )
210 extra_dom0_irqs = simple_strtoul(s, &s, 0);
211 }
212 custom_param("extra_guest_irqs", parse_extra_guest_irqs);
214 struct domain *domain_create(
215 domid_t domid, unsigned int domcr_flags, ssidref_t ssidref)
216 {
217 struct domain *d, **pd;
218 enum { INIT_xsm = 1u<<0, INIT_watchdog = 1u<<1, INIT_rangeset = 1u<<2,
219 INIT_evtchn = 1u<<3, INIT_gnttab = 1u<<4, INIT_arch = 1u<<5 };
220 int init_status = 0;
221 int poolid = CPUPOOLID_NONE;
223 if ( (d = alloc_domain_struct()) == NULL )
224 return NULL;
226 d->domain_id = domid;
228 lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain");
230 if ( xsm_alloc_security_domain(d) != 0 )
231 goto fail;
232 init_status |= INIT_xsm;
234 watchdog_domain_init(d);
235 init_status |= INIT_watchdog;
237 atomic_set(&d->refcnt, 1);
238 spin_lock_init_prof(d, domain_lock);
239 spin_lock_init_prof(d, page_alloc_lock);
240 spin_lock_init(&d->hypercall_deadlock_mutex);
241 INIT_PAGE_LIST_HEAD(&d->page_list);
242 INIT_PAGE_LIST_HEAD(&d->xenpage_list);
244 spin_lock_init(&d->node_affinity_lock);
246 spin_lock_init(&d->shutdown_lock);
247 d->shutdown_code = -1;
249 if ( domcr_flags & DOMCRF_hvm )
250 d->is_hvm = 1;
252 if ( domid == 0 )
253 {
254 d->is_pinned = opt_dom0_vcpus_pin;
255 d->disable_migrate = 1;
256 }
258 rangeset_domain_initialise(d);
259 init_status |= INIT_rangeset;
261 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
262 d->irq_caps = rangeset_new(d, "Interrupts", 0);
263 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
264 goto fail;
266 if ( domcr_flags & DOMCRF_dummy )
267 return d;
269 if ( !is_idle_domain(d) )
270 {
271 if ( xsm_domain_create(d, ssidref) != 0 )
272 goto fail;
274 d->is_paused_by_controller = 1;
275 atomic_inc(&d->pause_count);
277 if ( domid )
278 d->nr_pirqs = nr_irqs_gsi + extra_domU_irqs;
279 else
280 d->nr_pirqs = nr_irqs_gsi + extra_dom0_irqs;
281 if ( d->nr_pirqs > nr_irqs )
282 d->nr_pirqs = nr_irqs;
284 d->pirq_to_evtchn = xmalloc_array(u16, d->nr_pirqs);
285 d->pirq_mask = xmalloc_array(
286 unsigned long, BITS_TO_LONGS(d->nr_pirqs));
287 if ( (d->pirq_to_evtchn == NULL) || (d->pirq_mask == NULL) )
288 goto fail;
289 memset(d->pirq_to_evtchn, 0, d->nr_pirqs * sizeof(*d->pirq_to_evtchn));
290 bitmap_zero(d->pirq_mask, d->nr_pirqs);
292 if ( evtchn_init(d) != 0 )
293 goto fail;
294 init_status |= INIT_evtchn;
296 if ( grant_table_create(d) != 0 )
297 goto fail;
298 init_status |= INIT_gnttab;
300 poolid = 0;
301 }
303 if ( arch_domain_create(d, domcr_flags) != 0 )
304 goto fail;
305 init_status |= INIT_arch;
307 if ( cpupool_add_domain(d, poolid) != 0 )
308 goto fail;
310 if ( sched_init_domain(d) != 0 )
311 goto fail;
313 if ( !is_idle_domain(d) )
314 {
315 spin_lock(&domlist_update_lock);
316 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
317 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
318 if ( (*pd)->domain_id > d->domain_id )
319 break;
320 d->next_in_list = *pd;
321 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
322 rcu_assign_pointer(*pd, d);
323 rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d);
324 spin_unlock(&domlist_update_lock);
325 }
327 return d;
329 fail:
330 d->is_dying = DOMDYING_dead;
331 atomic_set(&d->refcnt, DOMAIN_DESTROYED);
332 if ( init_status & INIT_arch )
333 arch_domain_destroy(d);
334 if ( init_status & INIT_gnttab )
335 grant_table_destroy(d);
336 if ( init_status & INIT_evtchn )
337 {
338 evtchn_destroy(d);
339 evtchn_destroy_final(d);
340 }
341 if ( init_status & INIT_rangeset )
342 rangeset_domain_destroy(d);
343 if ( init_status & INIT_watchdog )
344 watchdog_domain_destroy(d);
345 if ( init_status & INIT_xsm )
346 xsm_free_security_domain(d);
347 xfree(d->pirq_mask);
348 xfree(d->pirq_to_evtchn);
349 free_domain_struct(d);
350 return NULL;
351 }
354 void domain_update_node_affinity(struct domain *d)
355 {
356 cpumask_t cpumask = CPU_MASK_NONE;
357 nodemask_t nodemask = NODE_MASK_NONE;
358 struct vcpu *v;
359 unsigned int node;
361 spin_lock(&d->node_affinity_lock);
363 for_each_vcpu ( d, v )
364 cpus_or(cpumask, cpumask, v->cpu_affinity);
366 for_each_online_node ( node )
367 if ( cpus_intersects(node_to_cpumask(node), cpumask) )
368 node_set(node, nodemask);
370 d->node_affinity = nodemask;
371 spin_unlock(&d->node_affinity_lock);
372 }
375 struct domain *get_domain_by_id(domid_t dom)
376 {
377 struct domain *d;
379 rcu_read_lock(&domlist_read_lock);
381 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
382 d != NULL;
383 d = rcu_dereference(d->next_in_hashbucket) )
384 {
385 if ( d->domain_id == dom )
386 {
387 if ( unlikely(!get_domain(d)) )
388 d = NULL;
389 break;
390 }
391 }
393 rcu_read_unlock(&domlist_read_lock);
395 return d;
396 }
399 struct domain *rcu_lock_domain_by_id(domid_t dom)
400 {
401 struct domain *d = NULL;
403 rcu_read_lock(&domlist_read_lock);
405 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
406 d != NULL;
407 d = rcu_dereference(d->next_in_hashbucket) )
408 {
409 if ( d->domain_id == dom )
410 {
411 rcu_lock_domain(d);
412 break;
413 }
414 }
416 rcu_read_unlock(&domlist_read_lock);
418 return d;
419 }
421 int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d)
422 {
423 if ( dom == DOMID_SELF )
424 {
425 *d = rcu_lock_current_domain();
426 return 0;
427 }
429 if ( (*d = rcu_lock_domain_by_id(dom)) == NULL )
430 return -ESRCH;
432 if ( !IS_PRIV_FOR(current->domain, *d) )
433 {
434 rcu_unlock_domain(*d);
435 return -EPERM;
436 }
438 return 0;
439 }
441 int domain_kill(struct domain *d)
442 {
443 int rc = 0;
445 if ( d == current->domain )
446 return -EINVAL;
448 /* Protected by domctl_lock. */
449 switch ( d->is_dying )
450 {
451 case DOMDYING_alive:
452 domain_pause(d);
453 d->is_dying = DOMDYING_dying;
454 spin_barrier(&d->domain_lock);
455 evtchn_destroy(d);
456 gnttab_release_mappings(d);
457 tmem_destroy(d->tmem);
458 d->tmem = NULL;
459 /* fallthrough */
460 case DOMDYING_dying:
461 rc = domain_relinquish_resources(d);
462 if ( rc != 0 )
463 {
464 BUG_ON(rc != -EAGAIN);
465 break;
466 }
467 d->is_dying = DOMDYING_dead;
468 put_domain(d);
469 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
470 /* fallthrough */
471 case DOMDYING_dead:
472 break;
473 }
475 return rc;
476 }
479 void __domain_crash(struct domain *d)
480 {
481 if ( d->is_shutting_down )
482 {
483 /* Print nothing: the domain is already shutting down. */
484 }
485 else if ( d == current->domain )
486 {
487 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
488 d->domain_id, current->vcpu_id, smp_processor_id());
489 show_execution_state(guest_cpu_user_regs());
490 }
491 else
492 {
493 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
494 d->domain_id, current->domain->domain_id, smp_processor_id());
495 }
497 domain_shutdown(d, SHUTDOWN_crash);
498 }
501 void __domain_crash_synchronous(void)
502 {
503 __domain_crash(current->domain);
505 vcpu_end_shutdown_deferral(current);
507 for ( ; ; )
508 do_softirq();
509 }
512 void domain_shutdown(struct domain *d, u8 reason)
513 {
514 struct vcpu *v;
516 spin_lock(&d->shutdown_lock);
518 if ( d->shutdown_code == -1 )
519 d->shutdown_code = reason;
520 reason = d->shutdown_code;
522 if ( d->domain_id == 0 )
523 dom0_shutdown(reason);
525 if ( d->is_shutting_down )
526 {
527 spin_unlock(&d->shutdown_lock);
528 return;
529 }
531 d->is_shutting_down = 1;
533 smp_mb(); /* set shutdown status /then/ check for per-cpu deferrals */
535 for_each_vcpu ( d, v )
536 {
537 if ( reason == SHUTDOWN_crash )
538 v->defer_shutdown = 0;
539 else if ( v->defer_shutdown )
540 continue;
541 vcpu_pause_nosync(v);
542 v->paused_for_shutdown = 1;
543 }
545 __domain_finalise_shutdown(d);
547 spin_unlock(&d->shutdown_lock);
548 }
550 void domain_resume(struct domain *d)
551 {
552 struct vcpu *v;
554 /*
555 * Some code paths assume that shutdown status does not get reset under
556 * their feet (e.g., some assertions make this assumption).
557 */
558 domain_pause(d);
560 spin_lock(&d->shutdown_lock);
562 d->is_shutting_down = d->is_shut_down = 0;
563 d->shutdown_code = -1;
565 for_each_vcpu ( d, v )
566 {
567 if ( v->paused_for_shutdown )
568 vcpu_unpause(v);
569 v->paused_for_shutdown = 0;
570 }
572 spin_unlock(&d->shutdown_lock);
574 domain_unpause(d);
575 }
577 int vcpu_start_shutdown_deferral(struct vcpu *v)
578 {
579 if ( v->defer_shutdown )
580 return 1;
582 v->defer_shutdown = 1;
583 smp_mb(); /* set deferral status /then/ check for shutdown */
584 if ( unlikely(v->domain->is_shutting_down) )
585 vcpu_check_shutdown(v);
587 return v->defer_shutdown;
588 }
590 void vcpu_end_shutdown_deferral(struct vcpu *v)
591 {
592 v->defer_shutdown = 0;
593 smp_mb(); /* clear deferral status /then/ check for shutdown */
594 if ( unlikely(v->domain->is_shutting_down) )
595 vcpu_check_shutdown(v);
596 }
598 void domain_pause_for_debugger(void)
599 {
600 struct domain *d = current->domain;
601 struct vcpu *v;
603 atomic_inc(&d->pause_count);
604 if ( test_and_set_bool(d->is_paused_by_controller) )
605 domain_unpause(d); /* race-free atomic_dec(&d->pause_count) */
607 for_each_vcpu ( d, v )
608 vcpu_sleep_nosync(v);
610 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
611 }
613 /* Complete domain destroy after RCU readers are not holding old references. */
614 static void complete_domain_destroy(struct rcu_head *head)
615 {
616 struct domain *d = container_of(head, struct domain, rcu);
617 struct vcpu *v;
618 int i;
620 for ( i = d->max_vcpus - 1; i >= 0; i-- )
621 {
622 if ( (v = d->vcpu[i]) == NULL )
623 continue;
624 tasklet_kill(&v->continue_hypercall_tasklet);
625 vcpu_destroy(v);
626 sched_destroy_vcpu(v);
627 destroy_waitqueue_vcpu(v);
628 }
630 grant_table_destroy(d);
632 arch_domain_destroy(d);
634 watchdog_domain_destroy(d);
636 rangeset_domain_destroy(d);
638 cpupool_rm_domain(d);
640 sched_destroy_domain(d);
642 /* Free page used by xen oprofile buffer. */
643 free_xenoprof_pages(d);
645 for ( i = d->max_vcpus - 1; i >= 0; i-- )
646 if ( (v = d->vcpu[i]) != NULL )
647 free_vcpu_struct(v);
649 if ( d->target != NULL )
650 put_domain(d->target);
652 evtchn_destroy_final(d);
654 xfree(d->pirq_mask);
655 xfree(d->pirq_to_evtchn);
657 xsm_free_security_domain(d);
658 free_domain_struct(d);
660 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
661 }
663 /* Release resources belonging to task @p. */
664 void domain_destroy(struct domain *d)
665 {
666 struct domain **pd;
667 atomic_t old, new;
669 BUG_ON(!d->is_dying);
671 /* May be already destroyed, or get_domain() can race us. */
672 _atomic_set(old, 0);
673 _atomic_set(new, DOMAIN_DESTROYED);
674 old = atomic_compareandswap(old, new, &d->refcnt);
675 if ( _atomic_read(old) != 0 )
676 return;
678 /* Delete from task list and task hashtable. */
679 TRACE_1D(TRC_SCHED_DOM_REM, d->domain_id);
680 spin_lock(&domlist_update_lock);
681 pd = &domain_list;
682 while ( *pd != d )
683 pd = &(*pd)->next_in_list;
684 rcu_assign_pointer(*pd, d->next_in_list);
685 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
686 while ( *pd != d )
687 pd = &(*pd)->next_in_hashbucket;
688 rcu_assign_pointer(*pd, d->next_in_hashbucket);
689 spin_unlock(&domlist_update_lock);
691 /* Schedule RCU asynchronous completion of domain destroy. */
692 call_rcu(&d->rcu, complete_domain_destroy);
693 }
695 void vcpu_pause(struct vcpu *v)
696 {
697 ASSERT(v != current);
698 atomic_inc(&v->pause_count);
699 vcpu_sleep_sync(v);
700 }
702 void vcpu_pause_nosync(struct vcpu *v)
703 {
704 atomic_inc(&v->pause_count);
705 vcpu_sleep_nosync(v);
706 }
708 void vcpu_unpause(struct vcpu *v)
709 {
710 if ( atomic_dec_and_test(&v->pause_count) )
711 vcpu_wake(v);
712 }
714 void domain_pause(struct domain *d)
715 {
716 struct vcpu *v;
718 ASSERT(d != current->domain);
720 atomic_inc(&d->pause_count);
722 for_each_vcpu( d, v )
723 vcpu_sleep_sync(v);
724 }
726 void domain_unpause(struct domain *d)
727 {
728 struct vcpu *v;
730 if ( atomic_dec_and_test(&d->pause_count) )
731 for_each_vcpu( d, v )
732 vcpu_wake(v);
733 }
735 void domain_pause_by_systemcontroller(struct domain *d)
736 {
737 domain_pause(d);
738 if ( test_and_set_bool(d->is_paused_by_controller) )
739 domain_unpause(d);
740 }
742 void domain_unpause_by_systemcontroller(struct domain *d)
743 {
744 if ( test_and_clear_bool(d->is_paused_by_controller) )
745 domain_unpause(d);
746 }
748 int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
749 {
750 struct vcpu *v = d->vcpu[vcpuid];
752 BUG_ON(v->is_initialised);
754 return arch_set_info_guest(v, ctxt);
755 }
757 void vcpu_reset(struct vcpu *v)
758 {
759 struct domain *d = v->domain;
761 vcpu_pause(v);
762 domain_lock(d);
764 arch_vcpu_reset(v);
766 set_bit(_VPF_down, &v->pause_flags);
768 clear_bit(v->vcpu_id, d->poll_mask);
769 v->poll_evtchn = 0;
771 v->fpu_initialised = 0;
772 v->fpu_dirtied = 0;
773 v->is_initialised = 0;
774 #ifdef VCPU_TRAP_LAST
775 v->async_exception_mask = 0;
776 memset(v->async_exception_state, 0, sizeof(v->async_exception_state));
777 #endif
778 cpus_clear(v->cpu_affinity_tmp);
779 clear_bit(_VPF_blocked, &v->pause_flags);
781 domain_unlock(v->domain);
782 vcpu_unpause(v);
783 }
786 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
787 {
788 struct domain *d = current->domain;
789 struct vcpu *v;
790 struct vcpu_guest_context *ctxt;
791 long rc = 0;
793 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
794 return -EINVAL;
796 if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
797 return -ENOENT;
799 switch ( cmd )
800 {
801 case VCPUOP_initialise:
802 if ( v->vcpu_info == &dummy_vcpu_info )
803 return -EINVAL;
805 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
806 return -ENOMEM;
808 if ( copy_from_guest(ctxt, arg, 1) )
809 {
810 xfree(ctxt);
811 return -EFAULT;
812 }
814 domain_lock(d);
815 rc = -EEXIST;
816 if ( !v->is_initialised )
817 rc = boot_vcpu(d, vcpuid, ctxt);
818 domain_unlock(d);
820 xfree(ctxt);
821 break;
823 case VCPUOP_up:
824 if ( !v->is_initialised )
825 return -EINVAL;
827 if ( test_and_clear_bit(_VPF_down, &v->pause_flags) )
828 vcpu_wake(v);
830 break;
832 case VCPUOP_down:
833 if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
834 vcpu_sleep_nosync(v);
835 break;
837 case VCPUOP_is_up:
838 rc = !test_bit(_VPF_down, &v->pause_flags);
839 break;
841 case VCPUOP_get_runstate_info:
842 {
843 struct vcpu_runstate_info runstate;
844 vcpu_runstate_get(v, &runstate);
845 if ( copy_to_guest(arg, &runstate, 1) )
846 rc = -EFAULT;
847 break;
848 }
850 case VCPUOP_set_periodic_timer:
851 {
852 struct vcpu_set_periodic_timer set;
854 if ( copy_from_guest(&set, arg, 1) )
855 return -EFAULT;
857 if ( set.period_ns < MILLISECS(1) )
858 return -EINVAL;
860 v->periodic_period = set.period_ns;
861 vcpu_force_reschedule(v);
863 break;
864 }
866 case VCPUOP_stop_periodic_timer:
867 v->periodic_period = 0;
868 vcpu_force_reschedule(v);
869 break;
871 case VCPUOP_set_singleshot_timer:
872 {
873 struct vcpu_set_singleshot_timer set;
875 if ( v != current )
876 return -EINVAL;
878 if ( copy_from_guest(&set, arg, 1) )
879 return -EFAULT;
881 if ( (set.flags & VCPU_SSHOTTMR_future) &&
882 (set.timeout_abs_ns < NOW()) )
883 return -ETIME;
885 migrate_timer(&v->singleshot_timer, smp_processor_id());
886 set_timer(&v->singleshot_timer, set.timeout_abs_ns);
888 break;
889 }
891 case VCPUOP_stop_singleshot_timer:
892 if ( v != current )
893 return -EINVAL;
895 stop_timer(&v->singleshot_timer);
897 break;
899 #ifdef VCPU_TRAP_NMI
900 case VCPUOP_send_nmi:
901 if ( !guest_handle_is_null(arg) )
902 return -EINVAL;
904 if ( !test_and_set_bool(v->nmi_pending) )
905 vcpu_kick(v);
907 break;
908 #endif
910 default:
911 rc = arch_do_vcpu_op(cmd, v, arg);
912 break;
913 }
915 return rc;
916 }
918 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
919 {
920 if ( type > MAX_VMASST_TYPE )
921 return -EINVAL;
923 switch ( cmd )
924 {
925 case VMASST_CMD_enable:
926 set_bit(type, &p->vm_assist);
927 return 0;
928 case VMASST_CMD_disable:
929 clear_bit(type, &p->vm_assist);
930 return 0;
931 }
933 return -ENOSYS;
934 }
936 struct migrate_info {
937 long (*func)(void *data);
938 void *data;
939 struct vcpu *vcpu;
940 unsigned int cpu;
941 unsigned int nest;
942 };
944 static DEFINE_PER_CPU(struct migrate_info *, continue_info);
946 static void continue_hypercall_tasklet_handler(unsigned long _info)
947 {
948 struct migrate_info *info = (struct migrate_info *)_info;
949 struct vcpu *v = info->vcpu;
951 /* Wait for vcpu to sleep so that we can access its register state. */
952 vcpu_sleep_sync(v);
954 this_cpu(continue_info) = info;
955 return_reg(v) = (info->cpu == smp_processor_id())
956 ? info->func(info->data) : -EINVAL;
957 this_cpu(continue_info) = NULL;
959 if ( info->nest-- == 0 )
960 {
961 xfree(info);
962 vcpu_unpause(v);
963 put_domain(v->domain);
964 }
965 }
967 int continue_hypercall_on_cpu(
968 unsigned int cpu, long (*func)(void *data), void *data)
969 {
970 struct migrate_info *info;
972 if ( (cpu >= NR_CPUS) || !cpu_online(cpu) )
973 return -EINVAL;
975 info = this_cpu(continue_info);
976 if ( info == NULL )
977 {
978 struct vcpu *curr = current;
980 info = xmalloc(struct migrate_info);
981 if ( info == NULL )
982 return -ENOMEM;
984 info->vcpu = curr;
985 info->nest = 0;
987 tasklet_kill(
988 &curr->continue_hypercall_tasklet);
989 tasklet_init(
990 &curr->continue_hypercall_tasklet,
991 continue_hypercall_tasklet_handler,
992 (unsigned long)info);
994 get_knownalive_domain(curr->domain);
995 vcpu_pause_nosync(curr);
996 }
997 else
998 {
999 BUG_ON(info->nest != 0);
1000 info->nest++;
1003 info->func = func;
1004 info->data = data;
1005 info->cpu = cpu;
1007 tasklet_schedule_on_cpu(&info->vcpu->continue_hypercall_tasklet, cpu);
1009 /* Dummy return value will be overwritten by tasklet. */
1010 return 0;
1013 /*
1014 * Local variables:
1015 * mode: C
1016 * c-set-style: "BSD"
1017 * c-basic-offset: 4
1018 * tab-width: 4
1019 * indent-tabs-mode: nil
1020 * End:
1021 */