VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/GIM.cpp@ 57989

Last change on this file since 57989 was 57989, checked in by vboxsync, 9 years ago

Added support for GIM Hyper-V hypercalls and guest debugging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.3 KB
Line 
1/* $Id: GIM.cpp 57989 2015-10-01 16:44:12Z vboxsync $ */
2/** @file
3 * GIM - Guest Interface Manager.
4 */
5
6/*
7 * Copyright (C) 2014-2015 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_gim GIM - The Guest Interface Manager
19 *
20 * The Guest Interface Manager abstracts an interface provider through which
21 * guests may interact with the hypervisor.
22 *
23 * @see grp_gim
24 *
25 *
26 * @section sec_gim_provider Providers
27 *
28 * A GIM provider implements a particular hypervisor interface such as Microsoft
29 * Hyper-V, Linux KVM and so on. It hooks into various components in the VMM to
30 * ease the guest in running under a recognized, virtualized environment.
31 *
32 * The GIM provider configured for the VM needs to be recognized by the guest OS
33 * in order to make use of features supported by the interface. Since it
34 * requires co-operation from the guest OS, a GIM provider may also referred to
35 * as a paravirtualization interface.
36 *
37 * One of the goals of having a paravirtualized interface is for enabling guests
38 * to be more accurate and efficient when operating in a virtualized
39 * environment. For instance, a guest OS which interfaces to VirtualBox through
40 * a GIM provider may rely on the provider for supplying the correct TSC
41 * frequency of the host processor. The guest can then avoid caliberating the
42 * TSC itself, resulting in higher accuracy and better performance.
43 *
44 * At most, only one GIM provider can be active for a running VM and cannot be
45 * changed during the lifetime of the VM.
46 */
47
48
49/*********************************************************************************************************************************
50* Header Files *
51*********************************************************************************************************************************/
52#define LOG_GROUP LOG_GROUP_GIM
53#include <VBox/log.h>
54#include "GIMInternal.h"
55#include <VBox/vmm/vm.h>
56#include <VBox/vmm/hm.h>
57#include <VBox/vmm/ssm.h>
58#include <VBox/vmm/pdmdev.h>
59
60#include <iprt/err.h>
61#include <iprt/string.h>
62
63/* Include all GIM providers. */
64#include "GIMMinimalInternal.h"
65#include "GIMHvInternal.h"
66#include "GIMKvmInternal.h"
67
68
69/*********************************************************************************************************************************
70* Internal Functions *
71*********************************************************************************************************************************/
72static DECLCALLBACK(int) gimR3Save(PVM pVM, PSSMHANDLE pSSM);
73static DECLCALLBACK(int) gimR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion, uint32_t uPass);
74static FNPGMPHYSHANDLER gimR3Mmio2WriteHandler;
75
76
77/**
78 * Initializes the GIM.
79 *
80 * @returns VBox status code.
81 * @param pVM Pointer to the VM.
82 */
83VMMR3_INT_DECL(int) GIMR3Init(PVM pVM)
84{
85 LogFlow(("GIMR3Init\n"));
86
87 /*
88 * Assert alignment and sizes.
89 */
90 AssertCompile(sizeof(pVM->gim.s) <= sizeof(pVM->gim.padding));
91
92 /*
93 * Initialize members.
94 */
95 pVM->gim.s.hSemiReadOnlyMmio2Handler = NIL_PGMPHYSHANDLERTYPE;
96
97 /*
98 * Register the saved state data unit.
99 */
100 int rc = SSMR3RegisterInternal(pVM, "GIM", 0 /* uInstance */, GIM_SAVED_STATE_VERSION, sizeof(GIM),
101 NULL /* pfnLivePrep */, NULL /* pfnLiveExec */, NULL /* pfnLiveVote*/,
102 NULL /* pfnSavePrep */, gimR3Save, NULL /* pfnSaveDone */,
103 NULL /* pfnLoadPrep */, gimR3Load, NULL /* pfnLoadDone */);
104 if (RT_FAILURE(rc))
105 return rc;
106
107 /*
108 * Read configuration.
109 */
110 PCFGMNODE pCfgNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "GIM/");
111
112 /** @cfgm{/GIM/Provider, string}
113 * The name of the GIM provider. The default is "none". */
114 char szProvider[64];
115 rc = CFGMR3QueryStringDef(pCfgNode, "Provider", szProvider, sizeof(szProvider), "None");
116 AssertLogRelRCReturn(rc, rc);
117
118 /** @cfgm{/GIM/Version, uint32_t}
119 * The interface version. The default is 0, which means "provide the most
120 * up-to-date implementation". */
121 uint32_t uVersion;
122 rc = CFGMR3QueryU32Def(pCfgNode, "Version", &uVersion, 0 /* default */);
123 AssertLogRelRCReturn(rc, rc);
124
125 /*
126 * Setup the GIM provider for this VM.
127 */
128 LogRel(("GIM: Using provider '%s' (Implementation version: %u)\n", szProvider, uVersion));
129 if (!RTStrCmp(szProvider, "None"))
130 pVM->gim.s.enmProviderId = GIMPROVIDERID_NONE;
131 else
132 {
133 pVM->gim.s.u32Version = uVersion;
134 /** @todo r=bird: Because u32Version is saved, it should be translated to the
135 * 'most up-to-date implementation' version number when 0. Otherwise,
136 * we'll have abiguities when loading the state of older VMs. */
137 if (!RTStrCmp(szProvider, "Minimal"))
138 {
139 pVM->gim.s.enmProviderId = GIMPROVIDERID_MINIMAL;
140 rc = gimR3MinimalInit(pVM);
141 }
142 else if (!RTStrCmp(szProvider, "HyperV"))
143 {
144 pVM->gim.s.enmProviderId = GIMPROVIDERID_HYPERV;
145 rc = gimR3HvInit(pVM);
146 }
147 else if (!RTStrCmp(szProvider, "KVM"))
148 {
149 pVM->gim.s.enmProviderId = GIMPROVIDERID_KVM;
150 rc = gimR3KvmInit(pVM);
151 }
152 else
153 rc = VMR3SetError(pVM->pUVM, VERR_GIM_INVALID_PROVIDER, RT_SRC_POS, "Provider '%s' unknown.", szProvider);
154 }
155 return rc;
156}
157
158
159/**
160 * Initializes the remaining bits of the GIM provider.
161 *
162 * This is called after initializing HM and most other VMM components.
163 *
164 * @returns VBox status code.
165 * @param pVM Pointer to the VM.
166 * @param enmWhat What has been completed.
167 * @thread EMT(0)
168 */
169VMMR3_INT_DECL(int) GIMR3InitCompleted(PVM pVM)
170{
171 switch (pVM->gim.s.enmProviderId)
172 {
173 case GIMPROVIDERID_MINIMAL:
174 return gimR3MinimalInitCompleted(pVM);
175
176 case GIMPROVIDERID_HYPERV:
177 return gimR3HvInitCompleted(pVM);
178
179 case GIMPROVIDERID_KVM:
180 return gimR3KvmInitCompleted(pVM);
181
182 default:
183 break;
184 }
185
186 if (!TMR3CpuTickIsFixedRateMonotonic(pVM, true /* fWithParavirtEnabled */))
187 LogRel(("GIM: Warning!!! Host TSC is unstable. The guest may behave unpredictably with a paravirtualized clock.\n"));
188
189 return VINF_SUCCESS;
190}
191
192
193/**
194 * Applies relocations to data and code managed by this component.
195 *
196 * This function will be called at init and whenever the VMM need to relocate
197 * itself inside the GC.
198 *
199 * @param pVM Pointer to the VM.
200 * @param offDelta Relocation delta relative to old location.
201 */
202VMM_INT_DECL(void) GIMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
203{
204 LogFlow(("GIMR3Relocate\n"));
205
206 if ( pVM->gim.s.enmProviderId == GIMPROVIDERID_NONE
207 || HMIsEnabled(pVM))
208 return;
209
210 switch (pVM->gim.s.enmProviderId)
211 {
212 case GIMPROVIDERID_MINIMAL:
213 {
214 gimR3MinimalRelocate(pVM, offDelta);
215 break;
216 }
217
218 case GIMPROVIDERID_HYPERV:
219 {
220 gimR3HvRelocate(pVM, offDelta);
221 break;
222 }
223
224 case GIMPROVIDERID_KVM:
225 {
226 gimR3KvmRelocate(pVM, offDelta);
227 break;
228 }
229
230 default:
231 {
232 AssertMsgFailed(("Invalid provider Id %#x\n", pVM->gim.s.enmProviderId));
233 break;
234 }
235 }
236}
237
238
239/**
240 * Executes state-save operation.
241 *
242 * @returns VBox status code.
243 * @param pVM Pointer to the VM.
244 * @param pSSM SSM operation handle.
245 */
246DECLCALLBACK(int) gimR3Save(PVM pVM, PSSMHANDLE pSSM)
247{
248 AssertReturn(pVM, VERR_INVALID_PARAMETER);
249 AssertReturn(pSSM, VERR_SSM_INVALID_STATE);
250
251 /** @todo Save per-CPU data. */
252 int rc = VINF_SUCCESS;
253#if 0
254 SSMR3PutU32(pSSM, pVM->cCpus);
255 for (VMCPUID i = 0; i < pVM->cCpus; i++)
256 {
257 rc = SSMR3PutXYZ(pSSM, pVM->aCpus[i].gim.s.XYZ);
258 }
259#endif
260
261 /*
262 * Save per-VM data.
263 */
264 SSMR3PutU32(pSSM, pVM->gim.s.enmProviderId);
265 SSMR3PutU32(pSSM, pVM->gim.s.u32Version);
266
267 /*
268 * Save provider-specific data.
269 */
270 switch (pVM->gim.s.enmProviderId)
271 {
272 case GIMPROVIDERID_HYPERV:
273 rc = gimR3HvSave(pVM, pSSM);
274 AssertRCReturn(rc, rc);
275 break;
276
277 case GIMPROVIDERID_KVM:
278 rc = gimR3KvmSave(pVM, pSSM);
279 AssertRCReturn(rc, rc);
280 break;
281
282 default:
283 break;
284 }
285
286 return rc;
287}
288
289
290/**
291 * Execute state load operation.
292 *
293 * @returns VBox status code.
294 * @param pVM Pointer to the VM.
295 * @param pSSM SSM operation handle.
296 * @param uVersion Data layout version.
297 * @param uPass The data pass.
298 */
299DECLCALLBACK(int) gimR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion, uint32_t uPass)
300{
301 if (uPass != SSM_PASS_FINAL)
302 return VINF_SUCCESS;
303 if (uSSMVersion != GIM_SAVED_STATE_VERSION)
304 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
305
306 /** @todo Load per-CPU data. */
307 int rc;
308#if 0
309 for (VMCPUID i = 0; i < pVM->cCpus; i++)
310 {
311 rc = SSMR3PutXYZ(pSSM, pVM->aCpus[i].gim.s.XYZ);
312 }
313#endif
314
315 /*
316 * Load per-VM data.
317 */
318 uint32_t uProviderId;
319 uint32_t uProviderVersion;
320
321 rc = SSMR3GetU32(pSSM, &uProviderId); AssertRCReturn(rc, rc);
322 rc = SSMR3GetU32(pSSM, &uProviderVersion); AssertRCReturn(rc, rc);
323
324 if ((GIMPROVIDERID)uProviderId != pVM->gim.s.enmProviderId)
325 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Saved GIM provider %u differs from the configured one (%u)."),
326 uProviderId, pVM->gim.s.enmProviderId);
327#if 0 /** @todo r=bird: Figure out what you mean to do here with the version. */
328 if (uProviderVersion != pVM->gim.s.u32Version)
329 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Saved GIM provider version %u differs from the configured one (%u)."),
330 uProviderVersion, pVM->gim.s.u32Version);
331#else
332 pVM->gim.s.u32Version = uProviderVersion;
333#endif
334
335 /*
336 * Load provider-specific data.
337 */
338 switch (pVM->gim.s.enmProviderId)
339 {
340 case GIMPROVIDERID_HYPERV:
341 rc = gimR3HvLoad(pVM, pSSM, uSSMVersion);
342 AssertRCReturn(rc, rc);
343 break;
344
345 case GIMPROVIDERID_KVM:
346 rc = gimR3KvmLoad(pVM, pSSM, uSSMVersion);
347 AssertRCReturn(rc, rc);
348 break;
349
350 default:
351 break;
352 }
353
354 return VINF_SUCCESS;
355}
356
357
358/**
359 * Terminates the GIM.
360 *
361 * Termination means cleaning up and freeing all resources,
362 * the VM itself is, at this point, powered off or suspended.
363 *
364 * @returns VBox status code.
365 * @param pVM Pointer to the VM.
366 */
367VMMR3_INT_DECL(int) GIMR3Term(PVM pVM)
368{
369 switch (pVM->gim.s.enmProviderId)
370 {
371 case GIMPROVIDERID_HYPERV:
372 return gimR3HvTerm(pVM);
373
374 case GIMPROVIDERID_KVM:
375 return gimR3KvmTerm(pVM);
376
377 default:
378 break;
379 }
380 return VINF_SUCCESS;
381}
382
383
384/**
385 * The VM is being reset.
386 *
387 * For the GIM component this means unmapping and unregistering MMIO2 regions
388 * and other provider-specific resets.
389 *
390 * @returns VBox status code.
391 * @param pVM Pointer to the VM.
392 */
393VMMR3_INT_DECL(void) GIMR3Reset(PVM pVM)
394{
395 switch (pVM->gim.s.enmProviderId)
396 {
397 case GIMPROVIDERID_HYPERV:
398 return gimR3HvReset(pVM);
399
400 case GIMPROVIDERID_KVM:
401 return gimR3KvmReset(pVM);
402
403 default:
404 break;
405 }
406}
407
408
409/**
410 * Registers the GIM device with VMM.
411 *
412 * @param pVM Pointer to the VM.
413 * @param pDevInsR3 Pointer to the GIM device instance.
414 * @param pDebugStream Pointer to the GIM device debug connection, can be
415 * NULL.
416 */
417VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PPDMISTREAM pDebugStreamR3)
418{
419 pVM->gim.s.pDevInsR3 = pDevInsR3;
420 pVM->gim.s.pDebugStreamR3 = pDebugStreamR3;
421}
422
423
424/**
425 * Read data from a host debug session.
426 *
427 * @returns VBox status code.
428 *
429 * @param pVM Pointer to the VM.
430 * @param pvRead The read buffer.
431 * @param pcbRead The size of the read buffer as well as where to store
432 * the number of bytes read.
433 * @thread EMT.
434 */
435VMMR3_INT_DECL(int) GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead)
436{
437 PPDMISTREAM pDebugStream = pVM->gim.s.pDebugStreamR3;
438 if (pDebugStream)
439 return pDebugStream->pfnRead(pDebugStream, pvRead, pcbRead);
440 return VERR_GIM_NO_DEBUG_CONNECTION;
441}
442
443
444/**
445 * Write data to a host debug session.
446 *
447 * @returns VBox status code.
448 *
449 * @param pVM Pointer to the VM.
450 * @param pvWrite The write buffer.
451 * @param pcbWrite The size of the write buffer as well as where to store
452 * the number of bytes written.
453 * @thread EMT.
454 */
455VMMR3_INT_DECL(int) GIMR3DebugWrite(PVM pVM, void *pvWrite, size_t *pcbWrite)
456{
457 PPDMISTREAM pDebugStream = pVM->gim.s.pDebugStreamR3;
458 if (pDebugStream)
459 return pDebugStream->pfnWrite(pDebugStream, pvWrite, pcbWrite);
460 return VERR_GIM_NO_DEBUG_CONNECTION;
461}
462
463
464/**
465 * Returns the array of MMIO2 regions that are expected to be registered and
466 * later mapped into the guest-physical address space for the GIM provider
467 * configured for the VM.
468 *
469 * @returns Pointer to an array of GIM MMIO2 regions, may return NULL.
470 * @param pVM Pointer to the VM.
471 * @param pcRegions Where to store the number of items in the array.
472 *
473 * @remarks The caller does not own and therefore must -NOT- try to free the
474 * returned pointer.
475 */
476VMMR3DECL(PGIMMMIO2REGION) GIMR3GetMmio2Regions(PVM pVM, uint32_t *pcRegions)
477{
478 Assert(pVM);
479 Assert(pcRegions);
480
481 *pcRegions = 0;
482 switch (pVM->gim.s.enmProviderId)
483 {
484 case GIMPROVIDERID_HYPERV:
485 return gimR3HvGetMmio2Regions(pVM, pcRegions);
486
487 default:
488 break;
489 }
490
491 return NULL;
492}
493
494
495/**
496 * Unmaps a registered MMIO2 region in the guest address space and removes any
497 * access handlers for it.
498 *
499 * @returns VBox status code.
500 * @param pVM Pointer to the VM.
501 * @param pRegion Pointer to the GIM MMIO2 region.
502 */
503VMMR3_INT_DECL(int) GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion)
504{
505 AssertPtr(pVM);
506 AssertPtr(pRegion);
507
508 PPDMDEVINS pDevIns = pVM->gim.s.pDevInsR3;
509 AssertPtr(pDevIns);
510 if (pRegion->fMapped)
511 {
512 int rc = PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
513 AssertRC(rc);
514
515 rc = PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, pRegion->GCPhysPage);
516 if (RT_SUCCESS(rc))
517 {
518 pRegion->fMapped = false;
519 pRegion->GCPhysPage = NIL_RTGCPHYS;
520 }
521 }
522 return VINF_SUCCESS;
523}
524
525
526/**
527 * @callback_method_impl{FNPGMPHYSHANDLER,
528 * Write access handler for mapped MMIO2 pages. Currently ignores writes.}
529 *
530 * @todo In the future we might want to let the GIM provider decide what the
531 * handler should do (like throwing #GP faults).
532 */
533static DECLCALLBACK(VBOXSTRICTRC)
534gimR3Mmio2WriteHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
535 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
536{
537 /*
538 * Ignore writes to the mapped MMIO2 page.
539 */
540 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
541 return VINF_SUCCESS; /** @todo Hyper-V says we should #GP(0) fault for writes to the Hypercall and TSC page. */
542}
543
544
545/**
546 * Maps a registered MMIO2 region in the guest address space. The region will be
547 * made read-only and writes from the guest will be ignored.
548 *
549 * @returns VBox status code.
550 * @param pVM Pointer to the VM.
551 * @param pRegion Pointer to the GIM MMIO2 region.
552 * @param GCPhysRegion Where in the guest address space to map the region.
553 */
554VMMR3_INT_DECL(int) GIMR3Mmio2Map(PVM pVM, PGIMMMIO2REGION pRegion, RTGCPHYS GCPhysRegion)
555{
556 PPDMDEVINS pDevIns = pVM->gim.s.pDevInsR3;
557 AssertPtr(pDevIns);
558
559 /* The guest-physical address must be page-aligned. */
560 if (GCPhysRegion & PAGE_OFFSET_MASK)
561 {
562 LogFunc(("%s: %#RGp not paging aligned\n", pRegion->szDescription, GCPhysRegion));
563 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
564 }
565
566 /* Allow only normal pages to be overlaid using our MMIO2 pages (disallow MMIO, ROM, reserved pages). */
567 /** @todo Hyper-V doesn't seem to be very strict about this, may be relax
568 * later if some guest really requires it. */
569 if (!PGMPhysIsGCPhysNormal(pVM, GCPhysRegion))
570 {
571 LogFunc(("%s: %#RGp is not normal memory\n", pRegion->szDescription, GCPhysRegion));
572 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
573 }
574
575 if (!pRegion->fRegistered)
576 {
577 LogFunc(("%s: Region has not been registered.\n", pRegion->szDescription));
578 return VERR_GIM_IPE_1;
579 }
580
581 /*
582 * Map the MMIO2 region over the specified guest-physical address.
583 */
584 int rc = PDMDevHlpMMIO2Map(pDevIns, pRegion->iRegion, GCPhysRegion);
585 if (RT_SUCCESS(rc))
586 {
587 /*
588 * Install access-handlers for the mapped page to prevent (ignore) writes to it
589 * from the guest.
590 */
591 if (pVM->gim.s.hSemiReadOnlyMmio2Handler == NIL_PGMPHYSHANDLERTYPE)
592 rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_WRITE,
593 gimR3Mmio2WriteHandler,
594 NULL /* pszModR0 */, NULL /* pszHandlerR0 */, NULL /* pszPfHandlerR0 */,
595 NULL /* pszModRC */, NULL /* pszHandlerRC */, NULL /* pszPfHandlerRC */,
596 "GIM read-only MMIO2 handler",
597 &pVM->gim.s.hSemiReadOnlyMmio2Handler);
598 if (RT_SUCCESS(rc))
599 {
600 rc = PGMHandlerPhysicalRegister(pVM, GCPhysRegion, GCPhysRegion + (pRegion->cbRegion - 1),
601 pVM->gim.s.hSemiReadOnlyMmio2Handler,
602 NULL /* pvUserR3 */, NIL_RTR0PTR /* pvUserR0 */, NIL_RTRCPTR /* pvUserRC */,
603 pRegion->szDescription);
604 if (RT_SUCCESS(rc))
605 {
606 pRegion->fMapped = true;
607 pRegion->GCPhysPage = GCPhysRegion;
608 return rc;
609 }
610 }
611
612 PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, GCPhysRegion);
613 }
614
615 return rc;
616}
617
618#if 0
619/**
620 * Registers the physical handler for the registered and mapped MMIO2 region.
621 *
622 * @returns VBox status code.
623 * @param pVM Pointer to the VM.
624 * @param pRegion Pointer to the GIM MMIO2 region.
625 */
626VMMR3_INT_DECL(int) GIMR3Mmio2HandlerPhysicalRegister(PVM pVM, PGIMMMIO2REGION pRegion)
627{
628 AssertPtr(pRegion);
629 AssertReturn(pRegion->fRegistered, VERR_GIM_IPE_2);
630 AssertReturn(pRegion->fMapped, VERR_GIM_IPE_3);
631
632 return PGMR3HandlerPhysicalRegister(pVM,
633 PGMPHYSHANDLERKIND_WRITE,
634 pRegion->GCPhysPage, pRegion->GCPhysPage + (pRegion->cbRegion - 1),
635 gimR3Mmio2WriteHandler, NULL /* pvUserR3 */,
636 NULL /* pszModR0 */, NULL /* pszHandlerR0 */, NIL_RTR0PTR /* pvUserR0 */,
637 NULL /* pszModRC */, NULL /* pszHandlerRC */, NIL_RTRCPTR /* pvUserRC */,
638 pRegion->szDescription);
639}
640
641
642/**
643 * Deregisters the physical handler for the MMIO2 region.
644 *
645 * @returns VBox status code.
646 * @param pVM Pointer to the VM.
647 * @param pRegion Pointer to the GIM MMIO2 region.
648 */
649VMMR3_INT_DECL(int) GIMR3Mmio2HandlerPhysicalDeregister(PVM pVM, PGIMMMIO2REGION pRegion)
650{
651 return PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
652}
653#endif
654
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