VirtualBox

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

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

IOM: Moved some RC code into IOMRC.cpp.

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