ia64/xen-unstable

view xen/arch/x86/hvm/vmx/realmode.c @ 16468:9f61a0add5b6

x86_emulate: Emulate CPUID and HLT.
vmx realmode: Fix decode & emulate loop, add hooks for CPUID, HLT and
WBINVD. Also do not hook realmode entry off of vmentry failure any
more.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Nov 26 15:32:54 2007 +0000 (2007-11-26)
parents bb961bda7eff
children 11bfa26dd125
line source
1 /******************************************************************************
2 * arch/x86/hvm/vmx/realmode.c
3 *
4 * Real-mode emulation for VMX.
5 *
6 * Copyright (c) 2007 Citrix Systems, Inc.
7 *
8 * Authors:
9 * Keir Fraser <keir.fraser@citrix.com>
10 */
12 #include <xen/config.h>
13 #include <xen/init.h>
14 #include <xen/lib.h>
15 #include <xen/sched.h>
16 #include <asm/event.h>
17 #include <asm/hvm/hvm.h>
18 #include <asm/hvm/support.h>
19 #include <asm/hvm/vmx/vmx.h>
20 #include <asm/hvm/vmx/vmcs.h>
21 #include <asm/hvm/vmx/cpu.h>
22 #include <asm/x86_emulate.h>
24 struct realmode_emulate_ctxt {
25 struct x86_emulate_ctxt ctxt;
27 /* Cache of 16 bytes of instruction. */
28 uint8_t insn_buf[16];
29 unsigned long insn_buf_eip;
31 struct segment_register seg_reg[10];
33 union {
34 struct {
35 unsigned int hlt:1;
36 unsigned int mov_ss:1;
37 unsigned int sti:1;
38 unsigned int exn_raised:1;
39 } flags;
40 unsigned int flag_word;
41 };
42 };
44 static void realmode_deliver_exception(
45 unsigned int vector,
46 unsigned int insn_len,
47 struct realmode_emulate_ctxt *rm_ctxt)
48 {
49 struct segment_register *idtr = &rm_ctxt->seg_reg[x86_seg_idtr];
50 struct segment_register *csr = &rm_ctxt->seg_reg[x86_seg_cs];
51 struct cpu_user_regs *regs = rm_ctxt->ctxt.regs;
52 uint32_t cs_eip, pstk;
53 uint16_t frame[3];
54 unsigned int last_byte;
56 again:
57 last_byte = (vector * 4) + 3;
58 if ( idtr->limit < last_byte )
59 {
60 /* Software interrupt? */
61 if ( insn_len != 0 )
62 {
63 insn_len = 0;
64 vector = TRAP_gp_fault;
65 goto again;
66 }
68 /* Exception or hardware interrupt. */
69 switch ( vector )
70 {
71 case TRAP_double_fault:
72 hvm_triple_fault();
73 return;
74 case TRAP_gp_fault:
75 vector = TRAP_double_fault;
76 goto again;
77 default:
78 vector = TRAP_gp_fault;
79 goto again;
80 }
81 }
83 (void)hvm_copy_from_guest_phys(&cs_eip, idtr->base + vector * 4, 4);
85 frame[0] = regs->eip + insn_len;
86 frame[1] = csr->sel;
87 frame[2] = regs->eflags & ~X86_EFLAGS_RF;
89 if ( rm_ctxt->ctxt.addr_size == 32 )
90 {
91 regs->esp -= 4;
92 pstk = regs->esp;
93 }
94 else
95 {
96 pstk = (uint16_t)(regs->esp - 4);
97 regs->esp &= ~0xffff;
98 regs->esp |= pstk;
99 }
101 pstk += rm_ctxt->seg_reg[x86_seg_ss].base;
102 (void)hvm_copy_to_guest_phys(pstk, frame, sizeof(frame));
104 csr->sel = cs_eip >> 16;
105 csr->base = (uint32_t)csr->sel << 4;
106 regs->eip = (uint16_t)cs_eip;
107 regs->eflags &= ~(X86_EFLAGS_AC | X86_EFLAGS_TF |
108 X86_EFLAGS_AC | X86_EFLAGS_RF);
109 }
111 static int
112 realmode_read(
113 enum x86_segment seg,
114 unsigned long offset,
115 unsigned long *val,
116 unsigned int bytes,
117 enum hvm_access_type access_type,
118 struct realmode_emulate_ctxt *rm_ctxt)
119 {
120 uint32_t addr = rm_ctxt->seg_reg[seg].base + offset;
121 int todo;
123 *val = 0;
124 todo = hvm_copy_from_guest_phys(val, addr, bytes);
126 if ( todo )
127 {
128 struct vcpu *curr = current;
130 if ( todo != bytes )
131 {
132 gdprintk(XENLOG_WARNING, "RM: Partial read at %08x (%d/%d)\n",
133 addr, todo, bytes);
134 return X86EMUL_UNHANDLEABLE;
135 }
137 if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
138 return X86EMUL_UNHANDLEABLE;
140 if ( !curr->arch.hvm_vmx.real_mode_io_completed )
141 {
142 curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
143 send_mmio_req(IOREQ_TYPE_COPY, addr, 1, bytes,
144 0, IOREQ_READ, 0, 0);
145 }
147 if ( !curr->arch.hvm_vmx.real_mode_io_completed )
148 return X86EMUL_UNHANDLEABLE;
150 *val = curr->arch.hvm_vmx.real_mode_io_data;
151 curr->arch.hvm_vmx.real_mode_io_completed = 0;
152 }
154 return X86EMUL_OKAY;
155 }
157 static int
158 realmode_emulate_read(
159 enum x86_segment seg,
160 unsigned long offset,
161 unsigned long *val,
162 unsigned int bytes,
163 struct x86_emulate_ctxt *ctxt)
164 {
165 return realmode_read(
166 seg, offset, val, bytes, hvm_access_read,
167 container_of(ctxt, struct realmode_emulate_ctxt, ctxt));
168 }
170 static int
171 realmode_emulate_insn_fetch(
172 enum x86_segment seg,
173 unsigned long offset,
174 unsigned long *val,
175 unsigned int bytes,
176 struct x86_emulate_ctxt *ctxt)
177 {
178 struct realmode_emulate_ctxt *rm_ctxt =
179 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
180 unsigned int insn_off = offset - rm_ctxt->insn_buf_eip;
182 /* Fall back if requested bytes are not in the prefetch cache. */
183 if ( unlikely((insn_off + bytes) > sizeof(rm_ctxt->insn_buf)) )
184 return realmode_read(
185 seg, offset, val, bytes,
186 hvm_access_insn_fetch, rm_ctxt);
188 /* Hit the cache. Simple memcpy. */
189 *val = 0;
190 memcpy(val, &rm_ctxt->insn_buf[insn_off], bytes);
191 return X86EMUL_OKAY;
192 }
194 static int
195 realmode_emulate_write(
196 enum x86_segment seg,
197 unsigned long offset,
198 unsigned long val,
199 unsigned int bytes,
200 struct x86_emulate_ctxt *ctxt)
201 {
202 struct realmode_emulate_ctxt *rm_ctxt =
203 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
204 uint32_t addr = rm_ctxt->seg_reg[seg].base + offset;
205 int todo;
207 todo = hvm_copy_to_guest_phys(addr, &val, bytes);
209 if ( todo )
210 {
211 struct vcpu *curr = current;
213 if ( todo != bytes )
214 {
215 gdprintk(XENLOG_WARNING, "RM: Partial write at %08x (%d/%d)\n",
216 addr, todo, bytes);
217 return X86EMUL_UNHANDLEABLE;
218 }
220 if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
221 return X86EMUL_UNHANDLEABLE;
223 curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
224 send_mmio_req(IOREQ_TYPE_COPY, addr, 1, bytes,
225 val, IOREQ_WRITE, 0, 0);
226 }
228 return X86EMUL_OKAY;
229 }
231 static int
232 realmode_emulate_cmpxchg(
233 enum x86_segment seg,
234 unsigned long offset,
235 unsigned long old,
236 unsigned long new,
237 unsigned int bytes,
238 struct x86_emulate_ctxt *ctxt)
239 {
240 return X86EMUL_UNHANDLEABLE;
241 }
243 static int
244 realmode_read_segment(
245 enum x86_segment seg,
246 struct segment_register *reg,
247 struct x86_emulate_ctxt *ctxt)
248 {
249 struct realmode_emulate_ctxt *rm_ctxt =
250 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
251 memcpy(reg, &rm_ctxt->seg_reg[seg], sizeof(struct segment_register));
252 return X86EMUL_OKAY;
253 }
255 static int
256 realmode_write_segment(
257 enum x86_segment seg,
258 struct segment_register *reg,
259 struct x86_emulate_ctxt *ctxt)
260 {
261 struct realmode_emulate_ctxt *rm_ctxt =
262 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
263 memcpy(&rm_ctxt->seg_reg[seg], reg, sizeof(struct segment_register));
264 if ( seg == x86_seg_ss )
265 rm_ctxt->flags.mov_ss = 1;
266 return X86EMUL_OKAY;
267 }
269 static int
270 realmode_read_io(
271 unsigned int port,
272 unsigned int bytes,
273 unsigned long *val,
274 struct x86_emulate_ctxt *ctxt)
275 {
276 struct vcpu *curr = current;
278 if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
279 return X86EMUL_UNHANDLEABLE;
281 if ( !curr->arch.hvm_vmx.real_mode_io_completed )
282 {
283 curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
284 send_pio_req(port, 1, bytes, 0, IOREQ_READ, 0, 0);
285 }
287 if ( !curr->arch.hvm_vmx.real_mode_io_completed )
288 return X86EMUL_UNHANDLEABLE;
290 *val = curr->arch.hvm_vmx.real_mode_io_data;
291 curr->arch.hvm_vmx.real_mode_io_completed = 0;
293 return X86EMUL_OKAY;
294 }
296 static int realmode_write_io(
297 unsigned int port,
298 unsigned int bytes,
299 unsigned long val,
300 struct x86_emulate_ctxt *ctxt)
301 {
302 struct vcpu *curr = current;
304 if ( port == 0xe9 )
305 {
306 hvm_print_line(curr, val);
307 return X86EMUL_OKAY;
308 }
310 if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
311 return X86EMUL_UNHANDLEABLE;
313 curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
314 send_pio_req(port, 1, bytes, val, IOREQ_WRITE, 0, 0);
316 return X86EMUL_OKAY;
317 }
319 static int
320 realmode_read_cr(
321 unsigned int reg,
322 unsigned long *val,
323 struct x86_emulate_ctxt *ctxt)
324 {
325 switch ( reg )
326 {
327 case 0:
328 case 2:
329 case 3:
330 case 4:
331 *val = current->arch.hvm_vcpu.guest_cr[reg];
332 break;
333 default:
334 return X86EMUL_UNHANDLEABLE;
335 }
337 return X86EMUL_OKAY;
338 }
340 static int realmode_write_rflags(
341 unsigned long val,
342 struct x86_emulate_ctxt *ctxt)
343 {
344 struct realmode_emulate_ctxt *rm_ctxt =
345 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
346 if ( (val & X86_EFLAGS_IF) && !(ctxt->regs->eflags & X86_EFLAGS_IF) )
347 rm_ctxt->flags.sti = 1;
348 return X86EMUL_OKAY;
349 }
351 static int realmode_wbinvd(
352 struct x86_emulate_ctxt *ctxt)
353 {
354 vmx_wbinvd_intercept();
355 return X86EMUL_OKAY;
356 }
358 static int realmode_cpuid(
359 unsigned int *eax,
360 unsigned int *ebx,
361 unsigned int *ecx,
362 unsigned int *edx,
363 struct x86_emulate_ctxt *ctxt)
364 {
365 vmx_cpuid_intercept(eax, ebx, ecx, edx);
366 return X86EMUL_OKAY;
367 }
369 static int realmode_hlt(
370 struct x86_emulate_ctxt *ctxt)
371 {
372 struct realmode_emulate_ctxt *rm_ctxt =
373 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
374 rm_ctxt->flags.hlt = 1;
375 return X86EMUL_OKAY;
376 }
378 static int realmode_inject_hw_exception(
379 uint8_t vector,
380 struct x86_emulate_ctxt *ctxt)
381 {
382 struct realmode_emulate_ctxt *rm_ctxt =
383 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
385 rm_ctxt->flags.exn_raised = 1;
386 realmode_deliver_exception(vector, 0, rm_ctxt);
388 return X86EMUL_OKAY;
389 }
391 static int realmode_inject_sw_interrupt(
392 uint8_t vector,
393 uint8_t insn_len,
394 struct x86_emulate_ctxt *ctxt)
395 {
396 struct realmode_emulate_ctxt *rm_ctxt =
397 container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
399 realmode_deliver_exception(vector, insn_len, rm_ctxt);
401 return X86EMUL_OKAY;
402 }
404 static struct x86_emulate_ops realmode_emulator_ops = {
405 .read = realmode_emulate_read,
406 .insn_fetch = realmode_emulate_insn_fetch,
407 .write = realmode_emulate_write,
408 .cmpxchg = realmode_emulate_cmpxchg,
409 .read_segment = realmode_read_segment,
410 .write_segment = realmode_write_segment,
411 .read_io = realmode_read_io,
412 .write_io = realmode_write_io,
413 .read_cr = realmode_read_cr,
414 .write_rflags = realmode_write_rflags,
415 .wbinvd = realmode_wbinvd,
416 .cpuid = realmode_cpuid,
417 .hlt = realmode_hlt,
418 .inject_hw_exception = realmode_inject_hw_exception,
419 .inject_sw_interrupt = realmode_inject_sw_interrupt
420 };
422 int vmx_realmode(struct cpu_user_regs *regs)
423 {
424 struct vcpu *curr = current;
425 struct realmode_emulate_ctxt rm_ctxt;
426 unsigned long intr_info;
427 int i, rc = 0;
428 u32 intr_shadow, new_intr_shadow;
430 rm_ctxt.ctxt.regs = regs;
432 for ( i = 0; i < 10; i++ )
433 hvm_get_segment_register(curr, i, &rm_ctxt.seg_reg[i]);
435 rm_ctxt.ctxt.addr_size =
436 rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
437 rm_ctxt.ctxt.sp_size =
438 rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
440 intr_info = __vmread(VM_ENTRY_INTR_INFO);
441 if ( intr_info & INTR_INFO_VALID_MASK )
442 {
443 __vmwrite(VM_ENTRY_INTR_INFO, 0);
444 realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
445 }
447 intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
448 new_intr_shadow = intr_shadow;
450 while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
451 !softirq_pending(smp_processor_id()) &&
452 !hvm_local_events_need_delivery(curr) )
453 {
454 rm_ctxt.insn_buf_eip = regs->eip;
455 (void)hvm_copy_from_guest_phys(
456 rm_ctxt.insn_buf,
457 (uint32_t)(rm_ctxt.seg_reg[x86_seg_cs].base + regs->eip),
458 sizeof(rm_ctxt.insn_buf));
460 rm_ctxt.flag_word = 0;
462 rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
464 /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
465 if ( rm_ctxt.flags.mov_ss )
466 new_intr_shadow ^= VMX_INTR_SHADOW_MOV_SS;
467 else
468 new_intr_shadow &= ~VMX_INTR_SHADOW_MOV_SS;
470 /* STI instruction toggles STI shadow, else we just clear it. */
471 if ( rm_ctxt.flags.sti )
472 new_intr_shadow ^= VMX_INTR_SHADOW_STI;
473 else
474 new_intr_shadow &= ~VMX_INTR_SHADOW_STI;
476 /* Update interrupt shadow information in VMCS only if it changes. */
477 if ( intr_shadow != new_intr_shadow )
478 {
479 intr_shadow = new_intr_shadow;
480 __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
481 }
483 /* HLT happens after instruction retire, if no interrupt/exception. */
484 if ( unlikely(rm_ctxt.flags.hlt) &&
485 !rm_ctxt.flags.exn_raised &&
486 !hvm_local_events_need_delivery(curr) )
487 hvm_hlt(regs->eflags);
489 if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
490 {
491 rc = 0;
492 break;
493 }
495 if ( rc == X86EMUL_UNHANDLEABLE )
496 {
497 gdprintk(XENLOG_DEBUG,
498 "RM %04x:%08lx: %02x %02x %02x %02x %02x %02x\n",
499 rm_ctxt.seg_reg[x86_seg_cs].sel, rm_ctxt.insn_buf_eip,
500 rm_ctxt.insn_buf[0], rm_ctxt.insn_buf[1],
501 rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
502 rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
503 gdprintk(XENLOG_ERR, "Emulation failed\n");
504 rc = -EINVAL;
505 break;
506 }
507 }
509 for ( i = 0; i < 10; i++ )
510 hvm_set_segment_register(curr, i, &rm_ctxt.seg_reg[i]);
512 return rc;
513 }
515 int vmx_realmode_io_complete(void)
516 {
517 struct vcpu *curr = current;
518 ioreq_t *p = &get_ioreq(curr)->vp_ioreq;
520 if ( !curr->arch.hvm_vmx.real_mode_io_in_progress )
521 return 0;
523 #if 0
524 gdprintk(XENLOG_DEBUG, "RM I/O %d %c bytes=%d addr=%lx data=%lx\n",
525 p->type, p->dir ? 'R' : 'W',
526 (int)p->size, (long)p->addr, (long)p->data);
527 #endif
529 curr->arch.hvm_vmx.real_mode_io_in_progress = 0;
530 if ( p->dir == IOREQ_READ )
531 {
532 curr->arch.hvm_vmx.real_mode_io_completed = 1;
533 curr->arch.hvm_vmx.real_mode_io_data = p->data;
534 }
536 return 1;
537 }