debuggers.hg

view xen/common/dom0_ops.c @ 3515:d331c6994d28

bitkeeper revision 1.1159.223.12 (41f14d3cE4GADmEAEr6XE9nXX4dyGw)

Common-code cleanups. Moved arch-specific code out into arch/x86
and asm-x86.
author kaf24@scramble.cl.cam.ac.uk
date Fri Jan 21 18:43:08 2005 +0000 (2005-01-21)
parents 86a5dde2aef1
children 46c14b1a4351 ac9c554c75d1 fead3d49dca1
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 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) )
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 )
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->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 unsigned int i, cnt[NR_CPUS] = { 0 };
183 read_lock(&domlist_lock);
184 for_each_domain ( d )
185 cnt[d->processor]++;
186 read_unlock(&domlist_lock);
188 for ( i = 0; i < smp_num_cpus; i++ )
189 if ( cnt[i] < cnt[pro] )
190 pro = i;
191 }
192 else
193 pro = op->u.createdomain.cpu % smp_num_cpus;
195 ret = -ENOMEM;
196 if ( (d = do_createdomain(dom, pro)) == NULL )
197 break;
199 ret = alloc_new_dom_mem(d, op->u.createdomain.memory_kb);
200 if ( ret != 0 )
201 {
202 domain_kill(d);
203 break;
204 }
206 ret = 0;
208 op->u.createdomain.domain = d->id;
209 copy_to_user(u_dom0_op, op, sizeof(*op));
210 }
211 break;
213 case DOM0_DESTROYDOMAIN:
214 {
215 struct domain *d = find_domain_by_id(op->u.destroydomain.domain);
216 ret = -ESRCH;
217 if ( d != NULL )
218 {
219 ret = -EINVAL;
220 if ( d != current )
221 {
222 domain_kill(d);
223 ret = 0;
224 }
225 put_domain(d);
226 }
227 }
228 break;
230 case DOM0_PINCPUDOMAIN:
231 {
232 domid_t dom = op->u.pincpudomain.domain;
233 struct domain *d = find_domain_by_id(dom);
234 int cpu = op->u.pincpudomain.cpu;
236 if ( d == NULL )
237 {
238 ret = -ESRCH;
239 break;
240 }
242 if ( d == current )
243 {
244 ret = -EINVAL;
245 put_domain(d);
246 break;
247 }
249 if ( cpu == -1 )
250 {
251 clear_bit(DF_CPUPINNED, &d->flags);
252 }
253 else
254 {
255 domain_pause(d);
256 synchronise_pagetables(~0UL);
257 if ( d->processor != (cpu % smp_num_cpus) )
258 set_bit(DF_MIGRATED, &d->flags);
259 set_bit(DF_CPUPINNED, &d->flags);
260 d->processor = cpu % smp_num_cpus;
261 domain_unpause(d);
262 }
264 put_domain(d);
265 }
266 break;
268 case DOM0_SCHEDCTL:
269 {
270 ret = sched_ctl(&op->u.schedctl);
271 copy_to_user(u_dom0_op, op, sizeof(*op));
272 }
273 break;
275 case DOM0_ADJUSTDOM:
276 {
277 ret = sched_adjdom(&op->u.adjustdom);
278 copy_to_user(u_dom0_op, op, sizeof(*op));
279 }
280 break;
282 case DOM0_GETMEMLIST:
283 {
284 int i;
285 struct domain *d = find_domain_by_id(op->u.getmemlist.domain);
286 unsigned long max_pfns = op->u.getmemlist.max_pfns;
287 unsigned long pfn;
288 unsigned long *buffer = op->u.getmemlist.buffer;
289 struct list_head *list_ent;
291 ret = -EINVAL;
292 if ( d != NULL )
293 {
294 ret = 0;
296 spin_lock(&d->page_alloc_lock);
297 list_ent = d->page_list.next;
298 for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
299 {
300 pfn = list_entry(list_ent, struct pfn_info, list) -
301 frame_table;
302 if ( put_user(pfn, buffer) )
303 {
304 ret = -EFAULT;
305 break;
306 }
307 buffer++;
308 list_ent = frame_table[pfn].list.next;
309 }
310 spin_unlock(&d->page_alloc_lock);
312 op->u.getmemlist.num_pfns = i;
313 copy_to_user(u_dom0_op, op, sizeof(*op));
315 put_domain(d);
316 }
317 }
318 break;
320 case DOM0_GETDOMAININFO:
321 {
322 full_execution_context_t *c;
323 struct domain *d;
325 read_lock(&domlist_lock);
327 for_each_domain ( d )
328 {
329 if ( d->id >= op->u.getdomaininfo.domain )
330 break;
331 }
333 if ( (d == NULL) || !get_domain(d) )
334 {
335 read_unlock(&domlist_lock);
336 ret = -ESRCH;
337 break;
338 }
340 read_unlock(&domlist_lock);
342 op->u.getdomaininfo.domain = d->id;
344 op->u.getdomaininfo.flags =
345 (test_bit(DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) |
346 (test_bit(DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) |
347 (test_bit(DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) |
348 (test_bit(DF_CTRLPAUSE, &d->flags) ? DOMFLAGS_PAUSED : 0) |
349 (test_bit(DF_BLOCKED, &d->flags) ? DOMFLAGS_BLOCKED : 0) |
350 (test_bit(DF_RUNNING, &d->flags) ? DOMFLAGS_RUNNING : 0);
352 op->u.getdomaininfo.flags |= d->processor << DOMFLAGS_CPUSHIFT;
353 op->u.getdomaininfo.flags |=
354 d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
356 op->u.getdomaininfo.tot_pages = d->tot_pages;
357 op->u.getdomaininfo.max_pages = d->max_pages;
358 op->u.getdomaininfo.cpu_time = d->cpu_time;
359 op->u.getdomaininfo.shared_info_frame =
360 __pa(d->shared_info) >> PAGE_SHIFT;
362 if ( op->u.getdomaininfo.ctxt != NULL )
363 {
364 if ( (c = xmalloc(sizeof(*c))) == NULL )
365 {
366 ret = -ENOMEM;
367 put_domain(d);
368 break;
369 }
371 if ( d != current )
372 domain_pause(d);
374 arch_getdomaininfo_ctxt(d,c);
376 if ( d != current )
377 domain_unpause(d);
379 if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) )
380 ret = -EINVAL;
382 if ( c != NULL )
383 xfree(c);
384 }
386 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
387 ret = -EINVAL;
389 put_domain(d);
390 }
391 break;
393 #ifdef XEN_DEBUGGER
394 case DOM0_DEBUG:
395 {
396 pdb_do_debug(op);
397 copy_to_user(u_dom0_op, op, sizeof(*op));
398 ret = 0;
399 }
400 break;
401 #endif
403 case DOM0_SETTIME:
404 {
405 do_settime(op->u.settime.secs,
406 op->u.settime.usecs,
407 op->u.settime.system_time);
408 ret = 0;
409 }
410 break;
412 #ifdef TRACE_BUFFER
413 case DOM0_GETTBUFS:
414 {
415 ret = get_tb_info(&op->u.gettbufs);
416 copy_to_user(u_dom0_op, op, sizeof(*op));
417 }
418 break;
419 #endif
421 case DOM0_READCONSOLE:
422 {
423 ret = read_console_ring(op->u.readconsole.str,
424 op->u.readconsole.count,
425 op->u.readconsole.cmd);
426 }
427 break;
429 case DOM0_PCIDEV_ACCESS:
430 {
431 extern int physdev_pci_access_modify(domid_t, int, int, int, int);
432 ret = physdev_pci_access_modify(op->u.pcidev_access.domain,
433 op->u.pcidev_access.bus,
434 op->u.pcidev_access.dev,
435 op->u.pcidev_access.func,
436 op->u.pcidev_access.enable);
437 }
438 break;
440 case DOM0_SCHED_ID:
441 {
442 op->u.sched_id.sched_id = sched_id();
443 copy_to_user(u_dom0_op, op, sizeof(*op));
444 ret = 0;
445 }
446 break;
448 case DOM0_SETDOMAININITIALMEM:
449 {
450 struct domain *d;
451 ret = -ESRCH;
452 d = find_domain_by_id(op->u.setdomaininitialmem.domain);
453 if ( d != NULL )
454 {
455 /* should only be used *before* domain is built. */
456 if ( !test_bit(DF_CONSTRUCTED, &d->flags) )
457 ret = alloc_new_dom_mem(
458 d, op->u.setdomaininitialmem.initial_memkb );
459 else
460 ret = -EINVAL;
461 put_domain(d);
462 }
463 }
464 break;
466 case DOM0_SETDOMAINMAXMEM:
467 {
468 struct domain *d;
469 ret = -ESRCH;
470 d = find_domain_by_id( op->u.setdomainmaxmem.domain );
471 if ( d != NULL )
472 {
473 d->max_pages =
474 (op->u.setdomainmaxmem.max_memkb+PAGE_SIZE-1)>> PAGE_SHIFT;
475 put_domain(d);
476 ret = 0;
477 }
478 }
479 break;
481 case DOM0_SETDOMAINVMASSIST:
482 {
483 struct domain *d;
484 ret = -ESRCH;
485 d = find_domain_by_id( op->u.setdomainvmassist.domain );
486 if ( d != NULL )
487 {
488 vm_assist(d, op->u.setdomainvmassist.cmd,
489 op->u.setdomainvmassist.type);
490 put_domain(d);
491 ret = 0;
492 }
493 }
494 break;
496 #ifdef PERF_COUNTERS
497 case DOM0_PERFCCONTROL:
498 {
499 extern int perfc_control(dom0_perfccontrol_t *);
500 ret = perfc_control(&op->u.perfccontrol);
501 copy_to_user(u_dom0_op, op, sizeof(*op));
502 }
503 break;
504 #endif
506 default:
507 ret = arch_do_dom0_op(op,u_dom0_op);
509 }
511 TRACE_5D(TRC_DOM0OP_LEAVE_BASE + op->cmd, ret,
512 op->u.dummy[0], op->u.dummy[1], op->u.dummy[2], op->u.dummy[3]);
515 return ret;
516 }