VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/NEMR3.cpp@ 72403

Last change on this file since 72403 was 72343, checked in by vboxsync, 7 years ago

VMM,ConsoleImpl2: NEM and 64-bit guests. Sync NXE state with PGM. bugref:9044

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/* $Id: NEMR3.cpp 72343 2018-05-25 13:24:28Z vboxsync $ */
2/** @file
3 * NEM - Native execution manager.
4 */
5
6/*
7 * Copyright (C) 2018 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/** @page pg_nem NEM - Native Execution Manager.
19 *
20 * This is an alternative execution manage to HM and raw-mode. On one host
21 * (Windows) we're forced to use this, on the others we just do it because we
22 * can. Since this is host specific in nature, information about an
23 * implementation is contained in the NEMR3Native-xxxx.cpp files.
24 *
25 * @ref pg_nem_win
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_NEM
33#include <VBox/vmm/nem.h>
34#include "NEMInternal.h"
35#include <VBox/vmm/vm.h>
36#include <VBox/vmm/uvm.h>
37
38#include <iprt/asm.h>
39
40
41
42/**
43 * Basic init and configuration reading.
44 *
45 * Always call NEMR3Term after calling this.
46 *
47 * @returns VBox status code.
48 * @param pVM The cross context VM structure.
49 */
50VMMR3_INT_DECL(int) NEMR3InitConfig(PVM pVM)
51{
52 LogFlow(("NEMR3Init\n"));
53
54 /*
55 * Assert alignment and sizes.
56 */
57 AssertCompileMemberAlignment(VM, nem.s, 64);
58 AssertCompile(sizeof(pVM->nem.s) <= sizeof(pVM->nem.padding));
59
60 /*
61 * Initialize state info so NEMR3Term will always be happy.
62 * No returning prior to setting magics!
63 */
64 pVM->nem.s.u32Magic = NEM_MAGIC;
65 for (VMCPUID iCpu = 0; iCpu < pVM->cCpus; iCpu++)
66 pVM->aCpus[iCpu].nem.s.u32Magic = NEMCPU_MAGIC;
67
68 /*
69 * Read configuration.
70 */
71 PCFGMNODE pCfgNem = CFGMR3GetChild(CFGMR3GetRoot(pVM), "NEM/");
72
73 /*
74 * Validate the NEM settings.
75 */
76 int rc = CFGMR3ValidateConfig(pCfgNem,
77 "/NEM/",
78 "Enabled"
79 "|Allow64BitGuests",
80 "" /* pszValidNodes */, "NEM" /* pszWho */, 0 /* uInstance */);
81 if (RT_FAILURE(rc))
82 return rc;
83
84 /** @cfgm{/NEM/NEMEnabled, bool, true}
85 * Whether NEM is enabled. */
86 rc = CFGMR3QueryBoolDef(pCfgNem, "Enabled", &pVM->nem.s.fEnabled, true);
87 AssertLogRelRCReturn(rc, rc);
88
89
90#ifdef VBOX_WITH_64_BITS_GUESTS
91 /** @cfgm{/HM/Allow64BitGuests, bool, 32-bit:false, 64-bit:true}
92 * Enables AMD64 CPU features.
93 * On 32-bit hosts this isn't default and require host CPU support. 64-bit hosts
94 * already have the support. */
95 rc = CFGMR3QueryBoolDef(pCfgNem, "Allow64BitGuests", &pVM->nem.s.fAllow64BitGuests, HC_ARCH_BITS == 64);
96 AssertLogRelRCReturn(rc, rc);
97#else
98 pVM->nem.s.fAllow64BitGuests = false;
99#endif
100
101
102 return VINF_SUCCESS;
103}
104
105
106/**
107 * This is called by HMR3Init() when HM cannot be used.
108 *
109 * Sets VM::bMainExecutionEngine to VM_EXEC_ENGINE_NATIVE_API if we can use a
110 * native hypervisor API to execute the VM.
111 *
112 * @returns VBox status code.
113 * @param pVM The cross context VM structure.
114 * @param fFallback Whether this is a fallback call. Cleared if the VM is
115 * configured to use NEM instead of HM.
116 * @param fForced Whether /HM/HMForced was set. If set and we fail to
117 * enable NEM, we'll return a failure status code.
118 * Otherwise we'll assume HMR3Init falls back on raw-mode.
119 */
120VMMR3_INT_DECL(int) NEMR3Init(PVM pVM, bool fFallback, bool fForced)
121{
122 Assert(pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NATIVE_API);
123 int rc;
124 if (pVM->nem.s.fEnabled)
125 {
126#ifdef VBOX_WITH_NATIVE_NEM
127 rc = nemR3NativeInit(pVM, fFallback, fForced);
128 ASMCompilerBarrier(); /* May have changed bMainExecutionEngine. */
129#else
130 RT_NOREF(fFallback);
131 rc = VINF_SUCCESS;
132#endif
133 if (RT_SUCCESS(rc))
134 {
135 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
136 LogRel(("NEM: NEMR3Init: Active.\n"));
137 else
138 {
139 LogRel(("NEM: NEMR3Init: Not available.\n"));
140 if (fForced)
141 rc = VERR_NEM_NOT_AVAILABLE;
142 }
143 }
144 else
145 LogRel(("NEM: NEMR3Init: Native init failed: %Rrc.\n", rc));
146 }
147 else
148 {
149 LogRel(("NEM: NEMR3Init: Disabled.\n"));
150 rc = fForced ? VERR_NEM_NOT_ENABLED : VINF_SUCCESS;
151 }
152 return rc;
153}
154
155
156/**
157 * Perform initialization that depends on CPUM working.
158 *
159 * This is a noop if NEM wasn't activated by a previous NEMR3Init() call.
160 *
161 * @returns VBox status code.
162 * @param pVM The cross context VM structure.
163 */
164VMMR3_INT_DECL(int) NEMR3InitAfterCPUM(PVM pVM)
165{
166 int rc = VINF_SUCCESS;
167 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
168 {
169 /*
170 * Enable CPU features making general ASSUMPTIONS (there are two similar
171 * blocks of code in HM.cpp), to avoid duplicating this code. The
172 * native backend can make check capabilities and adjust as needed.
173 */
174 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SEP);
175 if (CPUMGetGuestCpuVendor(pVM) == CPUMCPUVENDOR_AMD)
176 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SYSCALL); /* 64 bits only on Intel CPUs */
177 if (pVM->nem.s.fAllow64BitGuests)
178 {
179 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SYSCALL);
180 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_PAE);
181 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_LONG_MODE);
182 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_LAHF);
183 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
184 }
185 /* Turn on NXE if PAE has been enabled. */
186 else if (CPUMR3GetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_PAE))
187 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
188
189 /*
190 * Do native after-CPUM init.
191 */
192#ifdef VBOX_WITH_NATIVE_NEM
193 rc = nemR3NativeInitAfterCPUM(pVM);
194#else
195 RT_NOREF(pVM);
196#endif
197 }
198 return rc;
199}
200
201
202/**
203 * Called when a init phase has completed.
204 *
205 * @returns VBox status code.
206 * @param pVM The cross context VM structure.
207 * @param enmWhat The phase that completed.
208 */
209VMMR3_INT_DECL(int) NEMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
210{
211 int rc = VINF_SUCCESS;
212#ifdef VBOX_WITH_NATIVE_NEM
213 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
214 rc = nemR3NativeInitCompleted(pVM, enmWhat);
215#else
216 RT_NOREF(pVM, enmWhat);
217#endif
218 return rc;
219}
220
221
222/**
223 *
224 * @returns VBox status code.
225 * @param pVM The cross context VM structure.
226 */
227VMMR3_INT_DECL(int) NEMR3Term(PVM pVM)
228{
229 AssertReturn(pVM->nem.s.u32Magic == NEM_MAGIC, VERR_WRONG_ORDER);
230 for (VMCPUID iCpu = 0; iCpu < pVM->cCpus; iCpu++)
231 AssertReturn(pVM->aCpus[iCpu].nem.s.u32Magic == NEMCPU_MAGIC, VERR_WRONG_ORDER);
232
233 /* Do native termination. */
234 int rc = VINF_SUCCESS;
235#ifdef VBOX_WITH_NATIVE_NEM
236 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
237 rc = nemR3NativeTerm(pVM);
238#endif
239
240 /* Mark it as terminated. */
241 for (VMCPUID iCpu = 0; iCpu < pVM->cCpus; iCpu++)
242 pVM->aCpus[iCpu].nem.s.u32Magic = NEMCPU_MAGIC_DEAD;
243 pVM->nem.s.u32Magic = NEM_MAGIC_DEAD;
244 return rc;
245}
246
247/**
248 * External interface for querying whether native execution API is used.
249 *
250 * @returns true if NEM is being used, otherwise false.
251 * @param pUVM The user mode VM handle.
252 * @sa HMR3IsEnabled
253 */
254VMMR3DECL(bool) NEMR3IsEnabled(PUVM pUVM)
255{
256 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
257 PVM pVM = pUVM->pVM;
258 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
259 return VM_IS_NEM_ENABLED(pVM);
260}
261
262
263/**
264 * The VM is being reset.
265 *
266 * @param pVM The cross context VM structure.
267 */
268VMMR3_INT_DECL(void) NEMR3Reset(PVM pVM)
269{
270#ifdef VBOX_WITH_NATIVE_NEM
271 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
272 nemR3NativeReset(pVM);
273#else
274 RT_NOREF(pVM);
275#endif
276}
277
278
279/**
280 * Resets a virtual CPU.
281 *
282 * Used to bring up secondary CPUs on SMP as well as CPU hot plugging.
283 *
284 * @param pVCpu The cross context virtual CPU structure to reset.
285 * @param fInitIpi Set if being reset due to INIT IPI.
286 */
287VMMR3_INT_DECL(void) NEMR3ResetCpu(PVMCPU pVCpu, bool fInitIpi)
288{
289#ifdef VBOX_WITH_NATIVE_NEM
290 if (pVCpu->pVMR3->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
291 nemR3NativeResetCpu(pVCpu, fInitIpi);
292#else
293 RT_NOREF(pVCpu, fInitIpi);
294#endif
295}
296
297
298VMMR3_INT_DECL(VBOXSTRICTRC) NEMR3RunGC(PVM pVM, PVMCPU pVCpu)
299{
300 Assert(VM_IS_NEM_ENABLED(pVM));
301#ifdef VBOX_WITH_NATIVE_NEM
302 return nemR3NativeRunGC(pVM, pVCpu);
303#else
304 NOREF(pVM); NOREF(pVCpu);
305 return VERR_INTERNAL_ERROR_3;
306#endif
307}
308
309
310VMMR3_INT_DECL(bool) NEMR3CanExecuteGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
311{
312 Assert(VM_IS_NEM_ENABLED(pVM));
313#ifdef VBOX_WITH_NATIVE_NEM
314 return nemR3NativeCanExecuteGuest(pVM, pVCpu, pCtx);
315#else
316 NOREF(pVM); NOREF(pVCpu); NOREF(pCtx);
317 return false;
318#endif
319}
320
321
322VMMR3_INT_DECL(bool) NEMR3SetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable)
323{
324 Assert(VM_IS_NEM_ENABLED(pVM));
325#ifdef VBOX_WITH_NATIVE_NEM
326 return nemR3NativeSetSingleInstruction(pVM, pVCpu, fEnable);
327#else
328 NOREF(pVM); NOREF(pVCpu); NOREF(fEnable);
329 return false;
330#endif
331}
332
333
334VMMR3_INT_DECL(void) NEMR3NotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags)
335{
336 AssertLogRelReturnVoid(VM_IS_NEM_ENABLED(pVM));
337#ifdef VBOX_WITH_NATIVE_NEM
338 nemR3NativeNotifyFF(pVM, pVCpu, fFlags);
339#else
340 RT_NOREF(pVM, pVCpu, fFlags);
341#endif
342}
343
344
345
346
347VMMR3_INT_DECL(int) NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb)
348{
349 int rc = VINF_SUCCESS;
350#ifdef VBOX_WITH_NATIVE_NEM
351 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
352 rc = nemR3NativeNotifyPhysRamRegister(pVM, GCPhys, cb);
353#else
354 NOREF(pVM); NOREF(GCPhys); NOREF(cb);
355#endif
356 return rc;
357}
358
359
360VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, void *pvMmio2)
361{
362 int rc = VINF_SUCCESS;
363#ifdef VBOX_WITH_NATIVE_NEM
364 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
365 rc = nemR3NativeNotifyPhysMmioExMap(pVM, GCPhys, cb, fFlags, pvMmio2);
366#else
367 NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags); NOREF(pvMmio2);
368#endif
369 return rc;
370}
371
372
373VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
374{
375 int rc = VINF_SUCCESS;
376#ifdef VBOX_WITH_NATIVE_NEM
377 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
378 rc = nemR3NativeNotifyPhysMmioExUnmap(pVM, GCPhys, cb, fFlags);
379#else
380 NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
381#endif
382 return rc;
383}
384
385
386VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
387{
388 int rc = VINF_SUCCESS;
389#ifdef VBOX_WITH_NATIVE_NEM
390 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
391 rc = nemR3NativeNotifyPhysRomRegisterEarly(pVM, GCPhys, cb, fFlags);
392#else
393 NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
394#endif
395 return rc;
396}
397
398
399/**
400 * Called after the ROM range has been fully completed.
401 *
402 * This will be preceeded by a NEMR3NotifyPhysRomRegisterEarly() call as well a
403 * number of NEMHCNotifyPhysPageProtChanged calls.
404 *
405 * @returns VBox status code
406 * @param pVM The cross context VM structure.
407 * @param GCPhys The ROM address (page aligned).
408 * @param cb The size (page aligned).
409 * @param fFlags NEM_NOTIFY_PHYS_ROM_F_XXX.
410 */
411VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
412{
413 int rc = VINF_SUCCESS;
414#ifdef VBOX_WITH_NATIVE_NEM
415 if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
416 rc = nemR3NativeNotifyPhysRomRegisterLate(pVM, GCPhys, cb, fFlags);
417#else
418 NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
419#endif
420 return rc;
421}
422
423
424VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled)
425{
426#ifdef VBOX_WITH_NATIVE_NEM
427 if (pVCpu->pVMR3->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
428 nemR3NativeNotifySetA20(pVCpu, fEnabled);
429#else
430 NOREF(pVCpu); NOREF(fEnabled);
431#endif
432}
433
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