VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/HM-armv8.cpp@ 106952

Last change on this file since 106952 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.7 KB
Line 
1/* $Id: HM-armv8.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * HM - VM Hardware Support Manager, ARMv8 shim.
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/** @page pg_hm_armv8 HM - Hardware Assisted Virtualization Manager
29 *
30 * This is just a stub for ARMv8 which is bound to use NEM exclusively for the time being.
31 * But to not mess up the upper layers too much for now this is really tiny shim which takes
32 * of initializing NEM like it is done on AMD64.
33 *
34 * @sa @ref grp_hm
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP LOG_GROUP_HM
42#define VMCPU_INCL_CPUM_GST_CTX
43#include <VBox/vmm/cpum.h>
44#include <VBox/vmm/stam.h>
45#include <VBox/vmm/em.h>
46#include <VBox/vmm/pdmapi.h>
47#include <VBox/vmm/pgm.h>
48#include <VBox/vmm/ssm.h>
49#include <VBox/vmm/gim.h>
50#include <VBox/vmm/gcm.h>
51#include <VBox/vmm/trpm.h>
52#include <VBox/vmm/dbgf.h>
53#include <VBox/vmm/iom.h>
54#include <VBox/vmm/iem.h>
55#include <VBox/vmm/selm.h>
56#include <VBox/vmm/nem.h>
57#include <VBox/vmm/hm_vmx.h>
58#include <VBox/vmm/hm_svm.h>
59#include "HMInternal.h"
60#include <VBox/vmm/vmcc.h>
61#include <VBox/err.h>
62#include <VBox/param.h>
63
64#include <iprt/assert.h>
65#include <VBox/log.h>
66#include <iprt/asm.h>
67#include <iprt/env.h>
68#include <iprt/thread.h>
69
70
71/*********************************************************************************************************************************
72* Defined Constants And Macros *
73*********************************************************************************************************************************/
74
75
76/*********************************************************************************************************************************
77* Internal Functions *
78*********************************************************************************************************************************/
79static int hmR3InitFinalizeR3(PVM pVM);
80static int hmR3TermCPU(PVM pVM);
81
82
83/**
84 * Initializes the HM.
85 *
86 * This is the very first component to really do init after CFGM so that we can
87 * establish the predominant execution engine for the VM prior to initializing
88 * other modules. It takes care of NEM initialization if needed (HM disabled or
89 * not available in HW).
90 *
91 * If VT-x or AMD-V hardware isn't available, HM will try fall back on a native
92 * hypervisor API via NEM, and then back on raw-mode if that isn't available
93 * either. The fallback to raw-mode will not happen if /HM/HMForced is set
94 * (like for guest using SMP or 64-bit as well as for complicated guest like OS
95 * X, OS/2 and others).
96 *
97 * Note that a lot of the set up work is done in ring-0 and thus postponed till
98 * the ring-3 and ring-0 callback to HMR3InitCompleted.
99 *
100 * @returns VBox status code.
101 * @param pVM The cross context VM structure.
102 *
103 * @remarks Be careful with what we call here, since most of the VMM components
104 * are uninitialized.
105 */
106VMMR3_INT_DECL(int) HMR3Init(PVM pVM)
107{
108 LogFlowFunc(("\n"));
109
110 /*
111 * Assert alignment and sizes.
112 */
113 AssertCompileMemberAlignment(VM, hm.s, 32);
114 AssertCompile(sizeof(pVM->hm.s) <= sizeof(pVM->hm.padding));
115
116 /*
117 * Read configuration.
118 */
119 PCFGMNODE pCfgHm = CFGMR3GetChild(CFGMR3GetRoot(pVM), "HM/");
120
121 /*
122 * Validate the HM settings.
123 */
124#if 0
125 int rc = CFGMR3ValidateConfig(pCfgHm, "/HM/",
126 "|FallbackToIEM"
127 , "" /* pszValidNodes */, "HM" /* pszWho */, 0 /* uInstance */);
128 if (RT_FAILURE(rc))
129 return rc;
130#else
131 int rc;
132#endif
133
134 AssertRelease(!pVM->fHMEnabled);
135
136 /** @cfgm{/HM/FallbackToIEM, bool, false on AMD64 else true }
137 * Enables fallback on NEM. */
138 bool fFallbackToIEM = true;
139 rc = CFGMR3QueryBoolDef(pCfgHm, "FallbackToIEM", &fFallbackToIEM, true);
140 AssertRCReturn(rc, rc);
141
142 /*
143 * Disabled HM mean raw-mode, unless NEM is supposed to be used.
144 */
145 rc = NEMR3Init(pVM, false /*fFallback*/, true);
146 ASMCompilerBarrier(); /* NEMR3Init may have changed bMainExecutionEngine. */
147 if (RT_SUCCESS(rc))
148 {
149 /* For some reason, HM is in charge or large pages. Make sure to enable them: */
150 //PGMSetLargePageUsage(pVM, pVM->hm.s.fLargePages);
151 }
152 else if (!fFallbackToIEM || rc != VERR_NEM_NOT_AVAILABLE)
153 return rc;
154
155 if (fFallbackToIEM && rc == VERR_NEM_NOT_AVAILABLE)
156 {
157 LogRel(("HM: HMR3Init: Falling back on IEM: NEM not available"));
158 VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_IEM);
159#ifdef VBOX_WITH_PGM_NEM_MODE
160 PGMR3EnableNemMode(pVM);
161#endif
162 }
163
164 if ( pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NOT_SET
165 || pVM->bMainExecutionEngine == VM_EXEC_ENGINE_HW_VIRT /* paranoia */)
166 return VM_SET_ERROR(pVM, rc, "Misconfigured VM: No guest execution engine available!");
167
168 Assert(pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NOT_SET);
169 return VINF_SUCCESS;
170}
171
172
173/**
174 * Initializes HM components after ring-3 phase has been fully initialized.
175 *
176 * @returns VBox status code.
177 * @param pVM The cross context VM structure.
178 */
179static int hmR3InitFinalizeR3(PVM pVM)
180{
181 LogFlowFunc(("\n"));
182 RT_NOREF(pVM);
183 return VINF_SUCCESS;
184}
185
186
187/**
188 * Called when a init phase has completed.
189 *
190 * @returns VBox status code.
191 * @param pVM The cross context VM structure.
192 * @param enmWhat The phase that completed.
193 */
194VMMR3_INT_DECL(int) HMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
195{
196 switch (enmWhat)
197 {
198 case VMINITCOMPLETED_RING3:
199 return hmR3InitFinalizeR3(pVM);
200 default:
201 return VINF_SUCCESS;
202 }
203}
204
205
206/**
207 * Applies relocations to data and code managed by this
208 * component. This function will be called at init and
209 * whenever the VMM need to relocate it self inside the GC.
210 *
211 * @param pVM The cross context VM structure.
212 */
213VMMR3_INT_DECL(void) HMR3Relocate(PVM pVM)
214{
215 RT_NOREF(pVM);
216}
217
218
219/**
220 * Terminates the HM.
221 *
222 * Termination means cleaning up and freeing all resources,
223 * the VM itself is, at this point, powered off or suspended.
224 *
225 * @returns VBox status code.
226 * @param pVM The cross context VM structure.
227 */
228VMMR3_INT_DECL(int) HMR3Term(PVM pVM)
229{
230 hmR3TermCPU(pVM);
231 return VINF_SUCCESS;
232}
233
234
235/**
236 * Terminates the per-VCPU HM.
237 *
238 * @returns VBox status code.
239 * @param pVM The cross context VM structure.
240 */
241static int hmR3TermCPU(PVM pVM)
242{
243 RT_NOREF(pVM);
244 return VINF_SUCCESS;
245}
246
247
248/**
249 * Resets a virtual CPU.
250 *
251 * Used by HMR3Reset and CPU hot plugging.
252 *
253 * @param pVCpu The cross context virtual CPU structure to reset.
254 */
255VMMR3_INT_DECL(void) HMR3ResetCpu(PVMCPU pVCpu)
256{
257 RT_NOREF(pVCpu);
258}
259
260
261/**
262 * The VM is being reset.
263 *
264 * For the HM component this means that any GDT/LDT/TSS monitors
265 * needs to be removed.
266 *
267 * @param pVM The cross context VM structure.
268 */
269VMMR3_INT_DECL(void) HMR3Reset(PVM pVM)
270{
271 LogFlow(("HMR3Reset:\n"));
272 RT_NOREF(pVM);
273}
274
275
276/**
277 * Enable patching in a VT-x/AMD-V guest
278 *
279 * @returns VBox status code.
280 * @param pVM The cross context VM structure.
281 * @param pPatchMem Patch memory range.
282 * @param cbPatchMem Size of the memory range.
283 */
284VMMR3_INT_DECL(int) HMR3EnablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
285{
286 AssertReleaseFailed();
287 RT_NOREF(pVM, pPatchMem, cbPatchMem);
288 return VERR_NOT_SUPPORTED;
289}
290
291
292/**
293 * Disable patching in a VT-x/AMD-V guest.
294 *
295 * @returns VBox status code.
296 * @param pVM The cross context VM structure.
297 * @param pPatchMem Patch memory range.
298 * @param cbPatchMem Size of the memory range.
299 */
300VMMR3_INT_DECL(int) HMR3DisablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
301{
302 AssertReleaseFailed();
303 RT_NOREF(pVM, pPatchMem, cbPatchMem);
304 return VERR_NOT_SUPPORTED;
305}
306
307
308/**
309 * Noticiation callback from DBGF when interrupt breakpoints or generic debug
310 * event settings changes.
311 *
312 * DBGF will call HMR3NotifyDebugEventChangedPerCpu on each CPU afterwards, this
313 * function is just updating the VM globals.
314 *
315 * @param pVM The VM cross context VM structure.
316 * @thread EMT(0)
317 */
318VMMR3_INT_DECL(void) HMR3NotifyDebugEventChanged(PVM pVM)
319{
320 /* Interrupts. */
321 bool fUseDebugLoop = pVM->dbgf.ro.cSoftIntBreakpoints > 0
322 || pVM->dbgf.ro.cHardIntBreakpoints > 0;
323
324 /* CPU Exceptions. */
325 for (DBGFEVENTTYPE enmEvent = DBGFEVENT_XCPT_FIRST;
326 !fUseDebugLoop && enmEvent <= DBGFEVENT_XCPT_LAST;
327 enmEvent = (DBGFEVENTTYPE)(enmEvent + 1))
328 fUseDebugLoop = DBGF_IS_EVENT_ENABLED(pVM, enmEvent);
329
330 /* Common VM exits. */
331 for (DBGFEVENTTYPE enmEvent = DBGFEVENT_EXIT_FIRST;
332 !fUseDebugLoop && enmEvent <= DBGFEVENT_EXIT_LAST_COMMON;
333 enmEvent = (DBGFEVENTTYPE)(enmEvent + 1))
334 fUseDebugLoop = DBGF_IS_EVENT_ENABLED(pVM, enmEvent);
335
336 /* Vendor specific VM exits. */
337 if (HMR3IsVmxEnabled(pVM->pUVM))
338 for (DBGFEVENTTYPE enmEvent = DBGFEVENT_EXIT_VMX_FIRST;
339 !fUseDebugLoop && enmEvent <= DBGFEVENT_EXIT_VMX_LAST;
340 enmEvent = (DBGFEVENTTYPE)(enmEvent + 1))
341 fUseDebugLoop = DBGF_IS_EVENT_ENABLED(pVM, enmEvent);
342 else
343 for (DBGFEVENTTYPE enmEvent = DBGFEVENT_EXIT_SVM_FIRST;
344 !fUseDebugLoop && enmEvent <= DBGFEVENT_EXIT_SVM_LAST;
345 enmEvent = (DBGFEVENTTYPE)(enmEvent + 1))
346 fUseDebugLoop = DBGF_IS_EVENT_ENABLED(pVM, enmEvent);
347
348 /* Done. */
349 pVM->hm.s.fUseDebugLoop = fUseDebugLoop;
350}
351
352
353/**
354 * Follow up notification callback to HMR3NotifyDebugEventChanged for each CPU.
355 *
356 * HM uses this to combine the decision made by HMR3NotifyDebugEventChanged with
357 * per CPU settings.
358 *
359 * @param pVM The VM cross context VM structure.
360 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
361 */
362VMMR3_INT_DECL(void) HMR3NotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu)
363{
364 pVCpu->hm.s.fUseDebugLoop = pVCpu->hm.s.fSingleInstruction | pVM->hm.s.fUseDebugLoop;
365}
366
367
368#if 0 /* evil */
369/**
370 * Checks if we are currently using hardware acceleration.
371 *
372 * @returns true if hardware acceleration is being used, otherwise false.
373 * @param pVCpu The cross context virtual CPU structure.
374 */
375VMMR3_INT_DECL(bool) HMR3IsActive(PCVMCPU pVCpu)
376{
377 return pVCpu->hm.s.fActive;
378}
379#endif
380
381
382/**
383 * External interface for querying whether hardware acceleration is enabled.
384 *
385 * @returns true if VT-x or AMD-V is being used, otherwise false.
386 * @param pUVM The user mode VM handle.
387 * @sa HMIsEnabled, HMIsEnabledNotMacro.
388 */
389VMMR3DECL(bool) HMR3IsEnabled(PUVM pUVM)
390{
391 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
392 PVM pVM = pUVM->pVM;
393 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
394 return false;
395}
396
397
398/**
399 * External interface for querying whether VT-x is being used.
400 *
401 * @returns true if VT-x is being used, otherwise false.
402 * @param pUVM The user mode VM handle.
403 * @sa HMR3IsSvmEnabled, HMIsEnabled
404 */
405VMMR3DECL(bool) HMR3IsVmxEnabled(PUVM pUVM)
406{
407 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
408 PVM pVM = pUVM->pVM;
409 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
410 return false;
411}
412
413
414/**
415 * External interface for querying whether AMD-V is being used.
416 *
417 * @returns true if VT-x is being used, otherwise false.
418 * @param pUVM The user mode VM handle.
419 * @sa HMR3IsVmxEnabled, HMIsEnabled
420 */
421VMMR3DECL(bool) HMR3IsSvmEnabled(PUVM pUVM)
422{
423 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
424 PVM pVM = pUVM->pVM;
425 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
426 return false;
427}
428
429
430/**
431 * Checks if we are currently using nested paging.
432 *
433 * @returns true if nested paging is being used, otherwise false.
434 * @param pUVM The user mode VM handle.
435 */
436VMMR3DECL(bool) HMR3IsNestedPagingActive(PUVM pUVM)
437{
438 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
439 PVM pVM = pUVM->pVM;
440 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
441 return true; /* NEM requires nested paging always. */
442}
443
444
445/**
446 * Checks if virtualized APIC registers are enabled.
447 *
448 * When enabled this feature allows the hardware to access most of the
449 * APIC registers in the virtual-APIC page without causing VM-exits. See
450 * Intel spec. 29.1.1 "Virtualized APIC Registers".
451 *
452 * @returns true if virtualized APIC registers is enabled, otherwise
453 * false.
454 * @param pUVM The user mode VM handle.
455 */
456VMMR3DECL(bool) HMR3AreVirtApicRegsEnabled(PUVM pUVM)
457{
458 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
459 PVM pVM = pUVM->pVM;
460 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
461 return false;
462}
463
464
465/**
466 * Checks if APIC posted-interrupt processing is enabled.
467 *
468 * This returns whether we can deliver interrupts to the guest without
469 * leaving guest-context by updating APIC state from host-context.
470 *
471 * @returns true if APIC posted-interrupt processing is enabled,
472 * otherwise false.
473 * @param pUVM The user mode VM handle.
474 */
475VMMR3DECL(bool) HMR3IsPostedIntrsEnabled(PUVM pUVM)
476{
477 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
478 PVM pVM = pUVM->pVM;
479 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
480 return false;
481}
482
483
484/**
485 * Checks if we are currently using VPID in VT-x mode.
486 *
487 * @returns true if VPID is being used, otherwise false.
488 * @param pUVM The user mode VM handle.
489 */
490VMMR3DECL(bool) HMR3IsVpidActive(PUVM pUVM)
491{
492 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
493 PVM pVM = pUVM->pVM;
494 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
495 return false;
496}
497
498
499/**
500 * Checks if we are currently using VT-x unrestricted execution,
501 * aka UX.
502 *
503 * @returns true if UX is being used, otherwise false.
504 * @param pUVM The user mode VM handle.
505 */
506VMMR3DECL(bool) HMR3IsUXActive(PUVM pUVM)
507{
508 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
509 PVM pVM = pUVM->pVM;
510 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
511 return false;
512}
513
514
515/**
516 * Check fatal VT-x/AMD-V error and produce some meaningful
517 * log release message.
518 *
519 * @param pVM The cross context VM structure.
520 * @param iStatusCode VBox status code.
521 */
522VMMR3_INT_DECL(void) HMR3CheckError(PVM pVM, int iStatusCode)
523{
524 AssertReleaseFailed();
525 RT_NOREF(pVM, iStatusCode);
526}
527
528
529/**
530 * Checks whether HM (VT-x/AMD-V) is being used by this VM.
531 *
532 * @retval true if used.
533 * @retval false if software virtualization (raw-mode) is used.
534 * @param pVM The cross context VM structure.
535 * @sa HMIsEnabled, HMR3IsEnabled
536 * @internal
537 *
538 * @note Doesn't belong here really but it doesn't make sense to create a new source file for a single function.
539 */
540VMMDECL(bool) HMIsEnabledNotMacro(PVM pVM)
541{
542 Assert(pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NOT_SET);
543 RT_NOREF(pVM);
544 return false;
545}
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