VirtualBox

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

Last change on this file since 100101 was 99051, checked in by vboxsync, 21 months ago

VMM: More ARMv8 x86/amd64 separation work, VBoxVMMArm compiles and links now, bugref:10385

  • 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 99051 2023-03-19 16:40:06Z vboxsync $ */
2/** @file
3 * HM - VM Hardware Support Manager, ARMv8 shim.
4 */
5
6/*
7 * Copyright (C) 2023 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/**
369 * Checks if we are currently using hardware acceleration.
370 *
371 * @returns true if hardware acceleration is being used, otherwise false.
372 * @param pVCpu The cross context virtual CPU structure.
373 */
374VMMR3_INT_DECL(bool) HMR3IsActive(PCVMCPU pVCpu)
375{
376 return pVCpu->hm.s.fActive;
377}
378
379
380/**
381 * External interface for querying whether hardware acceleration is enabled.
382 *
383 * @returns true if VT-x or AMD-V is being used, otherwise false.
384 * @param pUVM The user mode VM handle.
385 * @sa HMIsEnabled, HMIsEnabledNotMacro.
386 */
387VMMR3DECL(bool) HMR3IsEnabled(PUVM pUVM)
388{
389 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
390 PVM pVM = pUVM->pVM;
391 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
392 return false;
393}
394
395
396/**
397 * External interface for querying whether VT-x is being used.
398 *
399 * @returns true if VT-x is being used, otherwise false.
400 * @param pUVM The user mode VM handle.
401 * @sa HMR3IsSvmEnabled, HMIsEnabled
402 */
403VMMR3DECL(bool) HMR3IsVmxEnabled(PUVM pUVM)
404{
405 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
406 PVM pVM = pUVM->pVM;
407 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
408 return false;
409}
410
411
412/**
413 * External interface for querying whether AMD-V is being used.
414 *
415 * @returns true if VT-x is being used, otherwise false.
416 * @param pUVM The user mode VM handle.
417 * @sa HMR3IsVmxEnabled, HMIsEnabled
418 */
419VMMR3DECL(bool) HMR3IsSvmEnabled(PUVM pUVM)
420{
421 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
422 PVM pVM = pUVM->pVM;
423 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
424 return false;
425}
426
427
428/**
429 * Checks if we are currently using nested paging.
430 *
431 * @returns true if nested paging is being used, otherwise false.
432 * @param pUVM The user mode VM handle.
433 */
434VMMR3DECL(bool) HMR3IsNestedPagingActive(PUVM pUVM)
435{
436 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
437 PVM pVM = pUVM->pVM;
438 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
439 return true; /* NEM requires nested paging always. */
440}
441
442
443/**
444 * Checks if virtualized APIC registers are enabled.
445 *
446 * When enabled this feature allows the hardware to access most of the
447 * APIC registers in the virtual-APIC page without causing VM-exits. See
448 * Intel spec. 29.1.1 "Virtualized APIC Registers".
449 *
450 * @returns true if virtualized APIC registers is enabled, otherwise
451 * false.
452 * @param pUVM The user mode VM handle.
453 */
454VMMR3DECL(bool) HMR3AreVirtApicRegsEnabled(PUVM pUVM)
455{
456 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
457 PVM pVM = pUVM->pVM;
458 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
459 return false;
460}
461
462
463/**
464 * Checks if APIC posted-interrupt processing is enabled.
465 *
466 * This returns whether we can deliver interrupts to the guest without
467 * leaving guest-context by updating APIC state from host-context.
468 *
469 * @returns true if APIC posted-interrupt processing is enabled,
470 * otherwise false.
471 * @param pUVM The user mode VM handle.
472 */
473VMMR3DECL(bool) HMR3IsPostedIntrsEnabled(PUVM pUVM)
474{
475 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
476 PVM pVM = pUVM->pVM;
477 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
478 return false;
479}
480
481
482/**
483 * Checks if we are currently using VPID in VT-x mode.
484 *
485 * @returns true if VPID is being used, otherwise false.
486 * @param pUVM The user mode VM handle.
487 */
488VMMR3DECL(bool) HMR3IsVpidActive(PUVM pUVM)
489{
490 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
491 PVM pVM = pUVM->pVM;
492 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
493 return false;
494}
495
496
497/**
498 * Checks if we are currently using VT-x unrestricted execution,
499 * aka UX.
500 *
501 * @returns true if UX is being used, otherwise false.
502 * @param pUVM The user mode VM handle.
503 */
504VMMR3DECL(bool) HMR3IsUXActive(PUVM pUVM)
505{
506 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
507 PVM pVM = pUVM->pVM;
508 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
509 return false;
510}
511
512
513/**
514 * Check fatal VT-x/AMD-V error and produce some meaningful
515 * log release message.
516 *
517 * @param pVM The cross context VM structure.
518 * @param iStatusCode VBox status code.
519 */
520VMMR3_INT_DECL(void) HMR3CheckError(PVM pVM, int iStatusCode)
521{
522 AssertReleaseFailed();
523 RT_NOREF(pVM, iStatusCode);
524}
525
526
527/**
528 * Checks whether HM (VT-x/AMD-V) is being used by this VM.
529 *
530 * @retval true if used.
531 * @retval false if software virtualization (raw-mode) is used.
532 * @param pVM The cross context VM structure.
533 * @sa HMIsEnabled, HMR3IsEnabled
534 * @internal
535 *
536 * @note Doesn't belong here really but it doesn't make sense to create a new source file for a single function.
537 */
538VMMDECL(bool) HMIsEnabledNotMacro(PVM pVM)
539{
540 Assert(pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NOT_SET);
541 return false;
542}
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