Virtualbox源码分析23 NEM(Hyper-V兼容)4 VMExit

Native execution manager (VMExit)


本篇重点介绍NEM模式的处理VMExit的函数,基本框架和HM/Raw-mode完全一样,只是具体实现代码(调用的API)不同而已。

23.1 EPT内存管理

NEM内存管理,NEM模式的内存管理和HM模式的内存管理方法一样,EPT表也是由PGM维护,只不过当EPT表修改的之后(分配EPT内存,释放EPT内存,修改EPT内存属性等),会调用HvCallMapGpaPages/HvCallUnmapGpaPages的hypercall 修改hypervisor里的虚拟机物理地址和真机物理地址的对应关系

相关知识: A20 Gate 模拟 :相关内存在内存管理里详细介绍

https://blog.csdn.net/lightseed/article/details/4305865

23.1.1分配内存

int pgmPhysAllocPage(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
{
    ...
    //分配虚拟机物理地址,当发现开启了NEM,调用NEMHCNotifyPhysPageAllocated通知NEM需要map内存
	if (VM_IS_NEM_ENABLED(pVM))
    {
        PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
        if (   enmType != PGMPAGETYPE_ROM_SHADOW
            || pgmPhysGetPage(pVM, GCPhys) == pPage)
        {
            uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
            rc2 = NEMHCNotifyPhysPageAllocated(pVM, GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK, HCPhys,
                                               pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
            if (RT_SUCCESS(rc))
                PGM_PAGE_SET_NEM_STATE(pPage, u2State);
            else
                rc = rc2;
        }
    }
    ...
}

# define NEM_WIN_IS_SUBJECT_TO_A20(a_GCPhys)    ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K)
# define NEM_WIN_IS_RELEVANT_TO_A20(a_GCPhys)    \
    ( ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K) || ((RTGCPHYS)(a_GCPhys) < (RTGCPHYS)_64K) )

int nemHCNativeNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
                                       PGMPAGETYPE enmType, uint8_t *pu2State)
{
    PVMCPUCC pVCpu = VMMGetCpu(pVM);
    if (   pVM->nem.s.fA20Enabled
        || !NEM_WIN_IS_RELEVANT_TO_A20(GCPhys))
        rc = nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
    else
    {
        rc = nemHCWinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
        if (!NEM_WIN_IS_SUBJECT_TO_A20(GCPhys) && RT_SUCCESS(rc))
            rc = nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);

    }
}

nemHCNativeSetPhysPage

Map或者修改内存属性和状态

NEM_TMPL_STATIC int nemHCNativeSetPhysPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst,
                                           uint32_t fPageProt, uint8_t *pu2State, bool fBackingChanged)
{
    uint8_t const u2OldState = *pu2State;
    if (fPageProt == NEM_PAGE_PROT_NONE)
    {
        //需要unmap
        if (u2OldState > NEM_WIN_PAGE_STATE_UNMAPPED)
        {
            //如果之前map过,直接unmap
            rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
            if (RT_SUCCESS(rc))
            {
                *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
                //页面个数减一
                uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
            }
        }
        else
            //本来就没有map过,什么都不做
            rc = VINF_SUCCESS;
    }
    //新的页面属性需要可写
    else if (fPageProt & NEM_PAGE_PROT_WRITE)
    {
        //之前的页面属性不写,调用hypercall修改成可读可写可执行
        if (u2OldState != NEM_WIN_PAGE_STATE_WRITABLE || fBackingChanged)
        {
            //如果之前页面没有被映射过,页面个数加一
            rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
                                            HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
                                          | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
            if (RT_SUCCESS(rc))
            {
                *pu2State = NEM_WIN_PAGE_STATE_WRITABLE;
                uint32_t cMappedPages = u2OldState <= NEM_WIN_PAGE_STATE_UNMAPPED
                                      ? ASMAtomicIncU32(&pVM->nem.s.cMappedPages) : pVM->nem.s.cMappedPages;
            }
        }
        else
            rc = VINF_SUCCESS;
	}
    else
    {
        //剩下的是可读属性
        if (u2OldState != NEM_WIN_PAGE_STATE_READABLE || fBackingChanged)
        {
            rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
                                          HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
            if (RT_SUCCESS(rc))
            {
                *pu2State = NEM_WIN_PAGE_STATE_READABLE;
                //如果之前页面没有被映射过,页面个数加一
                uint32_t cMappedPages = u2OldState <= NEM_WIN_PAGE_STATE_UNMAPPED
                                      ? ASMAtomicIncU32(&pVM->nem.s.cMappedPages) : pVM->nem.s.cMappedPages;
            }
        }
        else
            rc = VINF_SUCCESS;
    }
}

nemR0WinMapPages

