VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/GCM.cpp@ 95638

Last change on this file since 95638 was 94882, checked in by vboxsync, 3 years ago

VMM: First stab at Guest Compatibility Manager, fixing up things like division overflows caused by fast CPUs (see bugref:9735).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1/** @file
2 * GCM - Guest Compatibility Manager.
3 */
4
5/*
6 * Copyright (C) 2022 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17/** @page pg_gcm GCM - The Guest Compatibility Manager
18 *
19 * The Guest Compatibility Manager provides run-time compatibility fixes
20 * for certain known guest bugs.
21 *
22 * @see grp_gcm
23 *
24 *
25 * @section sec_gcm_fixer Fixers
26 *
27 * A GCM fixer implements a collection of run-time helpers/patches suitable for
28 * a specific guest type. Several fixers can be active at the same time; for
29 * example OS/2 or Windows 9x need their own fixers, but can also runs DOS
30 * applications which need DOS-specific fixers.
31 *
32 * The concept of fixers exists to reduce the number of false positives to a
33 * minimum. Heuristics are used to decide whether a particular fix should be
34 * applied or not; restricting the number of applicable fixes minimizes the
35 * chance that a fix could be misapplied.
36 *
37 * The fixers are invisible to a guest. A common problem is division by zero
38 * caused by a software timing loop which cannot deal with fast CPUs (where
39 * "fast" very much depends on the era when the software was written). A fixer
40 * intercepts division by zero, recognizes known register contents and code
41 * sequence, modifies one or more registers to avoid a divide error, and
42 * restarts the instruction.
43 *
44 * It is not expected that the set of active fixers would be changed during
45 * the lifetime of the VM.
46 */
47
48
49/*********************************************************************************************************************************
50* Header Files *
51*********************************************************************************************************************************/
52#define LOG_GROUP LOG_GROUP_GIM
53#include <VBox/vmm/gcm.h>
54#include <VBox/vmm/hm.h>
55#include <VBox/vmm/ssm.h>
56#include <VBox/vmm/pdmdev.h>
57#include "GCMInternal.h"
58#include <VBox/vmm/vm.h>
59
60#include <VBox/log.h>
61
62#include <iprt/err.h>
63#include <iprt/semaphore.h>
64#include <iprt/string.h>
65
66
67/*********************************************************************************************************************************
68* Internal Functions *
69*********************************************************************************************************************************/
70static FNSSMINTSAVEEXEC gcmR3Save;
71static FNSSMINTLOADEXEC gcmR3Load;
72
73
74/**
75 * Initializes the GCM.
76 *
77 * @returns VBox status code.
78 * @param pVM The cross context VM structure.
79 */
80VMMR3_INT_DECL(int) GCMR3Init(PVM pVM)
81{
82 LogFlow(("GCMR3Init\n"));
83
84 /*
85 * Assert alignment and sizes.
86 */
87 AssertCompile(sizeof(pVM->gcm.s) <= sizeof(pVM->gcm.padding));
88
89 /*
90 * Register the saved state data unit.
91 */
92 int rc = SSMR3RegisterInternal(pVM, "GCM", 0 /* uInstance */, GCM_SAVED_STATE_VERSION, sizeof(GCM),
93 NULL /* pfnLivePrep */, NULL /* pfnLiveExec */, NULL /* pfnLiveVote*/,
94 NULL /* pfnSavePrep */, gcmR3Save, NULL /* pfnSaveDone */,
95 NULL /* pfnLoadPrep */, gcmR3Load, NULL /* pfnLoadDone */);
96 if (RT_FAILURE(rc))
97 return rc;
98
99 /*
100 * Read configuration.
101 */
102 PCFGMNODE pCfgNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "GCM/");
103
104 /*
105 * Validate the GCM settings.
106 */
107 rc = CFGMR3ValidateConfig(pCfgNode, "/GCM/", /* pszNode */
108 "FixerSet", /* pszValidValues */
109 "", /* pszValidNodes */
110 "GCM", /* pszWho */
111 0); /* uInstance */
112 if (RT_FAILURE(rc))
113 return rc;
114
115#if 1
116 /** @cfgm{/GCM/FixerSet, uint32_t, 0}
117 * The set (bit mask) of enabled fixers. See GCMFIXERID.
118 */
119 uint32_t u32FixerIds;
120 rc = CFGMR3QueryU32Def(pCfgNode, "FixerSet", &u32FixerIds, 0);
121 AssertRCReturn(rc, rc);
122
123 /* Check for unknown bits. */
124 uint32_t u32BadBits = u32FixerIds & ~(GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2 | GCMFIXER_DBZ_WIN9X);
125
126 if (u32BadBits)
127 {
128 rc = VMR3SetError(pVM->pUVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS, "Unsupported GCM fixer bits (%#x) set.", u32BadBits);
129 }
130 else
131 {
132 pVM->gcm.s.enmFixerIds = u32FixerIds;
133 }
134#else
135 pVM->gcm.s.enmFixerIds = GCMFIXER_DBZ_OS2 | GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_WIN9X;
136#endif
137 LogRel(("GCM: Initialized (fixer bits: %#x)\n", u32FixerIds));
138
139 return rc;
140}
141
142
143/**
144 * Finalize the GCM initialization.
145 *
146 * This is called after initializing HM and most other VMM components.
147 *
148 * @returns VBox status code.
149 * @param pVM The cross context VM structure.
150 * @thread EMT(0)
151 */
152VMMR3_INT_DECL(int) GCMR3InitCompleted(PVM pVM)
153{
154 RT_NOREF(pVM);
155 return VINF_SUCCESS;
156}
157
158
159/**
160 * @callback_method_impl{FNSSMINTSAVEEXEC}
161 */
162static DECLCALLBACK(int) gcmR3Save(PVM pVM, PSSMHANDLE pSSM)
163{
164 AssertReturn(pVM, VERR_INVALID_PARAMETER);
165 AssertReturn(pSSM, VERR_SSM_INVALID_STATE);
166
167 int rc = VINF_SUCCESS;
168
169 /*
170 * Save per-VM data.
171 */
172 SSMR3PutU32(pSSM, pVM->gcm.s.enmFixerIds);
173
174 return rc;
175}
176
177
178/**
179 * @callback_method_impl{FNSSMINTLOADEXEC}
180 */
181static DECLCALLBACK(int) gcmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
182{
183 if (uPass != SSM_PASS_FINAL)
184 return VINF_SUCCESS;
185 if (uVersion != GCM_SAVED_STATE_VERSION)
186 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
187
188 int rc;
189
190 /*
191 * Load per-VM data.
192 */
193 uint32_t uFixerIds;
194
195 rc = SSMR3GetU32(pSSM, &uFixerIds);
196 AssertRCReturn(rc, rc);
197
198 if ((GCMFIXERID)uFixerIds != pVM->gcm.s.enmFixerIds)
199 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Saved GCM fixer set %#X differs from the configured one (%#X)."),
200 uFixerIds, pVM->gcm.s.enmFixerIds);
201
202 return VINF_SUCCESS;
203}
204
205
206/**
207 * Terminates the GCM.
208 *
209 * Termination means cleaning up and freeing all resources,
210 * the VM itself is, at this point, powered off or suspended.
211 *
212 * @returns VBox status code.
213 * @param pVM The cross context VM structure.
214 */
215VMMR3_INT_DECL(int) GCMR3Term(PVM pVM)
216{
217 RT_NOREF(pVM);
218 return VINF_SUCCESS;
219}
220
221
222/**
223 * Applies relocations to data and code managed by this
224 * component. This function will be called at init and
225 * whenever the VMM need to relocate itself inside the GC.
226 *
227 * @param pVM The cross context VM structure.
228 * @param offDelta Relocation delta relative to old location.
229 */
230VMMR3_INT_DECL(void) GCMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
231{
232 RT_NOREF(pVM);
233 RT_NOREF(offDelta);
234}
235
236
237/**
238 * The VM is being reset.
239 *
240 * Do whatever fixer-specific resetting that needs to be done.
241 *
242 * @returns VBox status code.
243 * @param pVM The cross context VM structure.
244 */
245VMMR3_INT_DECL(void) GCMR3Reset(PVM pVM)
246{
247 RT_NOREF(pVM);
248}
249
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