1 | /** @file
|
---|
2 | *
|
---|
3 | * IOM - Input / Output Monitor - Guest Context.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006 InnoTek Systemberatung GmbH
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
12 | * General Public License as published by the Free Software Foundation,
|
---|
13 | * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
|
---|
14 | * distribution. VirtualBox OSE is distributed in the hope that it will
|
---|
15 | * be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
16 | *
|
---|
17 | * If you received this file as part of a commercial VirtualBox
|
---|
18 | * distribution, then only the terms of your commercial VirtualBox
|
---|
19 | * license agreement apply instead of the previous paragraph.
|
---|
20 | */
|
---|
21 |
|
---|
22 |
|
---|
23 | /*******************************************************************************
|
---|
24 | * Header Files *
|
---|
25 | *******************************************************************************/
|
---|
26 | #define LOG_GROUP LOG_GROUP_IOM
|
---|
27 | #include <VBox/iom.h>
|
---|
28 | #include <VBox/cpum.h>
|
---|
29 | #include <VBox/pgm.h>
|
---|
30 | #include <VBox/selm.h>
|
---|
31 | #include <VBox/mm.h>
|
---|
32 | #include <VBox/em.h>
|
---|
33 | #include <VBox/pgm.h>
|
---|
34 | #include <VBox/trpm.h>
|
---|
35 | #include "IOMInternal.h"
|
---|
36 | #include <VBox/vm.h>
|
---|
37 |
|
---|
38 | #include <VBox/dis.h>
|
---|
39 | #include <VBox/disopcode.h>
|
---|
40 | #include <VBox/param.h>
|
---|
41 | #include <VBox/err.h>
|
---|
42 | #include <iprt/assert.h>
|
---|
43 | #include <VBox/log.h>
|
---|
44 | #include <iprt/asm.h>
|
---|
45 | #include <iprt/string.h>
|
---|
46 |
|
---|
47 |
|
---|
48 | /** @def IOMGC_MOVS_SUPPORT
|
---|
49 | * Define IOMGC_MOVS_SUPPORT for movsb/w/d support in GC.
|
---|
50 | */
|
---|
51 | #define IOMGC_MOVS_SUPPORT
|
---|
52 |
|
---|
53 |
|
---|
54 | /*******************************************************************************
|
---|
55 | * Internal Functions *
|
---|
56 | *******************************************************************************/
|
---|
57 | #if 0
|
---|
58 | static bool iomGCCalcParamEA(PDISCPUSTATE pCpu, POP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, void **ppAddr);
|
---|
59 | #endif
|
---|
60 | static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam);
|
---|
61 | static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize);
|
---|
62 | static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t u32Data);
|
---|
63 |
|
---|
64 |
|
---|
65 | /*******************************************************************************
|
---|
66 | * Global Variables *
|
---|
67 | *******************************************************************************/
|
---|
68 | /**
|
---|
69 | * Array for accessing 32-bit general registers in VMMREGFRAME structure
|
---|
70 | * by register's index from disasm.
|
---|
71 | */
|
---|
72 | static unsigned g_aReg32Index[] =
|
---|
73 | {
|
---|
74 | RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_EAX */
|
---|
75 | RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_ECX */
|
---|
76 | RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_EDX */
|
---|
77 | RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_EBX */
|
---|
78 | RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_ESP */
|
---|
79 | RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_EBP */
|
---|
80 | RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_ESI */
|
---|
81 | RT_OFFSETOF(CPUMCTXCORE, edi) /* USE_REG_EDI */
|
---|
82 | };
|
---|
83 |
|
---|
84 | /**
|
---|
85 | * Macro for accessing 32-bit general purpose registers in CPUMCTXCORE structure.
|
---|
86 | */
|
---|
87 | #define ACCESS_REG32(p, idx) (*((uint32_t *)((char *)(p) + g_aReg32Index[idx])))
|
---|
88 |
|
---|
89 | /**
|
---|
90 | * Array for accessing 16-bit general registers in CPUMCTXCORE structure
|
---|
91 | * by register's index from disasm.
|
---|
92 | */
|
---|
93 | static unsigned g_aReg16Index[] =
|
---|
94 | {
|
---|
95 | RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AX */
|
---|
96 | RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CX */
|
---|
97 | RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DX */
|
---|
98 | RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BX */
|
---|
99 | RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_SP */
|
---|
100 | RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_BP */
|
---|
101 | RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_SI */
|
---|
102 | RT_OFFSETOF(CPUMCTXCORE, edi) /* USE_REG_DI */
|
---|
103 | };
|
---|
104 |
|
---|
105 | /**
|
---|
106 | * Macro for accessing 16-bit general purpose registers in CPUMCTXCORE structure.
|
---|
107 | */
|
---|
108 | #define ACCESS_REG16(p, idx) (*((uint16_t *)((char *)(p) + g_aReg16Index[idx])))
|
---|
109 |
|
---|
110 | /**
|
---|
111 | * Array for accessing 8-bit general registers in CPUMCTXCORE structure
|
---|
112 | * by register's index from disasm.
|
---|
113 | */
|
---|
114 | static unsigned g_aReg8Index[] =
|
---|
115 | {
|
---|
116 | RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AL */
|
---|
117 | RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CL */
|
---|
118 | RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DL */
|
---|
119 | RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BL */
|
---|
120 | RT_OFFSETOF(CPUMCTXCORE, eax) + 1, /* USE_REG_AH */
|
---|
121 | RT_OFFSETOF(CPUMCTXCORE, ecx) + 1, /* USE_REG_CH */
|
---|
122 | RT_OFFSETOF(CPUMCTXCORE, edx) + 1, /* USE_REG_DH */
|
---|
123 | RT_OFFSETOF(CPUMCTXCORE, ebx) + 1 /* USE_REG_BH */
|
---|
124 | };
|
---|
125 |
|
---|
126 | /**
|
---|
127 | * Macro for accessing 8-bit general purpose registers in CPUMCTXCORE structure.
|
---|
128 | */
|
---|
129 | #define ACCESS_REG8(p, idx) (*((uint8_t *)((char *)(p) + g_aReg8Index[idx])))
|
---|
130 |
|
---|
131 | /**
|
---|
132 | * Array for accessing segment registers in CPUMCTXCORE structure
|
---|
133 | * by register's index from disasm.
|
---|
134 | */
|
---|
135 | static unsigned g_aRegSegIndex[] =
|
---|
136 | {
|
---|
137 | RT_OFFSETOF(CPUMCTXCORE, es), /* USE_REG_ES */
|
---|
138 | RT_OFFSETOF(CPUMCTXCORE, cs), /* USE_REG_CS */
|
---|
139 | RT_OFFSETOF(CPUMCTXCORE, ss), /* USE_REG_SS */
|
---|
140 | RT_OFFSETOF(CPUMCTXCORE, ds), /* USE_REG_DS */
|
---|
141 | RT_OFFSETOF(CPUMCTXCORE, fs), /* USE_REG_FS */
|
---|
142 | RT_OFFSETOF(CPUMCTXCORE, gs) /* USE_REG_GS */
|
---|
143 | };
|
---|
144 |
|
---|
145 | /**
|
---|
146 | * Macro for accessing segment registers in CPUMCTXCORE structure.
|
---|
147 | */
|
---|
148 | #define ACCESS_REGSEG(p, idx) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])))
|
---|
149 |
|
---|
150 | /**
|
---|
151 | * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
|
---|
152 | */
|
---|
153 | static const unsigned g_aSize2Shift[] =
|
---|
154 | {
|
---|
155 | ~0, /* 0 - invalid */
|
---|
156 | 0, /* *1 == 2^0 */
|
---|
157 | 1, /* *2 == 2^1 */
|
---|
158 | ~0, /* 3 - invalid */
|
---|
159 | 2, /* *4 == 2^2 */
|
---|
160 | ~0, /* 5 - invalid */
|
---|
161 | ~0, /* 6 - invalid */
|
---|
162 | ~0, /* 7 - invalid */
|
---|
163 | 3 /* *8 == 2^3 */
|
---|
164 | };
|
---|
165 |
|
---|
166 | /**
|
---|
167 | * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
|
---|
168 | */
|
---|
169 | #define SIZE2SHIFT(cb) (g_aSize2Shift[cb])
|
---|
170 |
|
---|
171 |
|
---|
172 | #if 0
|
---|
173 | /**
|
---|
174 | * Calculates effective address (offset from current segment register) for
|
---|
175 | * instruction parameter, i.e. [eax + esi*4 + 1234h] -> virtual address.
|
---|
176 | *
|
---|
177 | * @returns true on success.
|
---|
178 | * @param pCpu Pointer to current disassembler context.
|
---|
179 | * @param pParam Pointer to parameter of instruction to calc EA.
|
---|
180 | * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
|
---|
181 | * @param ppAddr Where to store result address.
|
---|
182 | */
|
---|
183 | static bool iomGCCalcParamEA(PDISCPUSTATE pCpu, POP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, void **ppAddr)
|
---|
184 | {
|
---|
185 | uint8_t *pAddr = 0;
|
---|
186 |
|
---|
187 | if (pCpu->addrmode == CPUMODE_32BIT)
|
---|
188 | {
|
---|
189 | /* 32-bit addressing. */
|
---|
190 | if (pParam->flags & USE_BASE)
|
---|
191 | pAddr += ACCESS_REG32(pRegFrame, pParam->base.reg_gen32);
|
---|
192 | if (pParam->flags & USE_INDEX)
|
---|
193 | {
|
---|
194 | unsigned i = ACCESS_REG32(pRegFrame, pParam->index.reg_gen);
|
---|
195 | if (pParam->flags & USE_SCALE)
|
---|
196 | i *= pParam->scale;
|
---|
197 | pAddr += i;
|
---|
198 | }
|
---|
199 | if (pParam->flags & USE_DISPLACEMENT8)
|
---|
200 | pAddr += pParam->disp8;
|
---|
201 | else
|
---|
202 | if (pParam->flags & USE_DISPLACEMENT16)
|
---|
203 | pAddr += pParam->disp16;
|
---|
204 | else
|
---|
205 | if (pParam->flags & USE_DISPLACEMENT32)
|
---|
206 | pAddr += pParam->disp32;
|
---|
207 |
|
---|
208 | if (pParam->flags & (USE_BASE | USE_INDEX | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
|
---|
209 | {
|
---|
210 | /* EA present in parameter. */
|
---|
211 | *ppAddr = pAddr;
|
---|
212 | return true;
|
---|
213 | }
|
---|
214 | }
|
---|
215 | else
|
---|
216 | {
|
---|
217 | /* 16-bit addressing. */
|
---|
218 | if (pParam->flags & USE_BASE)
|
---|
219 | pAddr += ACCESS_REG16(pRegFrame, pParam->base.reg_gen16);
|
---|
220 | if (pParam->flags & USE_INDEX)
|
---|
221 | pAddr += ACCESS_REG16(pRegFrame, pParam->index.reg_gen);
|
---|
222 | if (pParam->flags & USE_DISPLACEMENT8)
|
---|
223 | pAddr += pParam->disp8;
|
---|
224 | else
|
---|
225 | if (pParam->flags & USE_DISPLACEMENT16)
|
---|
226 | pAddr += pParam->disp16;
|
---|
227 |
|
---|
228 | if (pParam->flags & (USE_BASE | USE_INDEX | USE_DISPLACEMENT8 | USE_DISPLACEMENT16))
|
---|
229 | {
|
---|
230 | /* EA present in parameter. */
|
---|
231 | *ppAddr = pAddr;
|
---|
232 | return true;
|
---|
233 | }
|
---|
234 | }
|
---|
235 |
|
---|
236 | /* Error exit. */
|
---|
237 | return false;
|
---|
238 | }
|
---|
239 | #endif
|
---|
240 |
|
---|
241 | /**
|
---|
242 | * Calculates the size of register parameter.
|
---|
243 | *
|
---|
244 | * @returns 1, 2, 4 on success.
|
---|
245 | * @returns 0 if non-register parameter.
|
---|
246 | * @param pCpu Pointer to current disassembler context.
|
---|
247 | * @param pParam Pointer to parameter of instruction to proccess.
|
---|
248 | */
|
---|
249 | static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam)
|
---|
250 | {
|
---|
251 | if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE16_SX8 | USE_IMMEDIATE32_SX8))
|
---|
252 | return 0;
|
---|
253 |
|
---|
254 | if (pParam->flags & USE_REG_GEN32)
|
---|
255 | return 4;
|
---|
256 |
|
---|
257 | if (pParam->flags & USE_REG_GEN16)
|
---|
258 | return 2;
|
---|
259 |
|
---|
260 | if (pParam->flags & USE_REG_GEN8)
|
---|
261 | return 1;
|
---|
262 |
|
---|
263 | if (pParam->flags & USE_REG_SEG)
|
---|
264 | return 2;
|
---|
265 | return 0;
|
---|
266 | }
|
---|
267 |
|
---|
268 | /**
|
---|
269 | * Returns the contents of register or immediate data of instruction's parameter.
|
---|
270 | *
|
---|
271 | * @returns true on success.
|
---|
272 | *
|
---|
273 | * @param pCpu Pointer to current disassembler context.
|
---|
274 | * @param pParam Pointer to parameter of instruction to proccess.
|
---|
275 | * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
|
---|
276 | * @param pu32Data Where to store retrieved data.
|
---|
277 | * @param pcbSize Where to store the size of data (1, 2, 4).
|
---|
278 | */
|
---|
279 | static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize)
|
---|
280 | {
|
---|
281 | if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
|
---|
282 | {
|
---|
283 | *pcbSize = 0;
|
---|
284 | *pu32Data = 0;
|
---|
285 | return false;
|
---|
286 | }
|
---|
287 |
|
---|
288 | if (pParam->flags & USE_REG_GEN32)
|
---|
289 | {
|
---|
290 | *pcbSize = 4;
|
---|
291 | *pu32Data = ACCESS_REG32(pRegFrame, pParam->base.reg_gen32);
|
---|
292 | return true;
|
---|
293 | }
|
---|
294 |
|
---|
295 | if (pParam->flags & USE_REG_GEN16)
|
---|
296 | {
|
---|
297 | *pcbSize = 2;
|
---|
298 | *pu32Data = ACCESS_REG16(pRegFrame, pParam->base.reg_gen16);
|
---|
299 | return true;
|
---|
300 | }
|
---|
301 |
|
---|
302 | if (pParam->flags & USE_REG_GEN8)
|
---|
303 | {
|
---|
304 | *pcbSize = 1;
|
---|
305 | *pu32Data = ACCESS_REG8(pRegFrame, pParam->base.reg_gen8);
|
---|
306 | return true;
|
---|
307 | }
|
---|
308 |
|
---|
309 | if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_SX8))
|
---|
310 | {
|
---|
311 | *pcbSize = 4;
|
---|
312 | *pu32Data = (uint32_t)pParam->parval;
|
---|
313 | return true;
|
---|
314 | }
|
---|
315 |
|
---|
316 | if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_SX8))
|
---|
317 | {
|
---|
318 | *pcbSize = 2;
|
---|
319 | *pu32Data = (uint16_t)pParam->parval;
|
---|
320 | return true;
|
---|
321 | }
|
---|
322 |
|
---|
323 | if (pParam->flags & USE_IMMEDIATE8)
|
---|
324 | {
|
---|
325 | *pcbSize = 1;
|
---|
326 | *pu32Data = (uint8_t)pParam->parval;
|
---|
327 | return true;
|
---|
328 | }
|
---|
329 |
|
---|
330 | if (pParam->flags & USE_REG_SEG)
|
---|
331 | {
|
---|
332 | *pcbSize = 2;
|
---|
333 | *pu32Data = ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg);
|
---|
334 | return true;
|
---|
335 | } /* Else - error. */
|
---|
336 |
|
---|
337 | *pcbSize = 0;
|
---|
338 | *pu32Data = 0;
|
---|
339 | return false;
|
---|
340 | }
|
---|
341 |
|
---|
342 |
|
---|
343 | /**
|
---|
344 | * Saves data to 8/16/32 general purpose or segment register defined by
|
---|
345 | * instruction's parameter.
|
---|
346 | *
|
---|
347 | * @returns true on success.
|
---|
348 | * @param pCpu Pointer to current disassembler context.
|
---|
349 | * @param pParam Pointer to parameter of instruction to proccess.
|
---|
350 | * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
|
---|
351 | * @param u32Data 8/16/32 bit data to store.
|
---|
352 | */
|
---|
353 | static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, unsigned u32Data)
|
---|
354 | {
|
---|
355 | if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8 | USE_IMMEDIATE16_SX8))
|
---|
356 | {
|
---|
357 | return false;
|
---|
358 | }
|
---|
359 |
|
---|
360 | if (pParam->flags & USE_REG_GEN32)
|
---|
361 | {
|
---|
362 | ACCESS_REG32(pRegFrame, pParam->base.reg_gen32) = u32Data;
|
---|
363 | return true;
|
---|
364 | }
|
---|
365 |
|
---|
366 | if (pParam->flags & USE_REG_GEN16)
|
---|
367 | {
|
---|
368 | ACCESS_REG16(pRegFrame, pParam->base.reg_gen16) = (uint16_t)u32Data;
|
---|
369 | return true;
|
---|
370 | }
|
---|
371 |
|
---|
372 | if (pParam->flags & USE_REG_GEN8)
|
---|
373 | {
|
---|
374 | ACCESS_REG8(pRegFrame, pParam->base.reg_gen8) = (uint8_t)u32Data;
|
---|
375 | return true;
|
---|
376 | }
|
---|
377 |
|
---|
378 | if (pParam->flags & USE_REG_SEG)
|
---|
379 | {
|
---|
380 | ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg) = (uint16_t)u32Data;
|
---|
381 | return true;
|
---|
382 | }
|
---|
383 |
|
---|
384 | /* Else - error. */
|
---|
385 | return false;
|
---|
386 | }
|
---|
387 |
|
---|
388 |
|
---|
389 | /*
|
---|
390 | * Internal - statistics only.
|
---|
391 | */
|
---|
392 | inline void iomGCMMIOStatLength(PVM pVM, unsigned cb)
|
---|
393 | {
|
---|
394 | #ifdef VBOX_WITH_STATISTICS
|
---|
395 | switch (cb)
|
---|
396 | {
|
---|
397 | case 1:
|
---|
398 | STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO1Byte);
|
---|
399 | break;
|
---|
400 | case 2:
|
---|
401 | STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO2Bytes);
|
---|
402 | break;
|
---|
403 | case 4:
|
---|
404 | STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO4Bytes);
|
---|
405 | break;
|
---|
406 | default:
|
---|
407 | /* No way. */
|
---|
408 | AssertMsgFailed(("Invalid data length %d\n", cb));
|
---|
409 | break;
|
---|
410 | }
|
---|
411 | #else
|
---|
412 | NOREF(pVM); NOREF(cb);
|
---|
413 | #endif
|
---|
414 | }
|
---|
415 |
|
---|
416 |
|
---|
417 | /**
|
---|
418 | * IN <AL|AX|EAX>, <DX|imm16>
|
---|
419 | *
|
---|
420 | * @returns VBox status code.
|
---|
421 | *
|
---|
422 | * @param pVM The virtual machine (GC pointer ofcourse).
|
---|
423 | * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
|
---|
424 | * @param pCpu Disassembler CPU state.
|
---|
425 | */
|
---|
426 | IOMDECL(int) IOMInterpretIN(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
|
---|
427 | {
|
---|
428 | #ifdef VBOX_WITH_STATISTICS
|
---|
429 | STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIn);
|
---|
430 | #endif
|
---|
431 |
|
---|
432 | /*
|
---|
433 | * Get port number from second parameter.
|
---|
434 | * And get the register size from the first parameter.
|
---|
435 | */
|
---|
436 | uint32_t uPort = 0;
|
---|
437 | unsigned cbSize = 0;
|
---|
438 | bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uPort, &cbSize);
|
---|
439 | AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
|
---|
440 |
|
---|
441 | cbSize = iomGCGetRegSize(pCpu, &pCpu->param1);
|
---|
442 | Assert(cbSize > 0);
|
---|
443 | int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
|
---|
444 | if (rc == VINF_SUCCESS)
|
---|
445 | {
|
---|
446 | /*
|
---|
447 | * Attemp to read the port.
|
---|
448 | */
|
---|
449 | uint32_t u32Data = ~0U;
|
---|
450 | rc = IOMIOPortRead(pVM, uPort, &u32Data, cbSize);
|
---|
451 | if (rc == VINF_SUCCESS)
|
---|
452 | {
|
---|
453 | /*
|
---|
454 | * Store the result in the AL|AX|EAX register.
|
---|
455 | */
|
---|
456 | fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data);
|
---|
457 | AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
|
---|
458 | }
|
---|
459 | }
|
---|
460 | return rc;
|
---|
461 | }
|
---|
462 |
|
---|
463 |
|
---|
464 | /**
|
---|
465 | * OUT <DX|imm16>, <AL|AX|EAX>
|
---|
466 | *
|
---|
467 | * @returns VBox status code.
|
---|
468 | *
|
---|
469 | * @param pVM The virtual machine (GC pointer ofcourse).
|
---|
470 | * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
|
---|
471 | * @param pCpu Disassembler CPU state.
|
---|
472 | */
|
---|
473 | IOMDECL(int) IOMInterpretOUT(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
|
---|
474 | {
|
---|
475 | #ifdef VBOX_WITH_STATISTICS
|
---|
476 | STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOut);
|
---|
477 | #endif
|
---|
478 |
|
---|
479 | /*
|
---|
480 | * Get port number from first parameter.
|
---|
481 | * And get the register size and value from the second parameter.
|
---|
482 | */
|
---|
483 | uint32_t uPort = 0;
|
---|
484 | unsigned cbSize = 0;
|
---|
485 | bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
|
---|
486 | AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
|
---|
487 |
|
---|
488 | int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
|
---|
489 | if (rc == VINF_SUCCESS)
|
---|
490 | {
|
---|
491 | uint32_t u32Data = 0;
|
---|
492 | fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u32Data, &cbSize);
|
---|
493 | AssertMsg(fRc, ("Failed to get reg value!\n")); NOREF(fRc);
|
---|
494 |
|
---|
495 | /*
|
---|
496 | * Attemp to write to the port.
|
---|
497 | */
|
---|
498 | rc = IOMIOPortWrite(pVM, uPort, u32Data, cbSize);
|
---|
499 | }
|
---|
500 | return rc;
|
---|
501 | }
|
---|
502 |
|
---|
503 |
|
---|
504 | /**
|
---|
505 | * [REP*] INSB/INSW/INSD
|
---|
506 | * ES:EDI,DX[,ECX]
|
---|
507 | *
|
---|
508 | * @returns VBox status code.
|
---|
509 | *
|
---|
510 | * @param pVM The virtual machine (GC pointer ofcourse).
|
---|
511 | * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
|
---|
512 | * @param pCpu Disassembler CPU state.
|
---|
513 | */
|
---|
514 | IOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
|
---|
515 | {
|
---|
516 | #ifdef VBOX_WITH_STATISTICS
|
---|
517 | STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);
|
---|
518 | #endif
|
---|
519 |
|
---|
520 | /*
|
---|
521 | * We do not support REPNE, 16-bit addressing or decrementing destination
|
---|
522 | * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
|
---|
523 | */
|
---|
524 | if ( pCpu->prefix & PREFIX_REPNE
|
---|
525 | || (pCpu->addrmode != CPUMODE_32BIT)
|
---|
526 | || pRegFrame->eflags.Bits.u1DF)
|
---|
527 | return VINF_IOM_HC_IOPORT_READ;
|
---|
528 |
|
---|
529 | /*
|
---|
530 | * Get port number directly from the register (no need to bother the
|
---|
531 | * disassembler). And get the I/O register size from the opcode / prefix.
|
---|
532 | */
|
---|
533 | uint32_t uPort = pRegFrame->edx & 0xffff;
|
---|
534 | unsigned cbSize = 0;
|
---|
535 | if (pCpu->pCurInstr->opcode == OP_INSB)
|
---|
536 | cbSize = 1;
|
---|
537 | else
|
---|
538 | cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
|
---|
539 |
|
---|
540 | int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
|
---|
541 | if (rc == VINF_SUCCESS)
|
---|
542 | {
|
---|
543 | /*
|
---|
544 | * Get bytes/words/dwords count to transfer.
|
---|
545 | */
|
---|
546 | RTGCUINTREG cTransfers = 1;
|
---|
547 | if (pCpu->prefix & PREFIX_REP)
|
---|
548 | {
|
---|
549 | cTransfers = pRegFrame->ecx;
|
---|
550 | if (!cTransfers)
|
---|
551 | return VINF_SUCCESS;
|
---|
552 | }
|
---|
553 |
|
---|
554 | /* Convert destination address es:edi. */
|
---|
555 | RTGCPTR GCPtrDst;
|
---|
556 | rc = SELMToFlatEx(pVM, pRegFrame->es, (RTGCPTR)pRegFrame->edi,
|
---|
557 | SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
|
---|
558 | &GCPtrDst, NULL);
|
---|
559 | if (VBOX_FAILURE(rc))
|
---|
560 | {
|
---|
561 | Log(("INS destination address conversion failed -> fallback, rc=%d\n", rc));
|
---|
562 | return VINF_IOM_HC_IOPORT_READ;
|
---|
563 | }
|
---|
564 |
|
---|
565 | /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
|
---|
566 | rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrDst, cTransfers * cbSize,
|
---|
567 | X86_PTE_RW | (((pRegFrame->ss & X86_SEL_RPL) == 3) ? X86_PTE_US : 0));
|
---|
568 | if (rc != VINF_SUCCESS)
|
---|
569 | {
|
---|
570 | Log(("INS will generate a trap -> fallback, rc=%d\n", rc));
|
---|
571 | return VINF_IOM_HC_IOPORT_READ;
|
---|
572 | }
|
---|
573 |
|
---|
574 | Log(("IOMGC: rep ins%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
|
---|
575 | MMGCRamRegisterTrapHandler(pVM);
|
---|
576 |
|
---|
577 | /* If the device supports string transfers, ask it to do as
|
---|
578 | * much as it wants. The rest is done with single-word transfers. */
|
---|
579 | const RTGCUINTREG cTransfersOrg = cTransfers;
|
---|
580 | rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbSize);
|
---|
581 | AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
|
---|
582 | pRegFrame->edi += (cTransfersOrg - cTransfers) * cbSize;
|
---|
583 |
|
---|
584 | while (cTransfers && rc == VINF_SUCCESS)
|
---|
585 | {
|
---|
586 | uint32_t u32Value;
|
---|
587 | rc = IOMIOPortRead(pVM, uPort, &u32Value, cbSize);
|
---|
588 | if (rc == VINF_IOM_HC_IOPORT_READ || VBOX_FAILURE(rc))
|
---|
589 | break;
|
---|
590 | int rc2 = MMGCRamWriteNoTrapHandler(GCPtrDst, &u32Value, cbSize);
|
---|
591 | Assert(rc2 == VINF_SUCCESS); NOREF(rc2);
|
---|
592 | GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbSize);
|
---|
593 | pRegFrame->edi += cbSize;
|
---|
594 | cTransfers--;
|
---|
595 | }
|
---|
596 | MMGCRamDeregisterTrapHandler(pVM);
|
---|
597 |
|
---|
598 | /* Update ecx on exit. */
|
---|
599 | if (pCpu->prefix & PREFIX_REP)
|
---|
600 | pRegFrame->ecx = cTransfers;
|
---|
601 | }
|
---|
602 | return rc;
|
---|
603 | }
|
---|
604 |
|
---|
605 |
|
---|
606 | /**
|
---|
607 | * [REP*] OUTSB/OUTSW/OUTSD
|
---|
608 | * DS:ESI,DX[,ECX]
|
---|
609 | *
|
---|
610 | * @returns VBox status code.
|
---|
611 | *
|
---|
612 | * @param pVM The virtual machine (GC pointer ofcourse).
|
---|
613 | * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
|
---|
614 | * @param pCpu Disassembler CPU state.
|
---|
615 | */
|
---|
616 | IOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
|
---|
617 | {
|
---|
618 | #ifdef VBOX_WITH_STATISTICS
|
---|
619 | STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);
|
---|
620 | #endif
|
---|
621 |
|
---|
622 | /*
|
---|
623 | * We do not support segment prefixes, REPNE, 16-bit addressing or
|
---|
624 | * decrementing source pointer.
|
---|
625 | */
|
---|
626 | if ( pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE)
|
---|
627 | || (pCpu->addrmode != CPUMODE_32BIT)
|
---|
628 | || pRegFrame->eflags.Bits.u1DF)
|
---|
629 | return VINF_IOM_HC_IOPORT_WRITE;
|
---|
630 |
|
---|
631 | /*
|
---|
632 | * Get port number from the first parameter.
|
---|
633 | * And get the I/O register size from the opcode / prefix.
|
---|
634 | */
|
---|
635 | uint32_t uPort = 0;
|
---|
636 | unsigned cbSize = 0;
|
---|
637 | bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
|
---|
638 | AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
|
---|
639 | if (pCpu->pCurInstr->opcode == OP_OUTSB)
|
---|
640 | cbSize = 1;
|
---|
641 | else
|
---|
642 | cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
|
---|
643 |
|
---|
644 | int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
|
---|
645 | if (rc == VINF_SUCCESS)
|
---|
646 | {
|
---|
647 | /*
|
---|
648 | * Get bytes/words/dwords count to transfer.
|
---|
649 | */
|
---|
650 | RTGCUINTREG cTransfers = 1;
|
---|
651 | if (pCpu->prefix & PREFIX_REP)
|
---|
652 | {
|
---|
653 | cTransfers = pRegFrame->ecx;
|
---|
654 | if (!cTransfers)
|
---|
655 | return VINF_SUCCESS;
|
---|
656 | }
|
---|
657 |
|
---|
658 | /* Convert source address ds:esi. */
|
---|
659 | RTGCPTR GCPtrSrc;
|
---|
660 | rc = SELMToFlatEx(pVM, pRegFrame->ds, (RTGCPTR)pRegFrame->esi,
|
---|
661 | SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
|
---|
662 | &GCPtrSrc, NULL);
|
---|
663 | if (VBOX_FAILURE(rc))
|
---|
664 | {
|
---|
665 | Log(("OUTS source address conversion failed -> fallback, rc=%d\n", rc));
|
---|
666 | return VINF_IOM_HC_IOPORT_WRITE;
|
---|
667 | }
|
---|
668 |
|
---|
669 | /* Access verification first; we currently can't recover properly from traps inside this instruction */
|
---|
670 | rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbSize,
|
---|
671 | ((pRegFrame->ss & X86_SEL_RPL) == 3) ? X86_PTE_US : 0);
|
---|
672 | if (rc != VINF_SUCCESS)
|
---|
673 | {
|
---|
674 | Log(("OUTS will generate a trap -> fallback, rc=%d\n", rc));
|
---|
675 | return VINF_IOM_HC_IOPORT_WRITE;
|
---|
676 | }
|
---|
677 |
|
---|
678 | Log(("IOMGC: rep outs%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
|
---|
679 | MMGCRamRegisterTrapHandler(pVM);
|
---|
680 |
|
---|
681 | /*
|
---|
682 | * If the device supports string transfers, ask it to do as
|
---|
683 | * much as it wants. The rest is done with single-word transfers.
|
---|
684 | */
|
---|
685 | const RTGCUINTREG cTransfersOrg = cTransfers;
|
---|
686 | rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbSize);
|
---|
687 | AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
|
---|
688 | pRegFrame->esi += (cTransfersOrg - cTransfers) * cbSize;
|
---|
689 |
|
---|
690 | while (cTransfers && rc == VINF_SUCCESS)
|
---|
691 | {
|
---|
692 | uint32_t u32Value;
|
---|
693 | rc = MMGCRamReadNoTrapHandler(&u32Value, GCPtrSrc, cbSize);
|
---|
694 | if (rc != VINF_SUCCESS)
|
---|
695 | break;
|
---|
696 | rc = IOMIOPortWrite(pVM, uPort, u32Value, cbSize);
|
---|
697 | if (rc == VINF_IOM_HC_IOPORT_WRITE)
|
---|
698 | break;
|
---|
699 | GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbSize);
|
---|
700 | pRegFrame->esi += cbSize;
|
---|
701 | cTransfers--;
|
---|
702 | }
|
---|
703 |
|
---|
704 | MMGCRamDeregisterTrapHandler(pVM);
|
---|
705 |
|
---|
706 | /* Update ecx on exit. */
|
---|
707 | if (pCpu->prefix & PREFIX_REP)
|
---|
708 | pRegFrame->ecx = cTransfers;
|
---|
709 | }
|
---|
710 | return rc;
|
---|
711 | }
|
---|
712 |
|
---|
713 |
|
---|
714 | /**
|
---|
715 | * Attempts to service an IN/OUT instruction.
|
---|
716 | *
|
---|
717 | * The \#GP trap handler in GC will call this function if the opcode causing the
|
---|
718 | * trap is a in or out type instruction.
|
---|
719 | *
|
---|
720 | * @returns VBox status code.
|
---|
721 | *
|
---|
722 | * @param pVM The virtual machine (GC pointer ofcourse).
|
---|
723 | * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
|
---|
724 | * @param pCpu Disassembler CPU state.
|
---|
725 | */
|
---|
726 | IOMGCDECL(int) IOMGCIOPortHandler(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
|
---|
727 | {
|
---|
728 | switch (pCpu->pCurInstr->opcode)
|
---|
729 | {
|
---|
730 | case OP_IN:
|
---|
731 | return IOMInterpretIN(pVM, pRegFrame, pCpu);
|
---|
732 |
|
---|
733 | case OP_OUT:
|
---|
734 | return IOMInterpretOUT(pVM, pRegFrame, pCpu);
|
---|
735 |
|
---|
736 | case OP_INSB:
|
---|
737 | case OP_INSWD:
|
---|
738 | return IOMInterpretINS(pVM, pRegFrame, pCpu);
|
---|
739 |
|
---|
740 | case OP_OUTSB:
|
---|
741 | case OP_OUTSWD:
|
---|
742 | return IOMInterpretOUTS(pVM, pRegFrame, pCpu);
|
---|
743 |
|
---|
744 | /*
|
---|
745 | * The opcode wasn't know to us, freak out.
|
---|
746 | */
|
---|
747 | default:
|
---|
748 | AssertMsgFailed(("Unknown I/O port access opcode %d.\n", pCpu->pCurInstr->opcode));
|
---|
749 | return VERR_INTERNAL_ERROR;
|
---|
750 | }
|
---|
751 | }
|
---|
752 |
|
---|