direct-io.hg

view xen/common/dom0_ops.c @ 5517:10e9028c8e3d

bitkeeper revision 1.1718.1.10 (42b7b19aqOS_1M8I4pIOFjiTPYWV-g)

Merge bk://xenbits.xensource.com/xen-unstable.bk
into spot.cl.cam.ac.uk:C:/Documents and Settings/iap10/xen-unstable.bk
author iap10@spot.cl.cam.ac.uk
date Tue Jun 21 06:20:10 2005 +0000 (2005-06-21)
parents aa52b853c28b
children 649cd37aa1ab
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 <xen/sched.h>
14 #include <xen/domain.h>
15 #include <xen/event.h>
16 #include <xen/domain_page.h>
17 #include <xen/trace.h>
18 #include <xen/console.h>
19 #include <asm/current.h>
20 #include <public/dom0_ops.h>
21 #include <public/sched_ctl.h>
22 #include <acm/acm_hooks.h>
24 extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
25 extern void arch_getdomaininfo_ctxt(
26 struct vcpu *, struct vcpu_guest_context *);
28 static inline int is_free_domid(domid_t dom)
29 {
30 struct domain *d;
32 if ( dom >= DOMID_FIRST_RESERVED )
33 return 0;
35 if ( (d = find_domain_by_id(dom)) == NULL )
36 return 1;
38 put_domain(d);
39 return 0;
40 }
42 /*
43 * Allocate a free domain id. We try to reuse domain ids in a fairly low range,
44 * only expanding the range when there are no free domain ids. This is to keep
45 * domain ids in a range depending on the number that exist simultaneously,
46 * rather than incrementing domain ids in the full 32-bit range.
47 */
48 static int allocate_domid(domid_t *pdom)
49 {
50 static spinlock_t domid_lock = SPIN_LOCK_UNLOCKED;
51 static domid_t curdom = 0;
52 static domid_t topdom = 101;
53 int err = 0;
54 domid_t dom;
56 spin_lock(&domid_lock);
58 /* Try to use a domain id in the range 0..topdom, starting at curdom. */
59 for ( dom = curdom + 1; dom != curdom; dom++ )
60 {
61 if ( dom == topdom )
62 dom = 1;
63 if ( is_free_domid(dom) )
64 goto exit;
65 }
67 /* Couldn't find a free domain id in 0..topdom, try higher. */
68 for ( dom = topdom; dom < DOMID_FIRST_RESERVED; dom++ )
69 {
70 if ( is_free_domid(dom) )
71 {
72 topdom = dom + 1;
73 goto exit;
74 }
75 }
77 /* No free domain ids. */
78 err = -ENOMEM;
80 exit:
81 if ( err == 0 )
82 {
83 curdom = dom;
84 *pdom = dom;
85 }
87 spin_unlock(&domid_lock);
88 return err;
89 }
91 long do_dom0_op(dom0_op_t *u_dom0_op)
92 {
93 long ret = 0;
94 dom0_op_t curop, *op = &curop;
95 void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
97 if ( !IS_PRIV(current->domain) )
98 return -EPERM;
100 if ( copy_from_user(op, u_dom0_op, sizeof(*op)) )
101 return -EFAULT;
103 if ( op->interface_version != DOM0_INTERFACE_VERSION )
104 return -EACCES;
106 if ( acm_pre_dom0_op(op, &ssid) )
107 return -EACCES;
109 switch ( op->cmd )
110 {
112 case DOM0_SETDOMAININFO:
113 {
114 struct domain *d = find_domain_by_id(op->u.setdomaininfo.domain);
115 ret = -ESRCH;
116 if ( d != NULL )
117 {
118 ret = set_info_guest(d, &op->u.setdomaininfo);
119 put_domain(d);
120 }
121 }
122 break;
124 case DOM0_PAUSEDOMAIN:
125 {
126 struct domain *d = find_domain_by_id(op->u.pausedomain.domain);
127 ret = -ESRCH;
128 if ( d != NULL )
129 {
130 ret = -EINVAL;
131 if ( d != current->domain )
132 {
133 domain_pause_by_systemcontroller(d);
134 ret = 0;
135 }
136 put_domain(d);
137 }
138 }
139 break;
141 case DOM0_UNPAUSEDOMAIN:
142 {
143 struct domain *d = find_domain_by_id(op->u.unpausedomain.domain);
144 ret = -ESRCH;
145 if ( d != NULL )
146 {
147 ret = -EINVAL;
148 if ( (d != current->domain) &&
149 test_bit(_DOMF_constructed, &d->domain_flags) )
150 {
151 domain_unpause_by_systemcontroller(d);
152 ret = 0;
153 }
154 put_domain(d);
155 }
156 }
157 break;
159 case DOM0_CREATEDOMAIN:
160 {
161 struct domain *d;
162 unsigned int pro;
163 domid_t dom;
164 struct vcpu *v;
165 unsigned int i, cnt[NR_CPUS] = { 0 };
168 dom = op->u.createdomain.domain;
169 if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
170 {
171 ret = -EINVAL;
172 if ( !is_free_domid(dom) )
173 break;
174 }
175 else if ( (ret = allocate_domid(&dom)) != 0 )
176 {
177 break;
178 }
180 /* Do an initial CPU placement. Pick the least-populated CPU. */
181 read_lock(&domlist_lock);
182 for_each_domain ( d )
183 for_each_vcpu ( d, v )
184 cnt[v->processor]++;
185 read_unlock(&domlist_lock);
187 /*
188 * If we're on a HT system, we only use the first HT for dom0, other
189 * domains will all share the second HT of each CPU. Since dom0 is on
190 * CPU 0, we favour high numbered CPUs in the event of a tie.
191 */
192 pro = smp_num_siblings - 1;
193 for ( i = pro; i < num_online_cpus(); i += smp_num_siblings )
194 if ( cnt[i] <= cnt[pro] )
195 pro = i;
197 ret = -ENOMEM;
198 if ( (d = do_createdomain(dom, pro)) == NULL )
199 break;
201 ret = 0;
203 op->u.createdomain.domain = d->domain_id;
204 copy_to_user(u_dom0_op, op, sizeof(*op));
205 }
206 break;
208 case DOM0_DESTROYDOMAIN:
209 {
210 struct domain *d = find_domain_by_id(op->u.destroydomain.domain);
211 ret = -ESRCH;
212 if ( d != NULL )
213 {
214 ret = -EINVAL;
215 if ( d != current->domain )
216 {
217 domain_kill(d);
218 ret = 0;
219 }
220 put_domain(d);
221 }
222 }
223 break;
225 case DOM0_PINCPUDOMAIN:
226 {
227 domid_t dom = op->u.pincpudomain.domain;
228 struct domain *d = find_domain_by_id(dom);
229 struct vcpu *v;
230 cpumap_t cpumap;
233 if ( d == NULL )
234 {
235 ret = -ESRCH;
236 break;
237 }
239 if ( (op->u.pincpudomain.vcpu >= MAX_VIRT_CPUS) ||
240 !d->vcpu[op->u.pincpudomain.vcpu] )
241 {
242 ret = -EINVAL;
243 put_domain(d);
244 break;
245 }
247 v = d->vcpu[op->u.pincpudomain.vcpu];
248 if ( v == NULL )
249 {
250 ret = -ESRCH;
251 put_domain(d);
252 break;
253 }
255 if ( v == current )
256 {
257 ret = -EINVAL;
258 put_domain(d);
259 break;
260 }
262 if ( copy_from_user(&cpumap, op->u.pincpudomain.cpumap,
263 sizeof(cpumap)) )
264 {
265 ret = -EFAULT;
266 put_domain(d);
267 break;
268 }
270 /* update cpumap for this vcpu */
271 v->cpumap = cpumap;
273 if ( cpumap == CPUMAP_RUNANYWHERE )
274 clear_bit(_VCPUF_cpu_pinned, &v->vcpu_flags);
275 else
276 {
277 /* pick a new cpu from the usable map */
278 int new_cpu = (int)find_first_set_bit(cpumap) % num_online_cpus();
280 vcpu_pause(v);
281 if ( v->processor != new_cpu )
282 set_bit(_VCPUF_cpu_migrated, &v->vcpu_flags);
283 set_bit(_VCPUF_cpu_pinned, &v->vcpu_flags);
284 v->processor = new_cpu;
285 vcpu_unpause(v);
286 }
288 put_domain(d);
289 }
290 break;
292 case DOM0_SCHEDCTL:
293 {
294 ret = sched_ctl(&op->u.schedctl);
295 copy_to_user(u_dom0_op, op, sizeof(*op));
296 }
297 break;
299 case DOM0_ADJUSTDOM:
300 {
301 ret = sched_adjdom(&op->u.adjustdom);
302 copy_to_user(u_dom0_op, op, sizeof(*op));
303 }
304 break;
306 case DOM0_GETDOMAININFO:
307 {
308 struct domain *d;
309 struct vcpu *v;
310 u64 cpu_time = 0;
311 int vcpu_count = 0;
312 int flags = DOMFLAGS_PAUSED | DOMFLAGS_BLOCKED;
314 read_lock(&domlist_lock);
316 for_each_domain ( d )
317 {
318 if ( d->domain_id >= op->u.getdomaininfo.domain )
319 break;
320 }
322 if ( (d == NULL) || !get_domain(d) )
323 {
324 read_unlock(&domlist_lock);
325 ret = -ESRCH;
326 break;
327 }
329 read_unlock(&domlist_lock);
331 op->u.getdomaininfo.domain = d->domain_id;
333 memset(&op->u.getdomaininfo.vcpu_to_cpu, -1,
334 sizeof(op->u.getdomaininfo.vcpu_to_cpu));
335 memset(&op->u.getdomaininfo.cpumap, 0,
336 sizeof(op->u.getdomaininfo.cpumap));
338 /*
339 * - domain is marked as paused or blocked only if all its vcpus
340 * are paused or blocked
341 * - domain is marked as running if any of its vcpus is running
342 */
343 for_each_vcpu ( d, v ) {
344 op->u.getdomaininfo.vcpu_to_cpu[v->vcpu_id] = v->processor;
345 op->u.getdomaininfo.cpumap[v->vcpu_id] = v->cpumap;
346 if ( !(v->vcpu_flags & VCPUF_ctrl_pause) )
347 flags &= ~DOMFLAGS_PAUSED;
348 if ( !(v->vcpu_flags & VCPUF_blocked) )
349 flags &= ~DOMFLAGS_BLOCKED;
350 if ( v->vcpu_flags & VCPUF_running )
351 flags |= DOMFLAGS_RUNNING;
352 if ( v->cpu_time > cpu_time )
353 cpu_time += v->cpu_time;
354 vcpu_count++;
355 }
357 op->u.getdomaininfo.cpu_time = cpu_time;
358 op->u.getdomaininfo.n_vcpu = vcpu_count;
360 op->u.getdomaininfo.flags = flags |
361 ((d->domain_flags & DOMF_dying) ? DOMFLAGS_DYING : 0) |
362 ((d->domain_flags & DOMF_shutdown) ? DOMFLAGS_SHUTDOWN : 0) |
363 d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
365 if (d->ssid != NULL)
366 op->u.getdomaininfo.ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
367 else
368 op->u.getdomaininfo.ssidref = ACM_DEFAULT_SSID;
370 op->u.getdomaininfo.tot_pages = d->tot_pages;
371 op->u.getdomaininfo.max_pages = d->max_pages;
372 op->u.getdomaininfo.shared_info_frame =
373 __pa(d->shared_info) >> PAGE_SHIFT;
375 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
376 ret = -EINVAL;
378 put_domain(d);
379 }
380 break;
382 case DOM0_GETVCPUCONTEXT:
383 {
384 struct vcpu_guest_context *c;
385 struct domain *d;
386 struct vcpu *v;
388 d = find_domain_by_id(op->u.getvcpucontext.domain);
389 if ( d == NULL )
390 {
391 ret = -ESRCH;
392 break;
393 }
395 if ( op->u.getvcpucontext.vcpu >= MAX_VIRT_CPUS )
396 {
397 ret = -EINVAL;
398 put_domain(d);
399 break;
400 }
402 v = d->vcpu[op->u.getvcpucontext.vcpu];
403 if ( v == NULL )
404 {
405 ret = -ESRCH;
406 put_domain(d);
407 break;
408 }
410 op->u.getvcpucontext.cpu_time = v->cpu_time;
412 if ( op->u.getvcpucontext.ctxt != NULL )
413 {
414 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
415 {
416 ret = -ENOMEM;
417 put_domain(d);
418 break;
419 }
421 if ( v != current )
422 vcpu_pause(v);
424 arch_getdomaininfo_ctxt(v,c);
426 if ( v != current )
427 vcpu_unpause(v);
429 if ( copy_to_user(op->u.getvcpucontext.ctxt, c, sizeof(*c)) )
430 ret = -EINVAL;
432 xfree(c);
433 }
435 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
436 ret = -EINVAL;
438 put_domain(d);
439 }
440 break;
442 case DOM0_SETTIME:
443 {
444 do_settime(op->u.settime.secs,
445 op->u.settime.usecs,
446 op->u.settime.system_time);
447 ret = 0;
448 }
449 break;
451 #ifdef TRACE_BUFFER
452 case DOM0_TBUFCONTROL:
453 {
454 ret = tb_control(&op->u.tbufcontrol);
455 copy_to_user(u_dom0_op, op, sizeof(*op));
456 }
457 break;
458 #endif
460 case DOM0_READCONSOLE:
461 {
462 ret = read_console_ring(
463 &op->u.readconsole.buffer,
464 &op->u.readconsole.count,
465 op->u.readconsole.clear);
466 copy_to_user(u_dom0_op, op, sizeof(*op));
467 }
468 break;
470 case DOM0_SCHED_ID:
471 {
472 op->u.sched_id.sched_id = sched_id();
473 copy_to_user(u_dom0_op, op, sizeof(*op));
474 ret = 0;
475 }
476 break;
478 case DOM0_SETDOMAINMAXMEM:
479 {
480 struct domain *d;
481 ret = -ESRCH;
482 d = find_domain_by_id(op->u.setdomainmaxmem.domain);
483 if ( d != NULL )
484 {
485 d->max_pages = op->u.setdomainmaxmem.max_memkb >> (PAGE_SHIFT-10);
486 put_domain(d);
487 ret = 0;
488 }
489 }
490 break;
492 #ifdef PERF_COUNTERS
493 case DOM0_PERFCCONTROL:
494 {
495 extern int perfc_control(dom0_perfccontrol_t *);
496 ret = perfc_control(&op->u.perfccontrol);
497 copy_to_user(u_dom0_op, op, sizeof(*op));
498 }
499 break;
500 #endif
502 default:
503 ret = arch_do_dom0_op(op,u_dom0_op);
505 }
506 if (!ret)
507 acm_post_dom0_op(op, ssid);
508 else
509 acm_fail_dom0_op(op, ssid);
510 return ret;
511 }
513 /*
514 * Local variables:
515 * mode: C
516 * c-set-style: "BSD"
517 * c-basic-offset: 4
518 * tab-width: 4
519 * indent-tabs-mode: nil
520 * End:
521 */