NEM_TMPL_STATIC int nemR0WinMapPages(PGVM pGVM, PGVMCPU pGVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst,
                                     uint32_t cPages, uint32_t fFlags)
{
    //GCPhysSrc和GCPhysDst需要相同?
    if (GCPhysSrc != GCPhysDst)
    {
        AssertMsgReturn(!(GCPhysSrc & X86_PAGE_OFFSET_MASK), ("GCPhysSrc=%RGp\n", GCPhysSrc), VERR_OUT_OF_RANGE);
        AssertReturn(GCPhysSrc < _1E, VERR_OUT_OF_RANGE);
    }
	//循环尝试,最多只尝试16次
    for (uint32_t iTries = 0;; iTries++)
    {
        HV_INPUT_MAP_GPA_PAGES *pMapPages = (HV_INPUT_MAP_GPA_PAGES *)pGVCpu->nemr0.s.HypercallData.pbPage;
        pMapPages->TargetPartitionId    = pGVM->nemr0.s.idHvPartition;
        pMapPages->TargetGpaBase        = GCPhysDst >> X86_PAGE_SHIFT;
        pMapPages->MapFlags             = fFlags;
        pMapPages->u32ExplicitPadding   = 0;
        //获取每一个虚拟机物理地址对应的真机物理地址并保存在hypercallData里
        for (uint32_t iPage = 0; iPage < cPages; iPage++, GCPhysSrc += X86_PAGE_SIZE)
        {
            RTHCPHYS HCPhys = NIL_RTGCPHYS;
            int rc = PGMPhysGCPhys2HCPhys(pGVM, GCPhysSrc, &HCPhys);
            pMapPages->PageList[iPage] = HCPhys >> X86_PAGE_SHIFT;
        }
	    //调用HvCallMapGpaPages hypercall, map虚拟机物理地址和真机物理地址
        uint64_t uResult = g_pfnHvlInvokeHypercall(HvCallMapGpaPages | ((uint64_t)cPages << 32),
                                                   pGVCpu->nemr0.s.HypercallData.HCPhysPage, 0);
        if (uResult == ((uint64_t)cPages << 32))
            return VINF_SUCCESS;
        //如果partition没有物理内存了,尝试调用WinHvDepositMemory函数分配512个page
        if (   uResult != HV_STATUS_INSUFFICIENT_MEMORY
            || iTries > 16
            || g_pfnWinHvDepositMemory == NULL)
        {
            return VERR_NEM_MAP_PAGES_FAILED;
        }
	   //调用WinHvDepositMemory函数分配512个page,返回真实分配的内存
        size_t cPagesAdded = 0;
        NTSTATUS rcNt = g_pfnWinHvDepositMemory(pGVM->nemr0.s.idHvPartition, 512, 0, &cPagesAdded);
        if (!cPagesAdded)
        {
            //分配失败,返回错误
            return VERR_NEM_MAP_PAGES_FAILED;
        }
        //分配成功,尝试再次Map内存
    }
}

23.1.2 Unmap内存

nemR0WinUnmapPages

去掉GCPhys和HCPhys的map

NEM_TMPL_STATIC int nemR0WinUnmapPages(PGVM pGVM, PGVMCPU pGVCpu, RTGCPHYS GCPhys, uint32_t cPages)
{
    HV_INPUT_UNMAP_GPA_PAGES *pUnmapPages = (HV_INPUT_UNMAP_GPA_PAGES *)pGVCpu->nemr0.s.HypercallData.pbPage;
    //partitionid
    pUnmapPages->TargetPartitionId    = pGVM->nemr0.s.idHvPartition;
    //虚拟机物理地址起始地址
    pUnmapPages->TargetGpaBase        = GCPhys >> X86_PAGE_SHIFT;
    pUnmapPages->fFlags               = 0;
    //unmap cPages个页面
    uint64_t uResult = g_pfnHvlInvokeHypercall(HvCallUnmapGpaPages | ((uint64_t)cPages << 32),
                                               pGVCpu->nemr0.s.HypercallData.HCPhysPage, 0);
    if (uResult == ((uint64_t)cPages << 32))
    {
        //unmap成功,uncomit 内存?
        uint64_t volatile uR = g_pfnHvlInvokeHypercall(HvCallUncommitGpaPages | ((uint64_t)cPages << 32),
                                                       pGVCpu->nemr0.s.HypercallData.HCPhysPage, 0);
        return VINF_SUCCESS;
    }
    return VERR_NEM_UNMAP_PAGES_FAILED;
}

nemHCWinUnmapPageForA20Gate

NEM_TMPL_STATIC DECLCALLBACK(int) nemHCWinUnsetForA20CheckerCallback(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys,
                                                                     PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
{
    if (pInfo->u2NemState > NEM_WIN_PAGE_STATE_UNMAPPED)
    {
        //unmap
        int rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhys);
        if (RT_SUCCESS(rc))
        {
            //mappd page个数减一
            uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages);
            pInfo->u2NemState = NEM_WIN_PAGE_STATE_UNMAPPED;
	    }
    }
}
NEM_TMPL_STATIC int nemHCWinUnmapPageForA20Gate(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys)
{
    PGMPHYSNEMPAGEINFO Info;
    return PGMPhysNemPageInfoChecker(pVM, pVCpu, GCPhys, false /*fMakeWritable*/, &Info,
                                     nemHCWinUnsetForA20CheckerCallback, NULL);
}
                                                                     

23.1.3 修改内存属性和页面Map关系

nemHCNativeNotifyPhysPageProtChanged

页面属性改变

void nemHCNativeNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
                                          PGMPAGETYPE enmType, uint8_t *pu2State)
{
    PVMCPUCC pVCpu = VMMGetCpu(pVM);
    if (   pVM->nem.s.fA20Enabled
        || !NEM_WIN_IS_RELEVANT_TO_A20(GCPhys))
        //开启了A20 Gate模拟或者物理地址不在A20物理地址范围内
        nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, false /*fBackingChanged*/);
    else
    {
        //没有开启A20 模拟,先unmap,再map
        nemHCWinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
        if (!NEM_WIN_IS_SUBJECT_TO_A20(GCPhys))
            nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, false /*fBackingChanged*/);
    }
}

nemHCNativeNotifyPhysPageChanged

HCPhys改变

void nemHCNativeNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew,
                                     uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State)
{
    PVMCPUCC pVCpu = VMMGetCpu(pVM);
    if (   pVM->nem.s.fA20Enabled
        || !NEM_WIN_IS_RELEVANT_TO_A20(GCPhys))
        nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
    else
    {
        nemHCWinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
        if (!NEM_WIN_IS_SUBJECT_TO_A20(GCPhys))
            nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
    }
}

23.2 VMExit处理

nemHCWinStopCpu

停止VCPU并且处理VMExit

NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinStopCpu(PVMCC pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict,
                                             VID_MESSAGE_MAPPING_HEADER volatile *pMappingHeader)
{
    //调用IOCTL停止VCPU
    pVCpu->nem.s.uIoCtlBuf.idCpu = pVCpu->idCpu;
    NTSTATUS rcNt = nemR0NtPerformIoControl(pVM, pVCpu, pVM->nemr0.s.IoCtlStopVirtualProcessor.uFunction,
                                            &pVCpu->nem.s.uIoCtlBuf.idCpu, sizeof(pVCpu->nem.s.uIoCtlBuf.idCpu),
                                            NULL, 0);
    if (NT_SUCCESS(rcNt))
    {
        return rcStrict;
    }
    //调用IOCTL获取VMExit事件
    //flags: VID_MSHAGN_F_HANDLE_MESSAGE: 标记message已经被处理了,可以继续执行GuestOS代码
    //       VID_MSHAGN_F_GET_NEXT_MESSAGE: 获取message
    rcNt = nemR0NtPerformIoCtlMessageSlotHandleAndGetNext(pVM, pVCpu, VID_MSHAGN_F_GET_NEXT_MESSAGE, 30000 /*ms*/);
    VID_MESSAGE_TYPE enmVidMsgType = pMappingHeader->enmVidMsgType;
    /*
    两个MessageType:
    VidMessageHypervisorMessage :  成功从hypervisor里获取信息
    VidMessageStopRequestComplete:停止接受Request? virtualbox对这种返回值什么都么做
    */
    if (enmVidMsgType != VidMessageStopRequestComplete)
    {
        //处理VMexit
        VBOXSTRICTRC rcStrict2 = nemHCWinHandleMessage(pVM, pVCpu, pMappingHeader);
        if (rcStrict2 != VINF_SUCCESS && RT_SUCCESS(rcStrict))
            rcStrict = rcStrict2;
        //这个地方为什么要再调用一次?
        rcNt = nemR0NtPerformIoCtlMessageSlotHandleAndGetNext(pVM, pVCpu,
                                                              VID_MSHAGN_F_HANDLE_MESSAGE | VID_MSHAGN_F_GET_NEXT_MESSAGE,
                                                              30000 /*ms*/);
        enmVidMsgType = pMappingHeader->enmVidMsgType;
        //标记VidMessageStopRequestComplete message已经被handle了
        rcNt = nemR0NtPerformIoCtlMessageSlotHandleAndGetNext(pVM, pVCpu, VID_MSHAGN_F_HANDLE_MESSAGE, 30000 /*ms*/);
    }
}

nemHCWinHandleMessage

中断处理的总入口,根据MsgType分发到对应的函数执行

NEM_TMPL_STATIC VBOXSTRICTRC
nemHCWinHandleMessage(PVMCC pVM, PVMCPUCC pVCpu, VID_MESSAGE_MAPPING_HEADER volatile *pMappingHeader)
{
    if (pMappingHeader->enmVidMsgType == VidMessageHypervisorMessage)
    {
        HV_MESSAGE const *pMsg = (HV_MESSAGE const *)(pMappingHeader + 1);
        switch (pMsg->Header.MessageType)
        {
            case HvMessageTypeUnmappedGpa:
                //虚拟机物理地址没有对应的真机物理地址 (VMX_EPT_MISCONFIG)
                return nemHCWinHandleMessageMemory(pVM, pVCpu, &pMsg->X64MemoryIntercept);
            case HvMessageTypeGpaIntercept:
                //真机物理地址访问异常(权限不对等)(VMX_EPT_VIOLATION)
                return nemHCWinHandleMessageMemory(pVM, pVCpu, &pMsg->X64MemoryIntercept);
            case HvMessageTypeX64IoPortIntercept:
                return nemHCWinHandleMessageIoPort(pVM, pVCpu, &pMsg->X64IoPortIntercept);
            case HvMessageTypeX64Halt:
                return VINF_EM_HALT;
            case HvMessageTypeX64InterruptWindow:
                return nemHCWinHandleMessageInterruptWindow(pVM, pVCpu, &pMsg->X64InterruptWindow);
            case HvMessageTypeX64CpuidIntercept:
                return nemHCWinHandleMessageCpuId(pVM, pVCpu, &pMsg->X64CpuIdIntercept);
            case HvMessageTypeX64MsrIntercept:
                return nemHCWinHandleMessageMsr(pVCpu, &pMsg->X64MsrIntercept);
            case HvMessageTypeX64ExceptionIntercept:
                return nemHCWinHandleMessageException(pVCpu, &pMsg->X64ExceptionIntercept);
            case HvMessageTypeUnrecoverableException:
                return nemHCWinHandleMessageUnrecoverableException(pVCpu, &pMsg->X64InterceptHeader);
            //下面是现在不支持的VMExit事件,直接返回
            case HvMessageTypeInvalidVpRegisterValue:
            case HvMessageTypeUnsupportedFeature:
            case HvMessageTypeTlbPageSizeMismatch:
                AssertLogRelMsgFailedReturn(("Message type %#x not implemented!\n%.32Rhxd\n", pMsg->Header.MessageType, pMsg),
                                            VERR_NEM_IPE_3);
            case HvMessageTypeX64ApicEoi:
            case HvMessageTypeX64LegacyFpError:
            case HvMessageTypeX64RegisterIntercept:
            case HvMessageTypeApicEoi:
            case HvMessageTypeFerrAsserted:
            case HvMessageTypeEventLogBufferComplete:
            case HvMessageTimerExpired:
                AssertLogRelMsgFailedReturn(("Unexpected message on CPU #%u: %#x\n", pVCpu->idCpu, pMsg->Header.MessageType),VERR_NEM_IPE_3);
            default:
                AssertLogRelMsgFailedReturn(("Unknown message on CPU #%u: %#x\n", pVCpu->idCpu, pMsg->Header.MessageType),
                                            VERR_NEM_IPE_3);
        }
    }
}

nemHCWinCopyStateFromX64Header

从VMExit header里拷贝相关信息

typedef struct
{
    //VCPU的id
    HV_VP_INDEX                     VpIndex;                
    //发生异常的指令长度
    uint8_t                         InstructionLength : 4;
    //cr8:irql
    uint8_t                         Cr8 : 4;                
    //读,写,执行标记
    HV_INTERCEPT_ACCESS_TYPE        InterceptAccessType;    /**< 0x05 */
    //一些VCPU的flags,见下面的结构体
    HV_X64_VP_EXECUTION_STATE       ExecutionState;         /**< 0x06 */
    //发生异常的指令地址信息
    HV_X64_SEGMENT_REGISTER         CsSegment;              /**< 0x08 */
    uint64_t                        Rip;                    /**< 0x18 */
    //Guest的RFlags
    uint64_t                        Rflags;                 /**< 0x20 */
} HV_X64_INTERCEPT_MESSAGE_HEADER;
typedef union
{
    uint16_t            AsUINT16;
    struct
    {
        uint16_t        Cpl                 : 2;     //R3 or R0
        uint16_t        Cr0Pe               : 1;     //是否开启分页
        uint16_t        Cr0Am               : 1;
        uint16_t        EferLma             : 1;     //是否开启长模式
        uint16_t        DebugActive         : 1;     //是否被调试
        uint16_t        InterruptionPending : 1;     //是否有pending中断
        uint16_t        Reserved0           : 5;
        uint16_t        InterruptShadow     : 1;     //是否屏蔽中断
        uint16_t        Reserved1           : 3;
    };
} HV_X64_VP_EXECUTION_STATE;

DECLINLINE(void) nemHCWinCopyStateFromX64Header(PVMCPUCC pVCpu, HV_X64_INTERCEPT_MESSAGE_HEADER const *pHdr)
{
    //拷贝cs,rip,rflags
    NEM_WIN_COPY_BACK_SEG(pVCpu->cpum.GstCtx.cs, pHdr->CsSegment);
    pVCpu->cpum.GstCtx.rip      = pHdr->Rip;
    pVCpu->cpum.GstCtx.rflags.u = pHdr->Rflags;
    //保存之前的中断屏蔽状态,后面设置GuestOS寄存器的时候用到
    pVCpu->nem.s.fLastInterruptShadow = pHdr->ExecutionState.InterruptShadow;
    if (!pHdr->ExecutionState.InterruptShadow)
    {
        //没有屏蔽中断
        //开启中断
        if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
        { /* likely */ }
        else
            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
    }
    else
        //屏蔽了中断,保持Rip(干什么用的)
        EMSetInhibitInterruptsPC(pVCpu, pHdr->Rip);
}
VMMDECL(void) EMSetInhibitInterruptsPC(PVMCPU pVCpu, RTGCUINTPTR PC)
{
    pVCpu->em.s.GCPtrInhibitInterrupts = PC;
   	//设置屏蔽了中断
    VMCPU_FF_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
}

nemHCWinHandleMessageMemory

EPT相关的VMExit

typedef struct
{
    HV_X64_INTERCEPT_MESSAGE_HEADER Header;                 /**< 0x00 */
    HV_CACHE_TYPE                   CacheType;              /**< 0x28 */
    uint8_t                         InstructionByteCount;   /**< 0x2c */
    HV_X64_MEMORY_ACCESS_INFO       MemoryAccessInfo;       /**< 0x2d */
    uint16_t                        Reserved1;              /**< 0x2e */
    uint64_t                        GuestVirtualAddress;    /**< 0x30 */
    uint64_t                        GuestPhysicalAddress;   /**< 0x38 */
    uint8_t                         InstructionBytes[16];   /**< 0x40 */
    /* We don't the following (v5 / WinHvPlatform): */
    HV_X64_SEGMENT_REGISTER         DsSegment;              /**< 0x50 */
    HV_X64_SEGMENT_REGISTER         SsSegment;              /**< 0x60 */
    uint64_t                        Rax;                    /**< 0x70 */
    uint64_t                        Rcx;                    /**< 0x78 */
    uint64_t                        Rdx;                    /**< 0x80 */
    uint64_t                        Rbx;                    /**< 0x88 */
    uint64_t                        Rsp;                    /**< 0x90 */
    uint64_t                        Rbp;                    /**< 0x98 */
    uint64_t                        Rsi;                    /**< 0xa0 */
    uint64_t                        Rdi;                    /**< 0xa8 */
    uint64_t                        R8;                     /**< 0xb0 */
    uint64_t                        R9;                     /**< 0xb8 */
    uint64_t                        R10;                    /**< 0xc0 */
    uint64_t                        R11;                    /**< 0xc8 */
    uint64_t                        R12;                    /**< 0xd0 */
    uint64_t                        R13;                    /**< 0xd8 */
    uint64_t                        R14;                    /**< 0xe0 */
    uint64_t                        R15;                    /**< 0xe8 */
} HV_X64_MEMORY_INTERCEPT_MESSAGE;

