/** @file * SUP - Support Library. (HDrv) */ /* * Copyright (C) 2006-2016 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. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. */ #ifndef ___VBox_sup_h #define ___VBox_sup_h #include #include #include #include #include #include #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) # include #endif RT_C_DECLS_BEGIN struct VTGOBJHDR; struct VTGPROBELOC; /** @defgroup grp_sup The Support Library API * @{ */ /** * Physical page descriptor. */ #pragma pack(4) /* space is more important. */ typedef struct SUPPAGE { /** Physical memory address. */ RTHCPHYS Phys; /** Reserved entry for internal use by the caller. */ RTHCUINTPTR uReserved; } SUPPAGE; #pragma pack() /** Pointer to a page descriptor. */ typedef SUPPAGE *PSUPPAGE; /** Pointer to a const page descriptor. */ typedef const SUPPAGE *PCSUPPAGE; /** * The paging mode. * * @remarks Users are making assumptions about the order here! */ typedef enum SUPPAGINGMODE { /** The usual invalid entry. * This is returned by SUPR3GetPagingMode() */ SUPPAGINGMODE_INVALID = 0, /** Normal 32-bit paging, no global pages */ SUPPAGINGMODE_32_BIT, /** Normal 32-bit paging with global pages. */ SUPPAGINGMODE_32_BIT_GLOBAL, /** PAE mode, no global pages, no NX. */ SUPPAGINGMODE_PAE, /** PAE mode with global pages. */ SUPPAGINGMODE_PAE_GLOBAL, /** PAE mode with NX, no global pages. */ SUPPAGINGMODE_PAE_NX, /** PAE mode with global pages and NX. */ SUPPAGINGMODE_PAE_GLOBAL_NX, /** AMD64 mode, no global pages. */ SUPPAGINGMODE_AMD64, /** AMD64 mode with global pages, no NX. */ SUPPAGINGMODE_AMD64_GLOBAL, /** AMD64 mode with NX, no global pages. */ SUPPAGINGMODE_AMD64_NX, /** AMD64 mode with global pages and NX. */ SUPPAGINGMODE_AMD64_GLOBAL_NX } SUPPAGINGMODE; /** @name Flags returned by SUPR0GetKernelFeatures(). * @{ */ /** GDT is read-only. */ #define SUPKERNELFEATURES_GDT_READ_ONLY RT_BIT(0) /** SMAP is possibly enabled. */ #define SUPKERNELFEATURES_SMAP RT_BIT(1) /** @} */ /** * Usermode probe context information. */ typedef struct SUPDRVTRACERUSRCTX { /** The probe ID from the VTG location record. */ uint32_t idProbe; /** 32 if X86, 64 if AMD64. */ uint8_t cBits; /** Reserved padding. */ uint8_t abReserved[3]; /** Data which format is dictated by the cBits member. */ union { /** X86 context info. */ struct { uint32_t uVtgProbeLoc; /**< Location record address. */ uint32_t aArgs[20]; /**< Raw arguments. */ uint32_t eip; uint32_t eflags; uint32_t eax; uint32_t ecx; uint32_t edx; uint32_t ebx; uint32_t esp; uint32_t ebp; uint32_t esi; uint32_t edi; uint16_t cs; uint16_t ss; uint16_t ds; uint16_t es; uint16_t fs; uint16_t gs; } X86; /** AMD64 context info. */ struct { uint64_t uVtgProbeLoc; /**< Location record address. */ uint64_t aArgs[10]; /**< Raw arguments. */ uint64_t rip; uint64_t rflags; uint64_t rax; uint64_t rcx; uint64_t rdx; uint64_t rbx; uint64_t rsp; uint64_t rbp; uint64_t rsi; uint64_t rdi; uint64_t r8; uint64_t r9; uint64_t r10; uint64_t r11; uint64_t r12; uint64_t r13; uint64_t r14; uint64_t r15; } Amd64; } u; } SUPDRVTRACERUSRCTX; /** Pointer to the usermode probe context information. */ typedef SUPDRVTRACERUSRCTX *PSUPDRVTRACERUSRCTX; /** Pointer to the const usermode probe context information. */ typedef SUPDRVTRACERUSRCTX const *PCSUPDRVTRACERUSRCTX; /** * The result of a modification operation (SUPMSRPROBEROP_MODIFY or * SUPMSRPROBEROP_MODIFY_FASTER). */ typedef struct SUPMSRPROBERMODIFYRESULT { /** The MSR value prior to the modifications. Valid if fBeforeGp is false */ uint64_t uBefore; /** The value that was written. Valid if fBeforeGp is false */ uint64_t uWritten; /** The MSR value after the modifications. Valid if AfterGp is false. */ uint64_t uAfter; /** Set if we GPed reading the MSR before the modification. */ bool fBeforeGp; /** Set if we GPed while trying to write the modified value. * This is set when fBeforeGp is true. */ bool fModifyGp; /** Set if we GPed while trying to read the MSR after the modification. * This is set when fBeforeGp is true. */ bool fAfterGp; /** Set if we GPed while trying to restore the MSR after the modification. * This is set when fBeforeGp is true. */ bool fRestoreGp; /** Structure size alignment padding. */ bool afReserved[4]; } SUPMSRPROBERMODIFYRESULT, *PSUPMSRPROBERMODIFYRESULT; /** * The CPU state. */ typedef enum SUPGIPCPUSTATE { /** Invalid CPU state / unused CPU entry. */ SUPGIPCPUSTATE_INVALID = 0, /** The CPU is not present. */ SUPGIPCPUSTATE_ABSENT, /** The CPU is offline. */ SUPGIPCPUSTATE_OFFLINE, /** The CPU is online. */ SUPGIPCPUSTATE_ONLINE, /** Force 32-bit enum type. */ SUPGIPCPUSTATE_32_BIT_HACK = 0x7fffffff } SUPGIPCPUSTATE; /** * Per CPU data. */ typedef struct SUPGIPCPU { /** Update transaction number. * This number is incremented at the start and end of each update. It follows * thusly that odd numbers indicates update in progress, while even numbers * indicate stable data. Use this to make sure that the data items you fetch * are consistent. */ volatile uint32_t u32TransactionId; /** The interval in TSC ticks between two NanoTS updates. * This is the average interval over the last 2, 4 or 8 updates + a little slack. * The slack makes the time go a tiny tiny bit slower and extends the interval enough * to avoid ending up with too many 1ns increments. */ volatile uint32_t u32UpdateIntervalTSC; /** Current nanosecond timestamp. */ volatile uint64_t u64NanoTS; /** The TSC at the time of u64NanoTS. */ volatile uint64_t u64TSC; /** Current CPU Frequency. */ volatile uint64_t u64CpuHz; /** The TSC delta with reference to the master TSC, subtract from RDTSC. */ volatile int64_t i64TSCDelta; /** Number of errors during updating. * Typical errors are under/overflows. */ volatile uint32_t cErrors; /** Index of the head item in au32TSCHistory. */ volatile uint32_t iTSCHistoryHead; /** Array of recent TSC interval deltas. * The most recent item is at index iTSCHistoryHead. * This history is used to calculate u32UpdateIntervalTSC. */ volatile uint32_t au32TSCHistory[8]; /** The interval between the last two NanoTS updates. (experiment for now) */ volatile uint32_t u32PrevUpdateIntervalNS; /** Reserved for future per processor data. */ volatile uint32_t u32Reserved; /** The TSC value read while doing TSC delta measurements across CPUs. */ volatile uint64_t u64TSCSample; /** Reserved for future per processor data. */ volatile uint32_t au32Reserved1[3]; /** The CPU state. */ SUPGIPCPUSTATE volatile enmState; /** The host CPU ID of this CPU (the SUPGIPCPU is indexed by APIC ID). */ RTCPUID idCpu; /** The CPU set index of this CPU. */ int16_t iCpuSet; /** CPU group number (always zero, except on windows). */ uint16_t iCpuGroup; /** CPU group number (same as iCpuSet, except on windows). */ uint16_t iCpuGroupMember; /** The APIC ID of this CPU. */ uint16_t idApic; /** @todo Add topology/NUMA info. */ uint32_t iReservedForNumaNode; } SUPGIPCPU; AssertCompileSize(RTCPUID, 4); AssertCompileSize(SUPGIPCPU, 128); AssertCompileMemberAlignment(SUPGIPCPU, u64NanoTS, 8); AssertCompileMemberAlignment(SUPGIPCPU, u64TSC, 8); AssertCompileMemberAlignment(SUPGIPCPU, u64TSCSample, 8); /** Pointer to per cpu data. * @remark there is no const version of this typedef, see g_pSUPGlobalInfoPage for details. */ typedef SUPGIPCPU *PSUPGIPCPU; /** * The rules concerning the applicability of SUPGIPCPU::i64TscDelta. */ typedef enum SUPGIPUSETSCDELTA { /** Value for SUPGIPMODE_ASYNC_TSC. */ SUPGIPUSETSCDELTA_NOT_APPLICABLE = 0, /** The OS specific part of SUPDrv (or the user) claims the TSC is as * good as zero. */ SUPGIPUSETSCDELTA_ZERO_CLAIMED, /** The differences in RDTSC output between the CPUs/cores/threads should * be considered zero for all practical purposes. */ SUPGIPUSETSCDELTA_PRACTICALLY_ZERO, /** The differences in RDTSC output between the CPUs/cores/threads are a few * hundred ticks or less. (Probably not worth calling ASMGetApicId two times * just to apply deltas.) */ SUPGIPUSETSCDELTA_ROUGHLY_ZERO, /** Significant differences in RDTSC output between the CPUs/cores/threads, * deltas must be applied. */ SUPGIPUSETSCDELTA_NOT_ZERO, /** End of valid values (exclusive). */ SUPGIPUSETSCDELTA_END, /** Make sure the type is 32-bit sized. */ SUPGIPUSETSCDELTA_32BIT_HACK = 0x7fffffff } SUPGIPUSETSCDELTA; /** @name SUPGIPGETCPU_XXX - methods that aCPUs can be indexed. * * @note Linux offers information via selector 0x78, and Windows via selector * 0x53. But since they both support RDTSCP as well, and because most * CPUs now have RDTSCP, we prefer it over LSL. We can implement more * alternatives if it becomes necessary. * * @{ */ /** Use ASMGetApicId (or equivalent) and translate the result via * aiCpuFromApicId. */ #define SUPGIPGETCPU_APIC_ID RT_BIT_32(0) /** Use RDTSCP and translate the first RTCPUSET_MAX_CPUS of ECX via * aiCpuFromCpuSetIdx. * * Linux stores the RTMpCpuId() value in ECX[11:0] and NUMA node number in * ECX[12:31]. Solaris only stores RTMpCpuId() in ECX. On both systems * RTMpCpuId() == RTMpCpuIdToSetIndex(RTMpCpuId()). RTCPUSET_MAX_CPUS is * currently 64, 256 or 1024 in size, which lower than * 4096, so there shouldn't be any range issues. */ #define SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS RT_BIT_32(1) /** Subtract the max IDT size from IDTR.LIMIT, extract the * first RTCPUSET_MAX_CPUS and translate it via aiCpuFromCpuSetIdx. * * Darwin stores the RTMpCpuId() (== RTMpCpuIdToSetIndex(RTMpCpuId())) * value in the IDT limit. The masking is a precaution against what linux * does with RDTSCP. */ #define SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS RT_BIT_32(2) /** Windows specific RDTSCP variant, where CH gives you the group and CL gives * you the CPU number within that group. * * Use SUPGLOBALINFOPAGE::aidFirstCpuFromCpuGroup to get the group base CPU set * index, then translate the sum of thru aiCpuFromCpuSetIdx to find the aCPUs * entry. * * @note The group number is actually 16-bit wide (ECX[23:8]), but we simplify * it since we only support 256 CPUs/groups at the moment. */ #define SUPGIPGETCPU_RDTSCP_GROUP_IN_CH_NUMBER_IN_CL RT_BIT_32(3) /** @} */ /** * Global Information Page. * * This page contains useful information and can be mapped into any * process or VM. It can be accessed thru the g_pSUPGlobalInfoPage * pointer when a session is open. */ typedef struct SUPGLOBALINFOPAGE { /** Magic (SUPGLOBALINFOPAGE_MAGIC). */ uint32_t u32Magic; /** The GIP version. */ uint32_t u32Version; /** The GIP update mode, see SUPGIPMODE. */ uint32_t u32Mode; /** The number of entries in the CPU table. * (This can work as RTMpGetArraySize().) */ uint16_t cCpus; /** The size of the GIP in pages. */ uint16_t cPages; /** The update frequency of the of the NanoTS. */ volatile uint32_t u32UpdateHz; /** The update interval in nanoseconds. (10^9 / u32UpdateHz) */ volatile uint32_t u32UpdateIntervalNS; /** The timestamp of the last time we update the update frequency. */ volatile uint64_t u64NanoTSLastUpdateHz; /** The TSC frequency of the system. */ uint64_t u64CpuHz; /** The set of online CPUs. */ RTCPUSET OnlineCpuSet; /** The set of present CPUs. */ RTCPUSET PresentCpuSet; /** The set of possible CPUs. */ RTCPUSET PossibleCpuSet; /** The number of CPUs that are online. */ volatile uint16_t cOnlineCpus; /** The number of CPUs present in the system. */ volatile uint16_t cPresentCpus; /** The highest number of CPUs possible. */ uint16_t cPossibleCpus; /** The highest number of CPU groups possible. */ uint16_t cPossibleCpuGroups; /** The max CPU ID (RTMpGetMaxCpuId). */ RTCPUID idCpuMax; /** The applicability of SUPGIPCPU::i64TscDelta. */ SUPGIPUSETSCDELTA enmUseTscDelta; /** Mask of SUPGIPGETCPU_XXX values that indicates different ways that aCPU * can be accessed from ring-3 and raw-mode context. */ uint32_t fGetGipCpu; /** GIP flags, see SUPGIP_FLAGS_XXX. */ volatile uint32_t fFlags; /** Padding / reserved space for future data. */ uint32_t au32Padding1[24]; /** Table indexed by the CPU APIC ID to get the CPU table index. */ uint16_t aiCpuFromApicId[256]; /** CPU set index to CPU table index. */ uint16_t aiCpuFromCpuSetIdx[RTCPUSET_MAX_CPUS]; /** Table indexed by CPU group index to get the CPU set index of the first * CPU. */ uint16_t aiFirstCpuSetIdxFromCpuGroup[RTCPUSET_MAX_CPUS]; /** Array of per-cpu data. * This is index by ApicId via the aiCpuFromApicId table. * * The clock and frequency information is updated for all CPUs if @c u32Mode * is SUPGIPMODE_ASYNC_TSC. If @c u32Mode is SUPGIPMODE_SYNC_TSC only the first * entry is updated. If @c u32Mode is SUPGIPMODE_SYNC_TSC the TSC frequency in * @c u64CpuHz is copied to all CPUs. */ SUPGIPCPU aCPUs[1]; } SUPGLOBALINFOPAGE; AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz, 8); #if defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPUs, 32); #else AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPUs, 256); #endif AssertCompile(sizeof(SUPGLOBALINFOPAGE) <= 0x1000); /* Keeping it less or equal to a page for raw-mode (saved state). */ /** Pointer to the global info page. * @remark there is no const version of this typedef, see g_pSUPGlobalInfoPage for details. */ typedef SUPGLOBALINFOPAGE *PSUPGLOBALINFOPAGE; /** The value of the SUPGLOBALINFOPAGE::u32Magic field. (Soryo Fuyumi) */ #define SUPGLOBALINFOPAGE_MAGIC 0x19590106 /** The GIP version. * Upper 16 bits is the major version. Major version is only changed with * incompatible changes in the GIP. */ #define SUPGLOBALINFOPAGE_VERSION 0x00070000 /** * SUPGLOBALINFOPAGE::u32Mode values. */ typedef enum SUPGIPMODE { /** The usual invalid null entry. */ SUPGIPMODE_INVALID = 0, /** The TSC of the cores and cpus in the system is in sync. */ SUPGIPMODE_SYNC_TSC, /** Each core has it's own TSC. */ SUPGIPMODE_ASYNC_TSC, /** The TSC of the cores are non-stop and have a constant frequency. */ SUPGIPMODE_INVARIANT_TSC, /** End of valid GIP mode values (exclusive). */ SUPGIPMODE_END, /** The usual 32-bit hack. */ SUPGIPMODE_32BIT_HACK = 0x7fffffff } SUPGIPMODE; /** Pointer to the Global Information Page. * * This pointer is valid as long as SUPLib has a open session. Anyone using * the page must treat this pointer as highly volatile and not trust it beyond * one transaction. * * @remark The GIP page is read-only to everyone but the support driver and * is actually mapped read only everywhere but in ring-0. However * it is not marked 'const' as this might confuse compilers into * thinking that values doesn't change even if members are marked * as volatile. Thus, there is no PCSUPGLOBALINFOPAGE type. */ #if defined(IN_SUP_R3) || defined(IN_SUP_R0) extern DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage; #elif !defined(IN_RING0) || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) extern DECLIMPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage; #else /* IN_RING0 && !RT_OS_WINDOWS */ # if !defined(__GNUC__) || defined(RT_OS_DARWIN) || !defined(RT_ARCH_AMD64) # define g_pSUPGlobalInfoPage (&g_SUPGlobalInfoPage) # else # define g_pSUPGlobalInfoPage (SUPGetGIPHlp()) /** Workaround for ELF+GCC problem on 64-bit hosts. * (GCC emits a mov with a R_X86_64_32 reloc, we need R_X86_64_64.) */ DECLINLINE(PSUPGLOBALINFOPAGE) SUPGetGIPHlp(void) { PSUPGLOBALINFOPAGE pGIP; __asm__ __volatile__ ("movabs $g_SUPGlobalInfoPage,%0\n\t" : "=a" (pGIP)); return pGIP; } # endif /** The GIP. * We save a level of indirection by exporting the GIP instead of a variable * pointing to it. */ extern DECLIMPORT(SUPGLOBALINFOPAGE) g_SUPGlobalInfoPage; #endif /** * Gets the GIP pointer. * * @returns Pointer to the GIP or NULL. */ SUPDECL(PSUPGLOBALINFOPAGE) SUPGetGIP(void); /** @name SUPGIP_FLAGS_XXX - SUPR3GipSetFlags flags. * @{ */ /** Enable GIP test mode. */ #define SUPGIP_FLAGS_TESTING_ENABLE RT_BIT_32(0) /** Valid mask of flags that can be set through the ioctl. */ #define SUPGIP_FLAGS_VALID_MASK RT_BIT_32(0) /** GIP test mode needs to be checked (e.g. when enabled or being disabled). */ #define SUPGIP_FLAGS_TESTING RT_BIT_32(24) /** Prepare to start GIP test mode. */ #define SUPGIP_FLAGS_TESTING_START RT_BIT_32(25) /** Prepare to stop GIP test mode. */ #define SUPGIP_FLAGS_TESTING_STOP RT_BIT_32(26) /** @} */ /** @internal */ SUPDECL(uint64_t) SUPGetCpuHzFromGipForAsyncMode(PSUPGLOBALINFOPAGE pGip); SUPDECL(bool) SUPIsTscFreqCompatible(uint64_t uCpuHz, uint64_t *puGipCpuHz, bool fRelax); SUPDECL(bool) SUPIsTscFreqCompatibleEx(uint64_t uBaseCpuHz, uint64_t uCpuHz, bool fRelax); /** * Gets the TSC frequency of the calling CPU. * * @returns TSC frequency, UINT64_MAX on failure (asserted). * @param pGip The GIP pointer. */ DECLINLINE(uint64_t) SUPGetCpuHzFromGip(PSUPGLOBALINFOPAGE pGip) { if (RT_LIKELY( pGip && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) { switch (pGip->u32Mode) { case SUPGIPMODE_INVARIANT_TSC: case SUPGIPMODE_SYNC_TSC: return pGip->aCPUs[0].u64CpuHz; case SUPGIPMODE_ASYNC_TSC: return SUPGetCpuHzFromGipForAsyncMode(pGip); default: break; /* shut up gcc */ } } AssertFailed(); return UINT64_MAX; } /** * Gets the TSC frequency of the specified CPU. * * @returns TSC frequency, UINT64_MAX on failure (asserted). * @param pGip The GIP pointer. * @param iCpuSet The CPU set index of the CPU in question. */ DECLINLINE(uint64_t) SUPGetCpuHzFromGipBySetIndex(PSUPGLOBALINFOPAGE pGip, uint32_t iCpuSet) { if (RT_LIKELY( pGip && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) { switch (pGip->u32Mode) { case SUPGIPMODE_INVARIANT_TSC: case SUPGIPMODE_SYNC_TSC: return pGip->aCPUs[0].u64CpuHz; case SUPGIPMODE_ASYNC_TSC: if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) { uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; if (RT_LIKELY(iCpu < pGip->cCpus)) return pGip->aCPUs[iCpu].u64CpuHz; } break; default: break; /* shut up gcc */ } } AssertFailed(); return UINT64_MAX; } /** * Gets the pointer to the per CPU data for a CPU given by its set index. * * @returns Pointer to the corresponding per CPU structure, or NULL if invalid. * @param pGip The GIP pointer. * @param iCpuSet The CPU set index of the CPU which we want. */ DECLINLINE(PSUPGIPCPU) SUPGetGipCpuBySetIndex(PSUPGLOBALINFOPAGE pGip, uint32_t iCpuSet) { if (RT_LIKELY( pGip && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) { if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) { uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; if (RT_LIKELY(iCpu < pGip->cCpus)) return &pGip->aCPUs[iCpu]; } } return NULL; } #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) /** @internal */ SUPDECL(uint64_t) SUPReadTscWithDelta(PSUPGLOBALINFOPAGE pGip); /** * Read the host TSC value and applies the TSC delta if appropriate. * * @returns the TSC value. * @remarks Requires GIP to be initialized and valid. */ DECLINLINE(uint64_t) SUPReadTsc(void) { PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) return ASMReadTSC(); return SUPReadTscWithDelta(pGip); } #endif /* X86 || AMD64 */ /** @internal */ SUPDECL(uint64_t) SUPGetTscDeltaSlow(PSUPGLOBALINFOPAGE pGip); /** * Gets the TSC delta for the current CPU. * * @returns The TSC delta value (will not return the special INT64_MAX value). * @remarks Requires GIP to be initialized and valid. */ DECLINLINE(int64_t) SUPGetTscDelta(void) { PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) return 0; return SUPGetTscDeltaSlow(pGip); } /** * Gets the TSC delta for a given CPU. * * @returns The TSC delta value (will not return the special INT64_MAX value). * @param iCpuSet The CPU set index of the CPU which TSC delta we want. * @remarks Requires GIP to be initialized and valid. */ DECLINLINE(int64_t) SUPGetTscDeltaByCpuSetIndex(uint32_t iCpuSet) { PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) return 0; if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) { uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; if (RT_LIKELY(iCpu < pGip->cCpus)) { int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta; if (iTscDelta != INT64_MAX) return iTscDelta; } } AssertFailed(); return 0; } /** * Checks if the TSC delta is available for a given CPU (if TSC-deltas are * relevant). * * @returns true if it's okay to read the TSC, false otherwise. * * @param iCpuSet The CPU set index of the CPU which TSC delta we check. * @remarks Requires GIP to be initialized and valid. */ DECLINLINE(bool) SUPIsTscDeltaAvailableForCpuSetIndex(uint32_t iCpuSet) { PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) return true; if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) { uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; if (RT_LIKELY(iCpu < pGip->cCpus)) { int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta; if (iTscDelta != INT64_MAX) return true; } } return false; } /** * Gets the descriptive GIP mode name. * * @returns The name. * @param pGip Pointer to the GIP. */ DECLINLINE(const char *) SUPGetGIPModeName(PSUPGLOBALINFOPAGE pGip) { AssertReturn(pGip, NULL); switch (pGip->u32Mode) { case SUPGIPMODE_INVARIANT_TSC: return "Invariant"; case SUPGIPMODE_SYNC_TSC: return "Synchronous"; case SUPGIPMODE_ASYNC_TSC: return "Asynchronous"; case SUPGIPMODE_INVALID: return "Invalid"; default: return "???"; } } /** * Gets the descriptive TSC-delta enum name. * * @returns The name. * @param pGip Pointer to the GIP. */ DECLINLINE(const char *) SUPGetGIPTscDeltaModeName(PSUPGLOBALINFOPAGE pGip) { AssertReturn(pGip, NULL); switch (pGip->enmUseTscDelta) { case SUPGIPUSETSCDELTA_NOT_APPLICABLE: return "Not Applicable"; case SUPGIPUSETSCDELTA_ZERO_CLAIMED: return "Zero Claimed"; case SUPGIPUSETSCDELTA_PRACTICALLY_ZERO: return "Pratically Zero"; case SUPGIPUSETSCDELTA_ROUGHLY_ZERO: return "Roughly Zero"; case SUPGIPUSETSCDELTA_NOT_ZERO: return "Not Zero"; default: return "???"; } } /** * Request for generic VMMR0Entry calls. */ typedef struct SUPVMMR0REQHDR { /** The magic. (SUPVMMR0REQHDR_MAGIC) */ uint32_t u32Magic; /** The size of the request. */ uint32_t cbReq; } SUPVMMR0REQHDR; /** Pointer to a ring-0 request header. */ typedef SUPVMMR0REQHDR *PSUPVMMR0REQHDR; /** the SUPVMMR0REQHDR::u32Magic value (Ethan Iverson - The Bad Plus). */ #define SUPVMMR0REQHDR_MAGIC UINT32_C(0x19730211) /** For the fast ioctl path. * @{ */ /** @see VMMR0_DO_RAW_RUN. */ #define SUP_VMMR0_DO_RAW_RUN 0 /** @see VMMR0_DO_HM_RUN. */ #define SUP_VMMR0_DO_HM_RUN 1 /** @see VMMR0_DO_NOP */ #define SUP_VMMR0_DO_NOP 2 /** @} */ /** SUPR3QueryVTCaps capability flags * @{ */ /** AMD-V support. */ #define SUPVTCAPS_AMD_V RT_BIT(0) /** VT-x support. */ #define SUPVTCAPS_VT_X RT_BIT(1) /** Nested paging is supported. */ #define SUPVTCAPS_NESTED_PAGING RT_BIT(2) /** VT-x: Unrestricted guest execution is supported. */ #define SUPVTCAPS_VTX_UNRESTRICTED_GUEST RT_BIT(3) /** @} */ /** * Request for generic FNSUPR0SERVICEREQHANDLER calls. */ typedef struct SUPR0SERVICEREQHDR { /** The magic. (SUPR0SERVICEREQHDR_MAGIC) */ uint32_t u32Magic; /** The size of the request. */ uint32_t cbReq; } SUPR0SERVICEREQHDR; /** Pointer to a ring-0 service request header. */ typedef SUPR0SERVICEREQHDR *PSUPR0SERVICEREQHDR; /** the SUPVMMR0REQHDR::u32Magic value (Esbjoern Svensson - E.S.P.). */ #define SUPR0SERVICEREQHDR_MAGIC UINT32_C(0x19640416) /** * Creates a single release event semaphore. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param phEvent Where to return the handle to the event semaphore. */ SUPDECL(int) SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent); /** * Closes a single release event semaphore handle. * * @returns VBox status code. * @retval VINF_OBJECT_DESTROYED if the semaphore was destroyed. * @retval VINF_SUCCESS if the handle was successfully closed but the semaphore * object remained alive because of other references. * * @param pSession The session handle of the caller. * @param hEvent The handle. Nil is quietly ignored. */ SUPDECL(int) SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent); /** * Signals a single release event semaphore. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEvent The semaphore handle. */ SUPDECL(int) SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent); #ifdef IN_RING0 /** * Waits on a single release event semaphore, not interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEvent The semaphore handle. * @param cMillies The number of milliseconds to wait. * @remarks Not available in ring-3. */ SUPDECL(int) SUPSemEventWait(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies); #endif /** * Waits on a single release event semaphore, interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEvent The semaphore handle. * @param cMillies The number of milliseconds to wait. */ SUPDECL(int) SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies); /** * Waits on a single release event semaphore, interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEvent The semaphore handle. * @param uNsTimeout The deadline given on the RTTimeNanoTS() clock. */ SUPDECL(int) SUPSemEventWaitNsAbsIntr(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint64_t uNsTimeout); /** * Waits on a single release event semaphore, interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEvent The semaphore handle. * @param cNsTimeout The number of nanoseconds to wait. */ SUPDECL(int) SUPSemEventWaitNsRelIntr(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint64_t cNsTimeout); /** * Gets the best timeout resolution that SUPSemEventWaitNsAbsIntr and * SUPSemEventWaitNsAbsIntr can do. * * @returns The resolution in nanoseconds. * @param pSession The session handle of the caller. */ SUPDECL(uint32_t) SUPSemEventGetResolution(PSUPDRVSESSION pSession); /** * Creates a multiple release event semaphore. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param phEventMulti Where to return the handle to the event semaphore. */ SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti); /** * Closes a multiple release event semaphore handle. * * @returns VBox status code. * @retval VINF_OBJECT_DESTROYED if the semaphore was destroyed. * @retval VINF_SUCCESS if the handle was successfully closed but the semaphore * object remained alive because of other references. * * @param pSession The session handle of the caller. * @param hEventMulti The handle. Nil is quietly ignored. */ SUPDECL(int) SUPSemEventMultiClose(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); /** * Signals a multiple release event semaphore. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEventMulti The semaphore handle. */ SUPDECL(int) SUPSemEventMultiSignal(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); /** * Resets a multiple release event semaphore. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEventMulti The semaphore handle. */ SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); #ifdef IN_RING0 /** * Waits on a multiple release event semaphore, not interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEventMulti The semaphore handle. * @param cMillies The number of milliseconds to wait. * @remarks Not available in ring-3. */ SUPDECL(int) SUPSemEventMultiWait(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies); #endif /** * Waits on a multiple release event semaphore, interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEventMulti The semaphore handle. * @param cMillies The number of milliseconds to wait. */ SUPDECL(int) SUPSemEventMultiWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies); /** * Waits on a multiple release event semaphore, interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEventMulti The semaphore handle. * @param uNsTimeout The deadline given on the RTTimeNanoTS() clock. */ SUPDECL(int) SUPSemEventMultiWaitNsAbsIntr(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout); /** * Waits on a multiple release event semaphore, interruptible. * * @returns VBox status code. * @param pSession The session handle of the caller. * @param hEventMulti The semaphore handle. * @param cNsTimeout The number of nanoseconds to wait. */ SUPDECL(int) SUPSemEventMultiWaitNsRelIntr(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout); /** * Gets the best timeout resolution that SUPSemEventMultiWaitNsAbsIntr and * SUPSemEventMultiWaitNsRelIntr can do. * * @returns The resolution in nanoseconds. * @param pSession The session handle of the caller. */ SUPDECL(uint32_t) SUPSemEventMultiGetResolution(PSUPDRVSESSION pSession); #ifdef IN_RING3 /** @defgroup grp_sup_r3 SUP Host Context Ring-3 API * @{ */ /** * Installs the support library. * * @returns VBox status code. */ SUPR3DECL(int) SUPR3Install(void); /** * Uninstalls the support library. * * @returns VBox status code. */ SUPR3DECL(int) SUPR3Uninstall(void); /** * Trusted main entry point. * * This is exported as "TrustedMain" by the dynamic libraries which contains the * "real" application binary for which the hardened stub is built. The entry * point is invoked upon successful initialization of the support library and * runtime. * * @returns main kind of exit code. * @param argc The argument count. * @param argv The argument vector. * @param envp The environment vector. */ typedef DECLCALLBACK(int) FNSUPTRUSTEDMAIN(int argc, char **argv, char **envp); /** Pointer to FNSUPTRUSTEDMAIN(). */ typedef FNSUPTRUSTEDMAIN *PFNSUPTRUSTEDMAIN; /** Which operation failed. */ typedef enum SUPINITOP { /** Invalid. */ kSupInitOp_Invalid = 0, /** Installation integrity error. */ kSupInitOp_Integrity, /** Setuid related. */ kSupInitOp_RootCheck, /** Driver related. */ kSupInitOp_Driver, /** IPRT init related. */ kSupInitOp_IPRT, /** Miscellaneous. */ kSupInitOp_Misc, /** Place holder. */ kSupInitOp_End } SUPINITOP; /** * Trusted error entry point, optional. * * This is exported as "TrustedError" by the dynamic libraries which contains * the "real" application binary for which the hardened stub is built. The * hardened main() must specify SUPSECMAIN_FLAGS_TRUSTED_ERROR when calling * SUPR3HardenedMain. * * @param pszWhere Where the error occurred (function name). * @param enmWhat Which operation went wrong. * @param rc The status code. * @param pszMsgFmt Error message format string. * @param va The message format arguments. */ typedef DECLCALLBACK(void) FNSUPTRUSTEDERROR(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); /** Pointer to FNSUPTRUSTEDERROR. */ typedef FNSUPTRUSTEDERROR *PFNSUPTRUSTEDERROR; /** * Secure main. * * This is used for the set-user-ID-on-execute binaries on unixy systems * and when using the open-vboxdrv-via-root-service setup on Windows. * * This function will perform the integrity checks of the VirtualBox * installation, open the support driver, open the root service (later), * and load the DLL corresponding to \a pszProgName and execute its main * function. * * @returns Return code appropriate for main(). * * @param pszProgName The program name. This will be used to figure out which * DLL/SO/DYLIB to load and execute. * @param fFlags Flags. * @param argc The argument count. * @param argv The argument vector. * @param envp The environment vector. */ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp); /** @name SUPR3HardenedMain flags. * @{ */ /** Don't open the device. (Intended for VirtualBox without -startvm.) */ #define SUPSECMAIN_FLAGS_DONT_OPEN_DEV RT_BIT_32(0) /** The hardened DLL has a "TrustedError" function (see FNSUPTRUSTEDERROR). */ #define SUPSECMAIN_FLAGS_TRUSTED_ERROR RT_BIT_32(1) /** Hack for making VirtualBoxVM use VirtualBox.dylib on Mac OS X. */ #define SUPSECMAIN_FLAGS_OSX_VM_APP RT_BIT_32(2) /** Program binary location mask. */ #define SUPSECMAIN_FLAGS_LOC_MASK UINT32_C(0x00000010) /** Default binary location is the application binary directory. Does * not need to be given explicitly (it's 0). */ #define SUPSECMAIN_FLAGS_LOC_APP_BIN UINT32_C(0x00000000) /** The binary is located in the testcase directory instead of the * default application binary directory. */ #define SUPSECMAIN_FLAGS_LOC_TESTCASE UINT32_C(0x00000010) /** @} */ /** * Initializes the support library. * * Each successful call to SUPR3Init() or SUPR3InitEx must be countered by a * call to SUPR3Term(false). * * @returns VBox status code. * @param ppSession Where to store the session handle. Defaults to NULL. */ SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession); /** * Initializes the support library, extended version. * * Each successful call to SUPR3Init() or SUPR3InitEx must be countered by a * call to SUPR3Term(false). * * @returns VBox status code. * @param fUnrestricted The desired access. * @param ppSession Where to store the session handle. Defaults to NULL. */ SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession); /** * Terminates the support library. * * @returns VBox status code. * @param fForced Forced termination. This means to ignore the * init call count and just terminated. */ #ifdef __cplusplus SUPR3DECL(int) SUPR3Term(bool fForced = false); #else SUPR3DECL(int) SUPR3Term(int fForced); #endif /** * Sets the ring-0 VM handle for use with fast IOCtls. * * @returns VBox status code. * @param pVMR0 The ring-0 VM handle. * NIL_RTR0PTR can be used to unset the handle when the * VM is about to be destroyed. */ SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0); /** * Calls the HC R0 VMM entry point. * See VMMR0Entry() for more details. * * @returns error code specific to uFunction. * @param pVMR0 Pointer to the Ring-0 (Host Context) mapping of the VM structure. * @param idCpu The virtual CPU ID. * @param uOperation Operation to execute. * @param pvArg Argument. */ SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg); /** * Variant of SUPR3CallVMMR0, except that this takes the fast ioclt path * regardsless of compile-time defaults. * * @returns VBox status code. * @param pVMR0 The ring-0 VM handle. * @param uOperation The operation; only the SUP_VMMR0_DO_* ones are valid. * @param idCpu The virtual CPU ID. */ SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu); /** * Calls the HC R0 VMM entry point, in a safer but slower manner than * SUPR3CallVMMR0. When entering using this call the R0 components can call * into the host kernel (i.e. use the SUPR0 and RT APIs). * * See VMMR0Entry() for more details. * * @returns error code specific to uFunction. * @param pVMR0 Pointer to the Ring-0 (Host Context) mapping of the VM structure. * @param idCpu The virtual CPU ID. * @param uOperation Operation to execute. * @param u64Arg Constant argument. * @param pReqHdr Pointer to a request header. Optional. * This will be copied in and out of kernel space. There currently is a size * limit on this, just below 4KB. */ SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); /** * Calls a ring-0 service. * * The operation and the request packet is specific to the service. * * @returns error code specific to uFunction. * @param pszService The service name. * @param cchService The length of the service name. * @param uOperation The request number. * @param u64Arg Constant argument. * @param pReqHdr Pointer to a request header. Optional. * This will be copied in and out of kernel space. There currently is a size * limit on this, just below 4KB. */ SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr); /** Which logger. */ typedef enum SUPLOGGER { SUPLOGGER_DEBUG = 1, SUPLOGGER_RELEASE } SUPLOGGER; /** * Changes the settings of the specified ring-0 logger. * * @returns VBox status code. * @param enmWhich Which logger. * @param pszFlags The flags settings. * @param pszGroups The groups settings. * @param pszDest The destination specificier. */ SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest); /** * Creates a ring-0 logger instance. * * @returns VBox status code. * @param enmWhich Which logger to create. * @param pszFlags The flags settings. * @param pszGroups The groups settings. * @param pszDest The destination specificier. */ SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest); /** * Destroys a ring-0 logger instance. * * @returns VBox status code. * @param enmWhich Which logger. */ SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich); /** * Queries the paging mode of the host OS. * * @returns The paging mode. */ SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void); /** * Allocate zero-filled pages. * * Use this to allocate a number of pages suitable for seeding / locking. * Call SUPR3PageFree() to free the pages once done with them. * * @returns VBox status. * @param cPages Number of pages to allocate. * @param ppvPages Where to store the base pointer to the allocated pages. */ SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, void **ppvPages); /** * Frees pages allocated with SUPR3PageAlloc(). * * @returns VBox status. * @param pvPages Pointer returned by SUPR3PageAlloc(). * @param cPages Number of pages that was allocated. */ SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages); /** * Allocate non-zeroed, locked, pages with user and, optionally, kernel * mappings. * * Use SUPR3PageFreeEx() to free memory allocated with this function. * * @returns VBox status code. * @param cPages The number of pages to allocate. * @param fFlags Flags, reserved. Must be zero. * @param ppvPages Where to store the address of the user mapping. * @param pR0Ptr Where to store the address of the kernel mapping. * NULL if no kernel mapping is desired. * @param paPages Where to store the physical addresses of each page. * Optional. */ SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages); /** * Maps a portion of a ring-3 only allocation into kernel space. * * @returns VBox status code. * * @param pvR3 The address SUPR3PageAllocEx return. * @param off Offset to start mapping at. Must be page aligned. * @param cb Number of bytes to map. Must be page aligned. * @param fFlags Flags, must be zero. * @param pR0Ptr Where to store the address on success. * */ SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr); /** * Changes the protection of * * @returns VBox status code. * @retval VERR_NOT_SUPPORTED if the OS doesn't allow us to change page level * protection. See also RTR0MemObjProtect. * * @param pvR3 The ring-3 address SUPR3PageAllocEx returned. * @param R0Ptr The ring-0 address SUPR3PageAllocEx returned if it * is desired that the corresponding ring-0 page * mappings should change protection as well. Pass * NIL_RTR0PTR if the ring-0 pages should remain * unaffected. * @param off Offset to start at which to start chagning the page * level protection. Must be page aligned. * @param cb Number of bytes to change. Must be page aligned. * @param fProt The new page level protection, either a combination * of RTMEM_PROT_READ, RTMEM_PROT_WRITE and * RTMEM_PROT_EXEC, or just RTMEM_PROT_NONE. */ SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt); /** * Free pages allocated by SUPR3PageAllocEx. * * @returns VBox status code. * @param pvPages The address of the user mapping. * @param cPages The number of pages. */ SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages); /** * Allocated memory with page aligned memory with a contiguous and locked physical * memory backing below 4GB. * * @returns Pointer to the allocated memory (virtual address). * *pHCPhys is set to the physical address of the memory. * If ppvR0 isn't NULL, *ppvR0 is set to the ring-0 mapping. * The returned memory must be freed using SUPR3ContFree(). * @returns NULL on failure. * @param cPages Number of pages to allocate. * @param pR0Ptr Where to store the ring-0 mapping of the allocation. (optional) * @param pHCPhys Where to store the physical address of the memory block. * * @remark This 2nd version of this API exists because we're not able to map the * ring-3 mapping executable on WIN64. This is a serious problem in regard to * the world switchers. */ SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys); /** * Frees memory allocated with SUPR3ContAlloc(). * * @returns VBox status code. * @param pv Pointer to the memory block which should be freed. * @param cPages Number of pages to be freed. */ SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages); /** * Allocated non contiguous physical memory below 4GB. * * The memory isn't zeroed. * * @returns VBox status code. * @returns NULL on failure. * @param cPages Number of pages to allocate. * @param ppvPages Where to store the pointer to the allocated memory. * The pointer stored here on success must be passed to * SUPR3LowFree when the memory should be released. * @param ppvPagesR0 Where to store the ring-0 pointer to the allocated memory. optional. * @param paPages Where to store the physical addresses of the individual pages. */ SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages); /** * Frees memory allocated with SUPR3LowAlloc(). * * @returns VBox status code. * @param pv Pointer to the memory block which should be freed. * @param cPages Number of pages that was allocated. */ SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages); /** * Load a module into R0 HC. * * This will verify the file integrity in a similar manner as * SUPR3HardenedVerifyFile before loading it. * * @returns VBox status code. * @param pszFilename The path to the image file. * @param pszModule The module name. Max 32 bytes. * @param ppvImageBase Where to store the image address. * @param pErrInfo Where to return extended error information. * Optional. */ SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase, PRTERRINFO pErrInfo); /** * Load a module into R0 HC. * * This will verify the file integrity in a similar manner as * SUPR3HardenedVerifyFile before loading it. * * @returns VBox status code. * @param pszFilename The path to the image file. * @param pszModule The module name. Max 32 bytes. * @param pszSrvReqHandler The name of the service request handler entry * point. See FNSUPR0SERVICEREQHANDLER. * @param ppvImageBase Where to store the image address. */ SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase); /** * Frees a R0 HC module. * * @returns VBox status code. * @param pvImageBase The base address of the image to free. * @remark This will not actually 'free' the module, there are of course usage counting. */ SUPR3DECL(int) SUPR3FreeModule(void *pvImageBase); /** * Lock down the module loader interface. * * This will lock down the module loader interface. No new modules can be * loaded and all loaded modules can no longer be freed. * * @returns VBox status code. * @param pErrInfo Where to return extended error information. * Optional. */ SUPR3DECL(int) SUPR3LockDownLoader(PRTERRINFO pErrInfo); /** * Get the address of a symbol in a ring-0 module. * * @returns VBox status code. * @param pvImageBase The base address of the image to search. * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a * ordinal value rather than a string pointer. * @param ppvValue Where to store the symbol value. */ SUPR3DECL(int) SUPR3GetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue); /** * Load R0 HC VMM code. * * @returns VBox status code. * @deprecated Use SUPR3LoadModule(pszFilename, "VMMR0.r0", &pvImageBase) */ SUPR3DECL(int) SUPR3LoadVMM(const char *pszFilename); /** * Unloads R0 HC VMM code. * * @returns VBox status code. * @deprecated Use SUPR3FreeModule(). */ SUPR3DECL(int) SUPR3UnloadVMM(void); /** * Get the physical address of the GIP. * * @returns VBox status code. * @param pHCPhys Where to store the physical address of the GIP. */ SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys); /** * Initializes only the bits relevant for the SUPR3HardenedVerify* APIs. * * This is for users that don't necessarily need to initialize the whole of * SUPLib. There is no harm in calling this one more time. * * @returns VBox status code. * @remarks Currently not counted, so only call once. */ SUPR3DECL(int) SUPR3HardenedVerifyInit(void); /** * Reverses the effect of SUPR3HardenedVerifyInit if SUPR3InitEx hasn't been * called. * * Ignored if the support library was initialized using SUPR3Init or * SUPR3InitEx. * * @returns VBox status code. */ SUPR3DECL(int) SUPR3HardenedVerifyTerm(void); /** * Verifies the integrity of a file, and optionally opens it. * * The integrity check is for whether the file is suitable for loading into * the hypervisor or VM process. The integrity check may include verifying * the authenticode/elfsign/whatever signature of the file, which can take * a little while. * * @returns VBox status code. On failure it will have printed a LogRel message. * * @param pszFilename The file. * @param pszWhat For the LogRel on failure. * @param phFile Where to store the handle to the opened file. This is optional, pass NULL * if the file should not be opened. * @deprecated Write a new one. */ SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszWhat, PRTFILE phFile); /** * Verifies the integrity of a the current process, including the image * location and that the invocation was absolute. * * This must currently be called after initializing the runtime. The intended * audience is set-uid-to-root applications, root services and similar. * * @returns VBox status code. On failure * message. * @param pszArgv0 The first argument to main(). * @param fInternal Set this to @c true if this is an internal * VirtualBox application. Otherwise pass @c false. * @param pErrInfo Where to return extended error information. */ SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, PRTERRINFO pErrInfo); /** * Verifies the integrity of an installation directory. * * The integrity check verifies that the directory cannot be tampered with by * normal users on the system. On Unix this translates to root ownership and * no symbolic linking. * * @returns VBox status code. On failure a message will be stored in @a pszErr. * * @param pszDirPath The directory path. * @param fRecursive Whether the check should be recursive or * not. When set, all sub-directores will be checked, * including files (@a fCheckFiles is ignored). * @param fCheckFiles Whether to apply the same basic integrity check to * the files in the directory as the directory itself. * @param pErrInfo Where to return extended error information. * Optional. */ SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo); /** * Verifies the integrity of a plug-in module. * * This is similar to SUPR3HardenedLdrLoad, except it does not load the module * and that the module does not have to be shipped with VirtualBox. * * @returns VBox status code. On failure a message will be stored in @a pszErr. * * @param pszFilename The filename of the plug-in module (nothing can be * omitted here). * @param pErrInfo Where to return extended error information. * Optional. */ SUPR3DECL(int) SUPR3HardenedVerifyPlugIn(const char *pszFilename, PRTERRINFO pErrInfo); /** * Same as RTLdrLoad() but will verify the files it loads (hardened builds). * * Will add dll suffix if missing and try load the file. * * @returns iprt status code. * @param pszFilename Image filename. This must have a path. * @param phLdrMod Where to store the handle to the loaded module. * @param fFlags See RTLDRLOAD_FLAGS_XXX. * @param pErrInfo Where to return extended error information. * Optional. */ SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); /** * Same as RTLdrLoadAppPriv() but it will verify the files it loads (hardened * builds). * * Will add dll suffix to the file if missing, then look for it in the * architecture dependent application directory. * * @returns iprt status code. * @param pszFilename Image filename. * @param phLdrMod Where to store the handle to the loaded module. * @param fFlags See RTLDRLOAD_FLAGS_XXX. * @param pErrInfo Where to return extended error information. * Optional. */ SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); /** * Same as RTLdrLoad() but will verify the files it loads (hardened builds). * * This differs from SUPR3HardenedLdrLoad() in that it can load modules from * extension packs and anything else safely installed on the system, provided * they pass the hardening tests. * * @returns iprt status code. * @param pszFilename The full path to the module, with extension. * @param phLdrMod Where to store the handle to the loaded module. * @param pErrInfo Where to return extended error information. * Optional. */ SUPR3DECL(int) SUPR3HardenedLdrLoadPlugIn(const char *pszFilename, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo); /** * Check if the host kernel can run in VMX root mode. * * @returns VINF_SUCCESS if supported, error code indicating why if not. */ SUPR3DECL(int) SUPR3QueryVTxSupported(void); /** * Return VT-x/AMD-V capabilities. * * @returns VINF_SUCCESS if supported, error code indicating why if not. * @param pfCaps Pointer to capability dword (out). * @todo Intended for main, which means we need to relax the privilege requires * when accessing certain vboxdrv functions. */ SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps); /** * Open the tracer. * * @returns VBox status code. * @param uCookie Cookie identifying the tracer we expect to talk to. * @param uArg Tracer specific open argument. */ SUPR3DECL(int) SUPR3TracerOpen(uint32_t uCookie, uintptr_t uArg); /** * Closes the tracer. * * @returns VBox status code. */ SUPR3DECL(int) SUPR3TracerClose(void); /** * Perform an I/O request on the tracer. * * @returns VBox status. * @param uCmd The tracer command. * @param uArg The argument. * @param piRetVal Where to store the tracer return value. */ SUPR3DECL(int) SUPR3TracerIoCtl(uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal); /** * Registers the user module with the tracer. * * @returns VBox status code. * @param hModNative Native module handle. Pass ~(uintptr_t)0 if not * at hand. * @param pszModule The module name. * @param pVtgHdr The VTG header. * @param uVtgHdrAddr The address to which the VTG header is loaded * in the relevant execution context. * @param fFlags See SUP_TRACER_UMOD_FLAGS_XXX */ SUPR3DECL(int) SUPR3TracerRegisterModule(uintptr_t hModNative, const char *pszModule, struct VTGOBJHDR *pVtgHdr, RTUINTPTR uVtgHdrAddr, uint32_t fFlags); /** * Deregisters the user module. * * @returns VBox status code. * @param pVtgHdr The VTG header. */ SUPR3DECL(int) SUPR3TracerDeregisterModule(struct VTGOBJHDR *pVtgHdr); /** * Fire the probe. * * @param pVtgProbeLoc The probe location record. * @param uArg0 Raw probe argument 0. * @param uArg1 Raw probe argument 1. * @param uArg2 Raw probe argument 2. * @param uArg3 Raw probe argument 3. * @param uArg4 Raw probe argument 4. */ SUPDECL(void) SUPTracerFireProbe(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, uintptr_t uArg3, uintptr_t uArg4); /** * Attempts to read the value of an MSR. * * @returns VBox status code. * @param uMsr The MSR to read. * @param idCpu The CPU to read it on, NIL_RTCPUID if it doesn't * matter which CPU. * @param puValue Where to return the value. * @param pfGp Where to store the \#GP indicator for the read * operation. */ SUPR3DECL(int) SUPR3MsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue, bool *pfGp); /** * Attempts to write to an MSR. * * @returns VBox status code. * @param uMsr The MSR to write to. * @param idCpu The CPU to wrtie it on, NIL_RTCPUID if it * doesn't matter which CPU. * @param uValue The value to write. * @param pfGp Where to store the \#GP indicator for the write * operation. */ SUPR3DECL(int) SUPR3MsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue, bool *pfGp); /** * Attempts to modify the value of an MSR. * * @returns VBox status code. * @param uMsr The MSR to modify. * @param idCpu The CPU to modify it on, NIL_RTCPUID if it * doesn't matter which CPU. * @param fAndMask The bits to keep in the current MSR value. * @param fOrMask The bits to set before writing. * @param pResult The result buffer. */ SUPR3DECL(int) SUPR3MsrProberModify(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, PSUPMSRPROBERMODIFYRESULT pResult); /** * Attempts to modify the value of an MSR, extended version. * * @returns VBox status code. * @param uMsr The MSR to modify. * @param idCpu The CPU to modify it on, NIL_RTCPUID if it * doesn't matter which CPU. * @param fAndMask The bits to keep in the current MSR value. * @param fOrMask The bits to set before writing. * @param fFaster If set to @c true some cache/tlb invalidation is * skipped, otherwise behave like * SUPR3MsrProberModify. * @param pResult The result buffer. */ SUPR3DECL(int) SUPR3MsrProberModifyEx(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, bool fFaster, PSUPMSRPROBERMODIFYRESULT pResult); /** * Resume built-in keyboard on MacBook Air and Pro hosts. * * @returns VBox status code. */ SUPR3DECL(int) SUPR3ResumeSuspendedKeyboards(void); /** * Measure the TSC-delta for the specified CPU. * * @returns VBox status code. * @param idCpu The CPU to measure the TSC-delta for. * @param fAsync Whether the measurement is asynchronous, returns * immediately after signalling a measurement * request. * @param fForce Whether to perform a measurement even if the * specified CPU has a (possibly) valid TSC delta. * @param cRetries Number of times to retry failed delta * measurements. * @param cMsWaitRetry Number of milliseconds to wait between retries. */ SUPR3DECL(int) SUPR3TscDeltaMeasure(RTCPUID idCpu, bool fAsync, bool fForce, uint8_t cRetries, uint8_t cMsWaitRetry); /** * Reads the delta-adjust TSC value. * * @returns VBox status code. * @param puTsc Where to store the read TSC value. * @param pidApic Where to store the APIC ID of the CPU where the TSC * was read (optional, can be NULL). */ SUPR3DECL(int) SUPR3ReadTsc(uint64_t *puTsc, uint16_t *pidApic); /** * Modifies the GIP flags. * * @returns VBox status code. * @param fOrMask The OR mask of the GIP flags, see SUPGIP_FLAGS_XXX. * @param fAndMask The AND mask of the GIP flags, see SUPGIP_FLAGS_XXX. */ SUPR3DECL(int) SUPR3GipSetFlags(uint32_t fOrMask, uint32_t fAndMask); /** @} */ #endif /* IN_RING3 */ /** @name User mode module flags (SUPR3TracerRegisterModule & SUP_IOCTL_TRACER_UMOD_REG). * @{ */ /** Executable image. */ #define SUP_TRACER_UMOD_FLAGS_EXE UINT32_C(1) /** Shared library (DLL, DYLIB, SO, etc). */ #define SUP_TRACER_UMOD_FLAGS_SHARED UINT32_C(2) /** Image type mask. */ #define SUP_TRACER_UMOD_FLAGS_TYPE_MASK UINT32_C(3) /** @} */ #ifdef IN_RING0 /** @defgroup grp_sup_r0 SUP Host Context Ring-0 API * @{ */ /** * Security objectype. */ typedef enum SUPDRVOBJTYPE { /** The usual invalid object. */ SUPDRVOBJTYPE_INVALID = 0, /** A Virtual Machine instance. */ SUPDRVOBJTYPE_VM, /** Internal network. */ SUPDRVOBJTYPE_INTERNAL_NETWORK, /** Internal network interface. */ SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, /** Single release event semaphore. */ SUPDRVOBJTYPE_SEM_EVENT, /** Multiple release event semaphore. */ SUPDRVOBJTYPE_SEM_EVENT_MULTI, /** Raw PCI device. */ SUPDRVOBJTYPE_RAW_PCI_DEVICE, /** The first invalid object type in this end. */ SUPDRVOBJTYPE_END, /** The usual 32-bit type size hack. */ SUPDRVOBJTYPE_32_BIT_HACK = 0x7ffffff } SUPDRVOBJTYPE; /** * Object destructor callback. * This is called for reference counted objectes when the count reaches 0. * * @param pvObj The object pointer. * @param pvUser1 The first user argument. * @param pvUser2 The second user argument. */ typedef DECLCALLBACK(void) FNSUPDRVDESTRUCTOR(void *pvObj, void *pvUser1, void *pvUser2); /** Pointer to a FNSUPDRVDESTRUCTOR(). */ typedef FNSUPDRVDESTRUCTOR *PFNSUPDRVDESTRUCTOR; SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2); SUPR0DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession); SUPR0DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking); SUPR0DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession); SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName); SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages); SUPR0DECL(int) SUPR0UnlockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3); SUPR0DECL(int) SUPR0ContAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys); SUPR0DECL(int) SUPR0ContFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); SUPR0DECL(int) SUPR0LowAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages); SUPR0DECL(int) SUPR0LowFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); SUPR0DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3); SUPR0DECL(int) SUPR0MemGetPhys(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages); SUPR0DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); SUPR0DECL(int) SUPR0PageAllocEx(PSUPDRVSESSION pSession, uint32_t cPages, uint32_t fFlags, PRTR3PTR ppvR3, PRTR0PTR ppvR0, PRTHCPHYS paPages); SUPR0DECL(int) SUPR0PageMapKernel(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t offSub, uint32_t cbSub, uint32_t fFlags, PRTR0PTR ppvR0); SUPR0DECL(int) SUPR0PageProtect(PSUPDRVSESSION pSession, RTR3PTR pvR3, RTR0PTR pvR0, uint32_t offSub, uint32_t cbSub, uint32_t fProt); SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3); SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip); SUPR0DECL(int) SUPR0GetSvmUsability(bool fInitSvm); SUPR0DECL(int) SUPR0GetVmxUsability(bool *pfIsSmxModeAmbiguous); SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps); SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession); SUPR0DECL(SUPPAGINGMODE) SUPR0GetPagingMode(void); SUPR0DECL(RTCCUINTREG) SUPR0ChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask); SUPR0DECL(int) SUPR0EnableVTx(bool fEnable); SUPR0DECL(bool) SUPR0SuspendVTxOnCpu(void); SUPR0DECL(void) SUPR0ResumeVTxOnCpu(bool fSuspended); #define SUP_TSCDELTA_MEASURE_F_FORCE RT_BIT_32(0) #define SUP_TSCDELTA_MEASURE_F_ASYNC RT_BIT_32(1) #define SUP_TSCDELTA_MEASURE_F_VALID_MASK UINT32_C(0x00000003) SUPR0DECL(int) SUPR0TscDeltaMeasureBySetIndex(PSUPDRVSESSION pSession, uint32_t iCpuSet, uint32_t fFlags, RTMSINTERVAL cMsWaitRetry, RTMSINTERVAL cMsWaitThread, uint32_t cTries); SUPR0DECL(void) SUPR0BadContext(PSUPDRVSESSION pSession, const char *pszFile, uint32_t uLine, const char *pszExpr); /** * Writes to the debugger and/or kernel log. * * The length of the formatted message is somewhat limited, so keep things short * and to the point. * * @returns Number of bytes written, mabye. * @param pszFormat IPRT format string. * @param ... Arguments referenced by the format string. */ SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); /** * Returns configuration flags of the host kernel. * * @returns Combination of SUPKERNELFEATURES_XXX flags. */ SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void); /** @name Absolute symbols * Take the address of these, don't try call them. * @{ */ SUPR0DECL(void) SUPR0AbsIs64bit(void); SUPR0DECL(void) SUPR0Abs64bitKernelCS(void); SUPR0DECL(void) SUPR0Abs64bitKernelSS(void); SUPR0DECL(void) SUPR0Abs64bitKernelDS(void); SUPR0DECL(void) SUPR0AbsKernelCS(void); SUPR0DECL(void) SUPR0AbsKernelSS(void); SUPR0DECL(void) SUPR0AbsKernelDS(void); SUPR0DECL(void) SUPR0AbsKernelES(void); SUPR0DECL(void) SUPR0AbsKernelFS(void); SUPR0DECL(void) SUPR0AbsKernelGS(void); /** @} */ /** * Support driver component factory. * * Component factories are registered by drivers that provides services * such as the host network interface filtering and access to the host * TCP/IP stack. * * @remark Module dependencies and making sure that a component doesn't * get unloaded while in use, is the sole responsibility of the * driver/kext/whatever implementing the component. */ typedef struct SUPDRVFACTORY { /** The (unique) name of the component factory. */ char szName[56]; /** * Queries a factory interface. * * The factory interface is specific to each component and will be be * found in the header(s) for the component alongside its UUID. * * @returns Pointer to the factory interfaces on success, NULL on failure. * * @param pSupDrvFactory Pointer to this structure. * @param pSession The SUPDRV session making the query. * @param pszInterfaceUuid The UUID of the factory interface. */ DECLR0CALLBACKMEMBER(void *, pfnQueryFactoryInterface,(struct SUPDRVFACTORY const *pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)); } SUPDRVFACTORY; /** Pointer to a support driver factory. */ typedef SUPDRVFACTORY *PSUPDRVFACTORY; /** Pointer to a const support driver factory. */ typedef SUPDRVFACTORY const *PCSUPDRVFACTORY; SUPR0DECL(int) SUPR0ComponentRegisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory); SUPR0DECL(int) SUPR0ComponentDeregisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory); SUPR0DECL(int) SUPR0ComponentQueryFactory(PSUPDRVSESSION pSession, const char *pszName, const char *pszInterfaceUuid, void **ppvFactoryIf); /** @name Tracing * @{ */ /** * Tracer data associated with a provider. */ typedef union SUPDRVTRACERDATA { /** Generic */ uint64_t au64[2]; /** DTrace data. */ struct { /** Provider ID. */ uintptr_t idProvider; /** The number of trace points provided. */ uint32_t volatile cProvidedProbes; /** Whether we've invalidated this bugger. */ bool fZombie; } DTrace; } SUPDRVTRACERDATA; /** Pointer to the tracer data associated with a provider. */ typedef SUPDRVTRACERDATA *PSUPDRVTRACERDATA; /** * Probe location info for ring-0. * * Since we cannot trust user tracepoint modules, we need to duplicate the probe * ID and enabled flag in ring-0. */ typedef struct SUPDRVPROBELOC { /** The probe ID. */ uint32_t idProbe; /** Whether it's enabled or not. */ bool fEnabled; } SUPDRVPROBELOC; /** Pointer to a ring-0 probe location record. */ typedef SUPDRVPROBELOC *PSUPDRVPROBELOC; /** * Probe info for ring-0. * * Since we cannot trust user tracepoint modules, we need to duplicate the * probe enable count. */ typedef struct SUPDRVPROBEINFO { /** The number of times this probe has been enabled. */ uint32_t volatile cEnabled; } SUPDRVPROBEINFO; /** Pointer to a ring-0 probe info record. */ typedef SUPDRVPROBEINFO *PSUPDRVPROBEINFO; /** * Support driver tracepoint provider core. */ typedef struct SUPDRVVDTPROVIDERCORE { /** The tracer data member. */ SUPDRVTRACERDATA TracerData; /** Pointer to the provider name (a copy that's always available). */ const char *pszName; /** Pointer to the module name (a copy that's always available). */ const char *pszModName; /** The provider descriptor. */ struct VTGDESCPROVIDER *pDesc; /** The VTG header. */ struct VTGOBJHDR *pHdr; /** The size of the entries in the pvProbeLocsEn table. */ uint8_t cbProbeLocsEn; /** The actual module bit count (corresponds to cbProbeLocsEn). */ uint8_t cBits; /** Set if this is a Umod, otherwise clear. */ bool fUmod; /** Explicit alignment padding (paranoia). */ uint8_t abAlignment[ARCH_BITS == 32 ? 1 : 5]; /** The probe locations used for descriptive purposes. */ struct VTGPROBELOC const *paProbeLocsRO; /** Pointer to the probe location array where the enable flag needs * flipping. For kernel providers, this will always be SUPDRVPROBELOC, * while user providers can either be 32-bit or 64-bit. Use * cbProbeLocsEn to calculate the address of an entry. */ void *pvProbeLocsEn; /** Pointer to the probe array containing the enabled counts. */ uint32_t *pacProbeEnabled; /** The ring-0 probe location info for user tracepoint modules. * This is NULL if fUmod is false. */ PSUPDRVPROBELOC paR0ProbeLocs; /** The ring-0 probe info for user tracepoint modules. * This is NULL if fUmod is false. */ PSUPDRVPROBEINFO paR0Probes; } SUPDRVVDTPROVIDERCORE; /** Pointer to a tracepoint provider core structure. */ typedef SUPDRVVDTPROVIDERCORE *PSUPDRVVDTPROVIDERCORE; /** Pointer to a tracer registration record. */ typedef struct SUPDRVTRACERREG const *PCSUPDRVTRACERREG; /** * Support driver tracer registration record. */ typedef struct SUPDRVTRACERREG { /** Magic value (SUPDRVTRACERREG_MAGIC). */ uint32_t u32Magic; /** Version (SUPDRVTRACERREG_VERSION). */ uint32_t u32Version; /** * Fire off a kernel probe. * * @param pVtgProbeLoc The probe location record. * @param uArg0 The first raw probe argument. * @param uArg1 The second raw probe argument. * @param uArg2 The third raw probe argument. * @param uArg3 The fourth raw probe argument. * @param uArg4 The fifth raw probe argument. * * @remarks SUPR0TracerFireProbe will do a tail jump thru this member, so * no extra stack frames will be added. * @remarks This does not take a 'this' pointer argument because it doesn't map * well onto VTG or DTrace. * */ DECLR0CALLBACKMEMBER(void, pfnProbeFireKernel, (struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, uintptr_t uArg3, uintptr_t uArg4)); /** * Fire off a user-mode probe. * * @param pThis Pointer to the registration record. * * @param pVtgProbeLoc The probe location record. * @param pSession The user session. * @param pCtx The usermode context info. * @param pVtgHdr The VTG header (read-only). * @param pProbeLocRO The read-only probe location record . */ DECLR0CALLBACKMEMBER(void, pfnProbeFireUser, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx, struct VTGOBJHDR const *pVtgHdr, struct VTGPROBELOC const *pProbeLocRO)); /** * Opens up the tracer. * * @returns VBox status code. * @param pThis Pointer to the registration record. * @param pSession The session doing the opening. * @param uCookie A cookie (magic) unique to the tracer, so it can * fend off incompatible clients. * @param uArg Tracer specific argument. * @param puSessionData Pointer to the session data variable. This must be * set to a non-zero value on success. */ DECLR0CALLBACKMEMBER(int, pfnTracerOpen, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg, uintptr_t *puSessionData)); /** * I/O control style tracer communication method. * * * @returns VBox status code. * @param pThis Pointer to the registration record. * @param pSession The session. * @param uSessionData The session data value. * @param uCmd The tracer specific command. * @param uArg The tracer command specific argument. * @param piRetVal The tracer specific return value. */ DECLR0CALLBACKMEMBER(int, pfnTracerIoCtl, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData, uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)); /** * Cleans up data the tracer has associated with a session. * * @param pThis Pointer to the registration record. * @param pSession The session handle. * @param uSessionData The data assoicated with the session. */ DECLR0CALLBACKMEMBER(void, pfnTracerClose, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)); /** * Registers a provider. * * @returns VBox status code. * @param pThis Pointer to the registration record. * @param pCore The provider core data. * * @todo Kernel vs. Userland providers. */ DECLR0CALLBACKMEMBER(int, pfnProviderRegister, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); /** * Attempts to deregisters a provider. * * @returns VINF_SUCCESS or VERR_TRY_AGAIN. If the latter, the provider * should be made as harmless as possible before returning as the * VTG object and associated code will be unloaded upon return. * * @param pThis Pointer to the registration record. * @param pCore The provider core data. */ DECLR0CALLBACKMEMBER(int, pfnProviderDeregister, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); /** * Make another attempt at unregister a busy provider. * * @returns VINF_SUCCESS or VERR_TRY_AGAIN. * @param pThis Pointer to the registration record. * @param pCore The provider core data. */ DECLR0CALLBACKMEMBER(int, pfnProviderDeregisterZombie, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); /** End marker (SUPDRVTRACERREG_MAGIC). */ uintptr_t uEndMagic; } SUPDRVTRACERREG; /** Tracer magic (Kenny Garrett). */ #define SUPDRVTRACERREG_MAGIC UINT32_C(0x19601009) /** Tracer registration structure version. */ #define SUPDRVTRACERREG_VERSION RT_MAKE_U32(0, 1) /** Pointer to a trace helper structure. */ typedef struct SUPDRVTRACERHLP const *PCSUPDRVTRACERHLP; /** * Helper structure. */ typedef struct SUPDRVTRACERHLP { /** The structure version (SUPDRVTRACERHLP_VERSION). */ uintptr_t uVersion; /** @todo ... */ /** End marker (SUPDRVTRACERHLP_VERSION) */ uintptr_t uEndVersion; } SUPDRVTRACERHLP; /** Tracer helper structure version. */ #define SUPDRVTRACERHLP_VERSION RT_MAKE_U32(0, 1) SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp); SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession); SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, struct VTGOBJHDR *pVtgHdr, const char *pszName); SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession); SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, struct VTGOBJHDR *pVtgHdr); SUPR0DECL(void) SUPR0TracerFireProbe(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, uintptr_t uArg3, uintptr_t uArg4); SUPR0DECL(void) SUPR0TracerUmodProbeFire(PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx); /** @} */ /** * Service request callback function. * * @returns VBox status code. * @param pSession The caller's session. * @param u64Arg 64-bit integer argument. * @param pReqHdr The request header. Input / Output. Optional. */ typedef DECLCALLBACK(int) FNSUPR0SERVICEREQHANDLER(PSUPDRVSESSION pSession, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr); /** Pointer to a FNR0SERVICEREQHANDLER(). */ typedef R0PTRTYPE(FNSUPR0SERVICEREQHANDLER *) PFNSUPR0SERVICEREQHANDLER; /** @defgroup grp_sup_r0_idc The IDC Interface * @{ */ /** The current SUPDRV IDC version. * This follows the usual high word / low word rules, i.e. high word is the * major number and it signifies incompatible interface changes. */ #define SUPDRV_IDC_VERSION UINT32_C(0x00010000) /** * Inter-Driver Communication Handle. */ typedef union SUPDRVIDCHANDLE { /** Padding for opaque usage. * Must be greater or equal in size than the private struct. */ void *apvPadding[4]; #ifdef SUPDRVIDCHANDLEPRIVATE_DECLARED /** The private view. */ struct SUPDRVIDCHANDLEPRIVATE s; #endif } SUPDRVIDCHANDLE; /** Pointer to a handle. */ typedef SUPDRVIDCHANDLE *PSUPDRVIDCHANDLE; SUPR0DECL(int) SUPR0IdcOpen(PSUPDRVIDCHANDLE pHandle, uint32_t uReqVersion, uint32_t uMinVersion, uint32_t *puSessionVersion, uint32_t *puDriverVersion, uint32_t *puDriverRevision); SUPR0DECL(int) SUPR0IdcCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, void *pvReq, uint32_t cbReq); SUPR0DECL(int) SUPR0IdcClose(PSUPDRVIDCHANDLE pHandle); SUPR0DECL(PSUPDRVSESSION) SUPR0IdcGetSession(PSUPDRVIDCHANDLE pHandle); SUPR0DECL(int) SUPR0IdcComponentRegisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory); SUPR0DECL(int) SUPR0IdcComponentDeregisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory); /** @} */ /** @name Ring-0 module entry points. * * These can be exported by ring-0 modules SUP are told to load. * * @{ */ DECLEXPORT(int) ModuleInit(void *hMod); DECLEXPORT(void) ModuleTerm(void *hMod); /** @} */ /** @} */ #endif /** @name Trust Anchors and Certificates * @{ */ /** * Trust anchor table entry (in generated Certificates.cpp). */ typedef struct SUPTAENTRY { /** Pointer to the raw bytes. */ const unsigned char *pch; /** Number of bytes. */ unsigned cb; } SUPTAENTRY; /** Pointer to a trust anchor table entry. */ typedef SUPTAENTRY const *PCSUPTAENTRY; /** Macro for simplifying generating the trust anchor tables. */ #define SUPTAENTRY_GEN(a_abTA) { &a_abTA[0], sizeof(a_abTA) } /** All certificates we know. */ extern SUPTAENTRY const g_aSUPAllTAs[]; /** Number of entries in g_aSUPAllTAs. */ extern unsigned const g_cSUPAllTAs; /** Software publisher certificate roots (Authenticode). */ extern SUPTAENTRY const g_aSUPSpcRootTAs[]; /** Number of entries in g_aSUPSpcRootTAs. */ extern unsigned const g_cSUPSpcRootTAs; /** Kernel root certificates used by Windows. */ extern SUPTAENTRY const g_aSUPNtKernelRootTAs[]; /** Number of entries in g_aSUPNtKernelRootTAs. */ extern unsigned const g_cSUPNtKernelRootTAs; /** Timestamp root certificates trusted by Windows. */ extern SUPTAENTRY const g_aSUPTimestampTAs[]; /** Number of entries in g_aSUPTimestampTAs. */ extern unsigned const g_cSUPTimestampTAs; /** TAs we trust (the build certificate, Oracle VirtualBox). */ extern SUPTAENTRY const g_aSUPTrustedTAs[]; /** Number of entries in g_aSUPTrustedTAs. */ extern unsigned const g_cSUPTrustedTAs; /** Supplemental certificates, like cross signing certificates. */ extern SUPTAENTRY const g_aSUPSupplementalTAs[]; /** Number of entries in g_aSUPTrustedTAs. */ extern unsigned const g_cSUPSupplementalTAs; /** The build certificate. */ extern const unsigned char g_abSUPBuildCert[]; /** The size of the build certificate. */ extern const unsigned g_cbSUPBuildCert; /** @} */ /** @} */ RT_C_DECLS_END #endif