ia64/xen-unstable

view xen/arch/x86/dom0_ops.c @ 8455:188ef899e626

Fix iobmp_mask setup when permitting a domU access to
I/O port ranges.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
author kaf24@firebug.cl.cam.ac.uk
date Wed Dec 28 16:23:42 2005 +0100 (2005-12-28)
parents 3d1c7be170a7
children 4369fd869f51
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 = total_pages;
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 = pfn_to_page(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 (PAGE_SIZE / sizeof(unsigned long))
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 put_domain(d);
267 break;
268 }
270 l_arr = alloc_xenheap_page();
272 ret = 0;
273 for( n = 0; n < num; )
274 {
275 int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n);
277 if ( copy_from_user(l_arr, &s_ptr[n], k*sizeof(unsigned long)) )
278 {
279 ret = -EINVAL;
280 break;
281 }
283 for( j = 0; j < k; j++ )
284 {
285 struct pfn_info *page;
286 unsigned long mfn = l_arr[j];
288 page = pfn_to_page(mfn);
290 if ( likely(pfn_valid(mfn) && get_page(page, d)) )
291 {
292 unsigned long type = 0;
294 switch( page->u.inuse.type_info & PGT_type_mask )
295 {
296 case PGT_l1_page_table:
297 type = L1TAB;
298 break;
299 case PGT_l2_page_table:
300 type = L2TAB;
301 break;
302 case PGT_l3_page_table:
303 type = L3TAB;
304 break;
305 case PGT_l4_page_table:
306 type = L4TAB;
307 break;
308 }
310 if ( page->u.inuse.type_info & PGT_pinned )
311 type |= LPINTAB;
312 l_arr[j] |= type;
313 put_page(page);
314 }
315 else
316 l_arr[j] |= XTAB;
318 }
320 if ( copy_to_user(&s_ptr[n], l_arr, k*sizeof(unsigned long)) )
321 {
322 ret = -EINVAL;
323 break;
324 }
326 n += k;
327 }
329 free_xenheap_page(l_arr);
331 put_domain(d);
332 }
333 break;
335 case DOM0_GETMEMLIST:
336 {
337 int i;
338 struct domain *d = find_domain_by_id(op->u.getmemlist.domain);
339 unsigned long max_pfns = op->u.getmemlist.max_pfns;
340 unsigned long pfn;
341 unsigned long *buffer = op->u.getmemlist.buffer;
342 struct list_head *list_ent;
344 ret = -EINVAL;
345 if ( d != NULL )
346 {
347 ret = 0;
349 spin_lock(&d->page_alloc_lock);
350 list_ent = d->page_list.next;
351 for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
352 {
353 pfn = page_to_pfn(list_entry(list_ent, struct pfn_info, list));
354 if ( put_user(pfn, buffer) )
355 {
356 ret = -EFAULT;
357 break;
358 }
359 buffer++;
360 list_ent = pfn_to_page(pfn)->list.next;
361 }
362 spin_unlock(&d->page_alloc_lock);
364 op->u.getmemlist.num_pfns = i;
365 copy_to_user(u_dom0_op, op, sizeof(*op));
367 put_domain(d);
368 }
369 }
370 break;
372 case DOM0_PLATFORM_QUIRK:
373 {
374 extern int opt_noirqbalance;
375 switch ( op->u.platform_quirk.quirk_id )
376 {
377 case QUIRK_NOIRQBALANCING:
378 printk("Platform quirk -- Disabling IRQ balancing/affinity.\n");
379 opt_noirqbalance = 1;
380 setup_ioapic_dest();
381 break;
382 default:
383 ret = -EINVAL;
384 break;
385 }
386 }
387 break;
389 case DOM0_PHYSICAL_MEMORY_MAP:
390 {
391 struct dom0_memory_map_entry entry;
392 int i;
394 for ( i = 0; i < e820.nr_map; i++ )
395 {
396 if ( i >= op->u.physical_memory_map.max_map_entries )
397 break;
398 entry.start = e820.map[i].addr;
399 entry.end = e820.map[i].addr + e820.map[i].size;
400 entry.is_ram = (e820.map[i].type == E820_RAM);
401 (void)copy_to_user(
402 &op->u.physical_memory_map.memory_map[i],
403 &entry, sizeof(entry));
404 }
406 op->u.physical_memory_map.nr_map_entries = i;
407 (void)copy_to_user(u_dom0_op, op, sizeof(*op));
408 }
409 break;
411 default:
412 ret = -ENOSYS;
413 break;
414 }
416 return ret;
417 }
419 void arch_getdomaininfo_ctxt(
420 struct vcpu *v, struct vcpu_guest_context *c)
421 {
422 extern void save_vmx_cpu_user_regs(struct cpu_user_regs *);
424 memcpy(c, &v->arch.guest_context, sizeof(*c));
426 if ( VMX_DOMAIN(v) )
427 {
428 save_vmx_cpu_user_regs(&c->user_regs);
429 __vmread(CR0_READ_SHADOW, &c->ctrlreg[0]);
430 __vmread(CR4_READ_SHADOW, &c->ctrlreg[4]);
431 }
432 else
433 {
434 /* IOPL privileges are virtualised: merge back into returned eflags. */
435 BUG_ON((c->user_regs.eflags & EF_IOPL) != 0);
436 c->user_regs.eflags |= v->arch.iopl << 12;
437 }
439 c->flags = 0;
440 if ( test_bit(_VCPUF_fpu_initialised, &v->vcpu_flags) )
441 c->flags |= VGCF_I387_VALID;
442 if ( KERNEL_MODE(v, &v->arch.guest_context.user_regs) )
443 c->flags |= VGCF_IN_KERNEL;
444 if (VMX_DOMAIN(v))
445 c->flags |= VGCF_VMX_GUEST;
447 c->ctrlreg[3] = pagetable_get_paddr(v->arch.guest_table);
449 c->vm_assist = v->domain->vm_assist;
450 }