ia64/xen-unstable

view xen/arch/x86/hvm/emulate.c @ 18341:e6a4f6a682ba

x86 hvm: Build fix: param is paddr_t not ulong.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Aug 19 18:47:01 2008 +0100 (2008-08-19)
parents a3fe573a0e1e
children 504e5334f1a2
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 /* Clip repetitions to a sensible maximum. */
214 *reps = min_t(unsigned long, *reps, 4096);
216 /* With no paging it's easy: linear == physical. */
217 if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG) )
218 {
219 *paddr = addr;
220 return X86EMUL_OKAY;
221 }
223 *paddr = addr & ~PAGE_MASK;
225 /* Reverse mode if this is a backwards multi-iteration string operation. */
226 reverse = (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (*reps > 1);
228 if ( reverse && ((-addr & ~PAGE_MASK) < bytes_per_rep) )
229 {
230 /* Do page-straddling first iteration forwards via recursion. */
231 paddr_t _paddr;
232 unsigned long one_rep = 1;
233 int rc = hvmemul_linear_to_phys(
234 addr, &_paddr, bytes_per_rep, &one_rep, pfec, hvmemul_ctxt);
235 if ( rc != X86EMUL_OKAY )
236 return rc;
237 pfn = _paddr >> PAGE_SHIFT;
238 }
239 else if ( (pfn = paging_gva_to_gfn(curr, addr, &pfec)) == INVALID_GFN )
240 {
241 hvm_inject_exception(TRAP_page_fault, pfec, addr);
242 return X86EMUL_EXCEPTION;
243 }
245 /* If the range does not straddle a page boundary then we're done. */
246 done = reverse ? bytes_per_rep + (addr & ~PAGE_MASK) : -addr & ~PAGE_MASK;
247 todo = *reps * bytes_per_rep;
248 if ( done >= todo )
249 goto done;
251 for ( i = 1; done < todo; i++ )
252 {
253 /* Get the next PFN in the range. */
254 addr += reverse ? -PAGE_SIZE : PAGE_SIZE;
255 npfn = paging_gva_to_gfn(curr, addr, &pfec);
257 /* Is it contiguous with the preceding PFNs? If not then we're done. */
258 if ( (npfn == INVALID_GFN) || (npfn != (pfn + (reverse ? -i : i))) )
259 {
260 done /= bytes_per_rep;
261 if ( done == 0 )
262 {
263 ASSERT(!reverse);
264 if ( npfn != INVALID_GFN )
265 return X86EMUL_UNHANDLEABLE;
266 hvm_inject_exception(TRAP_page_fault, pfec, addr & PAGE_MASK);
267 return X86EMUL_EXCEPTION;
268 }
269 *reps = done;
270 break;
271 }
273 done += PAGE_SIZE;
274 }
276 done:
277 *paddr |= (paddr_t)pfn << PAGE_SHIFT;
278 return X86EMUL_OKAY;
279 }
282 static int hvmemul_virtual_to_linear(
283 enum x86_segment seg,
284 unsigned long offset,
285 unsigned int bytes_per_rep,
286 unsigned long *reps,
287 enum hvm_access_type access_type,
288 struct hvm_emulate_ctxt *hvmemul_ctxt,
289 unsigned long *paddr)
290 {
291 struct segment_register *reg;
292 int okay;
294 if ( seg == x86_seg_none )
295 {
296 *paddr = offset;
297 return X86EMUL_OKAY;
298 }
300 *reps = min_t(unsigned long, *reps, 4096);
301 reg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
303 if ( (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (*reps > 1) )
304 {
305 ASSERT(offset >= ((*reps - 1) * bytes_per_rep));
306 okay = hvm_virtual_to_linear_addr(
307 seg, reg, offset - (*reps - 1) * bytes_per_rep,
308 *reps * bytes_per_rep, access_type,
309 hvmemul_ctxt->ctxt.addr_size, paddr);
310 *paddr += (*reps - 1) * bytes_per_rep;
311 if ( hvmemul_ctxt->ctxt.addr_size != 64 )
312 *paddr = (uint32_t)*paddr;
313 }
314 else
315 {
316 okay = hvm_virtual_to_linear_addr(
317 seg, reg, offset, *reps * bytes_per_rep, access_type,
318 hvmemul_ctxt->ctxt.addr_size, paddr);
319 }
321 if ( okay )
322 return X86EMUL_OKAY;
324 /* If this is a string operation, emulate each iteration separately. */
325 if ( *reps != 1 )
326 return X86EMUL_UNHANDLEABLE;
328 /* This is a singleton operation: fail it with an exception. */
329 hvmemul_ctxt->exn_pending = 1;
330 hvmemul_ctxt->exn_vector = TRAP_gp_fault;
331 hvmemul_ctxt->exn_error_code = 0;
332 hvmemul_ctxt->exn_insn_len = 0;
333 return X86EMUL_EXCEPTION;
334 }
336 static int __hvmemul_read(
337 enum x86_segment seg,
338 unsigned long offset,
339 void *p_data,
340 unsigned int bytes,
341 enum hvm_access_type access_type,
342 struct hvm_emulate_ctxt *hvmemul_ctxt)
343 {
344 struct vcpu *curr = current;
345 unsigned long addr, reps = 1;
346 uint32_t pfec = PFEC_page_present;
347 paddr_t gpa;
348 int rc;
350 rc = hvmemul_virtual_to_linear(
351 seg, offset, bytes, &reps, access_type, hvmemul_ctxt, &addr);
352 if ( rc != X86EMUL_OKAY )
353 return rc;
355 if ( unlikely(curr->arch.hvm_vcpu.mmio_gva == (addr & PAGE_MASK)) &&
356 curr->arch.hvm_vcpu.mmio_gva )
357 {
358 unsigned int off = addr & (PAGE_SIZE - 1);
359 if ( access_type == hvm_access_insn_fetch )
360 return X86EMUL_UNHANDLEABLE;
361 gpa = (((paddr_t)curr->arch.hvm_vcpu.mmio_gpfn << PAGE_SHIFT) | off);
362 if ( (off + bytes) <= PAGE_SIZE )
363 return hvmemul_do_mmio(gpa, &reps, bytes, 0,
364 IOREQ_READ, 0, p_data);
365 }
367 if ( (seg != x86_seg_none) &&
368 (hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3) )
369 pfec |= PFEC_user_mode;
371 rc = ((access_type == hvm_access_insn_fetch) ?
372 hvm_fetch_from_guest_virt(p_data, addr, bytes, pfec) :
373 hvm_copy_from_guest_virt(p_data, addr, bytes, pfec));
374 if ( rc == HVMCOPY_bad_gva_to_gfn )
375 return X86EMUL_EXCEPTION;
377 if ( rc == HVMCOPY_bad_gfn_to_mfn )
378 {
379 if ( access_type == hvm_access_insn_fetch )
380 return X86EMUL_UNHANDLEABLE;
382 rc = hvmemul_linear_to_phys(
383 addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
384 if ( rc != X86EMUL_OKAY )
385 return rc;
387 return hvmemul_do_mmio(gpa, &reps, bytes, 0, IOREQ_READ, 0, p_data);
388 }
390 return X86EMUL_OKAY;
391 }
393 static int hvmemul_read(
394 enum x86_segment seg,
395 unsigned long offset,
396 void *p_data,
397 unsigned int bytes,
398 struct x86_emulate_ctxt *ctxt)
399 {
400 return __hvmemul_read(
401 seg, offset, p_data, bytes, hvm_access_read,
402 container_of(ctxt, struct hvm_emulate_ctxt, ctxt));
403 }
405 static int hvmemul_insn_fetch(
406 enum x86_segment seg,
407 unsigned long offset,
408 void *p_data,
409 unsigned int bytes,
410 struct x86_emulate_ctxt *ctxt)
411 {
412 struct hvm_emulate_ctxt *hvmemul_ctxt =
413 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
414 unsigned int insn_off = offset - hvmemul_ctxt->insn_buf_eip;
416 /* Fall back if requested bytes are not in the prefetch cache. */
417 if ( unlikely((insn_off + bytes) > hvmemul_ctxt->insn_buf_bytes) )
418 return __hvmemul_read(
419 seg, offset, p_data, bytes,
420 hvm_access_insn_fetch, hvmemul_ctxt);
422 /* Hit the cache. Simple memcpy. */
423 memcpy(p_data, &hvmemul_ctxt->insn_buf[insn_off], bytes);
424 return X86EMUL_OKAY;
425 }
427 static int hvmemul_write(
428 enum x86_segment seg,
429 unsigned long offset,
430 void *p_data,
431 unsigned int bytes,
432 struct x86_emulate_ctxt *ctxt)
433 {
434 struct hvm_emulate_ctxt *hvmemul_ctxt =
435 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
436 struct vcpu *curr = current;
437 unsigned long addr, reps = 1;
438 uint32_t pfec = PFEC_page_present | PFEC_write_access;
439 paddr_t gpa;
440 int rc;
442 rc = hvmemul_virtual_to_linear(
443 seg, offset, bytes, &reps, hvm_access_write, hvmemul_ctxt, &addr);
444 if ( rc != X86EMUL_OKAY )
445 return rc;
447 if ( unlikely(curr->arch.hvm_vcpu.mmio_gva == (addr & PAGE_MASK)) &&
448 curr->arch.hvm_vcpu.mmio_gva )
449 {
450 unsigned int off = addr & (PAGE_SIZE - 1);
451 gpa = (((paddr_t)curr->arch.hvm_vcpu.mmio_gpfn << PAGE_SHIFT) | off);
452 if ( (off + bytes) <= PAGE_SIZE )
453 return hvmemul_do_mmio(gpa, &reps, bytes, 0,
454 IOREQ_WRITE, 0, p_data);
455 }
457 if ( (seg != x86_seg_none) &&
458 (hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3) )
459 pfec |= PFEC_user_mode;
461 rc = hvm_copy_to_guest_virt(addr, p_data, bytes, pfec);
462 if ( rc == HVMCOPY_bad_gva_to_gfn )
463 return X86EMUL_EXCEPTION;
465 if ( rc == HVMCOPY_bad_gfn_to_mfn )
466 {
467 rc = hvmemul_linear_to_phys(
468 addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
469 if ( rc != X86EMUL_OKAY )
470 return rc;
472 return hvmemul_do_mmio(gpa, &reps, bytes, 0,
473 IOREQ_WRITE, 0, p_data);
474 }
476 return X86EMUL_OKAY;
477 }
479 static int hvmemul_cmpxchg(
480 enum x86_segment seg,
481 unsigned long offset,
482 void *p_old,
483 void *p_new,
484 unsigned int bytes,
485 struct x86_emulate_ctxt *ctxt)
486 {
487 /* Fix this in case the guest is really relying on r-m-w atomicity. */
488 return hvmemul_write(seg, offset, p_new, bytes, ctxt);
489 }
491 static int hvmemul_rep_ins(
492 uint16_t src_port,
493 enum x86_segment dst_seg,
494 unsigned long dst_offset,
495 unsigned int bytes_per_rep,
496 unsigned long *reps,
497 struct x86_emulate_ctxt *ctxt)
498 {
499 struct hvm_emulate_ctxt *hvmemul_ctxt =
500 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
501 unsigned long addr;
502 uint32_t pfec = PFEC_page_present | PFEC_write_access;
503 paddr_t gpa;
504 int rc;
506 rc = hvmemul_virtual_to_linear(
507 dst_seg, dst_offset, bytes_per_rep, reps, hvm_access_write,
508 hvmemul_ctxt, &addr);
509 if ( rc != X86EMUL_OKAY )
510 return rc;
512 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
513 pfec |= PFEC_user_mode;
515 rc = hvmemul_linear_to_phys(
516 addr, &gpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
517 if ( rc != X86EMUL_OKAY )
518 return rc;
520 return hvmemul_do_pio(src_port, reps, bytes_per_rep, gpa, IOREQ_READ,
521 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
522 }
524 static int hvmemul_rep_outs(
525 enum x86_segment src_seg,
526 unsigned long src_offset,
527 uint16_t dst_port,
528 unsigned int bytes_per_rep,
529 unsigned long *reps,
530 struct x86_emulate_ctxt *ctxt)
531 {
532 struct hvm_emulate_ctxt *hvmemul_ctxt =
533 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
534 unsigned long addr;
535 uint32_t pfec = PFEC_page_present;
536 paddr_t gpa;
537 int rc;
539 rc = hvmemul_virtual_to_linear(
540 src_seg, src_offset, bytes_per_rep, reps, hvm_access_read,
541 hvmemul_ctxt, &addr);
542 if ( rc != X86EMUL_OKAY )
543 return rc;
545 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
546 pfec |= PFEC_user_mode;
548 rc = hvmemul_linear_to_phys(
549 addr, &gpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
550 if ( rc != X86EMUL_OKAY )
551 return rc;
553 return hvmemul_do_pio(dst_port, reps, bytes_per_rep, gpa, IOREQ_WRITE,
554 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
555 }
557 static int hvmemul_rep_movs(
558 enum x86_segment src_seg,
559 unsigned long src_offset,
560 enum x86_segment dst_seg,
561 unsigned long dst_offset,
562 unsigned int bytes_per_rep,
563 unsigned long *reps,
564 struct x86_emulate_ctxt *ctxt)
565 {
566 struct hvm_emulate_ctxt *hvmemul_ctxt =
567 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
568 unsigned long saddr, daddr;
569 paddr_t sgpa, dgpa;
570 uint32_t pfec = PFEC_page_present;
571 p2m_type_t p2mt;
572 int rc;
574 rc = hvmemul_virtual_to_linear(
575 src_seg, src_offset, bytes_per_rep, reps, hvm_access_read,
576 hvmemul_ctxt, &saddr);
577 if ( rc != X86EMUL_OKAY )
578 return rc;
580 rc = hvmemul_virtual_to_linear(
581 dst_seg, dst_offset, bytes_per_rep, reps, hvm_access_write,
582 hvmemul_ctxt, &daddr);
583 if ( rc != X86EMUL_OKAY )
584 return rc;
586 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
587 pfec |= PFEC_user_mode;
589 rc = hvmemul_linear_to_phys(
590 saddr, &sgpa, bytes_per_rep, reps, pfec, hvmemul_ctxt);
591 if ( rc != X86EMUL_OKAY )
592 return rc;
594 rc = hvmemul_linear_to_phys(
595 daddr, &dgpa, bytes_per_rep, reps,
596 pfec | PFEC_write_access, hvmemul_ctxt);
597 if ( rc != X86EMUL_OKAY )
598 return rc;
600 (void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt);
601 if ( !p2m_is_ram(p2mt) )
602 return hvmemul_do_mmio(
603 sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ,
604 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
606 (void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt);
607 if ( p2m_is_ram(p2mt) )
608 return X86EMUL_UNHANDLEABLE;
609 return hvmemul_do_mmio(
610 dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE,
611 !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL);
612 }
614 static int hvmemul_read_segment(
615 enum x86_segment seg,
616 struct segment_register *reg,
617 struct x86_emulate_ctxt *ctxt)
618 {
619 struct hvm_emulate_ctxt *hvmemul_ctxt =
620 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
621 struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
622 memcpy(reg, sreg, sizeof(struct segment_register));
623 return X86EMUL_OKAY;
624 }
626 static int hvmemul_write_segment(
627 enum x86_segment seg,
628 struct segment_register *reg,
629 struct x86_emulate_ctxt *ctxt)
630 {
631 struct hvm_emulate_ctxt *hvmemul_ctxt =
632 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
633 struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
635 memcpy(sreg, reg, sizeof(struct segment_register));
636 __set_bit(seg, &hvmemul_ctxt->seg_reg_dirty);
638 return X86EMUL_OKAY;
639 }
641 static int hvmemul_read_io(
642 unsigned int port,
643 unsigned int bytes,
644 unsigned long *val,
645 struct x86_emulate_ctxt *ctxt)
646 {
647 unsigned long reps = 1;
648 *val = 0;
649 return hvmemul_do_pio(port, &reps, bytes, 0, IOREQ_READ, 0, val);
650 }
652 static int hvmemul_write_io(
653 unsigned int port,
654 unsigned int bytes,
655 unsigned long val,
656 struct x86_emulate_ctxt *ctxt)
657 {
658 unsigned long reps = 1;
659 return hvmemul_do_pio(port, &reps, bytes, 0, IOREQ_WRITE, 0, &val);
660 }
662 static int hvmemul_read_cr(
663 unsigned int reg,
664 unsigned long *val,
665 struct x86_emulate_ctxt *ctxt)
666 {
667 switch ( reg )
668 {
669 case 0:
670 case 2:
671 case 3:
672 case 4:
673 *val = current->arch.hvm_vcpu.guest_cr[reg];
674 return X86EMUL_OKAY;
675 default:
676 break;
677 }
679 return X86EMUL_UNHANDLEABLE;
680 }
682 static int hvmemul_write_cr(
683 unsigned int reg,
684 unsigned long val,
685 struct x86_emulate_ctxt *ctxt)
686 {
687 switch ( reg )
688 {
689 case 0:
690 return hvm_set_cr0(val);
691 case 2:
692 current->arch.hvm_vcpu.guest_cr[2] = val;
693 return X86EMUL_OKAY;
694 case 3:
695 return hvm_set_cr3(val);
696 case 4:
697 return hvm_set_cr4(val);
698 default:
699 break;
700 }
702 return X86EMUL_UNHANDLEABLE;
703 }
705 static int hvmemul_read_msr(
706 unsigned long reg,
707 uint64_t *val,
708 struct x86_emulate_ctxt *ctxt)
709 {
710 struct cpu_user_regs _regs;
711 int rc;
713 _regs.ecx = (uint32_t)reg;
715 if ( (rc = hvm_msr_read_intercept(&_regs)) != 0 )
716 return rc;
718 *val = ((uint64_t)(uint32_t)_regs.edx << 32) || (uint32_t)_regs.eax;
719 return X86EMUL_OKAY;
720 }
722 static int hvmemul_write_msr(
723 unsigned long reg,
724 uint64_t val,
725 struct x86_emulate_ctxt *ctxt)
726 {
727 struct cpu_user_regs _regs;
729 _regs.edx = (uint32_t)(val >> 32);
730 _regs.eax = (uint32_t)val;
731 _regs.ecx = (uint32_t)reg;
733 return hvm_msr_write_intercept(&_regs);
734 }
736 static int hvmemul_wbinvd(
737 struct x86_emulate_ctxt *ctxt)
738 {
739 hvm_funcs.wbinvd_intercept();
740 return X86EMUL_OKAY;
741 }
743 static int hvmemul_cpuid(
744 unsigned int *eax,
745 unsigned int *ebx,
746 unsigned int *ecx,
747 unsigned int *edx,
748 struct x86_emulate_ctxt *ctxt)
749 {
750 hvm_funcs.cpuid_intercept(eax, ebx, ecx, edx);
751 return X86EMUL_OKAY;
752 }
754 static int hvmemul_inject_hw_exception(
755 uint8_t vector,
756 int32_t error_code,
757 struct x86_emulate_ctxt *ctxt)
758 {
759 struct hvm_emulate_ctxt *hvmemul_ctxt =
760 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
762 hvmemul_ctxt->exn_pending = 1;
763 hvmemul_ctxt->exn_vector = vector;
764 hvmemul_ctxt->exn_error_code = error_code;
765 hvmemul_ctxt->exn_insn_len = 0;
767 return X86EMUL_OKAY;
768 }
770 static int hvmemul_inject_sw_interrupt(
771 uint8_t vector,
772 uint8_t insn_len,
773 struct x86_emulate_ctxt *ctxt)
774 {
775 struct hvm_emulate_ctxt *hvmemul_ctxt =
776 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
778 hvmemul_ctxt->exn_pending = 1;
779 hvmemul_ctxt->exn_vector = vector;
780 hvmemul_ctxt->exn_error_code = -1;
781 hvmemul_ctxt->exn_insn_len = insn_len;
783 return X86EMUL_OKAY;
784 }
786 static int hvmemul_get_fpu(
787 void (*exception_callback)(void *, struct cpu_user_regs *),
788 void *exception_callback_arg,
789 enum x86_emulate_fpu_type type,
790 struct x86_emulate_ctxt *ctxt)
791 {
792 struct vcpu *curr = current;
794 switch ( type )
795 {
796 case X86EMUL_FPU_fpu:
797 break;
798 case X86EMUL_FPU_mmx:
799 if ( !cpu_has_mmx )
800 return X86EMUL_UNHANDLEABLE;
801 break;
802 default:
803 return X86EMUL_UNHANDLEABLE;
804 }
806 if ( !curr->fpu_dirtied )
807 hvm_funcs.fpu_dirty_intercept();
809 curr->arch.hvm_vcpu.fpu_exception_callback = exception_callback;
810 curr->arch.hvm_vcpu.fpu_exception_callback_arg = exception_callback_arg;
812 return X86EMUL_OKAY;
813 }
815 static void hvmemul_put_fpu(
816 struct x86_emulate_ctxt *ctxt)
817 {
818 struct vcpu *curr = current;
819 curr->arch.hvm_vcpu.fpu_exception_callback = NULL;
820 }
822 static int hvmemul_invlpg(
823 enum x86_segment seg,
824 unsigned long offset,
825 struct x86_emulate_ctxt *ctxt)
826 {
827 struct hvm_emulate_ctxt *hvmemul_ctxt =
828 container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
829 unsigned long addr, reps = 1;
830 int rc;
832 rc = hvmemul_virtual_to_linear(
833 seg, offset, 1, &reps, hvm_access_none, hvmemul_ctxt, &addr);
835 if ( rc == X86EMUL_OKAY )
836 hvm_funcs.invlpg_intercept(addr);
838 return rc;
839 }
841 static struct x86_emulate_ops hvm_emulate_ops = {
842 .read = hvmemul_read,
843 .insn_fetch = hvmemul_insn_fetch,
844 .write = hvmemul_write,
845 .cmpxchg = hvmemul_cmpxchg,
846 .rep_ins = hvmemul_rep_ins,
847 .rep_outs = hvmemul_rep_outs,
848 .rep_movs = hvmemul_rep_movs,
849 .read_segment = hvmemul_read_segment,
850 .write_segment = hvmemul_write_segment,
851 .read_io = hvmemul_read_io,
852 .write_io = hvmemul_write_io,
853 .read_cr = hvmemul_read_cr,
854 .write_cr = hvmemul_write_cr,
855 .read_msr = hvmemul_read_msr,
856 .write_msr = hvmemul_write_msr,
857 .wbinvd = hvmemul_wbinvd,
858 .cpuid = hvmemul_cpuid,
859 .inject_hw_exception = hvmemul_inject_hw_exception,
860 .inject_sw_interrupt = hvmemul_inject_sw_interrupt,
861 .get_fpu = hvmemul_get_fpu,
862 .put_fpu = hvmemul_put_fpu,
863 .invlpg = hvmemul_invlpg
864 };
866 int hvm_emulate_one(
867 struct hvm_emulate_ctxt *hvmemul_ctxt)
868 {
869 struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
870 struct vcpu *curr = current;
871 uint32_t new_intr_shadow, pfec = PFEC_page_present;
872 unsigned long addr;
873 int rc;
875 if ( hvm_long_mode_enabled(curr) &&
876 hvmemul_ctxt->seg_reg[x86_seg_cs].attr.fields.l )
877 {
878 hvmemul_ctxt->ctxt.addr_size = hvmemul_ctxt->ctxt.sp_size = 64;
879 }
880 else
881 {
882 hvmemul_ctxt->ctxt.addr_size =
883 hvmemul_ctxt->seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
884 hvmemul_ctxt->ctxt.sp_size =
885 hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
886 }
888 if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
889 pfec |= PFEC_user_mode;
891 hvmemul_ctxt->insn_buf_eip = regs->eip;
892 hvmemul_ctxt->insn_buf_bytes =
893 (hvm_virtual_to_linear_addr(
894 x86_seg_cs, &hvmemul_ctxt->seg_reg[x86_seg_cs],
895 regs->eip, sizeof(hvmemul_ctxt->insn_buf),
896 hvm_access_insn_fetch, hvmemul_ctxt->ctxt.addr_size, &addr) &&
897 !hvm_fetch_from_guest_virt_nofault(
898 hvmemul_ctxt->insn_buf, addr,
899 sizeof(hvmemul_ctxt->insn_buf), pfec))
900 ? sizeof(hvmemul_ctxt->insn_buf) : 0;
902 hvmemul_ctxt->exn_pending = 0;
904 rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops);
906 if ( rc != X86EMUL_RETRY )
907 curr->arch.hvm_vcpu.mmio_large_read_bytes =
908 curr->arch.hvm_vcpu.mmio_large_write_bytes = 0;
910 if ( rc != X86EMUL_OKAY )
911 return rc;
913 new_intr_shadow = hvmemul_ctxt->intr_shadow;
915 /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
916 if ( hvmemul_ctxt->ctxt.retire.flags.mov_ss )
917 new_intr_shadow ^= HVM_INTR_SHADOW_MOV_SS;
918 else
919 new_intr_shadow &= ~HVM_INTR_SHADOW_MOV_SS;
921 /* STI instruction toggles STI shadow, else we just clear it. */
922 if ( hvmemul_ctxt->ctxt.retire.flags.sti )
923 new_intr_shadow ^= HVM_INTR_SHADOW_STI;
924 else
925 new_intr_shadow &= ~HVM_INTR_SHADOW_STI;
927 if ( hvmemul_ctxt->intr_shadow != new_intr_shadow )
928 {
929 hvmemul_ctxt->intr_shadow = new_intr_shadow;
930 hvm_funcs.set_interrupt_shadow(curr, new_intr_shadow);
931 }
933 if ( hvmemul_ctxt->ctxt.retire.flags.hlt &&
934 !hvm_local_events_need_delivery(curr) )
935 {
936 hvm_hlt(regs->eflags);
937 }
939 return X86EMUL_OKAY;
940 }
942 void hvm_emulate_prepare(
943 struct hvm_emulate_ctxt *hvmemul_ctxt,
944 struct cpu_user_regs *regs)
945 {
946 hvmemul_ctxt->intr_shadow = hvm_funcs.get_interrupt_shadow(current);
947 hvmemul_ctxt->ctxt.regs = regs;
948 hvmemul_ctxt->ctxt.force_writeback = 1;
949 hvmemul_ctxt->seg_reg_accessed = 0;
950 hvmemul_ctxt->seg_reg_dirty = 0;
951 hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt);
952 hvmemul_get_seg_reg(x86_seg_ss, hvmemul_ctxt);
953 }
955 void hvm_emulate_writeback(
956 struct hvm_emulate_ctxt *hvmemul_ctxt)
957 {
958 enum x86_segment seg;
960 seg = find_first_bit(&hvmemul_ctxt->seg_reg_dirty,
961 ARRAY_SIZE(hvmemul_ctxt->seg_reg));
963 while ( seg < ARRAY_SIZE(hvmemul_ctxt->seg_reg) )
964 {
965 hvm_set_segment_register(current, seg, &hvmemul_ctxt->seg_reg[seg]);
966 seg = find_next_bit(&hvmemul_ctxt->seg_reg_dirty,
967 ARRAY_SIZE(hvmemul_ctxt->seg_reg),
968 seg+1);
969 }
970 }
972 struct segment_register *hvmemul_get_seg_reg(
973 enum x86_segment seg,
974 struct hvm_emulate_ctxt *hvmemul_ctxt)
975 {
976 if ( !__test_and_set_bit(seg, &hvmemul_ctxt->seg_reg_accessed) )
977 hvm_get_segment_register(current, seg, &hvmemul_ctxt->seg_reg[seg]);
978 return &hvmemul_ctxt->seg_reg[seg];
979 }