debuggers.hg

view xen/arch/x86/hvm/emulate.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 5c0bf00e371d
line source
1 /******************************************************************************
2 * hvm/emulate.c
3 *
4 * HVM instruction emulation. Used for MMIO and VMX real mode.
5 *
6 * Copyright (c) 2008, 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 <xen/paging.h>
17 #include <asm/event.h>
18 #include <asm/hvm/emulate.h>
19 #include <asm/hvm/hvm.h>
20 #include <asm/hvm/support.h>
22 static int hvmemul_do_io(
23 int is_mmio, paddr_t addr, unsigned long *reps, int size,
24 paddr_t value, int dir, int df, int value_is_ptr, unsigned long *val)
25 {
26 struct vcpu *curr = current;
27 vcpu_iodata_t *vio = get_ioreq(curr);
28 ioreq_t *p = &vio->vp_ioreq;
29 int rc;
31 /* Only retrieve the value from singleton (non-REP) reads. */
32 ASSERT((val == NULL) || ((dir == IOREQ_READ) && !value_is_ptr));
34 if ( is_mmio && !value_is_ptr )
35 {
36 /* Part of a multi-cycle read or write? */
37 if ( dir == IOREQ_WRITE )
38 {
39 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_write_pa;
40 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_write_bytes;
41 if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) )
42 return X86EMUL_OKAY;
43 }
44 else
45 {
46 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_read_pa;
47 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_read_bytes;
48 if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) )
49 {
50 *val = 0;
51 memcpy(val, &curr->arch.hvm_vcpu.mmio_large_read[addr - pa],
52 size);
53 return X86EMUL_OKAY;
54 }
55 }
56 }
58 switch ( curr->arch.hvm_vcpu.io_state )
59 {
60 case HVMIO_none:
61 break;
62 case HVMIO_completed:
63 curr->arch.hvm_vcpu.io_state = HVMIO_none;
64 if ( val == NULL )
65 return X86EMUL_UNHANDLEABLE;
66 goto finish_access;
67 case HVMIO_dispatched:
68 /* May have to wait for previous cycle of a multi-write to complete. */
69 if ( is_mmio && !value_is_ptr && (dir == IOREQ_WRITE) &&
70 (addr == (curr->arch.hvm_vcpu.mmio_large_write_pa +
71 curr->arch.hvm_vcpu.mmio_large_write_bytes)) )
72 return X86EMUL_RETRY;
73 default:
74 return X86EMUL_UNHANDLEABLE;
75 }
77 if ( p->state != STATE_IOREQ_NONE )
78 {
79 gdprintk(XENLOG_WARNING, "WARNING: io already pending (%d)?\n",
80 p->state);
81 return X86EMUL_UNHANDLEABLE;
82 }
84 curr->arch.hvm_vcpu.io_state =
85 (val == NULL) ? HVMIO_dispatched : HVMIO_awaiting_completion;
87 p->dir = dir;
88 p->data_is_ptr = value_is_ptr;
89 p->type = is_mmio ? IOREQ_TYPE_COPY : IOREQ_TYPE_PIO;
90 p->size = size;
91 p->addr = addr;
92 p->count = *reps;
93 p->df = df;
94 p->data = value;
95 p->io_count++;
97 if ( is_mmio )
98 {
99 rc = hvm_mmio_intercept(p);
100 if ( rc == X86EMUL_UNHANDLEABLE )
101 rc = hvm_buffered_io_intercept(p);
102 }
103 else
104 {
105 rc = hvm_portio_intercept(p);
106 }
108 switch ( rc )
109 {
110 case X86EMUL_OKAY:
111 case X86EMUL_RETRY:
112 *reps = p->count;
113 p->state = STATE_IORESP_READY;
114 hvm_io_assist();
115 curr->arch.hvm_vcpu.io_state = HVMIO_none;
116 break;
117 case X86EMUL_UNHANDLEABLE:
118 hvm_send_assist_req(curr);
119 rc = (val != NULL) ? X86EMUL_RETRY : X86EMUL_OKAY;
120 break;
121 default:
122 BUG();
123 }
125 if ( rc != X86EMUL_OKAY )
126 return rc;
128 finish_access:
129 if ( val != NULL )
130 *val = curr->arch.hvm_vcpu.io_data;
132 if ( is_mmio && !value_is_ptr )
133 {
134 /* Part of a multi-cycle read or write? */
135 if ( dir == IOREQ_WRITE )
136 {
137 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_write_pa;
138 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_write_bytes;
139 if ( bytes == 0 )
140 pa = curr->arch.hvm_vcpu.mmio_large_write_pa = addr;
141 if ( addr == (pa + bytes) )
142 curr->arch.hvm_vcpu.mmio_large_write_bytes += size;
143 }
144 else
145 {
146 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_read_pa;
147 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_read_bytes;
148 if ( bytes == 0 )
149 pa = curr->arch.hvm_vcpu.mmio_large_read_pa = addr;
150 if ( (addr == (pa + bytes)) &&
151 ((bytes + size) <
152 sizeof(curr->arch.hvm_vcpu.mmio_large_read)) )
153 {
154 memcpy(&curr->arch.hvm_vcpu.mmio_large_read[addr - pa],
155 val, size);
156 curr->arch.hvm_vcpu.mmio_large_read_bytes += size;
157 }
158 }
159 }
161 return X86EMUL_OKAY;
162 }
164 static int hvmemul_do_pio(
165 unsigned long port, unsigned long *reps, int size,
166 paddr_t value, int dir, int df, int value_is_ptr, unsigned long *val)
167 {
168 return hvmemul_do_io(0, port, reps, size, value,
169 dir, df, value_is_ptr, val);
170 }
172 static int hvmemul_do_mmio(
173 paddr_t gpa, unsigned long *reps, int size,
174 paddr_t value, int dir, int df, int value_is_ptr, unsigned long *val)
175 {
176 return hvmemul_do_io(1, gpa, reps, size, value,
177 dir, df, value_is_ptr, val);
178 }
180 /*
181 * Convert addr from linear to physical form, valid over the range
182 * [addr, addr + *reps * bytes_per_rep]. *reps is adjusted according to
183 * the valid computed range. It is always >0 when X86EMUL_OKAY is returned.
184 * @pfec indicates the access checks to be performed during page-table walks.
185 */
186 static int hvmemul_linear_to_phys(
187 unsigned long addr,
188 paddr_t *paddr,
189 unsigned int bytes_per_rep,
190 unsigned long *reps,
191 uint32_t pfec,
192 struct hvm_emulate_ctxt *hvmemul_ctxt)
193 {
194 struct vcpu *curr = current;
195 unsigned long pfn, npfn, done, todo, i;
197 /* Clip repetitions to a sensible maximum. */
198 *reps = min_t(unsigned long, *reps, 4096);
200 /* With no paging it's easy: linear == physical. */
201 if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG) )
202 {
203 *paddr = addr;
204 return X86EMUL_OKAY;
205 }
207 *paddr = addr & ~PAGE_MASK;
209 /* Get the first PFN in the range. */
210 if ( (pfn = paging_gva_to_gfn(curr, addr, &pfec)) == INVALID_GFN )
211 {
212 hvm_inject_exception(TRAP_page_fault, pfec, addr);
213 return X86EMUL_EXCEPTION;
214 }
216 /* If the range does not straddle a page boundary then we're done. */
217 done = PAGE_SIZE - (addr & ~PAGE_MASK);
218 todo = *reps * bytes_per_rep;
219 if ( done >= todo )
220 goto done;
222 addr += done;
223 for ( i = 1; done < todo; i++ )
224 {
225 /* Get the next PFN in the range. */
226 npfn = paging_gva_to_gfn(curr, addr, &pfec);
228 /* Is it contiguous with the preceding PFNs? If not then we're done. */
229 if ( (npfn == INVALID_GFN) || (npfn != (pfn + i)) )
230 {
231 done /= bytes_per_rep;
232 if ( done == 0 )
233 {
234 if ( npfn != INVALID_GFN )
235 return X86EMUL_UNHANDLEABLE;
236 hvm_inject_exception(TRAP_page_fault, pfec, addr);
237 return X86EMUL_EXCEPTION;
238 }
239 *reps = done;
240 break;
241 }
243 addr += PAGE_SIZE;
244 done += PAGE_SIZE;
245 }
247 done:
248 *paddr |= (paddr_t)pfn << PAGE_SHIFT;
249 return X86EMUL_OKAY;
250 }
253 static int hvmemul_virtual_to_linear(
254 enum x86_segment seg,
255 unsigned long offset,
256 unsigned int bytes,
257 enum hvm_access_type access_type,
258 struct hvm_emulate_ctxt *hvmemul_ctxt,
259 unsigned long *paddr)
260 {
261 struct segment_register *reg;
262 int okay;
264 if ( seg == x86_seg_none )
265 {
266 *paddr = offset;
267 return X86EMUL_OKAY;
268 }
270 reg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
271 okay = hvm_virtual_to_linear_addr(
272 seg, reg, offset, bytes, access_type,
273 hvmemul_ctxt->ctxt.addr_size, paddr);
275 if ( !okay )
276 {
277 hvmemul_ctxt->exn_pending = 1;
278 hvmemul_ctxt->exn_vector = TRAP_gp_fault;
279 hvmemul_ctxt->exn_error_code = 0;
280 hvmemul_ctxt->exn_insn_len = 0;
281 return X86EMUL_EXCEPTION;
282 }
284 return X86EMUL_OKAY;
285 }
287 static int __hvmemul_read(
288 enum x86_segment seg,
289 unsigned long offset,
290 unsigned long *val,
291 unsigned int bytes,
292 enum hvm_access_type access_type,
293 struct hvm_emulate_ctxt *hvmemul_ctxt)
294 {
295 struct vcpu *curr = current;
296 unsigned long addr, reps = 1;
297 uint32_t pfec = PFEC_page_present;
298 paddr_t gpa;
299 int rc;
301 rc = hvmemul_virtual_to_linear(
302 seg, offset, bytes, access_type, hvmemul_ctxt, &addr);
303 if ( rc != X86EMUL_OKAY )
304 return rc;
306 *val = 0;
308 if ( unlikely(curr->arch.hvm_vcpu.mmio_gva == (addr & PAGE_MASK)) &&
309 curr->arch.hvm_vcpu.mmio_gva )
310 {
311 unsigned int off = addr & (PAGE_SIZE - 1);
312 if ( access_type == hvm_access_insn_fetch )
313 return X86EMUL_UNHANDLEABLE;
314 gpa = (((paddr_t)curr->arch.hvm_vcpu.mmio_gpfn << PAGE_SHIFT) | off);
315 if ( (off + bytes) <= PAGE_SIZE )
316 return hvmemul_do_mmio(gpa, &reps, bytes, 0,
317 IOREQ_READ, 0, 0, val);
318 }
320 if ( (seg != x86_seg_none) &&
321 (hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3) )
322 pfec |= PFEC_user_mode;
324 rc = ((access_type == hvm_access_insn_fetch) ?
325 hvm_fetch_from_guest_virt(val, addr, bytes, pfec) :
326 hvm_copy_from_guest_virt(val, addr, bytes, pfec));
327 if ( rc == HVMCOPY_bad_gva_to_gfn )
328 return X86EMUL_EXCEPTION;
330 if ( rc == HVMCOPY_bad_gfn_to_mfn )
331 {
332 unsigned long reps = 1;
334 if ( access_type == hvm_access_insn_fetch )
335 return X86EMUL_UNHANDLEABLE;
337 rc = hvmemul_linear_to_phys(
338 addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
339 if ( rc != X86EMUL_OKAY )
340 return rc;
342 return hvmemul_do_mmio(gpa, &reps, bytes, 0, IOREQ_READ, 0, 0, val);
343 }
345 return X86EMUL_OKAY;
346 }
348 static int hvmemul_read(
349 enum x86_segment seg,
350 unsigned long offset,
351 unsigned long *val,
352 unsigned int bytes,
353 struct x86_emulate_ctxt *ctxt)
354 {
355 return __hvmemul_read(
356 seg, offset, val, bytes, hvm_access_read,
357 container_of(ctxt, struct hvm_emulate_ctxt, ctxt));
358 }
360 static int hvmemul_insn_fetch(
361 enum x86_segment seg,
362 unsigned long offset,
363 unsigned long *val,
364 unsigned int bytes,
365 struct x86_emulate_ctxt *ctxt)
366 {
367 struct hvm_emulate_ctxt *hvmemul_ctxt =
368 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
369 unsigned int insn_off = offset - hvmemul_ctxt->insn_buf_eip;
371 /* Fall back if requested bytes are not in the prefetch cache. */
372 if ( unlikely((insn_off + bytes) > hvmemul_ctxt->insn_buf_bytes) )
373 return __hvmemul_read(
374 seg, offset, val, bytes,
375 hvm_access_insn_fetch, hvmemul_ctxt);
377 /* Hit the cache. Simple memcpy. */
378 *val = 0;
379 memcpy(val, &hvmemul_ctxt->insn_buf[insn_off], bytes);
380 return X86EMUL_OKAY;
381 }
383 static int hvmemul_write(
384 enum x86_segment seg,
385 unsigned long offset,
386 unsigned long val,
387 unsigned int bytes,
388 struct x86_emulate_ctxt *ctxt)
389 {
390 struct hvm_emulate_ctxt *hvmemul_ctxt =
391 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
392 struct vcpu *curr = current;
393 unsigned long addr, reps = 1;
394 uint32_t pfec = PFEC_page_present | PFEC_write_access;
395 paddr_t gpa;
396 int rc;
398 rc = hvmemul_virtual_to_linear(
399 seg, offset, bytes, hvm_access_write, hvmemul_ctxt, &addr);
400 if ( rc != X86EMUL_OKAY )
401 return rc;
403 if ( unlikely(curr->arch.hvm_vcpu.mmio_gva == (addr & PAGE_MASK)) &&
404 curr->arch.hvm_vcpu.mmio_gva )
405 {
406 unsigned int off = addr & (PAGE_SIZE - 1);
407 gpa = (((paddr_t)curr->arch.hvm_vcpu.mmio_gpfn << PAGE_SHIFT) | off);
408 if ( (off + bytes) <= PAGE_SIZE )
409 return hvmemul_do_mmio(gpa, &reps, bytes, val,
410 IOREQ_WRITE, 0, 0, NULL);
411 }
413 if ( (seg != x86_seg_none) &&
414 (hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3) )
415 pfec |= PFEC_user_mode;
417 rc = hvm_copy_to_guest_virt(addr, &val, bytes, pfec);
418 if ( rc == HVMCOPY_bad_gva_to_gfn )
419 return X86EMUL_EXCEPTION;
421 if ( rc == HVMCOPY_bad_gfn_to_mfn )
422 {
423 unsigned long reps = 1;
425 rc = hvmemul_linear_to_phys(
426 addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
427 if ( rc != X86EMUL_OKAY )
428 return rc;
430 return hvmemul_do_mmio(gpa, &reps, bytes, val,
431 IOREQ_WRITE, 0, 0, NULL);
432 }
434 return X86EMUL_OKAY;
435 }
437 static int hvmemul_cmpxchg(
438 enum x86_segment seg,
439 unsigned long offset,
440 void *p_old,
441 void *p_new,
442 unsigned int bytes,
443 struct x86_emulate_ctxt *ctxt)
444 {
445 unsigned long new = 0;
446 if ( bytes > sizeof(new) )
447 return X86EMUL_UNHANDLEABLE;
448 memcpy(&new, p_new, bytes);
449 /* Fix this in case the guest is really relying on r-m-w atomicity. */
450 return hvmemul_write(seg, offset, new, bytes, ctxt);
451 }
453 static int hvmemul_rep_ins(
454 uint16_t src_port,
455 enum x86_segment dst_seg,
456 unsigned long dst_offset,
457 unsigned int bytes_per_rep,
458 unsigned long *reps,
459 struct x86_emulate_ctxt *ctxt)
460 {
461 struct hvm_emulate_ctxt *hvmemul_ctxt =
462 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
463 unsigned long addr;
464 uint32_t pfec = PFEC_page_present | PFEC_write_access;
465 paddr_t gpa;
466 int rc;
468 rc = hvmemul_virtual_to_linear(
469 dst_seg, dst_offset, *reps * bytes_per_rep, hvm_access_write,
470 hvmemul_ctxt, &addr);
471 if ( rc != X86EMUL_OKAY )
472 return rc;
474 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
475 pfec |= PFEC_user_mode;
477 rc = hvmemul_linear_to_phys(
478 addr, &gpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
479 if ( rc != X86EMUL_OKAY )
480 return rc;
482 return hvmemul_do_pio(src_port, reps, bytes_per_rep, gpa, IOREQ_READ,
483 !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
484 }
486 static int hvmemul_rep_outs(
487 enum x86_segment src_seg,
488 unsigned long src_offset,
489 uint16_t dst_port,
490 unsigned int bytes_per_rep,
491 unsigned long *reps,
492 struct x86_emulate_ctxt *ctxt)
493 {
494 struct hvm_emulate_ctxt *hvmemul_ctxt =
495 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
496 unsigned long addr;
497 uint32_t pfec = PFEC_page_present;
498 paddr_t gpa;
499 int rc;
501 rc = hvmemul_virtual_to_linear(
502 src_seg, src_offset, *reps * bytes_per_rep, hvm_access_read,
503 hvmemul_ctxt, &addr);
504 if ( rc != X86EMUL_OKAY )
505 return rc;
507 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
508 pfec |= PFEC_user_mode;
510 rc = hvmemul_linear_to_phys(
511 addr, &gpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
512 if ( rc != X86EMUL_OKAY )
513 return rc;
515 return hvmemul_do_pio(dst_port, reps, bytes_per_rep, gpa, IOREQ_WRITE,
516 !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
517 }
519 static int hvmemul_rep_movs(
520 enum x86_segment src_seg,
521 unsigned long src_offset,
522 enum x86_segment dst_seg,
523 unsigned long dst_offset,
524 unsigned int bytes_per_rep,
525 unsigned long *reps,
526 struct x86_emulate_ctxt *ctxt)
527 {
528 struct hvm_emulate_ctxt *hvmemul_ctxt =
529 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
530 unsigned long saddr, daddr;
531 paddr_t sgpa, dgpa;
532 uint32_t pfec = PFEC_page_present;
533 p2m_type_t p2mt;
534 int rc;
536 rc = hvmemul_virtual_to_linear(
537 src_seg, src_offset, *reps * bytes_per_rep, hvm_access_read,
538 hvmemul_ctxt, &saddr);
539 if ( rc != X86EMUL_OKAY )
540 return rc;
542 rc = hvmemul_virtual_to_linear(
543 dst_seg, dst_offset, *reps * bytes_per_rep, hvm_access_write,
544 hvmemul_ctxt, &daddr);
545 if ( rc != X86EMUL_OKAY )
546 return rc;
548 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
549 pfec |= PFEC_user_mode;
551 rc = hvmemul_linear_to_phys(
552 saddr, &sgpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
553 if ( rc != X86EMUL_OKAY )
554 return rc;
556 rc = hvmemul_linear_to_phys(
557 daddr, &dgpa, bytes_per_rep, reps,
558 pfec | PFEC_write_access, hvmemul_ctxt);
559 if ( rc != X86EMUL_OKAY )
560 return rc;
562 (void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt);
563 if ( !p2m_is_ram(p2mt) )
564 return hvmemul_do_mmio(
565 sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ,
566 !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
568 (void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt);
569 if ( p2m_is_ram(p2mt) )
570 return X86EMUL_UNHANDLEABLE;
571 return hvmemul_do_mmio(
572 dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE,
573 !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
574 }
576 static int hvmemul_read_segment(
577 enum x86_segment seg,
578 struct segment_register *reg,
579 struct x86_emulate_ctxt *ctxt)
580 {
581 struct hvm_emulate_ctxt *hvmemul_ctxt =
582 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
583 struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
584 memcpy(reg, sreg, sizeof(struct segment_register));
585 return X86EMUL_OKAY;
586 }
588 static int hvmemul_write_segment(
589 enum x86_segment seg,
590 struct segment_register *reg,
591 struct x86_emulate_ctxt *ctxt)
592 {
593 struct hvm_emulate_ctxt *hvmemul_ctxt =
594 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
595 struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
597 memcpy(sreg, reg, sizeof(struct segment_register));
598 __set_bit(seg, &hvmemul_ctxt->seg_reg_dirty);
600 return X86EMUL_OKAY;
601 }
603 static int hvmemul_read_io(
604 unsigned int port,
605 unsigned int bytes,
606 unsigned long *val,
607 struct x86_emulate_ctxt *ctxt)
608 {
609 unsigned long reps = 1;
610 return hvmemul_do_pio(port, &reps, bytes, 0, IOREQ_READ, 0, 0, val);
611 }
613 static int hvmemul_write_io(
614 unsigned int port,
615 unsigned int bytes,
616 unsigned long val,
617 struct x86_emulate_ctxt *ctxt)
618 {
619 unsigned long reps = 1;
620 return hvmemul_do_pio(port, &reps, bytes, val, IOREQ_WRITE, 0, 0, NULL);
621 }
623 static int hvmemul_read_cr(
624 unsigned int reg,
625 unsigned long *val,
626 struct x86_emulate_ctxt *ctxt)
627 {
628 switch ( reg )
629 {
630 case 0:
631 case 2:
632 case 3:
633 case 4:
634 *val = current->arch.hvm_vcpu.guest_cr[reg];
635 return X86EMUL_OKAY;
636 default:
637 break;
638 }
640 return X86EMUL_UNHANDLEABLE;
641 }
643 static int hvmemul_write_cr(
644 unsigned int reg,
645 unsigned long val,
646 struct x86_emulate_ctxt *ctxt)
647 {
648 switch ( reg )
649 {
650 case 0:
651 return hvm_set_cr0(val);
652 case 2:
653 current->arch.hvm_vcpu.guest_cr[2] = val;
654 return X86EMUL_OKAY;
655 case 3:
656 return hvm_set_cr3(val);
657 case 4:
658 return hvm_set_cr4(val);
659 default:
660 break;
661 }
663 return X86EMUL_UNHANDLEABLE;
664 }
666 static int hvmemul_read_msr(
667 unsigned long reg,
668 uint64_t *val,
669 struct x86_emulate_ctxt *ctxt)
670 {
671 struct cpu_user_regs _regs;
672 int rc;
674 _regs.ecx = (uint32_t)reg;
676 if ( (rc = hvm_msr_read_intercept(&_regs)) != 0 )
677 return rc;
679 *val = ((uint64_t)(uint32_t)_regs.edx << 32) || (uint32_t)_regs.eax;
680 return X86EMUL_OKAY;
681 }
683 static int hvmemul_write_msr(
684 unsigned long reg,
685 uint64_t val,
686 struct x86_emulate_ctxt *ctxt)
687 {
688 struct cpu_user_regs _regs;
690 _regs.edx = (uint32_t)(val >> 32);
691 _regs.eax = (uint32_t)val;
692 _regs.ecx = (uint32_t)reg;
694 return hvm_msr_write_intercept(&_regs);
695 }
697 static int hvmemul_wbinvd(
698 struct x86_emulate_ctxt *ctxt)
699 {
700 hvm_funcs.wbinvd_intercept();
701 return X86EMUL_OKAY;
702 }
704 static int hvmemul_cpuid(
705 unsigned int *eax,
706 unsigned int *ebx,
707 unsigned int *ecx,
708 unsigned int *edx,
709 struct x86_emulate_ctxt *ctxt)
710 {
711 hvm_funcs.cpuid_intercept(eax, ebx, ecx, edx);
712 return X86EMUL_OKAY;
713 }
715 static int hvmemul_inject_hw_exception(
716 uint8_t vector,
717 int32_t error_code,
718 struct x86_emulate_ctxt *ctxt)
719 {
720 struct hvm_emulate_ctxt *hvmemul_ctxt =
721 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
723 hvmemul_ctxt->exn_pending = 1;
724 hvmemul_ctxt->exn_vector = vector;
725 hvmemul_ctxt->exn_error_code = error_code;
726 hvmemul_ctxt->exn_insn_len = 0;
728 return X86EMUL_OKAY;
729 }
731 static int hvmemul_inject_sw_interrupt(
732 uint8_t vector,
733 uint8_t insn_len,
734 struct x86_emulate_ctxt *ctxt)
735 {
736 struct hvm_emulate_ctxt *hvmemul_ctxt =
737 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
739 hvmemul_ctxt->exn_pending = 1;
740 hvmemul_ctxt->exn_vector = vector;
741 hvmemul_ctxt->exn_error_code = -1;
742 hvmemul_ctxt->exn_insn_len = insn_len;
744 return X86EMUL_OKAY;
745 }
747 static int hvmemul_get_fpu(
748 void (*exception_callback)(void *, struct cpu_user_regs *),
749 void *exception_callback_arg,
750 enum x86_emulate_fpu_type type,
751 struct x86_emulate_ctxt *ctxt)
752 {
753 struct vcpu *curr = current;
755 switch ( type )
756 {
757 case X86EMUL_FPU_fpu:
758 break;
759 case X86EMUL_FPU_mmx:
760 if ( !cpu_has_mmx )
761 return X86EMUL_UNHANDLEABLE;
762 break;
763 default:
764 return X86EMUL_UNHANDLEABLE;
765 }
767 if ( !curr->fpu_dirtied )
768 hvm_funcs.fpu_dirty_intercept();
770 curr->arch.hvm_vcpu.fpu_exception_callback = exception_callback;
771 curr->arch.hvm_vcpu.fpu_exception_callback_arg = exception_callback_arg;
773 return X86EMUL_OKAY;
774 }
776 static void hvmemul_put_fpu(
777 struct x86_emulate_ctxt *ctxt)
778 {
779 struct vcpu *curr = current;
780 curr->arch.hvm_vcpu.fpu_exception_callback = NULL;
781 }
783 static int hvmemul_invlpg(
784 enum x86_segment seg,
785 unsigned long offset,
786 struct x86_emulate_ctxt *ctxt)
787 {
788 struct hvm_emulate_ctxt *hvmemul_ctxt =
789 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
790 unsigned long addr;
791 int rc;
793 rc = hvmemul_virtual_to_linear(
794 seg, offset, 1, hvm_access_none, hvmemul_ctxt, &addr);
796 if ( rc == X86EMUL_OKAY )
797 hvm_funcs.invlpg_intercept(addr);
799 return rc;
800 }
802 static struct x86_emulate_ops hvm_emulate_ops = {
803 .read = hvmemul_read,
804 .insn_fetch = hvmemul_insn_fetch,
805 .write = hvmemul_write,
806 .cmpxchg = hvmemul_cmpxchg,
807 .rep_ins = hvmemul_rep_ins,
808 .rep_outs = hvmemul_rep_outs,
809 .rep_movs = hvmemul_rep_movs,
810 .read_segment = hvmemul_read_segment,
811 .write_segment = hvmemul_write_segment,
812 .read_io = hvmemul_read_io,
813 .write_io = hvmemul_write_io,
814 .read_cr = hvmemul_read_cr,
815 .write_cr = hvmemul_write_cr,
816 .read_msr = hvmemul_read_msr,
817 .write_msr = hvmemul_write_msr,
818 .wbinvd = hvmemul_wbinvd,
819 .cpuid = hvmemul_cpuid,
820 .inject_hw_exception = hvmemul_inject_hw_exception,
821 .inject_sw_interrupt = hvmemul_inject_sw_interrupt,
822 .get_fpu = hvmemul_get_fpu,
823 .put_fpu = hvmemul_put_fpu,
824 .invlpg = hvmemul_invlpg
825 };
827 int hvm_emulate_one(
828 struct hvm_emulate_ctxt *hvmemul_ctxt)
829 {
830 struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
831 struct vcpu *curr = current;
832 uint32_t new_intr_shadow, pfec = PFEC_page_present;
833 unsigned long addr;
834 int rc;
836 if ( hvm_long_mode_enabled(curr) &&
837 hvmemul_ctxt->seg_reg[x86_seg_cs].attr.fields.l )
838 {
839 hvmemul_ctxt->ctxt.addr_size = hvmemul_ctxt->ctxt.sp_size = 64;
840 }
841 else
842 {
843 hvmemul_ctxt->ctxt.addr_size =
844 hvmemul_ctxt->seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
845 hvmemul_ctxt->ctxt.sp_size =
846 hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
847 }
849 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
850 pfec |= PFEC_user_mode;
852 hvmemul_ctxt->insn_buf_eip = regs->eip;
853 hvmemul_ctxt->insn_buf_bytes =
854 (hvm_virtual_to_linear_addr(
855 x86_seg_cs, &hvmemul_ctxt->seg_reg[x86_seg_cs],
856 regs->eip, sizeof(hvmemul_ctxt->insn_buf),
857 hvm_access_insn_fetch, hvmemul_ctxt->ctxt.addr_size, &addr) &&
858 !hvm_fetch_from_guest_virt_nofault(
859 hvmemul_ctxt->insn_buf, addr,
860 sizeof(hvmemul_ctxt->insn_buf), pfec))
861 ? sizeof(hvmemul_ctxt->insn_buf) : 0;
863 hvmemul_ctxt->exn_pending = 0;
865 rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops);
867 if ( rc != X86EMUL_RETRY )
868 curr->arch.hvm_vcpu.mmio_large_read_bytes =
869 curr->arch.hvm_vcpu.mmio_large_write_bytes = 0;
871 if ( rc != X86EMUL_OKAY )
872 return rc;
874 new_intr_shadow = hvmemul_ctxt->intr_shadow;
876 /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
877 if ( hvmemul_ctxt->ctxt.retire.flags.mov_ss )
878 new_intr_shadow ^= HVM_INTR_SHADOW_MOV_SS;
879 else
880 new_intr_shadow &= ~HVM_INTR_SHADOW_MOV_SS;
882 /* STI instruction toggles STI shadow, else we just clear it. */
883 if ( hvmemul_ctxt->ctxt.retire.flags.sti )
884 new_intr_shadow ^= HVM_INTR_SHADOW_STI;
885 else
886 new_intr_shadow &= ~HVM_INTR_SHADOW_STI;
888 if ( hvmemul_ctxt->intr_shadow != new_intr_shadow )
889 {
890 hvmemul_ctxt->intr_shadow = new_intr_shadow;
891 hvm_funcs.set_interrupt_shadow(curr, new_intr_shadow);
892 }
894 if ( hvmemul_ctxt->ctxt.retire.flags.hlt &&
895 !hvm_local_events_need_delivery(curr) )
896 {
897 hvm_hlt(regs->eflags);
898 }
900 return X86EMUL_OKAY;
901 }
903 void hvm_emulate_prepare(
904 struct hvm_emulate_ctxt *hvmemul_ctxt,
905 struct cpu_user_regs *regs)
906 {
907 hvmemul_ctxt->intr_shadow = hvm_funcs.get_interrupt_shadow(current);
908 hvmemul_ctxt->ctxt.regs = regs;
909 hvmemul_ctxt->ctxt.force_writeback = 1;
910 hvmemul_ctxt->seg_reg_accessed = 0;
911 hvmemul_ctxt->seg_reg_dirty = 0;
912 hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt);
913 hvmemul_get_seg_reg(x86_seg_ss, hvmemul_ctxt);
914 }
916 void hvm_emulate_writeback(
917 struct hvm_emulate_ctxt *hvmemul_ctxt)
918 {
919 enum x86_segment seg;
921 seg = find_first_bit(&hvmemul_ctxt->seg_reg_dirty,
922 ARRAY_SIZE(hvmemul_ctxt->seg_reg));
924 while ( seg < ARRAY_SIZE(hvmemul_ctxt->seg_reg) )
925 {
926 hvm_set_segment_register(current, seg, &hvmemul_ctxt->seg_reg[seg]);
927 seg = find_next_bit(&hvmemul_ctxt->seg_reg_dirty,
928 ARRAY_SIZE(hvmemul_ctxt->seg_reg),
929 seg+1);
930 }
931 }
933 struct segment_register *hvmemul_get_seg_reg(
934 enum x86_segment seg,
935 struct hvm_emulate_ctxt *hvmemul_ctxt)
936 {
937 if ( !__test_and_set_bit(seg, &hvmemul_ctxt->seg_reg_accessed) )
938 hvm_get_segment_register(current, seg, &hvmemul_ctxt->seg_reg[seg]);
939 return &hvmemul_ctxt->seg_reg[seg];
940 }