- Timestamp:
- Oct 14, 2015 3:19:54 PM (9 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
r58123 r58248 172 172 && rcHv == GIM_HV_STATUS_SUCCESS) 173 173 { 174 LogRelMax(1, ("GIM: HyperV: Guest initiated debug data reception \n"));174 LogRelMax(1, ("GIM: HyperV: Guest initiated debug data reception via hypercall\n")); 175 175 rc = gimR3HvHypercallRetrieveDebugData(pVM, GCPhysOut, &rcHv); 176 176 if (RT_FAILURE(rc)) … … 192 192 && rcHv == GIM_HV_STATUS_SUCCESS) 193 193 { 194 LogRelMax(1, ("GIM: HyperV: Guest initiated debug data transmission \n"));194 LogRelMax(1, ("GIM: HyperV: Guest initiated debug data transmission via hypercall\n")); 195 195 rc = gimR3HvHypercallPostDebugData(pVM, GCPhysOut, &rcHv); 196 196 if (RT_FAILURE(rc)) … … 234 234 rcHv = GIM_HV_STATUS_INVALID_PARAMETER; 235 235 else 236 LogRelMax(1, ("GIM: HyperV: Guest resetting debug session \n"));236 LogRelMax(1, ("GIM: HyperV: Guest resetting debug session via hypercall\n")); 237 237 } 238 238 } … … 396 396 return VERR_CPUM_RAISE_GP_0; 397 397 return VINF_SUCCESS; 398 } 399 400 case MSR_GIM_HV_SYNTH_DEBUG_STATUS: 401 *puValue = pHv->uDebugStatusMsr; 402 return VINF_SUCCESS; 403 404 case MSR_GIM_HV_SINT2: 405 { 406 #ifndef IN_RING3 407 return VINF_CPUM_R3_MSR_READ; 408 #else 409 LogRelMax(10, ("GIM: HyperV: reading MSR_GIM_HV_SINT2 CS:RIP=%04x:%RX64\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu))); 410 *puValue = RT_BIT_64(16); 411 return VERR_CPUM_RAISE_GP_0; 412 #endif 413 } 414 415 case MSR_GIM_HV_SIMP: 416 { 417 #ifndef IN_RING3 418 return VINF_CPUM_R3_MSR_READ; 419 #else 420 LogRelMax(10, ("GIM: HyperV: reading MSR_GIM_HV_SIMP CS:RIP=%04x:%RX64\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu))); 421 *puValue = 0; 422 return VINF_SUCCESS; 423 #endif 398 424 } 399 425 … … 640 666 } 641 667 668 case MSR_GIM_HV_SYNTH_DEBUG_SEND_BUFFER: 669 { 670 #ifndef IN_RING3 671 return VINF_CPUM_R3_MSR_WRITE; 672 #else 673 RTGCPHYS GCPhysBuffer = (RTGCPHYS)uRawValue; 674 pHv->uDebugSendBufferMsr = GCPhysBuffer; 675 if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer)) 676 LogRel(("GIM: HyperV: Guest set up debug send buffer at %#RGp\n", GCPhysBuffer)); 677 else 678 LogRel(("GIM: HyperV: Guest destroyed debug send buffer\n")); 679 pHv->uDebugSendBufferMsr = uRawValue; 680 return VINF_SUCCESS; 681 #endif 682 } 683 684 case MSR_GIM_HV_SYNTH_DEBUG_RECEIVE_BUFFER: 685 { 686 #ifndef IN_RING3 687 return VINF_CPUM_R3_MSR_WRITE; 688 #else 689 RTGCPHYS GCPhysBuffer = (RTGCPHYS)uRawValue; 690 pHv->uDebugRecvBufferMsr = GCPhysBuffer; 691 if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer)) 692 LogRel(("GIM: HyperV: Guest set up debug receive buffer at %#RGp\n", GCPhysBuffer)); 693 else 694 LogRel(("GIM: HyperV: Guest destroyed debug receive buffer\n")); 695 return VINF_SUCCESS; 696 #endif 697 } 698 699 case MSR_GIM_HV_SYNTH_DEBUG_PENDING_BUFFER: 700 { 701 #ifndef IN_RING3 702 return VINF_CPUM_R3_MSR_WRITE; 703 #else 704 RTGCPHYS GCPhysBuffer = (RTGCPHYS)uRawValue; 705 pHv->uDebugPendingBufferMsr = GCPhysBuffer; 706 if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer)) 707 { 708 LogRel(("GIM: HyperV: Guest set up debug pending buffer at %#RGp\n", uRawValue)); 709 710 /* Indicate that there is always debug data to be read (guest will poll). */ 711 uint8_t uPendingData = 1; 712 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysBuffer, (void *)&uPendingData, sizeof(uPendingData)); 713 if (RT_FAILURE(rc)) 714 LogRelMax(5, ("GIM: HyperV: Failed to update pending buffer at %#RGp, rc=%Rrc\n", GCPhysBuffer, rc)); 715 } 716 else 717 LogRel(("GIM: HyperV: Guest destroyed debug pending buffer\n")); 718 return VINF_SUCCESS; 719 #endif 720 } 721 722 case MSR_GIM_HV_SYNTH_DEBUG_CONTROL: 723 { 724 #ifndef IN_RING3 725 return VINF_CPUM_R3_MSR_WRITE; 726 #else 727 if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_WRITE(uRawValue)) 728 { 729 LogRelMax(1, ("GIM: HyperV: Guest initiated debug data transmission via MSR\n", 730 MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue))); 731 size_t cbWrite = MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue); 732 if ( cbWrite > 0 733 && cbWrite < GIM_HV_PAGE_SIZE) 734 { 735 void *pvBuf = RTMemAlloc(cbWrite); /** @todo perhaps we can do this alloc once during VM init. */ 736 if (RT_LIKELY(pvBuf)) 737 { 738 if (PGMPhysIsGCPhysNormal(pVM, (RTGCPHYS)pHv->uDebugSendBufferMsr)) 739 { 740 int rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, (RTGCPHYS)pHv->uDebugSendBufferMsr, cbWrite); 741 if (RT_SUCCESS(rc)) 742 { 743 uint32_t cbWritten = 0; 744 rc = gimR3HvDebugWrite(pVM, pvBuf, cbWrite, &cbWritten, false /*fUdpPkt*/); 745 if ( RT_SUCCESS(rc) 746 && cbWrite == cbWritten) 747 pHv->uDebugStatusMsr = MSR_GIM_HV_SYNTH_DEBUG_STATUS_W_SUCCESS_BIT; 748 else 749 pHv->uDebugStatusMsr = 0; 750 } 751 else 752 { 753 LogRelMax(5, ("GIM: HyperV: Failed to read debug send buffer at %#RGp, rc=%Rrc\n", 754 (RTGCPHYS)pHv->uDebugSendBufferMsr, rc)); 755 } 756 } 757 else 758 LogRelMax(5, ("GIM: HyperV: Debug send buffer address %#RGp invalid! Ignoring debug write\n", 759 (RTGCPHYS)pHv->uDebugSendBufferMsr)); 760 RTMemFree(pvBuf); 761 } 762 else 763 { 764 LogRel(("GIM: HyperV: Failed to alloc %u bytes for copying debug send buffer\n", cbWrite)); 765 return VERR_NO_MEMORY; 766 } 767 } 768 } 769 else if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_READ(uRawValue)) 770 { 771 LogRelMax(1, ("GIM: HyperV: Guest initiated debug data reception via MSR\n")); 772 if (PGMPhysIsGCPhysNormal(pVM, (RTGCPHYS)pHv->uDebugRecvBufferMsr)) 773 { 774 void *pvBuf = RTMemAlloc(PAGE_SIZE); /** @todo perhaps we can do this alloc once during VM init. */ 775 if (RT_LIKELY(pvBuf)) 776 { 777 uint32_t cbReallyRead; 778 int rc = gimR3HvDebugRead(pVM, pvBuf, PAGE_SIZE, PAGE_SIZE, &cbReallyRead, 0, false /*fUdpPkt*/); 779 if ( RT_SUCCESS(rc) 780 && cbReallyRead > 0) 781 { 782 rc = PGMPhysSimpleWriteGCPhys(pVM, (RTGCPHYS)pHv->uDebugRecvBufferMsr, pvBuf, cbReallyRead); 783 if (RT_SUCCESS(rc)) 784 { 785 pHv->uDebugStatusMsr = ((uint16_t)cbReallyRead) << 16; 786 pHv->uDebugStatusMsr |= MSR_GIM_HV_SYNTH_DEBUG_STATUS_R_SUCCESS_BIT; 787 } 788 else 789 { 790 pHv->uDebugStatusMsr = 0; 791 LogRelMax(5, ("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", rc)); 792 } 793 } 794 else 795 pHv->uDebugStatusMsr = 0; 796 RTMemFree(pvBuf); 797 } 798 else 799 { 800 LogRel(("GIM: HyperV: Failed to alloc %u bytes for copying debug receive buffer\n", PAGE_SIZE)); 801 return VERR_NO_MEMORY; 802 } 803 } 804 else 805 LogRelMax(5, ("GIM: HyperV: Debug receive buffer address %#RGp invalid! Ignoring debug data reception\n")); 806 } 807 return VINF_SUCCESS; 808 #endif 809 } 810 811 case MSR_GIM_HV_SINT2: 812 #ifndef IN_RING3 813 return VINF_CPUM_R3_MSR_WRITE; 814 #else 815 LogRelMax(5, ("GIM: HyperV: Guest writing MSR_GIM_HV_SINT2 with %#RX64, ignoring CS:RIP=%04x:%RX64\n", uRawValue, 816 CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu))); 817 return VERR_CPUM_RAISE_GP_0; 818 #endif 819 642 820 case MSR_GIM_HV_CRASH_P0: pHv->uCrashP0 = uRawValue; return VINF_SUCCESS; 643 821 case MSR_GIM_HV_CRASH_P1: pHv->uCrashP1 = uRawValue; return VINF_SUCCESS; … … 660 838 return VINF_CPUM_R3_MSR_WRITE; 661 839 #else 662 LogRelMax( 1, ("GIM: HyperV: Guest setting debug options MSR to %#RX64, ignoring\n", uRawValue));840 LogRelMax(5, ("GIM: HyperV: Guest setting debug options MSR to %#RX64, ignoring\n", uRawValue)); 663 841 return VINF_SUCCESS; 664 842 #endif -
trunk/src/VBox/VMM/VMMR3/GIM.cpp
r58126 r58248 110 110 PCFGMNODE pCfgNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "GIM/"); 111 111 112 /* 113 * Validate the GIM settings. 114 */ 115 rc = CFGMR3ValidateConfig(pCfgNode, "/GIM/", 116 "Provider" /* pszValidValues */ 117 "|Version", 118 "HyperV" /* pszValidNodes */, 119 "GIM" /* pszWho */, 120 0 /* uInstance */); 121 if (RT_FAILURE(rc)) 122 return rc; 123 112 124 /** @cfgm{/GIM/Provider, string} 113 125 * The name of the GIM provider. The default is "none". */ … … 143 155 { 144 156 pVM->gim.s.enmProviderId = GIMPROVIDERID_HYPERV; 145 rc = gimR3HvInit(pVM );157 rc = gimR3HvInit(pVM, pCfgNode); 146 158 } 147 159 else if (!RTStrCmp(szProvider, "KVM")) -
trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
r58126 r58248 84 84 * Internal Functions * 85 85 *********************************************************************************************************************************/ 86 static int gimR3HvInit DebugSupport(PVM pVM);87 static void gimR3HvTerm DebugSupport(PVM pVM);86 static int gimR3HvInitHypercallSupport(PVM pVM); 87 static void gimR3HvTermHypercallSupport(PVM pVM); 88 88 89 89 … … 94 94 * @param pVM The cross context VM structure. 95 95 */ 96 VMMR3_INT_DECL(int) gimR3HvInit(PVM pVM )96 VMMR3_INT_DECL(int) gimR3HvInit(PVM pVM, PCFGMNODE pGimCfg) 97 97 { 98 98 AssertReturn(pVM, VERR_INVALID_PARAMETER); … … 105 105 * Read configuration. 106 106 */ 107 PCFGMNODE pCfgNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "GIM/HyperV"); 107 PCFGMNODE pCfgHv = CFGMR3GetChild(pGimCfg, "HyperV"); 108 if (pCfgHv) 109 { 110 /* 111 * Validate the Hyper-V settings. 112 */ 113 rc = CFGMR3ValidateConfig(pCfgHv, "/HyperV/", 114 "VendorID", 115 "" /* pszValidNodes */, "GIM/HyperV" /* pszWho */, 0 /* uInstance */); 116 if (RT_FAILURE(rc)) 117 return rc; 118 } 108 119 109 120 /** @cfgm{/GIM/HyperV/VendorID, string, 'VBoxVBoxVBox'} 110 121 * The Hyper-V vendor signature, must be 12 characters. */ 111 122 char szVendor[13]; 112 rc = CFGMR3QueryStringDef(pCfg Node, "VendorID", szVendor, sizeof(szVendor), "VBoxVBoxVBox");123 rc = CFGMR3QueryStringDef(pCfgHv, "VendorID", szVendor, sizeof(szVendor), "VBoxVBoxVBox"); 113 124 AssertLogRelRCReturn(rc, rc); 114 125 … … 119 130 pHv->fIsVendorMsHv = true; 120 131 } 132 133 pHv->fIsInterfaceVs = true; 121 134 122 135 /* … … 156 169 157 170 /* Expose more if we're posing as Microsoft. */ 158 if (pHv->fIsVendorMsHv) 171 if ( pHv->fIsVendorMsHv 172 /*&& !pHv->fIsInterfaceVs*/) 159 173 { 160 174 pHv->uMiscFeat |= GIM_HV_MISC_FEAT_GUEST_DEBUGGING … … 274 288 AssertLogRelRCReturn(rc, rc); 275 289 290 if ( pHv->fIsVendorMsHv 291 && pHv->fIsInterfaceVs) 292 { 293 HyperLeaf.uLeaf = UINT32_C(0x40000080); 294 HyperLeaf.uEax = 0; 295 HyperLeaf.uEbx = 0x7263694d; /* 'rciM' */ 296 HyperLeaf.uEcx = 0x666f736f; /* 'foso'*/ 297 HyperLeaf.uEdx = 0x53562074; /* 'SV t' */ 298 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); 299 AssertLogRelRCReturn(rc, rc); 300 301 HyperLeaf.uLeaf = UINT32_C(0x40000081); 302 HyperLeaf.uEax = 0x31235356; /* '1#SV' */ 303 HyperLeaf.uEbx = 0; 304 HyperLeaf.uEcx = 0; 305 HyperLeaf.uEdx = 0; 306 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); 307 AssertLogRelRCReturn(rc, rc); 308 309 HyperLeaf.uLeaf = UINT32_C(0x40000082); 310 HyperLeaf.uEax = RT_BIT_32(1); 311 HyperLeaf.uEbx = 0; 312 HyperLeaf.uEcx = 0; 313 HyperLeaf.uEdx = 0; 314 rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); 315 AssertLogRelRCReturn(rc, rc); 316 } 317 276 318 /* 277 319 * Insert all MSR ranges of Hyper-V. … … 290 332 291 333 /* 292 * Setup guest-host debugging connection.334 * Setup guest-host hypercall based debugging support. 293 335 */ 294 336 if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_DEBUGGING) 295 337 { 296 rc = gimR3HvInit DebugSupport(pVM);338 rc = gimR3HvInitHypercallSupport(pVM); 297 339 AssertLogRelRCReturn(rc, rc); 298 340 } … … 366 408 PGIMHV pHv = &pVM->gim.s.u.Hv; 367 409 if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_DEBUGGING) 368 gimR3HvTerm DebugSupport(pVM);410 gimR3HvTermHypercallSupport(pVM); 369 411 return VINF_SUCCESS; 370 412 } … … 422 464 * Reset MSRs (Careful! Don't reset non-zero MSRs). 423 465 */ 424 pHv->u64GuestOsIdMsr = 0; 425 pHv->u64HypercallMsr = 0; 426 pHv->u64TscPageMsr = 0; 427 pHv->uCrashP0 = 0; 428 pHv->uCrashP1 = 0; 429 pHv->uCrashP2 = 0; 430 pHv->uCrashP3 = 0; 431 pHv->uCrashP4 = 0; 466 pHv->u64GuestOsIdMsr = 0; 467 pHv->u64HypercallMsr = 0; 468 pHv->u64TscPageMsr = 0; 469 pHv->uCrashP0 = 0; 470 pHv->uCrashP1 = 0; 471 pHv->uCrashP2 = 0; 472 pHv->uCrashP3 = 0; 473 pHv->uCrashP4 = 0; 474 pHv->uDebugStatusMsr = 0; 475 pHv->uDebugPendingBufferMsr = 0; 476 pHv->uDebugSendBufferMsr = 0; 477 pHv->uDebugRecvBufferMsr = 0; 432 478 } 433 479 … … 909 955 910 956 /** 911 * Initializes Hyper-V guest debuggingsupport.957 * Initializes Hyper-V guest hypercall support. 912 958 * 913 959 * @returns VBox status code. 914 960 * @param pVM The cross context VM structure. 915 961 */ 916 static int gimR3HvInit DebugSupport(PVM pVM)962 static int gimR3HvInitHypercallSupport(PVM pVM) 917 963 { 918 964 int rc = VINF_SUCCESS; … … 931 977 932 978 /** 933 * Terminates Hyper-V guest debuggingsupport.979 * Terminates Hyper-V guest hypercall support. 934 980 * 935 981 * @param pVM The cross context VM structure. 936 982 */ 937 static void gimR3HvTerm DebugSupport(PVM pVM)983 static void gimR3HvTermHypercallSupport(PVM pVM) 938 984 { 939 985 PGIMHV pHv = &pVM->gim.s.u.Hv; … … 952 998 * @param pVM The cross context VM structure. 953 999 * @param pvBuf Where to read the data. 954 * @param cbBuf Size of the read buffer @a pvBuf. 1000 * @param cbBuf Size of the read buffer @a pvBuf, must be >= @a cbRead. 1001 * @param cbRead Number of bytes to read. 955 1002 * @param pcbRead Where to store how many bytes were really read. 956 1003 * @param cMsTimeout Timeout of the read operation in milliseconds. 1004 * @param fUdpPkt Whether the debug data returned in @a pvBuf needs to be 1005 * encapsulated in a UDP frame. 957 1006 * 958 1007 * @thread EMT. 959 1008 */ 960 static int gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead, uint32_t cMsTimeout) 961 { 962 NOREF(cMsTimeout); /** @todo implement */ 963 PGIMHV pHv = &pVM->gim.s.u.Hv;1009 VMMR3_INT_DECL(int) gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t cbRead, uint32_t *pcbRead, 1010 uint32_t cMsTimeout, bool fUdpPkt) 1011 { 1012 NOREF(cMsTimeout); /** @todo implement timeout. */ 964 1013 AssertCompile(sizeof(size_t) >= sizeof(uint32_t)); 965 size_t cbRead = cbBuf; 966 int rc = GIMR3DebugRead(pVM, pvBuf, &cbRead); 967 *pcbRead = (uint32_t)cbRead; 1014 AssertReturn(cbBuf >= cbRead, VERR_INVALID_PARAMETER); 1015 1016 /* 1017 * Read the data. 1018 */ 1019 size_t cbReallyRead = cbRead; 1020 int rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead); 1021 1022 /* 1023 * Encapsulate it in a UDP packet if required. 1024 */ 1025 if ( RT_SUCCESS(rc) 1026 && fUdpPkt 1027 && cbReallyRead > 0) 1028 { 1029 uint8_t abFrame[sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + sizeof(RTNETUDP)]; 1030 if (cbReallyRead + sizeof(abFrame) <= cbBuf) 1031 { 1032 /* 1033 * Windows guests pumps ethernet frames over the Hyper-V debug connection as 1034 * explained in gimR3HvHypercallPostDebugData(). Here, we reconstruct the packet 1035 * with the guest's self-chosen IP ARP address we saved in pHv->DbgGuestAddr. 1036 * 1037 * Note! We really need to pass the minimum IPv4 header length. The Windows 10 guest 1038 * is -not- happy if we include the IPv4 options field, i.e. using sizeof(RTNETIPV4) 1039 * instead of RTNETIPV4_MIN_LEN. 1040 */ 1041 PGIMHV pHv = &pVM->gim.s.u.Hv; 1042 RT_ZERO(abFrame); 1043 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)&abFrame[0]; 1044 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1); 1045 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN); 1046 1047 /* Ethernet */ 1048 pEthHdr->EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4); 1049 /* IPv4 */ 1050 pIpHdr->ip_v = 4; 1051 pIpHdr->ip_hl = RTNETIPV4_MIN_LEN / sizeof(uint32_t); 1052 pIpHdr->ip_tos = 0; 1053 pIpHdr->ip_len = RT_H2N_U16((uint16_t)cbReallyRead + sizeof(RTNETUDP) + RTNETIPV4_MIN_LEN); 1054 pIpHdr->ip_id = 0; 1055 pIpHdr->ip_off = 0; 1056 pIpHdr->ip_ttl = 255; 1057 pIpHdr->ip_p = RTNETIPV4_PROT_UDP; 1058 pIpHdr->ip_sum = 0; 1059 pIpHdr->ip_src.u = 0; 1060 pIpHdr->ip_dst.u = pHv->DbgGuestAddr.u; 1061 pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); 1062 /* UDP */ 1063 pUdpHdr->uh_ulen = RT_H2N_U16_C((uint16_t)cbReallyRead + sizeof(*pUdpHdr)); 1064 1065 /* Make room by moving the payload and prepending the headers. */ 1066 uint8_t *pbData = (uint8_t *)pvBuf; 1067 memmove(pbData + sizeof(abFrame), pbData, cbReallyRead); 1068 memcpy(pbData, &abFrame[0], sizeof(abFrame)); 1069 1070 /* Update the adjusted sizes. */ 1071 cbReallyRead += sizeof(abFrame); 1072 } 1073 else 1074 rc = VERR_BUFFER_UNDERFLOW; 1075 } 1076 1077 *pcbRead = (uint32_t)cbReallyRead; 968 1078 return rc; 969 1079 } … … 975 1085 * @returns VBox status code. 976 1086 * @param pVM The cross context VM structure. 977 * @param pvBuf Pointer to the data to be written. 978 * @param cbBuf Size of the write buffer @a pvBuf. 979 * @param pcbWritten Where to store how many bytes were really written. 1087 * @param pvData Pointer to the data to be written. 1088 * @param cbWrite Size of the write buffer @a pvData. 1089 * @param pcbWritten Where to store the number of bytes written. 1090 * @param fUdpPkt Whether the debug data in @a pvData is encapsulated in a 1091 * UDP frame. 980 1092 * 981 1093 * @thread EMT. 982 1094 */ 983 static int gimR3HvDebugWrite(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 984 { 985 PGIMHV pHv = &pVM->gim.s.u.Hv; 986 AssertCompile(sizeof(size_t) >= sizeof(uint32_t)); 987 size_t cbWrite = cbBuf; 988 int rc = GIMR3DebugWrite(pVM, pvBuf, &cbWrite); 989 *pcbWritten = (uint32_t)cbWrite; 990 return rc; 1095 VMMR3_INT_DECL(int) gimR3HvDebugWrite(PVM pVM, void *pvData, uint32_t cbWrite, uint32_t *pcbWritten, bool fUdpPkt) 1096 { 1097 Assert(cbWrite > 0); 1098 1099 PGIMHV pHv = &pVM->gim.s.u.Hv; 1100 bool fIgnorePkt = false; 1101 uint8_t *pbData = (uint8_t *)pvData; 1102 if (fUdpPkt) 1103 { 1104 /* 1105 * Windows guests sends us ethernet frames over the Hyper-V debug connection. 1106 * It sends DHCP/ARP queries with zero'd out MAC addresses and requires fudging up the 1107 * packets somewhere. 1108 * 1109 * The Microsoft WinDbg debugger talks UDP and thus only expects the actual debug 1110 * protocol payload. 1111 * 1112 * At present, we only handle guests configured with the "nodhcp" option. This makes 1113 * the guest send ARP queries with a self-chosen IP and after a couple of attempts of 1114 * receiving no replies, the guest picks its own IP address. After this, the guest 1115 * starts sending the UDP packets we require. We thus ignore the initial ARP packets 1116 * (and to be safe all non-UDP packets) until the guest eventually starts talking 1117 * UDP. Then we can finally feed the UDP payload over the debug connection. 1118 */ 1119 if (cbWrite > sizeof(RTNETETHERHDR)) 1120 { 1121 PCRTNETETHERHDR pEtherHdr = (PCRTNETETHERHDR)pbData; 1122 if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4)) 1123 { 1124 if (cbWrite > sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN) 1125 { 1126 size_t const cbMaxIpHdr = cbWrite - sizeof(RTNETETHERHDR) - sizeof(RTNETUDP) - 1; 1127 size_t const cbMaxIpPkt = cbWrite - sizeof(RTNETETHERHDR); 1128 PCRTNETIPV4 pIp4Hdr = (PCRTNETIPV4)(pbData + sizeof(RTNETETHERHDR)); 1129 bool const fValidIp4 = RTNetIPv4IsHdrValid(pIp4Hdr, cbMaxIpHdr, cbMaxIpPkt, false /*fChecksum*/); 1130 if ( fValidIp4 1131 && pIp4Hdr->ip_p == RTNETIPV4_PROT_UDP) 1132 { 1133 uint32_t const cbIpHdr = pIp4Hdr->ip_hl * 4; 1134 uint32_t const cbMaxUdpPkt = cbWrite - sizeof(RTNETETHERHDR) - cbIpHdr; 1135 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t *)pIp4Hdr + cbIpHdr); 1136 if ( pUdpHdr->uh_ulen > RT_H2N_U16(sizeof(RTNETUDP)) 1137 && pUdpHdr->uh_ulen <= RT_H2N_U16((uint16_t)cbMaxUdpPkt)) 1138 { 1139 /* 1140 * Extract the UDP payload and pass it to the debugger and record the guest IP address. 1141 * Hyper-V sends UDP debugger packets with source and destination port as 0. If we don't 1142 * filter out the ports here, we would receive BOOTP, NETBIOS and other UDP sub-protocol 1143 * packets which the debugger yells as "Bad packet received from...". 1144 */ 1145 if ( !pUdpHdr->uh_dport 1146 && !pUdpHdr->uh_sport) 1147 { 1148 uint32_t const cbFrameHdr = sizeof(RTNETETHERHDR) + cbIpHdr + sizeof(RTNETUDP); 1149 pbData += cbFrameHdr; 1150 cbWrite -= cbFrameHdr; 1151 pHv->DbgGuestAddr = pIp4Hdr->ip_src; 1152 } 1153 else 1154 { 1155 LogFlow(("GIM: HyperV: Ignoring UDP packet not src and dst port 0\n")); 1156 fIgnorePkt = true; 1157 } 1158 } 1159 else 1160 { 1161 LogFlow(("GIM: HyperV: Ignoring malformed UDP packet. cbMaxUdpPkt=%u UdpPkt.len=%u\n", cbMaxUdpPkt, 1162 RT_N2H_U16(pUdpHdr->uh_ulen))); 1163 fIgnorePkt = true; 1164 } 1165 } 1166 else 1167 { 1168 LogFlow(("GIM: HyperV: Ignoring non-IP / non-UDP packet. fValidIp4=%RTbool Proto=%u\n", fValidIp4, 1169 pIp4Hdr->ip_p)); 1170 fIgnorePkt = true; 1171 } 1172 } 1173 else 1174 { 1175 LogFlow(("GIM: HyperV: Ignoring IPv4 packet; too short to be valid UDP. cbWrite=%u\n", cbWrite)); 1176 fIgnorePkt = true; 1177 } 1178 } 1179 else 1180 { 1181 LogFlow(("GIM: HyperV: Ignoring non-IP packet. Ethertype=%#x\n", RT_N2H_U16(pEtherHdr->EtherType))); 1182 fIgnorePkt = true; 1183 } 1184 } 1185 } 1186 1187 if (!fIgnorePkt) 1188 { 1189 AssertCompile(sizeof(size_t) >= sizeof(uint32_t)); 1190 size_t cbWriteBuf = cbWrite; 1191 int rc = GIMR3DebugWrite(pVM, pbData, &cbWriteBuf); 1192 if ( RT_SUCCESS(rc) 1193 && cbWriteBuf == cbWrite) 1194 *pcbWritten = (uint32_t)cbWriteBuf; 1195 else 1196 *pcbWritten = 0; 1197 } 1198 else 1199 *pcbWritten = cbWrite; 1200 1201 return VINF_SUCCESS; 991 1202 } 992 1203 … … 1020 1231 1021 1232 PGIMHVDEBUGPOSTOUT pOut = (PGIMHVDEBUGPOSTOUT)pHv->pbHypercallOut; 1022 AssertPtrReturn(pOut, VERR_GIM_IPE_2);1023 uint32_t *pcbPendingWrite = &pOut->cbPending;1024 1233 1025 1234 /* … … 1034 1243 rcHv = GIM_HV_STATUS_INVALID_PARAMETER; 1035 1244 else if (!cbWrite) 1245 { 1036 1246 rcHv = GIM_HV_STATUS_SUCCESS; 1247 pOut->cbPending = 0; 1248 } 1037 1249 else if (cbWrite > 0) 1038 1250 { 1039 bool fIgnorePacket = false; 1040 if (pHv->fIsVendorMsHv) 1251 uint32_t cbWritten = 0; 1252 int rc2 = gimR3HvDebugWrite(pVM, pbData, cbWrite, &cbWritten, pHv->fIsVendorMsHv /*fUdpPkt*/); 1253 if ( RT_SUCCESS(rc2) 1254 && cbWritten == cbWrite) 1041 1255 { 1042 /* 1043 * Windows guests sends us ethernet frames over the Hyper-V debug connection. 1044 * It sends DHCP/ARP queries with zero'd out MAC addresses and requires fudging up the 1045 * packets somewhere. 1046 * 1047 * The Microsoft WinDbg debugger talks UDP and thus only expects the actual debug 1048 * protocol payload. 1049 * 1050 * At present, we only handle guests configured with the "nodhcp" option. This makes 1051 * the guest send ARP queries with a self-chosen IP and after a couple of attempts of 1052 * receiving no replies, the guest picks its own IP address. After this, the guest 1053 * starts sending the UDP packets we require. We thus ignore the initial ARP packets 1054 * (and to be safe all non-UDP packets) until the guest eventually starts talking 1055 * UDP. Then we can finally feed the UDP payload over the debug connection. 1056 */ 1057 if (cbWrite > sizeof(RTNETETHERHDR)) 1058 { 1059 PCRTNETETHERHDR pEtherHdr = (PCRTNETETHERHDR)pbData; 1060 if (pEtherHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4)) 1061 { 1062 if (cbWrite > sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN) 1063 { 1064 size_t const cbMaxIpHdr = cbWrite - sizeof(RTNETETHERHDR) - sizeof(RTNETUDP) - 1; 1065 size_t const cbMaxIpPkt = cbWrite - sizeof(RTNETETHERHDR); 1066 PCRTNETIPV4 pIp4Hdr = (PCRTNETIPV4)(pbData + sizeof(RTNETETHERHDR)); 1067 bool const fValidIp4 = RTNetIPv4IsHdrValid(pIp4Hdr, cbMaxIpHdr, cbMaxIpPkt, false /*fChecksum*/); 1068 if ( fValidIp4 1069 && pIp4Hdr->ip_p == RTNETIPV4_PROT_UDP) 1070 { 1071 uint32_t const cbIpHdr = pIp4Hdr->ip_hl * 4; 1072 uint32_t const cbMaxUdpPkt = cbWrite - sizeof(RTNETETHERHDR) - cbIpHdr; 1073 PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t *)pIp4Hdr + cbIpHdr); 1074 if ( pUdpHdr->uh_ulen > RT_H2N_U16(sizeof(RTNETUDP)) 1075 && pUdpHdr->uh_ulen <= RT_H2N_U16((uint16_t)cbMaxUdpPkt)) 1076 { 1077 /* 1078 * Extract the UDP payload and pass it to the debugger and record the guest IP address. 1079 * Hyper-V sends UDP debugger packets with source and destination port as 0. If we don't 1080 * filter out the ports here, we would receive BOOTP, NETBIOS and other UDP sub-protocol 1081 * packets which the debugger yells as "Bad packet received from...". 1082 */ 1083 if ( !pUdpHdr->uh_dport 1084 && !pUdpHdr->uh_sport) 1085 { 1086 uint32_t const cbFrameHdr = sizeof(RTNETETHERHDR) + cbIpHdr + sizeof(RTNETUDP); 1087 pbData += cbFrameHdr; 1088 cbWrite -= cbFrameHdr; 1089 pHv->DbgGuestAddr = pIp4Hdr->ip_src; 1090 } 1091 else 1092 { 1093 LogFlow(("GIM: HyperV: Ignoring UDP packet not src and dst port 0\n")); 1094 fIgnorePacket = true; 1095 } 1096 } 1097 else 1098 { 1099 LogFlow(("GIM: HyperV: Ignoring malformed UDP packet. cbMaxUdpPkt=%u UdpPkt.len=%u\n", 1100 cbMaxUdpPkt, RT_N2H_U16(pUdpHdr->uh_ulen))); 1101 fIgnorePacket = true; 1102 } 1103 } 1104 else 1105 { 1106 LogFlow(("GIM: HyperV: Ignoring non-IP / non-UDP packet. fValidIp4=%RTBool Proto=%u\n", fValidIp4, 1107 pIp4Hdr->ip_p)); 1108 fIgnorePacket = true; 1109 } 1110 } 1111 else 1112 { 1113 LogFlow(("GIM: HyperV: Ignoring IPv4 packet; too short to be valid UDP. cbWrite=%u\n", cbWrite)); 1114 fIgnorePacket = true; 1115 } 1116 } 1117 else 1118 { 1119 LogFlow(("GIM: HyperV: Ignoring non-IP packet. Ethertype=%#x\n", RT_N2H_U16(pEtherHdr->EtherType))); 1120 fIgnorePacket = true; 1121 } 1122 } 1123 } 1124 1125 if (!fIgnorePacket) 1126 { 1127 uint32_t cbReallyWritten = 0; 1128 int rc2 = gimR3HvDebugWrite(pVM, pbData, cbWrite, &cbReallyWritten); 1129 if ( RT_SUCCESS(rc2) 1130 && cbReallyWritten == cbWrite) 1131 { 1132 *pcbPendingWrite = 0; 1133 rcHv = GIM_HV_STATUS_SUCCESS; 1134 } 1135 else 1136 { 1137 /* 1138 * No need to update "*pcbPendingWrite" here as the guest isn't supposed to/doesn't 1139 * look at any of the output parameters when we fail the hypercall operation. 1140 */ 1141 rcHv = GIM_HV_STATUS_INSUFFICIENT_BUFFERS; 1142 } 1256 pOut->cbPending = 0; 1257 rcHv = GIM_HV_STATUS_SUCCESS; 1143 1258 } 1144 1259 else 1145 { 1146 /* Pretend success. */ 1147 *pcbPendingWrite = 0; 1148 rcHv = GIM_HV_STATUS_SUCCESS; 1149 } 1260 rcHv = GIM_HV_STATUS_INSUFFICIENT_BUFFER; 1150 1261 } 1151 1262 … … 1217 1328 else if (cbRead > 0) 1218 1329 { 1219 int rc2 = gimR3HvDebugRead(pVM, pvData, cbRead, pcbReallyRead, cMsTimeout); 1330 int rc2 = gimR3HvDebugRead(pVM, pvData, GIM_HV_PAGE_SIZE, cbRead, pcbReallyRead, cMsTimeout, 1331 pHv->fIsVendorMsHv /*fUdpPkt*/); 1220 1332 Assert(*pcbReallyRead <= cbRead); 1221 1333 if ( RT_SUCCESS(rc2) 1222 1334 && *pcbReallyRead > 0) 1223 1335 { 1224 uint8_t abFrame[sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + sizeof(RTNETUDP)]; 1225 if ( pHv->fIsVendorMsHv 1226 && *pcbReallyRead + sizeof(abFrame) <= GIM_HV_PAGE_SIZE) 1227 { 1228 /* 1229 * Windows guests pumps ethernet frames over the Hyper-V debug connection as 1230 * explained in gimR3HvHypercallPostDebugData(). Here, we reconstruct the packet 1231 * with the guest's self-chosen IP ARP address we saved in pHv->DbgGuestAddr. 1232 * 1233 * Note! We really need to pass the minimum IPv4 header length. The Windows 10 guest 1234 * is -not- happy if we include the IPv4 options field, i.e. using sizeof(RTNETIPV4) 1235 * instead of RTNETIPV4_MIN_LEN. 1236 */ 1237 RT_ZERO(abFrame); 1238 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)&abFrame[0]; 1239 PRTNETIPV4 pIpHdr = (PRTNETIPV4) (pEthHdr + 1); 1240 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN); 1241 1242 /* Ethernet */ 1243 pEthHdr->EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4); 1244 /* IPv4 */ 1245 pIpHdr->ip_v = 4; 1246 pIpHdr->ip_hl = RTNETIPV4_MIN_LEN / sizeof(uint32_t); 1247 pIpHdr->ip_tos = 0; 1248 pIpHdr->ip_len = RT_H2N_U16((uint16_t)*pcbReallyRead + sizeof(RTNETUDP) + RTNETIPV4_MIN_LEN); 1249 pIpHdr->ip_id = 0; 1250 pIpHdr->ip_off = 0; 1251 pIpHdr->ip_ttl = 255; 1252 pIpHdr->ip_p = RTNETIPV4_PROT_UDP; 1253 pIpHdr->ip_sum = 0; 1254 pIpHdr->ip_src.u = 0; 1255 pIpHdr->ip_dst.u = pHv->DbgGuestAddr.u; 1256 pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); 1257 /* UDP */ 1258 pUdpHdr->uh_ulen = RT_H2N_U16_C((uint16_t)*pcbReallyRead + sizeof(*pUdpHdr)); 1259 1260 /* Make room by moving the payload and prepending the headers. */ 1261 uint8_t *pbData = (uint8_t *)pvData; 1262 memmove(pbData + sizeof(abFrame), pbData, *pcbReallyRead); 1263 memcpy(pbData, &abFrame[0], sizeof(abFrame)); 1264 1265 /* Update the adjusted sizes. */ 1266 *pcbReallyRead += sizeof(abFrame); 1267 *pcbRemainingRead = cbRead - *pcbReallyRead; 1268 } 1336 *pcbRemainingRead = cbRead - *pcbReallyRead; 1269 1337 rcHv = GIM_HV_STATUS_SUCCESS; 1270 1338 } -
trunk/src/VBox/VMM/include/GIMHvInternal.h
r58014 r58248 243 243 /** Base address of synthetic interrupt event flag (R/W) */ 244 244 #define MSR_GIM_HV_SIEFP UINT32_C(0x40000082) 245 /** Base address of synthetic interrupt parameterpage (R/W) */245 /** Base address of synthetic interrupt message page (R/W) */ 246 246 #define MSR_GIM_HV_SIMP UINT32_C(0x40000083) 247 247 /** End-Of-Message in synthetic interrupt parameter page (W) */ … … 644 644 645 645 646 /** @name Hyper-V debug support. 646 /** @name Hyper-V MSR - Debug control (MSR_GIM_HV_SYNTH_DEBUG_CONTROL). 647 * @{ 648 */ 649 /** Perform debug write. */ 650 #define MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_WRITE(a) RT_BOOL((a) & RT_BIT_64(0)) 651 /** Perform debug read. */ 652 #define MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_READ(a) RT_BOOL((a) & RT_BIT_64(1)) 653 /** Returns length of the debug write buffer. */ 654 #define MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(a) (((a) & UINT64_C(0xffff0000)) >> 16) 655 /** @} */ 656 657 658 /** @name Hyper-V MSR - Debug status (MSR_GIM_HV_SYNTH_DEBUG_STATUS). 659 * @{ 660 */ 661 /** Debug send buffer operation success. */ 662 #define MSR_GIM_HV_SYNTH_DEBUG_STATUS_W_SUCCESS_BIT RT_BIT_32(0) 663 /** Debug receive buffer operation success. */ 664 #define MSR_GIM_HV_SYNTH_DEBUG_STATUS_R_SUCCESS_BIT RT_BIT_32(2) 665 /** Debug connection was reset. */ 666 #define MSR_GIM_HV_SYNTH_DEBUG_STATUS_CONN_RESET_BIT RT_BIT_32(3) 667 /** @} */ 668 669 670 /** @name Hyper-V hypercall debug support. 647 671 * Options and constants for Hyper-V debug hypercalls. 648 672 * @{ … … 837 861 /** @name Guest debugging. 838 862 * @{ */ 839 /** Whether we're posing as the officialMicrosoft vendor. */863 /** Whether we're posing as the Microsoft vendor. */ 840 864 bool fIsVendorMsHv; 841 bool afAlignment0[7]; 865 /** Whether we're posing as the Microsoft virtualization service. */ 866 bool fIsInterfaceVs; 867 bool afAlignment0[6]; 842 868 /** The auto IP address last chosen by the guest after failed ARP queries. */ 843 869 RTNETADDRIPV4 DbgGuestAddr; 844 870 uint32_t uAlignment1; 871 /** Debug send buffer MSR. */ 872 uint64_t uDebugSendBufferMsr; 873 /** Debug receive buffer MSR. */ 874 uint64_t uDebugRecvBufferMsr; 875 /** Debug pending buffer MSR. */ 876 uint64_t uDebugPendingBufferMsr; 877 /** Debug status MSR. */ 878 uint64_t uDebugStatusMsr; 845 879 /** @} */ 846 880 … … 864 898 865 899 #ifdef IN_RING3 866 VMMR3_INT_DECL(int) gimR3HvInit(PVM pVM );900 VMMR3_INT_DECL(int) gimR3HvInit(PVM pVM, PCFGMNODE pGimCfg); 867 901 VMMR3_INT_DECL(int) gimR3HvInitCompleted(PVM pVM); 868 902 VMMR3_INT_DECL(int) gimR3HvTerm(PVM pVM); … … 880 914 VMMR3_INT_DECL(int) gimR3HvHypercallPostDebugData(PVM pVM, RTGCPHYS GCPhysOut, int *prcHv); 881 915 VMMR3_INT_DECL(int) gimR3HvHypercallRetrieveDebugData(PVM pVM, RTGCPHYS GCPhysOut, int *prcHv); 916 VMMR3_INT_DECL(int) gimR3HvDebugWrite(PVM pVM, void *pvData, uint32_t cbWrite, uint32_t *pcbWritten, bool fUdpPkt); 917 VMMR3_INT_DECL(int) gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t cbRead, uint32_t *pcbRead, 918 uint32_t cMsTimeout, bool fUdpPkt); 882 919 #endif /* IN_RING3 */ 883 920
Note:
See TracChangeset
for help on using the changeset viewer.