ia64/xen-unstable

view xen/arch/x86/hvm/emulate.c @ 18342:504e5334f1a2

x86 hvm: Add clarifying comments about clipping repeated string
instructions to 4096 iterations.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Aug 19 18:52:04 2008 +0100 (2008-08-19)
parents e6a4f6a682ba
children a864ba2f0aa5
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 ram_gpa, int dir, int df, void *p_data)
25 {
26 paddr_t value = ram_gpa;
27 int value_is_ptr = (p_data == NULL);
28 struct vcpu *curr = current;
29 vcpu_iodata_t *vio = get_ioreq(curr);
30 ioreq_t *p = &vio->vp_ioreq;
31 int rc;
33 /*
34 * Weird-sized accesses have undefined behaviour: we discard writes
35 * and read all-ones.
36 */
37 if ( unlikely((size > sizeof(long)) || (size & (size - 1))) )
38 {
39 gdprintk(XENLOG_WARNING, "bad mmio size %d\n", size);
40 ASSERT(p_data != NULL); /* cannot happen with a REP prefix */
41 if ( dir == IOREQ_READ )
42 memset(p_data, ~0, size);
43 return X86EMUL_UNHANDLEABLE;
44 }
46 if ( (p_data != NULL) && (dir == IOREQ_WRITE) )
47 {
48 memcpy(&value, p_data, size);
49 p_data = NULL;
50 }
52 if ( is_mmio && !value_is_ptr )
53 {
54 /* Part of a multi-cycle read or write? */
55 if ( dir == IOREQ_WRITE )
56 {
57 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_write_pa;
58 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_write_bytes;
59 if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) )
60 return X86EMUL_OKAY;
61 }
62 else
63 {
64 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_read_pa;
65 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_read_bytes;
66 if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) )
67 {
68 memcpy(p_data, &curr->arch.hvm_vcpu.mmio_large_read[addr - pa],
69 size);
70 return X86EMUL_OKAY;
71 }
72 }
73 }
75 switch ( curr->arch.hvm_vcpu.io_state )
76 {
77 case HVMIO_none:
78 break;
79 case HVMIO_completed:
80 curr->arch.hvm_vcpu.io_state = HVMIO_none;
81 if ( p_data == NULL )
82 return X86EMUL_UNHANDLEABLE;
83 goto finish_access;
84 case HVMIO_dispatched:
85 /* May have to wait for previous cycle of a multi-write to complete. */
86 if ( is_mmio && !value_is_ptr && (dir == IOREQ_WRITE) &&
87 (addr == (curr->arch.hvm_vcpu.mmio_large_write_pa +
88 curr->arch.hvm_vcpu.mmio_large_write_bytes)) )
89 return X86EMUL_RETRY;
90 default:
91 return X86EMUL_UNHANDLEABLE;
92 }
94 if ( p->state != STATE_IOREQ_NONE )
95 {
96 gdprintk(XENLOG_WARNING, "WARNING: io already pending (%d)?\n",
97 p->state);
98 return X86EMUL_UNHANDLEABLE;
99 }
101 curr->arch.hvm_vcpu.io_state =
102 (p_data == NULL) ? HVMIO_dispatched : HVMIO_awaiting_completion;
104 p->dir = dir;
105 p->data_is_ptr = value_is_ptr;
106 p->type = is_mmio ? IOREQ_TYPE_COPY : IOREQ_TYPE_PIO;
107 p->size = size;
108 p->addr = addr;
109 p->count = *reps;
110 p->df = df;
111 p->data = value;
112 p->io_count++;
114 if ( is_mmio )
115 {
116 rc = hvm_mmio_intercept(p);
117 if ( rc == X86EMUL_UNHANDLEABLE )
118 rc = hvm_buffered_io_intercept(p);
119 }
120 else
121 {
122 rc = hvm_portio_intercept(p);
123 }
125 switch ( rc )
126 {
127 case X86EMUL_OKAY:
128 case X86EMUL_RETRY:
129 *reps = p->count;
130 p->state = STATE_IORESP_READY;
131 hvm_io_assist();
132 curr->arch.hvm_vcpu.io_state = HVMIO_none;
133 break;
134 case X86EMUL_UNHANDLEABLE:
135 hvm_send_assist_req(curr);
136 rc = (p_data != NULL) ? X86EMUL_RETRY : X86EMUL_OKAY;
137 break;
138 default:
139 BUG();
140 }
142 if ( rc != X86EMUL_OKAY )
143 return rc;
145 finish_access:
146 if ( p_data != NULL )
147 memcpy(p_data, &curr->arch.hvm_vcpu.io_data, size);
149 if ( is_mmio && !value_is_ptr )
150 {
151 /* Part of a multi-cycle read or write? */
152 if ( dir == IOREQ_WRITE )
153 {
154 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_write_pa;
155 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_write_bytes;
156 if ( bytes == 0 )
157 pa = curr->arch.hvm_vcpu.mmio_large_write_pa = addr;
158 if ( addr == (pa + bytes) )
159 curr->arch.hvm_vcpu.mmio_large_write_bytes += size;
160 }
161 else
162 {
163 paddr_t pa = curr->arch.hvm_vcpu.mmio_large_read_pa;
164 unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_read_bytes;
165 if ( bytes == 0 )
166 pa = curr->arch.hvm_vcpu.mmio_large_read_pa = addr;
167 if ( (addr == (pa + bytes)) &&
168 ((bytes + size) <
169 sizeof(curr->arch.hvm_vcpu.mmio_large_read)) )
170 {
171 memcpy(&curr->arch.hvm_vcpu.mmio_large_read[addr - pa],
172 p_data, size);
173 curr->arch.hvm_vcpu.mmio_large_read_bytes += size;
174 }
175 }
176 }
178 return X86EMUL_OKAY;
179 }
181 static int hvmemul_do_pio(
182 unsigned long port, unsigned long *reps, int size,
183 paddr_t ram_gpa, int dir, int df, void *p_data)
184 {
185 return hvmemul_do_io(0, port, reps, size, ram_gpa, dir, df, p_data);
186 }
188 static int hvmemul_do_mmio(
189 paddr_t gpa, unsigned long *reps, int size,
190 paddr_t ram_gpa, int dir, int df, void *p_data)
191 {
192 return hvmemul_do_io(1, gpa, reps, size, ram_gpa, dir, df, p_data);
193 }
195 /*
196 * Convert addr from linear to physical form, valid over the range
197 * [addr, addr + *reps * bytes_per_rep]. *reps is adjusted according to
198 * the valid computed range. It is always >0 when X86EMUL_OKAY is returned.
199 * @pfec indicates the access checks to be performed during page-table walks.
200 */
201 static int hvmemul_linear_to_phys(
202 unsigned long addr,
203 paddr_t *paddr,
204 unsigned int bytes_per_rep,
205 unsigned long *reps,
206 uint32_t pfec,
207 struct hvm_emulate_ctxt *hvmemul_ctxt)
208 {
209 struct vcpu *curr = current;
210 unsigned long pfn, npfn, done, todo, i;
211 int reverse;
213 /*
214 * Clip repetitions to a sensible maximum. This avoids extensive looping in
215 * this function while still amortising the cost of I/O trap-and-emulate.
216 */
217 *reps = min_t(unsigned long, *reps, 4096);
219 /* With no paging it's easy: linear == physical. */
220 if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG) )
221 {
222 *paddr = addr;
223 return X86EMUL_OKAY;
224 }
226 *paddr = addr & ~PAGE_MASK;
228 /* Reverse mode if this is a backwards multi-iteration string operation. */
229 reverse = (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (*reps > 1);
231 if ( reverse && ((-addr & ~PAGE_MASK) < bytes_per_rep) )
232 {
233 /* Do page-straddling first iteration forwards via recursion. */
234 paddr_t _paddr;
235 unsigned long one_rep = 1;
236 int rc = hvmemul_linear_to_phys(
237 addr, &_paddr, bytes_per_rep, &one_rep, pfec, hvmemul_ctxt);
238 if ( rc != X86EMUL_OKAY )
239 return rc;
240 pfn = _paddr >> PAGE_SHIFT;
241 }
242 else if ( (pfn = paging_gva_to_gfn(curr, addr, &pfec)) == INVALID_GFN )
243 {
244 hvm_inject_exception(TRAP_page_fault, pfec, addr);
245 return X86EMUL_EXCEPTION;
246 }
248 /* If the range does not straddle a page boundary then we're done. */
249 done = reverse ? bytes_per_rep + (addr & ~PAGE_MASK) : -addr & ~PAGE_MASK;
250 todo = *reps * bytes_per_rep;
251 if ( done >= todo )
252 goto done;
254 for ( i = 1; done < todo; i++ )
255 {
256 /* Get the next PFN in the range. */
257 addr += reverse ? -PAGE_SIZE : PAGE_SIZE;
258 npfn = paging_gva_to_gfn(curr, addr, &pfec);
260 /* Is it contiguous with the preceding PFNs? If not then we're done. */
261 if ( (npfn == INVALID_GFN) || (npfn != (pfn + (reverse ? -i : i))) )
262 {
263 done /= bytes_per_rep;
264 if ( done == 0 )
265 {
266 ASSERT(!reverse);
267 if ( npfn != INVALID_GFN )
268 return X86EMUL_UNHANDLEABLE;
269 hvm_inject_exception(TRAP_page_fault, pfec, addr & PAGE_MASK);
270 return X86EMUL_EXCEPTION;
271 }
272 *reps = done;
273 break;
274 }
276 done += PAGE_SIZE;
277 }
279 done:
280 *paddr |= (paddr_t)pfn << PAGE_SHIFT;
281 return X86EMUL_OKAY;
282 }
285 static int hvmemul_virtual_to_linear(
286 enum x86_segment seg,
287 unsigned long offset,
288 unsigned int bytes_per_rep,
289 unsigned long *reps,
290 enum hvm_access_type access_type,
291 struct hvm_emulate_ctxt *hvmemul_ctxt,
292 unsigned long *paddr)
293 {
294 struct segment_register *reg;
295 int okay;
297 if ( seg == x86_seg_none )
298 {
299 *paddr = offset;
300 return X86EMUL_OKAY;
301 }
303 /*
304 * Clip repetitions to avoid overflow when multiplying by @bytes_per_rep.
305 * The chosen maximum is very conservative but it's what we use in
306 * hvmemul_linear_to_phys() so there is no point in using a larger value.
307 */
308 *reps = min_t(unsigned long, *reps, 4096);
310 reg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
312 if ( (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (*reps > 1) )
313 {
314 ASSERT(offset >= ((*reps - 1) * bytes_per_rep));
315 okay = hvm_virtual_to_linear_addr(
316 seg, reg, offset - (*reps - 1) * bytes_per_rep,
317 *reps * bytes_per_rep, access_type,
318 hvmemul_ctxt->ctxt.addr_size, paddr);
319 *paddr += (*reps - 1) * bytes_per_rep;
320 if ( hvmemul_ctxt->ctxt.addr_size != 64 )
321 *paddr = (uint32_t)*paddr;
322 }
323 else
324 {
325 okay = hvm_virtual_to_linear_addr(
326 seg, reg, offset, *reps * bytes_per_rep, access_type,
327 hvmemul_ctxt->ctxt.addr_size, paddr);
328 }
330 if ( okay )
331 return X86EMUL_OKAY;
333 /* If this is a string operation, emulate each iteration separately. */
334 if ( *reps != 1 )
335 return X86EMUL_UNHANDLEABLE;
337 /* This is a singleton operation: fail it with an exception. */
338 hvmemul_ctxt->exn_pending = 1;
339 hvmemul_ctxt->exn_vector = TRAP_gp_fault;
340 hvmemul_ctxt->exn_error_code = 0;
341 hvmemul_ctxt->exn_insn_len = 0;
342 return X86EMUL_EXCEPTION;
343 }
345 static int __hvmemul_read(
346 enum x86_segment seg,
347 unsigned long offset,
348 void *p_data,
349 unsigned int bytes,
350 enum hvm_access_type access_type,
351 struct hvm_emulate_ctxt *hvmemul_ctxt)
352 {
353 struct vcpu *curr = current;
354 unsigned long addr, reps = 1;
355 uint32_t pfec = PFEC_page_present;
356 paddr_t gpa;
357 int rc;
359 rc = hvmemul_virtual_to_linear(
360 seg, offset, bytes, &reps, access_type, hvmemul_ctxt, &addr);
361 if ( rc != X86EMUL_OKAY )
362 return rc;
364 if ( unlikely(curr->arch.hvm_vcpu.mmio_gva == (addr & PAGE_MASK)) &&
365 curr->arch.hvm_vcpu.mmio_gva )
366 {
367 unsigned int off = addr & (PAGE_SIZE - 1);
368 if ( access_type == hvm_access_insn_fetch )
369 return X86EMUL_UNHANDLEABLE;
370 gpa = (((paddr_t)curr->arch.hvm_vcpu.mmio_gpfn << PAGE_SHIFT) | off);
371 if ( (off + bytes) <= PAGE_SIZE )
372 return hvmemul_do_mmio(gpa, &reps, bytes, 0,
373 IOREQ_READ, 0, p_data);
374 }
376 if ( (seg != x86_seg_none) &&
377 (hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3) )
378 pfec |= PFEC_user_mode;
380 rc = ((access_type == hvm_access_insn_fetch) ?
381 hvm_fetch_from_guest_virt(p_data, addr, bytes, pfec) :
382 hvm_copy_from_guest_virt(p_data, addr, bytes, pfec));
383 if ( rc == HVMCOPY_bad_gva_to_gfn )
384 return X86EMUL_EXCEPTION;
386 if ( rc == HVMCOPY_bad_gfn_to_mfn )
387 {
388 if ( access_type == hvm_access_insn_fetch )
389 return X86EMUL_UNHANDLEABLE;
391 rc = hvmemul_linear_to_phys(
392 addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
393 if ( rc != X86EMUL_OKAY )
394 return rc;
396 return hvmemul_do_mmio(gpa, &reps, bytes, 0, IOREQ_READ, 0, p_data);
397 }
399 return X86EMUL_OKAY;
400 }
402 static int hvmemul_read(
403 enum x86_segment seg,
404 unsigned long offset,
405 void *p_data,
406 unsigned int bytes,
407 struct x86_emulate_ctxt *ctxt)
408 {
409 return __hvmemul_read(
410 seg, offset, p_data, bytes, hvm_access_read,
411 container_of(ctxt, struct hvm_emulate_ctxt, ctxt));
412 }
414 static int hvmemul_insn_fetch(
415 enum x86_segment seg,
416 unsigned long offset,
417 void *p_data,
418 unsigned int bytes,
419 struct x86_emulate_ctxt *ctxt)
420 {
421 struct hvm_emulate_ctxt *hvmemul_ctxt =
422 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
423 unsigned int insn_off = offset - hvmemul_ctxt->insn_buf_eip;
425 /* Fall back if requested bytes are not in the prefetch cache. */
426 if ( unlikely((insn_off + bytes) > hvmemul_ctxt->insn_buf_bytes) )
427 return __hvmemul_read(
428 seg, offset, p_data, bytes,
429 hvm_access_insn_fetch, hvmemul_ctxt);
431 /* Hit the cache. Simple memcpy. */
432 memcpy(p_data, &hvmemul_ctxt->insn_buf[insn_off], bytes);
433 return X86EMUL_OKAY;
434 }
436 static int hvmemul_write(
437 enum x86_segment seg,
438 unsigned long offset,
439 void *p_data,
440 unsigned int bytes,
441 struct x86_emulate_ctxt *ctxt)
442 {
443 struct hvm_emulate_ctxt *hvmemul_ctxt =
444 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
445 struct vcpu *curr = current;
446 unsigned long addr, reps = 1;
447 uint32_t pfec = PFEC_page_present | PFEC_write_access;
448 paddr_t gpa;
449 int rc;
451 rc = hvmemul_virtual_to_linear(
452 seg, offset, bytes, &reps, hvm_access_write, hvmemul_ctxt, &addr);
453 if ( rc != X86EMUL_OKAY )
454 return rc;
456 if ( unlikely(curr->arch.hvm_vcpu.mmio_gva == (addr & PAGE_MASK)) &&
457 curr->arch.hvm_vcpu.mmio_gva )
458 {
459 unsigned int off = addr & (PAGE_SIZE - 1);
460 gpa = (((paddr_t)curr->arch.hvm_vcpu.mmio_gpfn << PAGE_SHIFT) | off);
461 if ( (off + bytes) <= PAGE_SIZE )
462 return hvmemul_do_mmio(gpa, &reps, bytes, 0,
463 IOREQ_WRITE, 0, p_data);
464 }
466 if ( (seg != x86_seg_none) &&
467 (hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3) )
468 pfec |= PFEC_user_mode;
470 rc = hvm_copy_to_guest_virt(addr, p_data, bytes, pfec);
471 if ( rc == HVMCOPY_bad_gva_to_gfn )
472 return X86EMUL_EXCEPTION;
474 if ( rc == HVMCOPY_bad_gfn_to_mfn )
475 {
476 rc = hvmemul_linear_to_phys(
477 addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
478 if ( rc != X86EMUL_OKAY )
479 return rc;
481 return hvmemul_do_mmio(gpa, &reps, bytes, 0,
482 IOREQ_WRITE, 0, p_data);
483 }
485 return X86EMUL_OKAY;
486 }
488 static int hvmemul_cmpxchg(
489 enum x86_segment seg,
490 unsigned long offset,
491 void *p_old,
492 void *p_new,
493 unsigned int bytes,
494 struct x86_emulate_ctxt *ctxt)
495 {
496 /* Fix this in case the guest is really relying on r-m-w atomicity. */
497 return hvmemul_write(seg, offset, p_new, bytes, ctxt);
498 }
500 static int hvmemul_rep_ins(
501 uint16_t src_port,
502 enum x86_segment dst_seg,
503 unsigned long dst_offset,
504 unsigned int bytes_per_rep,
505 unsigned long *reps,
506 struct x86_emulate_ctxt *ctxt)
507 {
508 struct hvm_emulate_ctxt *hvmemul_ctxt =
509 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
510 unsigned long addr;
511 uint32_t pfec = PFEC_page_present | PFEC_write_access;
512 paddr_t gpa;
513 int rc;
515 rc = hvmemul_virtual_to_linear(
516 dst_seg, dst_offset, bytes_per_rep, reps, hvm_access_write,
517 hvmemul_ctxt, &addr);
518 if ( rc != X86EMUL_OKAY )
519 return rc;
521 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
522 pfec |= PFEC_user_mode;
524 rc = hvmemul_linear_to_phys(
525 addr, &gpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
526 if ( rc != X86EMUL_OKAY )
527 return rc;
529 return hvmemul_do_pio(src_port, reps, bytes_per_rep, gpa, IOREQ_READ,
530 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
531 }
533 static int hvmemul_rep_outs(
534 enum x86_segment src_seg,
535 unsigned long src_offset,
536 uint16_t dst_port,
537 unsigned int bytes_per_rep,
538 unsigned long *reps,
539 struct x86_emulate_ctxt *ctxt)
540 {
541 struct hvm_emulate_ctxt *hvmemul_ctxt =
542 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
543 unsigned long addr;
544 uint32_t pfec = PFEC_page_present;
545 paddr_t gpa;
546 int rc;
548 rc = hvmemul_virtual_to_linear(
549 src_seg, src_offset, bytes_per_rep, reps, hvm_access_read,
550 hvmemul_ctxt, &addr);
551 if ( rc != X86EMUL_OKAY )
552 return rc;
554 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
555 pfec |= PFEC_user_mode;
557 rc = hvmemul_linear_to_phys(
558 addr, &gpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
559 if ( rc != X86EMUL_OKAY )
560 return rc;
562 return hvmemul_do_pio(dst_port, reps, bytes_per_rep, gpa, IOREQ_WRITE,
563 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
564 }
566 static int hvmemul_rep_movs(
567 enum x86_segment src_seg,
568 unsigned long src_offset,
569 enum x86_segment dst_seg,
570 unsigned long dst_offset,
571 unsigned int bytes_per_rep,
572 unsigned long *reps,
573 struct x86_emulate_ctxt *ctxt)
574 {
575 struct hvm_emulate_ctxt *hvmemul_ctxt =
576 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
577 unsigned long saddr, daddr;
578 paddr_t sgpa, dgpa;
579 uint32_t pfec = PFEC_page_present;
580 p2m_type_t p2mt;
581 int rc;
583 rc = hvmemul_virtual_to_linear(
584 src_seg, src_offset, bytes_per_rep, reps, hvm_access_read,
585 hvmemul_ctxt, &saddr);
586 if ( rc != X86EMUL_OKAY )
587 return rc;
589 rc = hvmemul_virtual_to_linear(
590 dst_seg, dst_offset, bytes_per_rep, reps, hvm_access_write,
591 hvmemul_ctxt, &daddr);
592 if ( rc != X86EMUL_OKAY )
593 return rc;
595 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
596 pfec |= PFEC_user_mode;
598 rc = hvmemul_linear_to_phys(
599 saddr, &sgpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
600 if ( rc != X86EMUL_OKAY )
601 return rc;
603 rc = hvmemul_linear_to_phys(
604 daddr, &dgpa, bytes_per_rep, reps,
605 pfec | PFEC_write_access, hvmemul_ctxt);
606 if ( rc != X86EMUL_OKAY )
607 return rc;
609 (void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt);
610 if ( !p2m_is_ram(p2mt) )
611 return hvmemul_do_mmio(
612 sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ,
613 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
615 (void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt);
616 if ( p2m_is_ram(p2mt) )
617 return X86EMUL_UNHANDLEABLE;
618 return hvmemul_do_mmio(
619 dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE,
620 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
621 }
623 static int hvmemul_read_segment(
624 enum x86_segment seg,
625 struct segment_register *reg,
626 struct x86_emulate_ctxt *ctxt)
627 {
628 struct hvm_emulate_ctxt *hvmemul_ctxt =
629 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
630 struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
631 memcpy(reg, sreg, sizeof(struct segment_register));
632 return X86EMUL_OKAY;
633 }
635 static int hvmemul_write_segment(
636 enum x86_segment seg,
637 struct segment_register *reg,
638 struct x86_emulate_ctxt *ctxt)
639 {
640 struct hvm_emulate_ctxt *hvmemul_ctxt =
641 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
642 struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
644 memcpy(sreg, reg, sizeof(struct segment_register));
645 __set_bit(seg, &hvmemul_ctxt->seg_reg_dirty);
647 return X86EMUL_OKAY;
648 }
650 static int hvmemul_read_io(
651 unsigned int port,
652 unsigned int bytes,
653 unsigned long *val,
654 struct x86_emulate_ctxt *ctxt)
655 {
656 unsigned long reps = 1;
657 *val = 0;
658 return hvmemul_do_pio(port, &reps, bytes, 0, IOREQ_READ, 0, val);
659 }
661 static int hvmemul_write_io(
662 unsigned int port,
663 unsigned int bytes,
664 unsigned long val,
665 struct x86_emulate_ctxt *ctxt)
666 {
667 unsigned long reps = 1;
668 return hvmemul_do_pio(port, &reps, bytes, 0, IOREQ_WRITE, 0, &val);
669 }
671 static int hvmemul_read_cr(
672 unsigned int reg,
673 unsigned long *val,
674 struct x86_emulate_ctxt *ctxt)
675 {
676 switch ( reg )
677 {
678 case 0:
679 case 2:
680 case 3:
681 case 4:
682 *val = current->arch.hvm_vcpu.guest_cr[reg];
683 return X86EMUL_OKAY;
684 default:
685 break;
686 }
688 return X86EMUL_UNHANDLEABLE;
689 }
691 static int hvmemul_write_cr(
692 unsigned int reg,
693 unsigned long val,
694 struct x86_emulate_ctxt *ctxt)
695 {
696 switch ( reg )
697 {
698 case 0:
699 return hvm_set_cr0(val);
700 case 2:
701 current->arch.hvm_vcpu.guest_cr[2] = val;
702 return X86EMUL_OKAY;
703 case 3:
704 return hvm_set_cr3(val);
705 case 4:
706 return hvm_set_cr4(val);
707 default:
708 break;
709 }
711 return X86EMUL_UNHANDLEABLE;
712 }
714 static int hvmemul_read_msr(
715 unsigned long reg,
716 uint64_t *val,
717 struct x86_emulate_ctxt *ctxt)
718 {
719 struct cpu_user_regs _regs;
720 int rc;
722 _regs.ecx = (uint32_t)reg;
724 if ( (rc = hvm_msr_read_intercept(&_regs)) != 0 )
725 return rc;
727 *val = ((uint64_t)(uint32_t)_regs.edx << 32) || (uint32_t)_regs.eax;
728 return X86EMUL_OKAY;
729 }
731 static int hvmemul_write_msr(
732 unsigned long reg,
733 uint64_t val,
734 struct x86_emulate_ctxt *ctxt)
735 {
736 struct cpu_user_regs _regs;
738 _regs.edx = (uint32_t)(val >> 32);
739 _regs.eax = (uint32_t)val;
740 _regs.ecx = (uint32_t)reg;
742 return hvm_msr_write_intercept(&_regs);
743 }
745 static int hvmemul_wbinvd(
746 struct x86_emulate_ctxt *ctxt)
747 {
748 hvm_funcs.wbinvd_intercept();
749 return X86EMUL_OKAY;
750 }
752 static int hvmemul_cpuid(
753 unsigned int *eax,
754 unsigned int *ebx,
755 unsigned int *ecx,
756 unsigned int *edx,
757 struct x86_emulate_ctxt *ctxt)
758 {
759 hvm_funcs.cpuid_intercept(eax, ebx, ecx, edx);
760 return X86EMUL_OKAY;
761 }
763 static int hvmemul_inject_hw_exception(
764 uint8_t vector,
765 int32_t error_code,
766 struct x86_emulate_ctxt *ctxt)
767 {
768 struct hvm_emulate_ctxt *hvmemul_ctxt =
769 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
771 hvmemul_ctxt->exn_pending = 1;
772 hvmemul_ctxt->exn_vector = vector;
773 hvmemul_ctxt->exn_error_code = error_code;
774 hvmemul_ctxt->exn_insn_len = 0;
776 return X86EMUL_OKAY;
777 }
779 static int hvmemul_inject_sw_interrupt(
780 uint8_t vector,
781 uint8_t insn_len,
782 struct x86_emulate_ctxt *ctxt)
783 {
784 struct hvm_emulate_ctxt *hvmemul_ctxt =
785 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
787 hvmemul_ctxt->exn_pending = 1;
788 hvmemul_ctxt->exn_vector = vector;
789 hvmemul_ctxt->exn_error_code = -1;
790 hvmemul_ctxt->exn_insn_len = insn_len;
792 return X86EMUL_OKAY;
793 }
795 static int hvmemul_get_fpu(
796 void (*exception_callback)(void *, struct cpu_user_regs *),
797 void *exception_callback_arg,
798 enum x86_emulate_fpu_type type,
799 struct x86_emulate_ctxt *ctxt)
800 {
801 struct vcpu *curr = current;
803 switch ( type )
804 {
805 case X86EMUL_FPU_fpu:
806 break;
807 case X86EMUL_FPU_mmx:
808 if ( !cpu_has_mmx )
809 return X86EMUL_UNHANDLEABLE;
810 break;
811 default:
812 return X86EMUL_UNHANDLEABLE;
813 }
815 if ( !curr->fpu_dirtied )
816 hvm_funcs.fpu_dirty_intercept();
818 curr->arch.hvm_vcpu.fpu_exception_callback = exception_callback;
819 curr->arch.hvm_vcpu.fpu_exception_callback_arg = exception_callback_arg;
821 return X86EMUL_OKAY;
822 }
824 static void hvmemul_put_fpu(
825 struct x86_emulate_ctxt *ctxt)
826 {
827 struct vcpu *curr = current;
828 curr->arch.hvm_vcpu.fpu_exception_callback = NULL;
829 }
831 static int hvmemul_invlpg(
832 enum x86_segment seg,
833 unsigned long offset,
834 struct x86_emulate_ctxt *ctxt)
835 {
836 struct hvm_emulate_ctxt *hvmemul_ctxt =
837 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
838 unsigned long addr, reps = 1;
839 int rc;
841 rc = hvmemul_virtual_to_linear(
842 seg, offset, 1, &reps, hvm_access_none, hvmemul_ctxt, &addr);
844 if ( rc == X86EMUL_OKAY )
845 hvm_funcs.invlpg_intercept(addr);
847 return rc;
848 }
850 static struct x86_emulate_ops hvm_emulate_ops = {
851 .read = hvmemul_read,
852 .insn_fetch = hvmemul_insn_fetch,
853 .write = hvmemul_write,
854 .cmpxchg = hvmemul_cmpxchg,
855 .rep_ins = hvmemul_rep_ins,
856 .rep_outs = hvmemul_rep_outs,
857 .rep_movs = hvmemul_rep_movs,
858 .read_segment = hvmemul_read_segment,
859 .write_segment = hvmemul_write_segment,
860 .read_io = hvmemul_read_io,
861 .write_io = hvmemul_write_io,
862 .read_cr = hvmemul_read_cr,
863 .write_cr = hvmemul_write_cr,
864 .read_msr = hvmemul_read_msr,
865 .write_msr = hvmemul_write_msr,
866 .wbinvd = hvmemul_wbinvd,
867 .cpuid = hvmemul_cpuid,
868 .inject_hw_exception = hvmemul_inject_hw_exception,
869 .inject_sw_interrupt = hvmemul_inject_sw_interrupt,
870 .get_fpu = hvmemul_get_fpu,
871 .put_fpu = hvmemul_put_fpu,
872 .invlpg = hvmemul_invlpg
873 };
875 int hvm_emulate_one(
876 struct hvm_emulate_ctxt *hvmemul_ctxt)
877 {
878 struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
879 struct vcpu *curr = current;
880 uint32_t new_intr_shadow, pfec = PFEC_page_present;
881 unsigned long addr;
882 int rc;
884 if ( hvm_long_mode_enabled(curr) &&
885 hvmemul_ctxt->seg_reg[x86_seg_cs].attr.fields.l )
886 {
887 hvmemul_ctxt->ctxt.addr_size = hvmemul_ctxt->ctxt.sp_size = 64;
888 }
889 else
890 {
891 hvmemul_ctxt->ctxt.addr_size =
892 hvmemul_ctxt->seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
893 hvmemul_ctxt->ctxt.sp_size =
894 hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
895 }
897 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
898 pfec |= PFEC_user_mode;
900 hvmemul_ctxt->insn_buf_eip = regs->eip;
901 hvmemul_ctxt->insn_buf_bytes =
902 (hvm_virtual_to_linear_addr(
903 x86_seg_cs, &hvmemul_ctxt->seg_reg[x86_seg_cs],
904 regs->eip, sizeof(hvmemul_ctxt->insn_buf),
905 hvm_access_insn_fetch, hvmemul_ctxt->ctxt.addr_size, &addr) &&
906 !hvm_fetch_from_guest_virt_nofault(
907 hvmemul_ctxt->insn_buf, addr,
908 sizeof(hvmemul_ctxt->insn_buf), pfec))
909 ? sizeof(hvmemul_ctxt->insn_buf) : 0;
911 hvmemul_ctxt->exn_pending = 0;
913 rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops);
915 if ( rc != X86EMUL_RETRY )
916 curr->arch.hvm_vcpu.mmio_large_read_bytes =
917 curr->arch.hvm_vcpu.mmio_large_write_bytes = 0;
919 if ( rc != X86EMUL_OKAY )
920 return rc;
922 new_intr_shadow = hvmemul_ctxt->intr_shadow;
924 /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
925 if ( hvmemul_ctxt->ctxt.retire.flags.mov_ss )
926 new_intr_shadow ^= HVM_INTR_SHADOW_MOV_SS;
927 else
928 new_intr_shadow &= ~HVM_INTR_SHADOW_MOV_SS;
930 /* STI instruction toggles STI shadow, else we just clear it. */
931 if ( hvmemul_ctxt->ctxt.retire.flags.sti )
932 new_intr_shadow ^= HVM_INTR_SHADOW_STI;
933 else
934 new_intr_shadow &= ~HVM_INTR_SHADOW_STI;
936 if ( hvmemul_ctxt->intr_shadow != new_intr_shadow )
937 {
938 hvmemul_ctxt->intr_shadow = new_intr_shadow;
939 hvm_funcs.set_interrupt_shadow(curr, new_intr_shadow);
940 }
942 if ( hvmemul_ctxt->ctxt.retire.flags.hlt &&
943 !hvm_local_events_need_delivery(curr) )
944 {
945 hvm_hlt(regs->eflags);
946 }
948 return X86EMUL_OKAY;
949 }
951 void hvm_emulate_prepare(
952 struct hvm_emulate_ctxt *hvmemul_ctxt,
953 struct cpu_user_regs *regs)
954 {
955 hvmemul_ctxt->intr_shadow = hvm_funcs.get_interrupt_shadow(current);
956 hvmemul_ctxt->ctxt.regs = regs;
957 hvmemul_ctxt->ctxt.force_writeback = 1;
958 hvmemul_ctxt->seg_reg_accessed = 0;
959 hvmemul_ctxt->seg_reg_dirty = 0;
960 hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt);
961 hvmemul_get_seg_reg(x86_seg_ss, hvmemul_ctxt);
962 }
964 void hvm_emulate_writeback(
965 struct hvm_emulate_ctxt *hvmemul_ctxt)
966 {
967 enum x86_segment seg;
969 seg = find_first_bit(&hvmemul_ctxt->seg_reg_dirty,
970 ARRAY_SIZE(hvmemul_ctxt->seg_reg));
972 while ( seg < ARRAY_SIZE(hvmemul_ctxt->seg_reg) )
973 {
974 hvm_set_segment_register(current, seg, &hvmemul_ctxt->seg_reg[seg]);
975 seg = find_next_bit(&hvmemul_ctxt->seg_reg_dirty,
976 ARRAY_SIZE(hvmemul_ctxt->seg_reg),
977 seg+1);
978 }
979 }
981 struct segment_register *hvmemul_get_seg_reg(
982 enum x86_segment seg,
983 struct hvm_emulate_ctxt *hvmemul_ctxt)
984 {
985 if ( !__test_and_set_bit(seg, &hvmemul_ctxt->seg_reg_accessed) )
986 hvm_get_segment_register(current, seg, &hvmemul_ctxt->seg_reg[seg]);
987 return &hvmemul_ctxt->seg_reg[seg];
988 }