IMG_INT32 PVRSRV_BridgeDispatchKM(struct file *pFile, IMG_UINT unref__ ioctlCmd, IMG_UINT32 arg) #endif { IMG_UINT32 cmd; #if !defined(SUPPORT_DRI_DRM) PVRSRV_BRIDGE_PACKAGE *psBridgePackageUM = (PVRSRV_BRIDGE_PACKAGE *)arg; PVRSRV_BRIDGE_PACKAGE sBridgePackageKM; #endif PVRSRV_BRIDGE_PACKAGE *psBridgePackageKM; IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM(); PVRSRV_PER_PROCESS_DATA *psPerProc; IMG_INT err = -EFAULT; LinuxLockMutex(&gPVRSRVLock); #if defined(SUPPORT_DRI_DRM) PVR_UNREFERENCED_PARAMETER(dev); psBridgePackageKM = (PVRSRV_BRIDGE_PACKAGE *)arg; PVR_ASSERT(psBridgePackageKM != IMG_NULL); #else PVR_UNREFERENCED_PARAMETER(ioctlCmd); psBridgePackageKM = &sBridgePackageKM; if(!OSAccessOK(PVR_VERIFY_WRITE, psBridgePackageUM, sizeof(PVRSRV_BRIDGE_PACKAGE))) { PVR_DPF((PVR_DBG_ERROR, "%s: Received invalid pointer to function arguments", __FUNCTION__)); goto unlock_and_return; } if(OSCopyFromUser(IMG_NULL, psBridgePackageKM, psBridgePackageUM, sizeof(PVRSRV_BRIDGE_PACKAGE)) != PVRSRV_OK) { goto unlock_and_return; } #endif cmd = psBridgePackageKM->ui32BridgeID; #if defined(MODULE_TEST) switch (cmd) { case PVRSRV_BRIDGE_SERVICES_TEST_MEM1: { PVRSRV_ERROR eError = MemTest1(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_MEM2: { PVRSRV_ERROR eError = MemTest2(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_RESOURCE: { PVRSRV_ERROR eError = ResourceTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_EVENTOBJECT: { PVRSRV_ERROR eError = EventObjectTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_MEMMAPPING: { PVRSRV_ERROR eError = MemMappingTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_PROCESSID: { PVRSRV_ERROR eError = ProcessIDTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_CLOCKUSWAITUS: { PVRSRV_ERROR eError = ClockusWaitusTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_TIMER: { PVRSRV_ERROR eError = TimerTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_PRIVSRV: { PVRSRV_ERROR eError = PrivSrvTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; case PVRSRV_BRIDGE_SERVICES_TEST_COPYDATA: { IMG_UINT32 ui32PID; PVRSRV_PER_PROCESS_DATA *psPerProc; PVRSRV_ERROR eError; ui32PID = OSGetCurrentProcessIDKM(); PVRSRVTrace("PVRSRV_BRIDGE_SERVICES_TEST_COPYDATA %d", ui32PID); psPerProc = PVRSRVPerProcessData(ui32PID); eError = CopyDataTest(psBridgePackageKM->pvParamIn, psBridgePackageKM->pvParamOut, psPerProc); *(PVRSRV_ERROR*)psBridgePackageKM->pvParamOut = eError; err = 0; goto unlock_and_return; } case PVRSRV_BRIDGE_SERVICES_TEST_POWERMGMT: { PVRSRV_ERROR eError = PowerMgmtTest(); if (psBridgePackageKM->ui32OutBufferSize == sizeof(PVRSRV_BRIDGE_RETURN)) { PVRSRV_BRIDGE_RETURN* pReturn = (PVRSRV_BRIDGE_RETURN*)psBridgePackageKM->pvParamOut ; pReturn->eError = eError; } } err = 0; goto unlock_and_return; } #endif if(cmd != PVRSRV_BRIDGE_CONNECT_SERVICES) { PVRSRV_ERROR eError; eError = PVRSRVLookupHandle(KERNEL_HANDLE_BASE, (IMG_PVOID *)&psPerProc, psBridgePackageKM->hKernelServices, PVRSRV_HANDLE_TYPE_PERPROC_DATA); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "%s: Invalid kernel services handle (%d)", __FUNCTION__, eError)); goto unlock_and_return; } if(psPerProc->ui32PID != ui32PID) { PVR_DPF((PVR_DBG_ERROR, "%s: Process %d tried to access data " "belonging to process %d", __FUNCTION__, ui32PID, psPerProc->ui32PID)); goto unlock_and_return; } } else { psPerProc = PVRSRVPerProcessData(ui32PID); if(psPerProc == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "PVRSRV_BridgeDispatchKM: " "Couldn't create per-process data area")); goto unlock_and_return; } } psBridgePackageKM->ui32BridgeID = PVRSRV_GET_BRIDGE_ID(psBridgePackageKM->ui32BridgeID); #if defined(PVR_SECURE_FD_EXPORT) switch(cmd) { case PVRSRV_BRIDGE_EXPORT_DEVICEMEM: { PVRSRV_FILE_PRIVATE_DATA *psPrivateData = PRIVATE_DATA(pFile); if(psPrivateData->hKernelMemInfo) { PVR_DPF((PVR_DBG_ERROR, "%s: Can only export one MemInfo " "per file descriptor", __FUNCTION__)); err = -EINVAL; goto unlock_and_return; } break; } case PVRSRV_BRIDGE_MAP_DEV_MEMORY: { PVRSRV_BRIDGE_IN_MAP_DEV_MEMORY *psMapDevMemIN = (PVRSRV_BRIDGE_IN_MAP_DEV_MEMORY *)psBridgePackageKM->pvParamIn; PVRSRV_FILE_PRIVATE_DATA *psPrivateData = PRIVATE_DATA(pFile); if(!psPrivateData->hKernelMemInfo) { PVR_DPF((PVR_DBG_ERROR, "%s: File descriptor has no " "associated MemInfo handle", __FUNCTION__)); err = -EINVAL; goto unlock_and_return; } psMapDevMemIN->hKernelMemInfo = psPrivateData->hKernelMemInfo; break; } default: { PVRSRV_FILE_PRIVATE_DATA *psPrivateData = PRIVATE_DATA(pFile); if(psPrivateData->hKernelMemInfo) { PVR_DPF((PVR_DBG_ERROR, "%s: Import/Export handle tried " "to use privileged service", __FUNCTION__)); goto unlock_and_return; } break; } } #endif err = BridgedDispatchKM(psPerProc, psBridgePackageKM); if(err != PVRSRV_OK) goto unlock_and_return; switch(cmd) { #if defined(PVR_SECURE_FD_EXPORT) case PVRSRV_BRIDGE_EXPORT_DEVICEMEM: { PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM *psExportDeviceMemOUT = (PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM *)psBridgePackageKM->pvParamOut; PVRSRV_FILE_PRIVATE_DATA *psPrivateData = PRIVATE_DATA(pFile); psPrivateData->hKernelMemInfo = psExportDeviceMemOUT->hMemInfo; #if defined(SUPPORT_MEMINFO_IDS) psExportDeviceMemOUT->ui64Stamp = psPrivateData->ui64Stamp = ++ui64Stamp; #endif break; } #endif #if defined(SUPPORT_MEMINFO_IDS) case PVRSRV_BRIDGE_MAP_DEV_MEMORY: { PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY *psMapDeviceMemoryOUT = (PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY *)psBridgePackageKM->pvParamOut; PVRSRV_FILE_PRIVATE_DATA *psPrivateData = PRIVATE_DATA(pFile); psMapDeviceMemoryOUT->sDstClientMemInfo.ui64Stamp = psPrivateData->ui64Stamp; break; } case PVRSRV_BRIDGE_MAP_DEVICECLASS_MEMORY: { PVRSRV_BRIDGE_OUT_MAP_DEVICECLASS_MEMORY *psDeviceClassMemoryOUT = (PVRSRV_BRIDGE_OUT_MAP_DEVICECLASS_MEMORY *)psBridgePackageKM->pvParamOut; psDeviceClassMemoryOUT->sClientMemInfo.ui64Stamp = ++ui64Stamp; break; } #endif default: break; } unlock_and_return: LinuxUnLockMutex(&gPVRSRVLock); return err; }
IMG_INT BridgedDispatchKM(CONNECTION_DATA * psConnection, PVRSRV_BRIDGE_PACKAGE * psBridgePackageKM) { IMG_VOID * psBridgeIn; IMG_VOID * psBridgeOut; BridgeWrapperFunction pfBridgeHandler; IMG_UINT32 ui32BridgeID = psBridgePackageKM->ui32BridgeID; IMG_INT err = -EFAULT; #if defined(DEBUG_BRIDGE_KM_STOP_AT_DISPATCH) PVR_DBG_BREAK; #endif #if defined(DEBUG_BRIDGE_KM) PVR_DPF((PVR_DBG_MESSAGE, "%s: %s", __FUNCTION__, g_BridgeDispatchTable[ui32BridgeID].pszIOCName)); g_BridgeDispatchTable[ui32BridgeID].ui32CallCount++; g_BridgeGlobalStats.ui32IOCTLCount++; #endif if(!psConnection->bInitProcess) { if(PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RAN)) { if (ui32BridgeID == PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_SRVCORE_RELEASEGLOBALEVENTOBJECT)) { PVR_DPF((PVR_DBG_MESSAGE, "%s: Allowing release call through.", __FUNCTION__)); } else if (!PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL)) { PVR_DPF((PVR_DBG_ERROR, "%s: Initialisation failed. Driver unusable.", __FUNCTION__)); goto return_fault; } } else { if(PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RUNNING)) { PVR_DPF((PVR_DBG_ERROR, "%s: Initialisation is in progress", __FUNCTION__)); goto return_fault; } else { /* Only certain operations are allowed */ switch(ui32BridgeID) { case PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_SRVCORE_CONNECT): case PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_SRVCORE_DISCONNECT): case PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_SRVCORE_ACQUIREGLOBALEVENTOBJECT): case PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_SRVCORE_RELEASEGLOBALEVENTOBJECT): case PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_SRVCORE_INITSRVCONNECT): case PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_SRVCORE_INITSRVDISCONNECT): break; default: PVR_DPF((PVR_DBG_ERROR, "%s: Driver initialisation not completed yet.", __FUNCTION__)); goto return_fault; } } } } #if defined(__linux__) { ENV_DATA *psEnvData = OSGetEnvData(); /* We have already set up some static buffers to store our ioctl data... */ psBridgeIn = psEnvData->pvBridgeData; psBridgeOut = (IMG_PVOID)((IMG_PBYTE)psBridgeIn + PVRSRV_MAX_BRIDGE_IN_SIZE); /* check we are not using a bigger bridge than allocated */ #if defined(DEBUG) PVR_ASSERT(psBridgePackageKM->ui32InBufferSize < PVRSRV_MAX_BRIDGE_IN_SIZE); PVR_ASSERT(psBridgePackageKM->ui32OutBufferSize < PVRSRV_MAX_BRIDGE_OUT_SIZE); #endif if(psBridgePackageKM->ui32InBufferSize > 0) { if(!OSAccessOK(PVR_VERIFY_READ, psBridgePackageKM->pvParamIn, psBridgePackageKM->ui32InBufferSize)) { PVR_DPF((PVR_DBG_ERROR, "%s: Invalid pvParamIn pointer", __FUNCTION__)); } if(CopyFromUserWrapper(psConnection, ui32BridgeID, psBridgeIn, psBridgePackageKM->pvParamIn, psBridgePackageKM->ui32InBufferSize) != PVRSRV_OK) { goto return_fault; } } } #else psBridgeIn = psBridgePackageKM->pvParamIn; psBridgeOut = psBridgePackageKM->pvParamOut; #endif if(ui32BridgeID >= (BRIDGE_DISPATCH_TABLE_ENTRY_COUNT)) { PVR_DPF((PVR_DBG_ERROR, "%s: ui32BridgeID = %d is out if range!", __FUNCTION__, ui32BridgeID)); goto return_fault; } pfBridgeHandler = (BridgeWrapperFunction)g_BridgeDispatchTable[ui32BridgeID].pfFunction; if (pfBridgeHandler == NULL) { PVR_DPF((PVR_DBG_ERROR, "%s: ui32BridgeID = %d is not a registered function!", __FUNCTION__, ui32BridgeID)); goto return_fault; } err = pfBridgeHandler(ui32BridgeID, psBridgeIn, psBridgeOut, psConnection); if(err < 0) { goto return_fault; } #if defined(__linux__) /* This should always be true as a.t.m. all bridge calls have to return an error message, but this could change so we do this check to be safe. */ if(psBridgePackageKM->ui32OutBufferSize > 0) { if(CopyToUserWrapper(psConnection, ui32BridgeID, psBridgePackageKM->pvParamOut, psBridgeOut, psBridgePackageKM->ui32OutBufferSize) != PVRSRV_OK) { goto return_fault; } } #endif err = 0; return_fault: return err; }