1 | /** @file
|
---|
2 | * GCM - Guest Compatibility Manager - All Contexts.
|
---|
3 | */
|
---|
4 |
|
---|
5 | /*
|
---|
6 | * Copyright (C) 2022-2024 Oracle and/or its affiliates.
|
---|
7 | *
|
---|
8 | * This file is part of VirtualBox base platform packages, as
|
---|
9 | * available from https://www.virtualbox.org.
|
---|
10 | *
|
---|
11 | * This program is free software; you can redistribute it and/or
|
---|
12 | * modify it under the terms of the GNU General Public License
|
---|
13 | * as published by the Free Software Foundation, in version 3 of the
|
---|
14 | * License.
|
---|
15 | *
|
---|
16 | * This program is distributed in the hope that it will be useful, but
|
---|
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
19 | * General Public License for more details.
|
---|
20 | *
|
---|
21 | * You should have received a copy of the GNU General Public License
|
---|
22 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
23 | *
|
---|
24 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
25 | */
|
---|
26 |
|
---|
27 |
|
---|
28 | /*********************************************************************************************************************************
|
---|
29 | * Header Files *
|
---|
30 | *********************************************************************************************************************************/
|
---|
31 | #define LOG_GROUP LOG_GROUP_GCM
|
---|
32 | #include <VBox/vmm/gcm.h>
|
---|
33 | #include "GCMInternal.h"
|
---|
34 | #include <VBox/vmm/vmcc.h>
|
---|
35 |
|
---|
36 | #include <VBox/dis.h> /* For DISSTATE */
|
---|
37 | #include <VBox/err.h>
|
---|
38 | #include <iprt/string.h>
|
---|
39 |
|
---|
40 |
|
---|
41 | /*********************************************************************************************************************************
|
---|
42 | * Defined Constants And Macros *
|
---|
43 | *********************************************************************************************************************************/
|
---|
44 | #define VMWARE_HYPERVISOR_PORT UINT16_C(0x5658)
|
---|
45 | #define VMWARE_HYPERVISOR_PORT_HB UINT16_C(0x5659)
|
---|
46 | #define VMWARE_HYPERVISOR_MAGIC UINT32_C(0x564d5868) /**< eax value */
|
---|
47 |
|
---|
48 | #define VMWARE_HYPERVISOR_CMD_MSG 0x001e
|
---|
49 | #define VMWARE_HYPERVISOR_CMD_HB_MSG 0x0000
|
---|
50 | #define VMWARE_HYPERVISOR_CMD_OPEN_CHANNEL RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MSG, 0) /**< ecx */
|
---|
51 | #define VMWARE_OC_RPCI_PROTOCOL_NUM UINT32_C(0x49435052) /**< VMWARE_HYPERVISOR_CMD_OPEN_CHANNEL: ebx[30:0] */
|
---|
52 | #define VMWARE_OC_GUESTMSG_FLAG_COOKIE UINT32_C(0x80000000) /**< VMWARE_HYPERVISOR_CMD_OPEN_CHANNEL: ebx bit 31 */
|
---|
53 | #define VMWARE_HYPERVISOR_CMD_SEND_SIZE RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MSG, 1) /**< ecx */
|
---|
54 | #define VMWARE_HYPERVISOR_CMD_SEND_PAYLOAD RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MSG, 2) /**< ecx */
|
---|
55 | #define VMWARE_HYPERVISOR_CMD_RECV_SIZE RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MSG, 3) /**< ecx */
|
---|
56 | #define VMWARE_HYPERVISOR_CMD_RECV_PAYLOAD RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MSG, 4) /**< ecx */
|
---|
57 | #define VMWARE_HYPERVISOR_CMD_RECV_STATUS RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MSG, 5) /**< ecx */
|
---|
58 | #define VMWARE_HYPERVISOR_CMD_CLOSE_CHANNEL RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MSG, 6) /**< ecx */
|
---|
59 |
|
---|
60 | #define VMWARE_HYPERVISOR_CMD_MKS_GUEST_STATS 0x0055
|
---|
61 | #define VMWARE_HYPERVISOR_CMD_MKSGS_RESET RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MKS_GUEST_STATS, 0) /**< ecx */
|
---|
62 | #define VMWARE_HYPERVISOR_CMD_MKSGS_ADD_PPN RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MKS_GUEST_STATS, 1) /**< ecx */
|
---|
63 | #define VMWARE_HYPERVISOR_CMD_MKSGS_REMOVE_PPN RT_MAKE_U32(VMWARE_HYPERVISOR_CMD_MKS_GUEST_STATS, 2) /**< ecx */
|
---|
64 |
|
---|
65 | /** @name Message status return flags (ecx).
|
---|
66 | * @{ */
|
---|
67 | #define VMWARE_MSG_STATUS_F_SUCCESS UINT32_C(0x00010000)
|
---|
68 | #define VMWARE_MSG_STATUS_F_DO_RECV UINT32_C(0x00020000)
|
---|
69 | #define VMWARE_MSG_STATUS_F_CPT UINT32_C(0x00100000)
|
---|
70 | #define VMWARE_MSG_STATUS_F_HB UINT32_C(0x00800000)
|
---|
71 | /** @} */
|
---|
72 |
|
---|
73 |
|
---|
74 |
|
---|
75 | /**
|
---|
76 | * Whether \#DE exceptions in the guest should be intercepted by GCM and
|
---|
77 | * possibly fixed up.
|
---|
78 | *
|
---|
79 | * @returns true if needed, false otherwise.
|
---|
80 | * @param pVCpu The cross context virtual CPU structure.
|
---|
81 | */
|
---|
82 | VMM_INT_DECL(bool) GCMIsInterceptingXcptDE(PVMCPUCC pVCpu)
|
---|
83 | {
|
---|
84 | /* See if the enabled fixers need to intercept #DE. */
|
---|
85 | PVM const pVM = pVCpu->CTX_SUFF(pVM);
|
---|
86 | bool const fRet = (pVM->gcm.s.fFixerSet & (GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2 | GCMFIXER_DBZ_WIN9X)) != 0;
|
---|
87 | LogFlow(("GCMIsInterceptingXcptDE: returns %d\n", fRet));
|
---|
88 | return fRet;
|
---|
89 | }
|
---|
90 |
|
---|
91 |
|
---|
92 | /**
|
---|
93 | * Exception handler for \#DE when registered by GCM.
|
---|
94 | *
|
---|
95 | * @returns VBox status code.
|
---|
96 | * @retval VINF_SUCCESS retry division and continue.
|
---|
97 | * @retval VERR_NOT_FOUND deliver exception to guest.
|
---|
98 | *
|
---|
99 | * @param pVCpu The cross context virtual CPU structure.
|
---|
100 | * @param pCtx Pointer to the guest-CPU context.
|
---|
101 | *
|
---|
102 | * @thread EMT(pVCpu).
|
---|
103 | */
|
---|
104 | VMM_INT_DECL(int) GCMXcptDE(PVMCPUCC pVCpu, PCPUMCTX pCtx)
|
---|
105 | {
|
---|
106 | PVMCC pVM = pVCpu->CTX_SUFF(pVM);
|
---|
107 | Assert(pVM->gcm.s.fFixerSet & (GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2 | GCMFIXER_DBZ_WIN9X));
|
---|
108 |
|
---|
109 | LogRel(("GCM: Intercepted #DE at CS:RIP=%04x:%RX64 (%RX64 linear) RDX:RAX=%RX64:%RX64 RCX=%RX64 RBX=%RX64\n",
|
---|
110 | pCtx->cs.Sel, pCtx->rip, pCtx->cs.u64Base + pCtx->rip, pCtx->rdx, pCtx->rax, pCtx->rcx, pCtx->rbx));
|
---|
111 |
|
---|
112 | if (pVM->gcm.s.fFixerSet & GCMFIXER_DBZ_OS2)
|
---|
113 | {
|
---|
114 | if (pCtx->rcx == 0 && pCtx->rdx == 1 && pCtx->rax == 0x86a0)
|
---|
115 | {
|
---|
116 | /* OS/2 1.x drivers loaded during boot: DX:AX = 100,000, CX < 2 causes overflow. */
|
---|
117 | /* Example: OS/2 1.0 KBD01.SYS, 16,945 bytes, dated 10/21/1987, div cx at offset 2:2ffeh */
|
---|
118 | /* Code later merged into BASEDD01.SYS, crash fixed in OS/2 1.30.1; this should
|
---|
119 | * fix all affected versions of OS/2 1.x.
|
---|
120 | */
|
---|
121 | pCtx->rcx = 2;
|
---|
122 | return VINF_SUCCESS;
|
---|
123 | }
|
---|
124 | if ((uint16_t)pCtx->rbx == 0 && (uint16_t)pCtx->rdx == 0 && (uint16_t)pCtx->rax == 0x1000)
|
---|
125 | {
|
---|
126 | /* OS/2 2.1 and later boot loader: DX:AX = 0x1000, zero BX. May have junk in high words of all registers. */
|
---|
127 | /* Example: OS/2 MCP2 OS2LDR, 44,544 bytes, dated 03/08/2002, idiv bx at offset 847ah */
|
---|
128 | pCtx->rbx = (pCtx->rbx & ~0xffff) | 2;
|
---|
129 | return VINF_SUCCESS;
|
---|
130 | }
|
---|
131 | if (pCtx->rbx == 0 && pCtx->rdx == 0 && pCtx->rax == 0x100)
|
---|
132 | {
|
---|
133 | /* OS/2 2.0 boot loader: DX:AX = 0x100, zero BX. May have junk in high words of registers. */
|
---|
134 | /* Example: OS/2 2.0 OS2LDR, 32,256 bytes, dated 03/30/1992, idiv bx at offset 2298h */
|
---|
135 | pCtx->rbx = 2;
|
---|
136 | return VINF_SUCCESS;
|
---|
137 | }
|
---|
138 | }
|
---|
139 |
|
---|
140 | if (pVM->gcm.s.fFixerSet & GCMFIXER_DBZ_DOS)
|
---|
141 | {
|
---|
142 | /* NB: For 16-bit DOS software, we must generally only compare 16-bit registers.
|
---|
143 | * The contents of the high words may be unpredictable depending on the environment.
|
---|
144 | * For 32-bit Windows 3.x code that is not the case.
|
---|
145 | */
|
---|
146 | if (pCtx->rcx == 0 && pCtx->rdx == 0 && pCtx->rax == 0x100000)
|
---|
147 | {
|
---|
148 | /* NDIS.386 in WfW 3.11: CalibrateStall, EDX:EAX = 0x100000, zero ECX.
|
---|
149 | * Occurs when NDIS.386 loads.
|
---|
150 | */
|
---|
151 | pCtx->rcx = 0x20000; /* Want a large divisor to shorten stalls. */
|
---|
152 | return VINF_SUCCESS;
|
---|
153 | }
|
---|
154 | if (pCtx->rcx == 0 && pCtx->rdx == 0 && pCtx->rax > 0x100000)
|
---|
155 | {
|
---|
156 | /* NDIS.386 in WfW 3.11: NdisStallExecution, EDX:EAX = 0xYY00000, zero ECX.
|
---|
157 | * EDX:EAX is variable, but low 20 bits of EAX must be zero and EDX is likely
|
---|
158 | * to be zero as well.
|
---|
159 | * Only occurs if NdisStallExecution is called to do a longish stall.
|
---|
160 | */
|
---|
161 | pCtx->rcx = 22;
|
---|
162 | return VINF_SUCCESS;
|
---|
163 | }
|
---|
164 | if ((uint16_t)pCtx->rbx == 0 && (uint16_t)pCtx->rdx == 0 && (uint16_t)pCtx->rax == 0x64)
|
---|
165 | {
|
---|
166 | /* Norton Sysinfo or Diagnostics 8.0 DX:AX = 0x64 (100 decimal), zero BX. */
|
---|
167 | pCtx->rbx = (pCtx->rbx & 0xffff0000) | 1; /* BX = 1 */
|
---|
168 | return VINF_SUCCESS;
|
---|
169 | }
|
---|
170 | if ((uint16_t)pCtx->rbx == 0 && (uint16_t)pCtx->rdx == 0 && (uint16_t)pCtx->rax == 0xff)
|
---|
171 | {
|
---|
172 | /* IBM PC LAN Program 1.3: DX:AX=0xff (255 decimal), zero BX. */
|
---|
173 | /* NETWORK1.CMD, 64,324 bytes, dated 06/06/1988, div bx at offset 0xa400 in file. */
|
---|
174 | pCtx->rbx = (pCtx->rbx & 0xffff0000) | 1; /* BX = 1 */
|
---|
175 | return VINF_SUCCESS;
|
---|
176 | }
|
---|
177 | if ((uint16_t)pCtx->rdx == 0xffff && (uint16_t)pCtx->rax == 0xffff && (uint16_t)pCtx->rcx == 0xa8c0)
|
---|
178 | {
|
---|
179 | /* QNX 2.15C: DX:AX=0xffffffff (-1), constant CX = 0xa8c0 (43200). */
|
---|
180 | /* div cx at e.g. 2220:fa5 and 2220:10a0 in memory. */
|
---|
181 | pCtx->rdx = (pCtx->rdx & 0xffff0000) | 8; /* DX = 8 */
|
---|
182 | return VINF_SUCCESS;
|
---|
183 | }
|
---|
184 | if ((uint16_t)pCtx->rax > 0x1800 && ((uint16_t)pCtx->rax & 0x3f) == 0 && (uint16_t)pCtx->rbx == 0x19)
|
---|
185 | {
|
---|
186 | /* 3C501.COM ODI driver v1.21: AX > ~0x1900 (-1), BX = 0x19 (25). */
|
---|
187 | /* AX was shifted left by 6 bits so low bits must be zero. */
|
---|
188 | /* div bl at e.g. 06b3:2f80 and offset 0x2E80 in file. */
|
---|
189 | pCtx->rax = (pCtx->rax & 0xffff0000) | 0x8c0; /* AX = 0x8c0 */
|
---|
190 | return VINF_SUCCESS;
|
---|
191 | }
|
---|
192 | if ((uint16_t)pCtx->rcx == 0x37 && ((uint16_t)pCtx->rdx > 0x34))
|
---|
193 | {
|
---|
194 | /* Turbo Pascal, classic Runtime Error 200: CX = 55, DX > ~54, AX/BX variable. */
|
---|
195 | /* div cx at variable offset in file. */
|
---|
196 | pCtx->rdx = (pCtx->rdx & 0xffff0000) | 0x30; /* DX = 48 */
|
---|
197 | return VINF_SUCCESS;
|
---|
198 | }
|
---|
199 | }
|
---|
200 |
|
---|
201 | if (pVM->gcm.s.fFixerSet & GCMFIXER_DBZ_WIN9X)
|
---|
202 | {
|
---|
203 | if (pCtx->rcx == 0 && pCtx->rdx == 0 && pCtx->rax == 0x100000)
|
---|
204 | {
|
---|
205 | /* NDIS.VXD in Win9x: EDX:EAX = 0x100000, zero ECX. */
|
---|
206 | /* Example: Windows 95 NDIS.VXD, 99,084 bytes, dated 07/11/1994, div ecx at 28:Cxxxx80B */
|
---|
207 | /* Crash fixed in Windows 98 SE. */
|
---|
208 | pCtx->rcx = 0x20000; /* Want a large divisor to shorten stalls. */
|
---|
209 | return VINF_SUCCESS;
|
---|
210 | }
|
---|
211 | if (pCtx->rcx < 3 && pCtx->rdx == 2 && pCtx->rax == 0x540be400)
|
---|
212 | {
|
---|
213 | /* SCSI.PDR, ESDI506.PDR in Win95: EDX:EAX = 0x2540be400 (10,000,000,000 decimal), ECX < 3. */
|
---|
214 | /* Example: Windows 95 SCSIPORT.PDR, 23,133 bytes, dated 07/11/1995, div ecx at 28:Cxxxx876 */
|
---|
215 | /* Example: Win95 OSR2 ESDI506.PDR, 24,390 bytes, dated 04/24/1996, div ecx at 28:Cxxxx8E3 */
|
---|
216 | /* Crash fixed in Windows 98. */
|
---|
217 | pCtx->rcx = 1000;
|
---|
218 | return VINF_SUCCESS;
|
---|
219 | }
|
---|
220 | if (pCtx->rcx == 0 && pCtx->rdx == 0x3d && pCtx->rax == 0x9000000)
|
---|
221 | {
|
---|
222 | /* Unknown source, Win9x shutdown, div ecx. */
|
---|
223 | /* GCM: Intercepted #DE at CS:RIP=0028:c0050f8e RDX:RAX=3d:9000000 (250000*1024*1024) RCX=0 RBX=c19200e8 [RBX variable] */
|
---|
224 | pCtx->rcx = 4096;
|
---|
225 | return VINF_SUCCESS;
|
---|
226 | }
|
---|
227 | }
|
---|
228 |
|
---|
229 | /* If we got this far, deliver exception to guest. */
|
---|
230 | return VERR_NOT_FOUND;
|
---|
231 | }
|
---|
232 |
|
---|
233 |
|
---|
234 | #if 0
|
---|
235 | /**
|
---|
236 | * Whether \#GP exceptions in the guest should be intercepted by GCM and
|
---|
237 | * possibly fixed up.
|
---|
238 | *
|
---|
239 | * @returns true if needed, false otherwise.
|
---|
240 | * @param pVCpu The cross context virtual CPU structure.
|
---|
241 | */
|
---|
242 | VMM_INT_DECL(bool) GCMIsInterceptingXcptGP(PVMCPUCC pVCpu)
|
---|
243 | {
|
---|
244 | /* See if the enabled fixers require #GP interception. */
|
---|
245 | PVM const pVM = pVCpu->CTX_SUFF(pVM);
|
---|
246 | bool const fRet = (pVM->gcm.s.fFixerSet & GCMFIXER_MESA_VMSVGA_DRV) != 0;
|
---|
247 | LogFlow(("GCMIsInterceptingXcptDE: returns %d\n", fRet));
|
---|
248 | return fRet;
|
---|
249 | }
|
---|
250 |
|
---|
251 |
|
---|
252 | /**
|
---|
253 | * Exception handler for \#GP when registered by GCM.
|
---|
254 | *
|
---|
255 | * @returns VBox status code.
|
---|
256 | * @retval VINF_SUCCESS retry the instruction and continue.
|
---|
257 | * @retval VERR_NOT_FOUND deliver exception to guest.
|
---|
258 | *
|
---|
259 | * @param pVCpu The cross context virtual CPU structure.
|
---|
260 | * @param pCtx Pointer to the guest-CPU context.
|
---|
261 | *
|
---|
262 | * @thread EMT(pVCpu).
|
---|
263 | */
|
---|
264 | VMM_INT_DECL(int) GCMXcptGP(PVMCPUCC pVCpu, PCPUMCTX pCtx)
|
---|
265 | {
|
---|
266 |
|
---|
267 | }
|
---|
268 | #endif
|
---|
269 |
|
---|
270 |
|
---|
271 | /**
|
---|
272 | * Checks if I/O port reads for the given port need GCM attention.
|
---|
273 | *
|
---|
274 | * @returns true if needed, false otherwise.
|
---|
275 | * @param pVCpu The cross context virtual CPU structure.
|
---|
276 | * @param u16Port The port being accessed. UINT16_MAX and cbReg ==
|
---|
277 | * UINT8_MAX for any port.
|
---|
278 | * @param cbReg The access size. UINT8_MAX and u16Port == UINT16_MAX for
|
---|
279 | * any size.
|
---|
280 | */
|
---|
281 | VMM_INT_DECL(bool) GCMIsInterceptingIOPortReadSlow(PVMCPUCC pVCpu, uint16_t u16Port, uint8_t cbReg)
|
---|
282 | {
|
---|
283 | PVM const pVM = pVCpu->CTX_SUFF(pVM);
|
---|
284 | bool const fRet = (pVM->gcm.s.fFixerSet & GCMFIXER_MESA_VMSVGA_DRV) != 0
|
---|
285 | && ( (u16Port == VMWARE_HYPERVISOR_PORT && cbReg == 4)
|
---|
286 | || (u16Port == UINT16_MAX && cbReg == UINT8_MAX) );
|
---|
287 | LogFlow(("GCMIsInterceptingIOPortReadSlow(,%#x,%#x): returns %d\n", u16Port, cbReg, fRet));
|
---|
288 | return fRet;
|
---|
289 | }
|
---|
290 |
|
---|
291 |
|
---|
292 | /**
|
---|
293 | * Processes an intercepted IO port read instruction.
|
---|
294 | *
|
---|
295 | * @returns Strict VBox status code. Only two informational status codes
|
---|
296 | * are returned VINF_GCM_HANDLED and VINF_GCM_HANDLED_ADVANCE_RIP.
|
---|
297 | * @retval VINF_GCM_HANDLED
|
---|
298 | * @retval VINF_GCM_HANDLED_ADVANCE_RIP
|
---|
299 | * @retval VERR_GCM_NOT_HANDLED
|
---|
300 | * @param pVCpu The cross context virtual CPU structure.
|
---|
301 | * @param pCtx The CPU context.
|
---|
302 | * @param u16Port The port being accessed.
|
---|
303 | * @param cbReg The size of the access.
|
---|
304 | */
|
---|
305 | VMM_INT_DECL(VBOXSTRICTRC) GCMInterceptedIOPortRead(PVMCPUCC pVCpu, PCPUMCTX pCtx, uint16_t u16Port, uint8_t cbReg)
|
---|
306 | {
|
---|
307 | Assert((pVCpu->CTX_SUFF(pVM)->gcm.s.fFixerSet & GCMFIXER_MESA_VMSVGA_DRV) != 0);
|
---|
308 | if (u16Port == VMWARE_HYPERVISOR_PORT && cbReg == 4)
|
---|
309 | {
|
---|
310 | CPUM_IMPORT_EXTRN_WITH_CTX_RET(pVCpu, pCtx,
|
---|
311 | CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX
|
---|
312 | | CPUMCTX_EXTRN_RBX | CPUMCTX_EXTRN_RSI | CPUMCTX_EXTRN_RDI);
|
---|
313 | if (pCtx->rax == VMWARE_HYPERVISOR_MAGIC)
|
---|
314 | {
|
---|
315 | switch (pCtx->rcx)
|
---|
316 | {
|
---|
317 | case VMWARE_HYPERVISOR_CMD_OPEN_CHANNEL:
|
---|
318 | Log(("GCMInterceptedIOPortRead: vmware open channel: protocol=%#RX64\n", pCtx->rbx));
|
---|
319 | break;
|
---|
320 | case VMWARE_HYPERVISOR_CMD_SEND_SIZE:
|
---|
321 | Log(("GCMInterceptedIOPortRead: vmware send size\n"));
|
---|
322 | break;
|
---|
323 | case VMWARE_HYPERVISOR_CMD_SEND_PAYLOAD:
|
---|
324 | Log(("GCMInterceptedIOPortRead: vmware send payload\n"));
|
---|
325 | break;
|
---|
326 | case VMWARE_HYPERVISOR_CMD_RECV_SIZE:
|
---|
327 | Log(("GCMInterceptedIOPortRead: vmware recv size\n"));
|
---|
328 | break;
|
---|
329 | case VMWARE_HYPERVISOR_CMD_RECV_PAYLOAD:
|
---|
330 | Log(("GCMInterceptedIOPortRead: vmware recv payload\n"));
|
---|
331 | break;
|
---|
332 | case VMWARE_HYPERVISOR_CMD_RECV_STATUS:
|
---|
333 | Log(("GCMInterceptedIOPortRead: vmware recv status\n"));
|
---|
334 | break;
|
---|
335 | case VMWARE_HYPERVISOR_CMD_CLOSE_CHANNEL:
|
---|
336 | Log(("GCMInterceptedIOPortRead: vmware close channel\n"));
|
---|
337 | break;
|
---|
338 |
|
---|
339 | case VMWARE_HYPERVISOR_CMD_MKSGS_RESET:
|
---|
340 | Log(("GCMInterceptedIOPortRead: vmware mks guest stats reset\n"));
|
---|
341 | break;
|
---|
342 | case VMWARE_HYPERVISOR_CMD_MKSGS_ADD_PPN:
|
---|
343 | Log(("GCMInterceptedIOPortRead: vmware mks guest stats add ppn\n"));
|
---|
344 | break;
|
---|
345 | case VMWARE_HYPERVISOR_CMD_MKSGS_REMOVE_PPN:
|
---|
346 | Log(("GCMInterceptedIOPortRead: vmware mks guest stats remove ppn\n"));
|
---|
347 | break;
|
---|
348 |
|
---|
349 | default:
|
---|
350 | LogRelMax(64, ("GCMInterceptedIOPortRead: Unknown vmware hypervisor call: rcx=%#RX64 (cmd), rbx=%#RX64 (len/whatever), rsi=%#RX64 (input), rdi=%#RX64 (input), rdx=%#RX64 (flags + chid) at %04x:%08RX64\n",
|
---|
351 | pCtx->rcx, pCtx->rbx, pCtx->rsi, pCtx->rdi, pCtx->rdx, pCtx->cs.Sel, pCtx->rip));
|
---|
352 | return VERR_GCM_NOT_HANDLED;
|
---|
353 | }
|
---|
354 |
|
---|
355 | /* Just fail the command. */
|
---|
356 | pCtx->ecx &= ~VMWARE_MSG_STATUS_F_SUCCESS;
|
---|
357 | return VINF_GCM_HANDLED_ADVANCE_RIP;
|
---|
358 | }
|
---|
359 | }
|
---|
360 | return VERR_GCM_NOT_HANDLED;
|
---|
361 | }
|
---|
362 |
|
---|
363 |
|
---|
364 | #if 0 /* If we need to deal with high speed vmware hypervisor calls */
|
---|
365 |
|
---|
366 | /**
|
---|
367 | * Checks if I/O port string reads for the given port need GCM attention.
|
---|
368 | *
|
---|
369 | * @returns true if needed, false otherwise.
|
---|
370 | * @param pVCpu The cross context virtual CPU structure.
|
---|
371 | * @param u16Port The port being accessed. UINT16_MAX and cbReg ==
|
---|
372 | * UINT8_MAX for any port.
|
---|
373 | * @param cbReg The access size. UINT8_MAX and u16Port == UINT16_MAX for
|
---|
374 | * any size.
|
---|
375 | */
|
---|
376 | VMM_INT_DECL(bool) GCMIsInterceptingIOPortReadStringSlow(PVMCPUCC pVCpu, uint16_t u16Port, uint8_t cbReg)
|
---|
377 | {
|
---|
378 | PVM const pVM = pVCpu->CTX_SUFF(pVM);
|
---|
379 | bool const fRet = (pVM->gcm.s.fFixerSet & GCMFIXER_MESA_VMSVGA_DRV) != 0
|
---|
380 | && ( (u16Port == VMWARE_HYPERVISOR_PORT_HB && cbReg == 1)
|
---|
381 | || (u16Port == UINT16_MAX && cbReg == UINT8_MAX) );
|
---|
382 | LogFlow(("GCMIsInterceptingIOPortReadStringSlow(,%#x,%#x): returns %d\n", u16Port, cbReg, fRet));
|
---|
383 | return fRet;
|
---|
384 | }
|
---|
385 |
|
---|
386 |
|
---|
387 | /**
|
---|
388 | * Checks if I/O port string writes for the given port need GCM attention.
|
---|
389 | *
|
---|
390 | * @returns true if needed, false otherwise.
|
---|
391 | * @param pVCpu The cross context virtual CPU structure.
|
---|
392 | * @param u16Port The port being accessed. UINT16_MAX and cbReg ==
|
---|
393 | * UINT8_MAX for any port.
|
---|
394 | * @param cbReg The access size. UINT8_MAX and u16Port == UINT16_MAX for
|
---|
395 | * any size.
|
---|
396 | */
|
---|
397 | VMM_INT_DECL(bool) GCMIsInterceptingIOPortWriteStringSlow(PVMCPUCC pVCpu, uint16_t u16Port, uint8_t cbReg)
|
---|
398 | {
|
---|
399 | PVM const pVM = pVCpu->CTX_SUFF(pVM);
|
---|
400 | bool const fRet = (pVM->gcm.s.fFixerSet & GCMFIXER_MESA_VMSVGA_DRV) != 0
|
---|
401 | && ( (u16Port == VMWARE_HYPERVISOR_PORT_HB && cbReg == 1)
|
---|
402 | || (u16Port == UINT16_MAX && cbReg == UINT8_MAX) );
|
---|
403 | LogFlow(("GCMIsInterceptingIOPortWriteStringSlow(,%#x,%#x): returns %d\n", u16Port, cbReg, fRet));
|
---|
404 | return fRet;
|
---|
405 | }
|
---|
406 |
|
---|
407 | #endif
|
---|
408 |
|
---|