direct-io.hg

view xen/common/dom0_ops.c @ 3435:0fd048d86eed

bitkeeper revision 1.1159.220.3 (41e670c37jmaTxUns3KlvsbVRCg-UA)

The getdomaininfo hypercall now listens to the exec_domain parameter
that was already passed to it, and performs some basic sanity checking.

Added exec_domain (aka vcpu) parameters to xc_domain_getfullinfo()
and xc_domain_get_cpu_usage().
author mafetter@fleming.research
date Thu Jan 13 12:59:47 2005 +0000 (2005-01-13)
parents fd0d4d8e6193
children 6096356005ba
line source
1 /******************************************************************************
2 * dom0_ops.c
3 *
4 * Process command requests from domain-0 guest OS.
5 *
6 * Copyright (c) 2002, K A Fraser
7 */
9 #include <xen/config.h>
10 #include <xen/types.h>
11 #include <xen/lib.h>
12 #include <xen/mm.h>
13 #include <public/dom0_ops.h>
14 #include <xen/sched.h>
15 #include <xen/event.h>
16 #include <asm/domain_page.h>
17 #include <asm/pdb.h>
18 #include <xen/trace.h>
19 #include <xen/console.h>
20 #include <asm/shadow.h>
21 #include <public/sched_ctl.h>
23 #define TRC_DOM0OP_ENTER_BASE 0x00020000
24 #define TRC_DOM0OP_LEAVE_BASE 0x00030000
26 extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int);
27 extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
28 extern void arch_getdomaininfo_ctxt(
29 struct exec_domain *, full_execution_context_t *);
31 static inline int is_free_domid(domid_t dom)
32 {
33 struct domain *d;
35 if ( dom >= DOMID_FIRST_RESERVED )
36 return 0;
38 if ( (d = find_domain_by_id(dom)) == NULL )
39 return 1;
41 put_domain(d);
42 return 0;
43 }
45 /*
46 * Allocate a free domain id. We try to reuse domain ids in a fairly low range,
47 * only expanding the range when there are no free domain ids. This is to keep
48 * domain ids in a range depending on the number that exist simultaneously,
49 * rather than incrementing domain ids in the full 32-bit range.
50 */
51 static int allocate_domid(domid_t *pdom)
52 {
53 static spinlock_t domid_lock = SPIN_LOCK_UNLOCKED;
54 static domid_t curdom = 0;
55 static domid_t topdom = 101;
56 int err = 0;
57 domid_t dom;
59 spin_lock(&domid_lock);
61 /* Try to use a domain id in the range 0..topdom, starting at curdom. */
62 for ( dom = curdom + 1; dom != curdom; dom++ )
63 {
64 if ( dom == topdom )
65 dom = 1;
66 if ( is_free_domid(dom) )
67 goto exit;
68 }
70 /* Couldn't find a free domain id in 0..topdom, try higher. */
71 for ( dom = topdom; dom < DOMID_FIRST_RESERVED; dom++ )
72 {
73 if ( is_free_domid(dom) )
74 {
75 topdom = dom + 1;
76 goto exit;
77 }
78 }
80 /* No free domain ids. */
81 err = -ENOMEM;
83 exit:
84 if ( err == 0 )
85 {
86 curdom = dom;
87 *pdom = dom;
88 }
90 spin_unlock(&domid_lock);
91 return err;
92 }
94 long do_dom0_op(dom0_op_t *u_dom0_op)
95 {
96 long ret = 0;
97 dom0_op_t curop, *op = &curop;
99 if ( !IS_PRIV(current->domain) )
100 return -EPERM;
102 if ( copy_from_user(op, u_dom0_op, sizeof(*op)) )
103 return -EFAULT;
105 if ( op->interface_version != DOM0_INTERFACE_VERSION )
106 return -EACCES;
108 TRACE_5D(TRC_DOM0OP_ENTER_BASE + op->cmd,
109 0, op->u.dummy[0], op->u.dummy[1],
110 op->u.dummy[2], op->u.dummy[3] );
112 switch ( op->cmd )
113 {
115 case DOM0_BUILDDOMAIN:
116 {
117 struct domain *d = find_domain_by_id(op->u.builddomain.domain);
118 ret = -EINVAL;
119 if ( d != NULL )
120 {
121 ret = final_setup_guestos(d, &op->u.builddomain);
122 put_domain(d);
123 }
124 }
125 break;
127 case DOM0_PAUSEDOMAIN:
128 {
129 struct domain *d = find_domain_by_id(op->u.pausedomain.domain);
130 ret = -ESRCH;
131 if ( d != NULL )
132 {
133 ret = -EINVAL;
134 if ( d != current->domain )
135 {
136 domain_pause_by_systemcontroller(d);
137 ret = 0;
138 }
139 put_domain(d);
140 }
141 }
142 break;
144 case DOM0_UNPAUSEDOMAIN:
145 {
146 struct domain *d = find_domain_by_id(op->u.unpausedomain.domain);
147 ret = -ESRCH;
148 if ( d != NULL )
149 {
150 ret = -EINVAL;
151 if ( test_bit(DF_CONSTRUCTED, &d->d_flags) )
152 {
153 domain_unpause_by_systemcontroller(d);
154 ret = 0;
155 }
156 put_domain(d);
157 }
158 }
159 break;
161 case DOM0_CREATEDOMAIN:
162 {
163 struct domain *d;
164 unsigned int pro = 0;
165 domid_t dom;
167 dom = op->u.createdomain.domain;
168 if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
169 {
170 ret = -EINVAL;
171 if ( !is_free_domid(dom) )
172 break;
173 }
174 else if ( (ret = allocate_domid(&dom)) != 0 )
175 break;
177 if ( op->u.createdomain.cpu == -1 )
178 {
179 /* Do an initial placement. Pick the least-populated CPU. */
180 struct domain *d;
181 struct exec_domain *ed;
182 unsigned int i, cnt[NR_CPUS] = { 0 };
184 read_lock(&domlist_lock);
185 for_each_domain ( d ) {
186 for_each_exec_domain ( d, ed )
187 cnt[ed->processor]++;
188 }
189 read_unlock(&domlist_lock);
191 for ( i = 0; i < smp_num_cpus; i++ )
192 if ( cnt[i] < cnt[pro] )
193 pro = i;
194 }
195 else
196 pro = op->u.createdomain.cpu % smp_num_cpus;
198 ret = -ENOMEM;
199 if ( (d = do_createdomain(dom, pro)) == NULL )
200 break;
202 ret = alloc_new_dom_mem(d, op->u.createdomain.memory_kb);
203 if ( ret != 0 )
204 {
205 domain_kill(d);
206 break;
207 }
209 ret = 0;
211 op->u.createdomain.domain = d->id;
212 copy_to_user(u_dom0_op, op, sizeof(*op));
213 }
214 break;
216 case DOM0_DESTROYDOMAIN:
217 {
218 struct domain *d = find_domain_by_id(op->u.destroydomain.domain);
219 ret = -ESRCH;
220 if ( d != NULL )
221 {
222 ret = -EINVAL;
223 if ( d != current->domain )
224 {
225 domain_kill(d);
226 ret = 0;
227 }
228 put_domain(d);
229 }
230 }
231 break;
233 case DOM0_PINCPUDOMAIN:
234 {
235 domid_t dom = op->u.pincpudomain.domain;
236 struct domain *d = find_domain_by_id(dom);
237 struct exec_domain *ed;
238 int cpu = op->u.pincpudomain.cpu;
240 if ( d == NULL )
241 {
242 ret = -ESRCH;
243 break;
244 }
246 ed = d->exec_domain[op->u.pincpudomain.exec_domain];
247 if ( ed == NULL )
248 {
249 ret = -ESRCH;
250 put_domain(d);
251 break;
252 }
254 if ( ed == current )
255 {
256 ret = -EINVAL;
257 put_domain(d);
258 break;
259 }
261 if ( cpu == -1 )
262 {
263 clear_bit(EDF_CPUPINNED, &ed->ed_flags);
264 }
265 else
266 {
267 exec_domain_pause(ed);
268 synchronise_pagetables(~0UL);
269 if ( ed->processor != (cpu % smp_num_cpus) )
270 set_bit(EDF_MIGRATED, &ed->ed_flags);
271 set_bit(EDF_CPUPINNED, &ed->ed_flags);
272 ed->processor = cpu % smp_num_cpus;
273 exec_domain_unpause(ed);
274 }
276 put_domain(d);
277 }
278 break;
280 case DOM0_SCHEDCTL:
281 {
282 ret = sched_ctl(&op->u.schedctl);
283 copy_to_user(u_dom0_op, op, sizeof(*op));
284 }
285 break;
287 case DOM0_ADJUSTDOM:
288 {
289 ret = sched_adjdom(&op->u.adjustdom);
290 copy_to_user(u_dom0_op, op, sizeof(*op));
291 }
292 break;
294 case DOM0_GETMEMLIST:
295 {
296 int i;
297 struct domain *d = find_domain_by_id(op->u.getmemlist.domain);
298 unsigned long max_pfns = op->u.getmemlist.max_pfns;
299 unsigned long pfn;
300 unsigned long *buffer = op->u.getmemlist.buffer;
301 struct list_head *list_ent;
303 ret = -EINVAL;
304 if ( d != NULL )
305 {
306 ret = 0;
308 spin_lock(&d->page_alloc_lock);
309 list_ent = d->page_list.next;
310 for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
311 {
312 pfn = list_entry(list_ent, struct pfn_info, list) -
313 frame_table;
314 if ( put_user(pfn, buffer) )
315 {
316 ret = -EFAULT;
317 break;
318 }
319 buffer++;
320 list_ent = frame_table[pfn].list.next;
321 }
322 spin_unlock(&d->page_alloc_lock);
324 op->u.getmemlist.num_pfns = i;
325 copy_to_user(u_dom0_op, op, sizeof(*op));
327 put_domain(d);
328 }
329 }
330 break;
332 case DOM0_GETDOMAININFO:
333 {
334 full_execution_context_t *c;
335 struct domain *d;
336 struct exec_domain *ed;
338 read_lock(&domlist_lock);
340 for_each_domain ( d )
341 {
342 if ( d->id >= op->u.getdomaininfo.domain )
343 break;
344 }
346 if ( (d == NULL) || !get_domain(d) )
347 {
348 read_unlock(&domlist_lock);
349 ret = -ESRCH;
350 break;
351 }
353 read_unlock(&domlist_lock);
355 op->u.getdomaininfo.domain = d->id;
357 if ( (op->u.getdomaininfo.exec_domain >= MAX_VIRT_CPUS) ||
358 !d->exec_domain[op->u.getdomaininfo.exec_domain] )
359 {
360 ret = -EINVAL;
361 break;
362 }
364 ed = d->exec_domain[op->u.getdomaininfo.exec_domain];
366 op->u.getdomaininfo.flags =
367 (test_bit( DF_DYING, &d->d_flags) ? DOMFLAGS_DYING : 0) |
368 (test_bit( DF_CRASHED, &d->d_flags) ? DOMFLAGS_CRASHED : 0) |
369 (test_bit( DF_SHUTDOWN, &d->d_flags) ? DOMFLAGS_SHUTDOWN : 0) |
370 (test_bit(EDF_CTRLPAUSE, &ed->ed_flags) ? DOMFLAGS_PAUSED : 0) |
371 (test_bit(EDF_BLOCKED, &ed->ed_flags) ? DOMFLAGS_BLOCKED : 0) |
372 (test_bit(EDF_RUNNING, &ed->ed_flags) ? DOMFLAGS_RUNNING : 0);
374 op->u.getdomaininfo.flags |= ed->processor << DOMFLAGS_CPUSHIFT;
375 op->u.getdomaininfo.flags |=
376 d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
378 op->u.getdomaininfo.tot_pages = d->tot_pages;
379 op->u.getdomaininfo.max_pages = d->max_pages;
380 op->u.getdomaininfo.cpu_time = ed->cpu_time;
381 op->u.getdomaininfo.shared_info_frame =
382 __pa(d->shared_info) >> PAGE_SHIFT;
384 if ( op->u.getdomaininfo.ctxt != NULL )
385 {
386 if ( (c = xmalloc(sizeof(*c))) == NULL )
387 {
388 ret = -ENOMEM;
389 put_domain(d);
390 break;
391 }
393 if ( ed != current )
394 exec_domain_pause(ed);
396 arch_getdomaininfo_ctxt(ed,c);
398 if ( ed != current )
399 exec_domain_unpause(ed);
401 if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) )
402 ret = -EINVAL;
404 if ( c != NULL )
405 xfree(c);
406 }
408 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
409 ret = -EINVAL;
411 put_domain(d);
412 }
413 break;
415 case DOM0_GETPAGEFRAMEINFO:
416 {
417 struct pfn_info *page;
418 unsigned long pfn = op->u.getpageframeinfo.pfn;
419 domid_t dom = op->u.getpageframeinfo.domain;
420 struct domain *d;
422 ret = -EINVAL;
424 if ( unlikely(pfn >= max_page) ||
425 unlikely((d = find_domain_by_id(dom)) == NULL) )
426 break;
428 page = &frame_table[pfn];
430 if ( likely(get_page(page, d)) )
431 {
432 ret = 0;
434 op->u.getpageframeinfo.type = NOTAB;
436 if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
437 {
438 switch ( page->u.inuse.type_info & PGT_type_mask )
439 {
440 case PGT_l1_page_table:
441 op->u.getpageframeinfo.type = L1TAB;
442 break;
443 case PGT_l2_page_table:
444 op->u.getpageframeinfo.type = L2TAB;
445 break;
446 case PGT_l3_page_table:
447 op->u.getpageframeinfo.type = L3TAB;
448 break;
449 case PGT_l4_page_table:
450 op->u.getpageframeinfo.type = L4TAB;
451 break;
452 }
453 }
455 put_page(page);
456 }
458 put_domain(d);
460 copy_to_user(u_dom0_op, op, sizeof(*op));
461 }
462 break;
464 case DOM0_IOPL:
465 {
466 extern long do_iopl(domid_t, unsigned int);
467 ret = do_iopl(op->u.iopl.domain, op->u.iopl.iopl);
468 }
469 break;
471 #ifdef XEN_DEBUGGER
472 case DOM0_DEBUG:
473 {
474 pdb_do_debug(op);
475 copy_to_user(u_dom0_op, op, sizeof(*op));
476 ret = 0;
477 }
478 break;
479 #endif
481 case DOM0_SETTIME:
482 {
483 do_settime(op->u.settime.secs,
484 op->u.settime.usecs,
485 op->u.settime.system_time);
486 ret = 0;
487 }
488 break;
490 #ifdef TRACE_BUFFER
491 case DOM0_GETTBUFS:
492 {
493 ret = get_tb_info(&op->u.gettbufs);
494 copy_to_user(u_dom0_op, op, sizeof(*op));
495 }
496 break;
497 #endif
499 case DOM0_READCONSOLE:
500 {
501 ret = read_console_ring(op->u.readconsole.str,
502 op->u.readconsole.count,
503 op->u.readconsole.cmd);
504 }
505 break;
507 case DOM0_PHYSINFO:
508 {
509 dom0_physinfo_t *pi = &op->u.physinfo;
511 pi->ht_per_core = opt_noht ? 1 : ht_per_core;
512 pi->cores = smp_num_cpus / pi->ht_per_core;
513 pi->total_pages = max_page;
514 pi->free_pages = avail_domheap_pages();
515 pi->cpu_khz = cpu_khz;
517 copy_to_user(u_dom0_op, op, sizeof(*op));
518 ret = 0;
519 }
520 break;
522 case DOM0_PCIDEV_ACCESS:
523 {
524 extern int physdev_pci_access_modify(domid_t, int, int, int, int);
525 ret = physdev_pci_access_modify(op->u.pcidev_access.domain,
526 op->u.pcidev_access.bus,
527 op->u.pcidev_access.dev,
528 op->u.pcidev_access.func,
529 op->u.pcidev_access.enable);
530 }
531 break;
533 case DOM0_SCHED_ID:
534 {
535 op->u.sched_id.sched_id = sched_id();
536 copy_to_user(u_dom0_op, op, sizeof(*op));
537 ret = 0;
538 }
539 break;
541 case DOM0_SETDOMAININITIALMEM:
542 {
543 struct domain *d;
544 ret = -ESRCH;
545 d = find_domain_by_id(op->u.setdomaininitialmem.domain);
546 if ( d != NULL )
547 {
548 /* should only be used *before* domain is built. */
549 if ( !test_bit(DF_CONSTRUCTED, &d->d_flags) )
550 ret = alloc_new_dom_mem(
551 d, op->u.setdomaininitialmem.initial_memkb );
552 else
553 ret = -EINVAL;
554 put_domain(d);
555 }
556 }
557 break;
559 case DOM0_SETDOMAINMAXMEM:
560 {
561 struct domain *d;
562 ret = -ESRCH;
563 d = find_domain_by_id( op->u.setdomainmaxmem.domain );
564 if ( d != NULL )
565 {
566 d->max_pages =
567 (op->u.setdomainmaxmem.max_memkb+PAGE_SIZE-1)>> PAGE_SHIFT;
568 put_domain(d);
569 ret = 0;
570 }
571 }
572 break;
574 case DOM0_GETPAGEFRAMEINFO2:
575 {
576 #define GPF2_BATCH 128
577 int n,j;
578 int num = op->u.getpageframeinfo2.num;
579 domid_t dom = op->u.getpageframeinfo2.domain;
580 unsigned long *s_ptr = (unsigned long*) op->u.getpageframeinfo2.array;
581 struct domain *d;
582 unsigned long l_arr[GPF2_BATCH];
583 ret = -ESRCH;
585 if ( unlikely((d = find_domain_by_id(dom)) == NULL) )
586 break;
588 if ( unlikely(num > 1024) )
589 {
590 ret = -E2BIG;
591 break;
592 }
594 ret = 0;
595 for( n = 0; n < num; )
596 {
597 int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n);
599 if ( copy_from_user(l_arr, &s_ptr[n], k*sizeof(unsigned long)) )
600 {
601 ret = -EINVAL;
602 break;
603 }
605 for( j = 0; j < k; j++ )
606 {
607 struct pfn_info *page;
608 unsigned long mfn = l_arr[j];
610 if ( unlikely(mfn >= max_page) )
611 goto e2_err;
613 page = &frame_table[mfn];
615 if ( likely(get_page(page, d)) )
616 {
617 unsigned long type = 0;
619 switch( page->u.inuse.type_info & PGT_type_mask )
620 {
621 case PGT_l1_page_table:
622 type = L1TAB;
623 break;
624 case PGT_l2_page_table:
625 type = L2TAB;
626 break;
627 case PGT_l3_page_table:
628 type = L3TAB;
629 break;
630 case PGT_l4_page_table:
631 type = L4TAB;
632 break;
633 }
635 if ( page->u.inuse.type_info & PGT_pinned )
636 type |= LPINTAB;
637 l_arr[j] |= type;
638 put_page(page);
639 }
640 else
641 {
642 e2_err:
643 l_arr[j] |= XTAB;
644 }
646 }
648 if ( copy_to_user(&s_ptr[n], l_arr, k*sizeof(unsigned long)) )
649 {
650 ret = -EINVAL;
651 break;
652 }
654 n += j;
655 }
657 put_domain(d);
658 }
659 break;
661 case DOM0_SETDOMAINVMASSIST:
662 {
663 struct domain *d;
664 ret = -ESRCH;
665 d = find_domain_by_id( op->u.setdomainmaxmem.domain );
666 if ( d != NULL )
667 {
668 vm_assist(d, op->u.setdomainvmassist.cmd,
669 op->u.setdomainvmassist.type);
670 put_domain(d);
671 ret = 0;
672 }
673 }
674 break;
676 #ifdef PERF_COUNTERS
677 case DOM0_PERFCCONTROL:
678 {
679 extern int perfc_control(dom0_perfccontrol_t *);
680 ret = perfc_control(&op->u.perfccontrol);
681 copy_to_user(u_dom0_op, op, sizeof(*op));
682 }
683 break;
684 #endif
686 default:
687 ret = arch_do_dom0_op(op,u_dom0_op);
689 }
691 TRACE_5D(TRC_DOM0OP_LEAVE_BASE + op->cmd, ret,
692 op->u.dummy[0], op->u.dummy[1], op->u.dummy[2], op->u.dummy[3]);
695 return ret;
696 }