VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/GCMAll.cpp@ 104511

Last change on this file since 104511 was 104511, checked in by vboxsync, 7 months ago

VMM: Some more GCM cleanup. bugref:9735 bugref:10683

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1/** @file
2 * GCM - Guest Compatibility Manager - All Contexts.
3 */
4
5/*
6 * Copyright (C) 2022-2023 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 <iprt/errcore.h>
38#include <iprt/string.h>
39
40
41
42/**
43 * Whether \#DE exceptions in the guest should be intercepted by GCM and
44 * possibly fixed up.
45 *
46 * @returns true if needed, false otherwise.
47 * @param pVCpu The cross context virtual CPU structure.
48 */
49VMM_INT_DECL(bool) GCMIsInterceptingXcptDE(PVMCPUCC pVCpu)
50{
51 /* See if the enabled fixers need to intercept #DE. */
52 PVM const pVM = pVCpu->CTX_SUFF(pVM);
53 bool const fRet = (pVM->gcm.s.fFixerSet & (GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2 | GCMFIXER_DBZ_WIN9X)) != 0;
54 LogFlow(("GCMIsInterceptingXcptDE: returns %d\n", fRet));
55 return fRet;
56}
57
58
59/**
60 * Exception handler for \#DE when registered by GCM.
61 *
62 * @returns VBox status code.
63 * @retval VINF_SUCCESS retry division and continue.
64 * @retval VERR_NOT_FOUND deliver exception to guest.
65 *
66 * @param pVCpu The cross context virtual CPU structure.
67 * @param pCtx Pointer to the guest-CPU context.
68 *
69 * @thread EMT(pVCpu).
70 */
71VMM_INT_DECL(int) GCMXcptDE(PVMCPUCC pVCpu, PCPUMCTX pCtx)
72{
73 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
74 Assert(pVM->gcm.s.fFixerSet & (GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2 | GCMFIXER_DBZ_WIN9X));
75
76 LogRel(("GCM: Intercepted #DE at CS:RIP=%04x:%RX64 (%RX64 linear) RDX:RAX=%RX64:%RX64 RCX=%RX64 RBX=%RX64\n",
77 pCtx->cs.Sel, pCtx->rip, pCtx->cs.u64Base + pCtx->rip, pCtx->rdx, pCtx->rax, pCtx->rcx, pCtx->rbx));
78
79 if (pVM->gcm.s.fFixerSet & GCMFIXER_DBZ_OS2)
80 {
81 if (pCtx->rcx == 0 && pCtx->rdx == 1 && pCtx->rax == 0x86a0)
82 {
83 /* OS/2 1.x drivers loaded during boot: DX:AX = 100,000, CX < 2 causes overflow. */
84 /* Example: OS/2 1.0 KBD01.SYS, 16,945 bytes, dated 10/21/1987, div cx at offset 2:2ffeh */
85 /* Code later merged into BASEDD01.SYS, crash fixed in OS/2 1.30.1; this should
86 * fix all affected versions of OS/2 1.x.
87 */
88 pCtx->rcx = 2;
89 return VINF_SUCCESS;
90 }
91 if ((uint16_t)pCtx->rbx == 0 && (uint16_t)pCtx->rdx == 0 && (uint16_t)pCtx->rax == 0x1000)
92 {
93 /* OS/2 2.1 and later boot loader: DX:AX = 0x1000, zero BX. May have junk in high words of all registers. */
94 /* Example: OS/2 MCP2 OS2LDR, 44,544 bytes, dated 03/08/2002, idiv bx at offset 847ah */
95 pCtx->rbx = (pCtx->rbx & ~0xffff) | 2;
96 return VINF_SUCCESS;
97 }
98 if (pCtx->rbx == 0 && pCtx->rdx == 0 && pCtx->rax == 0x100)
99 {
100 /* OS/2 2.0 boot loader: DX:AX = 0x100, zero BX. May have junk in high words of registers. */
101 /* Example: OS/2 2.0 OS2LDR, 32,256 bytes, dated 03/30/1992, idiv bx at offset 2298h */
102 pCtx->rbx = 2;
103 return VINF_SUCCESS;
104 }
105 }
106
107 if (pVM->gcm.s.fFixerSet & GCMFIXER_DBZ_DOS)
108 {
109 /* NB: For 16-bit DOS software, we must generally only compare 16-bit registers.
110 * The contents of the high words may be unpredictable depending on the environment.
111 * For 32-bit Windows 3.x code that is not the case.
112 */
113 if (pCtx->rcx == 0 && pCtx->rdx == 0 && pCtx->rax == 0x100000)
114 {
115 /* NDIS.386 in WfW 3.11: CalibrateStall, EDX:EAX = 0x100000, zero ECX.
116 * Occurs when NDIS.386 loads.
117 */
118 pCtx->rcx = 0x20000; /* Want a large divisor to shorten stalls. */
119 return VINF_SUCCESS;
120 }
121 if (pCtx->rcx == 0 && pCtx->rdx == 0 && pCtx->rax > 0x100000)
122 {
123 /* NDIS.386 in WfW 3.11: NdisStallExecution, EDX:EAX = 0xYY00000, zero ECX.
124 * EDX:EAX is variable, but low 20 bits of EAX must be zero and EDX is likely
125 * to be zero as well.
126 * Only occurs if NdisStallExecution is called to do a longish stall.
127 */
128 pCtx->rcx = 22;
129 return VINF_SUCCESS;
130 }
131 if ((uint16_t)pCtx->rbx == 0 && (uint16_t)pCtx->rdx == 0 && (uint16_t)pCtx->rax == 0x64)
132 {
133 /* Norton Sysinfo or Diagnostics 8.0 DX:AX = 0x64 (100 decimal), zero BX. */
134 pCtx->rbx = (pCtx->rbx & 0xffff0000) | 1; /* BX = 1 */
135 return VINF_SUCCESS;
136 }
137 if ((uint16_t)pCtx->rbx == 0 && (uint16_t)pCtx->rdx == 0 && (uint16_t)pCtx->rax == 0xff)
138 {
139 /* IBM PC LAN Program 1.3: DX:AX=0xff (255 decimal), zero BX. */
140 /* NETWORK1.CMD, 64,324 bytes, dated 06/06/1988, div bx at offset 0xa400 in file. */
141 pCtx->rbx = (pCtx->rbx & 0xffff0000) | 1; /* BX = 1 */
142 return VINF_SUCCESS;
143 }
144 if ((uint16_t)pCtx->rdx == 0xffff && (uint16_t)pCtx->rax == 0xffff && (uint16_t)pCtx->rcx == 0xa8c0)
145 {
146 /* QNX 2.15C: DX:AX=0xffffffff (-1), constant CX = 0xa8c0 (43200). */
147 /* div cx at e.g. 2220:fa5 and 2220:10a0 in memory. */
148 pCtx->rdx = (pCtx->rdx & 0xffff0000) | 8; /* DX = 8 */
149 return VINF_SUCCESS;
150 }
151 if ((uint16_t)pCtx->rax > 0x1800 && ((uint16_t)pCtx->rax & 0x3f) == 0 && (uint16_t)pCtx->rbx == 0x19)
152 {
153 /* 3C501.COM ODI driver v1.21: AX > ~0x1900 (-1), BX = 0x19 (25). */
154 /* AX was shifted left by 6 bits so low bits must be zero. */
155 /* div bl at e.g. 06b3:2f80 and offset 0x2E80 in file. */
156 pCtx->rax = (pCtx->rax & 0xffff0000) | 0x8c0; /* AX = 0x8c0 */
157 return VINF_SUCCESS;
158 }
159 if ((uint16_t)pCtx->rcx == 0x37 && ((uint16_t)pCtx->rdx > 0x34))
160 {
161 /* Turbo Pascal, classic Runtime Error 200: CX = 55, DX > ~54, AX/BX variable. */
162 /* div cx at variable offset in file. */
163 pCtx->rdx = (pCtx->rdx & 0xffff0000) | 0x30; /* DX = 48 */
164 return VINF_SUCCESS;
165 }
166 }
167
168 if (pVM->gcm.s.fFixerSet & GCMFIXER_DBZ_WIN9X)
169 {
170 if (pCtx->rcx == 0 && pCtx->rdx == 0 && pCtx->rax == 0x100000)
171 {
172 /* NDIS.VXD in Win9x: EDX:EAX = 0x100000, zero ECX. */
173 /* Example: Windows 95 NDIS.VXD, 99,084 bytes, dated 07/11/1994, div ecx at 28:Cxxxx80B */
174 /* Crash fixed in Windows 98 SE. */
175 pCtx->rcx = 0x20000; /* Want a large divisor to shorten stalls. */
176 return VINF_SUCCESS;
177 }
178 if (pCtx->rcx < 3 && pCtx->rdx == 2 && pCtx->rax == 0x540be400)
179 {
180 /* SCSI.PDR, ESDI506.PDR in Win95: EDX:EAX = 0x2540be400 (10,000,000,000 decimal), ECX < 3. */
181 /* Example: Windows 95 SCSIPORT.PDR, 23,133 bytes, dated 07/11/1995, div ecx at 28:Cxxxx876 */
182 /* Example: Win95 OSR2 ESDI506.PDR, 24,390 bytes, dated 04/24/1996, div ecx at 28:Cxxxx8E3 */
183 /* Crash fixed in Windows 98. */
184 pCtx->rcx = 1000;
185 return VINF_SUCCESS;
186 }
187 if (pCtx->rcx == 0 && pCtx->rdx == 0x3d && pCtx->rax == 0x9000000)
188 {
189 /* Unknown source, Win9x shutdown, div ecx. */
190 /* GCM: Intercepted #DE at CS:RIP=0028:c0050f8e RDX:RAX=3d:9000000 (250000*1024*1024) RCX=0 RBX=c19200e8 [RBX variable] */
191 pCtx->rcx = 4096;
192 return VINF_SUCCESS;
193 }
194 }
195
196 /* If we got this far, deliver exception to guest. */
197 return VERR_NOT_FOUND;
198}
199
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