GIM.cpp revision 0bc35f54322c5f9b2d43b064f839a8cf8c99a234
ece9652d971886b99a269656ea4782319637e75avboxsync/* $Id$ */
ece9652d971886b99a269656ea4782319637e75avboxsync/** @file
ece9652d971886b99a269656ea4782319637e75avboxsync * GIM - Guest Interface Manager.
ece9652d971886b99a269656ea4782319637e75avboxsync */
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2014-2015 Oracle Corporation
ece9652d971886b99a269656ea4782319637e75avboxsync *
ece9652d971886b99a269656ea4782319637e75avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
ece9652d971886b99a269656ea4782319637e75avboxsync * available from http://www.virtualbox.org. This file is free software;
ece9652d971886b99a269656ea4782319637e75avboxsync * you can redistribute it and/or modify it under the terms of the GNU
ece9652d971886b99a269656ea4782319637e75avboxsync * General Public License (GPL) as published by the Free Software
ece9652d971886b99a269656ea4782319637e75avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
ece9652d971886b99a269656ea4782319637e75avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ece9652d971886b99a269656ea4782319637e75avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ece9652d971886b99a269656ea4782319637e75avboxsync */
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync/** @page pg_gim GIM - The Guest Interface Manager
ece9652d971886b99a269656ea4782319637e75avboxsync *
ece9652d971886b99a269656ea4782319637e75avboxsync * The Guest Interface Manager abstracts an interface provider through which
ece9652d971886b99a269656ea4782319637e75avboxsync * guests may interact with the hypervisor.
ece9652d971886b99a269656ea4782319637e75avboxsync *
ece9652d971886b99a269656ea4782319637e75avboxsync * @see grp_gim
ece9652d971886b99a269656ea4782319637e75avboxsync *
ece9652d971886b99a269656ea4782319637e75avboxsync *
ece9652d971886b99a269656ea4782319637e75avboxsync * @section sec_gim_provider Providers
ece9652d971886b99a269656ea4782319637e75avboxsync *
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * A GIM provider implements a particular hypervisor interface such as Microsoft
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * Hyper-V, Linux KVM and so on. It hooks into various components in the VMM to
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * ease the guest in running under a recognized, virtualized environment.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync *
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * The GIM provider configured for the VM needs to be recognized by the guest OS
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * in order to make use of features supported by the interface. Since it
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * requires co-operation from the guest OS, a GIM provider may also referred to
aafe9fe588edab292546a0e4c1f7eb377fd35df4vboxsync * as a paravirtualization interface.
aafe9fe588edab292546a0e4c1f7eb377fd35df4vboxsync *
aafe9fe588edab292546a0e4c1f7eb377fd35df4vboxsync * One of the goals of having a paravirtualized interface is for enabling guests
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * to be more accurate and efficient when operating in a virtualized
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync * environment. For instance, a guest OS which interfaces to VirtualBox through
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync * a GIM provider may rely on the provider for supplying the correct TSC
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync * frequency of the host processor. The guest can then avoid caliberating the
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync * TSC itself, resulting in higher accuracy and better performance.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync *
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * At most, only one GIM provider can be active for a running VM and cannot be
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync * changed during the lifetime of the VM.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync */
599595881adeaefb423b996cf29e21e5831c26d7vboxsync
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync/*******************************************************************************
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync* Header Files *
83365ff77c1571f994b3a15bfbdee077d2ea8a07vboxsync*******************************************************************************/
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync#define LOG_GROUP LOG_GROUP_GIM
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync#include <VBox/log.h>
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync#include "GIMInternal.h"
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync#include <VBox/vmm/vm.h>
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync#include <VBox/vmm/hm.h>
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync#include <VBox/vmm/ssm.h>
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync#include <VBox/vmm/pdmdev.h>
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync#include <iprt/err.h>
ece9652d971886b99a269656ea4782319637e75avboxsync#include <iprt/string.h>
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync/* Include all GIM providers. */
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync#include "GIMMinimalInternal.h"
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync#include "GIMHvInternal.h"
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync#include "GIMKvmInternal.h"
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync/*******************************************************************************
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync* Internal Functions *
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync*******************************************************************************/
992ef02987d71b2b9f73a50265997c7f8e384886vboxsyncstatic DECLCALLBACK(int) gimR3Save(PVM pVM, PSSMHANDLE pSSM);
992ef02987d71b2b9f73a50265997c7f8e384886vboxsyncstatic DECLCALLBACK(int) gimR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion, uint32_t uPass);
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync/**
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync * Initializes the GIM.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync *
ece9652d971886b99a269656ea4782319637e75avboxsync * @returns VBox status code.
ece9652d971886b99a269656ea4782319637e75avboxsync * @param pVM Pointer to the VM.
e7f5b62e52275099a4d14501306063e23876b771vboxsync */
e7f5b62e52275099a4d14501306063e23876b771vboxsyncVMMR3_INT_DECL(int) GIMR3Init(PVM pVM)
e7f5b62e52275099a4d14501306063e23876b771vboxsync{
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync LogFlow(("GIMR3Init\n"));
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync /*
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Assert alignment and sizes.
ece9652d971886b99a269656ea4782319637e75avboxsync */
ece9652d971886b99a269656ea4782319637e75avboxsync AssertCompile(sizeof(pVM->gim.s) <= sizeof(pVM->gim.padding));
e7f5b62e52275099a4d14501306063e23876b771vboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync /*
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Register the saved state data unit.
e7f5b62e52275099a4d14501306063e23876b771vboxsync */
e7f5b62e52275099a4d14501306063e23876b771vboxsync int rc = SSMR3RegisterInternal(pVM, "GIM", 0 /* uInstance */, GIM_SAVED_STATE_VERSION, sizeof(GIM),
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync NULL /* pfnLivePrep */, NULL /* pfnLiveExec */, NULL /* pfnLiveVote*/,
ece9652d971886b99a269656ea4782319637e75avboxsync NULL /* pfnSavePrep */, gimR3Save, NULL /* pfnSaveDone */,
ece9652d971886b99a269656ea4782319637e75avboxsync NULL /* pfnLoadPrep */, gimR3Load, NULL /* pfnLoadDone */);
08edd51145a38b2daffd73601db32bcd9a903514vboxsync if (RT_FAILURE(rc))
ece9652d971886b99a269656ea4782319637e75avboxsync return rc;
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync /*
ece9652d971886b99a269656ea4782319637e75avboxsync * Read configuration.
ece9652d971886b99a269656ea4782319637e75avboxsync */
ece9652d971886b99a269656ea4782319637e75avboxsync PCFGMNODE pCfgNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "GIM/");
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync /** @cfgm{/GIM/Provider, string}
ece9652d971886b99a269656ea4782319637e75avboxsync * The name of the GIM provider. The default is "none". */
08edd51145a38b2daffd73601db32bcd9a903514vboxsync char szProvider[64];
e7f5b62e52275099a4d14501306063e23876b771vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "Provider", szProvider, sizeof(szProvider), "None");
ece9652d971886b99a269656ea4782319637e75avboxsync AssertLogRelRCReturn(rc, rc);
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync /** @cfgm{/GIM/Version, uint32_t}
ece9652d971886b99a269656ea4782319637e75avboxsync * The interface version. The default is 0, which means "provide the most
ece9652d971886b99a269656ea4782319637e75avboxsync * up-to-date implementation". */
ece9652d971886b99a269656ea4782319637e75avboxsync uint32_t uVersion;
ece9652d971886b99a269656ea4782319637e75avboxsync rc = CFGMR3QueryU32Def(pCfgNode, "Version", &uVersion, 0 /* default */);
ece9652d971886b99a269656ea4782319637e75avboxsync AssertLogRelRCReturn(rc, rc);
ece9652d971886b99a269656ea4782319637e75avboxsync
0be1c98f1388ddc063a7e830f53e2018f658b348vboxsync /*
0be1c98f1388ddc063a7e830f53e2018f658b348vboxsync * Setup the GIM provider for this VM.
0be1c98f1388ddc063a7e830f53e2018f658b348vboxsync */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync LogRel(("GIM: Using provider \"%s\" (Implementation version: %u)\n", szProvider, uVersion));
e7f5b62e52275099a4d14501306063e23876b771vboxsync if (!RTStrCmp(szProvider, "None"))
79c6e4760808b57244846404a5a799fedba4353bvboxsync pVM->gim.s.enmProviderId = GIMPROVIDERID_NONE;
0be1c98f1388ddc063a7e830f53e2018f658b348vboxsync else
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync {
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync pVM->gim.s.u32Version = uVersion;
f8c709737db3e0499abab64fc2ff79df9a80d200vboxsync /** @todo r=bird: Because u32Version is saved, it should be translated to the
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * 'most up-to-date implementation' version number when 0. Otherwise,
e7f5b62e52275099a4d14501306063e23876b771vboxsync * we'll have abiguities when loading the state of older VMs. */
0be1c98f1388ddc063a7e830f53e2018f658b348vboxsync if (!RTStrCmp(szProvider, "Minimal"))
e7f5b62e52275099a4d14501306063e23876b771vboxsync {
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync pVM->gim.s.enmProviderId = GIMPROVIDERID_MINIMAL;
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync rc = gimR3MinimalInit(pVM);
e7f5b62e52275099a4d14501306063e23876b771vboxsync }
e7f5b62e52275099a4d14501306063e23876b771vboxsync else if (!RTStrCmp(szProvider, "HyperV"))
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync {
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync pVM->gim.s.enmProviderId = GIMPROVIDERID_HYPERV;
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync rc = gimR3HvInit(pVM);
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync }
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync else if (!RTStrCmp(szProvider, "KVM"))
e7f5b62e52275099a4d14501306063e23876b771vboxsync {
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync pVM->gim.s.enmProviderId = GIMPROVIDERID_KVM;
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync rc = gimR3KvmInit(pVM);
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync }
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** @todo KVM and others. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync else
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync rc = VMR3SetError(pVM->pUVM, VERR_GIM_INVALID_PROVIDER, RT_SRC_POS, "Provider \"%s\" unknown.", szProvider);
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync }
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync return rc;
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync}
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync/**
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync * Initializes the remaining bits of the GIM provider.
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync *
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync * This is called after initializing HM and most other VMM components.
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync *
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync * @returns VBox status code.
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync * @param pVM Pointer to the VM.
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync * @param enmWhat What has been completed.
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync * @thread EMT(0)
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync */
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsyncVMMR3_INT_DECL(int) GIMR3InitCompleted(PVM pVM)
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync{
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync switch (pVM->gim.s.enmProviderId)
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync {
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync case GIMPROVIDERID_MINIMAL:
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync return gimR3MinimalInitCompleted(pVM);
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync case GIMPROVIDERID_HYPERV:
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync return gimR3HvInitCompleted(pVM);
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync case GIMPROVIDERID_KVM:
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync return gimR3KvmInitCompleted(pVM);
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync default:
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync break;
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync }
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync if (!TMR3CpuTickIsFixedRateMonotonic(pVM, true /* fWithParavirtEnabled */))
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync LogRel(("GIM: Warning!!! Host TSC is unstable. The guest may behave unpredictably with a paravirtualized clock.\n"));
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync return VINF_SUCCESS;
e7f5b62e52275099a4d14501306063e23876b771vboxsync}
e7f5b62e52275099a4d14501306063e23876b771vboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync/**
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Applies relocations to data and code managed by this component.
3ffedb9dcf9aa3095f7f3fa2bdc879ba8e880cc2vboxsync *
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * This function will be called at init and whenever the VMM need to relocate
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * itself inside the GC.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync *
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * @param pVM Pointer to the VM.
599595881adeaefb423b996cf29e21e5831c26d7vboxsync * @param offDelta Relocation delta relative to old location.
599595881adeaefb423b996cf29e21e5831c26d7vboxsync */
599595881adeaefb423b996cf29e21e5831c26d7vboxsyncVMM_INT_DECL(void) GIMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
3ffedb9dcf9aa3095f7f3fa2bdc879ba8e880cc2vboxsync{
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync LogFlow(("GIMR3Relocate\n"));
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync if ( pVM->gim.s.enmProviderId == GIMPROVIDERID_NONE
3ffedb9dcf9aa3095f7f3fa2bdc879ba8e880cc2vboxsync || HMIsEnabled(pVM))
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync return;
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync
599595881adeaefb423b996cf29e21e5831c26d7vboxsync switch (pVM->gim.s.enmProviderId)
599595881adeaefb423b996cf29e21e5831c26d7vboxsync {
599595881adeaefb423b996cf29e21e5831c26d7vboxsync case GIMPROVIDERID_MINIMAL:
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync {
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync gimR3MinimalRelocate(pVM, offDelta);
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync break;
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync }
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync
6cb1a01aaf746e26c5190a7b0fca706393bdf3aevboxsync case GIMPROVIDERID_HYPERV:
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync {
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync gimR3HvRelocate(pVM, offDelta);
e7f5b62e52275099a4d14501306063e23876b771vboxsync break;
3ffedb9dcf9aa3095f7f3fa2bdc879ba8e880cc2vboxsync }
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync case GIMPROVIDERID_KVM:
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync {
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync gimR3KvmRelocate(pVM, offDelta);
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync break;
599595881adeaefb423b996cf29e21e5831c26d7vboxsync }
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync
3ffedb9dcf9aa3095f7f3fa2bdc879ba8e880cc2vboxsync default:
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync {
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync AssertMsgFailed(("Invalid provider Id %#x\n", pVM->gim.s.enmProviderId));
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync break;
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync }
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync }
3ffedb9dcf9aa3095f7f3fa2bdc879ba8e880cc2vboxsync}
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync/**
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync * Executes state-save operation.
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync *
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync * @returns VBox status code.
ece9652d971886b99a269656ea4782319637e75avboxsync * @param pVM Pointer to the VM.
ece9652d971886b99a269656ea4782319637e75avboxsync * @param pSSM SSM operation handle.
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync */
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsyncDECLCALLBACK(int) gimR3Save(PVM pVM, PSSMHANDLE pSSM)
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync{
1cc6d0ca9b70d90116a4fb8f7e60869cc98ad57cvboxsync AssertReturn(pVM, VERR_INVALID_PARAMETER);
1cc6d0ca9b70d90116a4fb8f7e60869cc98ad57cvboxsync AssertReturn(pSSM, VERR_SSM_INVALID_STATE);
e7f5b62e52275099a4d14501306063e23876b771vboxsync
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync /** @todo Save per-CPU data. */
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync int rc = VINF_SUCCESS;
ece9652d971886b99a269656ea4782319637e75avboxsync#if 0
ece9652d971886b99a269656ea4782319637e75avboxsync SSMR3PutU32(pSSM, pVM->cCpus);
ece9652d971886b99a269656ea4782319637e75avboxsync for (VMCPUID i = 0; i < pVM->cCpus; i++)
ece9652d971886b99a269656ea4782319637e75avboxsync {
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync rc = SSMR3PutXYZ(pSSM, pVM->aCpus[i].gim.s.XYZ);
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync }
ece9652d971886b99a269656ea4782319637e75avboxsync#endif
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync /*
ece9652d971886b99a269656ea4782319637e75avboxsync * Save per-VM data.
ece9652d971886b99a269656ea4782319637e75avboxsync */
ece9652d971886b99a269656ea4782319637e75avboxsync SSMR3PutU32(pSSM, pVM->gim.s.enmProviderId);
e7f5b62e52275099a4d14501306063e23876b771vboxsync SSMR3PutU32(pSSM, pVM->gim.s.u32Version);
ece9652d971886b99a269656ea4782319637e75avboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync /*
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Save provider-specific data.
e7f5b62e52275099a4d14501306063e23876b771vboxsync */
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync switch (pVM->gim.s.enmProviderId)
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync {
e7f5b62e52275099a4d14501306063e23876b771vboxsync case GIMPROVIDERID_HYPERV:
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync rc = gimR3HvSave(pVM, pSSM);
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync AssertRCReturn(rc, rc);
e7f5b62e52275099a4d14501306063e23876b771vboxsync break;
e7f5b62e52275099a4d14501306063e23876b771vboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync case GIMPROVIDERID_KVM:
e7f5b62e52275099a4d14501306063e23876b771vboxsync rc = gimR3KvmSave(pVM, pSSM);
e7f5b62e52275099a4d14501306063e23876b771vboxsync AssertRCReturn(rc, rc);
e7f5b62e52275099a4d14501306063e23876b771vboxsync break;
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync default:
e7f5b62e52275099a4d14501306063e23876b771vboxsync break;
e7f5b62e52275099a4d14501306063e23876b771vboxsync }
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync return rc;
ece9652d971886b99a269656ea4782319637e75avboxsync}
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync/**
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * Execute state load operation.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync *
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * @returns VBox status code.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * @param pVM Pointer to the VM.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * @param pSSM SSM operation handle.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * @param uVersion Data layout version.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * @param uPass The data pass.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync */
e35d51bc86d234abdf08fe247ea901501faa022fvboxsyncDECLCALLBACK(int) gimR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion, uint32_t uPass)
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync{
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync if (uPass != SSM_PASS_FINAL)
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync return VINF_SUCCESS;
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync if (uSSMVersion != GIM_SAVED_STATE_VERSION)
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync /** @todo Load per-CPU data. */
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync int rc;
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync#if 0
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync for (VMCPUID i = 0; i < pVM->cCpus; i++)
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync {
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync rc = SSMR3PutXYZ(pSSM, pVM->aCpus[i].gim.s.XYZ);
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync }
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync#endif
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync /*
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync * Load per-VM data.
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync */
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync uint32_t uProviderId;
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync uint32_t uProviderVersion;
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync rc = SSMR3GetU32(pSSM, &uProviderId); AssertRCReturn(rc, rc);
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync rc = SSMR3GetU32(pSSM, &uProviderVersion); AssertRCReturn(rc, rc);
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync if ((GIMPROVIDERID)uProviderId != pVM->gim.s.enmProviderId)
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Saved GIM provider %u differs from the configured one (%u)."),
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync uProviderId, pVM->gim.s.enmProviderId);
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync#if 0 /** @todo r=bird: Figure out what you mean to do here with the version. */
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync if (uProviderVersion != pVM->gim.s.u32Version)
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Saved GIM provider version %u differs from the configured one (%u)."),
e35d51bc86d234abdf08fe247ea901501faa022fvboxsync uProviderVersion, pVM->gim.s.u32Version);
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync#else
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync pVM->gim.s.u32Version = uProviderVersion;
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync#endif
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync /*
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * Load provider-specific data.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync */
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync switch (pVM->gim.s.enmProviderId)
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync {
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync case GIMPROVIDERID_HYPERV:
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync rc = gimR3HvLoad(pVM, pSSM, uSSMVersion);
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync AssertRCReturn(rc, rc);
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync break;
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync case GIMPROVIDERID_KVM:
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync rc = gimR3KvmLoad(pVM, pSSM, uSSMVersion);
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync AssertRCReturn(rc, rc);
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync break;
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync default:
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync break;
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync }
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync return VINF_SUCCESS;
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync}
1c19381e9455f78f30a14a20d19f1dab7da19334vboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync/**
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync * Terminates the GIM.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync *
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync * Termination means cleaning up and freeing all resources,
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync * the VM itself is, at this point, powered off or suspended.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync *
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * @returns VBox status code.
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync * @param pVM Pointer to the VM.
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync */
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsyncVMMR3_INT_DECL(int) GIMR3Term(PVM pVM)
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync{
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync switch (pVM->gim.s.enmProviderId)
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync {
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync case GIMPROVIDERID_HYPERV:
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync return gimR3HvTerm(pVM);
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync case GIMPROVIDERID_KVM:
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync return gimR3KvmTerm(pVM);
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync default:
ece9652d971886b99a269656ea4782319637e75avboxsync break;
ece9652d971886b99a269656ea4782319637e75avboxsync }
ece9652d971886b99a269656ea4782319637e75avboxsync return VINF_SUCCESS;
ece9652d971886b99a269656ea4782319637e75avboxsync}
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync
ece9652d971886b99a269656ea4782319637e75avboxsync/**
ece9652d971886b99a269656ea4782319637e75avboxsync * The VM is being reset.
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync *
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync * For the GIM component this means unmapping and unregistering MMIO2 regions
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync * and other provider-specific resets.
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync *
e5ffd0945e1eb5f641e513f84cfce9870e2d4e48vboxsync * @returns VBox status code.
ece9652d971886b99a269656ea4782319637e75avboxsync * @param pVM Pointer to the VM.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync */
e7f5b62e52275099a4d14501306063e23876b771vboxsyncVMMR3_INT_DECL(void) GIMR3Reset(PVM pVM)
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync{
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync switch (pVM->gim.s.enmProviderId)
e7f5b62e52275099a4d14501306063e23876b771vboxsync {
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync case GIMPROVIDERID_HYPERV:
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync return gimR3HvReset(pVM);
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync case GIMPROVIDERID_KVM:
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync return gimR3KvmReset(pVM);
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync default:
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync break;
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync }
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync}
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync
e7f5b62e52275099a4d14501306063e23876b771vboxsync/**
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Registers the GIM device with VMM.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync *
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @param pVM Pointer to the VM.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @param pDevIns Pointer to the GIM device instance.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync */
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsyncVMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns)
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync{
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync pVM->gim.s.pDevInsR3 = pDevIns;
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync}
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync/**
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * Returns the array of MMIO2 regions that are expected to be registered and
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * later mapped into the guest-physical address space for the GIM provider
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * configured for the VM.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync *
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @returns Pointer to an array of GIM MMIO2 regions, may return NULL.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @param pVM Pointer to the VM.
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync * @param pcRegions Where to store the number of items in the array.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync *
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @remarks The caller does not own and therefore must -NOT- try to free the
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync * returned pointer.
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync */
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsyncVMMR3DECL(PGIMMMIO2REGION) GIMR3GetMmio2Regions(PVM pVM, uint32_t *pcRegions)
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync{
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync Assert(pVM);
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync Assert(pcRegions);
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync
b09004e17d8096e3983fb0ecf5aad272877037ccvboxsync *pcRegions = 0;
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync switch (pVM->gim.s.enmProviderId)
e7f5b62e52275099a4d14501306063e23876b771vboxsync {
ece9652d971886b99a269656ea4782319637e75avboxsync case GIMPROVIDERID_HYPERV:
47c2a6d84685d16b7ef87c307331e5588d892ef0vboxsync return gimR3HvGetMmio2Regions(pVM, pcRegions);
default:
break;
}
return NULL;
}
/**
* Unmaps a registered MMIO2 region in the guest address space and removes any
* access handlers for it.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pRegion Pointer to the GIM MMIO2 region.
*/
VMMR3_INT_DECL(int) GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion)
{
AssertPtr(pVM);
AssertPtr(pRegion);
PPDMDEVINS pDevIns = pVM->gim.s.pDevInsR3;
AssertPtr(pDevIns);
if (pRegion->fMapped)
{
int rc = PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
AssertRC(rc);
rc = PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, pRegion->GCPhysPage);
if (RT_SUCCESS(rc))
{
pRegion->fMapped = false;
pRegion->GCPhysPage = NIL_RTGCPHYS;
}
}
return VINF_SUCCESS;
}
/**
* Write access handler for a mapped MMIO2 region. At present, this handler
* simply ignores writes.
*
* In the future we might want to let the GIM provider decide what the handler
* should do (like throwing #GP faults).
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param GCPhys The guest-physical address of the region.
* @param pvPhys Pointer to the region in the guest address space.
* @param pvBuf Pointer to the data being read/written.
* @param cbBuf The size of the buffer in @a pvBuf.
* @param enmAccessType The type of access.
* @param pvUser User argument (NULL, not used).
*/
static DECLCALLBACK(int) gimR3Mmio2WriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
PGMACCESSTYPE enmAccessType, void *pvUser)
{
/*
* Ignore writes to the mapped MMIO2 page.
*/
Assert(enmAccessType == PGMACCESSTYPE_WRITE);
return VINF_SUCCESS; /** @todo Hyper-V says we should #GP(0) fault for writes to the Hypercall and TSC page. */
}
/**
* Maps a registered MMIO2 region in the guest address space. The region will be
* made read-only and writes from the guest will be ignored.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pRegion Pointer to the GIM MMIO2 region.
* @param GCPhysRegion Where in the guest address space to map the region.
*/
VMMR3_INT_DECL(int) GIMR3Mmio2Map(PVM pVM, PGIMMMIO2REGION pRegion, RTGCPHYS GCPhysRegion)
{
PPDMDEVINS pDevIns = pVM->gim.s.pDevInsR3;
AssertPtr(pDevIns);
/* The guest-physical address must be page-aligned. */
if (GCPhysRegion & PAGE_OFFSET_MASK)
{
LogFunc(("%s: %#RGp not paging aligned\n", pRegion->szDescription, GCPhysRegion));
return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
}
/* Allow only normal pages to be overlaid using our MMIO2 pages (disallow MMIO, ROM, reserved pages). */
/** @todo Hyper-V doesn't seem to be very strict about this, may be relax
* later if some guest really requires it. */
if (!PGMPhysIsGCPhysNormal(pVM, GCPhysRegion))
{
LogFunc(("%s: %#RGp is not normal memory\n", pRegion->szDescription, GCPhysRegion));
return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
}
if (!pRegion->fRegistered)
{
LogFunc(("%s: Region has not been registered.\n"));
return VERR_GIM_IPE_1;
}
/*
* Map the MMIO2 region over the specified guest-physical address.
*/
int rc = PDMDevHlpMMIO2Map(pDevIns, pRegion->iRegion, GCPhysRegion);
if (RT_SUCCESS(rc))
{
/*
* Install access-handlers for the mapped page to prevent (ignore) writes to it from the guest.
*/
rc = PGMR3HandlerPhysicalRegister(pVM,
PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
GCPhysRegion, GCPhysRegion + (pRegion->cbRegion - 1),
gimR3Mmio2WriteHandler, NULL /* pvUserR3 */,
NULL /* pszModR0 */, NULL /* pszHandlerR0 */, NIL_RTR0PTR /* pvUserR0 */,
NULL /* pszModRC */, NULL /* pszHandlerRC */, NIL_RTRCPTR /* pvUserRC */,
pRegion->szDescription);
if (RT_SUCCESS(rc))
{
pRegion->fMapped = true;
pRegion->GCPhysPage = GCPhysRegion;
return rc;
}
PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, GCPhysRegion);
}
return rc;
}
#if 0
/**
* Registers the physical handler for the registered and mapped MMIO2 region.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pRegion Pointer to the GIM MMIO2 region.
*/
VMMR3_INT_DECL(int) GIMR3Mmio2HandlerPhysicalRegister(PVM pVM, PGIMMMIO2REGION pRegion)
{
AssertPtr(pRegion);
AssertReturn(pRegion->fRegistered, VERR_GIM_IPE_2);
AssertReturn(pRegion->fMapped, VERR_GIM_IPE_3);
return PGMR3HandlerPhysicalRegister(pVM,
PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
pRegion->GCPhysPage, pRegion->GCPhysPage + (pRegion->cbRegion - 1),
gimR3Mmio2WriteHandler, NULL /* pvUserR3 */,
NULL /* pszModR0 */, NULL /* pszHandlerR0 */, NIL_RTR0PTR /* pvUserR0 */,
NULL /* pszModRC */, NULL /* pszHandlerRC */, NIL_RTRCPTR /* pvUserRC */,
pRegion->szDescription);
}
/**
* Deregisters the physical handler for the MMIO2 region.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pRegion Pointer to the GIM MMIO2 region.
*/
VMMR3_INT_DECL(int) GIMR3Mmio2HandlerPhysicalDeregister(PVM pVM, PGIMMMIO2REGION pRegion)
{
return PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
}
#endif