xen-vtx-unstable

view xen/arch/x86/dom0_ops.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 813c37b68376
children
line source
1 /******************************************************************************
2 * Arch-specific 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 <xen/domain_page.h>
17 #include <asm/msr.h>
18 #include <xen/trace.h>
19 #include <xen/console.h>
20 #include <asm/shadow.h>
21 #include <asm/irq.h>
22 #include <asm/processor.h>
23 #include <public/sched_ctl.h>
25 #include <asm/mtrr.h>
26 #include "mtrr/mtrr.h"
28 #define TRC_DOM0OP_ENTER_BASE 0x00020000
29 #define TRC_DOM0OP_LEAVE_BASE 0x00030000
31 static int msr_cpu_mask;
32 static unsigned long msr_addr;
33 static unsigned long msr_lo;
34 static unsigned long msr_hi;
36 static void write_msr_for(void *unused)
37 {
38 if ( ((1 << current->processor) & msr_cpu_mask) )
39 (void)wrmsr_user(msr_addr, msr_lo, msr_hi);
40 }
42 static void read_msr_for(void *unused)
43 {
44 if ( ((1 << current->processor) & msr_cpu_mask) )
45 (void)rdmsr_user(msr_addr, msr_lo, msr_hi);
46 }
48 long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
49 {
50 long ret = 0;
52 if ( !IS_PRIV(current->domain) )
53 return -EPERM;
55 switch ( op->cmd )
56 {
58 case DOM0_MSR:
59 {
60 if ( op->u.msr.write )
61 {
62 msr_cpu_mask = op->u.msr.cpu_mask;
63 msr_addr = op->u.msr.msr;
64 msr_lo = op->u.msr.in1;
65 msr_hi = op->u.msr.in2;
66 smp_call_function(write_msr_for, NULL, 1, 1);
67 write_msr_for(NULL);
68 }
69 else
70 {
71 msr_cpu_mask = op->u.msr.cpu_mask;
72 msr_addr = op->u.msr.msr;
73 smp_call_function(read_msr_for, NULL, 1, 1);
74 read_msr_for(NULL);
76 op->u.msr.out1 = msr_lo;
77 op->u.msr.out2 = msr_hi;
78 copy_to_user(u_dom0_op, op, sizeof(*op));
79 }
80 ret = 0;
81 }
82 break;
84 case DOM0_SHADOW_CONTROL:
85 {
86 struct domain *d;
87 ret = -ESRCH;
88 d = find_domain_by_id(op->u.shadow_control.domain);
89 if ( d != NULL )
90 {
91 ret = shadow_mode_control(d, &op->u.shadow_control);
92 put_domain(d);
93 copy_to_user(u_dom0_op, op, sizeof(*op));
94 }
95 }
96 break;
98 case DOM0_ADD_MEMTYPE:
99 {
100 ret = mtrr_add_page(
101 op->u.add_memtype.pfn,
102 op->u.add_memtype.nr_pfns,
103 op->u.add_memtype.type,
104 1);
105 }
106 break;
108 case DOM0_DEL_MEMTYPE:
109 {
110 ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);
111 }
112 break;
114 case DOM0_READ_MEMTYPE:
115 {
116 unsigned long pfn;
117 unsigned int nr_pfns;
118 mtrr_type type;
120 ret = -EINVAL;
121 if ( op->u.read_memtype.reg < num_var_ranges )
122 {
123 mtrr_if->get(op->u.read_memtype.reg, &pfn, &nr_pfns, &type);
124 (void)__put_user(pfn, &u_dom0_op->u.read_memtype.pfn);
125 (void)__put_user(nr_pfns, &u_dom0_op->u.read_memtype.nr_pfns);
126 (void)__put_user(type, &u_dom0_op->u.read_memtype.type);
127 ret = 0;
128 }
129 }
130 break;
132 case DOM0_MICROCODE:
133 {
134 extern int microcode_update(void *buf, unsigned long len);
135 ret = microcode_update(op->u.microcode.data, op->u.microcode.length);
136 }
137 break;
139 case DOM0_IOPORT_PERMISSION:
140 {
141 struct domain *d;
142 unsigned int fp = op->u.ioport_permission.first_port;
143 unsigned int np = op->u.ioport_permission.nr_ports;
144 unsigned int p;
146 ret = -EINVAL;
147 if ( (fp + np) >= 65536 )
148 break;
150 ret = -ESRCH;
151 if ( unlikely((d = find_domain_by_id(
152 op->u.ioport_permission.domain)) == NULL) )
153 break;
155 ret = -ENOMEM;
156 if ( d->arch.iobmp_mask != NULL )
157 {
158 if ( (d->arch.iobmp_mask = xmalloc_array(
159 u8, IOBMP_BYTES)) == NULL )
160 {
161 put_domain(d);
162 break;
163 }
164 memset(d->arch.iobmp_mask, 0xFF, IOBMP_BYTES);
165 }
167 ret = 0;
168 for ( p = fp; p < (fp + np); p++ )
169 {
170 if ( op->u.ioport_permission.allow_access )
171 clear_bit(p, d->arch.iobmp_mask);
172 else
173 set_bit(p, d->arch.iobmp_mask);
174 }
176 put_domain(d);
177 }
178 break;
180 case DOM0_PHYSINFO:
181 {
182 dom0_physinfo_t *pi = &op->u.physinfo;
184 pi->threads_per_core = smp_num_siblings;
185 pi->cores_per_socket = boot_cpu_data.x86_num_cores;
186 pi->sockets_per_node =
187 num_online_cpus() / (pi->threads_per_core * pi->cores_per_socket);
188 pi->nr_nodes = 1;
189 pi->total_pages = max_page;
190 pi->free_pages = avail_domheap_pages();
191 pi->cpu_khz = cpu_khz;
192 memset(pi->hw_cap, 0, sizeof(pi->hw_cap));
193 memcpy(pi->hw_cap, boot_cpu_data.x86_capability, NCAPINTS*4);
194 ret = 0;
195 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
196 ret = -EFAULT;
197 }
198 break;
200 case DOM0_GETPAGEFRAMEINFO:
201 {
202 struct pfn_info *page;
203 unsigned long pfn = op->u.getpageframeinfo.pfn;
204 domid_t dom = op->u.getpageframeinfo.domain;
205 struct domain *d;
207 ret = -EINVAL;
209 if ( unlikely(pfn >= max_page) ||
210 unlikely((d = find_domain_by_id(dom)) == NULL) )
211 break;
213 page = &frame_table[pfn];
215 if ( likely(get_page(page, d)) )
216 {
217 ret = 0;
219 op->u.getpageframeinfo.type = NOTAB;
221 if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
222 {
223 switch ( page->u.inuse.type_info & PGT_type_mask )
224 {
225 case PGT_l1_page_table:
226 op->u.getpageframeinfo.type = L1TAB;
227 break;
228 case PGT_l2_page_table:
229 op->u.getpageframeinfo.type = L2TAB;
230 break;
231 case PGT_l3_page_table:
232 op->u.getpageframeinfo.type = L3TAB;
233 break;
234 case PGT_l4_page_table:
235 op->u.getpageframeinfo.type = L4TAB;
236 break;
237 }
238 }
240 put_page(page);
241 }
243 put_domain(d);
245 copy_to_user(u_dom0_op, op, sizeof(*op));
246 }
247 break;
249 case DOM0_GETPAGEFRAMEINFO2:
250 {
251 #define GPF2_BATCH 128
252 int n,j;
253 int num = op->u.getpageframeinfo2.num;
254 domid_t dom = op->u.getpageframeinfo2.domain;
255 unsigned long *s_ptr = (unsigned long*) op->u.getpageframeinfo2.array;
256 struct domain *d;
257 unsigned long *l_arr;
258 ret = -ESRCH;
260 if ( unlikely((d = find_domain_by_id(dom)) == NULL) )
261 break;
263 if ( unlikely(num > 1024) )
264 {
265 ret = -E2BIG;
266 break;
267 }
269 l_arr = alloc_xenheap_page();
271 ret = 0;
272 for( n = 0; n < num; )
273 {
274 int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n);
276 if ( copy_from_user(l_arr, &s_ptr[n], k*sizeof(unsigned long)) )
277 {
278 ret = -EINVAL;
279 break;
280 }
282 for( j = 0; j < k; j++ )
283 {
284 struct pfn_info *page;
285 unsigned long mfn = l_arr[j];
287 if ( unlikely(mfn >= max_page) )
288 goto e2_err;
290 page = &frame_table[mfn];
292 if ( likely(get_page(page, d)) )
293 {
294 unsigned long type = 0;
296 switch( page->u.inuse.type_info & PGT_type_mask )
297 {
298 case PGT_l1_page_table:
299 type = L1TAB;
300 break;
301 case PGT_l2_page_table:
302 type = L2TAB;
303 break;
304 case PGT_l3_page_table:
305 type = L3TAB;
306 break;
307 case PGT_l4_page_table:
308 type = L4TAB;
309 break;
310 }
312 if ( page->u.inuse.type_info & PGT_pinned )
313 type |= LPINTAB;
314 l_arr[j] |= type;
315 put_page(page);
316 }
317 else
318 {
319 e2_err:
320 l_arr[j] |= XTAB;
321 }
323 }
325 if ( copy_to_user(&s_ptr[n], l_arr, k*sizeof(unsigned long)) )
326 {
327 ret = -EINVAL;
328 break;
329 }
331 n += j;
332 }
334 free_xenheap_page(l_arr);
336 put_domain(d);
337 }
338 break;
340 case DOM0_GETMEMLIST:
341 {
342 int i;
343 struct domain *d = find_domain_by_id(op->u.getmemlist.domain);
344 unsigned long max_pfns = op->u.getmemlist.max_pfns;
345 unsigned long pfn;
346 unsigned long *buffer = op->u.getmemlist.buffer;
347 struct list_head *list_ent;
349 ret = -EINVAL;
350 if ( d != NULL )
351 {
352 ret = 0;
354 spin_lock(&d->page_alloc_lock);
355 list_ent = d->page_list.next;
356 for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
357 {
358 pfn = list_entry(list_ent, struct pfn_info, list) -
359 frame_table;
360 if ( put_user(pfn, buffer) )
361 {
362 ret = -EFAULT;
363 break;
364 }
365 buffer++;
366 list_ent = frame_table[pfn].list.next;
367 }
368 spin_unlock(&d->page_alloc_lock);
370 op->u.getmemlist.num_pfns = i;
371 copy_to_user(u_dom0_op, op, sizeof(*op));
373 put_domain(d);
374 }
375 }
376 break;
378 case DOM0_PLATFORM_QUIRK:
379 {
380 extern int opt_noirqbalance;
381 switch ( op->u.platform_quirk.quirk_id )
382 {
383 case QUIRK_NOIRQBALANCING:
384 printk("Platform quirk -- Disabling IRQ balancing/affinity.\n");
385 opt_noirqbalance = 1;
386 setup_ioapic_dest();
387 break;
388 default:
389 ret = -EINVAL;
390 break;
391 }
392 }
393 break;
395 case DOM0_PHYSICAL_MEMORY_MAP:
396 {
397 struct dom0_memory_map_entry entry;
398 int i;
400 for ( i = 0; i < e820.nr_map; i++ )
401 {
402 if ( i >= op->u.physical_memory_map.max_map_entries )
403 break;
404 entry.start = e820.map[i].addr;
405 entry.end = e820.map[i].addr + e820.map[i].size;
406 entry.is_ram = (e820.map[i].type == E820_RAM);
407 (void)copy_to_user(
408 &op->u.physical_memory_map.memory_map[i],
409 &entry, sizeof(entry));
410 }
412 op->u.physical_memory_map.nr_map_entries = i;
413 (void)copy_to_user(u_dom0_op, op, sizeof(*op));
414 }
415 break;
417 default:
418 ret = -ENOSYS;
419 break;
420 }
422 return ret;
423 }
425 void arch_getdomaininfo_ctxt(
426 struct vcpu *v, struct vcpu_guest_context *c)
427 {
428 extern void save_vmx_cpu_user_regs(struct cpu_user_regs *);
430 memcpy(c, &v->arch.guest_context, sizeof(*c));
432 if ( VMX_DOMAIN(v) )
433 {
434 save_vmx_cpu_user_regs(&c->user_regs);
435 __vmread(CR0_READ_SHADOW, &c->ctrlreg[0]);
436 __vmread(CR4_READ_SHADOW, &c->ctrlreg[4]);
437 }
438 else
439 {
440 /* IOPL privileges are virtualised: merge back into returned eflags. */
441 BUG_ON((c->user_regs.eflags & EF_IOPL) != 0);
442 c->user_regs.eflags |= v->arch.iopl << 12;
443 }
445 c->flags = 0;
446 if ( test_bit(_VCPUF_fpu_initialised, &v->vcpu_flags) )
447 c->flags |= VGCF_I387_VALID;
448 if ( KERNEL_MODE(v, &v->arch.guest_context.user_regs) )
449 c->flags |= VGCF_IN_KERNEL;
450 if (VMX_DOMAIN(v))
451 c->flags |= VGCF_VMX_GUEST;
453 c->ctrlreg[3] = pagetable_get_paddr(v->arch.guest_table);
455 c->vm_assist = v->domain->vm_assist;
456 }