VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/IOMRC.cpp@ 60847

Last change on this file since 60847 was 60847, checked in by vboxsync, 9 years ago

IOM: New way of defer RC+R0 I/O port writes, prepping for MMIO writes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.8 KB
Line 
1/* $Id: IOMRC.cpp 60847 2016-05-05 15:24:46Z vboxsync $ */
2/** @file
3 * IOM - Input / Output Monitor - Raw-Mode Context.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_IOM
23#include <VBox/vmm/iom.h>
24#include <VBox/vmm/cpum.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/vmm/selm.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/vmm/em.h>
29#include <VBox/vmm/iem.h>
30#include <VBox/vmm/pgm.h>
31#include <VBox/vmm/trpm.h>
32#include "IOMInternal.h"
33#include <VBox/vmm/vm.h>
34
35#include <VBox/dis.h>
36#include <VBox/disopcode.h>
37#include <VBox/param.h>
38#include <VBox/err.h>
39#include <iprt/assert.h>
40#include <VBox/log.h>
41#include <iprt/asm.h>
42#include <iprt/string.h>
43
44
45#ifdef VBOX_WITH_3RD_IEM_STEP
46/**
47 * Converts disassembler mode to IEM mode.
48 * @return IEM CPU mode.
49 * @param enmDisMode Disassembler CPU mode.
50 */
51DECLINLINE(IEMMODE) iomDisModeToIemMode(DISCPUMODE enmDisMode)
52{
53 switch (enmDisMode)
54 {
55 case DISCPUMODE_16BIT: return IEMMODE_16BIT;
56 case DISCPUMODE_32BIT: return IEMMODE_32BIT;
57 case DISCPUMODE_64BIT: return IEMMODE_64BIT;
58 default:
59 AssertFailed();
60 return IEMMODE_32BIT;
61 }
62}
63#endif
64
65
66
67/**
68 * IN <AL|AX|EAX>, <DX|imm16>
69 *
70 * @returns Strict VBox status code. Informational status codes other than the one documented
71 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
72 * @retval VINF_SUCCESS Success.
73 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
74 * status code must be passed on to EM.
75 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3. (R0/GC only)
76 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
77 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
78 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
79 *
80 * @param pVM The cross context VM structure.
81 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
82 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
83 * @param pCpu Disassembler CPU state.
84 */
85static VBOXSTRICTRC iomRCInterpretIN(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
86{
87#ifdef IN_RC
88 STAM_COUNTER_INC(&pVM->iom.s.StatInstIn);
89#endif
90
91 /*
92 * Get port number from second parameter.
93 * And get the register size from the first parameter.
94 */
95 uint64_t uPort = 0;
96 unsigned cbSize = 0;
97 bool fRc = iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &uPort, &cbSize);
98 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
99
100 cbSize = DISGetParamSize(pCpu, &pCpu->Param1);
101 Assert(cbSize > 0);
102 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
103 if (rcStrict == VINF_SUCCESS)
104 {
105 /*
106 * Attempt to read the port.
107 */
108 uint32_t u32Data = UINT32_C(0xffffffff);
109 rcStrict = IOMIOPortRead(pVM, pVCpu, uPort, &u32Data, cbSize);
110 if (IOM_SUCCESS(rcStrict))
111 {
112 /*
113 * Store the result in the AL|AX|EAX register.
114 */
115 fRc = iomSaveDataToReg(pCpu, &pCpu->Param1, pRegFrame, u32Data);
116 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
117 }
118 else
119 AssertMsg(rcStrict == VINF_IOM_R3_IOPORT_READ || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
120 }
121 else
122 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
123
124 return rcStrict;
125}
126
127
128/**
129 * OUT <DX|imm16>, <AL|AX|EAX>
130 *
131 * @returns Strict VBox status code. Informational status codes other than the one documented
132 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
133 * @retval VINF_SUCCESS Success.
134 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
135 * status code must be passed on to EM.
136 * @retval VINF_IOM_R3_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
137 * @retval VINF_IOM_R3_IOPORT_COMMIT_WRITE Defer the write to ring-3. (R0/GC only)
138 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
139 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
140 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
141 *
142 * @param pVM The cross context VM structure.
143 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
144 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
145 * @param pCpu Disassembler CPU state.
146 */
147static VBOXSTRICTRC iomRCInterpretOUT(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
148{
149#ifdef IN_RC
150 STAM_COUNTER_INC(&pVM->iom.s.StatInstOut);
151#endif
152
153 /*
154 * Get port number from first parameter.
155 * And get the register size and value from the second parameter.
156 */
157 uint64_t uPort = 0;
158 unsigned cbSize = 0;
159 bool fRc = iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &uPort, &cbSize);
160 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
161
162 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
163 if (rcStrict == VINF_SUCCESS)
164 {
165 uint64_t u64Data = 0;
166 fRc = iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &u64Data, &cbSize);
167 AssertMsg(fRc, ("Failed to get reg value!\n")); NOREF(fRc);
168
169 /*
170 * Attempt to write to the port.
171 */
172 rcStrict = IOMIOPortWrite(pVM, pVCpu, uPort, u64Data, cbSize);
173 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IOM_R3_IOPORT_WRITE || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
174 || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST) || RT_FAILURE(rcStrict),
175 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
176 }
177 else
178 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
179 return rcStrict;
180}
181
182
183/**
184 * [REP*] INSB/INSW/INSD
185 * ES:EDI,DX[,ECX]
186 *
187 * @returns Strict VBox status code. Informational status codes other than the one documented
188 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
189 * @retval VINF_SUCCESS Success.
190 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
191 * status code must be passed on to EM.
192 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3. (R0/GC only)
193 * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
194 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
195 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
196 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
197 *
198 * @param pVM The cross context VM structure.
199 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
200 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
201 * @param pCpu Disassembler CPU state.
202 */
203static VBOXSTRICTRC iomRCInterpretINS(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
204{
205#ifdef VBOX_WITH_3RD_IEM_STEP
206 uint8_t cbValue = pCpu->pCurInstr->uOpcode == OP_INSB ? 1
207 : pCpu->uOpMode == DISCPUMODE_16BIT ? 2 : 4; /* dword in both 32 & 64 bits mode */
208 return IEMExecStringIoRead(pVCpu,
209 cbValue,
210 iomDisModeToIemMode((DISCPUMODE)pCpu->uCpuMode),
211 RT_BOOL(pCpu->fPrefix & (DISPREFIX_REPNE | DISPREFIX_REP)),
212 pCpu->cbInstr);
213#else
214 /*
215 * Get port number directly from the register (no need to bother the
216 * disassembler). And get the I/O register size from the opcode / prefix.
217 */
218 RTIOPORT Port = pRegFrame->edx & 0xffff;
219 unsigned cb;
220 if (pCpu->pCurInstr->uOpcode == OP_INSB)
221 cb = 1;
222 else
223 cb = (pCpu->uOpMode == DISCPUMODE_16BIT) ? 2 : 4; /* dword in both 32 & 64 bits mode */
224
225 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, Port, cb);
226 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
227 {
228 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
229 return rcStrict;
230 }
231
232 return IOMInterpretINSEx(pVM, pVCpu, pRegFrame, Port, pCpu->fPrefix, (DISCPUMODE)pCpu->uAddrMode, cb);
233#endif
234}
235
236
237/**
238 * [REP*] OUTSB/OUTSW/OUTSD
239 * DS:ESI,DX[,ECX]
240 *
241 * @returns Strict VBox status code. Informational status codes other than the one documented
242 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
243 * @retval VINF_SUCCESS Success.
244 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
245 * status code must be passed on to EM.
246 * @retval VINF_IOM_R3_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
247 * @retval VINF_IOM_R3_IOPORT_COMMIT_WRITE Defer the write to ring-3. (R0/GC only)
248 * @retval VINF_EM_RAW_EMULATE_INSTR Defer the write to the REM.
249 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
250 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
251 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
252 *
253 * @param pVM The cross context VM structure.
254 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
255 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
256 * @param pCpu Disassembler CPU state.
257 */
258static VBOXSTRICTRC iomRCInterpretOUTS(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
259{
260#ifdef VBOX_WITH_3RD_IEM_STEP
261 uint8_t cbValue = pCpu->pCurInstr->uOpcode == OP_OUTSB ? 1
262 : pCpu->uOpMode == DISCPUMODE_16BIT ? 2 : 4; /* dword in both 32 & 64 bits mode */
263 return IEMExecStringIoWrite(pVCpu,
264 cbValue,
265 iomDisModeToIemMode((DISCPUMODE)pCpu->uCpuMode),
266 RT_BOOL(pCpu->fPrefix & (DISPREFIX_REPNE | DISPREFIX_REP)),
267 pCpu->cbInstr,
268 pCpu->fPrefix & DISPREFIX_SEG ? pCpu->idxSegPrefix : X86_SREG_DS);
269#else
270 /*
271 * Get port number from the first parameter.
272 * And get the I/O register size from the opcode / prefix.
273 */
274 uint64_t Port = 0;
275 unsigned cb;
276 bool fRc = iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &Port, &cb);
277 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
278 if (pCpu->pCurInstr->uOpcode == OP_OUTSB)
279 cb = 1;
280 else
281 cb = (pCpu->uOpMode == DISCPUMODE_16BIT) ? 2 : 4; /* dword in both 32 & 64 bits mode */
282
283 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, Port, cb);
284 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
285 {
286 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
287 return rcStrict;
288 }
289
290 return IOMInterpretOUTSEx(pVM, pVCpu, pRegFrame, Port, pCpu->fPrefix, (DISCPUMODE)pCpu->uAddrMode, cb);
291#endif
292}
293
294
295
296/**
297 * Attempts to service an IN/OUT instruction.
298 *
299 * The \#GP trap handler in RC will call this function if the opcode causing
300 * the trap is a in or out type instruction. (Call it indirectly via EM that
301 * is.)
302 *
303 * @returns Strict VBox status code. Informational status codes other than the one documented
304 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
305 * @retval VINF_SUCCESS Success.
306 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
307 * status code must be passed on to EM.
308 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
309 * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
310 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3.
311 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
312 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
313 *
314 * @param pVM The cross context VM structure.
315 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
316 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
317 * @param pCpu Disassembler CPU state.
318 */
319VMMRCDECL(VBOXSTRICTRC) IOMRCIOPortHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
320{
321 switch (pCpu->pCurInstr->uOpcode)
322 {
323 case OP_IN:
324 return iomRCInterpretIN(pVM, pVCpu, pRegFrame, pCpu);
325
326 case OP_OUT:
327 return iomRCInterpretOUT(pVM, pVCpu, pRegFrame, pCpu);
328
329 case OP_INSB:
330 case OP_INSWD:
331 return iomRCInterpretINS(pVM, pVCpu, pRegFrame, pCpu);
332
333 case OP_OUTSB:
334 case OP_OUTSWD:
335 return iomRCInterpretOUTS(pVM, pVCpu, pRegFrame, pCpu);
336
337 /*
338 * The opcode wasn't know to us, freak out.
339 */
340 default:
341 AssertMsgFailed(("Unknown I/O port access opcode %d.\n", pCpu->pCurInstr->uOpcode));
342 return VERR_IOM_IOPORT_UNKNOWN_OPCODE;
343 }
344}
345
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette