ia64/xen-unstable

view xen/arch/x86/dom0_ops.c @ 10892:0d2ba35c0cf2

[XEN] Add hypercall support for HVM guests. This is
fairly useless at the moment, since all of the hypercalls
fail, since copy_from_user doesn't work correctly in HVM
domains.

Signed-off-by: Steven Smith <ssmith@xensource.com>

Add a CPUID hypervisor platform interface at leaf
0x40000000. Allow hypercall transfer page to be filled
in via MSR 0x40000000.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Tue Aug 01 17:18:05 2006 +0100 (2006-08-01)
parents 74018b65c369
children 88e6bd5e2b54
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 <xen/guest_access.h>
14 #include <public/dom0_ops.h>
15 #include <xen/sched.h>
16 #include <xen/event.h>
17 #include <xen/domain_page.h>
18 #include <asm/msr.h>
19 #include <xen/trace.h>
20 #include <xen/console.h>
21 #include <xen/iocap.h>
22 #include <asm/shadow.h>
23 #include <asm/irq.h>
24 #include <asm/hvm/hvm.h>
25 #include <asm/hvm/support.h>
26 #include <asm/processor.h>
27 #include <public/sched_ctl.h>
29 #include <asm/mtrr.h>
30 #include "cpu/mtrr/mtrr.h"
32 #define TRC_DOM0OP_ENTER_BASE 0x00020000
33 #define TRC_DOM0OP_LEAVE_BASE 0x00030000
35 static int msr_cpu_mask;
36 static unsigned long msr_addr;
37 static unsigned long msr_lo;
38 static unsigned long msr_hi;
40 static void write_msr_for(void *unused)
41 {
42 if ( ((1 << smp_processor_id()) & msr_cpu_mask) )
43 (void)wrmsr_safe(msr_addr, msr_lo, msr_hi);
44 }
46 static void read_msr_for(void *unused)
47 {
48 if ( ((1 << smp_processor_id()) & msr_cpu_mask) )
49 (void)rdmsr_safe(msr_addr, msr_lo, msr_hi);
50 }
52 long arch_do_dom0_op(struct dom0_op *op, XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
53 {
54 long ret = 0;
56 switch ( op->cmd )
57 {
59 case DOM0_MSR:
60 {
61 if ( op->u.msr.write )
62 {
63 msr_cpu_mask = op->u.msr.cpu_mask;
64 msr_addr = op->u.msr.msr;
65 msr_lo = op->u.msr.in1;
66 msr_hi = op->u.msr.in2;
67 smp_call_function(write_msr_for, NULL, 1, 1);
68 write_msr_for(NULL);
69 }
70 else
71 {
72 msr_cpu_mask = op->u.msr.cpu_mask;
73 msr_addr = op->u.msr.msr;
74 smp_call_function(read_msr_for, NULL, 1, 1);
75 read_msr_for(NULL);
77 op->u.msr.out1 = msr_lo;
78 op->u.msr.out2 = msr_hi;
79 copy_to_guest(u_dom0_op, op, 1);
80 }
81 ret = 0;
82 }
83 break;
85 case DOM0_SHADOW_CONTROL:
86 {
87 struct domain *d;
88 ret = -ESRCH;
89 d = find_domain_by_id(op->u.shadow_control.domain);
90 if ( d != NULL )
91 {
92 ret = shadow_mode_control(d, &op->u.shadow_control);
93 put_domain(d);
94 copy_to_guest(u_dom0_op, op, 1);
95 }
96 }
97 break;
99 case DOM0_ADD_MEMTYPE:
100 {
101 ret = mtrr_add_page(
102 op->u.add_memtype.mfn,
103 op->u.add_memtype.nr_mfns,
104 op->u.add_memtype.type,
105 1);
106 if ( ret > 0 )
107 {
108 op->u.add_memtype.handle = 0;
109 op->u.add_memtype.reg = ret;
110 (void)copy_to_guest(u_dom0_op, op, 1);
111 ret = 0;
112 }
113 }
114 break;
116 case DOM0_DEL_MEMTYPE:
117 {
118 if (op->u.del_memtype.handle == 0
119 /* mtrr/main.c otherwise does a lookup */
120 && (int)op->u.del_memtype.reg >= 0)
121 {
122 ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);
123 if (ret > 0)
124 ret = 0;
125 }
126 else
127 ret = -EINVAL;
128 }
129 break;
131 case DOM0_READ_MEMTYPE:
132 {
133 unsigned long mfn;
134 unsigned int nr_mfns;
135 mtrr_type type;
137 ret = -EINVAL;
138 if ( op->u.read_memtype.reg < num_var_ranges )
139 {
140 mtrr_if->get(op->u.read_memtype.reg, &mfn, &nr_mfns, &type);
141 op->u.read_memtype.mfn = mfn;
142 op->u.read_memtype.nr_mfns = nr_mfns;
143 op->u.read_memtype.type = type;
144 (void)copy_to_guest(u_dom0_op, op, 1);
145 ret = 0;
146 }
147 }
148 break;
150 case DOM0_MICROCODE:
151 {
152 extern int microcode_update(void *buf, unsigned long len);
153 ret = microcode_update(op->u.microcode.data.p, op->u.microcode.length);
154 }
155 break;
157 case DOM0_IOPORT_PERMISSION:
158 {
159 struct domain *d;
160 unsigned int fp = op->u.ioport_permission.first_port;
161 unsigned int np = op->u.ioport_permission.nr_ports;
163 ret = -EINVAL;
164 if ( (fp + np) > 65536 )
165 break;
167 ret = -ESRCH;
168 if ( unlikely((d = find_domain_by_id(
169 op->u.ioport_permission.domain)) == NULL) )
170 break;
172 if ( np == 0 )
173 ret = 0;
174 else if ( op->u.ioport_permission.allow_access )
175 ret = ioports_permit_access(d, fp, fp + np - 1);
176 else
177 ret = ioports_deny_access(d, fp, fp + np - 1);
179 put_domain(d);
180 }
181 break;
183 case DOM0_PHYSINFO:
184 {
185 dom0_physinfo_t *pi = &op->u.physinfo;
187 pi->threads_per_core =
188 cpus_weight(cpu_sibling_map[0]);
189 pi->cores_per_socket =
190 cpus_weight(cpu_core_map[0]) / pi->threads_per_core;
191 pi->sockets_per_node =
192 num_online_cpus() / cpus_weight(cpu_core_map[0]);
194 pi->nr_nodes = 1;
195 pi->total_pages = total_pages;
196 pi->free_pages = avail_domheap_pages();
197 pi->scrub_pages = avail_scrub_pages();
198 pi->cpu_khz = cpu_khz;
199 memset(pi->hw_cap, 0, sizeof(pi->hw_cap));
200 memcpy(pi->hw_cap, boot_cpu_data.x86_capability, NCAPINTS*4);
201 ret = 0;
202 if ( copy_to_guest(u_dom0_op, op, 1) )
203 ret = -EFAULT;
204 }
205 break;
207 case DOM0_GETPAGEFRAMEINFO:
208 {
209 struct page_info *page;
210 unsigned long mfn = op->u.getpageframeinfo.gmfn;
211 domid_t dom = op->u.getpageframeinfo.domain;
212 struct domain *d;
214 ret = -EINVAL;
216 if ( unlikely(!mfn_valid(mfn)) ||
217 unlikely((d = find_domain_by_id(dom)) == NULL) )
218 break;
220 page = mfn_to_page(mfn);
222 if ( likely(get_page(page, d)) )
223 {
224 ret = 0;
226 op->u.getpageframeinfo.type = NOTAB;
228 if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
229 {
230 switch ( page->u.inuse.type_info & PGT_type_mask )
231 {
232 case PGT_l1_page_table:
233 op->u.getpageframeinfo.type = L1TAB;
234 break;
235 case PGT_l2_page_table:
236 op->u.getpageframeinfo.type = L2TAB;
237 break;
238 case PGT_l3_page_table:
239 op->u.getpageframeinfo.type = L3TAB;
240 break;
241 case PGT_l4_page_table:
242 op->u.getpageframeinfo.type = L4TAB;
243 break;
244 }
245 }
247 put_page(page);
248 }
250 put_domain(d);
252 copy_to_guest(u_dom0_op, op, 1);
253 }
254 break;
256 case DOM0_GETPAGEFRAMEINFO2:
257 {
258 #define GPF2_BATCH (PAGE_SIZE / sizeof(unsigned long))
259 int n,j;
260 int num = op->u.getpageframeinfo2.num;
261 domid_t dom = op->u.getpageframeinfo2.domain;
262 struct domain *d;
263 unsigned long *l_arr;
264 ret = -ESRCH;
266 if ( unlikely((d = find_domain_by_id(dom)) == NULL) )
267 break;
269 if ( unlikely(num > 1024) )
270 {
271 ret = -E2BIG;
272 put_domain(d);
273 break;
274 }
276 l_arr = alloc_xenheap_page();
278 ret = 0;
279 for( n = 0; n < num; )
280 {
281 int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n);
283 if ( copy_from_guest_offset(l_arr, op->u.getpageframeinfo2.array,
284 n, k) )
285 {
286 ret = -EINVAL;
287 break;
288 }
290 for( j = 0; j < k; j++ )
291 {
292 struct page_info *page;
293 unsigned long mfn = l_arr[j];
295 page = mfn_to_page(mfn);
297 if ( likely(mfn_valid(mfn) && get_page(page, d)) )
298 {
299 unsigned long type = 0;
301 switch( page->u.inuse.type_info & PGT_type_mask )
302 {
303 case PGT_l1_page_table:
304 type = L1TAB;
305 break;
306 case PGT_l2_page_table:
307 type = L2TAB;
308 break;
309 case PGT_l3_page_table:
310 type = L3TAB;
311 break;
312 case PGT_l4_page_table:
313 type = L4TAB;
314 break;
315 }
317 if ( page->u.inuse.type_info & PGT_pinned )
318 type |= LPINTAB;
319 l_arr[j] |= type;
320 put_page(page);
321 }
322 else
323 l_arr[j] |= XTAB;
325 }
327 if ( copy_to_guest_offset(op->u.getpageframeinfo2.array,
328 n, l_arr, k) )
329 {
330 ret = -EINVAL;
331 break;
332 }
334 n += k;
335 }
337 free_xenheap_page(l_arr);
339 put_domain(d);
340 }
341 break;
343 case DOM0_GETMEMLIST:
344 {
345 int i;
346 struct domain *d = find_domain_by_id(op->u.getmemlist.domain);
347 unsigned long max_pfns = op->u.getmemlist.max_pfns;
348 unsigned long mfn;
349 struct list_head *list_ent;
351 ret = -EINVAL;
352 if ( d != NULL )
353 {
354 ret = 0;
356 spin_lock(&d->page_alloc_lock);
357 list_ent = d->page_list.next;
358 for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
359 {
360 mfn = page_to_mfn(list_entry(
361 list_ent, struct page_info, list));
362 if ( copy_to_guest_offset(op->u.getmemlist.buffer,
363 i, &mfn, 1) )
364 {
365 ret = -EFAULT;
366 break;
367 }
368 list_ent = mfn_to_page(mfn)->list.next;
369 }
370 spin_unlock(&d->page_alloc_lock);
372 op->u.getmemlist.num_pfns = i;
373 copy_to_guest(u_dom0_op, op, 1);
375 put_domain(d);
376 }
377 }
378 break;
380 case DOM0_PLATFORM_QUIRK:
381 {
382 extern int opt_noirqbalance;
383 int quirk_id = op->u.platform_quirk.quirk_id;
384 switch ( quirk_id )
385 {
386 case QUIRK_NOIRQBALANCING:
387 printk("Platform quirk -- Disabling IRQ balancing/affinity.\n");
388 opt_noirqbalance = 1;
389 setup_ioapic_dest();
390 break;
391 case QUIRK_IOAPIC_BAD_REGSEL:
392 case QUIRK_IOAPIC_GOOD_REGSEL:
393 #ifndef sis_apic_bug
394 sis_apic_bug = (quirk_id == QUIRK_IOAPIC_BAD_REGSEL);
395 DPRINTK("Domain 0 says that IO-APIC REGSEL is %s\n",
396 sis_apic_bug ? "bad" : "good");
397 #else
398 BUG_ON(sis_apic_bug != (quirk_id == QUIRK_IOAPIC_BAD_REGSEL));
399 #endif
400 break;
401 default:
402 ret = -EINVAL;
403 break;
404 }
405 }
406 break;
408 case DOM0_HYPERCALL_INIT:
409 {
410 struct domain *d = find_domain_by_id(op->u.hypercall_init.domain);
411 unsigned long gmfn = op->u.hypercall_init.gmfn;
412 unsigned long mfn;
413 void *hypercall_page;
415 ret = -ESRCH;
416 if ( unlikely(d == NULL) )
417 break;
419 mfn = gmfn_to_mfn(d, gmfn);
421 ret = -EACCES;
422 if ( !mfn_valid(mfn) ||
423 !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
424 {
425 put_domain(d);
426 break;
427 }
429 ret = 0;
431 hypercall_page = map_domain_page(mfn);
432 hypercall_page_initialise(d, hypercall_page);
433 unmap_domain_page(hypercall_page);
435 put_page_and_type(mfn_to_page(mfn));
437 put_domain(d);
438 }
439 break;
441 default:
442 ret = -ENOSYS;
443 break;
444 }
446 return ret;
447 }
449 void arch_getdomaininfo_ctxt(
450 struct vcpu *v, struct vcpu_guest_context *c)
451 {
452 memcpy(c, &v->arch.guest_context, sizeof(*c));
454 if ( hvm_guest(v) )
455 {
456 hvm_store_cpu_guest_regs(v, &c->user_regs, c->ctrlreg);
457 }
458 else
459 {
460 /* IOPL privileges are virtualised: merge back into returned eflags. */
461 BUG_ON((c->user_regs.eflags & EF_IOPL) != 0);
462 c->user_regs.eflags |= v->arch.iopl << 12;
463 }
465 c->flags = 0;
466 if ( test_bit(_VCPUF_fpu_initialised, &v->vcpu_flags) )
467 c->flags |= VGCF_I387_VALID;
468 if ( guest_kernel_mode(v, &v->arch.guest_context.user_regs) )
469 c->flags |= VGCF_IN_KERNEL;
470 if ( hvm_guest(v) )
471 c->flags |= VGCF_HVM_GUEST;
473 c->ctrlreg[3] = xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
475 c->vm_assist = v->domain->vm_assist;
476 }
478 /*
479 * Local variables:
480 * mode: C
481 * c-set-style: "BSD"
482 * c-basic-offset: 4
483 * tab-width: 4
484 * indent-tabs-mode: nil
485 * End:
486 */