NEM_TMPL_STATIC VBOXSTRICTRC
nemHCWinHandleMessageMemory(PVMCC pVM, PVMCPUCC pVCpu, HV_X64_MEMORY_INTERCEPT_MESSAGE const *pMsg)
{
    if (pMsg->Header.ExecutionState.InterruptionPending)
        pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT;
    
    PGMPHYSNEMPAGEINFO   Info;
    int rc = PGMPhysNemPageInfoChecker(pVM, pVCpu, pMsg->GuestPhysicalAddress, State.fWriteAccess, &Info,
                                       nemHCWinHandleMemoryAccessPageCheckerCallback, &State);
    if (RT_SUCCESS(rc))
    {
        if (Info.fNemProt & (  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
                             ? NEM_PAGE_PROT_WRITE : NEM_PAGE_PROT_READ))
        {
            //如果修改过Hypervisor里的map关系,重新执行这条指令
            if (State.fCanResume)
            {
                EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_NEM, NEMEXITTYPE_MEMORY_ACCESS),
                                 pMsg->Header.Rip + pMsg->Header.CsSegment.Base, uHostTsc);
                return VINF_SUCCESS;
            }
        }
    }
    //PGMPhysNemPageInfoChecker里没有任何修改,模拟执行,交给IEM处理
    //模拟执行内存访问代码    
    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
                                              pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
                                            ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_WRITE)
                                            : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_READ),
                                            pMsg->Header.Rip + pMsg->Header.CsSegment.Base, uHostTsc);
    //从GuestOS里拷贝信息
    nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
    rcStrict = nemR0WinImportStateStrict(pVM, pVCpu,
                                         NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM | CPUMCTX_EXTRN_DS | CPUMCTX_EXTRN_ES, "MemExit");
    if (rcStrict != VINF_SUCCESS)
        return rcStrict;
    if (!pExitRec)
    {
        //模拟执行一条指令
        if (pMsg->InstructionByteCount > 0)
            rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx), pMsg->Header.Rip,
                                                    pMsg->InstructionBytes, pMsg->InstructionByteCount);
        else
            rcStrict = IEMExecOne(pVCpu);
    }
    else
    {
        //模拟执行多条指令
        rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
    }
    return rcStrict;
}

nemHCWinHandleMemoryAccessPageCheckerCallback

NEM_TMPL_STATIC DECLCALLBACK(int)
nemHCWinHandleMemoryAccessPageCheckerCallback(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
{
    NEMHCWINHMACPCCSTATE *pState = (NEMHCWINHMACPCCSTATE *)pvUser;
    pState->fDidSomething = false;
    pState->fCanResume    = false;
    
    //u2NemState:当前NEM页面属性
    //fNemProt: 需要的页面属性
    uint8_t  u2State = pInfo->u2NemState;
    RTGCPHYS GCPhysSrc;
    if (   pVM->nem.s.fA20Enabled
        || !NEM_WIN_IS_SUBJECT_TO_A20(GCPhys))
        GCPhysSrc = GCPhys;
    else
    {
        GCPhysSrc = GCPhys & ~(RTGCPHYS)RT_BIT_32(20);
        PGMPHYSNEMPAGEINFO Info2;
        //再次获取当前内存属性
        int rc = PGMPhysNemPageInfoChecker(pVM, pVCpu, GCPhysSrc, pState->fWriteAccess, &Info2, NULL, NULL);
        *pInfo = Info2;
        pInfo->u2NemState = u2State;
    }
    
    int rc;
    switch (u2State)
    {
        case NEM_WIN_PAGE_STATE_UNMAPPED:
        case NEM_WIN_PAGE_STATE_NOT_SET:
          	//之前没有map,新的状态还是不需要map, 直接返回,模拟执行内存访问指令
            if (pInfo->fNemProt == NEM_PAGE_PROT_NONE)
            {
                return VINF_SUCCESS;
            }

            //如果新的页面不需要可写属性,返回去模拟执行
            if (   pState->fWriteAccess
                && !(pInfo->fNemProt & NEM_PAGE_PROT_WRITE))
            {
                return VINF_SUCCESS;
            }

            //map页面
            rc = nemHCNativeSetPhysPage(pVM,
                                        pVCpu,
                                        GCPhysSrc & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
                                        GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
                                        pInfo->fNemProt,
                                        &u2State,
                                        true /*fBackingState*/);
            pInfo->u2NemState = u2State;
            pState->fDidSomething = true;
            //页面处理完成,可以重新执行内存访问指令
            pState->fCanResume    = true;
            return rc;
        case NEM_WIN_PAGE_STATE_READABLE:
            //如果之前内存可读,但是不需要内存可写,直接返回,模拟执行内存访问指令
            if (   !(pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
                && (pInfo->fNemProt & (NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE)))
            {
                return VINF_SUCCESS;
            }
	        //需要内存可写,修改页面属性加上可写
            if (   (pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
                && pState->fWriteAccess)
            {
                //修改页面map属性加上可读
                rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhys,
                                              HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
                                              | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
                if (RT_SUCCESS(rc))
                {
                    //标记页面属性可以写,返回重新执行内存访问指令
                    pInfo->u2NemState = NEM_WIN_PAGE_STATE_WRITABLE;
                    pState->fDidSomething = true;
                    pState->fCanResume    = true;
                }
            }
            else
            {
                //返回,模拟执行内存访问指令
                rc = VINF_SUCCESS;
            }
            return rc;
        case NEM_WIN_PAGE_STATE_WRITABLE:
            //原本内存可写,而且需要内存可写的页面,什么都不做
            if (pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
            {
                //原本内存就可以写,什么都没改变,返回,模拟执行内存访问指令
                if (pInfo->u2OldNemState == NEM_WIN_PAGE_STATE_WRITABLE)
                else
                {
                    //内存属性改变,重新执行这条内存访问指令
                    pState->fCanResume = true;
                }
                return VINF_SUCCESS;
            }
            AssertFailed();
    }
   
    return VINF_SUCCESS;
}

nemHCWinHandleMessageIoPort

处理过程和VMX模式的hmR0VmxExitIoInstr函数处理过程类似

NEM_TMPL_STATIC VBOXSTRICTRC
nemHCWinHandleMessageIoPort(PVMCC pVM, PVMCPUCC pVCpu, HV_X64_IO_PORT_INTERCEPT_MESSAGE const *pMsg)
{
    if (pMsg->Header.ExecutionState.InterruptionPending)
        pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT;
   	//判断是否可以模拟执行多条指令
    VBOXSTRICTRC rcStrict;
    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
                                            !pMsg->AccessInfo.StringOp
                                            ? (  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
                                               ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_WRITE)
                                               : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_READ))
                                            : (  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
                                               ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_WRITE)
                                               : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_READ)),
                                            pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
    if (!pExitRec)
    {
        if (!pMsg->AccessInfo.StringOp)
        {
            //in/out指令
            nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
            if (pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE)
            {
                //OUT 指令,调用IOMIOPortWrite往IO Port写入数据
                rcStrict = IOMIOPortWrite(pVM, pVCpu, pMsg->PortNumber, (uint32_t)pMsg->Rax & fAndMask, pMsg->AccessInfo.AccessSize);
                if (IOM_SUCCESS(rcStrict))
                    nemHCWinAdvanceGuestRipAndClearRF(pVCpu, &pMsg->Header, 1);
                else if (   rcStrict == VINF_IOM_R3_IOPORT_WRITE
                         && !pVCpu->cpum.GstCtx.rflags.Bits.u1TF)
                    //调用IOMIOPortWrite失败,设置pending IO event,返回R3循环处理
                    return EMRZSetPendingIoPortWrite(pVCpu, pMsg->PortNumber, pMsg->Header.InstructionLength,pMsg->AccessInfo.AccessSize, (uint32_t)pMsg->Rax & fAndMask);
                else
                {
                    //设置了单步
                    pVCpu->cpum.GstCtx.rax = pMsg->Rax;
                    pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_RAX;
                }
            }
            else
            {
                //IN指令,调用IOMIOPortRead读取IO Port
                uint32_t uValue = 0;
                rcStrict = IOMIOPortRead(pVM, pVCpu, pMsg->PortNumber, &uValue, pMsg->AccessInfo.AccessSize);
                if (IOM_SUCCESS(rcStrict))
                {
                    //读取IOport成功,继续执行下一条指令
                    if (pMsg->AccessInfo.AccessSize != 4)
                        pVCpu->cpum.GstCtx.rax = (pMsg->Rax & ~(uint64_t)fAndMask) | (uValue & fAndMask);
                    else
                        pVCpu->cpum.GstCtx.rax = uValue;
                    pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_RAX;
                    nemHCWinAdvanceGuestRipAndClearRF(pVCpu, &pMsg->Header, 1);
                }
                else
                {
                    //调用IOMIOPortRead失败,设置pending IO event,返回R3循环处理
                    pVCpu->cpum.GstCtx.rax = pMsg->Rax;
                    pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_RAX;
                    if (   rcStrict == VINF_IOM_R3_IOPORT_READ
                        && !pVCpu->cpum.GstCtx.rflags.Bits.u1TF
                        return EMRZSetPendingIoPortRead(pVCpu, pMsg->PortNumber, pMsg->Header.InstructionLength,pMsg->AccessInfo.AccessSize);
                 }
            }
        }
        else
		{
            //ins/outs指令
            nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
            pVCpu->cpum.GstCtx.fExtrn &= ~(  CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDI | CPUMCTX_EXTRN_RSI
                              | CPUMCTX_EXTRN_DS  | CPUMCTX_EXTRN_ES);
            NEM_WIN_COPY_BACK_SEG(pVCpu->cpum.GstCtx.ds, pMsg->DsSegment);
            NEM_WIN_COPY_BACK_SEG(pVCpu->cpum.GstCtx.es, pMsg->EsSegment);
            pVCpu->cpum.GstCtx.rax = pMsg->Rax;
            pVCpu->cpum.GstCtx.rcx = pMsg->Rcx;
            pVCpu->cpum.GstCtx.rdi = pMsg->Rdi;
            pVCpu->cpum.GstCtx.rsi = pMsg->Rsi;
            rcStrict = nemR0WinImportStateStrict(pVM, pVCpu, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "IOExit");
            if (rcStrict != VINF_SUCCESS)
                return rcStrict;
            //让IEM模拟执行处理这条指令
            //FNIEMOP_DEF(iemOp_inswd_Yv_DX) FNIEMOP_DEF(iemOp_outsb_Yb_DX) FNIEMOP_DEF(iemOp_outswd_Yv_DX) 等函数模拟执行
            rcStrict = IEMExecOne(pVCpu);
		}
         return rcStrict;
    }
    //到这边是需要模拟执行多条代码
    //获取异常信息
    nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
    if (!pMsg->AccessInfo.StringOp)
        pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_RAX;
    else
    {
        pVCpu->cpum.GstCtx.fExtrn &= ~(  CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDI | CPUMCTX_EXTRN_RSI
                          | CPUMCTX_EXTRN_DS  | CPUMCTX_EXTRN_ES);
        NEM_WIN_COPY_BACK_SEG(pVCpu->cpum.GstCtx.ds, pMsg->DsSegment);
        NEM_WIN_COPY_BACK_SEG(pVCpu->cpum.GstCtx.es, pMsg->EsSegment);
        pVCpu->cpum.GstCtx.rcx = pMsg->Rcx;
        pVCpu->cpum.GstCtx.rdi = pMsg->Rdi;
        pVCpu->cpum.GstCtx.rsi = pMsg->Rsi;
    }
    pVCpu->cpum.GstCtx.rax = pMsg->Rax;
    //从GuestOS里获取IEM需要的寄存器内存
    rcStrict = nemR0WinImportStateStrict(pVM, pVCpu, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "IOExit");
    if (rcStrict != VINF_SUCCESS)
        return rcStrict;
    //一次执行多条指令
    rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
    return rcStrict;
}

nemHCWinHandleMessageInterruptWindow

对应VMX的hmR0VmxExitIntWindow (VMX_EXIT_INT_WINDOW)函数,现在都是什么都没做

NEM_TMPL_STATIC VBOXSTRICTRC
nemHCWinHandleMessageInterruptWindow(PVMCC pVM, PVMCPUCC pVCpu, HV_X64_INTERRUPT_WINDOW_MESSAGE const *pMsg)
{
    EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_NEM, NEMEXITTYPE_INTTERRUPT_WINDOW),
                     pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
    nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
    //现在什么都没做
}

nemHCWinHandleMessageCpuId

对应VMX的hmR0VmxExitCpuid(hmR0VmxExitCpuid)函数

NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleMessageCpuId(PVMCC pVM, PVMCPUCC pVCpu, HV_X64_CPUID_INTERCEPT_MESSAGE const *pMsg)
{
    //是否需要连续模拟执行多条指令
    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_CPUID),
                                            pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
    if (!pExitRec)
    {
        //只模拟执行一条指令
        nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
        //获取CPUID的参数
        pVCpu->cpum.GstCtx.rax = (uint32_t)pMsg->Rax;
        pVCpu->cpum.GstCtx.rcx = (uint32_t)pMsg->Rcx;
        pVCpu->cpum.GstCtx.rdx = (uint32_t)pMsg->Rdx;
        pVCpu->cpum.GstCtx.rbx = (uint32_t)pMsg->Rbx;
        pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
        //调用CPUM里的API获取CPUID的返回值
        CPUMGetGuestCpuId(pVCpu, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx,
                          &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx, &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
       	//RIP指向下一条指令
        nemHCWinAdvanceGuestRipAndClearRF(pVCpu, &pMsg->Header, 2);
        return VINF_SUCCESS;
    }
   	//模拟执行多条指令
    nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
    pVCpu->cpum.GstCtx.rax = pMsg->Rax;
    pVCpu->cpum.GstCtx.rcx = pMsg->Rcx;
    pVCpu->cpum.GstCtx.rdx = pMsg->Rdx;
    pVCpu->cpum.GstCtx.rbx = pMsg->Rbx;
    pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
    
    VBOXSTRICTRC rcStrict = nemR0WinImportStateStrict(pVM, pVCpu, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "CpuIdExit");
    if (rcStrict != VINF_SUCCESS)
        return rcStrict;
    //模拟执行多条指令
    VBOXSTRICTRC rcStrictExec = EMHistoryExec(pVCpu, pExitRec, 0);
    return rcStrictExec;
}

nemHCWinHandleMessageMsr

对应VMX的hmR0VmxExitRdmsr/hmR0VmxExitWrmsr函数,从CPUM里获取MSR寄存器的值

typedef struct _HV_X64_MSR_INTERCEPT_MESSAGE
{
    HV_X64_INTERCEPT_MESSAGE_HEADER     Header;                 /**< 0x00 */
    uint32_t                            MsrNumber;              /**< 0x28 (ecx) */
    uint32_t                            Reserved;               /**< 0x2c */
    uint64_t                            Rdx;                    /**< 0x30 */
    uint64_t                            Rax;                    /**< 0x38 */
} HV_X64_MSR_INTERCEPT_MESSAGE;

NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleMessageMsr(PVMCPUCC pVCpu, HV_X64_MSR_INTERCEPT_MESSAGE const *pMsg)
{
  if (pMsg->Header.ExecutionState.Cpl == 0)
  {
    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
                                            pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
                                            ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_WRITE)
                                            : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_READ),
                                            pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
	//从VMExit信息里拷贝数据
    nemHCWinCopyStateFromX64Header(pVCpu, &pMsg->Header);
	//调用hypercall获取需要的Guest寄存器信息
    rcStrict = nemHCWinImportStateIfNeededStrict(pVCpu,
                                                 (!pExitRec ? 0 : IEM_CPUMCTX_EXTRN_MUST_MASK)
                                                 | CPUMCTX_EXTRN_ALL_MSRS | CPUMCTX_EXTRN_CR0
                                                 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4,
                                                 "MSRs");
    if (rcStrict == VINF_SUCCESS)
    {
        if (!pExitRec)
        {
            //不连续执行多条指令
            if (pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE)
            {
                //wrmsr
                rcStrict = CPUMSetGuestMsr(pVCpu, pMsg->MsrNumber, RT_MAKE_U64((uint32_t)pMsg->Rax, (uint32_t)pMsg->Rdx));
                if (rcStrict == VINF_SUCCESS)
                {
                    nemHCWinAdvanceGuestRipAndClearRF(pVCpu, &pMsg->Header, 2);
                    return VINF_SUCCESS;
                }
                //如果模拟执行返回需要注入中断,返回让R3模拟执行?
                if (rcStrict == VERR_CPUM_RAISE_GP_0)
                    rcStrict = VINF_CPUM_R3_MSR_WRITE;
                return rcStrict;
            }
            else
            {
                //rdmsr
                uint64_t uValue = 0;
                //调用CPUM里的函数,读取msr
                rcStrict = CPUMQueryGuestMsr(pVCpu, pMsg->MsrNumber, &uValue);
                if (rcStrict == VINF_SUCCESS)
                {
                    //写入cpum,后面会写入GuestOS里
                    pVCpu->cpum.GstCtx.rax = (uint32_t)uValue;
                    pVCpu->cpum.GstCtx.rdx = uValue >> 32;
                    pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
                    nemHCWinAdvanceGuestRipAndClearRF(pVCpu, &pMsg->Header, 2);
                    return VINF_SUCCESS;
                }
            }
        }
        else
        {
            //模拟执行多条指令
            rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
            return rcStrict;
        }
    }
  }
  //R3调用msr指令,注入GP
  //先从GuestOS里读取需要的寄存器
  rcStrict = nemHCWinImportStateIfNeededStrict(pVCpu, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM | CPUMCTX_EXTRN_ALL_MSRS, "MSR");
  if (rcStrict == VINF_SUCCESS)
  {		
      //模拟执行注入一个GP
      rcStrict = IEMInjectTrap(pVCpu, X86_XCPT_GP, TRPM_TRAP, 0, 0, 0);
      if (rcStrict == VINF_IEM_RAISED_XCPT)
          rcStrict = VINF_SUCCESS;
  }
}

nemHCWinHandleMessageException

NEM_TMPL_STATIC VBOXSTRICTRC
nemHCWinHandleMessageException(PVMCPUCC pVCpu, HV_X64_EXCEPTION_INTERCEPT_MESSAGE const *pMsg)
{
    //从GuestOS里读取异常处理需要的相关寄存器信息
    nemHCWinCopyStateFromExceptionMessage(pVCpu, pMsg, true /*fClearXcpt*/);
    uint64_t fWhat = NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM;
    //如果是DB异常,还需要获取相关DRx寄存器
    if (pMsg->ExceptionVector == X86_XCPT_DB)
        fWhat |= CPUMCTX_EXTRN_DR0_DR3 | CPUMCTX_EXTRN_DR7 | CPUMCTX_EXTRN_DR6;
    VBOXSTRICTRC rcStrict = nemHCWinImportStateIfNeededStrict(pVCpu, fWhat, "Xcpt");
    //处理异常
    TRPMEVENT enmEvtType = TRPM_TRAP;
    switch (pMsg->ExceptionVector)
    {
        //UD
        case X86_XCPT_UD:
            EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_NEM, NEMEXITTYPE_XCPT_UD),
                             pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
		   //如果是VMMCALL(AMD) & VMCALL(Intel)指令,需要模拟执行这条指令,其他UD异常直接inject给Guest
            if (nemHcWinIsInterestingUndefinedOpcode(pMsg->InstructionByteCount, pMsg->InstructionBytes,
                                                     pMsg->Header.ExecutionState.EferLma && pMsg->Header.CsSegment.Long ))
            {
                //VMMCALL(AMD) & VMCALL(Intel)是多字节指令,调用IEMExecOneWithPrefetchedByPC模拟执行
                rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx), pMsg->Header.Rip,
                                                        pMsg->InstructionBytes, pMsg->InstructionByteCount);
                return rcStrict;
            }
       case X86_XCPT_DB:
            //调试中断
            EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_NEM, NEMEXITTYPE_XCPT_DB),
                             pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
            break;
       case X86_XCPT_BP:
            //BP中断
            EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_NEM, NEMEXITTYPE_XCPT_BP),
                             pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
            //设置中断type成 INT 3
            enmEvtType = TRPM_SOFTWARE_INT; 
            break;
    }
    //模拟执行注入异常
    rcStrict = IEMInjectTrap(pVCpu, pMsg->ExceptionVector, enmEvtType, pMsg->ErrorCode,
                             pMsg->ExceptionParameter /*??*/, pMsg->Header.InstructionLength);
}

//判断是否是VMCALL指令
DECLINLINE(bool) nemHcWinIsInterestingUndefinedOpcode(uint8_t cbOpcodes, uint8_t const *pbOpcodes, bool f64BitMode)
{
    //指令操作数最多3个字节
    while (cbOpcodes >= 3)
    {
        switch (pbOpcodes[0])
        {
            case 0x0f:
                switch (pbOpcodes[1])
                {
                    case 0x01:
                        switch (pbOpcodes[2])
                        {
                            //找到了VMCALL指令,返回true
                            case 0xc1: /* 0f 01 c1  VMCALL */
                                return true;
                            case 0xd9: /* 0f 01 d9  VMMCALL */
                                return true;
                            default:
                                break;
                        }
                        break;
                }
                break;
            default:
                return false;
            //过滤掉前缀
            case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
            case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
                if (!f64BitMode)
                    return false;
                RT_FALL_THRU();
            case X86_OP_PRF_CS:
            case X86_OP_PRF_SS:
            case X86_OP_PRF_DS:
            case X86_OP_PRF_ES:
            case X86_OP_PRF_FS:
            case X86_OP_PRF_GS:
            case X86_OP_PRF_SIZE_OP:
            case X86_OP_PRF_SIZE_ADDR:
            case X86_OP_PRF_LOCK:
            case X86_OP_PRF_REPZ:
            case X86_OP_PRF_REPNZ:
                cbOpcodes--;
                pbOpcodes++;
                continue;
        }
        break;
    }
}

nemHCWinHandleMessageUnrecoverableException

对应VMX的hmR0VmxExitTripleFault

NEM_TMPL_STATIC VBOXSTRICTRC
nemHCWinHandleMessageUnrecoverableException(PVMCPUCC pVCpu, HV_X64_INTERCEPT_MESSAGE_HEADER const *pMsgHdr)
{
    EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_NEM, NEMEXITTYPE_UNRECOVERABLE_EXCEPTION),
                     pMsgHdr->Rip + pMsgHdr->CsSegment.Base, ASMReadTSC());
    //从GuestOS里拷贝信息
    nemHCWinCopyStateFromX64Header(pVCpu, pMsgHdr);
    VBOXSTRICTRC rcStrict = nemHCWinImportStateIfNeededStrict(pVCpu, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM | CPUMCTX_EXTRN_ALL, "TripleExit");
    if (rcStrict == VINF_SUCCESS)
    {
        //让IEM去模拟执行这条指令
        rcStrict = IEMExecOne(pVCpu);
        if (rcStrict == VINF_SUCCESS)
        {
            //模拟执行成功(什么样的TripleFault可以模拟执行成功?),返回成功继续执行GuestOS代码
            pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT; 
            return VINF_SUCCESS;
        }
    }
    //返回错误码
    return rcStrict;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值