Changeset 91676 in vbox for trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp
- Timestamp:
- Oct 11, 2021 8:46:03 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp
r91580 r91676 39 39 #include <VBox/param.h> 40 40 41 #include <iprt/ctype.h> 42 #include <iprt/critsect.h> 41 43 #include <iprt/dbg.h> 44 #include <iprt/mem.h> 42 45 #include <iprt/memobj.h> 43 46 #include <iprt/string.h> 44 47 #include <iprt/time.h> 48 #define PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS32_PECOFF 49 #include <iprt/formats/pecoff.h> 45 50 46 51 … … 75 80 */ 76 81 static NTSTATUS (*g_pfnWinHvDepositMemory)(uintptr_t idPartition, size_t cPages, uintptr_t IdealNode, size_t *pcActuallyAdded); 82 83 RT_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 */ 90 NTSTATUS WinHvGetPartitionProperty(uintptr_t idPartition, HV_PARTITION_PROPERTY_CODE enmProperty, PHV_PARTITION_PROPERTY puValue); 91 decltype(WinHvGetPartitionProperty) *g_pfnWinHvGetPartitionProperty; 92 RT_C_DECLS_END 93 94 /** @name VID.SYS image details. 95 * @{ */ 96 static uint8_t *g_pbVidSys = NULL; 97 static uintptr_t g_cbVidSys = 0; 98 static PIMAGE_NT_HEADERS g_pVidSysHdrs = NULL; 99 /** Pointer to the import thunk entry in VID.SYS for WinHvGetPartitionProperty if we found it. */ 100 static decltype(WinHvGetPartitionProperty) **g_ppfnVidSysWinHvGetPartitionProperty = NULL; 101 102 /** Critical section protecting the WinHvGetPartitionProperty hacking. */ 103 static RTCRITSECT g_VidSysCritSect; 104 RT_C_DECLS_BEGIN 105 /** The partition ID passed to WinHvGetPartitionProperty by VID.SYS. */ 106 HV_PARTITION_ID g_idVidSysFoundPartition = HV_PARTITION_ID_INVALID; 107 /** The thread which is currently looking for a partition ID. */ 108 RTNATIVETHREAD g_hVidSysMatchThread = NIL_RTNATIVETHREAD; 109 /** The property code we expect in WinHvGetPartitionProperty. */ 110 VID_PARTITION_PROPERTY_CODE g_enmVidSysMatchProperty = INT64_MAX; 111 /* NEMR0NativeA-win.asm: */ 112 extern uint8_t g_abNemR0WinHvrWinHvGetPartitionProperty_OriginalProlog[64]; 113 RT_C_DECLS_END 114 /** @} */ 115 77 116 78 117 … … 92 131 void *pvOutput, uint32_t cbOutput); 93 132 133 /* NEMR0NativeA-win.asm: */ 134 DECLASM(NTSTATUS) nemR0VidSysWinHvGetPartitionProperty(uintptr_t idPartition, HV_PARTITION_PROPERTY_CODE enmProperty, 135 PHV_PARTITION_PROPERTY puValue); 136 DECLASM(NTSTATUS) nemR0WinHvrWinHvGetPartitionProperty(uintptr_t idPartition, HV_PARTITION_PROPERTY_CODE enmProperty, 137 PHV_PARTITION_PROPERTY puValue); 138 94 139 95 140 /* … … 103 148 #include "../VMMAll/NEMAllNativeTemplate-win.cpp.h" 104 149 150 151 /** 152 * Module initialization for NEM. 153 */ 154 VMMR0_INT_DECL(int) NEMR0Init(void) 155 { 156 return RTCritSectInit(&g_VidSysCritSect); 157 } 158 159 160 /** 161 * Module termination for NEM. 162 */ 163 VMMR0_INT_DECL(void) NEMR0Term(void) 164 { 165 RTCritSectDelete(&g_VidSysCritSect); 166 } 105 167 106 168 … … 132 194 } 133 195 196 134 197 /** 135 198 * Worker for NEMR0CleanupVM and NEMR0InitVM that cleans up a hypercall page. … … 148 211 pHypercallData->hMemObj = NIL_RTR0MEMOBJ; 149 212 pHypercallData->HCPhysPage = NIL_RTHCPHYS; 213 } 214 215 216 static 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 */ 234 static 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 */ 342 static 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)); 150 376 } 151 377 … … 187 413 rc = rc == VERR_MODULE_NOT_FOUND ? VERR_NEM_MISSING_KERNEL_API_2 : VERR_NEM_MISSING_KERNEL_API_3; 188 414 } 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 189 423 RTR0DbgKrnlInfoRelease(hKrnlInfo); 190 424 if (RT_SUCCESS(rc)) … … 283 517 284 518 /** 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 */ 528 static 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 /** 285 799 * 2nd part of the initialization, after we've got a partition handle. 286 800 * … … 305 819 pGVM->nemr0.s.IoCtlGetHvPartitionId = Copy; 306 820 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 307 827 pGVM->nemr0.s.fMayUseRing0Runloop = pGVM->nem.s.fUseRing0Runloop; 308 828 … … 356 876 NTSTATUS rcNt = nemR0NtPerformIoControl(pGVM, pVCpu0, pGVM->nemr0.s.IoCtlGetHvPartitionId.uFunction, NULL, 0, 357 877 &pVCpu0->nem.s.uIoCtlBuf.idPartition, sizeof(pVCpu0->nem.s.uIoCtlBuf.idPartition)); 878 #if 0 358 879 AssertLogRelMsgReturn(NT_SUCCESS(rcNt), ("IoCtlGetHvPartitionId failed: %#x\n", rcNt), VERR_NEM_INIT_FAILED); 359 880 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 360 902 AssertLogRelMsgReturn(pGVM->nemr0.s.idHvPartition == pGVM->nem.s.idHvPartition, 361 903 ("idHvPartition mismatch: r0=%#RX64, r3=%#RX64\n", pGVM->nemr0.s.idHvPartition, pGVM->nem.s.idHvPartition), 362 904 VERR_NEM_INIT_FAILED); 905 if (RT_SUCCESS(rc) && pGVM->nemr0.s.idHvPartition == HV_PARTITION_ID_INVALID) 906 rc = VERR_NEM_INIT_FAILED; 363 907 } 364 908
Note:
See TracChangeset
for help on using the changeset viewer.