debuggers.hg

view xen/arch/x86/vmx.c @ 4640:e02fc4c21740

bitkeeper revision 1.1345 (4266bd05lHlHunb0CEvOq60j2DvKCQ)

[PATCH] VMX world switch

The attached code implements a VMX world switch to vmxassist (a small assist
module residing in a VMX enabled partition where it is responsible for
emulating real mode) whever CR0.PE is disabled.

The patch temporarily disables the PGE feature flag in cpuid as it is
currently broken (try running an unmodified 2.6 kernel that sets PGE in
mm/init.c/paging_init()).

The patch adds consistency checks before setting the ARCH_VMX_IO_WAIT state
to detect race conditions on SMP systems.

Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com>
Signed-off-by: ian@xensource.com
author leendert@watson.ibm.com[iap10]
date Wed Apr 20 20:35:17 2005 +0000 (2005-04-20)
parents 1803018b3b05
children 717d7dbd06ea
line source
1 /*
2 * vmx.c: handling VMX architecture-related VM exits
3 * Copyright (c) 2004, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 */
20 #include <xen/config.h>
21 #include <xen/init.h>
22 #include <xen/lib.h>
23 #include <xen/trace.h>
24 #include <xen/sched.h>
25 #include <xen/softirq.h>
26 #include <asm/current.h>
27 #include <asm/io.h>
28 #include <asm/irq.h>
29 #include <asm/shadow.h>
30 #include <asm/regs.h>
31 #include <asm/cpufeature.h>
32 #include <asm/processor.h>
33 #include <asm/types.h>
34 #include <asm/msr.h>
35 #include <asm/spinlock.h>
36 #include <asm/vmx.h>
37 #include <asm/vmx_vmcs.h>
38 #include <asm/vmx_intercept.h>
39 #include <asm/shadow.h>
40 #include <public/io/ioreq.h>
42 #ifdef CONFIG_VMX
44 int vmcs_size;
45 unsigned int opt_vmx_debug_level = 0;
47 extern long evtchn_send(int lport);
48 extern long do_block(void);
49 void do_nmi(struct xen_regs *, unsigned long);
51 int start_vmx()
52 {
53 struct vmcs_struct *vmcs;
54 unsigned long ecx;
55 u64 phys_vmcs; /* debugging */
57 vmcs_size = VMCS_SIZE;
58 /*
59 * Xen does not fill x86_capability words except 0.
60 */
61 ecx = cpuid_ecx(1);
62 boot_cpu_data.x86_capability[4] = ecx;
64 if (!(test_bit(X86_FEATURE_VMXE, &boot_cpu_data.x86_capability)))
65 return 0;
67 set_in_cr4(X86_CR4_VMXE); /* Enable VMXE */
69 if (!(vmcs = alloc_vmcs())) {
70 printk("Failed to allocate VMCS\n");
71 return 0;
72 }
74 phys_vmcs = (u64) virt_to_phys(vmcs);
76 if (!(__vmxon(phys_vmcs))) {
77 printk("VMXON is done\n");
78 }
80 return 1;
81 }
83 void stop_vmx()
84 {
85 if (read_cr4() & X86_CR4_VMXE)
86 __vmxoff();
87 }
89 /*
90 * Not all cases recevie valid value in the VM-exit instruction length field.
91 */
92 #define __get_instruction_length(len) \
93 __vmread(INSTRUCTION_LEN, &(len)); \
94 if ((len) < 1 || (len) > 15) \
95 __vmx_bug(&regs);
97 static void inline __update_guest_eip(unsigned long inst_len)
98 {
99 unsigned long current_eip;
101 __vmread(GUEST_EIP, &current_eip);
102 __vmwrite(GUEST_EIP, current_eip + inst_len);
103 }
106 #include <asm/domain_page.h>
108 static int vmx_do_page_fault(unsigned long va, struct xen_regs *regs)
109 {
110 struct exec_domain *ed = current;
111 unsigned long eip;
112 l1_pgentry_t gpte;
113 unsigned long gpa; /* FIXME: PAE */
114 int result;
116 #if VMX_DEBUG
117 {
118 __vmread(GUEST_EIP, &eip);
119 VMX_DBG_LOG(DBG_LEVEL_VMMU,
120 "vmx_do_page_fault = 0x%lx, eip = %lx, error_code = %lx",
121 va, eip, regs->error_code);
122 }
123 #endif
125 /*
126 * If vpagetable is zero, then we are still emulating 1:1 page tables,
127 * and we should have never gotten here.
128 */
129 if ( !test_bit(VMX_CPU_STATE_PG_ENABLED, &ed->arch.arch_vmx.cpu_state) )
130 {
131 printk("vmx_do_page_fault while running on 1:1 page table\n");
132 return 0;
133 }
135 gpte = gva_to_gpte(va);
136 if (!(l1e_get_flags(gpte) & _PAGE_PRESENT) )
137 return 0;
138 gpa = l1e_get_phys(gpte) + (va & ~PAGE_MASK);
140 /* Use 1:1 page table to identify MMIO address space */
141 if (mmio_space(gpa))
142 handle_mmio(va, gpa);
144 result = shadow_fault(va, regs);
146 #if 0
147 if ( !result )
148 {
149 __vmread(GUEST_EIP, &eip);
150 printk("vmx pgfault to guest va=%p eip=%p\n", va, eip);
151 }
152 #endif
154 return result;
155 }
157 static void vmx_do_general_protection_fault(struct xen_regs *regs)
158 {
159 unsigned long eip, error_code;
160 unsigned long intr_fields;
162 __vmread(GUEST_EIP, &eip);
163 __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
165 VMX_DBG_LOG(DBG_LEVEL_1,
166 "vmx_general_protection_fault: eip = %lx, erro_code = %lx",
167 eip, error_code);
169 VMX_DBG_LOG(DBG_LEVEL_1,
170 "eax=%lx, ebx=%lx, ecx=%lx, edx=%lx, esi=%lx, edi=%lx",
171 regs->eax, regs->ebx, regs->ecx, regs->edx, regs->esi, regs->edi);
173 /* Reflect it back into the guest */
174 intr_fields = (INTR_INFO_VALID_MASK |
175 INTR_TYPE_EXCEPTION |
176 INTR_INFO_DELIEVER_CODE_MASK |
177 TRAP_gp_fault);
178 __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
179 __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
180 }
182 static void vmx_vmexit_do_cpuid(unsigned long input, struct xen_regs *regs)
183 {
184 unsigned int eax, ebx, ecx, edx;
185 unsigned long eip;
187 __vmread(GUEST_EIP, &eip);
189 VMX_DBG_LOG(DBG_LEVEL_1,
190 "do_cpuid: (eax) %lx, (ebx) %lx, (ecx) %lx, (edx) %lx,"
191 " (esi) %lx, (edi) %lx",
192 regs->eax, regs->ebx, regs->ecx, regs->edx,
193 regs->esi, regs->edi);
195 cpuid(input, &eax, &ebx, &ecx, &edx);
197 if (input == 1) {
198 clear_bit(X86_FEATURE_PGE, &edx); /* temporarily disabled */
199 clear_bit(X86_FEATURE_PSE, &edx);
200 clear_bit(X86_FEATURE_PAE, &edx);
201 clear_bit(X86_FEATURE_PSE36, &edx);
202 }
204 regs->eax = (unsigned long) eax;
205 regs->ebx = (unsigned long) ebx;
206 regs->ecx = (unsigned long) ecx;
207 regs->edx = (unsigned long) edx;
209 VMX_DBG_LOG(DBG_LEVEL_1,
210 "vmx_vmexit_do_cpuid: eip: %lx, input: %lx, out:eax=%x, ebx=%x, ecx=%x, edx=%x",
211 eip, input, eax, ebx, ecx, edx);
213 }
215 #define CASE_GET_REG_P(REG, reg) \
216 case REG_ ## REG: reg_p = (unsigned long *)&(regs->reg); break
218 static void vmx_dr_access (unsigned long exit_qualification, struct xen_regs *regs)
219 {
220 unsigned int reg;
221 unsigned long *reg_p = 0;
222 struct exec_domain *ed = current;
223 unsigned long eip;
225 __vmread(GUEST_EIP, &eip);
227 reg = exit_qualification & DEBUG_REG_ACCESS_NUM;
229 VMX_DBG_LOG(DBG_LEVEL_1,
230 "vmx_dr_access : eip=%lx, reg=%d, exit_qualification = %lx",
231 eip, reg, exit_qualification);
233 switch(exit_qualification & DEBUG_REG_ACCESS_REG) {
234 CASE_GET_REG_P(EAX, eax);
235 CASE_GET_REG_P(ECX, ecx);
236 CASE_GET_REG_P(EDX, edx);
237 CASE_GET_REG_P(EBX, ebx);
238 CASE_GET_REG_P(EBP, ebp);
239 CASE_GET_REG_P(ESI, esi);
240 CASE_GET_REG_P(EDI, edi);
241 case REG_ESP:
242 break;
243 default:
244 __vmx_bug(regs);
245 }
247 switch (exit_qualification & DEBUG_REG_ACCESS_TYPE) {
248 case TYPE_MOV_TO_DR:
249 /* don't need to check the range */
250 if (reg != REG_ESP)
251 ed->arch.debugreg[reg] = *reg_p;
252 else {
253 unsigned long value;
254 __vmread(GUEST_ESP, &value);
255 ed->arch.debugreg[reg] = value;
256 }
257 break;
258 case TYPE_MOV_FROM_DR:
259 if (reg != REG_ESP)
260 *reg_p = ed->arch.debugreg[reg];
261 else {
262 __vmwrite(GUEST_ESP, ed->arch.debugreg[reg]);
263 }
264 break;
265 }
266 }
268 /*
269 * Invalidate the TLB for va. Invalidate the shadow page corresponding
270 * the address va.
271 */
272 static void vmx_vmexit_do_invlpg(unsigned long va)
273 {
274 unsigned long eip;
275 struct exec_domain *ed = current;
277 __vmread(GUEST_EIP, &eip);
279 VMX_DBG_LOG(DBG_LEVEL_VMMU, "vmx_vmexit_do_invlpg: eip=%p, va=%p",
280 eip, va);
282 /*
283 * We do the safest things first, then try to update the shadow
284 * copying from guest
285 */
286 shadow_invlpg(ed, va);
287 }
289 static void vmx_io_instruction(struct xen_regs *regs,
290 unsigned long exit_qualification, unsigned long inst_len)
291 {
292 struct exec_domain *d = current;
293 vcpu_iodata_t *vio;
294 ioreq_t *p;
295 unsigned long addr;
296 unsigned long eip, cs, eflags;
297 int vm86;
299 __vmread(GUEST_EIP, &eip);
300 __vmread(GUEST_CS_SELECTOR, &cs);
301 __vmread(GUEST_EFLAGS, &eflags);
302 vm86 = eflags & X86_EFLAGS_VM ? 1 : 0;
304 VMX_DBG_LOG(DBG_LEVEL_1,
305 "vmx_io_instruction: vm86 %d, eip=%p:%p, exit_qualification = %lx",
306 vm86, cs, eip, exit_qualification);
308 if (test_bit(6, &exit_qualification))
309 addr = (exit_qualification >> 16) & (0xffff);
310 else
311 addr = regs->edx & 0xffff;
313 if (addr == 0x80) {
314 __update_guest_eip(inst_len);
315 return;
316 }
318 vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
319 if (vio == 0) {
320 VMX_DBG_LOG(DBG_LEVEL_1, "bad shared page: %lx", (unsigned long) vio);
321 domain_crash_synchronous();
322 }
323 p = &vio->vp_ioreq;
324 p->dir = test_bit(3, &exit_qualification);
326 p->pdata_valid = 0;
327 p->count = 1;
328 p->size = (exit_qualification & 7) + 1;
330 if (test_bit(4, &exit_qualification)) {
331 p->df = (eflags & X86_EFLAGS_DF) ? 1 : 0;
332 p->pdata_valid = 1;
334 if (vm86) {
335 unsigned long seg;
336 if (p->dir == IOREQ_WRITE) {
337 __vmread(GUEST_DS_SELECTOR, &seg);
338 p->u.pdata = (void *)
339 ((seg << 4) | (regs->esi & 0xFFFF));
340 } else {
341 __vmread(GUEST_ES_SELECTOR, &seg);
342 p->u.pdata = (void *)
343 ((seg << 4) | (regs->edi & 0xFFFF));
344 }
345 } else {
346 p->u.pdata = (void *) ((p->dir == IOREQ_WRITE) ?
347 regs->esi : regs->edi);
348 }
349 p->u.pdata = (void *) gva_to_gpa(p->u.data);
352 if (test_bit(5, &exit_qualification))
353 p->count = vm86 ? regs->ecx & 0xFFFF : regs->ecx;
354 if ((p->u.data & PAGE_MASK) !=
355 ((p->u.data + p->count * p->size - 1) & PAGE_MASK)) {
356 printk("stringio crosses page boundary!\n");
357 if (p->u.data & (p->size - 1)) {
358 printk("Not aligned I/O!\n");
359 domain_crash_synchronous();
360 }
361 p->count = (PAGE_SIZE - (p->u.data & ~PAGE_MASK)) / p->size;
362 } else {
363 __update_guest_eip(inst_len);
364 }
365 } else if (p->dir == IOREQ_WRITE) {
366 p->u.data = regs->eax;
367 __update_guest_eip(inst_len);
368 } else
369 __update_guest_eip(inst_len);
371 p->addr = addr;
372 p->port_mm = 0;
374 /* Check if the packet needs to be intercepted */
375 if (vmx_io_intercept(p)) {
376 /* no blocking & no evtchn notification */
377 return;
378 }
380 set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
381 p->state = STATE_IOREQ_READY;
382 evtchn_send(IOPACKET_PORT);
383 do_block();
384 }
386 enum { COPY_IN = 0, COPY_OUT };
388 static inline int
389 vmx_copy(void *buf, unsigned long laddr, int size, int dir)
390 {
391 unsigned char *addr;
392 unsigned long mfn;
394 if ((size + (laddr & (PAGE_SIZE - 1))) >= PAGE_SIZE) {
395 printf("vmx_copy exceeds page boundary\n");
396 return 0;
397 }
399 mfn = phys_to_machine_mapping(gva_to_gpte(laddr) >> PAGE_SHIFT);
400 addr = map_domain_mem((mfn << PAGE_SHIFT) | (laddr & ~PAGE_MASK));
402 if (dir == COPY_IN)
403 memcpy(buf, addr, size);
404 else
405 memcpy(addr, buf, size);
407 unmap_domain_mem(addr);
408 return 1;
409 }
411 int
412 vmx_world_save(struct exec_domain *d, struct vmx_assist_context *c)
413 {
414 unsigned long inst_len;
415 int error = 0;
417 error |= __vmread(INSTRUCTION_LEN, &inst_len);
418 error |= __vmread(GUEST_EIP, &c->eip);
419 c->eip += inst_len; /* skip transition instruction */
420 error |= __vmread(GUEST_ESP, &c->esp);
421 error |= __vmread(GUEST_EFLAGS, &c->eflags);
423 error |= __vmread(CR0_READ_SHADOW, &c->cr0);
424 c->cr3 = d->arch.arch_vmx.cpu_cr3;
425 error |= __vmread(CR4_READ_SHADOW, &c->cr4);
427 error |= __vmread(GUEST_IDTR_LIMIT, &c->idtr_limit);
428 error |= __vmread(GUEST_IDTR_BASE, &c->idtr_base);
430 error |= __vmread(GUEST_GDTR_LIMIT, &c->gdtr_limit);
431 error |= __vmread(GUEST_GDTR_BASE, &c->gdtr_base);
433 error |= __vmread(GUEST_CS_SELECTOR, &c->cs_sel);
434 error |= __vmread(GUEST_CS_LIMIT, &c->cs_limit);
435 error |= __vmread(GUEST_CS_BASE, &c->cs_base);
436 error |= __vmread(GUEST_CS_AR_BYTES, &c->cs_arbytes.bytes);
438 error |= __vmread(GUEST_DS_SELECTOR, &c->ds_sel);
439 error |= __vmread(GUEST_DS_LIMIT, &c->ds_limit);
440 error |= __vmread(GUEST_DS_BASE, &c->ds_base);
441 error |= __vmread(GUEST_DS_AR_BYTES, &c->ds_arbytes.bytes);
443 error |= __vmread(GUEST_ES_SELECTOR, &c->es_sel);
444 error |= __vmread(GUEST_ES_LIMIT, &c->es_limit);
445 error |= __vmread(GUEST_ES_BASE, &c->es_base);
446 error |= __vmread(GUEST_ES_AR_BYTES, &c->es_arbytes.bytes);
448 error |= __vmread(GUEST_SS_SELECTOR, &c->ss_sel);
449 error |= __vmread(GUEST_SS_LIMIT, &c->ss_limit);
450 error |= __vmread(GUEST_SS_BASE, &c->ss_base);
451 error |= __vmread(GUEST_SS_AR_BYTES, &c->ss_arbytes.bytes);
453 error |= __vmread(GUEST_FS_SELECTOR, &c->fs_sel);
454 error |= __vmread(GUEST_FS_LIMIT, &c->fs_limit);
455 error |= __vmread(GUEST_FS_BASE, &c->fs_base);
456 error |= __vmread(GUEST_FS_AR_BYTES, &c->fs_arbytes.bytes);
458 error |= __vmread(GUEST_GS_SELECTOR, &c->gs_sel);
459 error |= __vmread(GUEST_GS_LIMIT, &c->gs_limit);
460 error |= __vmread(GUEST_GS_BASE, &c->gs_base);
461 error |= __vmread(GUEST_GS_AR_BYTES, &c->gs_arbytes.bytes);
463 error |= __vmread(GUEST_TR_SELECTOR, &c->tr_sel);
464 error |= __vmread(GUEST_TR_LIMIT, &c->tr_limit);
465 error |= __vmread(GUEST_TR_BASE, &c->tr_base);
466 error |= __vmread(GUEST_TR_AR_BYTES, &c->tr_arbytes.bytes);
468 error |= __vmread(GUEST_LDTR_SELECTOR, &c->ldtr_sel);
469 error |= __vmread(GUEST_LDTR_LIMIT, &c->ldtr_limit);
470 error |= __vmread(GUEST_LDTR_BASE, &c->ldtr_base);
471 error |= __vmread(GUEST_LDTR_AR_BYTES, &c->ldtr_arbytes.bytes);
473 return !error;
474 }
476 int
477 vmx_world_restore(struct exec_domain *d, struct vmx_assist_context *c)
478 {
479 unsigned long mfn, old_cr4;
480 int error = 0;
482 error |= __vmwrite(GUEST_EIP, c->eip);
483 error |= __vmwrite(GUEST_ESP, c->esp);
484 error |= __vmwrite(GUEST_EFLAGS, c->eflags);
486 error |= __vmwrite(CR0_READ_SHADOW, c->cr0);
488 if (c->cr3 == d->arch.arch_vmx.cpu_cr3) {
489 /*
490 * This is simple TLB flush, implying the guest has
491 * removed some translation or changed page attributes.
492 * We simply invalidate the shadow.
493 */
494 mfn = phys_to_machine_mapping(c->cr3 >> PAGE_SHIFT);
495 if ((mfn << PAGE_SHIFT) != pagetable_val(d->arch.guest_table)) {
496 VMX_DBG_LOG(DBG_LEVEL_VMMU, "Invalid CR3 value=%lx", c->cr3);
497 domain_crash_synchronous();
498 return 0;
499 }
500 shadow_sync_all(d->domain);
501 } else {
502 /*
503 * If different, make a shadow. Check if the PDBR is valid
504 * first.
505 */
506 VMX_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %lx", c->cr3);
507 if ((c->cr3 >> PAGE_SHIFT) > d->domain->max_pages) {
508 VMX_DBG_LOG(DBG_LEVEL_VMMU, "Invalid CR3 value=%lx", c->cr3);
509 domain_crash_synchronous();
510 return 0;
511 }
512 mfn = phys_to_machine_mapping(c->cr3 >> PAGE_SHIFT);
513 d->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT);
514 update_pagetables(d);
515 /*
516 * arch.shadow_table should now hold the next CR3 for shadow
517 */
518 d->arch.arch_vmx.cpu_cr3 = c->cr3;
519 VMX_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx", c->cr3);
520 __vmwrite(GUEST_CR3, pagetable_val(d->arch.shadow_table));
521 }
523 error |= __vmread(CR4_READ_SHADOW, &old_cr4);
524 error |= __vmwrite(GUEST_CR4, (c->cr4 | X86_CR4_VMXE));
525 error |= __vmwrite(CR4_READ_SHADOW, c->cr4);
527 error |= __vmwrite(GUEST_IDTR_LIMIT, c->idtr_limit);
528 error |= __vmwrite(GUEST_IDTR_BASE, c->idtr_base);
530 error |= __vmwrite(GUEST_GDTR_LIMIT, c->gdtr_limit);
531 error |= __vmwrite(GUEST_GDTR_BASE, c->gdtr_base);
533 error |= __vmwrite(GUEST_CS_SELECTOR, c->cs_sel);
534 error |= __vmwrite(GUEST_CS_LIMIT, c->cs_limit);
535 error |= __vmwrite(GUEST_CS_BASE, c->cs_base);
536 error |= __vmwrite(GUEST_CS_AR_BYTES, c->cs_arbytes.bytes);
538 error |= __vmwrite(GUEST_DS_SELECTOR, c->ds_sel);
539 error |= __vmwrite(GUEST_DS_LIMIT, c->ds_limit);
540 error |= __vmwrite(GUEST_DS_BASE, c->ds_base);
541 error |= __vmwrite(GUEST_DS_AR_BYTES, c->ds_arbytes.bytes);
543 error |= __vmwrite(GUEST_ES_SELECTOR, c->es_sel);
544 error |= __vmwrite(GUEST_ES_LIMIT, c->es_limit);
545 error |= __vmwrite(GUEST_ES_BASE, c->es_base);
546 error |= __vmwrite(GUEST_ES_AR_BYTES, c->es_arbytes.bytes);
548 error |= __vmwrite(GUEST_SS_SELECTOR, c->ss_sel);
549 error |= __vmwrite(GUEST_SS_LIMIT, c->ss_limit);
550 error |= __vmwrite(GUEST_SS_BASE, c->ss_base);
551 error |= __vmwrite(GUEST_SS_AR_BYTES, c->ss_arbytes.bytes);
553 error |= __vmwrite(GUEST_FS_SELECTOR, c->fs_sel);
554 error |= __vmwrite(GUEST_FS_LIMIT, c->fs_limit);
555 error |= __vmwrite(GUEST_FS_BASE, c->fs_base);
556 error |= __vmwrite(GUEST_FS_AR_BYTES, c->fs_arbytes.bytes);
558 error |= __vmwrite(GUEST_GS_SELECTOR, c->gs_sel);
559 error |= __vmwrite(GUEST_GS_LIMIT, c->gs_limit);
560 error |= __vmwrite(GUEST_GS_BASE, c->gs_base);
561 error |= __vmwrite(GUEST_GS_AR_BYTES, c->gs_arbytes.bytes);
563 error |= __vmwrite(GUEST_TR_SELECTOR, c->tr_sel);
564 error |= __vmwrite(GUEST_TR_LIMIT, c->tr_limit);
565 error |= __vmwrite(GUEST_TR_BASE, c->tr_base);
566 error |= __vmwrite(GUEST_TR_AR_BYTES, c->tr_arbytes.bytes);
568 error |= __vmwrite(GUEST_LDTR_SELECTOR, c->ldtr_sel);
569 error |= __vmwrite(GUEST_LDTR_LIMIT, c->ldtr_limit);
570 error |= __vmwrite(GUEST_LDTR_BASE, c->ldtr_base);
571 error |= __vmwrite(GUEST_LDTR_AR_BYTES, c->ldtr_arbytes.bytes);
573 return !error;
574 }
576 enum { VMX_ASSIST_INVOKE = 0, VMX_ASSIST_RESTORE };
578 int
579 vmx_assist(struct exec_domain *d, int mode)
580 {
581 struct vmx_assist_context c;
582 unsigned long magic, cp;
584 /* make sure vmxassist exists (this is not an error) */
585 if (!vmx_copy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), COPY_IN))
586 return 0;
587 if (magic != VMXASSIST_MAGIC)
588 return 0;
590 switch (mode) {
591 /*
592 * Transfer control to vmxassist.
593 * Store the current context in VMXASSIST_OLD_CONTEXT and load
594 * the new VMXASSIST_NEW_CONTEXT context. This context was created
595 * by vmxassist and will transfer control to it.
596 */
597 case VMX_ASSIST_INVOKE:
598 /* save the old context */
599 if (!vmx_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), COPY_IN))
600 goto error;
601 if (cp != 0) {
602 if (!vmx_world_save(d, &c))
603 goto error;
604 if (!vmx_copy(&c, cp, sizeof(c), COPY_OUT))
605 goto error;
606 }
608 /* restore the new context, this should activate vmxassist */
609 if (!vmx_copy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), COPY_IN))
610 goto error;
611 if (cp != 0) {
612 if (!vmx_copy(&c, cp, sizeof(c), COPY_IN))
613 goto error;
614 if (!vmx_world_restore(d, &c))
615 goto error;
616 return 1;
617 }
618 break;
620 /*
621 * Restore the VMXASSIST_OLD_CONTEXT that was saved by VMX_ASSIST_INVOKE
622 * above.
623 */
624 case VMX_ASSIST_RESTORE:
625 /* save the old context */
626 if (!vmx_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), COPY_IN))
627 goto error;
628 if (cp != 0) {
629 if (!vmx_copy(&c, cp, sizeof(c), COPY_IN))
630 goto error;
631 if (!vmx_world_restore(d, &c))
632 goto error;
633 return 1;
634 }
635 break;
636 }
638 error:
639 printf("Failed to transfer to vmxassist\n");
640 domain_crash_synchronous();
641 return 0;
642 }
644 #define CASE_GET_REG(REG, reg) \
645 case REG_ ## REG: value = regs->reg; break
647 /*
648 * Write to control registers
649 */
650 static int mov_to_cr(int gp, int cr, struct xen_regs *regs)
651 {
652 unsigned long value;
653 unsigned long old_cr;
654 unsigned long eip;
655 struct exec_domain *d = current;
657 switch (gp) {
658 CASE_GET_REG(EAX, eax);
659 CASE_GET_REG(ECX, ecx);
660 CASE_GET_REG(EDX, edx);
661 CASE_GET_REG(EBX, ebx);
662 CASE_GET_REG(EBP, ebp);
663 CASE_GET_REG(ESI, esi);
664 CASE_GET_REG(EDI, edi);
665 case REG_ESP:
666 __vmread(GUEST_ESP, &value);
667 break;
668 default:
669 printk("invalid gp: %d\n", gp);
670 __vmx_bug(regs);
671 }
673 VMX_DBG_LOG(DBG_LEVEL_1, "mov_to_cr: CR%d, value = %lx,", cr, value);
674 VMX_DBG_LOG(DBG_LEVEL_1, "current = %lx,", (unsigned long) current);
676 switch(cr) {
677 case 0:
678 {
679 unsigned long old_base_mfn = 0, mfn;
681 /*
682 * CR0:
683 * We don't want to lose PE and PG.
684 */
685 __vmwrite(GUEST_CR0, (value | X86_CR0_PE | X86_CR0_PG));
686 __vmwrite(CR0_READ_SHADOW, value);
688 if (value & (X86_CR0_PE | X86_CR0_PG) &&
689 !test_bit(VMX_CPU_STATE_PG_ENABLED, &d->arch.arch_vmx.cpu_state)) {
690 /*
691 * Enable paging
692 */
693 set_bit(VMX_CPU_STATE_PG_ENABLED, &d->arch.arch_vmx.cpu_state);
694 /*
695 * The guest CR3 must be pointing to the guest physical.
696 */
697 if (!VALID_MFN(mfn = phys_to_machine_mapping(
698 d->arch.arch_vmx.cpu_cr3 >> PAGE_SHIFT)))
699 {
700 VMX_DBG_LOG(DBG_LEVEL_VMMU, "Invalid CR3 value = %lx",
701 d->arch.arch_vmx.cpu_cr3);
702 domain_crash_synchronous(); /* need to take a clean path */
703 }
704 old_base_mfn = pagetable_val(d->arch.guest_table) >> PAGE_SHIFT;
706 /*
707 * Now arch.guest_table points to machine physical.
708 */
709 d->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT);
710 update_pagetables(d);
712 VMX_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
713 (unsigned long) (mfn << PAGE_SHIFT));
715 __vmwrite(GUEST_CR3, pagetable_val(d->arch.shadow_table));
716 /*
717 * arch->shadow_table should hold the next CR3 for shadow
718 */
719 VMX_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
720 d->arch.arch_vmx.cpu_cr3, mfn);
721 /* undo the get_page done in the para virt case */
722 put_page_and_type(&frame_table[old_base_mfn]);
723 } else {
724 if ((value & X86_CR0_PE) == 0) {
725 __vmread(GUEST_EIP, &eip);
726 VMX_DBG_LOG(DBG_LEVEL_1,
727 "Disabling CR0.PE at %%eip 0x%lx", eip);
728 if (vmx_assist(d, VMX_ASSIST_INVOKE)) {
729 set_bit(VMX_CPU_STATE_ASSIST_ENABLED,
730 &d->arch.arch_vmx.cpu_state);
731 __vmread(GUEST_EIP, &eip);
732 VMX_DBG_LOG(DBG_LEVEL_1,
733 "Transfering control to vmxassist %%eip 0x%lx", eip);
734 return 0; /* do not update eip! */
735 }
736 } else if (test_bit(VMX_CPU_STATE_ASSIST_ENABLED,
737 &d->arch.arch_vmx.cpu_state)) {
738 __vmread(GUEST_EIP, &eip);
739 VMX_DBG_LOG(DBG_LEVEL_1,
740 "Enabling CR0.PE at %%eip 0x%lx", eip);
741 if (vmx_assist(d, VMX_ASSIST_RESTORE)) {
742 clear_bit(VMX_CPU_STATE_ASSIST_ENABLED,
743 &d->arch.arch_vmx.cpu_state);
744 __vmread(GUEST_EIP, &eip);
745 VMX_DBG_LOG(DBG_LEVEL_1,
746 "Restoring to %%eip 0x%lx", eip);
747 return 0; /* do not update eip! */
748 }
749 }
750 }
751 break;
752 }
753 case 3:
754 {
755 unsigned long mfn;
757 /*
758 * If paging is not enabled yet, simply copy the value to CR3.
759 */
760 if (!test_bit(VMX_CPU_STATE_PG_ENABLED, &d->arch.arch_vmx.cpu_state)) {
761 d->arch.arch_vmx.cpu_cr3 = value;
762 break;
763 }
765 /*
766 * We make a new one if the shadow does not exist.
767 */
768 if (value == d->arch.arch_vmx.cpu_cr3) {
769 /*
770 * This is simple TLB flush, implying the guest has
771 * removed some translation or changed page attributes.
772 * We simply invalidate the shadow.
773 */
774 mfn = phys_to_machine_mapping(value >> PAGE_SHIFT);
775 if ((mfn << PAGE_SHIFT) != pagetable_val(d->arch.guest_table))
776 __vmx_bug(regs);
777 shadow_sync_all(d->domain);
778 } else {
779 /*
780 * If different, make a shadow. Check if the PDBR is valid
781 * first.
782 */
783 VMX_DBG_LOG(DBG_LEVEL_VMMU, "CR3 value = %lx", value);
784 if ((value >> PAGE_SHIFT) > d->domain->max_pages)
785 {
786 VMX_DBG_LOG(DBG_LEVEL_VMMU,
787 "Invalid CR3 value=%lx", value);
788 domain_crash_synchronous(); /* need to take a clean path */
789 }
790 mfn = phys_to_machine_mapping(value >> PAGE_SHIFT);
791 d->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT);
792 update_pagetables(d);
793 /*
794 * arch.shadow_table should now hold the next CR3 for shadow
795 */
796 d->arch.arch_vmx.cpu_cr3 = value;
797 VMX_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx",
798 value);
799 __vmwrite(GUEST_CR3, pagetable_val(d->arch.shadow_table));
800 }
801 break;
802 }
803 case 4:
804 /* CR4 */
805 if (value & X86_CR4_PAE)
806 __vmx_bug(regs); /* not implemented */
807 __vmread(CR4_READ_SHADOW, &old_cr);
809 __vmwrite(GUEST_CR4, (value | X86_CR4_VMXE));
810 __vmwrite(CR4_READ_SHADOW, value);
812 /*
813 * Writing to CR4 to modify the PSE, PGE, or PAE flag invalidates
814 * all TLB entries except global entries.
815 */
816 if ((old_cr ^ value) & (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE)) {
817 vmx_shadow_clear_state(d->domain);
818 shadow_sync_all(d->domain);
819 }
820 break;
821 default:
822 printk("invalid cr: %d\n", gp);
823 __vmx_bug(regs);
824 }
826 return 1;
827 }
829 #define CASE_SET_REG(REG, reg) \
830 case REG_ ## REG: \
831 regs->reg = value; \
832 break
834 /*
835 * Read from control registers. CR0 and CR4 are read from the shadow.
836 */
837 static void mov_from_cr(int cr, int gp, struct xen_regs *regs)
838 {
839 unsigned long value;
840 struct exec_domain *d = current;
842 if (cr != 3)
843 __vmx_bug(regs);
845 value = (unsigned long) d->arch.arch_vmx.cpu_cr3;
846 ASSERT(value);
848 switch (gp) {
849 CASE_SET_REG(EAX, eax);
850 CASE_SET_REG(ECX, ecx);
851 CASE_SET_REG(EDX, edx);
852 CASE_SET_REG(EBX, ebx);
853 CASE_SET_REG(EBP, ebp);
854 CASE_SET_REG(ESI, esi);
855 CASE_SET_REG(EDI, edi);
856 case REG_ESP:
857 __vmwrite(GUEST_ESP, value);
858 regs->esp = value;
859 break;
860 default:
861 printk("invalid gp: %d\n", gp);
862 __vmx_bug(regs);
863 }
865 VMX_DBG_LOG(DBG_LEVEL_VMMU, "mov_from_cr: CR%d, value = %lx,", cr, value);
866 }
868 static int vmx_cr_access(unsigned long exit_qualification, struct xen_regs *regs)
869 {
870 unsigned int gp, cr;
871 unsigned long value;
873 switch (exit_qualification & CONTROL_REG_ACCESS_TYPE) {
874 case TYPE_MOV_TO_CR:
875 gp = exit_qualification & CONTROL_REG_ACCESS_REG;
876 cr = exit_qualification & CONTROL_REG_ACCESS_NUM;
877 return mov_to_cr(gp, cr, regs);
878 case TYPE_MOV_FROM_CR:
879 gp = exit_qualification & CONTROL_REG_ACCESS_REG;
880 cr = exit_qualification & CONTROL_REG_ACCESS_NUM;
881 mov_from_cr(cr, gp, regs);
882 break;
883 case TYPE_CLTS:
884 __vmread(GUEST_CR0, &value);
885 value &= ~X86_CR0_TS; /* clear TS */
886 __vmwrite(GUEST_CR0, value);
888 __vmread(CR0_READ_SHADOW, &value);
889 value &= ~X86_CR0_TS; /* clear TS */
890 __vmwrite(CR0_READ_SHADOW, value);
891 break;
892 default:
893 __vmx_bug(regs);
894 break;
895 }
896 return 1;
897 }
899 static inline void vmx_do_msr_read(struct xen_regs *regs)
900 {
901 VMX_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read: ecx=%lx, eax=%lx, edx=%lx",
902 regs->ecx, regs->eax, regs->edx);
904 rdmsr(regs->ecx, regs->eax, regs->edx);
906 VMX_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read returns: "
907 "ecx=%lx, eax=%lx, edx=%lx",
908 regs->ecx, regs->eax, regs->edx);
909 }
911 /*
912 * Need to use this exit to reschedule
913 */
914 static inline void vmx_vmexit_do_hlt(void)
915 {
916 #if VMX_DEBUG
917 unsigned long eip;
918 __vmread(GUEST_EIP, &eip);
919 #endif
920 VMX_DBG_LOG(DBG_LEVEL_1, "vmx_vmexit_do_hlt:eip=%p", eip);
921 raise_softirq(SCHEDULE_SOFTIRQ);
922 }
924 static inline void vmx_vmexit_do_mwait(void)
925 {
926 #if VMX_DEBUG
927 unsigned long eip;
928 __vmread(GUEST_EIP, &eip);
929 #endif
930 VMX_DBG_LOG(DBG_LEVEL_1, "vmx_vmexit_do_mwait:eip=%p", eip);
931 raise_softirq(SCHEDULE_SOFTIRQ);
932 }
934 #define BUF_SIZ 256
935 #define MAX_LINE 80
936 char print_buf[BUF_SIZ];
937 static int index;
939 static void vmx_print_line(const char c, struct exec_domain *d)
940 {
942 if (index == MAX_LINE || c == '\n') {
943 if (index == MAX_LINE) {
944 print_buf[index++] = c;
945 }
946 print_buf[index] = '\0';
947 printk("(GUEST: %u) %s\n", d->domain->id, (char *) &print_buf);
948 index = 0;
949 }
950 else
951 print_buf[index++] = c;
952 }
954 void save_vmx_execution_context(execution_context_t *ctxt)
955 {
956 __vmread(GUEST_SS_SELECTOR, &ctxt->ss);
957 __vmread(GUEST_ESP, &ctxt->esp);
958 __vmread(GUEST_EFLAGS, &ctxt->eflags);
959 __vmread(GUEST_CS_SELECTOR, &ctxt->cs);
960 __vmread(GUEST_EIP, &ctxt->eip);
962 __vmread(GUEST_GS_SELECTOR, &ctxt->gs);
963 __vmread(GUEST_FS_SELECTOR, &ctxt->fs);
964 __vmread(GUEST_ES_SELECTOR, &ctxt->es);
965 __vmread(GUEST_DS_SELECTOR, &ctxt->ds);
966 }
968 #ifdef XEN_DEBUGGER
969 void save_xen_regs(struct xen_regs *regs)
970 {
971 __vmread(GUEST_SS_SELECTOR, &regs->xss);
972 __vmread(GUEST_ESP, &regs->esp);
973 __vmread(GUEST_EFLAGS, &regs->eflags);
974 __vmread(GUEST_CS_SELECTOR, &regs->xcs);
975 __vmread(GUEST_EIP, &regs->eip);
977 __vmread(GUEST_GS_SELECTOR, &regs->xgs);
978 __vmread(GUEST_FS_SELECTOR, &regs->xfs);
979 __vmread(GUEST_ES_SELECTOR, &regs->xes);
980 __vmread(GUEST_DS_SELECTOR, &regs->xds);
981 }
983 void restore_xen_regs(struct xen_regs *regs)
984 {
985 __vmwrite(GUEST_SS_SELECTOR, regs->xss);
986 __vmwrite(GUEST_ESP, regs->esp);
987 __vmwrite(GUEST_EFLAGS, regs->eflags);
988 __vmwrite(GUEST_CS_SELECTOR, regs->xcs);
989 __vmwrite(GUEST_EIP, regs->eip);
991 __vmwrite(GUEST_GS_SELECTOR, regs->xgs);
992 __vmwrite(GUEST_FS_SELECTOR, regs->xfs);
993 __vmwrite(GUEST_ES_SELECTOR, regs->xes);
994 __vmwrite(GUEST_DS_SELECTOR, regs->xds);
995 }
996 #endif
998 asmlinkage void vmx_vmexit_handler(struct xen_regs regs)
999 {
1000 unsigned int exit_reason, idtv_info_field;
1001 unsigned long exit_qualification, eip, inst_len = 0;
1002 struct exec_domain *ed = current;
1003 int error;
1005 if ((error = __vmread(VM_EXIT_REASON, &exit_reason)))
1006 __vmx_bug(&regs);
1008 perfc_incra(vmexits, exit_reason);
1010 __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
1011 if (idtv_info_field & INTR_INFO_VALID_MASK) {
1012 __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
1013 if ((idtv_info_field & 0xff) == 14) {
1014 unsigned long error_code;
1016 __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
1017 printk("#PG error code: %lx\n", error_code);
1019 VMX_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x",
1020 idtv_info_field);
1023 /* don't bother H/W interrutps */
1024 if (exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT &&
1025 exit_reason != EXIT_REASON_VMCALL &&
1026 exit_reason != EXIT_REASON_IO_INSTRUCTION)
1027 VMX_DBG_LOG(DBG_LEVEL_0, "exit reason = %x", exit_reason);
1029 if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) {
1030 domain_crash_synchronous();
1031 return;
1034 __vmread(GUEST_EIP, &eip);
1035 TRACE_3D(TRC_VMX_VMEXIT, ed->domain->id, eip, exit_reason);
1037 switch (exit_reason) {
1038 case EXIT_REASON_EXCEPTION_NMI:
1040 /*
1041 * We don't set the software-interrupt exiting (INT n).
1042 * (1) We can get an exception (e.g. #PG) in the guest, or
1043 * (2) NMI
1044 */
1045 int error;
1046 unsigned int vector;
1047 unsigned long va;
1049 if ((error = __vmread(VM_EXIT_INTR_INFO, &vector))
1050 && !(vector & INTR_INFO_VALID_MASK))
1051 __vmx_bug(&regs);
1052 vector &= 0xff;
1054 perfc_incra(cause_vector, vector);
1056 TRACE_3D(TRC_VMX_VECTOR, ed->domain->id, eip, vector);
1057 switch (vector) {
1058 #ifdef XEN_DEBUGGER
1059 case TRAP_debug:
1061 save_xen_regs(&regs);
1062 pdb_handle_exception(1, &regs, 1);
1063 restore_xen_regs(&regs);
1064 break;
1066 case TRAP_int3:
1068 save_xen_regs(&regs);
1069 pdb_handle_exception(3, &regs, 1);
1070 restore_xen_regs(&regs);
1071 break;
1073 #endif
1074 case TRAP_gp_fault:
1076 vmx_do_general_protection_fault(&regs);
1077 break;
1079 case TRAP_page_fault:
1081 __vmread(EXIT_QUALIFICATION, &va);
1082 __vmread(VM_EXIT_INTR_ERROR_CODE, &regs.error_code);
1083 VMX_DBG_LOG(DBG_LEVEL_VMMU,
1084 "eax=%lx, ebx=%lx, ecx=%lx, edx=%lx, esi=%lx, edi=%lx",
1085 regs.eax, regs.ebx, regs.ecx, regs.edx, regs.esi,
1086 regs.edi);
1087 ed->arch.arch_vmx.vmx_platform.mpci.inst_decoder_regs = &regs;
1089 if (!(error = vmx_do_page_fault(va, &regs))) {
1090 /*
1091 * Inject #PG using Interruption-Information Fields
1092 */
1093 unsigned long intr_fields;
1095 intr_fields = (INTR_INFO_VALID_MASK |
1096 INTR_TYPE_EXCEPTION |
1097 INTR_INFO_DELIEVER_CODE_MASK |
1098 TRAP_page_fault);
1099 __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
1100 __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, regs.error_code);
1101 ed->arch.arch_vmx.cpu_cr2 = va;
1102 TRACE_3D(TRC_VMX_INT, ed->domain->id, TRAP_page_fault, va);
1104 break;
1106 case TRAP_nmi:
1107 do_nmi(&regs, 0);
1108 break;
1109 default:
1110 printk("unexpected VMexit for exception vector 0x%x\n", vector);
1111 //__vmx_bug(&regs);
1112 break;
1114 break;
1116 case EXIT_REASON_EXTERNAL_INTERRUPT:
1118 extern int vector_irq[];
1119 extern asmlinkage void do_IRQ(struct xen_regs *);
1120 extern void smp_apic_timer_interrupt(struct xen_regs *);
1121 extern void timer_interrupt(int, void *, struct xen_regs *);
1122 unsigned int vector;
1124 if ((error = __vmread(VM_EXIT_INTR_INFO, &vector))
1125 && !(vector & INTR_INFO_VALID_MASK))
1126 __vmx_bug(&regs);
1128 vector &= 0xff;
1129 local_irq_disable();
1131 if (vector == LOCAL_TIMER_VECTOR) {
1132 smp_apic_timer_interrupt(&regs);
1133 } else {
1134 regs.entry_vector = (vector == FIRST_DEVICE_VECTOR?
1135 0 : vector_irq[vector]);
1136 do_IRQ(&regs);
1138 break;
1140 case EXIT_REASON_PENDING_INTERRUPT:
1141 __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
1142 MONITOR_CPU_BASED_EXEC_CONTROLS);
1143 vmx_intr_assist(ed);
1144 break;
1145 case EXIT_REASON_TASK_SWITCH:
1146 __vmx_bug(&regs);
1147 break;
1148 case EXIT_REASON_CPUID:
1149 __get_instruction_length(inst_len);
1150 vmx_vmexit_do_cpuid(regs.eax, &regs);
1151 __update_guest_eip(inst_len);
1152 break;
1153 case EXIT_REASON_HLT:
1154 __get_instruction_length(inst_len);
1155 __update_guest_eip(inst_len);
1156 vmx_vmexit_do_hlt();
1157 break;
1158 case EXIT_REASON_INVLPG:
1160 unsigned long va;
1162 __vmread(EXIT_QUALIFICATION, &va);
1163 vmx_vmexit_do_invlpg(va);
1164 __get_instruction_length(inst_len);
1165 __update_guest_eip(inst_len);
1166 break;
1168 case EXIT_REASON_VMCALL:
1169 __get_instruction_length(inst_len);
1170 __vmread(GUEST_EIP, &eip);
1171 __vmread(EXIT_QUALIFICATION, &exit_qualification);
1173 vmx_print_line(regs.eax, ed); /* provides the current domain */
1174 __update_guest_eip(inst_len);
1175 break;
1176 case EXIT_REASON_CR_ACCESS:
1178 __vmread(GUEST_EIP, &eip);
1179 __get_instruction_length(inst_len);
1180 __vmread(EXIT_QUALIFICATION, &exit_qualification);
1182 VMX_DBG_LOG(DBG_LEVEL_1, "eip = %lx, inst_len =%lx, exit_qualification = %lx",
1183 eip, inst_len, exit_qualification);
1184 if (vmx_cr_access(exit_qualification, &regs))
1185 __update_guest_eip(inst_len);
1186 break;
1188 case EXIT_REASON_DR_ACCESS:
1189 __vmread(EXIT_QUALIFICATION, &exit_qualification);
1190 vmx_dr_access(exit_qualification, &regs);
1191 __get_instruction_length(inst_len);
1192 __update_guest_eip(inst_len);
1193 break;
1194 case EXIT_REASON_IO_INSTRUCTION:
1195 __vmread(EXIT_QUALIFICATION, &exit_qualification);
1196 __get_instruction_length(inst_len);
1197 vmx_io_instruction(&regs, exit_qualification, inst_len);
1198 break;
1199 case EXIT_REASON_MSR_READ:
1200 __get_instruction_length(inst_len);
1201 vmx_do_msr_read(&regs);
1202 __update_guest_eip(inst_len);
1203 break;
1204 case EXIT_REASON_MSR_WRITE:
1205 __vmread(GUEST_EIP, &eip);
1206 VMX_DBG_LOG(DBG_LEVEL_1, "MSR_WRITE: eip=%p, eax=%p, edx=%p",
1207 eip, regs.eax, regs.edx);
1208 /* just ignore this point */
1209 __get_instruction_length(inst_len);
1210 __update_guest_eip(inst_len);
1211 break;
1212 case EXIT_REASON_MWAIT_INSTRUCTION:
1213 __get_instruction_length(inst_len);
1214 __update_guest_eip(inst_len);
1215 vmx_vmexit_do_mwait();
1216 break;
1217 default:
1218 __vmx_bug(&regs); /* should not happen */
1221 vmx_intr_assist(ed);
1222 return;
1225 asmlinkage void load_cr2(void)
1227 struct exec_domain *d = current;
1229 local_irq_disable();
1230 #ifdef __i386__
1231 asm volatile("movl %0,%%cr2": :"r" (d->arch.arch_vmx.cpu_cr2));
1232 #else
1233 asm volatile("movq %0,%%cr2": :"r" (d->arch.arch_vmx.cpu_cr2));
1234 #endif
1238 #endif /* CONFIG_VMX */
1240 /*
1241 * Local variables:
1242 * mode: C
1243 * c-set-style: "BSD"
1244 * c-basic-offset: 4
1245 * tab-width: 4
1246 * indent-tabs-mode: nil
1247 * End:
1248 */