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;
}