summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/NEMInternal.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/include/NEMInternal.h')
-rw-r--r--src/VBox/VMM/include/NEMInternal.h453
1 files changed, 453 insertions, 0 deletions
diff --git a/src/VBox/VMM/include/NEMInternal.h b/src/VBox/VMM/include/NEMInternal.h
new file mode 100644
index 00000000..523a39eb
--- /dev/null
+++ b/src/VBox/VMM/include/NEMInternal.h
@@ -0,0 +1,453 @@
+/* $Id: NEMInternal.h $ */
+/** @file
+ * NEM - Internal header file.
+ */
+
+/*
+ * Copyright (C) 2018-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VMM_INCLUDED_SRC_include_NEMInternal_h
+#define VMM_INCLUDED_SRC_include_NEMInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <VBox/vmm/nem.h>
+#include <VBox/vmm/cpum.h> /* For CPUMCPUVENDOR. */
+#include <VBox/vmm/stam.h>
+#include <VBox/vmm/vmapi.h>
+#ifdef RT_OS_WINDOWS
+#include <iprt/nt/hyperv.h>
+#include <iprt/critsect.h>
+#endif
+
+RT_C_DECLS_BEGIN
+
+
+/** @defgroup grp_nem_int Internal
+ * @ingroup grp_nem
+ * @internal
+ * @{
+ */
+
+
+#ifdef RT_OS_WINDOWS
+/*
+ * Windows: Code configuration.
+ */
+# define NEM_WIN_USE_HYPERCALLS_FOR_PAGES
+//# define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS /**< Applies to ring-3 code only. Useful for testing VID API. */
+//# define NEM_WIN_USE_OUR_OWN_RUN_API /**< Applies to ring-3 code only. Useful for testing VID API. */
+//# define NEM_WIN_WITH_RING0_RUNLOOP /**< Enables the ring-0 runloop. */
+//# define NEM_WIN_USE_RING0_RUNLOOP_BY_DEFAULT /**< For quickly testing ring-3 API without messing with CFGM. */
+# if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
+# error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS"
+# endif
+# if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES)
+# error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_PAGES"
+# endif
+# if defined(NEM_WIN_WITH_RING0_RUNLOOP) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES)
+# error "NEM_WIN_WITH_RING0_RUNLOOP requires NEM_WIN_USE_HYPERCALLS_FOR_PAGES"
+# endif
+
+/**
+ * Windows VID I/O control information.
+ */
+typedef struct NEMWINIOCTL
+{
+ /** The I/O control function number. */
+ uint32_t uFunction;
+ uint32_t cbInput;
+ uint32_t cbOutput;
+} NEMWINIOCTL;
+
+/** @name Windows: Our two-bit physical page state for PGMPAGE
+ * @{ */
+# define NEM_WIN_PAGE_STATE_NOT_SET 0
+# define NEM_WIN_PAGE_STATE_UNMAPPED 1
+# define NEM_WIN_PAGE_STATE_READABLE 2
+# define NEM_WIN_PAGE_STATE_WRITABLE 3
+/** @} */
+
+/** Windows: Checks if a_GCPhys is subject to the limited A20 gate emulation. */
+# define NEM_WIN_IS_SUBJECT_TO_A20(a_GCPhys) ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K)
+/** Windows: Checks if a_GCPhys is relevant to the limited A20 gate emulation. */
+# define NEM_WIN_IS_RELEVANT_TO_A20(a_GCPhys) \
+ ( ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K) || ((RTGCPHYS)(a_GCPhys) < (RTGCPHYS)_64K) )
+
+/** The CPUMCTX_EXTRN_XXX mask for IEM. */
+# define NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM ( IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_NEM_WIN_INHIBIT_INT \
+ | CPUMCTX_EXTRN_NEM_WIN_INHIBIT_NMI )
+/** The CPUMCTX_EXTRN_XXX mask for IEM when raising exceptions. */
+# define NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM_XCPT (IEM_CPUMCTX_EXTRN_XCPT_MASK | NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM)
+
+/** @name Windows: Interrupt window flags (NEM_WIN_INTW_F_XXX).
+ * @{ */
+# define NEM_WIN_INTW_F_NMI UINT8_C(0x01)
+# define NEM_WIN_INTW_F_REGULAR UINT8_C(0x02)
+# define NEM_WIN_INTW_F_PRIO_MASK UINT8_C(0x3c)
+# define NEM_WIN_INTW_F_PRIO_SHIFT 2
+/** @} */
+
+#endif /* RT_OS_WINDOWS */
+
+
+/** Trick to make slickedit see the static functions in the template. */
+#ifndef IN_SLICKEDIT
+# define NEM_TMPL_STATIC static
+#else
+# define NEM_TMPL_STATIC
+#endif
+
+
+/**
+ * Generic NEM exit type enumeration for use with EMHistoryAddExit.
+ *
+ * On windows we've got two different set of exit types and they are both jumping
+ * around the place value wise, so EM can use their values.
+ *
+ * @note We only have exit types for exits not covered by EM here.
+ */
+typedef enum NEMEXITTYPE
+{
+ /* windows: */
+ NEMEXITTYPE_UNRECOVERABLE_EXCEPTION = 1,
+ NEMEXITTYPE_INVALID_VP_REGISTER_VALUE,
+ NEMEXITTYPE_INTTERRUPT_WINDOW,
+ NEMEXITTYPE_HALT,
+ NEMEXITTYPE_XCPT_UD,
+ NEMEXITTYPE_XCPT_DB,
+ NEMEXITTYPE_XCPT_BP,
+ NEMEXITTYPE_CANCELED,
+ NEMEXITTYPE_MEMORY_ACCESS
+} NEMEXITTYPE;
+
+
+/**
+ * NEM VM Instance data.
+ */
+typedef struct NEM
+{
+ /** NEM_MAGIC. */
+ uint32_t u32Magic;
+
+ /** Set if enabled. */
+ bool fEnabled;
+ /** Set if long mode guests are allowed. */
+ bool fAllow64BitGuests;
+#ifdef RT_OS_WINDOWS
+ /** Set if we've created the EMTs. */
+ bool fCreatedEmts : 1;
+ /** WHvRunVpExitReasonX64Cpuid is supported. */
+ bool fExtendedMsrExit : 1;
+ /** WHvRunVpExitReasonX64MsrAccess is supported. */
+ bool fExtendedCpuIdExit : 1;
+ /** WHvRunVpExitReasonException is supported. */
+ bool fExtendedXcptExit : 1;
+ /** Set if we're using the ring-0 API to do the work. */
+ bool fUseRing0Runloop : 1;
+ /** Set if we've started more than one CPU and cannot mess with A20. */
+ bool fA20Fixed : 1;
+ /** Set if A20 is enabled. */
+ bool fA20Enabled : 1;
+ /** The reported CPU vendor. */
+ CPUMCPUVENDOR enmCpuVendor;
+ /** Cache line flush size as a power of two. */
+ uint8_t cCacheLineFlushShift;
+ /** The result of WHvCapabilityCodeProcessorFeatures. */
+ union
+ {
+ /** 64-bit view. */
+ uint64_t u64;
+# ifdef _WINHVAPIDEFS_H_
+ /** Interpreed features. */
+ WHV_PROCESSOR_FEATURES u;
+# endif
+ } uCpuFeatures;
+
+ /** The partition handle. */
+# ifdef _WINHVAPIDEFS_H_
+ WHV_PARTITION_HANDLE
+# else
+ RTHCUINTPTR
+# endif
+ hPartition;
+ /** The device handle for the partition, for use with Vid APIs or direct I/O
+ * controls. */
+ RTR3PTR hPartitionDevice;
+ /** The Hyper-V partition ID. */
+ uint64_t idHvPartition;
+
+ /** Number of currently mapped pages. */
+ uint32_t volatile cMappedPages;
+
+ /** Info about the VidGetHvPartitionId I/O control interface. */
+ NEMWINIOCTL IoCtlGetHvPartitionId;
+ /** Info about the VidStartVirtualProcessor I/O control interface. */
+ NEMWINIOCTL IoCtlStartVirtualProcessor;
+ /** Info about the VidStopVirtualProcessor I/O control interface. */
+ NEMWINIOCTL IoCtlStopVirtualProcessor;
+ /** Info about the VidStopVirtualProcessor I/O control interface. */
+ NEMWINIOCTL IoCtlMessageSlotHandleAndGetNext;
+
+ /** Statistics updated by NEMR0UpdateStatistics. */
+ struct
+ {
+ uint64_t cPagesAvailable;
+ uint64_t cPagesInUse;
+ } R0Stats;
+#endif /* RT_OS_WINDOWS */
+} NEM;
+/** Pointer to NEM VM instance data. */
+typedef NEM *PNEM;
+
+/** NEM::u32Magic value. */
+#define NEM_MAGIC UINT32_C(0x004d454e)
+/** NEM::u32Magic value after termination. */
+#define NEM_MAGIC_DEAD UINT32_C(0xdead1111)
+
+
+/**
+ * NEM VMCPU Instance data.
+ */
+typedef struct NEMCPU
+{
+ /** NEMCPU_MAGIC. */
+ uint32_t u32Magic;
+ /** Whether \#UD needs to be intercepted and presented to GIM. */
+ bool fGIMTrapXcptUD : 1;
+ /** Whether \#GP needs to be intercept for mesa driver workaround. */
+ bool fTrapXcptGpForLovelyMesaDrv: 1;
+#ifdef RT_OS_WINDOWS
+ /** The current state of the interrupt windows (NEM_WIN_INTW_F_XXX). */
+ uint8_t fCurrentInterruptWindows;
+ /** The desired state of the interrupt windows (NEM_WIN_INTW_F_XXX). */
+ uint8_t fDesiredInterruptWindows;
+ /** Last copy of HV_X64_VP_EXECUTION_STATE::InterruptShadow. */
+ bool fLastInterruptShadow : 1;
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
+ /** Pending VINF_NEM_FLUSH_TLB. */
+ int32_t rcPending;
+# else
+ uint32_t uPadding;
+# endif
+ /** The VID_MSHAGN_F_XXX flags.
+ * Either VID_MSHAGN_F_HANDLE_MESSAGE | VID_MSHAGN_F_GET_NEXT_MESSAGE or zero. */
+ uint32_t fHandleAndGetFlags;
+ /** What VidMessageSlotMap returns and is used for passing exit info. */
+ RTR3PTR pvMsgSlotMapping;
+ /** The windows thread handle. */
+ RTR3PTR hNativeThreadHandle;
+ /** Parameters for making Hyper-V hypercalls. */
+ union
+ {
+ uint8_t ab[64];
+ /** Arguments for NEMR0MapPages (HvCallMapGpaPages). */
+ struct
+ {
+ RTGCPHYS GCPhysSrc;
+ RTGCPHYS GCPhysDst; /**< Same as GCPhysSrc except maybe when the A20 gate is disabled. */
+ uint32_t cPages;
+ HV_MAP_GPA_FLAGS fFlags;
+ } MapPages;
+ /** Arguments for NEMR0UnmapPages (HvCallUnmapGpaPages). */
+ struct
+ {
+ RTGCPHYS GCPhys;
+ uint32_t cPages;
+ } UnmapPages;
+ /** Result from NEMR0QueryCpuTick. */
+ struct
+ {
+ uint64_t cTicks;
+ uint32_t uAux;
+ } QueryCpuTick;
+ /** Input and output for NEMR0DoExperiment. */
+ struct
+ {
+ uint32_t uItem;
+ bool fSuccess;
+ uint64_t uStatus;
+ uint64_t uLoValue;
+ uint64_t uHiValue;
+ } Experiment;
+ } Hypercall;
+ /** I/O control buffer, we always use this for I/O controls. */
+ union
+ {
+ uint8_t ab[64];
+ HV_PARTITION_ID idPartition;
+ HV_VP_INDEX idCpu;
+# ifdef VID_MSHAGN_F_GET_NEXT_MESSAGE
+ VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT MsgSlotHandleAndGetNext;
+# endif
+ } uIoCtlBuf;
+
+ /** @name Statistics
+ * @{ */
+ STAMCOUNTER StatExitPortIo;
+ STAMCOUNTER StatExitMemUnmapped;
+ STAMCOUNTER StatExitMemIntercept;
+ STAMCOUNTER StatExitHalt;
+ STAMCOUNTER StatExitInterruptWindow;
+ STAMCOUNTER StatExitCpuId;
+ STAMCOUNTER StatExitMsr;
+ STAMCOUNTER StatExitException;
+ STAMCOUNTER StatExitExceptionBp;
+ STAMCOUNTER StatExitExceptionDb;
+ STAMCOUNTER StatExitExceptionGp;
+ STAMCOUNTER StatExitExceptionGpMesa;
+ STAMCOUNTER StatExitExceptionUd;
+ STAMCOUNTER StatExitExceptionUdHandled;
+ STAMCOUNTER StatExitUnrecoverable;
+ STAMCOUNTER StatGetMsgTimeout;
+ STAMCOUNTER StatStopCpuSuccess;
+ STAMCOUNTER StatStopCpuPending;
+ STAMCOUNTER StatStopCpuPendingAlerts;
+ STAMCOUNTER StatStopCpuPendingOdd;
+ STAMCOUNTER StatCancelChangedState;
+ STAMCOUNTER StatCancelAlertedThread;
+ STAMCOUNTER StatBreakOnCancel;
+ STAMCOUNTER StatBreakOnFFPre;
+ STAMCOUNTER StatBreakOnFFPost;
+ STAMCOUNTER StatBreakOnStatus;
+ STAMCOUNTER StatImportOnDemand;
+ STAMCOUNTER StatImportOnReturn;
+ STAMCOUNTER StatImportOnReturnSkipped;
+ STAMCOUNTER StatQueryCpuTick;
+ /** @} */
+#endif /* RT_OS_WINDOWS */
+} NEMCPU;
+/** Pointer to NEM VMCPU instance data. */
+typedef NEMCPU *PNEMCPU;
+
+/** NEMCPU::u32Magic value. */
+#define NEMCPU_MAGIC UINT32_C(0x4d454e20)
+/** NEMCPU::u32Magic value after termination. */
+#define NEMCPU_MAGIC_DEAD UINT32_C(0xdead2222)
+
+
+#ifdef IN_RING0
+# ifdef RT_OS_WINDOWS
+/**
+ * Windows: Hypercall input/ouput page info.
+ */
+typedef struct NEMR0HYPERCALLDATA
+{
+ /** Host physical address of the hypercall input/output page. */
+ RTHCPHYS HCPhysPage;
+ /** Pointer to the hypercall input/output page. */
+ uint8_t *pbPage;
+ /** Handle to the memory object of the hypercall input/output page. */
+ RTR0MEMOBJ hMemObj;
+} NEMR0HYPERCALLDATA;
+/** Pointer to a Windows hypercall input/output page info. */
+typedef NEMR0HYPERCALLDATA *PNEMR0HYPERCALLDATA;
+# endif /* RT_OS_WINDOWS */
+
+/**
+ * NEM GVMCPU instance data.
+ */
+typedef struct NEMR0PERVCPU
+{
+# ifdef RT_OS_WINDOWS
+ /** Hypercall input/ouput page. */
+ NEMR0HYPERCALLDATA HypercallData;
+ /** Delta to add to convert a ring-0 pointer to a ring-3 one. */
+ uintptr_t offRing3ConversionDelta;
+# else
+ uint32_t uDummy;
+# endif
+} NEMR0PERVCPU;
+
+/**
+ * NEM GVM instance data.
+ */
+typedef struct NEMR0PERVM
+{
+# ifdef RT_OS_WINDOWS
+ /** The partition ID. */
+ uint64_t idHvPartition;
+ /** I/O control context. */
+ PSUPR0IOCTLCTX pIoCtlCtx;
+ /** Info about the VidGetHvPartitionId I/O control interface. */
+ NEMWINIOCTL IoCtlGetHvPartitionId;
+ /** Info about the VidStartVirtualProcessor I/O control interface. */
+ NEMWINIOCTL IoCtlStartVirtualProcessor;
+ /** Info about the VidStopVirtualProcessor I/O control interface. */
+ NEMWINIOCTL IoCtlStopVirtualProcessor;
+ /** Info about the VidStopVirtualProcessor I/O control interface. */
+ NEMWINIOCTL IoCtlMessageSlotHandleAndGetNext;
+ /** Whether we may use the ring-0 runloop or not. */
+ bool fMayUseRing0Runloop;
+
+ /** Hypercall input/ouput page for non-EMT. */
+ NEMR0HYPERCALLDATA HypercallData;
+ /** Critical section protecting use of HypercallData. */
+ RTCRITSECT HypercallDataCritSect;
+
+# else
+ uint32_t uDummy;
+# endif
+} NEMR0PERVM;
+
+#endif /* IN_RING*/
+
+
+#ifdef IN_RING3
+int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced);
+int nemR3NativeInitAfterCPUM(PVM pVM);
+int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
+int nemR3NativeTerm(PVM pVM);
+void nemR3NativeReset(PVM pVM);
+void nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi);
+VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu);
+bool nemR3NativeCanExecuteGuest(PVM pVM, PVMCPU pVCpu);
+bool nemR3NativeSetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable);
+void nemR3NativeNotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags);
+
+int nemR3NativeNotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb);
+int nemR3NativeNotifyPhysMmioExMap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, void *pvMmio2);
+int nemR3NativeNotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
+int nemR3NativeNotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
+int nemR3NativeNotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
+void nemR3NativeNotifySetA20(PVMCPU pVCpu, bool fEnabled);
+#endif
+
+void nemHCNativeNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb);
+void nemHCNativeNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb,
+ int fRestoreAsRAM, bool fRestoreAsRAM2);
+void nemHCNativeNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
+ RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM);
+int nemHCNativeNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
+ PGMPAGETYPE enmType, uint8_t *pu2State);
+void nemHCNativeNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
+ PGMPAGETYPE enmType, uint8_t *pu2State);
+void nemHCNativeNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew, uint32_t fPageProt,
+ PGMPAGETYPE enmType, uint8_t *pu2State);
+
+
+#ifdef RT_OS_WINDOWS
+/** Maximum number of pages we can map in a single NEMR0MapPages call. */
+# define NEM_MAX_MAP_PAGES ((PAGE_SIZE - RT_UOFFSETOF(HV_INPUT_MAP_GPA_PAGES, PageList)) / sizeof(HV_SPA_PAGE_NUMBER))
+/** Maximum number of pages we can unmap in a single NEMR0UnmapPages call. */
+# define NEM_MAX_UNMAP_PAGES 4095
+
+#endif
+/** @} */
+
+RT_C_DECLS_END
+
+#endif /* !VMM_INCLUDED_SRC_include_NEMInternal_h */
+