VirtualBox

Changeset 51560 in vbox


Ignore:
Timestamp:
Jun 6, 2014 5:17:02 AM (11 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
94218
Message:

VMM/GIM: Mapping of GIM MMIO2 regions and Hyper-V provider work.

Location:
trunk
Files:
3 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/err.h

    r51342 r51560  
    44
    55/*
    6  * Copyright (C) 2006-2013 Oracle Corporation
     6 * Copyright (C) 2006-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    10881088/** Reason for leaving RZ: I/O port write. */
    10891089#define VINF_IOM_R3_IOPORT_WRITE            2621
     1090/** Reason for leaving RZ: MMIO read. */
     1091#define VINF_IOM_R3_MMIO_READ               2623
    10901092/** Reason for leaving RZ: MMIO write. */
    1091 #define VINF_IOM_R3_MMIO_READ               2623
    1092 /** Reason for leaving RZ: MMIO read. */
    10931093#define VINF_IOM_R3_MMIO_WRITE              2624
    10941094/** Reason for leaving RZ: MMIO read/write. */
     
    20162016#define VERR_HM_NO_32_TO_64_SWITCHER                (-4106)
    20172017/** HMR0Leave was called on the wrong CPU. */
    2018 #define VERR_HM_WRONG_CPU_1                         (-4107)
     2018#define VERR_HM_WRONG_CPU                           (-4107)
    20192019/** Internal processing error \#1 in the HM code.  */
    20202020#define VERR_HM_IPE_1                               (-4108)
     
    20292029/** Internal processing error \#3 in the HM code.  */
    20302030#define VERR_HM_IPE_3                               (-4113)
    2031 /** Internal processing error \#3 in the HM code.  */
     2031/** Internal processing error \#4 in the HM code.  */
    20322032#define VERR_HM_IPE_4                               (-4114)
    2033 /** Internal processing error \#3 in the HM code.  */
     2033/** Internal processing error \#5 in the HM code.  */
    20342034#define VERR_HM_IPE_5                               (-4115)
    20352035/** Invalid HM64ON32OP value.  */
     
    23082308/** Syntax error - buggy parser. */
    23092309#define VERR_DBGC_PARSE_BUG                         (VERR_DBGC_PARSE_LOWEST + 25)
    2310 
    2311 
    2312 /** @} */
     2310/** @} */
     2311
    23132312
    23142313/** @name VBox Extension Pack Status Codes
     
    23272326
    23282327
    2329 /** @} */
    2330 
    23312328/** @name VBox Guest Control Status Codes
    23322329 * @{
     
    23392336
    23402337
     2338/** @name GIM Status Codes
     2339 * @{
     2340 */
     2341/** No GIM provider is configured for this VM. */
     2342#define VERR_GIM_NOT_ENABLED                        (-6300)
     2343/** GIM internal processing error \#1. */
     2344#define VERR_GIM_IPE_1                              (-6301)
     2345/** GIM internal processing error \#2. */
     2346#define VERR_GIM_IPE_2                              (-6302)
     2347/** GIM internal processing error \#3. */
     2348#define VERR_GIM_IPE_3                              (-6303)
     2349/** The GIM provider does not support any paravirtualized TSC. */
     2350#define VERR_GIM_PVTSC_NOT_AVAILABLE                (-6304)
     2351/** The guest has not setup use of the paravirtualized TSC. */
     2352#define VERR_GIM_PVTSC_NOT_ENABLED                  (-6305)
     2353/** Unknown or invalid GIM provider. */
     2354#define VERR_GIM_INVALID_PROVIDER                   (-6306)
     2355/** @} */
     2356
     2357
    23412358/* SED-END */
    23422359
  • trunk/include/VBox/log.h

    r51557 r51560  
    9898    /** Floppy Controller Device group. */
    9999    LOG_GROUP_DEV_FDC,
     100    /** Guest Interface Manager Device group. */
     101    LOG_GROUP_DEV_GIM,
    100102    /** High Precision Event Timer Device group. */
    101103    LOG_GROUP_DEV_HPET,
     
    790792    "DEV_EHCI",     \
    791793    "DEV_FDC",      \
     794    "DEV_GIM",      \
    792795    "DEV_HPET",     \
    793796    "DEV_IDE",      \
  • trunk/include/VBox/vmm/gim.h

    r51333 r51560  
    4444
    4545/**
    46  * Providers identifiers.
     46 * GIM Provider Identifiers.
    4747 */
    4848typedef enum GIMPROVIDERID
     
    5555    GIMPROVIDERID_HYPERV,
    5656    /** Linux KVM Interface. */
    57     GIMPROVIDERID_KVM,
    58     /** Ensure 32-bit type. */
    59     GIMPROVIDERID_32BIT_HACK = 0x7fffffff
     57    GIMPROVIDERID_KVM
    6058} GIMPROVIDERID;
     59AssertCompileSize(GIMPROVIDERID, 4);
     60
     61
     62/**
     63 * A GIM MMIO2 region record.
     64 */
     65typedef struct GIMMMIO2REGION
     66{
     67    /** The region index. */
     68    uint8_t             iRegion;
     69    /** Whether an RC mapping is required. */
     70    bool                fRCMapping;
     71    /** Whether this region has been registered. */
     72    bool                fRegistered;
     73    /** Whether this region is currently mapped. */
     74    bool                fMapped;
     75    /** Alignment padding. */
     76    uint8_t             au8Alignment0[4];
     77    /** Size of the region (must be page aligned). */
     78    uint32_t            cbRegion;
     79    /** Alignment padding. */
     80    uint32_t            u32Alignment0;
     81    /** The host ring-0 address of the first page in the region. */
     82    R0PTRTYPE(void *)   pvPageR0;
     83    /** The host ring-3 address of the first page in the region. */
     84    R3PTRTYPE(void *)   pvPageR3;
     85    /** The ring-context address of the first page in the region. */
     86    RCPTRTYPE(void *)   pvPageRC;
     87    /** The guest-physical address of the first page in the region. */
     88    RTGCPHYS            GCPhysPage;
     89    /** The description of the region. */
     90    char                szDescription[32];
     91} GIMMMIO2REGION;
     92/** Pointer to a GIM MMIO2 region. */
     93typedef GIMMMIO2REGION *PGIMMMIO2REGION;
     94/** Pointer to a const GIM MMIO2 region. */
     95typedef GIMMMIO2REGION const *PCGIMMMIO2REGION;
     96AssertCompileMemberAlignment(GIMMMIO2REGION, cbRegion,   8);
     97AssertCompileMemberAlignment(GIMMMIO2REGION, pvPageR0,   8);
    6198
    6299
     
    114151 * @{
    115152 */
    116 
     153VMMR0_INT_DECL(int)         GIMR0InitVM(PVM pVM);
     154VMMR0_INT_DECL(int)         GIMR0TermVM(PVM pVM);
    117155/** @} */
    118156#endif /* IN_RING0 */
     
    124162 * @{
    125163 */
    126 VMMR3_INT_DECL(int)     GIMR3Init(PVM pVM);
    127 VMMR3_INT_DECL(int)     GIMR3Term(PVM pVM);
     164VMMR3_INT_DECL(int)         GIMR3Init(PVM pVM);
     165VMMR3_INT_DECL(int)         GIMR3Term(PVM pVM);
     166VMMR3_INT_DECL(void)        GIMR3Reset(PVM pVM);
     167VMMR3DECL(void)             GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns);
     168VMMR3DECL(PGIMMMIO2REGION)  GIMR3GetMmio2Regions(PVM pVM, uint32_t *pcRegions);
    128169/** @} */
    129170#endif /* IN_RING3 */
    130171
    131 VMMDECL(bool)           GIMIsEnabled(PVM pVM);
    132 VMM_INT_DECL(int)       GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
    133 VMM_INT_DECL(int)       GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
    134 VMM_INT_DECL(int)       GIMWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue);
     172VMMDECL(bool)               GIMIsEnabled(PVM pVM);
     173VMMDECL(int)                GIMUpdateParavirtTsc(PVM pVM, uint64_t u64Offset);
     174VMM_INT_DECL(int)           GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
     175VMM_INT_DECL(int)           GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
     176VMM_INT_DECL(int)           GIMWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue);
    135177
    136178/** @} */
     
    138180RT_C_DECLS_END
    139181
    140 #endif
     182#endif  /* ___VBox_vmm_gim_h */
    141183
  • trunk/include/VBox/vmm/hm.h

    r50608 r51560  
    44
    55/*
    6  * Copyright (C) 2006-2013 Oracle Corporation
     6 * Copyright (C) 2006-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    144144VMM_INT_DECL(int)               HMAmdIsSubjectToErratum170(uint32_t *pu32Family, uint32_t *pu32Model, uint32_t *pu32Stepping);
    145145VMM_INT_DECL(bool)              HMSetSingleInstruction(PVMCPU pVCpu, bool fEnable);
     146VMM_INT_DECL(int)               HMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten);
    146147
    147148#ifndef IN_RC
  • trunk/include/VBox/vmm/vm.h

    r50953 r51560  
    44
    55/*
    6  * Copyright (C) 2006-2013 Oracle Corporation
     6 * Copyright (C) 2006-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    11221122        struct GIM s;
    11231123#endif
    1124         uint8_t     padding[64];        /* multiple of 64 */
     1124        uint8_t     padding[256];        /* multiple of 64 */
    11251125    } gim;
    11261126
     
    11471147
    11481148    /** Padding for aligning the cpu array on a page boundary. */
    1149     uint8_t         abAlignment2[350];
     1149    uint8_t         abAlignment2[158];
    11501150
    11511151    /* ---- end small stuff ---- */
  • trunk/include/VBox/vmm/vm.mac

    r50953 r51560  
    44
    55;
    6 ; Copyright (C) 2006-2013 Oracle Corporation
     6; Copyright (C) 2006-2014 Oracle Corporation
    77;
    88; This file is part of VirtualBox Open Source Edition (OSE), as
  • trunk/src/VBox/Devices/Makefile.kmk

    r50686 r51560  
    151151        PC/DevFwCommon.cpp \
    152152        PC/DevPcArch.cpp \
     153        GIMDev/GIMDev.cpp \
    153154        VMMDev/VMMDev.cpp \
    154155        $(if $(VBOX_WITH_HGCM),VMMDev/VMMDevHGCM.cpp,) \
  • trunk/src/VBox/Devices/build/VBoxDD.cpp

    r50686 r51560  
    192192        return rc;
    193193#endif
     194    rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceGIMDev);
     195    if (RT_FAILURE(rc))
     196        return rc;
    194197
    195198    return VINF_SUCCESS;
  • trunk/src/VBox/Devices/build/VBoxDD.h

    r50686 r51560  
    147147extern const PDMDRVREG g_DrvPciRaw;
    148148#endif
     149extern const PDMDEVREG g_DeviceGIMDev;
    149150
    150151#ifdef VBOX_WITH_USB
  • trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp

    r51476 r51560  
    11941194        InsertConfigNode(pRoot, "GIM", &pParavirtNode);
    11951195        const char *pcszParavirtProvider;
     1196        bool fGimDeviceNeeded = true;
    11961197        switch (paravirtProvider)
    11971198        {
    11981199            case ParavirtProvider_None:
    11991200                pcszParavirtProvider = "None";
     1201                fGimDeviceNeeded = false;
    12001202                break;
    12011203
    12021204            case ParavirtProvider_Default:  /** @todo Choose a provider based on guest OS type. There is no "Default" provider. */
    12031205                pcszParavirtProvider = "None";
     1206                fGimDeviceNeeded = false;
    12041207                break;
    12051208
     
    12091212                    pcszParavirtProvider = "Minimal";
    12101213                else
     1214                {
    12111215                    pcszParavirtProvider = "None";
     1216                    fGimDeviceNeeded = false;
     1217                }
    12121218                break;
    12131219            }
     
    13391345
    13401346        InsertConfigNode(pRoot, "Devices", &pDevices);
     1347
     1348        /*
     1349         * GIM Device
     1350         */
     1351        if (fGimDeviceNeeded)
     1352        {
     1353            InsertConfigNode(pDevices, "GIMDev", &pDev);
     1354            InsertConfigNode(pDev,     "0", &pInst);
     1355            InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
     1356            //InsertConfigNode(pInst,    "Config", &pCfg);
     1357        }
    13411358
    13421359        /*
  • trunk/src/VBox/VMM/VMMAll/GIMAll.cpp

    r51367 r51560  
    3737 *
    3838 * @param   pVM       Pointer to the VM.
    39  * @internal
    4039 */
    4140VMMDECL(bool) GIMIsEnabled(PVM pVM)
     
    6564        default:
    6665            AssertMsgFailed(("GIMHypercall: for unknown provider %u\n", pVM->gim.s.enmProviderId));
    67             return VERR_INTERNAL_ERROR_5; /** @todo Define and use VERR_GIM_HYPERCALL_UNEXPECTED */;
     66            return VERR_GIM_IPE_3;
    6867    }
     68}
     69
     70
     71/**
     72 * Updates the paravirtualized TSC supported by the GIM provider.
     73 *
     74 * @returns VBox status code.
     75 * @retval VINF_SUCCESS if the paravirt. TSC is setup and in use.
     76 * @retval VERR_GIM_NOT_ENABLED if no GIM provider is configured for this VM.
     77 * @retval VERR_GIM_PVTSC_NOT_AVAILABLE if the GIM provider does not support any
     78 *         paravirt. TSC.
     79 * @retval VERR_GIM_PVTSC_NOT_IN_USE if the GIM provider supports paravirt. TSC
     80 *         but the guest isn't currently using it.
     81 *
     82 * @param   pVM         Pointer to the VM.
     83 * @param   u64Offset   The computed TSC offset.
     84 *
     85 * @thread EMT(pVCpu)
     86 */
     87VMMDECL(int) GIMUpdateParavirtTsc(PVM pVM, uint64_t u64Offset)
     88{
     89    if (!pVM->gim.s.fEnabled)
     90        return VERR_GIM_NOT_ENABLED;
     91
     92    switch (pVM->gim.s.enmProviderId)
     93    {
     94        case GIMPROVIDERID_HYPERV:
     95            return GIMHvUpdateParavirtTsc(pVM, u64Offset);
     96
     97        default:
     98            break;
     99    }
     100    return VERR_GIM_PVTSC_NOT_AVAILABLE;
    69101}
    70102
  • trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp

    r51367 r51560  
    1616 */
    1717
    18 
    1918/*******************************************************************************
    2019*   Header Files                                                               *
     
    2221#define LOG_GROUP LOG_GROUP_GIM
    2322#include "GIMHvInternal.h"
     23#include "GIMInternal.h"
    2424
    2525#include <VBox/err.h>
     26#include <VBox/vmm/hm.h>
    2627#include <VBox/vmm/tm.h>
    2728#include <VBox/vmm/vm.h>
    28 
    29 DECLEXPORT(int) GIMHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
     29#include <VBox/vmm/pgm.h>
     30
     31
     32/**
     33 * Handles the Hyper-V hypercall.
     34 *
     35 * @returns VBox status code.
     36 * @param   pVCpu           Pointer to the VMCPU.
     37 * @param   pCtx            Pointer to the guest-CPU context.
     38 */
     39VMMDECL(int) GIMHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
    3040{
    3141    return VINF_SUCCESS;
     
    3343
    3444
    35 DECLEXPORT(int) GIMHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
     45/**
     46 * Updates Hyper-V's reference TSC page.
     47 *
     48 * @returns VBox status code.
     49 * @param   pVM         Pointer to the VM.
     50 * @param   u64Offset   The computed TSC offset.
     51 * @thread EMT(pVCpu)
     52 */
     53VMMDECL(int) GIMHvUpdateParavirtTsc(PVM pVM, uint64_t u64Offset)
     54{
     55    Assert(GIMIsEnabled(pVM));
     56    bool fHvTscEnabled = MSR_GIM_HV_REF_TSC_IS_ENABLED(pVM->gim.s.u.Hv.u64TscPageMsr);
     57    if (!fHvTscEnabled)
     58        return VERR_GIM_PVTSC_NOT_ENABLED;
     59
     60    PGIMHV          pHv      = &pVM->gim.s.u.Hv;
     61    PGIMMMIO2REGION pRegion  = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
     62    PGIMHVREFTSC    pRefTsc  = (PGIMHVREFTSC)pRegion->CTX_SUFF(pvPage);
     63    Assert(pRefTsc);
     64
     65    /** @todo Protect this with a spinlock! */
     66    pRefTsc->u64TscScale  = UINT64_C(0x1000000000000000);
     67    pRefTsc->u64TscOffset = u64Offset;
     68    ASMAtomicIncU32(&pRefTsc->u32TscSequence);
     69
     70    return VINF_SUCCESS;
     71}
     72
     73
     74/**
     75 * MSR read handler for Hyper-V.
     76 *
     77 * @returns VBox status code.
     78 * @param   pVCpu       Pointer to the VMCPU.
     79 * @param   idMsr       The MSR being read.
     80 * @param   pRange      The range this MSR belongs to.
     81 * @param   puValue     Where to store the MSR value read.
     82 */
     83VMMDECL(int) GIMHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
    3684{
    3785    NOREF(pRange);
     86    PVM    pVM = pVCpu->CTX_SUFF(pVM);
     87    PGIMHV pHv = &pVM->gim.s.u.Hv;
     88
    3889    switch (idMsr)
    3990    {
     
    4293            /* Hyper-V reports the time in 100ns units. */
    4394            uint64_t u64Tsc      = TMCpuTickGet(pVCpu);
    44             uint64_t u64TscHz    = TMCpuTicksPerSecond(pVCpu->CTX_SUFF(pVM));
     95            uint64_t u64TscHz    = TMCpuTicksPerSecond(pVM);
    4596            uint64_t u64Tsc100Ns = u64TscHz / UINT64_C(10000000); /* 100 ns */
    4697            *puValue = (u64Tsc / u64Tsc100Ns);
     
    50101        case MSR_GIM_HV_VP_INDEX:
    51102            *puValue = pVCpu->idCpu;
     103            return VINF_SUCCESS;
     104
     105        case MSR_GIM_HV_GUEST_OS_ID:
     106            *puValue = pHv->u64GuestOsIdMsr;
     107            return VINF_SUCCESS;
     108
     109        case MSR_GIM_HV_HYPERCALL:
     110            *puValue = pHv->u64HypercallMsr;
     111            return VINF_SUCCESS;
     112
     113        case MSR_GIM_HV_REF_TSC:
     114            *puValue = pHv->u64TscPageMsr;
     115            return VINF_SUCCESS;
     116
     117        case MSR_GIM_HV_TSC_FREQ:
     118            *puValue = TMCpuTicksPerSecond(pVM);
     119            return VINF_SUCCESS;
     120
     121        case MSR_GIM_HV_APIC_FREQ:
     122            /** @todo Fix this later! Get the information from DevApic. */
     123            *puValue = UINT32_C(1000000000); /* TMCLOCK_FREQ_VIRTUAL */
    52124            return VINF_SUCCESS;
    53125
     
    61133
    62134
    63 DECLEXPORT(int) GIMHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue)
     135/**
     136 * MSR write handler for Hyper-V.
     137 *
     138 * @returns VBox status code.
     139 * @param   pVCpu       Pointer to the VMCPU.
     140 * @param   idMsr       The MSR being written.
     141 * @param   pRange      The range this MSR belongs to.
     142 * @param   uValue      The value to set, ignored bits masked.
     143 * @param   uRawValue   The raw value with the ignored bits not masked.
     144 */
     145VMMDECL(int) GIMHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue)
    64146{
    65     LogRel(("GIMHvWriteMsr: Unknown/invalid WrMsr %#RX32 -> #GP(0)\n", idMsr));
     147    NOREF(pRange); NOREF(uValue);
     148    PVM    pVM = pVCpu->CTX_SUFF(pVM);
     149    PGIMHV pHv = &pVM->gim.s.u.Hv;
     150
     151    switch (idMsr)
     152    {
     153        case MSR_GIM_HV_GUEST_OS_ID:
     154        {
     155#ifndef IN_RING3
     156            return VERR_EM_INTERPRETER;
     157#else
     158            /* Disable the hypercall-page if 0 is written to this MSR. */
     159            if (!uRawValue)
     160            {
     161                GIMR3Mmio2Unmap(pVM, &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX]);
     162                pHv->u64HypercallMsr &= ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT;
     163                Log4Func(("Disabled hypercalls\n"));
     164            }
     165            pHv->u64GuestOsIdMsr = uRawValue;
     166            return VINF_SUCCESS;
     167#endif  /* !IN_RING3 */
     168        }
     169
     170        case MSR_GIM_HV_HYPERCALL:
     171        {
     172#ifndef IN_RING3
     173            return VERR_EM_INTERPRETER;
     174#else   /* IN_RING3 */
     175            /* First, update all but the hypercall enable bit. */
     176            pHv->u64HypercallMsr = (uRawValue & ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
     177
     178            /* Hypercalls can only be enabled when the guest has set the Guest-OS Id Msr. */
     179            bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
     180            if (   fEnable
     181                && !pHv->u64GuestOsIdMsr)
     182            {
     183                return VINF_SUCCESS;
     184            }
     185
     186            PPDMDEVINSR3    pDevIns = pVM->gim.s.pDevInsR3;
     187            PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
     188            AssertPtr(pDevIns);
     189            AssertPtr(pRegion);
     190
     191            /*
     192             * Is the guest disabling the hypercall-page? Allow it regardless of the Guest-OS Id Msr.
     193             */
     194            if (!fEnable)
     195            {
     196                GIMR3Mmio2Unmap(pVM, pRegion);
     197                pHv->u64HypercallMsr = uRawValue;
     198                Log4Func(("Disabled hypercalls\n"));
     199                return VINF_SUCCESS;
     200            }
     201
     202            /*
     203             * Map the hypercall-page.
     204             */
     205            RTGCPHYS GCPhysHypercallPage = MSR_GIM_HV_HYPERCALL_GUEST_PFN(uRawValue) << PAGE_SHIFT;
     206            int rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysHypercallPage, "Hyper-V Hypercall-page");
     207            if (RT_SUCCESS(rc))
     208            {
     209                /*
     210                 * Patch the hypercall-page.
     211                 */
     212                if (HMIsEnabled(pVM))
     213                {
     214                    size_t cbWritten = 0;
     215                    rc = HMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
     216                    if (   RT_SUCCESS(rc)
     217                        && cbWritten < PAGE_SIZE - 1)
     218                    {
     219                        uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
     220                        *pbLast = 0xc3;  /* RET */
     221
     222                        pHv->u64HypercallMsr = uRawValue;
     223                        LogRelFunc(("Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
     224                        LogRelFunc(("%.*Rhxd\n", cbWritten + 1, (uint8_t *)pRegion->pvPageR3));
     225                        return VINF_SUCCESS;
     226                    }
     227
     228                    LogFunc(("MSR_GIM_HV_HYPERCALL: HMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
     229                }
     230                else
     231                {
     232                    /** @todo Handle raw-mode hypercall page patching. */
     233                    LogRelFunc(("MSR_GIM_HV_HYPERCALL: raw-mode not yet implemented!\n"));
     234                }
     235
     236                GIMR3Mmio2Unmap(pVM, pRegion);
     237            }
     238            else
     239                LogFunc(("MSR_GIM_HV_HYPERCALL: GIMR3Mmio2Map failed. rc=%Rrc -> #GP(0)\n", rc));
     240
     241            return VERR_CPUM_RAISE_GP_0;
     242#endif  /* !IN_RING3 */
     243        }
     244
     245        case MSR_GIM_HV_REF_TSC:
     246        {
     247#ifndef IN_RING3
     248            return VERR_EM_INTERPRETER;
     249#else   /* IN_RING3 */
     250            /* First, update all but the TSC-page enable bit. */
     251            pHv->u64TscPageMsr = (uRawValue & ~MSR_GIM_HV_REF_TSC_ENABLE_BIT);
     252
     253            PPDMDEVINSR3    pDevIns = pVM->gim.s.pDevInsR3;
     254            PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
     255            AssertPtr(pDevIns);
     256            AssertPtr(pRegion);
     257
     258            /*
     259             * Is the guest disabling the TSC-page?
     260             */
     261            bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_REF_TSC_ENABLE_BIT);
     262            if (!fEnable)
     263            {
     264                GIMR3Mmio2Unmap(pVM, pRegion);
     265                Log4Func(("Disabled TSC-page\n"));
     266                return VINF_SUCCESS;
     267            }
     268
     269            /*
     270             * Map the TSC-page.
     271             */
     272            RTGCPHYS GCPhysTscPage = MSR_GIM_HV_REF_TSC_GUEST_PFN(uRawValue) << PAGE_SHIFT;
     273            int rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysTscPage, "Hyper-V TSC-page");
     274            if (RT_SUCCESS(rc))
     275            {
     276                pHv->u64TscPageMsr = uRawValue;
     277                Log4Func(("MSR_GIM_HV_REF_TSC: Enabled Hyper-V TSC page at %#RGp\n", GCPhysTscPage));
     278                return VINF_SUCCESS;
     279            }
     280            else
     281                LogFunc(("MSR_GIM_HV_REF_TSC: GIMR3Mmio2Map failed. rc=%Rrc -> #GP(0)\n", rc));
     282
     283            return VERR_CPUM_RAISE_GP_0;
     284#endif  /* !IN_RING3 */
     285        }
     286
     287        case MSR_GIM_HV_TIME_REF_COUNT:     /* Read-only MSRs. */
     288        case MSR_GIM_HV_VP_INDEX:
     289        case MSR_GIM_HV_TSC_FREQ:
     290        case MSR_GIM_HV_APIC_FREQ:
     291            LogFunc(("WrMsr on read-only MSR %#RX32 -> #GP(0)\n", idMsr));
     292            return VERR_CPUM_RAISE_GP_0;
     293
     294        default:
     295#ifdef IN_RING3
     296            static uint32_t s_cTimes = 0;
     297            if (s_cTimes++ < 20)
     298                LogRel(("GIM: Unknown/invalid WrMsr (%#x,%#x`%08x) -> #GP(0)\n", idMsr, uRawValue & UINT64_C(0xffffffff00000000),
     299                        uRawValue & UINT64_C(0xffffffff)));
     300#endif
     301            LogFunc(("Unknown/invalid WrMsr (%#RX32,%#RX64) -> #GP(0)\n", idMsr, uRawValue));
     302            break;
     303    }
     304
    66305    return VERR_CPUM_RAISE_GP_0;
    67306}
  • trunk/src/VBox/VMM/VMMAll/HMAll.cpp

    r47619 r51560  
    55
    66/*
    7  * Copyright (C) 2006-2013 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3838
    3939
    40 
    4140/**
    4241 * Checks whether HM (VT-x/AMD-V) is being used by this VM.
     
    7978}
    8079
     80
    8181/**
    8282 * Invalidates a guest page
     
    103103}
    104104
     105
    105106/**
    106107 * Flushes the guest TLB.
     
    118119}
    119120
     121
    120122#ifdef IN_RING0
    121 
    122123/**
    123124 * Dummy RTMpOnSpecific handler since RTMpPokeCpu couldn't be used.
     
    173174    }
    174175}
    175 
    176176#endif /* IN_RING0 */
     177
     178
    177179#ifndef IN_RC
    178 
    179180/**
    180181 * Poke an EMT so it can perform the appropriate TLB shootdowns.
     
    270271    return VINF_SUCCESS;
    271272}
    272 
    273273#endif /* !IN_RC */
    274274
     
    448448}
    449449
     450
     451/**
     452 * Patches the instructions necessary for making a hypercall to the hypervisor.
     453 * Used by GIM.
     454 *
     455 * @returns VBox status code.
     456 * @param   pVM         Pointer to the VM.
     457 * @param   pvBuf       The buffer in the hypercall page(s) to be patched.
     458 * @param   cbBuf       The size of the buffer.
     459 * @param   pcbWritten  Where to store the number of bytes patched. This
     460 *                      is reliably updated only when this function returns
     461 *                      VINF_SUCCESS.
     462 */
     463VMM_INT_DECL(int) HMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
     464{
     465    AssertReturn(pvBuf, VERR_INVALID_POINTER);
     466    AssertReturn(pcbWritten, VERR_INVALID_POINTER);
     467    AssertReturn(HMIsEnabled(pVM), VERR_HM_IPE_5);
     468
     469    if (pVM->hm.s.vmx.fSupported)
     470    {
     471        uint8_t abHypercall[] = { 0x0F, 0x01, 0xC1 };   /* VMCALL */
     472        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
     473        {
     474            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
     475            *pcbWritten = sizeof(abHypercall);
     476            return VINF_SUCCESS;
     477        }
     478        return VERR_BUFFER_OVERFLOW;
     479    }
     480    else
     481    {
     482        Assert(pVM->hm.s.svm.fSupported);
     483        uint8_t abHypercall[] = { 0x0F, 0x01, 0xD9 };   /* VMMCALL */
     484        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
     485        {
     486            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
     487            *pcbWritten = sizeof(abHypercall);
     488            return VINF_SUCCESS;
     489        }
     490        return VERR_BUFFER_OVERFLOW;
     491    }
     492}
     493
  • trunk/src/VBox/VMM/VMMR0/HMR0.cpp

    r51433 r51560  
    55
    66/*
    7  * Copyright (C) 2006-2013 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    1616 */
    17 
    1817
    1918/*******************************************************************************
     
    12291228
    12301229/**
    1231  * Does Ring-0 per VM HM initialization.
     1230 * Does ring-0 per-VM HM initialization.
    12321231 *
    12331232 * This will copy HM global into the VM structure and call the CPU specific
     
    12981297
    12991298/**
    1300  * Does Ring-0 per VM HM termination.
     1299 * Does ring-0 per VM HM termination.
    13011300 *
    13021301 * @returns VBox status code.
     
    14611460{
    14621461    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    1463     VMCPU_ASSERT_EMT_RETURN(pVCpu, VERR_HM_WRONG_CPU_1);
     1462    VMCPU_ASSERT_EMT_RETURN(pVCpu, VERR_HM_WRONG_CPU);
    14641463
    14651464    RTCPUID          idCpu = RTMpCpuId();
  • trunk/src/VBox/VMM/VMMR3/GIM.cpp

    r51367 r51560  
    2828 * A GIM provider implements a particular hypervisor interface such as Microsoft
    2929 * 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. This
    31  * is also referred to as paravirtualization interfaces.
    32  *
    33  * The idea behind this is primarily for making guests more accurate and
    34  * efficient when operating in a virtualized environment.
    35  *
    36  * For instance, a guest when interfaced to VirtualBox through a GIM provider
    37  * may rely on the provider (and VirtualBox ultimately) for providing the
    38  * correct TSC frequency and may therefore not have to caliberate the TSC
    39  * itself, resulting in higher accuracy and saving several CPU cycles.
     30 * ease the guest in running under a recognized, virtualized environment.
     31 *
     32 * If the GIM provider configured for the VM needs to be recognized by the guest
     33 * OS inorder to make use of features supported by the interface. Since it
     34 * requires co-operation from the guest OS, a GIM provider is also referred to
     35 * as a paravirtualization interface.
     36 *
     37 * One of the ideas behind this, is primarily for making guests more accurate
     38 * and efficient when operating in a virtualized environment. For instance, a
     39 * guest OS which interfaces to VirtualBox through a GIM provider may rely on
     40 * the provider (and VirtualBox ultimately) for providing the correct TSC
     41 * frequency of the host processor and may therefore not have to caliberate the
     42 * TSC itself, resulting in higher accuracy and saving several CPU cycles.
    4043 *
    4144 * At most, only one GIM provider can be active for a running VM and cannot be
     
    5255#include <VBox/vmm/hm.h>
    5356#include <VBox/vmm/ssm.h>
     57#include <VBox/vmm/pdmdev.h>
    5458
    5559#include <iprt/err.h>
     
    140144        {
    141145            LogRel(("GIM: Provider \"%s\" unknown.\n", szProvider));
    142             rc = VERR_NOT_SUPPORTED;
     146            rc = VERR_GIM_INVALID_PROVIDER;
    143147        }
    144148    }
    145149    return rc;
    146150}
     151
     152#if 0
     153VMM_INT_DECL(int) GIMR3InitFinalize(PVM pVM)
     154{
     155    LogFlow(("GIMR3InitFinalize\n"));
     156
     157    if (!pVM->gim.s.fEnabled)
     158        return VINF_SUCCESS;
     159
     160    switch (pVM->gim.s.enmProviderId)
     161    {
     162        case GIMPROVIDERID_MINIMAL:
     163        {
     164            GIMR3MinimalInitFinalize(pVM);
     165            break;
     166        }
     167
     168        case GIMPROVIDERID_HYPERV:
     169        {
     170            GIMR3HvInitFinalize(pVM);
     171            break;
     172        }
     173
     174        case GIMPROVIDERID_KVM:            /** @todo KVM. */
     175        default:
     176        {
     177            AssertMsgFailed(("Invalid provider Id %#x\n", pVM->gim.s.enmProviderId));
     178            break;
     179        }
     180    }
     181}
     182#endif
    147183
    148184
     
    233269}
    234270
     271
     272/**
     273 * The VM is being reset.
     274 *
     275 * For the GIM component this means unmapping and unregistering MMIO2 regions
     276 * and other provider-specific resets.
     277 *
     278 * @returns VBox status code.
     279 * @param   pVM     Pointer to the VM.
     280 */
     281VMMR3_INT_DECL(void) GIMR3Reset(PVM pVM)
     282{
     283    if (!pVM->gim.s.fEnabled)
     284        return;
     285
     286    switch (pVM->gim.s.enmProviderId)
     287    {
     288        case GIMPROVIDERID_HYPERV:
     289            return GIMR3HvReset(pVM);
     290
     291        default:
     292            break;
     293    }
     294}
     295
     296
     297/**
     298 * Registers the GIM device with VMM.
     299 *
     300 * @param   pVM         Pointer to the VM.
     301 * @param   pDevIns     Pointer to the GIM device instance.
     302 */
     303VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns)
     304{
     305    pVM->gim.s.pDevInsR3 = pDevIns;
     306}
     307
     308
     309/**
     310 * Returns the array of MMIO2 regions that are expected to be registered and
     311 * later mapped into the guest-physical address space for the GIM provider
     312 * configured for the VM.
     313 *
     314 * @returns Pointer to an array of GIM MMIO2 regions, may return NULL.
     315 * @param   pVM         Pointer to the VM.
     316 * @param   pcRegions   Where to store the number of items in the array.
     317 *
     318 * @remarks The caller does not own and therefore must -NOT- try to free the
     319 *          returned pointer.
     320 */
     321VMMR3DECL(PGIMMMIO2REGION) GIMR3GetMmio2Regions(PVM pVM, uint32_t *pcRegions)
     322{
     323    Assert(pVM);
     324    Assert(pcRegions);
     325
     326    *pcRegions = 0;
     327    if (!pVM->gim.s.fEnabled)
     328        return NULL;
     329
     330    switch (pVM->gim.s.enmProviderId)
     331    {
     332        case GIMPROVIDERID_HYPERV:
     333            return GIMR3HvGetMmio2Regions(pVM, pcRegions);
     334
     335        case GIMPROVIDERID_KVM:            /** @todo KVM. */
     336        default:
     337            break;
     338    }
     339
     340    return NULL;
     341}
     342
     343
     344/**
     345 * Unmaps a registered MMIO2 region in the guest address space and removes any
     346 * access handlers for it.
     347 *
     348 * @returns VBox status code.
     349 * @param   pVM         Pointer to the VM.
     350 * @param   pRegion     Pointer to the GIM MMIO2 region.
     351 */
     352VMM_INT_DECL(int) GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion)
     353{
     354    AssertPtr(pVM);
     355    AssertPtr(pRegion);
     356
     357    PPDMDEVINS pDevIns = pVM->gim.s.pDevInsR3;
     358    AssertPtr(pDevIns);
     359    if (pRegion->fMapped)
     360    {
     361        PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
     362        int rc = PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, pRegion->GCPhysPage);
     363        if (RT_SUCCESS(rc))
     364        {
     365            pRegion->fMapped    = false;
     366            pRegion->GCPhysPage = NIL_RTGCPHYS;
     367        }
     368    }
     369    return VINF_SUCCESS;
     370}
     371
     372
     373/**
     374 * Write access handler for a mapped MMIO2 region that presently ignores writes.
     375 *
     376 * @returns VBox status code.
     377 * @param pVM               Pointer to the VM.
     378 * @param GCPhys            The guest-physical address of the region.
     379 * @param pvPhys            Pointer to the region in the guest address space.
     380 * @param pvBuf             Pointer to the data being read/written.
     381 * @param cbBuf             The size of the buffer in @a pvBuf.
     382 * @param enmAccessType     The type of access.
     383 * @param pvUser            User argument (NULL, not used).
     384 */
     385static DECLCALLBACK(int) gimR3Mmio2PageWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
     386                                                    PGMACCESSTYPE enmAccessType, void *pvUser)
     387{
     388    /*
     389     * Ignore writes to the mapped MMIO2 page.
     390     */
     391    Assert(enmAccessType == PGMACCESSTYPE_WRITE);
     392    return VINF_SUCCESS;        /** @todo Hyper-V says we should #GP(0) fault for writes to the Hypercall and TSC page. */
     393}
     394
     395
     396/**
     397 * Maps a registered MMIO2 region in the guest address space. The region will be
     398 * made read-only and writes from the guest will be ignored.
     399 *
     400 * @returns VBox status code.
     401 * @param   pVM             Pointer to the VM.
     402 * @param   pRegion         Pointer to the GIM MMIO2 region.
     403 * @param   GCPhysRegion    Where in the guest address space to map the region.
     404 * @param   pszDesc         Description of the region being mapped.
     405 */
     406VMM_INT_DECL(int) GIMR3Mmio2Map(PVM pVM, PGIMMMIO2REGION pRegion, RTGCPHYS GCPhysRegion, const char *pszDesc)
     407{
     408    PPDMDEVINS pDevIns = pVM->gim.s.pDevInsR3;
     409    AssertPtr(pDevIns);
     410
     411    /* The guest-physical address must be page-aligned. */
     412    if (GCPhysRegion & PAGE_OFFSET_MASK)
     413    {
     414        LogFunc(("%s: %#RGp not paging aligned\n", pszDesc, GCPhysRegion));
     415        return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
     416    }
     417
     418    /* Allow only normal pages to be overlaid using our MMIO2 pages (disallow MMIO, ROM, reserved pages). */
     419    /** @todo Hyper-V doesn't seem to be very strict about this, may be relax
     420     *        later if some guest really requires it. */
     421    if (!PGMPhysIsGCPhysNormal(pVM, GCPhysRegion))
     422    {
     423        LogFunc(("%s: %#RGp is not normal memory\n", pszDesc, GCPhysRegion));
     424        return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
     425    }
     426
     427    if (pRegion->fMapped)
     428    {
     429        LogFunc(("%s: A mapping for %#RGp already exists.\n", pszDesc, GCPhysRegion));
     430        return VERR_PGM_MAPPING_CONFLICT;
     431    }
     432
     433    /*
     434     * Map the MMIO2 region over the guest-physical address.
     435     */
     436    int rc = PDMDevHlpMMIO2Map(pDevIns, pRegion->iRegion, GCPhysRegion);
     437    if (RT_SUCCESS(rc))
     438    {
     439        /*
     440         * Install access-handlers for the mapped page to prevent (ignore) writes to it from the guest.
     441         */
     442        rc = PGMR3HandlerPhysicalRegister(pVM,
     443                                          PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
     444                                          GCPhysRegion, GCPhysRegion + (pRegion->cbRegion - 1),
     445                                          gimR3Mmio2PageWriteHandler,  NULL /* pvUserR3 */,
     446                                          NULL /* pszModR0 */, NULL /* pszHandlerR0 */, NIL_RTR0PTR /* pvUserR0 */,
     447                                          NULL /* pszModRC */, NULL /* pszHandlerRC */, NIL_RTRCPTR /* pvUserRC */,
     448                                          pszDesc);
     449        if (RT_SUCCESS(rc))
     450        {
     451            pRegion->fMapped    = true;
     452            pRegion->GCPhysPage = GCPhysRegion;
     453            return VINF_SUCCESS;
     454        }
     455
     456        PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, GCPhysRegion);
     457    }
     458
     459    return rc;
     460}
     461
  • trunk/src/VBox/VMM/VMMR3/GIMHv.cpp

    r51367 r51560  
    2020*******************************************************************************/
    2121#define LOG_GROUP LOG_GROUP_GIM
    22 #include "GIMHvInternal.h"
    2322#include "GIMInternal.h"
    2423
     
    2625#include <iprt/err.h>
    2726#include <iprt/string.h>
     27#include <iprt/mem.h>
    2828
    2929#include <VBox/vmm/cpum.h>
     
    7979
    8080    int rc;
    81 #if 0
    82     pVM->gim.s.pfnHypercallR3 = &GIMHvHypercall;
    83     if (!HMIsEnabled(pVM))
    84     {
    85         rc = PDMR3LdrGetSymbolRC(pVM, NULL /* pszModule */, GIMHV_HYPERCALL, &pVM->gim.s.pfnHypercallRC);
    86         AssertRCReturn(rc, rc);
    87     }
    88     rc = PDMR3LdrGetSymbolR0(pVM, NULL /* pszModule */, GIMHV_HYPERCALL, &pVM->gim.s.pfnHypercallR0);
    89     AssertRCReturn(rc, rc);
    90 #endif
     81    PGIMHV pHv = &pVM->gim.s.u.Hv;
    9182
    9283    /*
    9384     * Determine interface capabilities based on the version.
    9485     */
    95     uint32_t uBaseFeat    = 0;
    96     uint32_t uPartFlags   = 0;
    97     uint32_t uPowMgmtFeat = 0;
    98     uint32_t uMiscFeat    = 0;
    99     uint32_t uHyperHints  = 0;
    10086    if (!pVM->gim.s.u32Version)
    10187    {
    102         uBaseFeat = 0
    103                   //| GIM_HV_BASE_FEAT_VP_RUNTIME_MSR
    104                   | GIM_HV_BASE_FEAT_PART_REF_COUNT_MSR
    105                   //| GIM_HV_BASE_FEAT_BASIC_SYNTH_IC
    106                   //| GIM_HV_BASE_FEAT_SYNTH_TIMER_MSRS
    107                   //| GIM_HV_BASE_FEAT_APIC_ACCESS_MSRS
    108                   //| GIM_HV_BASE_FEAT_HYPERCALL_MSRS
    109                   | GIM_HV_BASE_FEAT_VP_ID_MSR
    110                   //| GIM_HV_BASE_FEAT_VIRT_SYS_RESET_MSR
    111                   //| GIM_HV_BASE_FEAT_STAT_PAGES_MSR
    112                   //| GIM_HV_BASE_FEAT_PART_REF_TSC_MSR
    113                   //| GIM_HV_BASE_FEAT_GUEST_IDLE_STATE_MSR
    114                   //| GIM_HV_BASE_FEAT_TIMER_FREQ_MSRS
    115                   //| GIM_HV_BASE_FEAT_DEBUG_MSRS
    116                   ;
    117 
    118         pVM->gim.s.u.hv.u16HyperIdVersionMajor = VBOX_VERSION_MAJOR;
    119         pVM->gim.s.u.hv.u16HyperIdVersionMajor = VBOX_VERSION_MINOR;
    120         pVM->gim.s.u.hv.u32HyperIdBuildNumber  = VBOX_VERSION_BUILD;
     88        pHv->uBaseFeat = 0
     89                       //| GIM_HV_BASE_FEAT_VP_RUNTIME_MSR
     90                       | GIM_HV_BASE_FEAT_PART_TIME_REF_COUNT_MSR
     91                       //| GIM_HV_BASE_FEAT_BASIC_SYNTH_IC
     92                       //| GIM_HV_BASE_FEAT_SYNTH_TIMER_MSRS
     93                       //| GIM_HV_BASE_FEAT_APIC_ACCESS_MSRS
     94                       | GIM_HV_BASE_FEAT_HYPERCALL_MSRS
     95                       | GIM_HV_BASE_FEAT_VP_ID_MSR
     96                       //| GIM_HV_BASE_FEAT_VIRT_SYS_RESET_MSR
     97                       //| GIM_HV_BASE_FEAT_STAT_PAGES_MSR
     98                       | GIM_HV_BASE_FEAT_PART_REF_TSC_MSR
     99                       //| GIM_HV_BASE_FEAT_GUEST_IDLE_STATE_MSR
     100                       | GIM_HV_BASE_FEAT_TIMER_FREQ_MSRS
     101                       //| GIM_HV_BASE_FEAT_DEBUG_MSRS
     102                       ;
     103
     104        pHv->uMiscFeat = GIM_HV_MISC_FEAT_TIMER_FREQ;
     105    }
     106
     107    /*
     108     * Populate the required fields in MMIO2 region records for registering.
     109     */
     110    AssertCompile(GIM_HV_PAGE_SIZE == PAGE_SIZE);
     111    PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
     112    pRegion->iRegion    = GIM_HV_HYPERCALL_PAGE_REGION_IDX;
     113    pRegion->cbRegion   = PAGE_SIZE;
     114    pRegion->GCPhysPage = NIL_RTGCPHYS;
     115    RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hypercall Page");
     116    Assert(!pRegion->fRCMapping);
     117    Assert(!pRegion->fMapped);
     118
     119    pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
     120    pRegion->iRegion    = GIM_HV_REF_TSC_PAGE_REGION_IDX;
     121    pRegion->cbRegion   = PAGE_SIZE;
     122    pRegion->GCPhysPage = NIL_RTGCPHYS;
     123    RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "TSC Page");
     124
     125    /*
     126     * Make sure the CPU ID bit are in accordance to the Hyper-V
     127     * requirement and other paranoia checks.
     128     * See "Requirements for implementing the Microsoft hypervisor interface" spec.
     129     */
     130    Assert(!(pHv->uPartFlags & (  GIM_HV_PART_FLAGS_CREATE_PART
     131                                | GIM_HV_PART_FLAGS_ACCESS_MEMORY_POOL
     132                                | GIM_HV_PART_FLAGS_ACCESS_PART_ID
     133                                | GIM_HV_PART_FLAGS_ADJUST_MSG_BUFFERS
     134                                | GIM_HV_PART_FLAGS_CREATE_PORT
     135                                | GIM_HV_PART_FLAGS_ACCESS_STATS
     136                                | GIM_HV_PART_FLAGS_CPU_MGMT
     137                                | GIM_HV_PART_FLAGS_CPU_PROFILER)));
     138    Assert((pHv->uBaseFeat & (GIM_HV_BASE_FEAT_HYPERCALL_MSRS | GIM_HV_BASE_FEAT_VP_ID_MSR))
     139                          == (GIM_HV_BASE_FEAT_HYPERCALL_MSRS | GIM_HV_BASE_FEAT_VP_ID_MSR));
     140    for (unsigned i = 0; i < RT_ELEMENTS(pHv->aMmio2Regions); i++)
     141    {
     142        PCGIMMMIO2REGION pcCur = &pHv->aMmio2Regions[i];
     143        Assert(!pcCur->fRCMapping);
     144        Assert(!pcCur->fMapped);
     145        Assert(pcCur->GCPhysPage == NIL_RTGCPHYS);
    121146    }
    122147
     
    159184
    160185    HyperLeaf.uLeaf        = UINT32_C(0x40000003);
    161     HyperLeaf.uEax         = uBaseFeat;
    162     HyperLeaf.uEbx         = uPartFlags;
    163     HyperLeaf.uEcx         = uPowMgmtFeat;
    164     HyperLeaf.uEdx         = uMiscFeat;
     186    HyperLeaf.uEax         = pHv->uBaseFeat;
     187    HyperLeaf.uEbx         = pHv->uPartFlags;
     188    HyperLeaf.uEcx         = pHv->uPowMgmtFeat;
     189    HyperLeaf.uEdx         = pHv->uMiscFeat;
    165190    rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf);
    166191    AssertLogRelRCReturn(rc, rc);
     
    169194     * Insert all MSR ranges of Hyper-V.
    170195     */
    171     for (uint32_t i = 0; i < RT_ELEMENTS(g_aMsrRanges_HyperV); i++)
     196    for (unsigned i = 0; i < RT_ELEMENTS(g_aMsrRanges_HyperV); i++)
    172197    {
    173198        rc = CPUMR3MsrRangesInsert(pVM, &g_aMsrRanges_HyperV[i]);
    174199        AssertLogRelRCReturn(rc, rc);
    175200    }
     201
    176202    return VINF_SUCCESS;
    177203}
     204
     205
     206#if 0
     207VMMR3_INT_DECL(int) GIMR3HvInitFinalize(PVM pVM)
     208{
     209    pVM->gim.s.pfnHypercallR3 = &GIMHvHypercall;
     210    if (!HMIsEnabled(pVM))
     211    {
     212        rc = PDMR3LdrGetSymbolRC(pVM, NULL /* pszModule */, GIMHV_HYPERCALL, &pVM->gim.s.pfnHypercallRC);
     213        AssertRCReturn(rc, rc);
     214    }
     215    rc = PDMR3LdrGetSymbolR0(pVM, NULL /* pszModule */, GIMHV_HYPERCALL, &pVM->gim.s.pfnHypercallR0);
     216    AssertRCReturn(rc, rc);
     217}
     218#endif
    178219
    179220
     
    186227}
    187228
     229
     230/**
     231 * The VM is being reset. This resets Hyper-V provider MSRs and unmaps whatever
     232 * Hyper-V regions that the guest may have mapped.
     233 *
     234 * @param   pVM     Pointer to the VM.
     235 */
     236VMMR3_INT_DECL(void) GIMR3HvReset(PVM pVM)
     237{
     238    /*
     239     * Unmap MMIO2 pages that the guest may have setup.
     240     */
     241    PGIMHV pHv = &pVM->gim.s.u.Hv;
     242    for (unsigned i = 0; i < RT_ELEMENTS(pHv->aMmio2Regions); i++)
     243    {
     244        PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[i];
     245        GIMR3Mmio2Unmap(pVM, pRegion);
     246    }
     247
     248    /*
     249     * Reset MSRs.
     250     */
     251    pHv->u64GuestOsIdMsr = 0;
     252    pHv->u64HypercallMsr = 0;
     253    pHv->u64TscPageMsr   = 0;
     254}
     255
     256
     257/**
     258 * Returns a pointer to the MMIO2 regions supported by Hyper-V.
     259 *
     260 * @returns Pointer to an array of MMIO2 regions.
     261 * @param   pVM         Pointer to the VM.
     262 * @param   pcRegions   Where to store the number of regions in the array.
     263 */
     264VMMR3_INT_DECL(PGIMMMIO2REGION) GIMR3HvGetMmio2Regions(PVM pVM, uint32_t *pcRegions)
     265{
     266    Assert(GIMIsEnabled(pVM));
     267    PGIMHV pHv = &pVM->gim.s.u.Hv;
     268
     269    *pcRegions = RT_ELEMENTS(pHv->aMmio2Regions);
     270    Assert(*pcRegions <= UINT8_MAX);    /* See PGMR3PhysMMIO2Register(). */
     271    return pHv->aMmio2Regions;
     272}
     273
  • trunk/src/VBox/VMM/VMMR3/VM.cpp

    r51367 r51560  
    986986                                                                if (RT_SUCCESS(rc))
    987987                                                                {
    988                                                                     rc = PDMR3Init(pVM);
     988                                                                    /* GIM must be init'd before PDM, DevGIM construction may
     989                                                                       require GIM provider to be setup. */
     990                                                                    rc = GIMR3Init(pVM);
    989991                                                                    if (RT_SUCCESS(rc))
    990992                                                                    {
    991                                                                         /* GIM must be init'd after PDM, may rely on PDMR3 for
    992                                                                            symbol resolution. */
    993                                                                         rc = GIMR3Init(pVM);
     993                                                                        rc = PDMR3Init(pVM);
    994994                                                                        if (RT_SUCCESS(rc))
    995995                                                                        {
     
    10111011                                                                                rc = REMR3InitFinalize(pVM);
    10121012#endif
    1013 
    10141013                                                                            if (RT_SUCCESS(rc))
    10151014                                                                            {
     
    10251024                                                                            }
    10261025
    1027                                                                             int rc2 = GIMR3Term(pVM);
     1026                                                                            int rc2 = PDMR3Term(pVM);
    10281027                                                                            AssertRC(rc2);
    10291028                                                                        }
    1030                                                                         int rc2 = PDMR3Term(pVM);
     1029                                                                        int rc2 = GIMR3Term(pVM);
    10311030                                                                        AssertRC(rc2);
    10321031                                                                    }
     
    27982797        CSAMR3Reset(pVM);
    27992798#endif
     2799        GIMR3Reset(pVM);                /* This must come *before* PDM. */
    28002800        PDMR3Reset(pVM);
    28012801        PGMR3Reset(pVM);
  • trunk/src/VBox/VMM/include/GIMHvInternal.h

    r51367 r51560  
    1919#define ___GIMHvInternal_h
    2020
    21 #include <iprt/cdefs.h>
    22 #include <VBox/types.h>
     21#include <VBox/vmm/gim.h>
    2322#include <VBox/vmm/cpum.h>
    2423
    2524/** @name Hyper-V base feature identification.
    26  * Base features based on current partition privileges.
     25 * Features based on current partition privileges (per-VM).
    2726 * @{
    2827 */
     
    3029#define GIM_HV_BASE_FEAT_VP_RUNTIME_MSR           RT_BIT(0)
    3130/** Partition reference counter MSR available. */
    32 #define GIM_HV_BASE_FEAT_PART_REF_COUNT_MSR       RT_BIT(1)
     31#define GIM_HV_BASE_FEAT_PART_TIME_REF_COUNT_MSR  RT_BIT(1)
    3332/** Basic Synthetic Interrupt Controller MSRs available. */
    3433#define GIM_HV_BASE_FEAT_BASIC_SYNTH_IC           RT_BIT(2)
     
    4948/** Virtual guest idle state MSR available. */
    5049#define GIM_HV_BASE_FEAT_GUEST_IDLE_STATE_MSR     RT_BIT(10)
    51 /** Timer frequency MSRs available. */
     50/** Timer frequency MSRs (TSC and APIC) available. */
    5251#define GIM_HV_BASE_FEAT_TIMER_FREQ_MSRS          RT_BIT(11)
    5352/** Debug MSRs available. */
     
    212211/** Per-VM reference counter (R) */
    213212#define MSR_GIM_HV_TIME_REF_COUNT                 UINT32_C(0x40000020)
    214 /** Per-VM TSC (R) */
     213/** Per-VM TSC page (R/W) */
    215214#define MSR_GIM_HV_REF_TSC                        UINT32_C(0x40000021)
    216215/** Frequency of TSC in Hz as reported by the hypervisor (R) */
     
    390389AssertCompile(MSR_GIM_HV_RANGE11_START <= MSR_GIM_HV_RANGE11_END);
    391390
     391
     392/** @name Hyper-V MSR - Hypercall (MSR_GIM_HV_HYPERCALL).
     393 * @{
     394 */
     395/** Guest-physical page frame number of the hypercall-page. */
     396#define MSR_GIM_HV_HYPERCALL_GUEST_PFN(a)         ((a) >> 12)
     397/** The hypercall enable bit. */
     398#define MSR_GIM_HV_HYPERCALL_ENABLE_BIT           RT_BIT_64(0)
     399/** Whether the hypercall-page is enabled or not. */
     400#define MSR_GIM_HV_HYPERCALL_IS_ENABLED(a)        RT_BOOL((a) & MSR_GIM_HV_HYPERCALL_ENABLE_BIT)
     401/** @} */
     402
     403/** @name Hyper-V MSR - Reference TSC (MSR_GIM_HV_REF_TSC).
     404 * @{
     405 */
     406/** Guest-physical page frame number of the TSC-page. */
     407#define MSR_GIM_HV_REF_TSC_GUEST_PFN(a)           ((a) >> 12)
     408/** The TSC-page enable bit. */
     409#define MSR_GIM_HV_REF_TSC_ENABLE_BIT             RT_BIT_64(0)
     410/** Whether the TSC-page is enabled or not. */
     411#define MSR_GIM_HV_REF_TSC_IS_ENABLED(a)          RT_BOOL((a) & MSR_GIM_HV_REF_TSC_ENABLE_BIT)
     412/** @} */
     413
     414/** Hyper-V page size.  */
     415#define GIM_HV_PAGE_SIZE                          0x1000
     416
     417/**
     418 * MMIO2 region indices.
     419 */
     420/** The hypercall page region. */
     421#define GIM_HV_HYPERCALL_PAGE_REGION_IDX          UINT8_C(0)
     422/** The TSC page region. */
     423#define GIM_HV_REF_TSC_PAGE_REGION_IDX            UINT8_C(1)
     424/** The maximum region index (must be <= UINT8_MAX). */
     425#define GIM_HV_REGION_IDX_MAX                     GIM_HV_REF_TSC_PAGE_REGION_IDX
     426
     427/**
     428 * Hyper-V TSC (HV_REFERENCE_TSC_PAGE) structure placed in the TSC reference
     429 * page.
     430 */
     431typedef struct GIMHVREFTSC
     432{
     433    uint32_t volatile   u32TscSequence;
     434    uint32_t            uReserved0;
     435    uint64_t volatile   u64TscScale;
     436    uint64_t volatile   u64TscOffset;
     437} GIMHVTSCPAGE;
     438/** Pointer to GIM VMCPU instance data. */
     439typedef GIMHVREFTSC *PGIMHVREFTSC;
     440
     441/**
     442 * GIM Hyper-V VM Instance data.
     443 * Changes to this must checked against the padding of the gim union in VM!
     444 */
     445typedef struct GIMHV
     446{
     447    /** Guest OS identity MSR. */
     448    uint64_t                    u64GuestOsIdMsr;
     449    /** Hypercall MSR. */
     450    uint64_t                    u64HypercallMsr;
     451    /** Reference TSC page MSR. */
     452    uint64_t                    u64TscPageMsr;
     453
     454    /** Basic features. */
     455    uint32_t                    uBaseFeat;
     456    /** Partition flags. */
     457    uint32_t                    uPartFlags;
     458    /** Power management features. */
     459    uint32_t                    uPowMgmtFeat;
     460    /** Miscellaneous features. */
     461    uint32_t                    uMiscFeat;
     462    /** Hypervisor hints. */
     463    uint32_t                    uHyperHints;
     464    /** Alignment padding. */
     465    uint32_t                    u32Alignment0;
     466
     467    /** Array of MMIO2 regions. */
     468    GIMMMIO2REGION              aMmio2Regions[GIM_HV_REGION_IDX_MAX + 1];
     469} GIMHV;
     470/** Pointer to per-VM GIM Hyper-V instance data. */
     471typedef GIMHV *PGIMHV;
     472/** Pointer to const per-VM GIM Hyper-V instance data. */
     473typedef GIMHV const *PCGIMHV;
     474AssertCompileMemberAlignment(GIMHV, aMmio2Regions, 8);
     475
    392476RT_C_DECLS_BEGIN
     477
     478#ifdef IN_RING0
     479VMMR0_INT_DECL(int)     GIMR0HvInitVM(PVM pVM);
     480VMMR0_INT_DECL(int)     GIMR0HvTermVM(PVM pVM);
     481#endif /* IN_RING0 */
    393482
    394483#ifdef IN_RING3
    395484VMMR3_INT_DECL(int)     GIMR3HvInit(PVM pVM);
    396485VMMR3_INT_DECL(void)    GIMR3HvRelocate(PVM pVM, RTGCINTPTR offDelta);
     486VMMR3_INT_DECL(void)    GIMR3HvReset(PVM pVM);
     487VMMR3_INT_DECL(PGIMMMIO2REGION) GIMR3HvGetMmio2Regions(PVM pVM, uint32_t *pcRegions);
    397488#endif /* IN_RING3 */
    398489
     490VMMDECL(int)            GIMHvUpdateParavirtTsc(PVM pVM, uint64_t u64Offset);
    399491VMMDECL(int)            GIMHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
    400492VMMDECL(int)            GIMHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
  • trunk/src/VBox/VMM/include/GIMInternal.h

    r51333 r51560  
    2020
    2121#include <VBox/vmm/gim.h>
     22#include "GIMHvInternal.h"
    2223
    2324RT_C_DECLS_BEGIN
     
    4243    uint32_t                         u32Version;
    4344
     45    /** Pointer to the GIM device - ring-3 context. */
     46    R3PTRTYPE(PPDMDEVINS)            pDevInsR3;
    4447#if 0
    4548    /** Pointer to the provider's ring-3 hypercall handler. */
     
    6770    union
    6871    {
    69         struct
    70         {
    71         } minimal;
    72 
    73         struct
    74         {
    75             /** Hypervisor system identity - Minor version number. */
    76             uint16_t                 u16HyperIdVersionMinor;
    77             /** Hypervisor system identity - Major version number. */
    78             uint16_t                 u16HyperIdVersionMajor;
    79             /** Hypervisor system identify - Build number. */
    80             uint32_t                 u32HyperIdBuildNumber;
    81 
    82             /** Guest OS identity MSR. */
    83             uint64_t                 u64GuestOsIdMsr;
    84             /** Reference TSC page MSR. */
    85             uint64_t                 u64TscPageMsr;
    86         } hv;
     72        GIMHV Hv;
    8773
    8874        /** @todo KVM and others. */
     
    10288typedef GIMCPU *PGIMCPU;
    10389
    104 
    105 #ifdef IN_RING0
    106 #endif /* IN_RING0 */
     90#ifdef IN_RING3
     91VMM_INT_DECL(int)           GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion);
     92VMM_INT_DECL(int)           GIMR3Mmio2Map(PVM pVM, PGIMMMIO2REGION pRegion, RTGCPHYS GCPhysRegion, const char *pszDesc);
     93#endif /* IN_RING3 */
    10794
    10895/** @} */
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette