1 | /* |
---|
2 | * io.c: Handling I/O and interrupts. |
---|
3 | * |
---|
4 | * Copyright (c) 2004, Intel Corporation. |
---|
5 | * Copyright (c) 2005, International Business Machines Corporation. |
---|
6 | * |
---|
7 | * This program is free software; you can redistribute it and/or modify it |
---|
8 | * under the terms and conditions of the GNU General Public License, |
---|
9 | * version 2, as published by the Free Software Foundation. |
---|
10 | * |
---|
11 | * This program is distributed in the hope it will be useful, but WITHOUT |
---|
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
14 | * more details. |
---|
15 | * |
---|
16 | * You should have received a copy of the GNU General Public License along with |
---|
17 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
18 | * Place - Suite 330, Boston, MA 02111-1307 USA. |
---|
19 | */ |
---|
20 | |
---|
21 | #include <xen/config.h> |
---|
22 | #include <xen/init.h> |
---|
23 | #include <xen/mm.h> |
---|
24 | #include <xen/lib.h> |
---|
25 | #include <xen/errno.h> |
---|
26 | #include <xen/trace.h> |
---|
27 | #include <xen/event.h> |
---|
28 | |
---|
29 | #include <xen/hypercall.h> |
---|
30 | #include <asm/current.h> |
---|
31 | #include <asm/cpufeature.h> |
---|
32 | #include <asm/processor.h> |
---|
33 | #include <asm/msr.h> |
---|
34 | #include <asm/apic.h> |
---|
35 | #include <asm/paging.h> |
---|
36 | #include <asm/shadow.h> |
---|
37 | #include <asm/p2m.h> |
---|
38 | #include <asm/hvm/hvm.h> |
---|
39 | #include <asm/hvm/support.h> |
---|
40 | #include <asm/hvm/vpt.h> |
---|
41 | #include <asm/hvm/vpic.h> |
---|
42 | #include <asm/hvm/vlapic.h> |
---|
43 | |
---|
44 | #include <public/sched.h> |
---|
45 | #include <public/hvm/ioreq.h> |
---|
46 | |
---|
47 | #if defined (__i386__) |
---|
48 | static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *regs, long value) |
---|
49 | { |
---|
50 | switch (size) { |
---|
51 | case BYTE: |
---|
52 | switch (index) { |
---|
53 | case 0: |
---|
54 | regs->eax &= 0xFFFFFF00; |
---|
55 | regs->eax |= (value & 0xFF); |
---|
56 | break; |
---|
57 | case 1: |
---|
58 | regs->ecx &= 0xFFFFFF00; |
---|
59 | regs->ecx |= (value & 0xFF); |
---|
60 | break; |
---|
61 | case 2: |
---|
62 | regs->edx &= 0xFFFFFF00; |
---|
63 | regs->edx |= (value & 0xFF); |
---|
64 | break; |
---|
65 | case 3: |
---|
66 | regs->ebx &= 0xFFFFFF00; |
---|
67 | regs->ebx |= (value & 0xFF); |
---|
68 | break; |
---|
69 | case 4: |
---|
70 | regs->eax &= 0xFFFF00FF; |
---|
71 | regs->eax |= ((value & 0xFF) << 8); |
---|
72 | break; |
---|
73 | case 5: |
---|
74 | regs->ecx &= 0xFFFF00FF; |
---|
75 | regs->ecx |= ((value & 0xFF) << 8); |
---|
76 | break; |
---|
77 | case 6: |
---|
78 | regs->edx &= 0xFFFF00FF; |
---|
79 | regs->edx |= ((value & 0xFF) << 8); |
---|
80 | break; |
---|
81 | case 7: |
---|
82 | regs->ebx &= 0xFFFF00FF; |
---|
83 | regs->ebx |= ((value & 0xFF) << 8); |
---|
84 | break; |
---|
85 | default: |
---|
86 | goto crash; |
---|
87 | } |
---|
88 | break; |
---|
89 | case WORD: |
---|
90 | switch (index) { |
---|
91 | case 0: |
---|
92 | regs->eax &= 0xFFFF0000; |
---|
93 | regs->eax |= (value & 0xFFFF); |
---|
94 | break; |
---|
95 | case 1: |
---|
96 | regs->ecx &= 0xFFFF0000; |
---|
97 | regs->ecx |= (value & 0xFFFF); |
---|
98 | break; |
---|
99 | case 2: |
---|
100 | regs->edx &= 0xFFFF0000; |
---|
101 | regs->edx |= (value & 0xFFFF); |
---|
102 | break; |
---|
103 | case 3: |
---|
104 | regs->ebx &= 0xFFFF0000; |
---|
105 | regs->ebx |= (value & 0xFFFF); |
---|
106 | break; |
---|
107 | case 4: |
---|
108 | regs->esp &= 0xFFFF0000; |
---|
109 | regs->esp |= (value & 0xFFFF); |
---|
110 | break; |
---|
111 | case 5: |
---|
112 | regs->ebp &= 0xFFFF0000; |
---|
113 | regs->ebp |= (value & 0xFFFF); |
---|
114 | break; |
---|
115 | case 6: |
---|
116 | regs->esi &= 0xFFFF0000; |
---|
117 | regs->esi |= (value & 0xFFFF); |
---|
118 | break; |
---|
119 | case 7: |
---|
120 | regs->edi &= 0xFFFF0000; |
---|
121 | regs->edi |= (value & 0xFFFF); |
---|
122 | break; |
---|
123 | default: |
---|
124 | goto crash; |
---|
125 | } |
---|
126 | break; |
---|
127 | case LONG: |
---|
128 | switch (index) { |
---|
129 | case 0: |
---|
130 | regs->eax = value; |
---|
131 | break; |
---|
132 | case 1: |
---|
133 | regs->ecx = value; |
---|
134 | break; |
---|
135 | case 2: |
---|
136 | regs->edx = value; |
---|
137 | break; |
---|
138 | case 3: |
---|
139 | regs->ebx = value; |
---|
140 | break; |
---|
141 | case 4: |
---|
142 | regs->esp = value; |
---|
143 | break; |
---|
144 | case 5: |
---|
145 | regs->ebp = value; |
---|
146 | break; |
---|
147 | case 6: |
---|
148 | regs->esi = value; |
---|
149 | break; |
---|
150 | case 7: |
---|
151 | regs->edi = value; |
---|
152 | break; |
---|
153 | default: |
---|
154 | goto crash; |
---|
155 | } |
---|
156 | break; |
---|
157 | default: |
---|
158 | crash: |
---|
159 | gdprintk(XENLOG_ERR, "size:%x, index:%x are invalid!\n", size, index); |
---|
160 | domain_crash_synchronous(); |
---|
161 | } |
---|
162 | } |
---|
163 | #else |
---|
164 | static inline void __set_reg_value(unsigned long *reg, int size, long value) |
---|
165 | { |
---|
166 | switch (size) { |
---|
167 | case BYTE_64: |
---|
168 | *reg &= ~0xFF; |
---|
169 | *reg |= (value & 0xFF); |
---|
170 | break; |
---|
171 | case WORD: |
---|
172 | *reg &= ~0xFFFF; |
---|
173 | *reg |= (value & 0xFFFF); |
---|
174 | break; |
---|
175 | case LONG: |
---|
176 | *reg &= ~0xFFFFFFFF; |
---|
177 | *reg |= (value & 0xFFFFFFFF); |
---|
178 | break; |
---|
179 | case QUAD: |
---|
180 | *reg = value; |
---|
181 | break; |
---|
182 | default: |
---|
183 | gdprintk(XENLOG_ERR, "size:%x is invalid\n", size); |
---|
184 | domain_crash_synchronous(); |
---|
185 | } |
---|
186 | } |
---|
187 | |
---|
188 | static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *regs, long value) |
---|
189 | { |
---|
190 | if (size == BYTE) { |
---|
191 | switch (index) { |
---|
192 | case 0: |
---|
193 | regs->rax &= ~0xFF; |
---|
194 | regs->rax |= (value & 0xFF); |
---|
195 | break; |
---|
196 | case 1: |
---|
197 | regs->rcx &= ~0xFF; |
---|
198 | regs->rcx |= (value & 0xFF); |
---|
199 | break; |
---|
200 | case 2: |
---|
201 | regs->rdx &= ~0xFF; |
---|
202 | regs->rdx |= (value & 0xFF); |
---|
203 | break; |
---|
204 | case 3: |
---|
205 | regs->rbx &= ~0xFF; |
---|
206 | regs->rbx |= (value & 0xFF); |
---|
207 | break; |
---|
208 | case 4: |
---|
209 | regs->rax &= 0xFFFFFFFFFFFF00FF; |
---|
210 | regs->rax |= ((value & 0xFF) << 8); |
---|
211 | break; |
---|
212 | case 5: |
---|
213 | regs->rcx &= 0xFFFFFFFFFFFF00FF; |
---|
214 | regs->rcx |= ((value & 0xFF) << 8); |
---|
215 | break; |
---|
216 | case 6: |
---|
217 | regs->rdx &= 0xFFFFFFFFFFFF00FF; |
---|
218 | regs->rdx |= ((value & 0xFF) << 8); |
---|
219 | break; |
---|
220 | case 7: |
---|
221 | regs->rbx &= 0xFFFFFFFFFFFF00FF; |
---|
222 | regs->rbx |= ((value & 0xFF) << 8); |
---|
223 | break; |
---|
224 | default: |
---|
225 | gdprintk(XENLOG_ERR, "size:%x, index:%x are invalid!\n", |
---|
226 | size, index); |
---|
227 | domain_crash_synchronous(); |
---|
228 | break; |
---|
229 | } |
---|
230 | return; |
---|
231 | } |
---|
232 | |
---|
233 | switch (index) { |
---|
234 | case 0: |
---|
235 | __set_reg_value(®s->rax, size, value); |
---|
236 | break; |
---|
237 | case 1: |
---|
238 | __set_reg_value(®s->rcx, size, value); |
---|
239 | break; |
---|
240 | case 2: |
---|
241 | __set_reg_value(®s->rdx, size, value); |
---|
242 | break; |
---|
243 | case 3: |
---|
244 | __set_reg_value(®s->rbx, size, value); |
---|
245 | break; |
---|
246 | case 4: |
---|
247 | __set_reg_value(®s->rsp, size, value); |
---|
248 | break; |
---|
249 | case 5: |
---|
250 | __set_reg_value(®s->rbp, size, value); |
---|
251 | break; |
---|
252 | case 6: |
---|
253 | __set_reg_value(®s->rsi, size, value); |
---|
254 | break; |
---|
255 | case 7: |
---|
256 | __set_reg_value(®s->rdi, size, value); |
---|
257 | break; |
---|
258 | case 8: |
---|
259 | __set_reg_value(®s->r8, size, value); |
---|
260 | break; |
---|
261 | case 9: |
---|
262 | __set_reg_value(®s->r9, size, value); |
---|
263 | break; |
---|
264 | case 10: |
---|
265 | __set_reg_value(®s->r10, size, value); |
---|
266 | break; |
---|
267 | case 11: |
---|
268 | __set_reg_value(®s->r11, size, value); |
---|
269 | break; |
---|
270 | case 12: |
---|
271 | __set_reg_value(®s->r12, size, value); |
---|
272 | break; |
---|
273 | case 13: |
---|
274 | __set_reg_value(®s->r13, size, value); |
---|
275 | break; |
---|
276 | case 14: |
---|
277 | __set_reg_value(®s->r14, size, value); |
---|
278 | break; |
---|
279 | case 15: |
---|
280 | __set_reg_value(®s->r15, size, value); |
---|
281 | break; |
---|
282 | default: |
---|
283 | gdprintk(XENLOG_ERR, "Invalid index\n"); |
---|
284 | domain_crash_synchronous(); |
---|
285 | } |
---|
286 | return; |
---|
287 | } |
---|
288 | #endif |
---|
289 | |
---|
290 | long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs); |
---|
291 | |
---|
292 | static inline void set_eflags_CF(int size, |
---|
293 | unsigned int instr, |
---|
294 | unsigned long result, |
---|
295 | unsigned long src, |
---|
296 | unsigned long dst, |
---|
297 | struct cpu_user_regs *regs) |
---|
298 | { |
---|
299 | unsigned long mask; |
---|
300 | |
---|
301 | if ( size == BYTE_64 ) |
---|
302 | size = BYTE; |
---|
303 | ASSERT((size <= sizeof(mask)) && (size > 0)); |
---|
304 | |
---|
305 | mask = ~0UL >> (8 * (sizeof(mask) - size)); |
---|
306 | |
---|
307 | if ( instr == INSTR_ADD ) |
---|
308 | { |
---|
309 | /* CF=1 <==> result is less than the augend and addend) */ |
---|
310 | if ( (result & mask) < (dst & mask) ) |
---|
311 | { |
---|
312 | ASSERT((result & mask) < (src & mask)); |
---|
313 | regs->eflags |= X86_EFLAGS_CF; |
---|
314 | } |
---|
315 | } |
---|
316 | else |
---|
317 | { |
---|
318 | ASSERT( instr == INSTR_CMP || instr == INSTR_SUB ); |
---|
319 | if ( (src & mask) > (dst & mask) ) |
---|
320 | regs->eflags |= X86_EFLAGS_CF; |
---|
321 | } |
---|
322 | } |
---|
323 | |
---|
324 | static inline void set_eflags_OF(int size, |
---|
325 | unsigned int instr, |
---|
326 | unsigned long result, |
---|
327 | unsigned long src, |
---|
328 | unsigned long dst, |
---|
329 | struct cpu_user_regs *regs) |
---|
330 | { |
---|
331 | unsigned long mask; |
---|
332 | |
---|
333 | if ( size == BYTE_64 ) |
---|
334 | size = BYTE; |
---|
335 | ASSERT((size <= sizeof(mask)) && (size > 0)); |
---|
336 | |
---|
337 | mask = 1UL << ((8*size) - 1); |
---|
338 | |
---|
339 | if ( instr == INSTR_ADD ) |
---|
340 | { |
---|
341 | if ((src ^ result) & (dst ^ result) & mask); |
---|
342 | regs->eflags |= X86_EFLAGS_OF; |
---|
343 | } |
---|
344 | else |
---|
345 | { |
---|
346 | ASSERT(instr == INSTR_CMP || instr == INSTR_SUB); |
---|
347 | if ((dst ^ src) & (dst ^ result) & mask) |
---|
348 | regs->eflags |= X86_EFLAGS_OF; |
---|
349 | } |
---|
350 | } |
---|
351 | |
---|
352 | static inline void set_eflags_AF(int size, |
---|
353 | unsigned long result, |
---|
354 | unsigned long src, |
---|
355 | unsigned long dst, |
---|
356 | struct cpu_user_regs *regs) |
---|
357 | { |
---|
358 | if ((result ^ src ^ dst) & 0x10) |
---|
359 | regs->eflags |= X86_EFLAGS_AF; |
---|
360 | } |
---|
361 | |
---|
362 | static inline void set_eflags_ZF(int size, unsigned long result, |
---|
363 | struct cpu_user_regs *regs) |
---|
364 | { |
---|
365 | unsigned long mask; |
---|
366 | |
---|
367 | if ( size == BYTE_64 ) |
---|
368 | size = BYTE; |
---|
369 | ASSERT((size <= sizeof(mask)) && (size > 0)); |
---|
370 | |
---|
371 | mask = ~0UL >> (8 * (sizeof(mask) - size)); |
---|
372 | |
---|
373 | if ((result & mask) == 0) |
---|
374 | regs->eflags |= X86_EFLAGS_ZF; |
---|
375 | } |
---|
376 | |
---|
377 | static inline void set_eflags_SF(int size, unsigned long result, |
---|
378 | struct cpu_user_regs *regs) |
---|
379 | { |
---|
380 | unsigned long mask; |
---|
381 | |
---|
382 | if ( size == BYTE_64 ) |
---|
383 | size = BYTE; |
---|
384 | ASSERT((size <= sizeof(mask)) && (size > 0)); |
---|
385 | |
---|
386 | mask = 1UL << ((8*size) - 1); |
---|
387 | |
---|
388 | if (result & mask) |
---|
389 | regs->eflags |= X86_EFLAGS_SF; |
---|
390 | } |
---|
391 | |
---|
392 | static char parity_table[256] = { |
---|
393 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
---|
394 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
395 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
396 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
---|
397 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
398 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
---|
399 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
---|
400 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
401 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
402 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
---|
403 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
---|
404 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
405 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
---|
406 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
407 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
---|
408 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 |
---|
409 | }; |
---|
410 | |
---|
411 | static inline void set_eflags_PF(int size, unsigned long result, |
---|
412 | struct cpu_user_regs *regs) |
---|
413 | { |
---|
414 | if (parity_table[result & 0xFF]) |
---|
415 | regs->eflags |= X86_EFLAGS_PF; |
---|
416 | } |
---|
417 | |
---|
418 | static void hvm_pio_assist(struct cpu_user_regs *regs, ioreq_t *p, |
---|
419 | struct hvm_io_op *pio_opp) |
---|
420 | { |
---|
421 | unsigned long old_eax; |
---|
422 | int sign = p->df ? -1 : 1; |
---|
423 | |
---|
424 | if ( p->data_is_ptr || (pio_opp->flags & OVERLAP) ) |
---|
425 | { |
---|
426 | if ( pio_opp->flags & REPZ ) |
---|
427 | regs->ecx -= p->count; |
---|
428 | |
---|
429 | if ( p->dir == IOREQ_READ ) |
---|
430 | { |
---|
431 | if ( pio_opp->flags & OVERLAP ) |
---|
432 | { |
---|
433 | unsigned long addr = pio_opp->addr; |
---|
434 | if ( hvm_paging_enabled(current) ) |
---|
435 | { |
---|
436 | int rv = hvm_copy_to_guest_virt(addr, &p->data, p->size); |
---|
437 | if ( rv != 0 ) |
---|
438 | { |
---|
439 | /* Failed on the page-spanning copy. Inject PF into |
---|
440 | * the guest for the address where we failed. */ |
---|
441 | addr += p->size - rv; |
---|
442 | gdprintk(XENLOG_DEBUG, "Pagefault writing non-io side " |
---|
443 | "of a page-spanning PIO: va=%#lx\n", addr); |
---|
444 | hvm_inject_exception(TRAP_page_fault, |
---|
445 | PFEC_write_access, addr); |
---|
446 | return; |
---|
447 | } |
---|
448 | } |
---|
449 | else |
---|
450 | (void)hvm_copy_to_guest_phys(addr, &p->data, p->size); |
---|
451 | } |
---|
452 | regs->edi += sign * p->count * p->size; |
---|
453 | } |
---|
454 | else /* p->dir == IOREQ_WRITE */ |
---|
455 | { |
---|
456 | ASSERT(p->dir == IOREQ_WRITE); |
---|
457 | regs->esi += sign * p->count * p->size; |
---|
458 | } |
---|
459 | } |
---|
460 | else if ( p->dir == IOREQ_READ ) |
---|
461 | { |
---|
462 | old_eax = regs->eax; |
---|
463 | switch ( p->size ) |
---|
464 | { |
---|
465 | case 1: |
---|
466 | regs->eax = (old_eax & 0xffffff00) | (p->data & 0xff); |
---|
467 | break; |
---|
468 | case 2: |
---|
469 | regs->eax = (old_eax & 0xffff0000) | (p->data & 0xffff); |
---|
470 | break; |
---|
471 | case 4: |
---|
472 | regs->eax = (p->data & 0xffffffff); |
---|
473 | break; |
---|
474 | default: |
---|
475 | printk("Error: %s unknown port size\n", __FUNCTION__); |
---|
476 | domain_crash_synchronous(); |
---|
477 | } |
---|
478 | } |
---|
479 | } |
---|
480 | |
---|
481 | static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p, |
---|
482 | struct hvm_io_op *mmio_opp) |
---|
483 | { |
---|
484 | int sign = p->df ? -1 : 1; |
---|
485 | int size = -1, index = -1; |
---|
486 | unsigned long value = 0, result = 0; |
---|
487 | unsigned long src, dst; |
---|
488 | |
---|
489 | src = mmio_opp->operand[0]; |
---|
490 | dst = mmio_opp->operand[1]; |
---|
491 | size = operand_size(src); |
---|
492 | |
---|
493 | switch (mmio_opp->instr) { |
---|
494 | case INSTR_MOV: |
---|
495 | if (dst & REGISTER) { |
---|
496 | index = operand_index(dst); |
---|
497 | set_reg_value(size, index, 0, regs, p->data); |
---|
498 | } |
---|
499 | break; |
---|
500 | |
---|
501 | case INSTR_MOVZX: |
---|
502 | if (dst & REGISTER) { |
---|
503 | switch (size) { |
---|
504 | case BYTE: |
---|
505 | p->data &= 0xFFULL; |
---|
506 | break; |
---|
507 | |
---|
508 | case WORD: |
---|
509 | p->data &= 0xFFFFULL; |
---|
510 | break; |
---|
511 | |
---|
512 | case LONG: |
---|
513 | p->data &= 0xFFFFFFFFULL; |
---|
514 | break; |
---|
515 | |
---|
516 | default: |
---|
517 | printk("Impossible source operand size of movzx instr: %d\n", size); |
---|
518 | domain_crash_synchronous(); |
---|
519 | } |
---|
520 | index = operand_index(dst); |
---|
521 | set_reg_value(operand_size(dst), index, 0, regs, p->data); |
---|
522 | } |
---|
523 | break; |
---|
524 | |
---|
525 | case INSTR_MOVSX: |
---|
526 | if (dst & REGISTER) { |
---|
527 | switch (size) { |
---|
528 | case BYTE: |
---|
529 | p->data &= 0xFFULL; |
---|
530 | if ( p->data & 0x80ULL ) |
---|
531 | p->data |= 0xFFFFFFFFFFFFFF00ULL; |
---|
532 | break; |
---|
533 | |
---|
534 | case WORD: |
---|
535 | p->data &= 0xFFFFULL; |
---|
536 | if ( p->data & 0x8000ULL ) |
---|
537 | p->data |= 0xFFFFFFFFFFFF0000ULL; |
---|
538 | break; |
---|
539 | |
---|
540 | case LONG: |
---|
541 | p->data &= 0xFFFFFFFFULL; |
---|
542 | if ( p->data & 0x80000000ULL ) |
---|
543 | p->data |= 0xFFFFFFFF00000000ULL; |
---|
544 | break; |
---|
545 | |
---|
546 | default: |
---|
547 | printk("Impossible source operand size of movsx instr: %d\n", size); |
---|
548 | domain_crash_synchronous(); |
---|
549 | } |
---|
550 | index = operand_index(dst); |
---|
551 | set_reg_value(operand_size(dst), index, 0, regs, p->data); |
---|
552 | } |
---|
553 | break; |
---|
554 | |
---|
555 | case INSTR_MOVS: |
---|
556 | sign = p->df ? -1 : 1; |
---|
557 | |
---|
558 | if (mmio_opp->flags & REPZ) |
---|
559 | regs->ecx -= p->count; |
---|
560 | |
---|
561 | if ((mmio_opp->flags & OVERLAP) && p->dir == IOREQ_READ) { |
---|
562 | unsigned long addr = mmio_opp->addr; |
---|
563 | |
---|
564 | if (hvm_paging_enabled(current)) |
---|
565 | { |
---|
566 | int rv = hvm_copy_to_guest_virt(addr, &p->data, p->size); |
---|
567 | if ( rv != 0 ) |
---|
568 | { |
---|
569 | /* Failed on the page-spanning copy. Inject PF into |
---|
570 | * the guest for the address where we failed. */ |
---|
571 | addr += p->size - rv; |
---|
572 | gdprintk(XENLOG_DEBUG, "Pagefault writing non-io side of " |
---|
573 | "a page-spanning MMIO: va=%#lx\n", addr); |
---|
574 | hvm_inject_exception(TRAP_page_fault, |
---|
575 | PFEC_write_access, addr); |
---|
576 | return; |
---|
577 | } |
---|
578 | } |
---|
579 | else |
---|
580 | (void)hvm_copy_to_guest_phys(addr, &p->data, p->size); |
---|
581 | } |
---|
582 | |
---|
583 | regs->esi += sign * p->count * p->size; |
---|
584 | regs->edi += sign * p->count * p->size; |
---|
585 | |
---|
586 | break; |
---|
587 | |
---|
588 | case INSTR_STOS: |
---|
589 | sign = p->df ? -1 : 1; |
---|
590 | regs->edi += sign * p->count * p->size; |
---|
591 | if (mmio_opp->flags & REPZ) |
---|
592 | regs->ecx -= p->count; |
---|
593 | break; |
---|
594 | |
---|
595 | case INSTR_LODS: |
---|
596 | set_reg_value(size, 0, 0, regs, p->data); |
---|
597 | sign = p->df ? -1 : 1; |
---|
598 | regs->esi += sign * p->count * p->size; |
---|
599 | if (mmio_opp->flags & REPZ) |
---|
600 | regs->ecx -= p->count; |
---|
601 | break; |
---|
602 | |
---|
603 | case INSTR_AND: |
---|
604 | if (src & REGISTER) { |
---|
605 | index = operand_index(src); |
---|
606 | value = get_reg_value(size, index, 0, regs); |
---|
607 | result = (unsigned long) p->data & value; |
---|
608 | } else if (src & IMMEDIATE) { |
---|
609 | value = mmio_opp->immediate; |
---|
610 | result = (unsigned long) p->data & value; |
---|
611 | } else if (src & MEMORY) { |
---|
612 | index = operand_index(dst); |
---|
613 | value = get_reg_value(size, index, 0, regs); |
---|
614 | result = (unsigned long) p->data & value; |
---|
615 | set_reg_value(size, index, 0, regs, result); |
---|
616 | } |
---|
617 | |
---|
618 | /* |
---|
619 | * The OF and CF flags are cleared; the SF, ZF, and PF |
---|
620 | * flags are set according to the result. The state of |
---|
621 | * the AF flag is undefined. |
---|
622 | */ |
---|
623 | regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| |
---|
624 | X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); |
---|
625 | set_eflags_ZF(size, result, regs); |
---|
626 | set_eflags_SF(size, result, regs); |
---|
627 | set_eflags_PF(size, result, regs); |
---|
628 | break; |
---|
629 | |
---|
630 | case INSTR_ADD: |
---|
631 | if (src & REGISTER) { |
---|
632 | index = operand_index(src); |
---|
633 | value = get_reg_value(size, index, 0, regs); |
---|
634 | result = (unsigned long) p->data + value; |
---|
635 | } else if (src & IMMEDIATE) { |
---|
636 | value = mmio_opp->immediate; |
---|
637 | result = (unsigned long) p->data + value; |
---|
638 | } else if (src & MEMORY) { |
---|
639 | index = operand_index(dst); |
---|
640 | value = get_reg_value(size, index, 0, regs); |
---|
641 | result = (unsigned long) p->data + value; |
---|
642 | set_reg_value(size, index, 0, regs, result); |
---|
643 | } |
---|
644 | |
---|
645 | /* |
---|
646 | * The CF, OF, SF, ZF, AF, and PF flags are set according |
---|
647 | * to the result |
---|
648 | */ |
---|
649 | regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF| |
---|
650 | X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); |
---|
651 | set_eflags_CF(size, mmio_opp->instr, result, value, |
---|
652 | (unsigned long) p->data, regs); |
---|
653 | set_eflags_OF(size, mmio_opp->instr, result, value, |
---|
654 | (unsigned long) p->data, regs); |
---|
655 | set_eflags_AF(size, result, value, (unsigned long) p->data, regs); |
---|
656 | set_eflags_ZF(size, result, regs); |
---|
657 | set_eflags_SF(size, result, regs); |
---|
658 | set_eflags_PF(size, result, regs); |
---|
659 | break; |
---|
660 | |
---|
661 | case INSTR_OR: |
---|
662 | if (src & REGISTER) { |
---|
663 | index = operand_index(src); |
---|
664 | value = get_reg_value(size, index, 0, regs); |
---|
665 | result = (unsigned long) p->data | value; |
---|
666 | } else if (src & IMMEDIATE) { |
---|
667 | value = mmio_opp->immediate; |
---|
668 | result = (unsigned long) p->data | value; |
---|
669 | } else if (src & MEMORY) { |
---|
670 | index = operand_index(dst); |
---|
671 | value = get_reg_value(size, index, 0, regs); |
---|
672 | result = (unsigned long) p->data | value; |
---|
673 | set_reg_value(size, index, 0, regs, result); |
---|
674 | } |
---|
675 | |
---|
676 | /* |
---|
677 | * The OF and CF flags are cleared; the SF, ZF, and PF |
---|
678 | * flags are set according to the result. The state of |
---|
679 | * the AF flag is undefined. |
---|
680 | */ |
---|
681 | regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| |
---|
682 | X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); |
---|
683 | set_eflags_ZF(size, result, regs); |
---|
684 | set_eflags_SF(size, result, regs); |
---|
685 | set_eflags_PF(size, result, regs); |
---|
686 | break; |
---|
687 | |
---|
688 | case INSTR_XOR: |
---|
689 | if (src & REGISTER) { |
---|
690 | index = operand_index(src); |
---|
691 | value = get_reg_value(size, index, 0, regs); |
---|
692 | result = (unsigned long) p->data ^ value; |
---|
693 | } else if (src & IMMEDIATE) { |
---|
694 | value = mmio_opp->immediate; |
---|
695 | result = (unsigned long) p->data ^ value; |
---|
696 | } else if (src & MEMORY) { |
---|
697 | index = operand_index(dst); |
---|
698 | value = get_reg_value(size, index, 0, regs); |
---|
699 | result = (unsigned long) p->data ^ value; |
---|
700 | set_reg_value(size, index, 0, regs, result); |
---|
701 | } |
---|
702 | |
---|
703 | /* |
---|
704 | * The OF and CF flags are cleared; the SF, ZF, and PF |
---|
705 | * flags are set according to the result. The state of |
---|
706 | * the AF flag is undefined. |
---|
707 | */ |
---|
708 | regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| |
---|
709 | X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); |
---|
710 | set_eflags_ZF(size, result, regs); |
---|
711 | set_eflags_SF(size, result, regs); |
---|
712 | set_eflags_PF(size, result, regs); |
---|
713 | break; |
---|
714 | |
---|
715 | case INSTR_CMP: |
---|
716 | case INSTR_SUB: |
---|
717 | if (src & REGISTER) { |
---|
718 | index = operand_index(src); |
---|
719 | value = get_reg_value(size, index, 0, regs); |
---|
720 | result = (unsigned long) p->data - value; |
---|
721 | } else if (src & IMMEDIATE) { |
---|
722 | value = mmio_opp->immediate; |
---|
723 | result = (unsigned long) p->data - value; |
---|
724 | } else if (src & MEMORY) { |
---|
725 | index = operand_index(dst); |
---|
726 | value = get_reg_value(size, index, 0, regs); |
---|
727 | result = value - (unsigned long) p->data; |
---|
728 | if ( mmio_opp->instr == INSTR_SUB ) |
---|
729 | set_reg_value(size, index, 0, regs, result); |
---|
730 | } |
---|
731 | |
---|
732 | /* |
---|
733 | * The CF, OF, SF, ZF, AF, and PF flags are set according |
---|
734 | * to the result |
---|
735 | */ |
---|
736 | regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF| |
---|
737 | X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); |
---|
738 | if ( src & (REGISTER | IMMEDIATE) ) |
---|
739 | { |
---|
740 | set_eflags_CF(size, mmio_opp->instr, result, value, |
---|
741 | (unsigned long) p->data, regs); |
---|
742 | set_eflags_OF(size, mmio_opp->instr, result, value, |
---|
743 | (unsigned long) p->data, regs); |
---|
744 | } |
---|
745 | else |
---|
746 | { |
---|
747 | set_eflags_CF(size, mmio_opp->instr, result, |
---|
748 | (unsigned long) p->data, value, regs); |
---|
749 | set_eflags_OF(size, mmio_opp->instr, result, |
---|
750 | (unsigned long) p->data, value, regs); |
---|
751 | } |
---|
752 | set_eflags_AF(size, result, value, (unsigned long) p->data, regs); |
---|
753 | set_eflags_ZF(size, result, regs); |
---|
754 | set_eflags_SF(size, result, regs); |
---|
755 | set_eflags_PF(size, result, regs); |
---|
756 | break; |
---|
757 | |
---|
758 | case INSTR_TEST: |
---|
759 | if (src & REGISTER) { |
---|
760 | index = operand_index(src); |
---|
761 | value = get_reg_value(size, index, 0, regs); |
---|
762 | } else if (src & IMMEDIATE) { |
---|
763 | value = mmio_opp->immediate; |
---|
764 | } else if (src & MEMORY) { |
---|
765 | index = operand_index(dst); |
---|
766 | value = get_reg_value(size, index, 0, regs); |
---|
767 | } |
---|
768 | result = (unsigned long) p->data & value; |
---|
769 | |
---|
770 | /* |
---|
771 | * Sets the SF, ZF, and PF status flags. CF and OF are set to 0 |
---|
772 | */ |
---|
773 | regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| |
---|
774 | X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); |
---|
775 | set_eflags_ZF(size, result, regs); |
---|
776 | set_eflags_SF(size, result, regs); |
---|
777 | set_eflags_PF(size, result, regs); |
---|
778 | break; |
---|
779 | |
---|
780 | case INSTR_BT: |
---|
781 | if ( src & REGISTER ) |
---|
782 | { |
---|
783 | index = operand_index(src); |
---|
784 | value = get_reg_value(size, index, 0, regs); |
---|
785 | } |
---|
786 | else if ( src & IMMEDIATE ) |
---|
787 | value = mmio_opp->immediate; |
---|
788 | if (p->data & (1 << (value & ((1 << 5) - 1)))) |
---|
789 | regs->eflags |= X86_EFLAGS_CF; |
---|
790 | else |
---|
791 | regs->eflags &= ~X86_EFLAGS_CF; |
---|
792 | |
---|
793 | break; |
---|
794 | |
---|
795 | case INSTR_XCHG: |
---|
796 | if (src & REGISTER) { |
---|
797 | index = operand_index(src); |
---|
798 | set_reg_value(size, index, 0, regs, p->data); |
---|
799 | } else { |
---|
800 | index = operand_index(dst); |
---|
801 | set_reg_value(size, index, 0, regs, p->data); |
---|
802 | } |
---|
803 | break; |
---|
804 | |
---|
805 | case INSTR_PUSH: |
---|
806 | mmio_opp->addr += hvm_get_segment_base(current, x86_seg_ss); |
---|
807 | { |
---|
808 | unsigned long addr = mmio_opp->addr; |
---|
809 | int rv = hvm_copy_to_guest_virt(addr, &p->data, size); |
---|
810 | if ( rv != 0 ) |
---|
811 | { |
---|
812 | addr += p->size - rv; |
---|
813 | gdprintk(XENLOG_DEBUG, "Pagefault emulating PUSH from MMIO:" |
---|
814 | " va=%#lx\n", addr); |
---|
815 | hvm_inject_exception(TRAP_page_fault, PFEC_write_access, addr); |
---|
816 | return; |
---|
817 | } |
---|
818 | } |
---|
819 | break; |
---|
820 | } |
---|
821 | } |
---|
822 | |
---|
823 | void hvm_io_assist(void) |
---|
824 | { |
---|
825 | vcpu_iodata_t *vio; |
---|
826 | ioreq_t *p; |
---|
827 | struct cpu_user_regs *regs; |
---|
828 | struct hvm_io_op *io_opp; |
---|
829 | unsigned long gmfn; |
---|
830 | struct vcpu *v = current; |
---|
831 | struct domain *d = v->domain; |
---|
832 | |
---|
833 | io_opp = &v->arch.hvm_vcpu.io_op; |
---|
834 | regs = &io_opp->io_context; |
---|
835 | vio = get_ioreq(v); |
---|
836 | |
---|
837 | p = &vio->vp_ioreq; |
---|
838 | if ( p->state != STATE_IORESP_READY ) |
---|
839 | { |
---|
840 | gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state); |
---|
841 | domain_crash_synchronous(); |
---|
842 | } |
---|
843 | |
---|
844 | rmb(); /* see IORESP_READY /then/ read contents of ioreq */ |
---|
845 | |
---|
846 | p->state = STATE_IOREQ_NONE; |
---|
847 | |
---|
848 | switch ( p->type ) |
---|
849 | { |
---|
850 | case IOREQ_TYPE_INVALIDATE: |
---|
851 | goto out; |
---|
852 | case IOREQ_TYPE_PIO: |
---|
853 | hvm_pio_assist(regs, p, io_opp); |
---|
854 | break; |
---|
855 | default: |
---|
856 | hvm_mmio_assist(regs, p, io_opp); |
---|
857 | break; |
---|
858 | } |
---|
859 | |
---|
860 | /* Copy register changes back into current guest state. */ |
---|
861 | hvm_load_cpu_guest_regs(v, regs); |
---|
862 | memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES); |
---|
863 | |
---|
864 | /* Has memory been dirtied? */ |
---|
865 | if ( (p->dir == IOREQ_READ) && p->data_is_ptr ) |
---|
866 | { |
---|
867 | gmfn = get_mfn_from_gpfn(paging_gva_to_gfn(v, p->data)); |
---|
868 | mark_dirty(d, gmfn); |
---|
869 | } |
---|
870 | |
---|
871 | out: |
---|
872 | vcpu_end_shutdown_deferral(v); |
---|
873 | } |
---|
874 | |
---|
875 | /* |
---|
876 | * Local variables: |
---|
877 | * mode: C |
---|
878 | * c-set-style: "BSD" |
---|
879 | * c-basic-offset: 4 |
---|
880 | * tab-width: 4 |
---|
881 | * indent-tabs-mode: nil |
---|
882 | * End: |
---|
883 | */ |
---|