VirtualBox

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

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

VMM: Made @param pVCpu more uniform and to the point.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.6 KB
Line 
1/* $Id: IOMRC.cpp 58123 2015-10-08 18:09:45Z 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_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
138 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
139 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
140 *
141 * @param pVM The cross context VM structure.
142 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
143 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
144 * @param pCpu Disassembler CPU state.
145 */
146static VBOXSTRICTRC iomRCInterpretOUT(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
147{
148#ifdef IN_RC
149 STAM_COUNTER_INC(&pVM->iom.s.StatInstOut);
150#endif
151
152 /*
153 * Get port number from first parameter.
154 * And get the register size and value from the second parameter.
155 */
156 uint64_t uPort = 0;
157 unsigned cbSize = 0;
158 bool fRc = iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &uPort, &cbSize);
159 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
160
161 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
162 if (rcStrict == VINF_SUCCESS)
163 {
164 uint64_t u64Data = 0;
165 fRc = iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &u64Data, &cbSize);
166 AssertMsg(fRc, ("Failed to get reg value!\n")); NOREF(fRc);
167
168 /*
169 * Attempt to write to the port.
170 */
171 rcStrict = IOMIOPortWrite(pVM, pVCpu, uPort, u64Data, cbSize);
172 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IOM_R3_IOPORT_WRITE || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST) || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
173 }
174 else
175 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
176 return rcStrict;
177}
178
179
180/**
181 * [REP*] INSB/INSW/INSD
182 * ES:EDI,DX[,ECX]
183 *
184 * @returns Strict VBox status code. Informational status codes other than the one documented
185 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
186 * @retval VINF_SUCCESS Success.
187 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
188 * status code must be passed on to EM.
189 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3. (R0/GC only)
190 * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
191 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
192 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
193 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
194 *
195 * @param pVM The cross context VM structure.
196 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
197 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
198 * @param pCpu Disassembler CPU state.
199 */
200static VBOXSTRICTRC iomRCInterpretINS(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
201{
202#ifdef VBOX_WITH_3RD_IEM_STEP
203 uint8_t cbValue = pCpu->pCurInstr->uOpcode == OP_INSB ? 1
204 : pCpu->uOpMode == DISCPUMODE_16BIT ? 2 : 4; /* dword in both 32 & 64 bits mode */
205 return IEMExecStringIoRead(pVCpu,
206 cbValue,
207 iomDisModeToIemMode((DISCPUMODE)pCpu->uCpuMode),
208 RT_BOOL(pCpu->fPrefix & (DISPREFIX_REPNE | DISPREFIX_REP)),
209 pCpu->cbInstr);
210#else
211 /*
212 * Get port number directly from the register (no need to bother the
213 * disassembler). And get the I/O register size from the opcode / prefix.
214 */
215 RTIOPORT Port = pRegFrame->edx & 0xffff;
216 unsigned cb;
217 if (pCpu->pCurInstr->uOpcode == OP_INSB)
218 cb = 1;
219 else
220 cb = (pCpu->uOpMode == DISCPUMODE_16BIT) ? 2 : 4; /* dword in both 32 & 64 bits mode */
221
222 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, Port, cb);
223 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
224 {
225 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
226 return rcStrict;
227 }
228
229 return IOMInterpretINSEx(pVM, pVCpu, pRegFrame, Port, pCpu->fPrefix, (DISCPUMODE)pCpu->uAddrMode, cb);
230#endif
231}
232
233
234/**
235 * [REP*] OUTSB/OUTSW/OUTSD
236 * DS:ESI,DX[,ECX]
237 *
238 * @returns Strict VBox status code. Informational status codes other than the one documented
239 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
240 * @retval VINF_SUCCESS Success.
241 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
242 * status code must be passed on to EM.
243 * @retval VINF_IOM_R3_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
244 * @retval VINF_EM_RAW_EMULATE_INSTR Defer the write to the REM.
245 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
246 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
247 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
248 *
249 * @param pVM The cross context VM structure.
250 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
251 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
252 * @param pCpu Disassembler CPU state.
253 */
254static VBOXSTRICTRC iomRCInterpretOUTS(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
255{
256#ifdef VBOX_WITH_3RD_IEM_STEP
257 uint8_t cbValue = pCpu->pCurInstr->uOpcode == OP_OUTSB ? 1
258 : pCpu->uOpMode == DISCPUMODE_16BIT ? 2 : 4; /* dword in both 32 & 64 bits mode */
259 return IEMExecStringIoWrite(pVCpu,
260 cbValue,
261 iomDisModeToIemMode((DISCPUMODE)pCpu->uCpuMode),
262 RT_BOOL(pCpu->fPrefix & (DISPREFIX_REPNE | DISPREFIX_REP)),
263 pCpu->cbInstr,
264 pCpu->fPrefix & DISPREFIX_SEG ? pCpu->idxSegPrefix : X86_SREG_DS);
265#else
266 /*
267 * Get port number from the first parameter.
268 * And get the I/O register size from the opcode / prefix.
269 */
270 uint64_t Port = 0;
271 unsigned cb;
272 bool fRc = iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &Port, &cb);
273 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
274 if (pCpu->pCurInstr->uOpcode == OP_OUTSB)
275 cb = 1;
276 else
277 cb = (pCpu->uOpMode == DISCPUMODE_16BIT) ? 2 : 4; /* dword in both 32 & 64 bits mode */
278
279 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, Port, cb);
280 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
281 {
282 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
283 return rcStrict;
284 }
285
286 return IOMInterpretOUTSEx(pVM, pVCpu, pRegFrame, Port, pCpu->fPrefix, (DISCPUMODE)pCpu->uAddrMode, cb);
287#endif
288}
289
290
291
292/**
293 * Attempts to service an IN/OUT instruction.
294 *
295 * The \#GP trap handler in RC will call this function if the opcode causing
296 * the trap is a in or out type instruction. (Call it indirectly via EM that
297 * is.)
298 *
299 * @returns Strict VBox status code. Informational status codes other than the one documented
300 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
301 * @retval VINF_SUCCESS Success.
302 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
303 * status code must be passed on to EM.
304 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
305 * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
306 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3.
307 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
308 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
309 *
310 * @param pVM The cross context VM structure.
311 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
312 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
313 * @param pCpu Disassembler CPU state.
314 */
315VMMRCDECL(VBOXSTRICTRC) IOMRCIOPortHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
316{
317 switch (pCpu->pCurInstr->uOpcode)
318 {
319 case OP_IN:
320 return iomRCInterpretIN(pVM, pVCpu, pRegFrame, pCpu);
321
322 case OP_OUT:
323 return iomRCInterpretOUT(pVM, pVCpu, pRegFrame, pCpu);
324
325 case OP_INSB:
326 case OP_INSWD:
327 return iomRCInterpretINS(pVM, pVCpu, pRegFrame, pCpu);
328
329 case OP_OUTSB:
330 case OP_OUTSWD:
331 return iomRCInterpretOUTS(pVM, pVCpu, pRegFrame, pCpu);
332
333 /*
334 * The opcode wasn't know to us, freak out.
335 */
336 default:
337 AssertMsgFailed(("Unknown I/O port access opcode %d.\n", pCpu->pCurInstr->uOpcode));
338 return VERR_IOM_IOPORT_UNKNOWN_OPCODE;
339 }
340}
341
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