SUPDRVShared.c revision 71b548af8b5b8adb865702432045250bc56ad7e5
1N/A * available from http://www.virtualbox.org. This file is free software;
1N/A * Clara, CA 95054 USA or visit http://www.sun.com if you need
1N/A#ifndef PAGE_SHIFT
1N/A#ifdef RT_OS_LINUX
1N/A * instanciation in log-vbox.c(pp).
#ifdef VBOX_WITH_IDT_PATCHING
static int supdrvIOCtl_IdtInstall(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPIDTINSTALL pReq);
static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq);
static int supdrvLdrSetR0EP(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
#ifdef RT_OS_WINDOWS
static int supdrvPageGetPhys(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages);
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
int rc;
if (!rc)
if (!rc)
if (!rc)
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
#ifdef VBOX_WITH_IDT_PATCHING
#ifdef VBOX_WITH_IDT_PATCHING
while (pPatch)
while (pObj)
while (pUsage)
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
if (pSession)
if (!rc)
pSession->Bundle.cUsed = 0 */
return VINF_SUCCESS;
return rc;
#ifdef VBOX_WITH_IDT_PATCHING
AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
while (pBundle)
int rc;
Log2(("eType=%d pvR0=%p pvR3=%p cb=%ld\n", pBundle->aMem[i].eType, RTR0MemObjAddress(pBundle->aMem[i].MemObj),
(void *)RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3), (long)RTR0MemObjSize(pBundle->aMem[i].MemObj)));
while (pUsage)
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
int rc;
switch (uIOCtl)
case SUP_IOCTL_FAST_DO_NOP:
return rc;
* list, see http://www.kerneldrivers.org/RHEL5.
int chCur;
int ch;
int VBOXCALL supdrvIOCtl(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
OSDBGPRINT(("vboxdrv: bad cookie %#lx / %#lx.\n", (long)pReqHdr->u32Cookie, (long)pReqHdr->u32SessionCookie));
return VERR_INVALID_PARAMETER;
OSDBGPRINT(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld. cbOut=%ld expected %ld.\n", \
REQ_CHECK_SIZES_EX(SUP_IOCTL_QUERY_FUNCS, SUP_IOCTL_QUERY_FUNCS_SIZE_IN, SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(RT_ELEMENTS(g_aFunctions)));
#ifdef VBOX_WITH_IDT_PATCHING
#ifdef VBOX_WITH_IDT_PATCHING
pReq->Hdr.rc = SUPR0ContAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.HCPhys);
REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, !supdrvCheckInvalidChar(pReq->u.In.szName, ";:()[]{}/\\|&*%#@!~`\"'"));
REQ_CHECK_SIZES_EX(SUP_IOCTL_LDR_LOAD, SUP_IOCTL_LDR_LOAD_SIZE_IN(pReq->u.In.cbImage), SUP_IOCTL_LDR_LOAD_SIZE_OUT);
uint32_t i;
("SUP_IOCTL_LDR_LOAD: sym #%ld: symb off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offSymbol, (long)pReq->u.In.cbImage));
("SUP_IOCTL_LDR_LOAD: sym #%ld: name off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImage));
REQ_CHECK_EXPR_FMT(memchr(&pReq->u.In.achImage[pReq->u.In.offStrTab + paSyms[i].offName], '\0', pReq->u.In.cbStrTab - paSyms[i].offName),
("SUP_IOCTL_LDR_LOAD: sym #%ld: unterminated name! (%#lx / %#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImage));
REQ_CHECK_EXPR(SUP_IOCTL_LDR_GET_SYMBOL, memchr(pReq->u.In.szSymbol, '\0', sizeof(pReq->u.In.szSymbol)));
REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(0), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0));
pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg);
("SUP_IOCTL_CALL_VMMR0: cbIn=%#x < %#x\n", pReq->Hdr.cbIn, SUP_IOCTL_CALL_VMMR0_SIZE(sizeof(SUPVMMR0REQHDR))));
REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(pVMMReq->cbReq), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(pVMMReq->cbReq));
pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg);
pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
REQ_CHECK_SIZES_EX(SUP_IOCTL_LOW_ALLOC, SUP_IOCTL_LOW_ALLOC_SIZE_IN, SUP_IOCTL_LOW_ALLOC_SIZE_OUT(pReq->u.In.cPages));
pReq->Hdr.rc = SUPR0LowAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.aPages[0]);
REQ_CHECK_SIZES_EX(SUP_IOCTL_PAGE_ALLOC, SUP_IOCTL_PAGE_ALLOC_SIZE_IN, SUP_IOCTL_PAGE_ALLOC_SIZE_OUT(pReq->u.In.cPages));
pReq->Hdr.rc = SUPR0PageAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR3, &pReq->u.Out.aPages[0]);
return SUPDRV_ERR_GENERAL_FAILURE;
* @param pfnDestructor The destructore function which will be called when the reference count reaches 0.
SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
if (!pObj)
return NULL;
if (pUsage)
if (!pUsage)
return NULL;
return pObj;
if (pUsagePre)
if (!pUsagePre)
return VERR_NO_MEMORY;
if (pUsage)
Log(("SUPR0AddRef: pUsagePre=%p:{.pObj=%p, .pNext=%p}\n", pUsagePre, pUsagePre->pObj, pUsagePre->pNext));
if (pUsagePre)
return VINF_SUCCESS;
bool fDestroy = false;
AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
if (pUsagePrev)
fDestroy = true;
if (fDestroy)
pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
int rc;
return rc;
return VINF_SUCCESS;
return VERR_PERMISSION_DENIED;
SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages)
int rc;
LogFlow(("SUPR0LockMem: pSession=%p pvR3=%p cPages=%d paPages=%p\n", pSession, (void *)pvR3, cPages, paPages));
|| !pvR3)
return VERR_INVALID_PARAMETER;
#ifdef RT_OS_WINDOWS /* A temporary hack for windows, will be removed once all ring-3 code has been cleaned up. */
return rc;
AssertMsg(RTR0MemObjAddressR3(Mem.MemObj) == pvR3, ("%p == %p\n", RTR0MemObjAddressR3(Mem.MemObj), pvR3));
while (iPage-- > 0)
return rc;
#ifdef RT_OS_WINDOWS
return VINF_SUCCESS;
SUPR0DECL(int) SUPR0ContAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys)
int rc;
LogFlow(("SUPR0ContAlloc: pSession=%p cPages=%d ppvR0=%p ppvR3=%p pHCPhys=%p\n", pSession, cPages, ppvR0, ppvR3, pHCPhys));
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
int rc2;
if (!rc)
return rc;
SUPR0DECL(int) SUPR0LowAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages)
unsigned iPage;
int rc;
LogFlow(("SUPR0LowAlloc: pSession=%p cPages=%d ppvR3=%p ppvR0=%p paPages=%p\n", pSession, cPages, ppvR3, ppvR0, paPages));
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
int rc2;
if (!rc)
return rc;
int rc;
return VERR_INVALID_PARAMETER;
int rc2;
if (!rc)
return VINF_SUCCESS;
return rc;
SUPR0DECL(int) SUPR0MemGetPhys(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages) /** @todo switch this bugger to RTHCPHYS */
unsigned iPage;
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
SUPR0DECL(int) SUPR0PageAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR3PTR ppvR3, PRTHCPHYS paPages)
int rc;
* Validate input. The allowed allocation size must be at least equal to the maximum guest VRAM size.
Log(("SUPR0PageAlloc: Illegal request cb=%u; must be greater than 0 and smaller than 128MB.\n", cPages));
return VERR_INVALID_PARAMETER;
int rc2;
if (!rc)
if (paPages)
while (iPage-- > 0)
return VINF_SUCCESS;
return rc;
#ifdef RT_OS_WINDOWS
static int supdrvPageGetPhys(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages)
LogFlow(("supdrvPageGetPhys: pSession=%p pvR3=%p cPages=%#lx paPages=%p\n", pSession, (void *)pvR3, (long)cPages, paPages));
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
int rc = 0;
if (ppGipR3)
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
if (!rc)
ASMAtomicXchgU32(&pGip->aCPUs[i].u32TransactionId, pGip->aCPUs[i].u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1));
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
if (pHCPhysGip)
if (ppGipR3)
#ifdef DEBUG_DARWIN_GIP
OSDBGPRINT(("SUPR0GipMap: returns %d *pHCPhysGip=%lx *ppGip=%p GipMapObjR3\n", rc, (unsigned long)HCPhys, pGip, pSession->GipMapObjR3));
LogFlow(("SUPR0GipMap: returns %d *pHCPhysGip=%lx *ppGipR3=%p\n", rc, (unsigned long)HCPhys, (void *)(uintptr_t)pGip));
return rc;
#ifdef DEBUG_DARWIN_GIP
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
if (!rc)
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
return rc;
return VINF_SUCCESS;
if (!pBundle)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
if (!uPtr)
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
#ifdef VBOX_WITH_IDT_PATCHING
static int supdrvIOCtl_IdtInstall(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPIDTINSTALL pReq)
if (!pUsagePre)
return VERR_NO_MEMORY;
if (!pPatchPre)
return VERR_NO_MEMORY;
if (!pPatch)
if (pPatch)
if (pPatch)
if (!pUsage)
if (pPatchPre)
if (pUsagePre)
return NULL;
#ifdef RT_OS_WINDOWS /* We don't use 0xef and above because they are system stuff on linux (ef is IPI,
static int s_iWobble = 0;
u8Idt = 0;
if (!u8Idt)
u8Idt = 0;
if (!u8Idt)
return NULL;
#ifdef RT_ARCH_AMD64
#ifdef RT_ARCH_AMD64
#ifdef RT_ARCH_AMD64
uFixJmp = u;
# ifdef RT_OS_WINDOWS
uFixCall = u;
*u.pu32++ = 0;
uNotNested = u;
uFixJmp = u;
*u.pb++ = 0;
uFixJmpNotNested = u;
*u.pu32++ = 0;
*u.pu16++ = 0;
#ifdef RT_OS_WINDOWS
uFixCall = u;
*uFixJmpNotNested.pu32++ = ((uint32_t)pPatch->SavedIdt.u16OffsetHigh << 16) | pPatch->SavedIdt.u16OffsetLow;
AssertMsg(!memcmp((void *)pPatch->pIdtEntry, &pPatch->ChangedIdt, sizeof(pPatch->ChangedIdt)), ("The stupid change code didn't work!!!!!\n"));
return pPatch;
while (pUsage)
while (pUsage)
return VINF_SUCCESS;
while (pPatchPrev)
AssertMsg(!memcmp((void *)pPatch->pIdtEntry, &pPatch->ChangedIdt, sizeof(pPatch->ChangedIdt)), ("The hijacked IDT entry has CHANGED!!!\n"));
AssertMsg(!memcmp((void *)pPatch->pIdtEntry, &pPatch->SavedIdt, sizeof(pPatch->SavedIdt)), ("The hijacked IDT entry has CHANGED!!!\n"));
#ifdef RT_ARCH_AMD64
unsigned cb;
void *pv;
return VINF_SUCCESS;
if (!pv)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
int rc;
LogFlow(("supdrvIOCtl_LdrLoad: pvImageBase=%p cbImage=%d\n", pReq->u.In.pvImageBase, pReq->u.In.cbImage));
if (!pUsage)
return VERR_INVALID_HANDLE;
Log(("SUP_IOCTL_LDR_LOAD: image size mismatch!! %d(prep) != %d(load)\n", pImage->cbImage, pReq->u.In.cbImage));
return VERR_INVALID_HANDLE;
return SUPDRV_ERR_ALREADY_LOADED;
case SUPLDRLOADEP_NOTHING:
case SUPLDRLOADEP_VMMR0:
return VERR_INVALID_PARAMETER;
if ( (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryInt - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage
|| (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryFast - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage
|| (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryEx - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
Log(("Out of range (%p LB %#x): pvVMMR0EntryInt=%p, pvVMMR0EntryFast=%p or pvVMMR0EntryEx=%p is NULL!\n",
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
case SUPLDRLOADEP_NOTHING:
case SUPLDRLOADEP_VMMR0:
if (rc)
return rc;
int rc;
if (!pUsage)
return VERR_INVALID_HANDLE;
if (RT_UNLIKELY((uintptr_t)pGenUsage->pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImage))
if (pUsagePrev)
return VINF_SUCCESS;
static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq)
uint32_t i;
const char *pchStrings;
Log3(("supdrvIOCtl_LdrGetSymbol: pvImageBase=%p szSymbol=\"%s\"\n", pReq->u.In.pvImageBase, pReq->u.In.szSymbol));
if (!pUsage)
return VERR_INVALID_HANDLE;
return VERR_ALREADY_LOADED;
return rc;
static int supdrvLdrSetR0EP(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx)
#ifdef VBOX_WITH_IDT_PATCHING
#ifdef VBOX_WITH_IDT_PATCHING
# ifdef RT_ARCH_AMD64
ASMAtomicXchgU64((volatile uint64_t *)&pPatch->auCode[pPatch->offVMMR0EntryFixup], (uint64_t)pvVMMR0);
return rc;
#ifdef VBOX_WITH_IDT_PATCHING
#ifdef VBOX_WITH_IDT_PATCHING
# ifdef RT_ARCH_AMD64
(uint32_t)&pPatch->auCode[pPatch->offStub] - (uint32_t)&pPatch->auCode[pPatch->offVMMR0EntryFixup + 4]);
while (pUsage)
if (pUsage)
if (pImagePrev)
unsigned cObjs = 0;
cObjs++;
if (cObjs)
case X86_CR4_PGE:
case X86_CR4_PAE:
return enmMode;
#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
int rc;
return rc;
rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL, supdrvGipAsyncTimer, pDevExt);
return VINF_SUCCESS;
OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %ld ns interval. rc=%d\n", (long)u32Interval, rc));
return rc;
int rc;
#ifdef DEBUG_DARWIN_GIP
bool fIgnored;
for (i = 0; i < RTCPUSET_MAX_CPUS; i++)
int VBOXCALL supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS, unsigned uUpdateHz)
#ifdef DEBUG_DARWIN_GIP
OSDBGPRINT(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
LogFlow(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
return VINF_SUCCESS;
return SUPGIPMODE_ASYNC_TSC;
return SUPGIPMODE_ASYNC_TSC;
return SUPGIPMODE_SYNC_TSC;
unsigned iTSCHistoryHead;
/* this can happen on win32 if we're taking to long and there are more CPUs around. shouldn't happen though. */
static DECLCALLBACK(void) supdrvDetermineAsyncTscWorker(RTCPUID idCpu, void *pvUser1, void *pvUser2)
bool fBackwards;
int rc;
rc = RTMpOnSpecific(RTMpCpuIdFromSetIndex(iCpuSet), supdrvDetermineAsyncTscWorker, &s_aTsc[iSlot][iCpu], NULL);
iCpuSet++;
fBackwards = false;
u64TscLast = 0;
u64DiffMax = 0;
fBackwards = true;
fBackwards = true;
return fBackwards;
return NULL;
return NULL;
RTDECL(void) RTLogLoggerEx(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)