/********************************************************************** * * Copyright (C) Imagination Technologies Ltd. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful but, except * as otherwise stated in writing, without any warranty; without even the * implied warranty of merchantability or fitness for a particular purpose. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * * Contact Information: * Imagination Technologies Ltd. * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK * ******************************************************************************/ #if defined (SUPPORT_SGX) || defined (SUPPORT_VGX) #if defined (PDUMP) #include #include #if defined (SUPPORT_SGX) #include "sgxdefs.h" #endif #include "services_headers.h" #include "pvrversion.h" #include "pvr_debug.h" #include "dbgdrvif.h" #if defined (SUPPORT_SGX) #include "sgxmmu.h" #endif #include "mm.h" #include "pdump_km.h" #include "pdump_int.h" #include #include static IMG_BOOL PDumpWriteString2 (IMG_CHAR * pszString, IMG_UINT32 ui32Flags); static IMG_BOOL PDumpWriteILock (PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32Count, IMG_UINT32 ui32Flags); static IMG_VOID DbgSetFrame (PDBG_STREAM psStream, IMG_UINT32 ui32Frame); static IMG_VOID DbgSetMarker (PDBG_STREAM psStream, IMG_UINT32 ui32Marker); #define PDUMP_DATAMASTER_PIXEL (1) #define PDUMP_DATAMASTER_EDM (3) #define MAX_FILE_SIZE 0x40000000 static atomic_t gsPDumpSuspended = ATOMIC_INIT(0); static PDBGKM_SERVICE_TABLE gpfnDbgDrv = IMG_NULL; IMG_CHAR *pszStreamName[PDUMP_NUM_STREAMS] = { "ParamStream2", "ScriptStream2", "DriverInfoStream"}; typedef struct PDBG_PDUMP_STATE_TAG { PDBG_STREAM psStream[PDUMP_NUM_STREAMS]; IMG_UINT32 ui32ParamFileNum; IMG_CHAR *pszMsg; IMG_CHAR *pszScript; IMG_CHAR *pszFile; } PDBG_PDUMP_STATE; static PDBG_PDUMP_STATE gsDBGPdumpState = {{IMG_NULL}, 0, IMG_NULL, IMG_NULL, IMG_NULL}; #define SZ_MSG_SIZE_MAX PVRSRV_PDUMP_MAX_COMMENT_SIZE-1 #define SZ_SCRIPT_SIZE_MAX PVRSRV_PDUMP_MAX_COMMENT_SIZE-1 #define SZ_FILENAME_SIZE_MAX PVRSRV_PDUMP_MAX_COMMENT_SIZE-1 IMG_VOID DBGDrvGetServiceTable(IMG_VOID **fn_table); static inline IMG_BOOL PDumpSuspended(IMG_VOID) { return (atomic_read(&gsPDumpSuspended) != 0) ? IMG_TRUE : IMG_FALSE; } PVRSRV_ERROR PDumpOSGetScriptString(IMG_HANDLE *phScript, IMG_UINT32 *pui32MaxLen) { *phScript = (IMG_HANDLE)gsDBGPdumpState.pszScript; *pui32MaxLen = SZ_SCRIPT_SIZE_MAX; if ((!*phScript) || PDumpSuspended()) { return PVRSRV_ERROR_PDUMP_NOT_ACTIVE; } return PVRSRV_OK; } PVRSRV_ERROR PDumpOSGetMessageString(IMG_CHAR **ppszMsg, IMG_UINT32 *pui32MaxLen) { *ppszMsg = gsDBGPdumpState.pszMsg; *pui32MaxLen = SZ_MSG_SIZE_MAX; if ((!*ppszMsg) || PDumpSuspended()) { return PVRSRV_ERROR_PDUMP_NOT_ACTIVE; } return PVRSRV_OK; } PVRSRV_ERROR PDumpOSGetFilenameString(IMG_CHAR **ppszFile, IMG_UINT32 *pui32MaxLen) { *ppszFile = gsDBGPdumpState.pszFile; *pui32MaxLen = SZ_FILENAME_SIZE_MAX; if ((!*ppszFile) || PDumpSuspended()) { return PVRSRV_ERROR_PDUMP_NOT_ACTIVE; } return PVRSRV_OK; } IMG_BOOL PDumpOSWriteString2(IMG_HANDLE hScript, IMG_UINT32 ui32Flags) { return PDumpWriteString2(hScript, ui32Flags); } PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, ...) { IMG_CHAR* pszBuf = hBuf; IMG_INT32 n; va_list vaArgs; va_start(vaArgs, pszFormat); n = vsnprintf(pszBuf, ui32ScriptSizeMax, pszFormat, vaArgs); va_end(vaArgs); if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) { PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete.")); return PVRSRV_ERROR_PDUMP_BUF_OVERFLOW; } #if defined(PDUMP_DEBUG_OUTFILES) g_ui32EveryLineCounter++; #endif return PVRSRV_OK; } PVRSRV_ERROR PDumpOSVSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, PDUMP_va_list vaArgs) { IMG_INT32 n; n = vsnprintf(pszComment, ui32ScriptSizeMax, pszFormat, vaArgs); if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) { PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete.")); return PVRSRV_ERROR_PDUMP_BUF_OVERFLOW; } return PVRSRV_OK; } IMG_VOID PDumpOSDebugPrintf(IMG_CHAR* pszFormat, ...) { PVR_UNREFERENCED_PARAMETER(pszFormat); } PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR *pszFormat, ...) { IMG_INT32 n; va_list vaArgs; va_start(vaArgs, pszFormat); n = vsnprintf(pszComment, ui32ScriptSizeMax, pszFormat, vaArgs); va_end(vaArgs); if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) { PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete.")); return PVRSRV_ERROR_PDUMP_BUF_OVERFLOW; } return PVRSRV_OK; } IMG_UINT32 PDumpOSBuflen(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax) { IMG_CHAR* pszBuf = hBuffer; IMG_UINT32 ui32Count = 0; while ((pszBuf[ui32Count]!=0) && (ui32Count= 1) && (pszBuf[ui32Count-1] != '\n') && (ui32Count= 2) && (pszBuf[ui32Count-2] != '\r') && (ui32CountpfnGetStreamOffset(psStream); } IMG_UINT32 PDumpOSGetParamFileNum(IMG_VOID) { return gsDBGPdumpState.ui32ParamFileNum; } IMG_BOOL PDumpOSWriteString(IMG_HANDLE hStream, IMG_UINT8 *psui8Data, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags) { PDBG_STREAM psStream = (PDBG_STREAM)hStream; return PDumpWriteILock(psStream, psui8Data, ui32Size, ui32Flags); } IMG_VOID PDumpOSCheckForSplitting(IMG_HANDLE hStream, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags) { PVR_UNREFERENCED_PARAMETER(hStream); PVR_UNREFERENCED_PARAMETER(ui32Size); PVR_UNREFERENCED_PARAMETER(ui32Flags); } IMG_BOOL PDumpOSJTInitialised(IMG_VOID) { if(gpfnDbgDrv) { return IMG_TRUE; } return IMG_FALSE; } inline IMG_BOOL PDumpOSIsSuspended(IMG_VOID) { return (atomic_read(&gsPDumpSuspended) != 0) ? IMG_TRUE : IMG_FALSE; } IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_UINT8 *pui8LinAddr, IMG_UINT32 ui32PageSize, IMG_DEV_PHYADDR *psDevPAddr) { IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); PVR_UNREFERENCED_PARAMETER(ui32PageSize); PVR_ASSERT (hOSMemHandle != IMG_NULL); sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); PVR_ASSERT((sCpuPAddr.uiAddr & (ui32PageSize - 1)) == 0); *psDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); } IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_PUINT8 pui8LinAddr, IMG_UINT32 ui32DataPageMask, IMG_UINT32 *pui32PageOffset) { if(hOSMemHandle) { IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); *pui32PageOffset = sCpuPAddr.uiAddr & ui32DataPageMask; } else { PVR_UNREFERENCED_PARAMETER(hOSMemHandle); PVR_UNREFERENCED_PARAMETER(ui32Offset); *pui32PageOffset = ((IMG_UINT32)pui8LinAddr & ui32DataPageMask); } } IMG_UINT32 PDumpOSDebugDriverWrite( PDBG_STREAM psStream, PDUMP_DDWMODE eDbgDrvWriteMode, IMG_UINT8 *pui8Data, IMG_UINT32 ui32BCount, IMG_UINT32 ui32Level, IMG_UINT32 ui32DbgDrvFlags) { switch(eDbgDrvWriteMode) { case PDUMP_WRITE_MODE_CONTINUOUS: PVR_UNREFERENCED_PARAMETER(ui32DbgDrvFlags); return gpfnDbgDrv->pfnDBGDrivWrite2(psStream, pui8Data, ui32BCount, ui32Level); case PDUMP_WRITE_MODE_LASTFRAME: return gpfnDbgDrv->pfnWriteLF(psStream, pui8Data, ui32BCount, ui32Level, ui32DbgDrvFlags); case PDUMP_WRITE_MODE_BINCM: PVR_UNREFERENCED_PARAMETER(ui32DbgDrvFlags); return gpfnDbgDrv->pfnWriteBINCM(psStream, pui8Data, ui32BCount, ui32Level); case PDUMP_WRITE_MODE_PERSISTENT: PVR_UNREFERENCED_PARAMETER(ui32DbgDrvFlags); return gpfnDbgDrv->pfnWritePersist(psStream, pui8Data, ui32BCount, ui32Level); default: PVR_UNREFERENCED_PARAMETER(ui32DbgDrvFlags); break; } return 0xFFFFFFFFU; } IMG_VOID PDumpOSReleaseExecution(IMG_VOID) { OSReleaseThreadQuanta(); } IMG_VOID PDumpInit(IMG_VOID) { IMG_UINT32 i; DBGKM_CONNECT_NOTIFIER sConnectNotifier; if (!gpfnDbgDrv) { DBGDrvGetServiceTable((IMG_VOID **)&gpfnDbgDrv); if (gpfnDbgDrv == IMG_NULL) { return; } sConnectNotifier.pfnConnectNotifier = &PDumpConnectionNotify; gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier); if(!gsDBGPdumpState.pszFile) { if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_FILENAME_SIZE_MAX, (IMG_PVOID *)&gsDBGPdumpState.pszFile, 0, "Filename string") != PVRSRV_OK) { goto init_failed; } } if(!gsDBGPdumpState.pszMsg) { if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_MSG_SIZE_MAX, (IMG_PVOID *)&gsDBGPdumpState.pszMsg, 0, "Message string") != PVRSRV_OK) { goto init_failed; } } if(!gsDBGPdumpState.pszScript) { if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_SCRIPT_SIZE_MAX, (IMG_PVOID *)&gsDBGPdumpState.pszScript, 0, "Script string") != PVRSRV_OK) { goto init_failed; } } for(i=0; i < PDUMP_NUM_STREAMS; i++) { gsDBGPdumpState.psStream[i] = gpfnDbgDrv->pfnCreateStream(pszStreamName[i], DEBUG_CAPMODE_FRAMED, DEBUG_OUTMODE_STREAMENABLE, 0, 10); gpfnDbgDrv->pfnSetCaptureMode(gsDBGPdumpState.psStream[i],DEBUG_CAPMODE_FRAMED,0xFFFFFFFF, 0xFFFFFFFF, 1); gpfnDbgDrv->pfnSetFrame(gsDBGPdumpState.psStream[i],0); } PDUMPCOMMENT("Driver Product Name: %s", VS_PRODUCT_NAME); PDUMPCOMMENT("Driver Product Version: %s (%s)", PVRVERSION_STRING, PVRVERSION_FAMILY); PDUMPCOMMENT("Start of Init Phase"); } return; init_failed: if(gsDBGPdumpState.pszFile) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_FILENAME_SIZE_MAX, (IMG_PVOID) gsDBGPdumpState.pszFile, 0); gsDBGPdumpState.pszFile = IMG_NULL; } if(gsDBGPdumpState.pszScript) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_SCRIPT_SIZE_MAX, (IMG_PVOID) gsDBGPdumpState.pszScript, 0); gsDBGPdumpState.pszScript = IMG_NULL; } if(gsDBGPdumpState.pszMsg) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_MSG_SIZE_MAX, (IMG_PVOID) gsDBGPdumpState.pszMsg, 0); gsDBGPdumpState.pszMsg = IMG_NULL; } sConnectNotifier.pfnConnectNotifier = 0; gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier); gpfnDbgDrv = IMG_NULL; } IMG_VOID PDumpDeInit(IMG_VOID) { IMG_UINT32 i; DBGKM_CONNECT_NOTIFIER sConnectNotifier; for(i=0; i < PDUMP_NUM_STREAMS; i++) { gpfnDbgDrv->pfnDestroyStream(gsDBGPdumpState.psStream[i]); } if(gsDBGPdumpState.pszFile) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_FILENAME_SIZE_MAX, (IMG_PVOID) gsDBGPdumpState.pszFile, 0); gsDBGPdumpState.pszFile = IMG_NULL; } if(gsDBGPdumpState.pszScript) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_SCRIPT_SIZE_MAX, (IMG_PVOID) gsDBGPdumpState.pszScript, 0); gsDBGPdumpState.pszScript = IMG_NULL; } if(gsDBGPdumpState.pszMsg) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_MSG_SIZE_MAX, (IMG_PVOID) gsDBGPdumpState.pszMsg, 0); gsDBGPdumpState.pszMsg = IMG_NULL; } sConnectNotifier.pfnConnectNotifier = 0; gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier); gpfnDbgDrv = IMG_NULL; } PVRSRV_ERROR PDumpStartInitPhaseKM(IMG_VOID) { IMG_UINT32 i; if (gpfnDbgDrv) { PDUMPCOMMENT("Start Init Phase"); for(i=0; i < PDUMP_NUM_STREAMS; i++) { gpfnDbgDrv->pfnStartInitPhase(gsDBGPdumpState.psStream[i]); } } return PVRSRV_OK; } PVRSRV_ERROR PDumpStopInitPhaseKM(IMG_VOID) { IMG_UINT32 i; if (gpfnDbgDrv) { PDUMPCOMMENT("Stop Init Phase"); for(i=0; i < PDUMP_NUM_STREAMS; i++) { gpfnDbgDrv->pfnStopInitPhase(gsDBGPdumpState.psStream[i]); } } return PVRSRV_OK; } IMG_BOOL PDumpIsLastCaptureFrameKM(IMG_VOID) { return gpfnDbgDrv->pfnIsLastCaptureFrame(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2]); } IMG_BOOL PDumpOSIsCaptureFrameKM(IMG_VOID) { if (PDumpSuspended()) { return IMG_FALSE; } return gpfnDbgDrv->pfnIsCaptureFrame(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2], IMG_FALSE); } PVRSRV_ERROR PDumpOSSetFrameKM(IMG_UINT32 ui32Frame) { IMG_UINT32 ui32Stream; for (ui32Stream = 0; ui32Stream < PDUMP_NUM_STREAMS; ui32Stream++) { if (gsDBGPdumpState.psStream[ui32Stream]) { DbgSetFrame(gsDBGPdumpState.psStream[ui32Stream], ui32Frame); } } return PVRSRV_OK; } static IMG_BOOL PDumpWriteString2(IMG_CHAR * pszString, IMG_UINT32 ui32Flags) { return PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2], (IMG_UINT8 *) pszString, strlen(pszString), ui32Flags); } static IMG_BOOL PDumpWriteILock(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32Count, IMG_UINT32 ui32Flags) { IMG_UINT32 ui32Written = 0; if ((psStream == IMG_NULL) || PDumpSuspended() || ((ui32Flags & PDUMP_FLAGS_NEVER) != 0)) { PVR_DPF((PVR_DBG_MESSAGE, "PDumpWriteILock: Failed to write 0x%x bytes to stream 0x%x", ui32Count, (IMG_UINT32)psStream)); return IMG_TRUE; } if (psStream == gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2]) { IMG_UINT32 ui32ParamOutPos = gpfnDbgDrv->pfnGetStreamOffset(gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2]); if (ui32ParamOutPos + ui32Count > MAX_FILE_SIZE) { if ((gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2] && PDumpWriteString2("\r\n-- Splitting pdump output file\r\n\r\n", ui32Flags))) { DbgSetMarker(gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], ui32ParamOutPos); gsDBGPdumpState.ui32ParamFileNum++; } } } ui32Written = DbgWrite(psStream, pui8Data, ui32Count, ui32Flags); if (ui32Written == 0xFFFFFFFF) { return IMG_FALSE; } return IMG_TRUE; } static IMG_VOID DbgSetFrame(PDBG_STREAM psStream, IMG_UINT32 ui32Frame) { gpfnDbgDrv->pfnSetFrame(psStream, ui32Frame); } static IMG_VOID DbgSetMarker(PDBG_STREAM psStream, IMG_UINT32 ui32Marker) { gpfnDbgDrv->pfnSetMarker(psStream, ui32Marker); } IMG_VOID PDumpSuspendKM(IMG_VOID) { atomic_inc(&gsPDumpSuspended); } IMG_VOID PDumpResumeKM(IMG_VOID) { atomic_dec(&gsPDumpSuspended); } #endif #endif