VirtualBox

Ignore:
Timestamp:
Oct 11, 2021 8:46:03 PM (3 years ago)
Author:
vboxsync
Message:

VMM/NEM-win: Quick and very dirty hack to make the code work on windows 11. This is _not_ something we want to be doing in the longish run... bugref:10118

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp

    r91580 r91676  
    3939#include <VBox/param.h>
    4040
     41#include <iprt/ctype.h>
     42#include <iprt/critsect.h>
    4143#include <iprt/dbg.h>
     44#include <iprt/mem.h>
    4245#include <iprt/memobj.h>
    4346#include <iprt/string.h>
    4447#include <iprt/time.h>
     48#define PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS32_PECOFF
     49#include <iprt/formats/pecoff.h>
    4550
    4651
     
    7580 */
    7681static NTSTATUS (*g_pfnWinHvDepositMemory)(uintptr_t idPartition, size_t cPages, uintptr_t IdealNode, size_t *pcActuallyAdded);
     82
     83RT_C_DECLS_BEGIN
     84/**
     85 * The WinHvGetPartitionProperty function we intercept in VID.SYS to get the
     86 * Hyper-V partition ID.
     87 *
     88 * This is used from assembly.
     89 */
     90NTSTATUS WinHvGetPartitionProperty(uintptr_t idPartition, HV_PARTITION_PROPERTY_CODE enmProperty, PHV_PARTITION_PROPERTY puValue);
     91decltype(WinHvGetPartitionProperty) *g_pfnWinHvGetPartitionProperty;
     92RT_C_DECLS_END
     93
     94/** @name VID.SYS image details.
     95 * @{ */
     96static uint8_t                                 *g_pbVidSys                            = NULL;
     97static uintptr_t                                g_cbVidSys                            = 0;
     98static PIMAGE_NT_HEADERS                        g_pVidSysHdrs                         = NULL;
     99/** Pointer to the import thunk entry in VID.SYS for WinHvGetPartitionProperty if we found it. */
     100static decltype(WinHvGetPartitionProperty)    **g_ppfnVidSysWinHvGetPartitionProperty = NULL;
     101
     102/** Critical section protecting the WinHvGetPartitionProperty hacking. */
     103static RTCRITSECT                               g_VidSysCritSect;
     104RT_C_DECLS_BEGIN
     105/** The partition ID passed to WinHvGetPartitionProperty by VID.SYS.   */
     106HV_PARTITION_ID                                 g_idVidSysFoundPartition = HV_PARTITION_ID_INVALID;
     107/** The thread which is currently looking for a partition ID. */
     108RTNATIVETHREAD                                  g_hVidSysMatchThread     = NIL_RTNATIVETHREAD;
     109/** The property code we expect in WinHvGetPartitionProperty. */
     110VID_PARTITION_PROPERTY_CODE                     g_enmVidSysMatchProperty = INT64_MAX;
     111/* NEMR0NativeA-win.asm: */
     112extern uint8_t                                  g_abNemR0WinHvrWinHvGetPartitionProperty_OriginalProlog[64];
     113RT_C_DECLS_END
     114/** @} */
     115
    77116
    78117
     
    92131                                             void *pvOutput, uint32_t cbOutput);
    93132
     133/* NEMR0NativeA-win.asm: */
     134DECLASM(NTSTATUS)    nemR0VidSysWinHvGetPartitionProperty(uintptr_t idPartition, HV_PARTITION_PROPERTY_CODE enmProperty,
     135                                                          PHV_PARTITION_PROPERTY puValue);
     136DECLASM(NTSTATUS)    nemR0WinHvrWinHvGetPartitionProperty(uintptr_t idPartition, HV_PARTITION_PROPERTY_CODE enmProperty,
     137                                                          PHV_PARTITION_PROPERTY puValue);
     138
    94139
    95140/*
     
    103148#include "../VMMAll/NEMAllNativeTemplate-win.cpp.h"
    104149
     150
     151/**
     152 * Module initialization for NEM.
     153 */
     154VMMR0_INT_DECL(int)  NEMR0Init(void)
     155{
     156    return RTCritSectInit(&g_VidSysCritSect);
     157}
     158
     159
     160/**
     161 * Module termination for NEM.
     162 */
     163VMMR0_INT_DECL(void) NEMR0Term(void)
     164{
     165    RTCritSectDelete(&g_VidSysCritSect);
     166}
    105167
    106168
     
    132194}
    133195
     196
    134197/**
    135198 * Worker for NEMR0CleanupVM and NEMR0InitVM that cleans up a hypercall page.
     
    148211    pHypercallData->hMemObj    = NIL_RTR0MEMOBJ;
    149212    pHypercallData->HCPhysPage = NIL_RTHCPHYS;
     213}
     214
     215
     216static int nemR0StrICmp(const char *psz1, const char *psz2)
     217{
     218    for (;;)
     219    {
     220        char ch1 = *psz1++;
     221        char ch2 = *psz2++;
     222        if (   ch1 != ch2
     223            && RT_C_TO_LOWER(ch1) != RT_C_TO_LOWER(ch2))
     224            return ch1 - ch2;
     225        if (!ch1)
     226            return 0;
     227    }
     228}
     229
     230
     231/**
     232 * Worker for nemR0PrepareForVidSysIntercept().
     233 */
     234static void nemR0PrepareForVidSysInterceptInner(void)
     235{
     236    uint32_t const             cbImage       = g_cbVidSys;
     237    uint8_t * const            pbImage       = g_pbVidSys;
     238    PIMAGE_NT_HEADERS const    pNtHdrs       = g_pVidSysHdrs;
     239    uintptr_t const            offEndNtHdrs  = (uintptr_t)(pNtHdrs + 1) - (uintptr_t)pbImage;
     240
     241#define CHECK_LOG_RET(a_Expr, a_LogRel) do { \
     242            if (RT_LIKELY(a_Expr)) { /* likely */ } \
     243            else \
     244            { \
     245                LogRel(a_LogRel); \
     246                return; \
     247            } \
     248        } while (0)
     249
     250    //__try
     251    {
     252        /*
     253         * Get and validate the import directory entry.
     254         */
     255        CHECK_LOG_RET(   pNtHdrs->OptionalHeader.NumberOfRvaAndSizes >  IMAGE_DIRECTORY_ENTRY_IMPORT
     256                      || pNtHdrs->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_NUMBEROF_DIRECTORY_ENTRIES * 4,
     257                      ("NEMR0: vid.sys: NumberOfRvaAndSizes is out of range: %#x\n", pNtHdrs->OptionalHeader.NumberOfRvaAndSizes));
     258
     259        IMAGE_DATA_DIRECTORY const ImportDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
     260        CHECK_LOG_RET(   ImportDir.Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
     261                      && ImportDir.VirtualAddress >= offEndNtHdrs /* ASSUMES NT headers before imports */
     262                      && (uint64_t)ImportDir.VirtualAddress + ImportDir.Size <= cbImage,
     263                      ("NEMR0: vid.sys: Bad import directory entry: %#x LB %#x (cbImage=%#x, offEndNtHdrs=%#zx)\n",
     264                       ImportDir.VirtualAddress, ImportDir.Size, cbImage, offEndNtHdrs));
     265
     266        /*
     267         * Walk the import descriptor table looking for NTDLL.DLL.
     268         */
     269        for (PIMAGE_IMPORT_DESCRIPTOR pImps = (PIMAGE_IMPORT_DESCRIPTOR)&pbImage[ImportDir.VirtualAddress];
     270             pImps->Name != 0 && pImps->FirstThunk != 0;
     271             pImps++)
     272        {
     273            CHECK_LOG_RET(pImps->Name < cbImage, ("NEMR0: vid.sys: Bad import directory entry name: %#x", pImps->Name));
     274            const char *pszModName = (const char *)&pbImage[pImps->Name];
     275            if (nemR0StrICmp(pszModName, "winhvr.sys"))
     276                continue;
     277            CHECK_LOG_RET(pImps->FirstThunk < cbImage && pImps->FirstThunk >= offEndNtHdrs,
     278                          ("NEMR0: vid.sys: Bad FirstThunk: %#x", pImps->FirstThunk));
     279            CHECK_LOG_RET(   pImps->u.OriginalFirstThunk == 0
     280                          || (pImps->u.OriginalFirstThunk >= offEndNtHdrs && pImps->u.OriginalFirstThunk < cbImage),
     281                          ("NEMR0: vid.sys: Bad OriginalFirstThunk: %#x", pImps->u.OriginalFirstThunk));
     282
     283            /*
     284             * Walk the thunks table(s) looking for WinHvGetPartitionProperty.
     285             */
     286            uintptr_t *puFirstThunk = (uintptr_t *)&pbImage[pImps->FirstThunk]; /* update this. */
     287            if (   pImps->u.OriginalFirstThunk != 0
     288                && pImps->u.OriginalFirstThunk != pImps->FirstThunk)
     289            {
     290                uintptr_t const *puOrgThunk = (uintptr_t const *)&pbImage[pImps->u.OriginalFirstThunk]; /* read from this. */
     291                uintptr_t        cLeft      = (cbImage - (RT_MAX(pImps->FirstThunk, pImps->u.OriginalFirstThunk)))
     292                                            / sizeof(*puFirstThunk);
     293                while (cLeft-- > 0 && *puOrgThunk != 0)
     294                {
     295                    if (!(*puOrgThunk & IMAGE_ORDINAL_FLAG64))
     296                    {
     297                        CHECK_LOG_RET(*puOrgThunk >= offEndNtHdrs && *puOrgThunk < cbImage,
     298                                      ("NEMR0: vid.sys: Bad thunk entry: %#x", *puOrgThunk));
     299
     300                        const char *pszSymbol = (const char *)&pbImage[*puOrgThunk + 2];
     301                        if (strcmp(pszSymbol, "WinHvGetPartitionProperty") == 0)
     302                            g_ppfnVidSysWinHvGetPartitionProperty = (decltype(WinHvGetPartitionProperty) **)puFirstThunk;
     303                    }
     304
     305                    puOrgThunk++;
     306                    puFirstThunk++;
     307                }
     308            }
     309            else
     310            {
     311                /* No original thunk table, so scan the resolved symbols for a match
     312                   with the WinHvGetPartitionProperty address. */
     313                uintptr_t const uNeedle = (uintptr_t)g_pfnWinHvGetPartitionProperty;
     314                uintptr_t       cLeft   = (cbImage - pImps->FirstThunk) / sizeof(*puFirstThunk);
     315                while (cLeft-- > 0 && *puFirstThunk != 0)
     316                {
     317                    if (*puFirstThunk == uNeedle)
     318                        g_ppfnVidSysWinHvGetPartitionProperty = (decltype(WinHvGetPartitionProperty) **)puFirstThunk;
     319                    puFirstThunk++;
     320                }
     321            }
     322        }
     323
     324        /* Report the findings: */
     325        if (g_ppfnVidSysWinHvGetPartitionProperty)
     326            LogRel(("NEMR0: vid.sys: Found WinHvGetPartitionProperty import thunk at %p (value %p vs %p)\n",
     327                    g_ppfnVidSysWinHvGetPartitionProperty,*g_ppfnVidSysWinHvGetPartitionProperty, g_pfnWinHvGetPartitionProperty));
     328        else
     329            LogRel(("NEMR0: vid.sys: Did not find WinHvGetPartitionProperty!\n"));
     330    }
     331    //__except(EXCEPTION_EXECUTE_HANDLER)
     332    //{
     333    //    return;
     334    //}
     335#undef CHECK_LOG_RET
     336}
     337
     338
     339/**
     340 * Worker for NEMR0InitVM that prepares for intercepting stuff in VID.SYS.
     341 */
     342static void nemR0PrepareForVidSysIntercept(RTDBGKRNLINFO hKrnlInfo)
     343{
     344    /*
     345     * Resolve the symbols we need first.
     346     */
     347    int rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, "vid.sys", "__ImageBase", (void **)&g_pbVidSys);
     348    if (RT_SUCCESS(rc))
     349    {
     350        rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, "vid.sys", "__ImageSize", (void **)&g_cbVidSys);
     351        if (RT_SUCCESS(rc))
     352        {
     353            rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, "vid.sys", "__ImageNtHdrs", (void **)&g_pVidSysHdrs);
     354            if (RT_SUCCESS(rc))
     355            {
     356                rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, "winhvr.sys", "WinHvGetPartitionProperty",
     357                                                (void **)&g_pfnWinHvGetPartitionProperty);
     358                if (RT_SUCCESS(rc))
     359                {
     360                    /*
     361                     * Now locate the import thunk entry for WinHvGetPartitionProperty in vid.sys.
     362                     */
     363                    nemR0PrepareForVidSysInterceptInner();
     364                }
     365                else
     366                    LogRel(("NEMR0: Failed to find winhvr.sys!WinHvGetPartitionProperty (%Rrc)\n", rc));
     367            }
     368            else
     369                LogRel(("NEMR0: Failed to find vid.sys!__ImageNtHdrs (%Rrc)\n", rc));
     370        }
     371        else
     372            LogRel(("NEMR0: Failed to find vid.sys!__ImageSize (%Rrc)\n", rc));
     373    }
     374    else
     375        LogRel(("NEMR0: Failed to find vid.sys!__ImageBase (%Rrc)\n", rc));
    150376}
    151377
     
    187413                rc = rc == VERR_MODULE_NOT_FOUND ? VERR_NEM_MISSING_KERNEL_API_2 : VERR_NEM_MISSING_KERNEL_API_3;
    188414        }
     415
     416        /*
     417         * Since late 2021 we may also need to do some nasty trickery with vid.sys to get
     418         * the partition ID. So, ge the necessary info while we have a hKrnlInfo instance.
     419         */
     420        if (RT_SUCCESS(rc))
     421            nemR0PrepareForVidSysIntercept(hKrnlInfo);
     422
    189423        RTR0DbgKrnlInfoRelease(hKrnlInfo);
    190424        if (RT_SUCCESS(rc))
     
    283517
    284518/**
     519 * Here is something that we really do not wish to do, but find us force do to
     520 * right now as we cannot rewrite the memory management of VBox 6.1 in time for
     521 * windows 11.
     522 *
     523 * @returns VBox status code.
     524 * @param   pGVM        The ring-0 VM structure.
     525 * @param   pahMemObjs  Array of 6 memory objects that the caller will release.
     526 *                      ASSUMES that they are initialized to NIL.
     527 */
     528static int nemR0InitVMPart2DontWannaDoTheseUglyPartitionIdFallbacks(PGVM pGVM, PRTR0MEMOBJ pahMemObjs)
     529{
     530    /*
     531     * Check preconditions:
     532     */
     533    if (   !g_ppfnVidSysWinHvGetPartitionProperty
     534        || (uintptr_t)g_ppfnVidSysWinHvGetPartitionProperty & (sizeof(uintptr_t) - 1))
     535    {
     536        LogRel(("NEMR0: g_ppfnVidSysWinHvGetPartitionProperty is NULL or misaligned (%p), partition ID fallback not possible.\n",
     537                g_ppfnVidSysWinHvGetPartitionProperty));
     538        return VERR_NEM_INIT_FAILED;
     539    }
     540    if (!g_pfnWinHvGetPartitionProperty)
     541    {
     542        LogRel(("NEMR0: g_pfnWinHvGetPartitionProperty is NULL, partition ID fallback not possible.\n"));
     543        return VERR_NEM_INIT_FAILED;
     544    }
     545    if (!pGVM->nem.s.IoCtlGetPartitionProperty.uFunction)
     546    {
     547        LogRel(("NEMR0: IoCtlGetPartitionProperty.uFunction is 0, partition ID fallback not possible.\n"));
     548        return VERR_NEM_INIT_FAILED;
     549    }
     550
     551    /*
     552     * Create an alias for the thunk table entry because its very likely to be read-only.
     553     */
     554    int rc = RTR0MemObjLockKernel(&pahMemObjs[0], g_ppfnVidSysWinHvGetPartitionProperty, sizeof(uintptr_t), RTMEM_PROT_READ);
     555    if (RT_FAILURE(rc))
     556    {
     557        LogRel(("NEMR0: RTR0MemObjLockKernel failed on VID.SYS thunk table entry: %Rrc\n", rc));
     558        return rc;
     559    }
     560
     561    rc = RTR0MemObjEnterPhys(&pahMemObjs[1], RTR0MemObjGetPagePhysAddr(pahMemObjs[0], 0), PAGE_SIZE, RTMEM_CACHE_POLICY_DONT_CARE);
     562    if (RT_FAILURE(rc))
     563    {
     564        LogRel(("NEMR0: RTR0MemObjEnterPhys failed on VID.SYS thunk table entry: %Rrc\n", rc));
     565        return rc;
     566    }
     567
     568    rc = RTR0MemObjMapKernel(&pahMemObjs[2], pahMemObjs[1], (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
     569    if (RT_FAILURE(rc))
     570    {
     571        LogRel(("NEMR0: RTR0MemObjMapKernel failed on VID.SYS thunk table entry: %Rrc\n", rc));
     572        return rc;
     573    }
     574
     575    decltype(WinHvGetPartitionProperty) **ppfnThunkAlias
     576        = (decltype(WinHvGetPartitionProperty) **)(  (uintptr_t)RTR0MemObjAddress(pahMemObjs[2])
     577                                                   | ((uintptr_t)g_ppfnVidSysWinHvGetPartitionProperty & PAGE_OFFSET_MASK));
     578    LogRel(("NEMR0: ppfnThunkAlias=%p *ppfnThunkAlias=%p; original: %p & %p, phys %RHp\n", ppfnThunkAlias, *ppfnThunkAlias,
     579            g_ppfnVidSysWinHvGetPartitionProperty, *g_ppfnVidSysWinHvGetPartitionProperty,
     580            RTR0MemObjGetPagePhysAddr(pahMemObjs[0], 0) ));
     581
     582    /*
     583     * Create an alias for the target code in WinHvr.sys as there is a very decent
     584     * chance we have to patch it.
     585     */
     586    rc = RTR0MemObjLockKernel(&pahMemObjs[3], g_pfnWinHvGetPartitionProperty, sizeof(uintptr_t), RTMEM_PROT_READ);
     587    if (RT_FAILURE(rc))
     588    {
     589        LogRel(("NEMR0: RTR0MemObjLockKernel failed on WinHvGetPartitionProperty (%p): %Rrc\n", g_pfnWinHvGetPartitionProperty, rc));
     590        return rc;
     591    }
     592
     593    rc = RTR0MemObjEnterPhys(&pahMemObjs[4], RTR0MemObjGetPagePhysAddr(pahMemObjs[3], 0), PAGE_SIZE, RTMEM_CACHE_POLICY_DONT_CARE);
     594    if (RT_FAILURE(rc))
     595    {
     596        LogRel(("NEMR0: RTR0MemObjEnterPhys failed on WinHvGetPartitionProperty: %Rrc\n", rc));
     597        return rc;
     598    }
     599
     600    rc = RTR0MemObjMapKernel(&pahMemObjs[5], pahMemObjs[4], (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
     601    if (RT_FAILURE(rc))
     602    {
     603        LogRel(("NEMR0: RTR0MemObjMapKernel failed on WinHvGetPartitionProperty: %Rrc\n", rc));
     604        return rc;
     605    }
     606
     607    uint8_t *pbTargetAlias = (uint8_t *)(  (uintptr_t)RTR0MemObjAddress(pahMemObjs[5])
     608                                         | ((uintptr_t)g_pfnWinHvGetPartitionProperty & PAGE_OFFSET_MASK));
     609    LogRel(("NEMR0: pbTargetAlias=%p %.16Rhxs; original: %p %.16Rhxs, phys %RHp\n", pbTargetAlias, pbTargetAlias,
     610            g_pfnWinHvGetPartitionProperty, g_pfnWinHvGetPartitionProperty, RTR0MemObjGetPagePhysAddr(pahMemObjs[3], 0) ));
     611
     612    /*
     613     * Analyse the target functions prologue to figure out how much we should copy
     614     * when patching it.  We repeat this every time because we don't want to get
     615     * tripped up by someone else doing the same stuff as we're doing here.
     616     * We need at least 12 bytes for the patch sequence (MOV RAX, QWORD; JMP RAX)
     617     */
     618    union
     619    {
     620        uint8_t  ab[48];    /**< Must be equal or smallar than g_abNemR0WinHvrWinHvGetPartitionProperty_OriginalProlog */
     621        int64_t  ai64[6];
     622    } Org;
     623    memcpy(Org.ab, g_pfnWinHvGetPartitionProperty, sizeof(Org)); /** @todo ASSUMES 48 valid bytes start at function... */
     624
     625    uint32_t       offJmpBack = 0;
     626    uint32_t const cbMinJmpPatch = 12;
     627    DISSTATE       Dis;
     628    while (offJmpBack < cbMinJmpPatch && offJmpBack < sizeof(Org) - 16)
     629    {
     630        uint32_t cbInstr = 1;
     631        rc = DISInstr(&Org.ab[offJmpBack], DISCPUMODE_64BIT, &Dis, &cbInstr);
     632        if (RT_FAILURE(rc))
     633        {
     634            LogRel(("NEMR0: DISInstr failed %#x bytes into WinHvGetPartitionProperty: %Rrc (%.48Rhxs)\n",
     635                    offJmpBack, rc, Org.ab));
     636            break;
     637        }
     638        if (Dis.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW)
     639        {
     640            LogRel(("NEMR0: Control flow instruction %#x bytes into WinHvGetPartitionProperty prologue: %.48Rhxs\n",
     641                    offJmpBack, Org.ab));
     642            break;
     643        }
     644        if (Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */)
     645        {
     646            LogRel(("NEMR0: RIP relative addressing %#x bytes into WinHvGetPartitionProperty prologue: %.48Rhxs\n",
     647                    offJmpBack, Org.ab));
     648            break;
     649        }
     650        offJmpBack += cbInstr;
     651    }
     652
     653    uintptr_t const cbLeftInPage = PAGE_SIZE - ((uintptr_t)g_pfnWinHvGetPartitionProperty & PAGE_OFFSET_MASK);
     654    if (cbLeftInPage < 16 && offJmpBack >= cbMinJmpPatch)
     655    {
     656        LogRel(("NEMR0: WinHvGetPartitionProperty patching not possible do the page crossing: %p (%#zx)\n",
     657                g_pfnWinHvGetPartitionProperty, cbLeftInPage));
     658        offJmpBack = 0;
     659    }
     660    if (offJmpBack >= cbMinJmpPatch)
     661        LogRel(("NEMR0: offJmpBack=%#x for WinHvGetPartitionProperty (%p: %.48Rhxs)\n",
     662                offJmpBack, g_pfnWinHvGetPartitionProperty, Org.ab));
     663    else
     664        offJmpBack = 0;
     665    rc = VINF_SUCCESS;
     666
     667    /*
     668     * Now enter serialization lock and get on with it...
     669     */
     670    PVMCPUCC const pVCpu0 = &pGVM->aCpus[0];
     671    NTSTATUS       rcNt;
     672    RTCritSectEnter(&g_VidSysCritSect);
     673
     674    /*
     675     * First attempt, patching the import table entry.
     676     */
     677    g_idVidSysFoundPartition = HV_PARTITION_ID_INVALID;
     678    g_hVidSysMatchThread     = RTThreadNativeSelf();
     679    g_enmVidSysMatchProperty = pVCpu0->nem.s.uIoCtlBuf.GetProp.enmProperty = HvPartitionPropertyProcessorVendor;
     680    pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue = 0;
     681
     682    void *pvOld = NULL;
     683    if (ASMAtomicCmpXchgExPtr(ppfnThunkAlias, (void *)(uintptr_t)nemR0VidSysWinHvGetPartitionProperty,
     684                              (void *)(uintptr_t)g_pfnWinHvGetPartitionProperty, &pvOld))
     685    {
     686        LogRel(("NEMR0: after switch to %p: ppfnThunkAlias=%p *ppfnThunkAlias=%p; original: %p & %p\n",
     687                nemR0VidSysWinHvGetPartitionProperty, ppfnThunkAlias, *ppfnThunkAlias,
     688                g_ppfnVidSysWinHvGetPartitionProperty, *g_ppfnVidSysWinHvGetPartitionProperty));
     689
     690        rcNt = nemR0NtPerformIoControl(pGVM, pVCpu0, pGVM->nemr0.s.IoCtlGetPartitionProperty.uFunction,
     691                                       &pVCpu0->nem.s.uIoCtlBuf.GetProp.enmProperty,
     692                                       sizeof(pVCpu0->nem.s.uIoCtlBuf.GetProp.enmProperty),
     693                                       &pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue,
     694                                       sizeof(pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue));
     695        ASMAtomicWritePtr(ppfnThunkAlias, (void *)(uintptr_t)g_pfnWinHvGetPartitionProperty);
     696        HV_PARTITION_ID idHvPartition = g_idVidSysFoundPartition;
     697
     698        LogRel(("NEMR0: WinHvGetPartitionProperty trick #1 yielded: rcNt=%#x idHvPartition=%#RX64 uValue=%#RX64\n",
     699                rcNt, idHvPartition, pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue));
     700        pGVM->nemr0.s.idHvPartition = idHvPartition;
     701    }
     702    else
     703    {
     704        LogRel(("NEMR0: Unexpected WinHvGetPartitionProperty pointer in VID.SYS: %p, expected %p\n",
     705                pvOld, g_pfnWinHvGetPartitionProperty));
     706        rc = VERR_NEM_INIT_FAILED;
     707    }
     708
     709    /*
     710     * If that didn't succeed, try patching the winhvr.sys code.
     711     */
     712    if (   pGVM->nemr0.s.idHvPartition == HV_PARTITION_ID_INVALID
     713        && offJmpBack >= cbMinJmpPatch)
     714    {
     715        g_idVidSysFoundPartition = HV_PARTITION_ID_INVALID;
     716        g_hVidSysMatchThread     = RTThreadNativeSelf();
     717        g_enmVidSysMatchProperty = pVCpu0->nem.s.uIoCtlBuf.GetProp.enmProperty = HvPartitionPropertyProcessorVendor;
     718        pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue = 0;
     719
     720        /*
     721         * Prepare the hook area.
     722         */
     723        uint8_t *pbDst = g_abNemR0WinHvrWinHvGetPartitionProperty_OriginalProlog;
     724        memcpy(pbDst, (uint8_t const *)(uintptr_t)g_pfnWinHvGetPartitionProperty, offJmpBack);
     725        pbDst += offJmpBack;
     726
     727        *pbDst++ = 0x48; /* mov rax, imm64 */
     728        *pbDst++ = 0xb8;
     729        *(uint64_t *)pbDst = (uintptr_t)g_pfnWinHvGetPartitionProperty + offJmpBack;
     730        pbDst += sizeof(uint64_t);
     731        *pbDst++ = 0xff; /* jmp rax */
     732        *pbDst++ = 0xe0;
     733        *pbDst++ = 0xcc; /* int3 */
     734
     735        /*
     736         * Patch the original. We use cmpxchg16b here to avoid concurrency problems
     737         * (this also makes sure we don't trample over someone else doing similar
     738         * patching at the same time).
     739         */
     740        union
     741        {
     742            uint8_t  ab[16];
     743            uint64_t au64[2];
     744        } Patch;
     745        memcpy(Patch.ab, Org.ab, sizeof(Patch));
     746        pbDst = Patch.ab;
     747        *pbDst++ = 0x48; /* mov rax, imm64 */
     748        *pbDst++ = 0xb8;
     749        *(uint64_t *)pbDst = (uintptr_t)nemR0WinHvrWinHvGetPartitionProperty;
     750        pbDst += sizeof(uint64_t);
     751        *pbDst++ = 0xff; /* jmp rax */
     752        *pbDst++ = 0xe0;
     753
     754        int64_t ai64CmpCopy[2] = { Org.ai64[0], Org.ai64[1] }; /* paranoia  */
     755        if (_InterlockedCompareExchange128((__int64 volatile *)pbTargetAlias, Patch.au64[1], Patch.au64[0], ai64CmpCopy) != 0)
     756        {
     757            rcNt = nemR0NtPerformIoControl(pGVM, pVCpu0, pGVM->nemr0.s.IoCtlGetPartitionProperty.uFunction,
     758                                           &pVCpu0->nem.s.uIoCtlBuf.GetProp.enmProperty,
     759                                           sizeof(pVCpu0->nem.s.uIoCtlBuf.GetProp.enmProperty),
     760                                           &pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue,
     761                                           sizeof(pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue));
     762
     763            for (uint32_t cFailures = 0; cFailures < 10; cFailures++)
     764            {
     765                ai64CmpCopy[0] = Patch.au64[0]; /* paranoia */
     766                ai64CmpCopy[1] = Patch.au64[1];
     767                if (_InterlockedCompareExchange128((__int64 volatile *)pbTargetAlias, Org.ai64[1], Org.ai64[0], ai64CmpCopy) != 0)
     768                {
     769                    if (cFailures > 0)
     770                        LogRel(("NEMR0: Succeeded on try #%u.\n", cFailures));
     771                    break;
     772                }
     773                LogRel(("NEMR0: Patch restore failure #%u: %.16Rhxs, expected %.16Rhxs\n",
     774                        cFailures + 1, &ai64CmpCopy[0], &Patch.au64[0]));
     775                RTThreadSleep(1000);
     776            }
     777
     778            HV_PARTITION_ID idHvPartition = g_idVidSysFoundPartition;
     779            LogRel(("NEMR0: WinHvGetPartitionProperty trick #2 yielded: rcNt=%#x idHvPartition=%#RX64 uValue=%#RX64\n",
     780                    rcNt, idHvPartition, pVCpu0->nem.s.uIoCtlBuf.GetProp.uValue));
     781            pGVM->nemr0.s.idHvPartition = idHvPartition;
     782
     783        }
     784        else
     785        {
     786            LogRel(("NEMR0: Failed to install WinHvGetPartitionProperty patch: %.16Rhxs, expected %.16Rhxs\n",
     787                    &ai64CmpCopy[0], &Org.ai64[0]));
     788            rc = VERR_NEM_INIT_FAILED;
     789        }
     790    }
     791
     792    RTCritSectLeave(&g_VidSysCritSect);
     793
     794    return rc;
     795}
     796
     797
     798/**
    285799 * 2nd part of the initialization, after we've got a partition handle.
    286800 *
     
    305819    pGVM->nemr0.s.IoCtlGetHvPartitionId = Copy;
    306820
     821    Copy = pGVM->nem.s.IoCtlGetPartitionProperty;
     822    AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED);
     823    AssertLogRelReturn(Copy.cbInput == sizeof(VID_PARTITION_PROPERTY_CODE), VERR_NEM_INIT_FAILED);
     824    AssertLogRelReturn(Copy.cbOutput == sizeof(HV_PARTITION_PROPERTY), VERR_NEM_INIT_FAILED);
     825    pGVM->nemr0.s.IoCtlGetPartitionProperty = Copy;
     826
    307827    pGVM->nemr0.s.fMayUseRing0Runloop = pGVM->nem.s.fUseRing0Runloop;
    308828
     
    356876        NTSTATUS rcNt = nemR0NtPerformIoControl(pGVM, pVCpu0, pGVM->nemr0.s.IoCtlGetHvPartitionId.uFunction, NULL, 0,
    357877                                                &pVCpu0->nem.s.uIoCtlBuf.idPartition, sizeof(pVCpu0->nem.s.uIoCtlBuf.idPartition));
     878#if 0
    358879        AssertLogRelMsgReturn(NT_SUCCESS(rcNt), ("IoCtlGetHvPartitionId failed: %#x\n", rcNt), VERR_NEM_INIT_FAILED);
    359880        pGVM->nemr0.s.idHvPartition = pVCpu0->nem.s.uIoCtlBuf.idPartition;
     881#else
     882        /*
     883         * Since 2021 (Win11) the above I/O control doesn't work on exo-partitions
     884         * so we have to go to extremes to get at it.  Sigh.
     885         */
     886        if (   !NT_SUCCESS(rcNt)
     887            || pVCpu0->nem.s.uIoCtlBuf.idPartition == HV_PARTITION_ID_INVALID)
     888        {
     889            LogRel(("IoCtlGetHvPartitionId failed: r0=%#RX64, r3=%#RX64, rcNt=%#x\n",
     890                    pGVM->nemr0.s.idHvPartition, pGVM->nem.s.idHvPartition, rcNt));
     891
     892            RTR0MEMOBJ ahMemObjs[6]
     893                = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ };
     894            rc = nemR0InitVMPart2DontWannaDoTheseUglyPartitionIdFallbacks(pGVM, ahMemObjs);
     895            size_t i = RT_ELEMENTS(ahMemObjs);
     896            while (i-- > 0)
     897                RTR0MemObjFree(ahMemObjs[i], false /*fFreeMappings*/);
     898        }
     899        if (pGVM->nem.s.idHvPartition == HV_PARTITION_ID_INVALID)
     900            pGVM->nem.s.idHvPartition = pGVM->nemr0.s.idHvPartition;
     901#endif
    360902        AssertLogRelMsgReturn(pGVM->nemr0.s.idHvPartition == pGVM->nem.s.idHvPartition,
    361903                              ("idHvPartition mismatch: r0=%#RX64, r3=%#RX64\n", pGVM->nemr0.s.idHvPartition, pGVM->nem.s.idHvPartition),
    362904                              VERR_NEM_INIT_FAILED);
     905        if (RT_SUCCESS(rc) && pGVM->nemr0.s.idHvPartition == HV_PARTITION_ID_INVALID)
     906            rc = VERR_NEM_INIT_FAILED;
    363907    }
    364908
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