ia64/xen-unstable

view xen/common/dom0_ops.c @ 938:eaaf88bbc222

bitkeeper revision 1.597 (3fb26743975c08pGlW-UntXWf-IBnQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/br260/xeno.bk
author br260@labyrinth.cl.cam.ac.uk
date Wed Nov 12 17:00:51 2003 +0000 (2003-11-12)
parents 53a122a3c2b5 106bc1c68738
children 151801bd4e5e
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 <xeno/config.h>
10 #include <xeno/types.h>
11 #include <xeno/lib.h>
12 #include <xeno/mm.h>
13 #include <hypervisor-ifs/dom0_ops.h>
14 #include <xeno/sched.h>
15 #include <xeno/event.h>
16 #include <asm/domain_page.h>
17 #include <asm/msr.h>
19 extern unsigned int alloc_new_dom_mem(struct task_struct *, unsigned int);
21 /* Basically used to protect the domain-id space. */
22 static spinlock_t create_dom_lock = SPIN_LOCK_UNLOCKED;
24 static unsigned int get_domnr(void)
25 {
26 static unsigned int domnr = 0;
27 struct task_struct *p;
28 int tries = 0;
30 for ( tries = 0; tries < 1024; tries++ )
31 {
32 domnr = (domnr+1) & ((1<<20)-1);
33 if ( (p = find_domain_by_id(domnr)) == NULL )
34 return domnr;
35 put_task_struct(p);
36 }
38 return 0;
39 }
41 static void build_page_list(struct task_struct *p)
42 {
43 unsigned long *list;
44 unsigned long curr;
45 struct list_head *list_ent;
47 curr = list_entry(p->pg_head.next, struct pfn_info, list) - frame_table;
48 list = (unsigned long *)map_domain_mem(curr << PAGE_SHIFT);
50 list_for_each(list_ent, &p->pg_head)
51 {
52 *list++ = list_entry(list_ent, struct pfn_info, list) - frame_table;
54 if( ((unsigned long)list & ~PAGE_MASK) == 0 )
55 {
56 struct list_head *ent = frame_table[curr].list.next;
57 curr = list_entry(ent, struct pfn_info, list) - frame_table;
58 unmap_domain_mem(list-1);
59 list = (unsigned long *)map_domain_mem(curr << PAGE_SHIFT);
60 }
61 }
63 unmap_domain_mem(list);
64 }
66 static int msr_cpu_mask;
67 static unsigned long msr_addr;
68 static unsigned long msr_lo;
69 static unsigned long msr_hi;
71 static void write_msr_for(void *unused)
72 {
73 if (((1 << current->processor) & msr_cpu_mask))
74 wrmsr(msr_addr, msr_lo, msr_hi);
75 }
77 static void read_msr_for(void *unused)
78 {
79 if (((1 << current->processor) & msr_cpu_mask))
80 rdmsr(msr_addr, msr_lo, msr_hi);
81 }
84 long do_dom0_op(dom0_op_t *u_dom0_op)
85 {
86 long ret = 0;
87 dom0_op_t op;
89 if ( !IS_PRIV(current) )
90 return -EPERM;
92 if ( copy_from_user(&op, u_dom0_op, sizeof(op)) )
93 return -EFAULT;
95 if ( op.interface_version != DOM0_INTERFACE_VERSION )
96 return -EACCES;
98 switch ( op.cmd )
99 {
101 case DOM0_BUILDDOMAIN:
102 {
103 struct task_struct * p = find_domain_by_id(op.u.builddomain.domain);
104 ret = -EINVAL;
105 if ( p != NULL )
106 {
107 if ( (ret = final_setup_guestos(p, &op.u.builddomain)) == 0 )
108 ret = p->domain;
109 put_task_struct(p);
110 }
111 }
112 break;
114 case DOM0_STARTDOMAIN:
115 {
116 struct task_struct * p = find_domain_by_id(op.u.startdomain.domain);
117 ret = -EINVAL;
118 if ( p != NULL )
119 {
120 if ( (p->flags & PF_CONSTRUCTED) != 0 )
121 {
122 wake_up(p);
123 reschedule(p);
124 ret = p->domain;
125 }
126 put_task_struct(p);
127 }
128 }
129 break;
131 case DOM0_STOPDOMAIN:
132 {
133 ret = stop_other_domain(op.u.stopdomain.domain);
134 }
135 break;
137 case DOM0_CREATEDOMAIN:
138 {
139 struct task_struct *p;
140 static unsigned int pro = 0;
141 unsigned int dom;
142 ret = -ENOMEM;
144 spin_lock_irq(&create_dom_lock);
146 if ( (dom = get_domnr()) == 0 )
147 goto exit_create;
149 pro = (pro+1) % smp_num_cpus;
150 p = do_createdomain(dom, pro);
151 if ( p == NULL )
152 goto exit_create;
154 if ( op.u.createdomain.name[0] )
155 {
156 strncpy (p->name, op.u.createdomain.name, MAX_DOMAIN_NAME);
157 p->name[MAX_DOMAIN_NAME - 1] = 0;
158 }
160 ret = alloc_new_dom_mem(p, op.u.createdomain.memory_kb);
161 if ( ret != 0 )
162 {
163 __kill_domain(p);
164 goto exit_create;
165 }
167 build_page_list(p);
169 ret = p->domain;
171 op.u.createdomain.domain = ret;
172 copy_to_user(u_dom0_op, &op, sizeof(op));
174 exit_create:
175 spin_unlock_irq(&create_dom_lock);
176 }
177 break;
179 case DOM0_DESTROYDOMAIN:
180 {
181 unsigned int dom = op.u.destroydomain.domain;
182 int force = op.u.destroydomain.force;
183 ret = (dom == IDLE_DOMAIN_ID) ? -EPERM : kill_other_domain(dom, force);
184 }
185 break;
187 case DOM0_BVTCTL:
188 {
189 unsigned long ctx_allow = op.u.bvtctl.ctx_allow;
190 ret = sched_bvtctl(ctx_allow);
192 }
193 break;
195 case DOM0_ADJUSTDOM:
196 {
197 unsigned int dom = op.u.adjustdom.domain;
198 unsigned long mcu_adv = op.u.adjustdom.mcu_adv;
199 unsigned long warp = op.u.adjustdom.warp;
200 unsigned long warpl = op.u.adjustdom.warpl;
201 unsigned long warpu = op.u.adjustdom.warpu;
203 ret = -EPERM;
204 if ( dom != IDLE_DOMAIN_ID )
205 ret = sched_adjdom(dom, mcu_adv, warp, warpl, warpu);
206 }
207 break;
209 case DOM0_GETMEMLIST:
210 {
211 int i;
212 struct task_struct * p = find_domain_by_id(op.u.getmemlist.domain);
213 unsigned long max_pfns = op.u.getmemlist.max_pfns;
214 unsigned long pfn;
215 unsigned long *buffer = op.u.getmemlist.buffer;
216 struct list_head *list_ent;
218 ret = -EINVAL;
219 if ( p != NULL )
220 {
221 list_ent = p->pg_head.next;
222 pfn = list_entry(list_ent, struct pfn_info, list) - frame_table;
224 for ( i = 0; (i < max_pfns) && (list_ent != &p->pg_head); i++ )
225 {
226 if ( put_user(pfn, buffer) )
227 {
228 ret = -EFAULT;
229 goto out_getmemlist;
230 }
231 buffer++;
232 list_ent = frame_table[pfn].list.next;
233 pfn = list_entry(list_ent, struct pfn_info, list) -
234 frame_table;
235 }
237 op.u.getmemlist.num_pfns = i;
238 copy_to_user(u_dom0_op, &op, sizeof(op));
240 ret = 0;
242 out_getmemlist:
243 put_task_struct(p);
244 }
245 }
246 break;
248 case DOM0_GETDOMAININFO:
249 {
250 struct task_struct *p = &idle0_task;
251 u_long flags;
252 int i;
254 read_lock_irqsave (&tasklist_lock, flags);
256 while ( (p = p->next_task) != &idle0_task )
257 if ( !is_idle_task(p) && (p->domain >= op.u.getdomaininfo.domain) )
258 break;
260 if ( p == &idle0_task )
261 {
262 ret = -ESRCH;
263 }
264 else
265 {
266 op.u.getdomaininfo.domain = p->domain;
267 strcpy (op.u.getdomaininfo.name, p->name);
268 op.u.getdomaininfo.processor = p->processor;
269 op.u.getdomaininfo.has_cpu = p->has_cpu;
270 op.u.getdomaininfo.state = DOMSTATE_ACTIVE;
271 if ( (p->state == TASK_STOPPED) || (p->state == TASK_DYING) )
272 op.u.getdomaininfo.state = DOMSTATE_STOPPED;
273 op.u.getdomaininfo.hyp_events = p->hyp_events;
274 op.u.getdomaininfo.mcu_advance = p->mcu_advance;
275 op.u.getdomaininfo.tot_pages = p->tot_pages;
276 op.u.getdomaininfo.cpu_time = p->cpu_time;
277 op.u.getdomaininfo.shared_info_frame =
278 __pa(p->shared_info) >> PAGE_SHIFT;
279 if ( p->state == TASK_STOPPED )
280 {
281 rmb(); /* Ensure that we see saved register state. */
282 op.u.getdomaininfo.ctxt.flags = 0;
283 memcpy(&op.u.getdomaininfo.ctxt.i386_ctxt,
284 &p->shared_info->execution_context,
285 sizeof(p->shared_info->execution_context));
286 if ( p->flags & PF_DONEFPUINIT )
287 op.u.getdomaininfo.ctxt.flags |= ECF_I387_VALID;
288 memcpy(&op.u.getdomaininfo.ctxt.i387_ctxt,
289 &p->thread.i387,
290 sizeof(p->thread.i387));
291 memcpy(&op.u.getdomaininfo.ctxt.trap_ctxt,
292 p->thread.traps,
293 sizeof(p->thread.traps));
294 if ( (p->thread.fast_trap_desc.a == 0) &&
295 (p->thread.fast_trap_desc.b == 0) )
296 op.u.getdomaininfo.ctxt.fast_trap_idx = 0;
297 else
298 op.u.getdomaininfo.ctxt.fast_trap_idx =
299 p->thread.fast_trap_idx;
300 op.u.getdomaininfo.ctxt.ldt_base = p->mm.ldt_base;
301 op.u.getdomaininfo.ctxt.ldt_ents = p->mm.ldt_ents;
302 op.u.getdomaininfo.ctxt.gdt_ents = 0;
303 if ( GET_GDT_ADDRESS(p) == GDT_VIRT_START )
304 {
305 for ( i = 0; i < 16; i++ )
306 op.u.getdomaininfo.ctxt.gdt_frames[i] =
307 l1_pgentry_to_pagenr(p->mm.perdomain_pt[i]);
308 op.u.getdomaininfo.ctxt.gdt_ents =
309 (GET_GDT_ENTRIES(p) + 1) >> 3;
310 }
311 op.u.getdomaininfo.ctxt.ring1_ss = p->thread.ss1;
312 op.u.getdomaininfo.ctxt.ring1_esp = p->thread.esp1;
313 op.u.getdomaininfo.ctxt.pt_base =
314 pagetable_val(p->mm.pagetable);
315 memcpy(op.u.getdomaininfo.ctxt.debugreg,
316 p->thread.debugreg,
317 sizeof(p->thread.debugreg));
318 op.u.getdomaininfo.ctxt.event_callback_cs = p->event_selector;
319 op.u.getdomaininfo.ctxt.event_callback_eip = p->event_address;
320 op.u.getdomaininfo.ctxt.failsafe_callback_cs =
321 p->failsafe_selector;
322 op.u.getdomaininfo.ctxt.failsafe_callback_eip =
323 p->failsafe_address;
324 }
325 }
326 read_unlock_irqrestore(&tasklist_lock, flags);
327 copy_to_user(u_dom0_op, &op, sizeof(op));
328 }
329 break;
331 case DOM0_GETPAGEFRAMEINFO:
332 {
333 struct pfn_info *page;
334 unsigned long pfn = op.u.getpageframeinfo.pfn;
336 if ( pfn >= max_page )
337 {
338 ret = -EINVAL;
339 }
340 else
341 {
342 page = frame_table + pfn;
344 op.u.getpageframeinfo.domain = page->flags & PG_domain_mask;
345 op.u.getpageframeinfo.type = NONE;
347 if ( page->type_count != 0 )
348 {
349 switch ( page->flags & PG_type_mask )
350 {
351 case PGT_l1_page_table:
352 op.u.getpageframeinfo.type = L1TAB;
353 break;
354 case PGT_l2_page_table:
355 op.u.getpageframeinfo.type = L2TAB;
356 break;
357 }
358 }
360 copy_to_user(u_dom0_op, &op, sizeof(op));
361 }
362 }
363 break;
365 case DOM0_IOPL:
366 {
367 extern long do_iopl(unsigned int, unsigned int);
368 ret = do_iopl(op.u.iopl.domain, op.u.iopl.iopl);
369 }
370 break;
372 case DOM0_MSR:
373 {
374 if (op.u.msr.write)
375 {
376 msr_cpu_mask = op.u.msr.cpu_mask;
377 msr_addr = op.u.msr.msr;
378 msr_lo = op.u.msr.in1;
379 msr_hi = op.u.msr.in2;
380 smp_call_function(write_msr_for, NULL, 1, 1);
381 write_msr_for(NULL);
382 }
383 else
384 {
385 msr_cpu_mask = op.u.msr.cpu_mask;
386 msr_addr = op.u.msr.msr;
387 smp_call_function(read_msr_for, NULL, 1, 1);
388 read_msr_for(NULL);
390 op.u.msr.out1 = msr_lo;
391 op.u.msr.out2 = msr_hi;
392 copy_to_user(u_dom0_op, &op, sizeof(op));
393 }
394 ret = 0;
395 }
396 break;
398 case DOM0_DEBUG:
399 {
400 extern void pdb_do_debug(dom0_op_t *);
401 pdb_do_debug(&op);
402 copy_to_user(u_dom0_op, &op, sizeof(op));
403 ret = 0;
404 }
405 break;
407 case DOM0_SETTIME:
408 {
409 do_settime(op.u.settime.secs,
410 op.u.settime.usecs,
411 op.u.settime.system_time);
412 ret = 0;
413 }
414 break;
416 case DOM0_READCONSOLE:
417 {
418 extern long read_console_ring(char *, unsigned int);
419 ret = read_console_ring(op.u.readconsole.str,
420 op.u.readconsole.count);
421 }
422 break;
424 default:
425 ret = -ENOSYS;
427 }
429 return ret;
430 }