VirtualBox

Changeset 70942 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Feb 9, 2018 7:44:03 PM (7 years ago)
Author:
vboxsync
Message:

VMM/NEM: More code.

Location:
trunk/src/VBox/VMM
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/Makefile.kmk

    r70918 r70942  
    308308        VMMSwitcher/AMD64Stub.asm
    309309
    310 VBoxVMM_SOURCES.win += VMMR3/NEMR3Native-win.cpp
    311 VBoxVMM_DEFS.win    += VBOX_WITH_NATIVE_NEM
     310if1of ($(USERNAME),bird) # experimental.
     311 VBoxVMM_SOURCES.win.amd64 += VMMR3/NEMR3Native-win.cpp
     312 VBoxVMM_DEFS.win.amd64    += VBOX_WITH_NATIVE_NEM
     313 VMMR3/NEMR3Native-win.cpp_DEFS.amd64 = _AMD64_
     314 VMMR3/NEMR3Native-win.cpp_INCS = \
     315        $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17083.0/include/10.0.17083.0/um \
     316        $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17083.0/include/10.0.17083.0/shared
     317endif
    312318
    313319VBoxVMM_LIBS = \
  • trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp

    r70918 r70942  
    2121*********************************************************************************************************************************/
    2222#define LOG_GROUP LOG_GROUP_NEM
     23#include <WinHvPlatform.h>
     24
     25#ifndef _WIN32_WINNT_WIN10
     26# error "Missing _WIN32_WINNT_WIN10"
     27#endif
     28#ifndef _WIN32_WINNT_WIN10_RS1 /* Missing define, causing trouble for us. */
     29# define _WIN32_WINNT_WIN10_RS1 (_WIN32_WINNT_WIN10 + 1)
     30#endif
     31#include <sysinfoapi.h>
     32#include <fileapi.h>
     33#include <errhandlingapi.h>
     34#include <winerror.h> /* no api header for this. */
     35
    2336#include <VBox/vmm/nem.h>
    2437#include "NEMInternal.h"
    2538#include <VBox/vmm/vm.h>
    2639
     40#include <iprt/ldr.h>
     41#include <iprt/path.h>
     42#include <iprt/string.h>
     43
     44
     45/*********************************************************************************************************************************
     46*   Global Variables                                                                                                             *
     47*********************************************************************************************************************************/
     48/** @name APIs imported from WinHvPlatform.dll
     49 * @{ */
     50static decltype(WHvGetCapability) *                 g_pfnWHvGetCapability;
     51static decltype(WHvCreatePartition) *               g_pfnWHvCreatePartition;
     52static decltype(WHvSetupPartition) *                g_pfnWHvSetupPartition;
     53static decltype(WHvDeletePartition) *               g_pfnWHvDeletePartition;
     54static decltype(WHvGetPartitionProperty) *          g_pfnWHvGetPartitionProperty;
     55static decltype(WHvSetPartitionProperty) *          g_pfnWHvSetPartitionProperty;
     56static decltype(WHvMapGpaRange) *                   g_pfnWHvMapGpaRange;
     57static decltype(WHvUnmapGpaRange) *                 g_pfnWHvUnmapGpaRange;
     58static decltype(WHvTranslateGva) *                  g_pfnWHvTranslateGva;
     59static decltype(WHvCreateVirtualProcessor) *        g_pfnWHvCreateVirtualProcessor;
     60static decltype(WHvDeleteVirtualProcessor) *        g_pfnWHvDeleteVirtualProcessor;
     61static decltype(WHvRunVirtualProcessor) *           g_pfnWHvRunVirtualProcessor;
     62static decltype(WHvGetRunExitContextSize) *         g_pfnWHvGetRunExitContextSize;
     63static decltype(WHvCancelRunVirtualProcessor) *     g_pfnWHvCancelRunVirtualProcessor;
     64static decltype(WHvGetVirtualProcessorRegisters) *  g_pfnWHvGetVirtualProcessorRegisters;
     65static decltype(WHvSetVirtualProcessorRegisters) *  g_pfnWHvSetVirtualProcessorRegisters;
     66/** @} */
     67
     68
     69/**
     70 * Import instructions.
     71 */
     72static const struct
     73{
     74    uint8_t     idxDll;     /**< 0 for WinHvPlatform.dll, 1 for vid.dll. */
     75    bool        fOptional;  /**< Set if import is optional. */
     76    PFNRT      *ppfn;       /**< The function pointer variable. */
     77    const char *pszName;    /**< The function name. */
     78} g_aImports[] =
     79{
     80#define NEM_WIN_IMPORT(a_idxDll, a_fOptional, a_Name) { (a_idxDll), (a_fOptional), (PFNRT *)&RT_CONCAT(g_pfn,a_Name), #a_Name }
     81    NEM_WIN_IMPORT(0, false, WHvGetCapability),
     82    NEM_WIN_IMPORT(0, false, WHvCreatePartition),
     83    NEM_WIN_IMPORT(0, false, WHvSetupPartition),
     84    NEM_WIN_IMPORT(0, false, WHvDeletePartition),
     85    NEM_WIN_IMPORT(0, false, WHvGetPartitionProperty),
     86    NEM_WIN_IMPORT(0, false, WHvSetPartitionProperty),
     87    NEM_WIN_IMPORT(0, false, WHvMapGpaRange),
     88    NEM_WIN_IMPORT(0, false, WHvUnmapGpaRange),
     89    NEM_WIN_IMPORT(0, false, WHvTranslateGva),
     90    NEM_WIN_IMPORT(0, false, WHvCreateVirtualProcessor),
     91    NEM_WIN_IMPORT(0, false, WHvDeleteVirtualProcessor),
     92    NEM_WIN_IMPORT(0, false, WHvRunVirtualProcessor),
     93    NEM_WIN_IMPORT(0, false, WHvGetRunExitContextSize),
     94    NEM_WIN_IMPORT(0, false, WHvCancelRunVirtualProcessor),
     95    NEM_WIN_IMPORT(0, false, WHvGetVirtualProcessorRegisters),
     96    NEM_WIN_IMPORT(0, false, WHvSetVirtualProcessorRegisters),
     97#undef NEM_WIN_IMPORT
     98};
     99
     100
     101/*
     102 * Let the preprocessor alias the APIs to import variables for better autocompletion.
     103 */
     104#ifndef IN_SLICKEDIT
     105# define WHvGetCapability                           g_pfnWHvGetCapability
     106# define WHvCreatePartition                         g_pfnWHvCreatePartition
     107# define WHvSetupPartition                          g_pfnWHvSetupPartition
     108# define WHvDeletePartition                         g_pfnWHvDeletePartition
     109# define WHvGetPartitionProperty                    g_pfnWHvGetPartitionProperty
     110# define WHvSetPartitionProperty                    g_pfnWHvSetPartitionProperty
     111# define WHvMapGpaRange                             g_pfnWHvMapGpaRange
     112# define WHvUnmapGpaRange                           g_pfnWHvUnmapGpaRange
     113# define WHvTranslateGva                            g_pfnWHvTranslateGva
     114# define WHvCreateVirtualProcessor                  g_pfnWHvCreateVirtualProcessor
     115# define WHvDeleteVirtualProcessor                  g_pfnWHvDeleteVirtualProcessor
     116# define WHvRunVirtualProcessor                     g_pfnWHvRunVirtualProcessor
     117# define WHvGetRunExitContextSize                   g_pfnWHvGetRunExitContextSize
     118# define WHvCancelRunVirtualProcessor               g_pfnWHvCancelRunVirtualProcessor
     119# define WHvGetVirtualProcessorRegisters            g_pfnWHvGetVirtualProcessorRegisters
     120# define WHvSetVirtualProcessorRegisters            g_pfnWHvSetVirtualProcessorRegisters
     121#endif
     122
    27123
    28124
    29125int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced)
    30126{
    31     NOREF(pVM); NOREF(fFallback); NOREF(fForced);
     127    /*
     128     * Error state.
     129     *
     130     * The error message will be non-empty on failure, 'rc' may or  may not
     131     * be set.  Early API detection failures will not set 'rc', so we'll sort
     132     * that out at the other end of the function.
     133     */
     134    RTERRINFOSTATIC ErrInfo;
     135    int             rc = VINF_SUCCESS;
     136    PRTERRINFO pErrInfo = RTErrInfoInitStatic(&ErrInfo);
     137
     138    /*
     139     * Check that the DLL files we need are present, but without loading them.
     140     * We'd like to avoid loading them unnecessarily.
     141     */
     142    WCHAR wszPath[MAX_PATH + 64];
     143    UINT  cwcPath = GetSystemDirectoryW(wszPath, MAX_PATH);
     144    if (cwcPath >= MAX_PATH || cwcPath < 2)
     145        rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "GetSystemDirectoryW failed (%#x / %u)", cwcPath, GetLastError());
     146    else
     147    {
     148        if (wszPath[cwcPath - 1] != '\\' || wszPath[cwcPath - 1] != '/')
     149            wszPath[cwcPath++] = '\\';
     150        RTUtf16CopyAscii(&wszPath[cwcPath], RT_ELEMENTS(wszPath) - cwcPath, "WinHvPlatform.dll");
     151        if (GetFileAttributesW(wszPath) == INVALID_FILE_ATTRIBUTES)
     152            rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "The native API dll was not found (%ls)", wszPath);
     153        else
     154        {
     155            /*
     156             * Check that we're in a VM and that the hypervisor identifies itself as Hyper-V.
     157             */
     158            if (!ASMHasCpuId())
     159                rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID support");
     160            else if (!ASMIsValidStdRange(ASMCpuId_EAX(0)))
     161                rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID leaf #1");
     162            else if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
     163                rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Not in a hypervisor partition (HVP=0)");
     164            else
     165            {
     166                uint32_t cMaxHyperLeaf = 0;
     167                uint32_t uEbx = 0;
     168                uint32_t uEcx = 0;
     169                uint32_t uEdx = 0;
     170                ASMCpuIdExSlow(0x40000000, 0, 0, 0, &cMaxHyperLeaf, &uEbx, &uEcx, &uEdx);
     171                if (!ASMIsValidHypervisorRange(cMaxHyperLeaf))
     172                    rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Invalid hypervisor CPUID range (%#x %#x %#x %#x)",
     173                                       cMaxHyperLeaf, uEbx, uEcx, uEdx);
     174                else if (   uEbx != UINT32_C(0x7263694d) /* Micr */
     175                         || uEcx != UINT32_C(0x666f736f) /* osof */
     176                         || uEdx != UINT32_C(0x76482074) /* t Hv */)
     177                    rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
     178                                       "Not Hyper-V CPUID signature: %#x %#x %#x (expected %#x %#x %#x)",
     179                                       uEbx, uEcx, uEdx, UINT32_C(0x7263694d), UINT32_C(0x666f736f), UINT32_C(0x76482074));
     180                else if (cMaxHyperLeaf < UINT32_C(0x40000005))
     181                    rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Too narrow hypervisor CPUID range (%#x)", cMaxHyperLeaf);
     182                else
     183                {
     184                    /** @todo would be great if we could recognize a root partition from the
     185                     *        CPUID info, but I currently don't dare do that. */
     186
     187                    /*
     188                     * Now try load the DLLs and resolve the APIs.
     189                     */
     190                    static const char * const s_pszDllPrefixes[] = { "WinHvPlatform.dll!",  "vid.dll!" };
     191                    RTLDRMOD                  ahMods[2]          = { NIL_RTLDRMOD,          NIL_RTLDRMOD };
     192                    rc = RTLdrLoadSystem("vid.dll", true /*fNoUnload*/, &ahMods[1]);
     193                    if (RT_SUCCESS(rc))
     194                    {
     195                        rc = RTLdrLoadSystem("WinHvPlatform.dll", true /*fNoUnload*/, &ahMods[0]);
     196                        if (RT_SUCCESS(rc))
     197                        {
     198                            for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++)
     199                            {
     200                                int rc2 = RTLdrGetSymbol(ahMods[g_aImports[i].idxDll], g_aImports[i].pszName,
     201                                                         (void **)g_aImports[i].ppfn);
     202                                if (RT_FAILURE(rc2))
     203                                {
     204                                    *g_aImports[i].ppfn = NULL;
     205
     206                                    LogRel(("NEM:  %s: Failed to import %s%s: %Rrc",
     207                                            g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error",
     208                                            s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName, rc2));
     209                                    if (!g_aImports[i].fOptional)
     210                                    {
     211                                        if (RTErrInfoIsSet(pErrInfo))
     212                                            RTErrInfoAddF(pErrInfo, rc2, ", %s%s",
     213                                                          s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName);
     214                                        else
     215                                            rc = RTErrInfoSetF(pErrInfo, rc2, "Failed to import: %s%s",
     216                                                               s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName);
     217                                        Assert(RT_FAILURE(rc));
     218                                    }
     219                                }
     220                            }
     221                            if (RT_SUCCESS(rc))
     222                            {
     223                                Assert(!RTErrInfoIsSet(pErrInfo));
     224
     225                                /*
     226                                 * Check if the hypervisor API is present.
     227                                 */
     228                                /** @todo Someone (MS) please explain weird API design:
     229                                 *   1. Caps.CapabilityCode duplication,
     230                                 *   2. No output size.
     231                                 */
     232                                WHV_CAPABILITY Caps;
     233                                RT_ZERO(Caps);
     234                                SetLastError(0);
     235                                HRESULT hrc = WHvGetCapability(WHvCapabilityCodeHypervisorPresent, &Caps, sizeof(Caps));
     236                                DWORD   rcWin = GetLastError();
     237                                if (FAILED(hrc))
     238                                    rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
     239                                                       "WHvGetCapability/WHvCapabilityCodeHypervisorPresent failed: %Rhrc", hrc);
     240                                else if (!Caps.HypervisorPresent)
     241                                {
     242                                    if (!RTPathExists(RTPATH_NT_PASSTHRU_PREFIX "Device\\VidExo"))
     243                                        rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
     244                                                           "WHvCapabilityCodeHypervisorPresent is FALSE! Make sure you have enabled the 'Windows Hypervisor Platform' feature.");
     245                                    else
     246                                        rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
     247                                                           "WHvCapabilityCodeHypervisorPresent is FALSE! (%u)", rcWin);
     248                                }
     249                                else
     250                                {
     251                                    /*
     252                                     * .
     253                                     */
     254                                    LogRel(("NEM: WHvCapabilityCodeHypervisorPresent is TRUE, so this might work...\n"));
     255
     256                                    rc = RTErrInfoAddF(pErrInfo, VERR_NOT_IMPLEMENTED, "lazy bugger isn't done yet");
     257                                }
     258                            }
     259                            RTLdrClose(ahMods[0]);
     260                        }
     261                        else
     262                            rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
     263                                               "Failed to load API DLL 'WinHvPlatform.dll': %Rrc", rc);
     264                        RTLdrClose(ahMods[1]);
     265                    }
     266                    else
     267                        rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Failed to load API DLL 'vid.dll': %Rrc", rc);
     268                }
     269            }
     270        }
     271    }
     272
     273    /*
     274     * We only fail if in forced mode, otherwise just log the complaint and return.
     275     */
     276    Assert(pVM->fNEMActive || RTErrInfoIsSet(pErrInfo));
     277    if (   (fForced || !fFallback)
     278        && !pVM->fNEMActive)
     279        return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s\n", pErrInfo->pszMsg);
     280
     281    if (RTErrInfoIsSet(pErrInfo))
     282        LogRel(("NEM: Not available: %s\n", pErrInfo->pszMsg));
    32283    return VINF_SUCCESS;
    33284}
Note: See TracChangeset for help on using the changeset viewer.

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