PVRSRV_ERROR PVRSRVGetMiscInfoKM_Device_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va)
{
	IMG_UINT32 *pui32StrLen;
	IMG_INT32 *pi32Count;
	IMG_CHAR **ppszStr;
	
	pui32StrLen = va_arg(va, IMG_UINT32*);
	pi32Count = va_arg(va, IMG_INT32*);
	ppszStr = va_arg(va, IMG_CHAR**);	

	CHECK_SPACE(*pui32StrLen);
	*pi32Count = OSSNPrintf(*ppszStr, 100, "\n\nDevice Type %d:\n", psDeviceNode->sDevId.eDeviceType);
	UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen);

	
	if(psDeviceNode->sDevMemoryInfo.pBMKernelContext)
	{
		CHECK_SPACE(*pui32StrLen);
		*pi32Count = OSSNPrintf(*ppszStr, 100, "\nKernel Context:\n");
		UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen);
		
		
		List_BM_HEAP_ForEach_va(psDeviceNode->sDevMemoryInfo.pBMKernelContext->psBMHeap,
								PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb,
								ppszStr,
								pui32StrLen);
	}

	
	return List_BM_CONTEXT_PVRSRV_ERROR_Any_va(psDeviceNode->sDevMemoryInfo.pBMContext,
												PVRSRVGetMiscInfoKM_BMContext_AnyVaCb,
							 					pui32StrLen,
												pi32Count,
												ppszStr);
}
static PVRSRV_ERROR PVRSRVGetMiscInfoKM_BMContext_AnyVaCb(BM_CONTEXT *psBMContext, va_list va)
{

	IMG_UINT32 *pui32StrLen;
	IMG_INT32 *pi32Count;
	IMG_CHAR **ppszStr;
	IMG_UINT32 ui32Mode;

	pui32StrLen = va_arg(va, IMG_UINT32*);
	pi32Count = va_arg(va, IMG_INT32*);
	ppszStr = va_arg(va, IMG_CHAR**);
	ui32Mode = va_arg(va, IMG_UINT32);

	CHECK_SPACE(*pui32StrLen);
	*pi32Count = OSSNPrintf(*ppszStr, 100, "\nApplication Context (hDevMemContext) %p:\n",
							(IMG_HANDLE)psBMContext);
	UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen);

	List_BM_HEAP_ForEach_va(psBMContext->psBMHeap,
							&PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb,
							ppszStr,
							pui32StrLen,
							ui32Mode);
	return PVRSRV_OK;
}
Exemple #3
0
/* Locate  a record in a VPD blob
 *
 * Note: This works with VPD LIDs. It will scan until it finds
 * the first 0x84, so it will skip all those 0's that the VPD
 * LIDs seem to contain
 */
const void *vpd_find_record(const void *vpd, size_t vpd_size,
			    const char *record, size_t *sz)
{
	const uint8_t *p = vpd, *end = vpd + vpd_size;
	bool first_start = true;
	size_t rec_sz;
	uint8_t namesz = 0;
	const char *rec_name;

	if (!vpd)
		return NULL;

	while (CHECK_SPACE(p, 4, end)) {
		/* Get header byte */
		if (*(p++) != 0x84) {
			/* Skip initial crap in VPD LIDs */
			if (first_start)
				continue;
			break;
		}
		first_start = false;
		rec_sz = *(p++);
		rec_sz |= *(p++) << 8;
		if (!CHECK_SPACE(p, rec_sz, end)) {
			prerror("VPD: Malformed or truncated VPD,"
				" record size doesn't fit\n");
			return NULL;
		}

		/* Find record name */
		rec_name = vpd_find_keyword(p, rec_sz, "RT", &namesz);
		if (rec_name && strncmp(record, rec_name, namesz) == 0) {
			*sz = rec_sz;
			return p;
		}

		p += rec_sz;
		if (*(p++) != 0x78) {
			prerror("VPD: Malformed or truncated VPD,"
				" missing final 0x78 in record %.4s\n",
				rec_name ? rec_name : "????");
			return NULL;
		}
	}
	return NULL;
}
Exemple #4
0
/* Low level keyword search in a record. Can be used when we
 * need to find the next keyword of a given type, for example
 * when having multiple MF/SM keyword pairs
 */
const void *vpd_find_keyword(const void *rec, size_t rec_sz,
                             const char *kw, uint8_t *kw_size)
{
    const uint8_t *p = rec, *end = rec + rec_sz;

    while (CHECK_SPACE(p, 3, end)) {
        uint8_t k1 = *(p++);
        uint8_t k2 = *(p++);
        uint8_t sz = *(p++);

        if (k1 == kw[0] && k2 == kw[1]) {
            if (kw_size)
                *kw_size = sz;
            return p;
        }
        p += sz;
    }
    return NULL;
}
Exemple #5
0
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo)
#endif
{
	SYS_DATA *psSysData;

	if(!psMiscInfo)
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	psMiscInfo->ui32StatePresent = 0;

	
	if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT
										|PVRSRV_MISC_INFO_CLOCKGATE_PRESENT
										|PVRSRV_MISC_INFO_MEMSTATS_PRESENT
										|PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT
										|PVRSRV_MISC_INFO_DDKVERSION_PRESENT
										|PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT
										|PVRSRV_MISC_INFO_RESET_PRESENT
										|PVRSRV_MISC_INFO_FREEMEM_PRESENT
										|PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT))
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	SysAcquireData(&psSysData);

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
		(psSysData->pvSOCTimerRegisterKM != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
		psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle;
	}
	else
	{
		psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
		(psSysData->pvSOCClockGateRegsBase != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
		psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase;
		psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
		(psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		RA_ARENA			**ppArena;
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;

		
		ppArena = &psSysData->apsLocalDevMemArena[0];
		while(*ppArena)
		{
			CHECK_SPACE(ui32StrLen);
			i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

			RA_GetStats(*ppArena,
							&pszStr,
							&ui32StrLen);
			
			ppArena++;
		}

		
		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_MEMSTATS_PRESENT);

		
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0)
		&& psMiscInfo->pszMemoryStr)
	{
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;
		
		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;
  
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FREEMEM_PRESENT;

		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_FREEMEM_PRESENT);
		
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
		(psSysData->psGlobalEventObject != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
		psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject;
	}

	

	if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL)
		&& ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL)
		&& (psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		IMG_CHAR	*pszStr;
		IMG_UINT32	ui32StrLen;
		IMG_UINT32 	ui32LenStrPerNum = 12; 
		IMG_INT32	i32Count;
		IMG_INT i;
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;

		
		psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ;
		psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN;
		psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BUILD_HI;
		psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD_LO;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		for (i=0; i<4; i++)
		{
			if (ui32StrLen < ui32LenStrPerNum)
			{
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%u", psMiscInfo->aui32DDKVersion[i]);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			if (i != 3)
			{
				i32Count = OSSNPrintf(pszStr, 2, ".");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			}
		}
	}

	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT) != 0UL)
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT;

		if(psMiscInfo->sCacheOpCtl.bDeferOp)
		{
			
			psSysData->ePendingCacheOpType = psMiscInfo->sCacheOpCtl.eCacheOpType;
		}
		else
		{
#if defined (SUPPORT_SID_INTERFACE)
			PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo = psMiscInfo->sCacheOpCtl.psKernelMemInfo;

			if(!psMiscInfo->sCacheOpCtl.psKernelMemInfo)
#else
			PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
			PVRSRV_PER_PROCESS_DATA *psPerProc;

			if(!psMiscInfo->sCacheOpCtl.u.psKernelMemInfo)
#endif
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Ignoring non-deferred cache op with no meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			if(psSysData->ePendingCacheOpType != PVRSRV_MISC_INFO_CPUCACHEOP_NONE)
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Deferred cache op is pending. It is unlikely you want "
						 "to combine deferred cache ops with immediate ones"));
			}

#if defined (SUPPORT_SID_INTERFACE)
			PVR_DBG_BREAK
#else
			
			psPerProc = PVRSRVFindPerProcessData();

			if(PVRSRVLookupHandle(psPerProc->psHandleBase,
								  (IMG_PVOID *)&psKernelMemInfo,
								  psMiscInfo->sCacheOpCtl.u.psKernelMemInfo,
								  PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
			{
				PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
						 "Can't find kernel meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}
#endif

			if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH)
			{
				if(!OSFlushCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
										   psMiscInfo->sCacheOpCtl.pvBaseVAddr,
										   psMiscInfo->sCacheOpCtl.ui32Length))
				{
					return PVRSRV_ERROR_CACHEOP_FAILED;
				}
			}
			else if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN)
			{
				/*if(psMiscInfo->sCacheOpCtl.bStridedCacheOp == IMG_TRUE)
				{
					IMG_BYTE *pbRowStart, *pbRowEnd, *pbRowThresh;
					IMG_UINT32 ui32Stride;
					pbRowStart  = psMiscInfo->sCacheOpCtl.pbRowStart;
					pbRowEnd    = psMiscInfo->sCacheOpCtl.pbRowEnd;
					pbRowThresh = psMiscInfo->sCacheOpCtl.pbRowThresh;
					ui32Stride  = psMiscInfo->sCacheOpCtl.ui32Stride;
					do
					{
						if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
										(IMG_VOID *)pbRowStart,
										(IMG_UINT32)(pbRowEnd - pbRowStart)))
						{
							return PVRSRV_ERROR_CACHEOP_FAILED;
						}
						pbRowStart += ui32Stride;
						pbRowEnd   += ui32Stride;
					}
					while(pbRowEnd <= pbRowThresh);
				}
				else
				{
					if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
									psMiscInfo->sCacheOpCtl.pvBaseVAddr,
									psMiscInfo->sCacheOpCtl.ui32Length))
					{
						return PVRSRV_ERROR_CACHEOP_FAILED;
					}
				}*/
				if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
								psMiscInfo->sCacheOpCtl.pvBaseVAddr,
								psMiscInfo->sCacheOpCtl.ui32Length))
					return PVRSRV_ERROR_CACHEOP_FAILED;
			}
		}
	}

	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT) != 0UL)
	{
#if !defined (SUPPORT_SID_INTERFACE)
		PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
		PVRSRV_PER_PROCESS_DATA *psPerProc;
#endif

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT;

#if defined (SUPPORT_SID_INTERFACE)
		PVR_DBG_BREAK
#else
		
		psPerProc = PVRSRVFindPerProcessData();

		if(PVRSRVLookupHandle(psPerProc->psHandleBase,
							  (IMG_PVOID *)&psKernelMemInfo,
							  psMiscInfo->sGetRefCountCtl.u.psKernelMemInfo,
							  PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
		{
			PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
									"Can't find kernel meminfo"));
			return PVRSRV_ERROR_INVALID_PARAMS;
		}

		psMiscInfo->sGetRefCountCtl.ui32RefCount = psKernelMemInfo->ui32RefCount;
#endif
	}

#if defined(PVRSRV_RESET_ON_HWTIMEOUT)
	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL)
	{
		PVR_LOG(("User requested OS reset"));
		OSPanic();
	}
#endif 

	return PVRSRV_OK;
}
Exemple #6
0
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo)
{
	SYS_DATA *psSysData;

	if(!psMiscInfo)
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	psMiscInfo->ui32StatePresent = 0;

	
	if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT
										|PVRSRV_MISC_INFO_CLOCKGATE_PRESENT
										|PVRSRV_MISC_INFO_MEMSTATS_PRESENT
										|PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT
										|PVRSRV_MISC_INFO_DDKVERSION_PRESENT
										|PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT
										|PVRSRV_MISC_INFO_RESET_PRESENT
										|PVRSRV_MISC_INFO_FREEMEM_PRESENT))
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	SysAcquireData(&psSysData);

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
		(psSysData->pvSOCTimerRegisterKM != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
		psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle;
	}
	else
	{
		psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
		(psSysData->pvSOCClockGateRegsBase != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
		psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase;
		psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
		(psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		RA_ARENA			**ppArena;
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;

		
		ppArena = &psSysData->apsLocalDevMemArena[0];
		while(*ppArena)
		{
			CHECK_SPACE(ui32StrLen);
			i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

			RA_GetStats(*ppArena,
							&pszStr,
							&ui32StrLen);
			
			ppArena++;
		}

		
		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_MEMSTATS_PRESENT);

		
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	
	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT)
		&& psMiscInfo->pszMemoryStr)
	{
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;
		
		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;
  
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FREEMEM_PRESENT;

		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_FREEMEM_PRESENT);
		
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
		(psSysData->psGlobalEventObject != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
		psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject;
	}

	

	if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL)
		&& ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL)
		&& (psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		IMG_CHAR	*pszStr;
		IMG_UINT32	ui32StrLen;
		IMG_UINT32 	ui32LenStrPerNum = 12; 
		IMG_INT32	i32Count;
		PVRSRV_SGXDEV_INFO 		*sgx_dev_info;
		PVRSRV_SGX_MISCINFO_INFO	*sgx_misc_info;
		PVRSRV_SGX_MISCINFO_FEATURES	*sgx_features;
		unsigned long			fw_ver;
		IMG_INT i;
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;

		/*
		 * Since the kernel driver has already made sure that the
		 * firmware version is supported by the kernel driver in
		 * SGXDevInitCompatCheck, it's redundant for the user space
		 * part to perform the same check. In order to support older
		 * user space libraries where this check hasn't yet been removed,
		 * simply report the version of the downloaded firmware which
		 * will result in an exact match in user space.
		 */
		sgx_dev_info = pvr_get_sgx_dev_info();
		if (!sgx_dev_info || !sgx_dev_info->psKernelSGXMiscMemInfo ||
		    !sgx_dev_info->psKernelSGXMiscMemInfo->pvLinAddrKM)
			return PVRSRV_ERROR_INVALID_DEVICE;

		sgx_misc_info = sgx_dev_info->psKernelSGXMiscMemInfo->pvLinAddrKM;
		sgx_features = &sgx_misc_info->sSGXFeatures;
		fw_ver = sgx_features->ui32DDKVersion;

		psMiscInfo->aui32DDKVersion[0] = PVR_FW_VER_MAJOR(fw_ver);
		psMiscInfo->aui32DDKVersion[1] = PVR_FW_VER_MINOR(fw_ver);
		psMiscInfo->aui32DDKVersion[2] = PVR_FW_VER_BRANCH(fw_ver);
		psMiscInfo->aui32DDKVersion[3] = sgx_features->ui32DDKBuild;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		for (i=0; i<4; i++)
		{
			if (ui32StrLen < ui32LenStrPerNum)
			{
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%u", psMiscInfo->aui32DDKVersion[i]);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			if (i != 3)
			{
				i32Count = OSSNPrintf(pszStr, 2, ".");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			}
		}
	}

	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT) != 0UL)
	{
		psMiscInfo->ui32StatePresent |=
			PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT;
		if(psMiscInfo->sCacheOpCtl.bDeferOp)
		{
			
			psSysData->ePendingCacheOpType = psMiscInfo->sCacheOpCtl.eCacheOpType;
		}
		else
		{
			PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
			PVRSRV_PER_PROCESS_DATA *psPerProc;

			if(!psMiscInfo->sCacheOpCtl.u.psKernelMemInfo)
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Ignoring non-deferred cache op with no meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			if(psSysData->ePendingCacheOpType != PVRSRV_MISC_INFO_CPUCACHEOP_NONE)
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Deferred cache op is pending. It is unlikely you want "
						 "to combine deferred cache ops with immediate ones"));
			}

			
			psPerProc = PVRSRVFindPerProcessData();

			if(PVRSRVLookupHandle(psPerProc->psHandleBase,
								  (IMG_PVOID *)&psKernelMemInfo,
								  psMiscInfo->sCacheOpCtl.u.psKernelMemInfo,
								  PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
			{
				PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
						 "Can't find kernel meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH)
			{
				if(!OSFlushCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
										   psMiscInfo->sCacheOpCtl.pvBaseVAddr,
										   psMiscInfo->sCacheOpCtl.ui32Length))
				{
					return PVRSRV_ERROR_CACHEOP_FAILED;
				}
			}
			else if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN)
			{
				if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
										   psMiscInfo->sCacheOpCtl.pvBaseVAddr,
										   psMiscInfo->sCacheOpCtl.ui32Length))
				{
					return PVRSRV_ERROR_CACHEOP_FAILED;
				}
			}
		}
	}

#if defined(PVRSRV_RESET_ON_HWTIMEOUT)
	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL)
	{
		PVR_LOG(("User requested OS reset"));
		OSPanic();
	}
#endif 

	return PVRSRV_OK;
}
/**
  The event occurs when an updating statement is done.
*/
Query_event::Query_event(const char* buf, unsigned int event_len,
                         const Format_description_event *description_event,
                         Log_event_type event_type)
: Binary_log_event(&buf, description_event->binlog_version,
                   description_event->server_version),
  query(0), db(0), catalog(0), time_zone_str(0),
  user(0), user_len(0), host(0), host_len(0),
  db_len(0), status_vars_len(0), q_len(0),
  flags2_inited(0), sql_mode_inited(0), charset_inited(0),
  auto_increment_increment(1), auto_increment_offset(1),
  time_zone_len(0), catalog_len(0), lc_time_names_number(0),
  charset_database_number(0), table_map_for_update(0), master_data_written(0),
  mts_accessed_dbs(OVER_MAX_DBS_IN_EVENT_MTS), last_committed(SEQ_UNINIT),
  sequence_number(SEQ_UNINIT)
{
  //buf is advanced in Binary_log_event constructor to point to
  //beginning of post-header
  uint32_t tmp;
  uint8_t common_header_len, post_header_len;
  Log_event_header::Byte *start;
  const Log_event_header::Byte *end;

  query_data_written= 0;

  common_header_len= description_event->common_header_len;
  post_header_len= description_event->post_header_len[event_type - 1];

  /*
    We test if the event's length is sensible, and if so we compute data_len.
    We cannot rely on QUERY_HEADER_LEN here as it would not be format-tolerant.
    We use QUERY_HEADER_MINIMAL_LEN which is the same for 3.23, 4.0 & 5.0.
  */
  if (event_len < (unsigned int)(common_header_len + post_header_len))
    return;
  data_len= event_len - (common_header_len + post_header_len);

  memcpy(&thread_id, buf + Q_THREAD_ID_OFFSET, sizeof(thread_id));
  thread_id= le32toh(thread_id);
  memcpy(&query_exec_time, buf + Q_EXEC_TIME_OFFSET, sizeof(query_exec_time));
  query_exec_time= le32toh(query_exec_time);

  db_len= (unsigned int)buf[Q_DB_LEN_OFFSET];
   // TODO: add a check of all *_len vars
  memcpy(&error_code, buf + Q_ERR_CODE_OFFSET, sizeof(error_code));
  error_code= le16toh(error_code);

  /*
    5.0 format starts here.
    Depending on the format, we may or not have affected/warnings etc
    The remnent post-header to be parsed has length:
  */
  tmp= post_header_len - QUERY_HEADER_MINIMAL_LEN;
  if (tmp)
  {
    memcpy(&status_vars_len, buf + Q_STATUS_VARS_LEN_OFFSET,
           sizeof(status_vars_len));
    status_vars_len= le16toh(status_vars_len);
    /*
      Check if status variable length is corrupt and will lead to very
      wrong data. We could be even more strict and require data_len to
      be even bigger, but this will suffice to catch most corruption
      errors that can lead to a crash.
    */
    if (status_vars_len >
        std::min<unsigned long>(data_len, MAX_SIZE_LOG_EVENT_STATUS))
    {
      query= 0;
      return;
    }
    data_len-= status_vars_len;
    tmp-= 2;
  }
  else
  {
    /*
      server version < 5.0 / binlog_version < 4 master's event is
      relay-logged with storing the original size of the event in
      Q_MASTER_DATA_WRITTEN_CODE status variable.
      The size is to be restored at reading Q_MASTER_DATA_WRITTEN_CODE-marked
      event from the relay log.
    */
    BAPI_ASSERT(description_event->binlog_version < 4);
    master_data_written= header()->data_written;
  }
  /*
    We have parsed everything we know in the post header for QUERY_EVENT,
    the rest of post header is either comes from older version MySQL or
    dedicated to derived events (e.g. Execute_load_query...)
  */

  /* variable-part: the status vars; only in MySQL 5.0  */
  start= (Log_event_header::Byte*) (buf + post_header_len);
  end= (const Log_event_header::Byte*) (start + status_vars_len);
  for (const Log_event_header::Byte* pos= start; pos < end;)
  {
    switch (*pos++) {
    case Q_FLAGS2_CODE:
      CHECK_SPACE(pos, end, 4);
      flags2_inited= 1;
      memcpy(&flags2, pos, sizeof(flags2));
      flags2= le32toh(flags2);
      pos+= 4;
      break;
    case Q_SQL_MODE_CODE:
    {
      CHECK_SPACE(pos, end, 8);
      sql_mode_inited= 1;
      memcpy(&sql_mode, pos, sizeof(sql_mode));
      sql_mode= le64toh(sql_mode);
      pos+= 8;
      break;
    }
    case Q_CATALOG_NZ_CODE:
      if ((catalog_len= *pos))
        catalog= (const char*) (pos + 1);
      CHECK_SPACE(pos, end, catalog_len + 1);
      pos+= catalog_len + 1;
      break;
    case Q_AUTO_INCREMENT:
      CHECK_SPACE(pos, end, 4);
      memcpy(&auto_increment_increment, pos, sizeof(auto_increment_increment));
      auto_increment_increment= le16toh(auto_increment_increment);
      memcpy(&auto_increment_offset, pos + 2, sizeof(auto_increment_offset));
      auto_increment_offset= le16toh(auto_increment_offset);
      pos+= 4;
      break;
    case Q_CHARSET_CODE:
    {
      CHECK_SPACE(pos, end, 6);
      charset_inited= 1;
      memcpy(charset, pos, 6);
      pos+= 6;
      break;
    }
    case Q_TIME_ZONE_CODE:
    {
      if ((time_zone_len= *pos))
        time_zone_str= (const char*)(pos + 1);
      pos+= time_zone_len + 1;
      break;
    }
    case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */
      CHECK_SPACE(pos, end, 1);
      if ((catalog_len= *pos))
        catalog= (const char*) (pos+1);
      CHECK_SPACE(pos, end, catalog_len + 2);
      pos+= catalog_len + 2; // leap over end 0
      break;
    case Q_LC_TIME_NAMES_CODE:
      CHECK_SPACE(pos, end, 2);
      memcpy(&lc_time_names_number, pos, sizeof(lc_time_names_number));
      lc_time_names_number= le16toh(lc_time_names_number);
      pos+= 2;
      break;
    case Q_CHARSET_DATABASE_CODE:
      CHECK_SPACE(pos, end, 2);
      memcpy(&charset_database_number, pos, sizeof(lc_time_names_number));
      charset_database_number= le16toh(charset_database_number);
      pos+= 2;
      break;
    case Q_TABLE_MAP_FOR_UPDATE_CODE:
      CHECK_SPACE(pos, end, 8);
      memcpy(&table_map_for_update, pos, sizeof(table_map_for_update));
      table_map_for_update= le64toh(table_map_for_update);
      pos+= 8;
      break;
    case Q_MASTER_DATA_WRITTEN_CODE:
      CHECK_SPACE(pos, end, 4);
      memcpy(&master_data_written, pos, sizeof(master_data_written));
      master_data_written= le32toh(static_cast<uint32_t>(master_data_written));
      header()->data_written= master_data_written;
      pos+= 4;
      break;
    case Q_MICROSECONDS:
    {
      CHECK_SPACE(pos, end, 3);
      uint32_t temp_usec= 0;
      memcpy(&temp_usec, pos, 3);
      header()->when.tv_usec= le32toh(temp_usec);
      pos+= 3;
break;
    }
    case Q_INVOKER:
    {
      CHECK_SPACE(pos, end, 1);
      user_len= *pos++;
      CHECK_SPACE(pos, end, user_len);
      user= (const char*)pos;
      pos+= user_len;

      CHECK_SPACE(pos, end, 1);
      host_len= *pos++;
      CHECK_SPACE(pos, end, host_len);
      host= (const char*)pos;
      pos+= host_len;
      break;
    }
    case Q_UPDATED_DB_NAMES:
    {
      unsigned char i= 0;
#ifndef DBUG_OFF
      bool is_corruption_injected= false;
#endif

      CHECK_SPACE(pos, end, 1);
      mts_accessed_dbs= *pos++;
      /*
         Notice, the following check is positive also in case of
         the master's MAX_DBS_IN_EVENT_MTS > the slave's one and the event
         contains e.g the master's MAX_DBS_IN_EVENT_MTS db:s.
      */
      if (mts_accessed_dbs > MAX_DBS_IN_EVENT_MTS)
      {
        mts_accessed_dbs= OVER_MAX_DBS_IN_EVENT_MTS;
        break;
      }

      BAPI_ASSERT(mts_accessed_dbs != 0);

      for (i= 0; i < mts_accessed_dbs && pos < start + status_vars_len; i++)
      {
        #ifndef DBUG_OFF
        /*
          This is specific to mysql test run on the server
          for the keyword "query_log_event_mts_corrupt_db_names"
        */
        if (binary_log_debug::debug_query_mts_corrupt_db_names)
        {
          if (mts_accessed_dbs == 2)
          {
            BAPI_ASSERT(pos[sizeof("d?") - 1] == 0);
            ((char*) pos)[sizeof("d?") - 1]= 'a';
            is_corruption_injected= true;
          }
        }
        #endif
        strncpy(mts_accessed_db_names[i], (char*) pos,
                std::min<unsigned long>(NAME_LEN, start + status_vars_len - pos));
        mts_accessed_db_names[i][NAME_LEN - 1]= 0;
        pos+= 1 + strlen((const char*) pos);
      }
      if (i != mts_accessed_dbs
#ifndef DBUG_OFF
          || is_corruption_injected
#endif
          )
        return;
      break;
    }
    case Q_COMMIT_TS2:
      CHECK_SPACE(pos, end, COMMIT_SEQ_LEN);
      last_committed= 0;
      memcpy(&last_committed, pos, 8);
      last_committed= le64toh(last_committed);
      sequence_number= 0;
      memcpy(&sequence_number, pos + 8, 8);
      sequence_number= le64toh(sequence_number);
      pos+= COMMIT_SEQ_LEN;
      break;

    default:
      /* That's why you must write status vars in growing order of code */
      pos= (const unsigned char*) end;         // Break loop
    }
  }
  if (catalog_len)                             // If catalog is given
    query_data_written+= catalog_len + 1;
  if (time_zone_len)
    query_data_written+= time_zone_len + 1;
  if (user_len > 0)
    query_data_written+= user_len + 1;
  if (host_len > 0)
    query_data_written+= host_len + 1;

  /*
    if time_zone_len or catalog_len are 0, then time_zone and catalog
    are uninitialized at this point.  shouldn't they point to the
    zero-length null-terminated strings we allocated space for in the
    my_alloc call above? /sven
  */

  /* A 2nd variable part; this is common to all versions */
  query_data_written+= data_len + 1;
  db= (const char* )end;
  q_len= data_len - db_len -1;
  start[status_vars_len + data_len]= '\0';
  query= (const char *)(end + db_len + 1);
  return;
}
Exemple #8
0
Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state) {

	if (!_code_ptr) {

		return Variant();
	}

	r_err.error = Variant::CallError::CALL_OK;

	Variant self;
	Variant retvalue;
	Variant *stack = NULL;
	Variant **call_args;
	int defarg = 0;

#ifdef DEBUG_ENABLED

//GDScriptLanguage::get_singleton()->calls++;

#endif

	uint32_t alloca_size = 0;
	GDScript *_class;
	int ip = 0;
	int line = _initial_line;

	if (p_state) {
		//use existing (supplied) state (yielded)
		stack = (Variant *)p_state->stack.ptr();
		call_args = (Variant **)stack + sizeof(Variant) * p_state->stack_size;
		line = p_state->line;
		ip = p_state->ip;
		alloca_size = p_state->stack.size();
		_class = p_state->_class;
		p_instance = p_state->instance;
		defarg = p_state->defarg;
		self = p_state->self;
		//stack[p_state->result_pos]=p_state->result; //assign stack with result

	} else {

		if (p_argcount != _argument_count) {

			if (p_argcount > _argument_count) {

				r_err.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
				r_err.argument = _argument_count;

				return Variant();
			} else if (p_argcount < _argument_count - _default_arg_count) {

				r_err.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
				r_err.argument = _argument_count - _default_arg_count;
				return Variant();
			} else {

				defarg = _argument_count - p_argcount;
			}
		}

		alloca_size = sizeof(Variant *) * _call_size + sizeof(Variant) * _stack_size;

		if (alloca_size) {

			uint8_t *aptr = (uint8_t *)alloca(alloca_size);

			if (_stack_size) {

				stack = (Variant *)aptr;
				for (int i = 0; i < p_argcount; i++)
					memnew_placement(&stack[i], Variant(*p_args[i]));
				for (int i = p_argcount; i < _stack_size; i++)
					memnew_placement(&stack[i], Variant);
			} else {
				stack = NULL;
			}

			if (_call_size) {

				call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
			} else {

				call_args = NULL;
			}

		} else {
			stack = NULL;
			call_args = NULL;
		}

		if (p_instance) {
			if (p_instance->base_ref && static_cast<Reference *>(p_instance->owner)->is_referenced()) {

				self = REF(static_cast<Reference *>(p_instance->owner));
			} else {
				self = p_instance->owner;
			}
			_class = p_instance->script.ptr();
		} else {
			_class = _script;
		}
	}

	String err_text;

#ifdef DEBUG_ENABLED

	if (ScriptDebugger::get_singleton())
		GDScriptLanguage::get_singleton()->enter_function(p_instance, this, stack, &ip, &line);

#define CHECK_SPACE(m_space) \
	ERR_BREAK((ip + m_space) > _code_size)

#define GET_VARIANT_PTR(m_v, m_code_ofs)                                                       \
	Variant *m_v;                                                                              \
	m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, _class, self, stack, err_text); \
	if (!m_v)                                                                                  \
		break;

#else
#define CHECK_SPACE(m_space)
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
	Variant *m_v;                        \
	m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, _class, self, stack, err_text);

#endif

#ifdef DEBUG_ENABLED

	uint64_t function_start_time;
	uint64_t function_call_time;

	if (GDScriptLanguage::get_singleton()->profiling) {
		function_start_time = OS::get_singleton()->get_ticks_usec();
		function_call_time = 0;
		profile.call_count++;
		profile.frame_call_count++;
	}
#endif
	bool exit_ok = false;

	while (ip < _code_size) {

		int last_opcode = _code_ptr[ip];
		switch (_code_ptr[ip]) {

			case OPCODE_OPERATOR: {

				CHECK_SPACE(5);

				bool valid;
				Variant::Operator op = (Variant::Operator)_code_ptr[ip + 1];
				ERR_BREAK(op >= Variant::OP_MAX);

				GET_VARIANT_PTR(a, 2);
				GET_VARIANT_PTR(b, 3);
				GET_VARIANT_PTR(dst, 4);

#ifdef DEBUG_ENABLED
				Variant ret;
				Variant::evaluate(op, *a, *b, ret, valid);
#else
				Variant::evaluate(op, *a, *b, *dst, valid);
#endif

				if (!valid) {
#ifdef DEBUG_ENABLED

					if (ret.get_type() == Variant::STRING) {
						//return a string when invalid with the error
						err_text = ret;
						err_text += " in operator '" + Variant::get_operator_name(op) + "'.";
					} else {
						err_text = "Invalid operands '" + Variant::get_type_name(a->get_type()) + "' and '" + Variant::get_type_name(b->get_type()) + "' in operator '" + Variant::get_operator_name(op) + "'.";
					}
#endif
					break;
				}
#ifdef DEBUG_ENABLED
				*dst = ret;
#endif

				ip += 5;
				continue;
			}
			case OPCODE_EXTENDS_TEST: {

				CHECK_SPACE(4);

				GET_VARIANT_PTR(a, 1);
				GET_VARIANT_PTR(b, 2);
				GET_VARIANT_PTR(dst, 3);

#ifdef DEBUG_ENABLED

				if (a->get_type() != Variant::OBJECT || a->operator Object *() == NULL) {

					err_text = "Left operand of 'extends' is not an instance of anything.";
					break;
				}
				if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) {

					err_text = "Right operand of 'extends' is not a class.";
					break;
				}
#endif

				Object *obj_A = *a;
				Object *obj_B = *b;

				GDScript *scr_B = obj_B->cast_to<GDScript>();

				bool extends_ok = false;

				if (scr_B) {
					//if B is a script, the only valid condition is that A has an instance which inherits from the script
					//in other situation, this shoul return false.

					if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {

						GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
						//bool found=false;
						while (cmp) {

							if (cmp == scr_B) {
								//inherits from script, all ok
								extends_ok = true;
								break;
							}

							cmp = cmp->_base;
						}
					}

				} else {

					GDNativeClass *nc = obj_B->cast_to<GDNativeClass>();

					if (!nc) {

						err_text = "Right operand of 'extends' is not a class (type: '" + obj_B->get_class() + "').";
						break;
					}

					extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
				}

				*dst = extends_ok;
				ip += 4;
				continue;
			}
			case OPCODE_SET: {

				CHECK_SPACE(3);

				GET_VARIANT_PTR(dst, 1);
				GET_VARIANT_PTR(index, 2);
				GET_VARIANT_PTR(value, 3);

				bool valid;
				dst->set(*index, *value, &valid);

				if (!valid) {
					String v = index->operator String();
					if (v != "") {
						v = "'" + v + "'";
					} else {
						v = "of type '" + _get_var_type(index) + "'";
					}
					err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "').";
					break;
				}

				ip += 4;
				continue;
			}
			case OPCODE_GET: {

				CHECK_SPACE(3);

				GET_VARIANT_PTR(src, 1);
				GET_VARIANT_PTR(index, 2);
				GET_VARIANT_PTR(dst, 3);

				bool valid;
#ifdef DEBUG_ENABLED
				//allow better error message in cases where src and dst are the same stack position
				Variant ret = src->get(*index, &valid);
#else
				*dst = src->get(*index, &valid);

#endif
				if (!valid) {
					String v = index->operator String();
					if (v != "") {
						v = "'" + v + "'";
					} else {
						v = "of type '" + _get_var_type(index) + "'";
					}
					err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "').";
					break;
				}
#ifdef DEBUG_ENABLED
				*dst = ret;
#endif
				ip += 4;
				continue;
			}
			case OPCODE_SET_NAMED: {

				CHECK_SPACE(3);

				GET_VARIANT_PTR(dst, 1);
				GET_VARIANT_PTR(value, 3);

				int indexname = _code_ptr[ip + 2];

				ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
				const StringName *index = &_global_names_ptr[indexname];

				bool valid;
				dst->set_named(*index, *value, &valid);

				if (!valid) {
					String err_type;
					err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "').";
					break;
				}

				ip += 4;
				continue;
			}
			case OPCODE_GET_NAMED: {

				CHECK_SPACE(4);

				GET_VARIANT_PTR(src, 1);
				GET_VARIANT_PTR(dst, 3);

				int indexname = _code_ptr[ip + 2];

				ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
				const StringName *index = &_global_names_ptr[indexname];

				bool valid;
#ifdef DEBUG_ENABLED
				//allow better error message in cases where src and dst are the same stack position
				Variant ret = src->get_named(*index, &valid);

#else
				*dst = src->get_named(*index, &valid);
#endif

				if (!valid) {
					if (src->has_method(*index)) {
						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "'). Did you mean '." + index->operator String() + "()' ?";
					} else {
						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "').";
					}
					break;
				}
#ifdef DEBUG_ENABLED
				*dst = ret;
#endif
				ip += 4;
				continue;
			}
			case OPCODE_SET_MEMBER: {

				CHECK_SPACE(3);
				int indexname = _code_ptr[ip + 1];
				ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
				const StringName *index = &_global_names_ptr[indexname];
				GET_VARIANT_PTR(src, 2);

				bool valid;
				bool ok = ClassDB::set_property(p_instance->owner, *index, *src, &valid);
#ifdef DEBUG_ENABLED
				if (!ok) {
					err_text = "Internal error setting property: " + String(*index);
					break;
				} else if (!valid) {
					err_text = "Error setting property '" + String(*index) + "' with value of type " + Variant::get_type_name(src->get_type()) + ".";
					break;
				}
#endif
				ip += 3;
				continue;
			}
			case OPCODE_GET_MEMBER: {

				CHECK_SPACE(3);
				int indexname = _code_ptr[ip + 1];
				ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
				const StringName *index = &_global_names_ptr[indexname];
				GET_VARIANT_PTR(dst, 2);
				bool ok = ClassDB::get_property(p_instance->owner, *index, *dst);

#ifdef DEBUG_ENABLED
				if (!ok) {
					err_text = "Internal error getting property: " + String(*index);
					break;
				}
#endif
				ip += 3;
				continue;
			}
			case OPCODE_ASSIGN: {

				CHECK_SPACE(3);
				GET_VARIANT_PTR(dst, 1);
				GET_VARIANT_PTR(src, 2);

				*dst = *src;

				ip += 3;
				continue;
			}
			case OPCODE_ASSIGN_TRUE: {

				CHECK_SPACE(2);
				GET_VARIANT_PTR(dst, 1);

				*dst = true;

				ip += 2;
				continue;
			}
			case OPCODE_ASSIGN_FALSE: {

				CHECK_SPACE(2);
				GET_VARIANT_PTR(dst, 1);

				*dst = false;

				ip += 2;
				continue;
			}
			case OPCODE_CONSTRUCT: {

				CHECK_SPACE(2);
				Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
				int argc = _code_ptr[ip + 2];
				CHECK_SPACE(argc + 2);
				Variant **argptrs = call_args;
				for (int i = 0; i < argc; i++) {
					GET_VARIANT_PTR(v, 3 + i);
					argptrs[i] = v;
				}

				GET_VARIANT_PTR(dst, 3 + argc);
				Variant::CallError err;
				*dst = Variant::construct(t, (const Variant **)argptrs, argc, err);

				if (err.error != Variant::CallError::CALL_OK) {

					err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs);
					break;
				}

				ip += 4 + argc;
				//construct a basic type
				continue;
			}
			case OPCODE_CONSTRUCT_ARRAY: {

				CHECK_SPACE(1);
				int argc = _code_ptr[ip + 1];
				Array array; //arrays are always shared
				array.resize(argc);
				CHECK_SPACE(argc + 2);

				for (int i = 0; i < argc; i++) {
					GET_VARIANT_PTR(v, 2 + i);
					array[i] = *v;
				}

				GET_VARIANT_PTR(dst, 2 + argc);

				*dst = array;

				ip += 3 + argc;
				continue;
			}
			case OPCODE_CONSTRUCT_DICTIONARY: {

				CHECK_SPACE(1);
				int argc = _code_ptr[ip + 1];
				Dictionary dict; //arrays are always shared

				CHECK_SPACE(argc * 2 + 2);

				for (int i = 0; i < argc; i++) {

					GET_VARIANT_PTR(k, 2 + i * 2 + 0);
					GET_VARIANT_PTR(v, 2 + i * 2 + 1);
					dict[*k] = *v;
				}

				GET_VARIANT_PTR(dst, 2 + argc * 2);

				*dst = dict;

				ip += 3 + argc * 2;
				continue;
			}
			case OPCODE_CALL_RETURN:
			case OPCODE_CALL: {

				CHECK_SPACE(4);
				bool call_ret = _code_ptr[ip] == OPCODE_CALL_RETURN;

				int argc = _code_ptr[ip + 1];
				GET_VARIANT_PTR(base, 2);
				int nameg = _code_ptr[ip + 3];

				ERR_BREAK(nameg < 0 || nameg >= _global_names_count);
				const StringName *methodname = &_global_names_ptr[nameg];

				ERR_BREAK(argc < 0);
				ip += 4;
				CHECK_SPACE(argc + 1);
				Variant **argptrs = call_args;

				for (int i = 0; i < argc; i++) {
					GET_VARIANT_PTR(v, i);
					argptrs[i] = v;
				}

#ifdef DEBUG_ENABLED
				uint64_t call_time;

				if (GDScriptLanguage::get_singleton()->profiling) {
					call_time = OS::get_singleton()->get_ticks_usec();
				}

#endif
				Variant::CallError err;
				if (call_ret) {

					GET_VARIANT_PTR(ret, argc);
					base->call_ptr(*methodname, (const Variant **)argptrs, argc, ret, err);
				} else {

					base->call_ptr(*methodname, (const Variant **)argptrs, argc, NULL, err);
				}
#ifdef DEBUG_ENABLED
				if (GDScriptLanguage::get_singleton()->profiling) {
					function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
				}
#endif

				if (err.error != Variant::CallError::CALL_OK) {

					String methodstr = *methodname;
					String basestr = _get_var_type(base);

					if (methodstr == "call") {
						if (argc >= 1) {
							methodstr = String(*argptrs[0]) + " (via call)";
							if (err.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
								err.argument -= 1;
							}
						}
					} else if (methodstr == "free") {

						if (err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) {

							if (base->is_ref()) {
								err_text = "Attempted to free a reference.";
								break;
							} else if (base->get_type() == Variant::OBJECT) {

								err_text = "Attempted to free a locked object (calling or emitting).";
								break;
							}
						}
					}
					err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
					break;
				}

				//_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);
				ip += argc + 1;
				continue;
			}
			case OPCODE_CALL_BUILT_IN: {

				CHECK_SPACE(4);

				GDFunctions::Function func = GDFunctions::Function(_code_ptr[ip + 1]);
				int argc = _code_ptr[ip + 2];
				ERR_BREAK(argc < 0);

				ip += 3;
				CHECK_SPACE(argc + 1);
				Variant **argptrs = call_args;

				for (int i = 0; i < argc; i++) {
					GET_VARIANT_PTR(v, i);
					argptrs[i] = v;
				}

				GET_VARIANT_PTR(dst, argc);

				Variant::CallError err;

				GDFunctions::call(func, (const Variant **)argptrs, argc, *dst, err);

				if (err.error != Variant::CallError::CALL_OK) {

					String methodstr = GDFunctions::get_func_name(func);
					if (dst->get_type() == Variant::STRING) {
						//call provided error string
						err_text = "Error calling built-in function '" + methodstr + "': " + String(*dst);
					} else {
						err_text = _get_call_error(err, "built-in function '" + methodstr + "'", (const Variant **)argptrs);
					}
					break;
				}
				ip += argc + 1;
				continue;
			}
			case OPCODE_CALL_SELF: {

				break;
			}
			case OPCODE_CALL_SELF_BASE: {

				CHECK_SPACE(2);
				int self_fun = _code_ptr[ip + 1];
#ifdef DEBUG_ENABLED

				if (self_fun < 0 || self_fun >= _global_names_count) {

					err_text = "compiler bug, function name not found";
					break;
				}
#endif
				const StringName *methodname = &_global_names_ptr[self_fun];

				int argc = _code_ptr[ip + 2];

				CHECK_SPACE(2 + argc + 1);

				Variant **argptrs = call_args;

				for (int i = 0; i < argc; i++) {
					GET_VARIANT_PTR(v, i + 3);
					argptrs[i] = v;
				}

				GET_VARIANT_PTR(dst, argc + 3);

				const GDScript *gds = _script;

				const Map<StringName, GDFunction *>::Element *E = NULL;
				while (gds->base.ptr()) {
					gds = gds->base.ptr();
					E = gds->member_functions.find(*methodname);
					if (E)
						break;
				}

				Variant::CallError err;

				if (E) {

					*dst = E->get()->call(p_instance, (const Variant **)argptrs, argc, err);
				} else if (gds->native.ptr()) {

					if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {

						MethodBind *mb = ClassDB::get_method(gds->native->get_name(), *methodname);
						if (!mb) {
							err.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
						} else {
							*dst = mb->call(p_instance->owner, (const Variant **)argptrs, argc, err);
						}
					} else {
						err.error = Variant::CallError::CALL_OK;
					}
				} else {

					if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
						err.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
					} else {
						err.error = Variant::CallError::CALL_OK;
					}
				}

				if (err.error != Variant::CallError::CALL_OK) {

					String methodstr = *methodname;
					err_text = _get_call_error(err, "function '" + methodstr + "'", (const Variant **)argptrs);

					break;
				}

				ip += 4 + argc;
				continue;
			}
			case OPCODE_YIELD:
			case OPCODE_YIELD_SIGNAL: {

				int ipofs = 1;
				if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) {
					CHECK_SPACE(4);
					ipofs += 2;
				} else {
					CHECK_SPACE(2);
				}

				Ref<GDFunctionState> gdfs = memnew(GDFunctionState);
				gdfs->function = this;

				gdfs->state.stack.resize(alloca_size);
				//copy variant stack
				for (int i = 0; i < _stack_size; i++) {
					memnew_placement(&gdfs->state.stack[sizeof(Variant) * i], Variant(stack[i]));
				}
				gdfs->state.stack_size = _stack_size;
				gdfs->state.self = self;
				gdfs->state.alloca_size = alloca_size;
				gdfs->state._class = _class;
				gdfs->state.ip = ip + ipofs;
				gdfs->state.line = line;
				gdfs->state.instance_id = (p_instance && p_instance->get_owner()) ? p_instance->get_owner()->get_instance_ID() : 0;
				gdfs->state.script_id = _class->get_instance_ID();
				//gdfs->state.result_pos=ip+ipofs-1;
				gdfs->state.defarg = defarg;
				gdfs->state.instance = p_instance;
				gdfs->function = this;

				retvalue = gdfs;

				if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) {
					GET_VARIANT_PTR(argobj, 1);
					GET_VARIANT_PTR(argname, 2);
					//do the oneshot connect

					if (argobj->get_type() != Variant::OBJECT) {
						err_text = "First argument of yield() not of type object.";
						break;
					}
					if (argname->get_type() != Variant::STRING) {
						err_text = "Second argument of yield() not a string (for signal name).";
						break;
					}
					Object *obj = argobj->operator Object *();
					String signal = argname->operator String();
#ifdef DEBUG_ENABLED

					if (!obj) {
						err_text = "First argument of yield() is null.";
						break;
					}
					if (ScriptDebugger::get_singleton()) {
						if (!ObjectDB::instance_validate(obj)) {
							err_text = "First argument of yield() is a previously freed instance.";
							break;
						}
					}
					if (signal.length() == 0) {

						err_text = "Second argument of yield() is an empty string (for signal name).";
						break;
					}

#endif
					Error err = obj->connect(signal, gdfs.ptr(), "_signal_callback", varray(gdfs), Object::CONNECT_ONESHOT);
					if (err != OK) {
						err_text = "Error connecting to signal: " + signal + " during yield().";
						break;
					}
				}

				exit_ok = true;
				break;
			}
			case OPCODE_YIELD_RESUME: {

				CHECK_SPACE(2);
				if (!p_state) {
					err_text = ("Invalid Resume (bug?)");
					break;
				}
				GET_VARIANT_PTR(result, 1);
				*result = p_state->result;
				ip += 2;
				continue;
			}
			case OPCODE_JUMP: {

				CHECK_SPACE(2);
				int to = _code_ptr[ip + 1];

				ERR_BREAK(to < 0 || to > _code_size);
				ip = to;
				continue;
			}
			case OPCODE_JUMP_IF: {

				CHECK_SPACE(3);

				GET_VARIANT_PTR(test, 1);

				bool valid;
				bool result = test->booleanize(valid);
#ifdef DEBUG_ENABLED
				if (!valid) {

					err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
					break;
				}
#endif
				if (result) {
					int to = _code_ptr[ip + 2];
					ERR_BREAK(to < 0 || to > _code_size);
					ip = to;
					continue;
				}
				ip += 3;
				continue;
			}
			case OPCODE_JUMP_IF_NOT: {

				CHECK_SPACE(3);

				GET_VARIANT_PTR(test, 1);

				bool valid;
				bool result = test->booleanize(valid);
#ifdef DEBUG_ENABLED
				if (!valid) {

					err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
					break;
				}
#endif
				if (!result) {
					int to = _code_ptr[ip + 2];
					ERR_BREAK(to < 0 || to > _code_size);
					ip = to;
					continue;
				}
				ip += 3;
				continue;
			}
			case OPCODE_JUMP_TO_DEF_ARGUMENT: {

				CHECK_SPACE(2);
				ip = _default_arg_ptr[defarg];
				continue;
			}
			case OPCODE_RETURN: {

				CHECK_SPACE(2);
				GET_VARIANT_PTR(r, 1);
				retvalue = *r;
				exit_ok = true;
				break;
			}
			case OPCODE_ITERATE_BEGIN: {

				CHECK_SPACE(8); //space for this an regular iterate

				GET_VARIANT_PTR(counter, 1);
				GET_VARIANT_PTR(container, 2);

				bool valid;
				if (!container->iter_init(*counter, valid)) {
					if (!valid) {
						err_text = "Unable to iterate on object of type  " + Variant::get_type_name(container->get_type()) + "'.";
						break;
					}
					int jumpto = _code_ptr[ip + 3];
					ERR_BREAK(jumpto < 0 || jumpto > _code_size);
					ip = jumpto;
					continue;
				}
				GET_VARIANT_PTR(iterator, 4);

				*iterator = container->iter_get(*counter, valid);
				if (!valid) {
					err_text = "Unable to obtain iterator object of type  " + Variant::get_type_name(container->get_type()) + "'.";
					break;
				}

				ip += 5; //skip regular iterate which is always next
				continue;
			}
			case OPCODE_ITERATE: {

				CHECK_SPACE(4);

				GET_VARIANT_PTR(counter, 1);
				GET_VARIANT_PTR(container, 2);

				bool valid;
				if (!container->iter_next(*counter, valid)) {
					if (!valid) {
						err_text = "Unable to iterate on object of type  " + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
						break;
					}
					int jumpto = _code_ptr[ip + 3];
					ERR_BREAK(jumpto < 0 || jumpto > _code_size);
					ip = jumpto;
					continue;
				}
				GET_VARIANT_PTR(iterator, 4);

				*iterator = container->iter_get(*counter, valid);
				if (!valid) {
					err_text = "Unable to obtain iterator object of type  " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
					break;
				}

				ip += 5; //loop again
				continue;
			}
			case OPCODE_ASSERT: {
				CHECK_SPACE(2);
				GET_VARIANT_PTR(test, 1);

#ifdef DEBUG_ENABLED
				bool valid;
				bool result = test->booleanize(valid);

				if (!valid) {

					err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
					break;
				}

				if (!result) {

					err_text = "Assertion failed.";
					break;
				}

#endif

				ip += 2;
				continue;
			}
			case OPCODE_BREAKPOINT: {
#ifdef DEBUG_ENABLED
				if (ScriptDebugger::get_singleton()) {
					GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true);
				}
#endif
				ip += 1;
				continue;
			}
			case OPCODE_LINE: {
				CHECK_SPACE(2);

				line = _code_ptr[ip + 1];
				ip += 2;

				if (ScriptDebugger::get_singleton()) {
					// line
					bool do_break = false;

					if (ScriptDebugger::get_singleton()->get_lines_left() > 0) {

						if (ScriptDebugger::get_singleton()->get_depth() <= 0)
							ScriptDebugger::get_singleton()->set_lines_left(ScriptDebugger::get_singleton()->get_lines_left() - 1);
						if (ScriptDebugger::get_singleton()->get_lines_left() <= 0)
							do_break = true;
					}

					if (ScriptDebugger::get_singleton()->is_breakpoint(line, source))
						do_break = true;

					if (do_break) {
						GDScriptLanguage::get_singleton()->debug_break("Breakpoint", true);
					}

					ScriptDebugger::get_singleton()->line_poll();
				}
				continue;
			}
			case OPCODE_END: {

				exit_ok = true;
				break;
			}
			default: {

				err_text = "Illegal opcode " + itos(_code_ptr[ip]) + " at address " + itos(ip);
				break;
			}
		}

		if (exit_ok)
			break;
		//error
		// function, file, line, error, explanation
		String err_file;
		if (p_instance)
			err_file = p_instance->script->path;
		else if (_class)
			err_file = _class->path;
		if (err_file == "")
			err_file = "<built-in>";
		String err_func = name;
		if (p_instance && p_instance->script->name != "")
			err_func = p_instance->script->name + "." + err_func;
		int err_line = line;
		if (err_text == "") {
			err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please).";
		}

		if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) {
			// debugger break did not happen

			_err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
		}

		break;
	}

#ifdef DEBUG_ENABLED
	if (GDScriptLanguage::get_singleton()->profiling) {
		uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - function_start_time;
		profile.total_time += time_taken;
		profile.self_time += time_taken - function_call_time;
		profile.frame_total_time += time_taken;
		profile.frame_self_time += time_taken - function_call_time;
		GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
	}

#endif
	if (ScriptDebugger::get_singleton())
		GDScriptLanguage::get_singleton()->exit_function();

	if (_stack_size) {
		//free stack
		for (int i = 0; i < _stack_size; i++)
			stack[i].~Variant();
	}

	return retvalue;
}
Exemple #9
0
static size_t
xstrftime(
    char *str,			/* output buffer */
    size_t bsz,			/* space available */
    const char *fmt,
    struct tm *tm,
    double usec,
    double fulltime)
{
    size_t l = 0;			/* chars written so far */
    int incr = 0;			/* chars just written */
    char *s = str;
    TBOOLEAN sign_printed = FALSE;

    memset(str, '\0', bsz);

    while (*fmt != '\0') {
        if (*fmt != '%') {
            if (l >= bsz-1)
                return 0;
            *s++ = *fmt++;
            l++;
        } else {
            /* set up format modifiers */
            int w = 0;
            int z = 0;
            int p = 0;

            if (*++fmt == '0') {
                z = 1;
                ++fmt;
            }
            while (*fmt >= '0' && *fmt <= '9') {
                w = w * 10 + (*fmt - '0');
                ++fmt;
            }
            if (*fmt == '.') {
                ++fmt;
                while (*fmt >= '0' && *fmt <= '9') {
                    p = p * 10 + (*fmt - '0');
                    ++fmt;
                }
                if (p > 6) p = 6;
            }

            switch (*fmt++) {

                /* some shorthands : check that there is space in the
                 * output string. */
#define CHECK_SPACE(n) do {				\
		    if ((l+(n)) > bsz) return 0;	\
		} while (0)

                /* copy a fixed string, checking that there's room */
#define COPY_STRING(z) do {			\
		    CHECK_SPACE(strlen(z)) ;	\
		    strcpy(s, z);		\
		} while (0)

                /* format a string, using default spec if none given w
                 * and z are width and zero-flag dw and dz are the
                 * defaults for these In fact, CHECK_SPACE(w) is not a
                 * sufficient test, since sprintf("%2d", 365) outputs
                 * three characters
                 */
#define FORMAT_STRING(dz, dw, x) do {				\
		    if (w==0) {					\
			w=(dw);					\
			if (!z)					\
			    z=(dz);				\
		    }						\
		    incr = snprintf(s, bsz-l-1, z ? "%0*d" : "%*d", w, (x));	\
		    CHECK_SPACE(incr);				\
		} while(0)

            case '%':
                CHECK_SPACE(1);
                *s = '%';
                break;

            case 'a':
                COPY_STRING(abbrev_day_names[tm->tm_wday]);
                break;

            case 'A':
                COPY_STRING(full_day_names[tm->tm_wday]);
                break;

            case 'b':
            case 'h':
                COPY_STRING(abbrev_month_names[tm->tm_mon]);
                break;

            case 'B':
                COPY_STRING(full_month_names[tm->tm_mon]);
                break;

            case 'd':
                FORMAT_STRING(1, 2, tm->tm_mday);	/* %02d */
                break;

            case 'D':
                if (!xstrftime(s, bsz - l, "%m/%d/%y", tm, 0., fulltime))
                    return 0;
                break;

            case 'F':
                if (!xstrftime(s, bsz - l, "%Y-%m-%d", tm, 0., fulltime))
                    return 0;
                break;

            case 'H':
                FORMAT_STRING(1, 2, tm->tm_hour);	/* %02d */
                break;

            case 'I':
                FORMAT_STRING(1, 2, (tm->tm_hour + 11) % 12 + 1); /* %02d */
                break;

            case 'j':
                FORMAT_STRING(1, 3, tm->tm_yday + 1);	/* %03d */
                break;

            /* not in linux strftime man page. Not really needed now */
            case 'k':
                FORMAT_STRING(0, 2, tm->tm_hour);	/* %2d */
                break;

            case 'l':
                FORMAT_STRING(0, 2, (tm->tm_hour + 11) % 12 + 1); /* %2d */
                break;

            case 'm':
                FORMAT_STRING(1, 2, tm->tm_mon + 1);	/* %02d */
                break;

            case 'M':
                FORMAT_STRING(1, 2, tm->tm_min);	/* %02d */
                break;

            case 'p':
                CHECK_SPACE(2);
                strcpy(s, (tm->tm_hour < 12) ? "am" : "pm");
                break;

            case 'r':
                if (!xstrftime(s, bsz - l, "%I:%M:%S %p", tm, 0., fulltime))
                    return 0;
                break;

            case 'R':
                if (!xstrftime(s, bsz - l, "%H:%M", tm, 0., fulltime))
                    return 0;
                break;

            case 's':
                CHECK_SPACE(12); /* large enough for year 9999 */
                sprintf(s, "%.0f", gtimegm(tm));
                break;

            case 'S':
                FORMAT_STRING(1, 2, tm->tm_sec);	/* %02d */

                /* EAM FIXME - need to implement an actual format specifier */
                if (p > 0) {
                    double base = pow(10., (double)p);
                    int msec = floor(0.5 + base * usec);
                    char *f = &s[strlen(s)];
                    CHECK_SPACE(p+1);
                    sprintf(f, ".%0*d", p, msec<(int)base?msec:(int)base-1);
                }
                break;

            case 'T':
                if (!xstrftime(s, bsz - l, "%H:%M:%S", tm, 0., fulltime))
                    return 0;
                break;

            case 't':		/* Time (as opposed to Date) formats */
            {
                int tminute, tsecond;

                switch (*fmt++) {
                case 'H':
                    /* +/- fractional hours (not wrapped at 24h) */
                    if (p > 0) {
                        incr = snprintf(s, bsz-l-1, "%*.*f", w, p, fulltime/3600.);
                        CHECK_SPACE(incr);
                        break;
                    }
                    /* Set flag in case minutes come next */
                    if (fulltime < 0) {
                        CHECK_SPACE(1);	/* the minus sign */
                        sign_printed = TRUE;
                        *s++ = '-';
                        l++;
                    }
                    /* +/- integral hour truncated toward zero */
                    sprintf(s, "%0*d", w, (int)floor(fabs(fulltime/3600.)));
                    break;
                case 'M':
                    /* +/- fractional minutes (not wrapped at 60m) */
                    if (p > 0) {
                        incr = snprintf(s, bsz-l-1, "%*.*f", w, p,
                                        sign_printed ? fabs(fulltime)/60. : fulltime/60.);
                        CHECK_SPACE(incr);
                        break;
                    }
                    /* +/- integral minute truncated toward zero */
                    tminute = floor(60. * (fabs(fulltime/3600.) - floor(fabs(fulltime/3600.))));
                    if (fulltime < 0) {
                        if (!sign_printed) {
                            sign_printed = TRUE;
                            *s++ = '-';
                            l++;
                        }
                    }
                    FORMAT_STRING(1, 2, tminute);	/* %02d */
                    break;
                case 'S':
                    /* +/- fractional seconds */
                    tsecond = floor(60. * (fabs(fulltime/60.) - floor(fabs(fulltime/60.))));
                    if (fulltime < 0) {
                        if (usec > 0)
                            usec = 1.0 - usec;
                        if (!sign_printed) {
                            *s++ = '-';
                            l++;
                        }
                    }
                    FORMAT_STRING(1, 2, tsecond);	/* %02d */
                    if (p > 0) {
                        double base = pow(10., (double)p);
                        int msec = floor(0.5 + base * usec);
                        char *f = &s[strlen(s)];
                        CHECK_SPACE(p+1);
                        sprintf(f, ".%0*d", p, msec<(int)base?msec:(int)base-1);
                    }
                    break;
                default:
                    break;
                }
                break;
            }

            case 'W':		/* mon 1 day of week */
            {
                int week;
                if (tm->tm_yday <= tm->tm_wday) {
                    week = 1;

                    if ((tm->tm_mday - tm->tm_yday) > 4) {
                        week = 52;
                    }
                    if (tm->tm_yday == tm->tm_wday && tm->tm_wday == 0)
                        week = 52;

                } else {

                    /* sun prev week */
                    int bw = tm->tm_yday - tm->tm_wday;

                    if (tm->tm_wday > 0)
                        bw += 7;	/* sun end of week */

                    week = (int) bw / 7;

                    if ((bw % 7) > 2)	/* jan 1 is before friday */
                        week++;
                }
                FORMAT_STRING(1, 2, week);	/* %02d */
                break;
            }

            case 'U':		/* sun 1 day of week */
            {
                int week, bw;

                if (tm->tm_yday <= tm->tm_wday) {
                    week = 1;
                    if ((tm->tm_mday - tm->tm_yday) > 4) {
                        week = 52;
                    }
                } else {
                    /* sat prev week */
                    bw = tm->tm_yday - tm->tm_wday - 1;
                    if (tm->tm_wday >= 0)
                        bw += 7;	/* sat end of week */
                    week = (int) bw / 7;
                    if ((bw % 7) > 1) {	/* jan 1 is before friday */
                        week++;
                    }
                }
                FORMAT_STRING(1, 2, week);	/* %02d */
                break;
            }

            case 'w':		/* day of week, sun=0 */
                FORMAT_STRING(1, 2, tm->tm_wday);	/* %02d */
                break;

            case 'y':
                FORMAT_STRING(1, 2, tm->tm_year % 100);		/* %02d */
                break;

            case 'Y':
                FORMAT_STRING(1, 4, tm->tm_year);	/* %04d */
                break;

            }			/* switch */

            while (*s != '\0') {
                s++;
                l++;
            }
#undef CHECK_SPACE
#undef COPY_STRING
#undef FORMAT_STRING
        } /* switch(fmt letter) */
    } /* if(fmt letter not '%') */
    return (l);
}
Exemple #10
0
enum PVRSRV_ERROR RA_GetStats(struct RA_ARENA *pArena, char **ppszStr,
			      u32 *pui32StrLen)
{
	char *pszStr = *ppszStr;
	u32 ui32StrLen = *pui32StrLen;
	s32 i32Count;
	struct BT *pBT;

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "\nArena '%s':\n", pArena->name);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100,
		       "  allocCB=%08X freeCB=%08X handle=%08X quantum=%d\n",
		       pArena->pImportAlloc, pArena->pImportFree,
		       pArena->pImportHandle, pArena->uQuantum);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "span count\t\t%lu\n",
		       pArena->sStatistics.uSpanCount);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "live segment count\t%lu\n",
		       pArena->sStatistics.uLiveSegmentCount);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "free segment count\t%lu\n",
		       pArena->sStatistics.uFreeSegmentCount);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "free resource count\t%lu (0x%x)\n",
			      pArena->sStatistics.uFreeResourceCount,
			      (unsigned)pArena->sStatistics.uFreeResourceCount);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "total allocs\t\t%lu\n",
		       pArena->sStatistics.uCumulativeAllocs);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "total frees\t\t%lu\n",
		       pArena->sStatistics.uCumulativeFrees);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "import count\t\t%lu\n",
		       pArena->sStatistics.uImportCount);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "export count\t\t%lu\n",
		       pArena->sStatistics.uExportCount);
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	CHECK_SPACE(ui32StrLen);
	i32Count = OSSNPrintf(pszStr, 100, "  segment Chain:\n");
	UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

	if (pArena->pHeadSegment != NULL &&
	    pArena->pHeadSegment->pPrevSegment != NULL) {
		CHECK_SPACE(ui32StrLen);
		i32Count = OSSNPrintf(pszStr, 100,
		       "  error: head boundary tag has invalid pPrevSegment\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if (pArena->pTailSegment != NULL &&
	    pArena->pTailSegment->pNextSegment != NULL) {
		CHECK_SPACE(ui32StrLen);
		i32Count = OSSNPrintf(pszStr, 100,
		       "  error: tail boundary tag has invalid pNextSegment\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	for (pBT = pArena->pHeadSegment; pBT != NULL;
	     pBT = pBT->pNextSegment) {
		CHECK_SPACE(ui32StrLen);
		i32Count = OSSNPrintf(pszStr, 100,
			       "\tbase=0x%x size=0x%x type=%s ref=%08X\n",
			       (u32) pBT->base, pBT->uSize, _BTType(pBT->type),
			       pBT->psMapping);
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	*ppszStr = pszStr;
	*pui32StrLen = ui32StrLen;

	return PVRSRV_OK;
}
Exemple #11
0
enum PVRSRV_ERROR PVRSRVGetMiscInfoKM(struct PVRSRV_MISC_INFO *psMiscInfo)
{
	struct SYS_DATA *psSysData;
	enum PVRSRV_ERROR eError;

	if (!psMiscInfo) {
		PVR_DPF(PVR_DBG_ERROR,
			 "PVRSRVGetMiscInfoKM: invalid parameters");
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	psMiscInfo->ui32StatePresent = 0;

	if (psMiscInfo->ui32StateRequest & ~(
				PVRSRV_MISC_INFO_TIMER_PRESENT		   |
			  PVRSRV_MISC_INFO_CLOCKGATE_PRESENT |
			  PVRSRV_MISC_INFO_MEMSTATS_PRESENT |
				PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT |
				PVRSRV_MISC_INFO_DDKVERSION_PRESENT)) {
		PVR_DPF(PVR_DBG_ERROR,
			 "PVRSRVGetMiscInfoKM: invalid state request flags");
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	eError = SysAcquireData(&psSysData);
	if (eError != PVRSRV_OK) {
		PVR_DPF(PVR_DBG_ERROR,
			 "PVRSRVGetMiscInfoKM: Failed to get SysData");
		return eError;
	}

	if (((psMiscInfo->ui32StateRequest &
	     PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
	     (psSysData->pvSOCTimerRegisterKM != NULL)) {
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
		psMiscInfo->pvSOCTimerRegisterKM =
		    psSysData->pvSOCTimerRegisterKM;
		psMiscInfo->hSOCTimerRegisterOSMemHandle =
		    psSysData->hSOCTimerRegisterOSMemHandle;
	} else {
		psMiscInfo->pvSOCTimerRegisterKM = NULL;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = NULL;
	}

	if (((psMiscInfo->ui32StateRequest &
	    PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
	    (psSysData->pvSOCClockGateRegsBase != NULL)) {
		psMiscInfo->ui32StatePresent |=
		    PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
		psMiscInfo->pvSOCClockGateRegs =
		    psSysData->pvSOCClockGateRegsBase;
		psMiscInfo->ui32SOCClockGateRegsSize =
		    psSysData->ui32SOCClockGateRegsSize;
	}

	if (((psMiscInfo->ui32StateRequest &
	      PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
	     (psMiscInfo->pszMemoryStr != NULL)) {
		struct RA_ARENA **ppArena;
		struct BM_HEAP *psBMHeap;
		struct BM_CONTEXT *psBMContext;
		struct PVRSRV_DEVICE_NODE *psDeviceNode;
		char *pszStr;
		u32 ui32StrLen;
		s32 i32Count;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		psMiscInfo->ui32StatePresent |=
		    PVRSRV_MISC_INFO_MEMSTATS_PRESENT;

		ppArena = &psSysData->apsLocalDevMemArena[0];
		while (*ppArena) {
			CHECK_SPACE(ui32StrLen);
			i32Count =
			    OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

			RA_GetStats(*ppArena, &pszStr, &ui32StrLen);

			ppArena++;
		}

		psDeviceNode = psSysData->psDeviceNodeList;
		while (psDeviceNode) {
			CHECK_SPACE(ui32StrLen);
			i32Count =
			    OSSNPrintf(pszStr, 100, "\n\nDevice Type %d:\n",
				       psDeviceNode->sDevId.eDeviceType);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

			if (psDeviceNode->sDevMemoryInfo.pBMKernelContext) {
				CHECK_SPACE(ui32StrLen);
				i32Count =
				    OSSNPrintf(pszStr, 100,
					       "\nKernel Context:\n");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

				psBMHeap =
				    psDeviceNode->sDevMemoryInfo.
				    pBMKernelContext->psBMHeap;
				while (psBMHeap) {
					if (psBMHeap->pImportArena) {
						RA_GetStats(psBMHeap->
								pImportArena,
							    &pszStr,
							    &ui32StrLen);
					}

					if (psBMHeap->pVMArena) {
						RA_GetStats(psBMHeap->pVMArena,
							    &pszStr,
							    &ui32StrLen);
					}
					psBMHeap = psBMHeap->psNext;
				}
			}

			psBMContext = psDeviceNode->sDevMemoryInfo.pBMContext;
			while (psBMContext) {
				CHECK_SPACE(ui32StrLen);
				i32Count =
				    OSSNPrintf(pszStr, 100,
			"\nApplication Context (hDevMemContext) 0x%08X:\n",
						   (void *)psBMContext);
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

				psBMHeap = psBMContext->psBMHeap;
				while (psBMHeap) {
					if (psBMHeap->pImportArena) {
						RA_GetStats(psBMHeap->
								pImportArena,
							    &pszStr,
							    &ui32StrLen);
					}

					if (psBMHeap->pVMArena) {
						RA_GetStats(psBMHeap->pVMArena,
							    &pszStr,
							    &ui32StrLen);
					}
					psBMHeap = psBMHeap->psNext;
				}
				psBMContext = psBMContext->psNext;
			}
			psDeviceNode = psDeviceNode->psNext;
		}

		i32Count = OSSNPrintf(pszStr, 100, "\n\0");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if (((psMiscInfo->ui32StateRequest &
	      PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
	     (psSysData->psGlobalEventObject != NULL)) {
		psMiscInfo->ui32StatePresent |=
		    PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
		psMiscInfo->sGlobalEventObject =
		    *psSysData->psGlobalEventObject;
	}

	if (((psMiscInfo->ui32StateRequest &
			PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL) &&
	    ((psMiscInfo->ui32StateRequest &
			PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL) &&
	     (psMiscInfo->pszMemoryStr != NULL)) {
		char *pszStr;
		u32 ui32StrLen;
		u32 ui32LenStrPerNum = 12;
		s32 i32Count;
		int i;
		psMiscInfo->ui32StatePresent |=
		    PVRSRV_MISC_INFO_DDKVERSION_PRESENT;

		psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ;
		psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN;
		psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BRANCH;
		psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		for (i = 0; i < 4; i++) {
			if (ui32StrLen < ui32LenStrPerNum)
				return PVRSRV_ERROR_INVALID_PARAMS;

			i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%ld",
				       psMiscInfo->aui32DDKVersion[i]);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			if (i != 3) {
				i32Count = OSSNPrintf(pszStr, 2, ".");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			}
		}
	}

	return PVRSRV_OK;
}
IMG_EXPORT			
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo)
{
	SYS_DATA *psSysData;
	
	if(!psMiscInfo)
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters"));		
		return PVRSRV_ERROR_INVALID_PARAMS;
	}
	
	psMiscInfo->ui32StatePresent = 0;

	
	if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT
										|PVRSRV_MISC_INFO_CLOCKGATE_PRESENT
										|PVRSRV_MISC_INFO_MEMSTATS_PRESENT
										|PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT
										|PVRSRV_MISC_INFO_DDKVERSION_PRESENT))
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
		return PVRSRV_ERROR_INVALID_PARAMS;			
	}

	SysAcquireData(&psSysData);

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
		(psSysData->pvSOCTimerRegisterKM != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
		psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle;
	}
	else
	{
		psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
		(psSysData->pvSOCClockGateRegsBase != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
		psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase;
		psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
		(psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		RA_ARENA			**ppArena;
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;
		
		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;

		
		ppArena = &psSysData->apsLocalDevMemArena[0];
		while(*ppArena)
		{
			CHECK_SPACE(ui32StrLen);
			i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			
			RA_GetStats(*ppArena,
							&pszStr, 
							&ui32StrLen);
			
			ppArena++;
		}

		
		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr);

		
		i32Count = OSSNPrintf(pszStr, 100, "\n\0");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
		(psSysData->psGlobalEventObject != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
		psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject;
	}
	
	

	if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL)
		&& ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL)
		&& (psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		IMG_CHAR	*pszStr;
		IMG_UINT32	ui32StrLen;
		IMG_UINT32 	ui32LenStrPerNum = 12; 
		IMG_INT32	i32Count;
		IMG_INT i;
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;

		
		psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ;
		psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN;
		psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BRANCH;
		psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		for (i=0; i<4; i++)
		{
			if (ui32StrLen < ui32LenStrPerNum)
			{
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%ld", psMiscInfo->aui32DDKVersion[i]);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			if (i != 3)
			{
				i32Count = OSSNPrintf(pszStr, 2, ".");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			}
		}
	}

	return PVRSRV_OK;
}
IMG_EXPORT			
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo)
{
	SYS_DATA *psSysData;
	
	if(!psMiscInfo)
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters"));		
		return PVRSRV_ERROR_INVALID_PARAMS;
	}
	
	psMiscInfo->ui32StatePresent = 0;

	
	if(psMiscInfo->ui32StateRequest & ~( PVRSRV_MISC_INFO_TIMER_PRESENT
										|PVRSRV_MISC_INFO_CLOCKGATE_PRESENT
										|PVRSRV_MISC_INFO_MEMSTATS_PRESENT
										|PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT
										|PVRSRV_MISC_INFO_DDKVERSION_PRESENT
										|PVRSRV_MISC_INFO_CPUCACHEFLUSH_PRESENT
										|PVRSRV_MISC_INFO_RESET_PRESENT))
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
		return PVRSRV_ERROR_INVALID_PARAMS;			
	}

	SysAcquireData(&psSysData);

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
		(psSysData->pvSOCTimerRegisterKM != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
		psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle;
	}
	else
	{
		psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
		(psSysData->pvSOCClockGateRegsBase != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
		psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase;
		psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
		(psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		RA_ARENA			**ppArena;
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;
		
		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;

		
		ppArena = &psSysData->apsLocalDevMemArena[0];
		while(*ppArena)
		{
			CHECK_SPACE(ui32StrLen);
			i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			
			RA_GetStats(*ppArena,
							&pszStr, 
							&ui32StrLen);
			
			ppArena++;
		}

		
		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr);

		
		i32Count = OSSNPrintf(pszStr, 100, "\n\0");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
		(psSysData->psGlobalEventObject != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
		psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject;
	}
	
	

	if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL)
		&& ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL)
		&& (psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		IMG_CHAR	*pszStr;
		IMG_UINT32	ui32StrLen;
		IMG_UINT32 	ui32LenStrPerNum = 12; 
		IMG_INT32	i32Count;
		IMG_INT i;
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;

		
		psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ;
		psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN;
		psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BRANCH;
		psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		for (i=0; i<4; i++)
		{
			if (ui32StrLen < ui32LenStrPerNum)
			{
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%ld", psMiscInfo->aui32DDKVersion[i]);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			if (i != 3)
			{
				i32Count = OSSNPrintf(pszStr, 2, ".");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			}
		}
	}

#if defined(SUPPORT_CPU_CACHED_BUFFERS)
	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CPUCACHEFLUSH_PRESENT) != 0UL)
	{
		if(psMiscInfo->bDeferCPUCacheFlush)
		{

			if(!psMiscInfo->bCPUCacheFlushAll)
			{



				PVR_DPF((PVR_DBG_MESSAGE,"PVRSRVGetMiscInfoKM: don't support deferred range flushes"));
				PVR_DPF((PVR_DBG_MESSAGE,"                     using deferred flush all instead"));
			}

			psSysData->bFlushAll = IMG_TRUE;
		}
		else
		{

			if(psMiscInfo->bCPUCacheFlushAll)
			{

				OSFlushCPUCacheKM();

				psSysData->bFlushAll = IMG_FALSE;
			}
			else
			{

				OSFlushCPUCacheRangeKM(psMiscInfo->pvRangeAddrStart, psMiscInfo->pvRangeAddrEnd);
			}
		}
	}
#endif

#if defined(PVRSRV_RESET_ON_HWTIMEOUT)
	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL)
	{
		PVR_LOG(("User requested OS reset"));
		OSPanic();
	}
#endif

	return PVRSRV_OK;
}
Exemple #14
0
/*
 * Pack the parameters for a delegate closure call onto the CVM stack.
 */
static int PackDelegateParams(ILExecThread *thread, ILMethod *method,
					          int isCtor, void *_this, void *userData)
{
	void **args = ((PackDelegateUserData *)userData)->args;
	ILMethod *pinvokeInfo = ((PackDelegateUserData *)userData)->pinvokeInfo;
	ILType *signature = ILMethod_Signature(method);
	CVMWord *stacktop, *stacklimit;
	ILUInt32 param, numParams;
	ILType *paramType;
	void *ptr;
	ILUInt32 size, sizeInWords;
	ILNativeFloat tempFloat;
	ILUInt32 marshalType;
	char *customName;
	int customNameLen;
	char *customCookie;
	int customCookieLen;
	char *strValue;

	/* Get the top and extent of the stack */
	stacktop = thread->stackTop;
	stacklimit = thread->stackLimit;

	/* Push the arguments onto the evaluation stack */
	if(ILType_HasThis(signature))
	{
		/* Push the "this" argument */
		CHECK_SPACE(1);
		if(((PackDelegateUserData *)userData)->needThis)
		{
			/* We get the "this" value from the incoming arguments */
			stacktop->ptrValue = *((void **)(*args));
			++args;
		}
		else
		{
			/* We get the "this" value from the delegate object */
			stacktop->ptrValue = _this;
		}
		++stacktop;
	}
	numParams = ILTypeNumParams(signature);
	for(param = 1; param <= numParams; ++param)
	{
		/* Marshal parameters that need special handling */
		marshalType = ILPInvokeGetMarshalType(0, pinvokeInfo, param,
											  &customName, &customNameLen,
											  &customCookie, &customCookieLen,
											  ILTypeGetParam(signature, param));
		if(marshalType != IL_META_MARSHAL_DIRECT)
		{
			switch(marshalType)
			{
				case IL_META_MARSHAL_ANSI_STRING:
				{
					/* Marshal an ANSI string from the native world */
					CHECK_SPACE(1);
					strValue = *((char **)(*args));
					if(strValue)
					{
						stacktop->ptrValue = ILStringCreate(thread, strValue);

						/* Free the native string */
						ILFreeNativeString(strValue);

						if(!(stacktop->ptrValue))
						{
							return 1;
						}
					}
					else
					{
						stacktop->ptrValue = 0;
					}
					++args;
					++stacktop;
				}
				continue;

				case IL_META_MARSHAL_UTF8_STRING:
				{
					/* Marshal a UTF-8 string from the native world */
					CHECK_SPACE(1);
					strValue = *((char **)(*args));
					if(strValue)
					{
						stacktop->ptrValue =
							ILStringCreateUTF8(thread, strValue);

						/* Free the native string */
						ILFreeNativeString(strValue);

						if(!(stacktop->ptrValue))
						{
							return 1;
						}
					}
					else
					{
						stacktop->ptrValue = 0;
					}
					++args;
					++stacktop;
				}
				continue;

				case IL_META_MARSHAL_UTF16_STRING:
				{
					/* Marshal a UTF-16 string from the native world */
					CHECK_SPACE(1);
					strValue = *((char **)(*args));
					if(strValue)
					{
						stacktop->ptrValue =
							ILStringWCreate(thread, (ILUInt16 *)strValue);

						/* Free the native string */
						ILFreeNativeString(strValue);
					
						if(!(stacktop->ptrValue))
						{
							return 1;
						}
					}
					else
					{
						stacktop->ptrValue = 0;
					}
					++args;
					++stacktop;
				}
				continue;

				case IL_META_MARSHAL_CUSTOM:
				{
					/* Marshal a custom value from the native world */
					CHECK_SPACE(1);
					stacktop->ptrValue = _ILCustomToObject
						(thread, *((void **)(*args)),
						 customName, customNameLen,
						 customCookie, customCookieLen);
					if(_ILExecThreadHasException(thread))
					{
						return 1;
					}
					++args;
					++stacktop;
				}
				continue;
			}
		}

		/* Marshal the parameter directly */
		paramType = ILTypeGetEnumType(ILTypeGetParam(signature, param));
		if(ILType_IsPrimitive(paramType))
		{
			/* Process a primitive value */
			switch(ILType_ToElement(paramType))
			{
				case IL_META_ELEMTYPE_VOID:		break;

				case IL_META_ELEMTYPE_BOOLEAN:
				case IL_META_ELEMTYPE_I1:
				case IL_META_ELEMTYPE_U1:
				case IL_META_ELEMTYPE_I2:
				case IL_META_ELEMTYPE_U2:
				case IL_META_ELEMTYPE_CHAR:
				case IL_META_ELEMTYPE_I4:
				case IL_META_ELEMTYPE_U4:
			#ifdef IL_NATIVE_INT32
				case IL_META_ELEMTYPE_I:
				case IL_META_ELEMTYPE_U:
			#endif
				{
					CHECK_SPACE(1);
					stacktop->intValue = *((ILInt32 *)(*args));
					++args;
					++stacktop;
				}
				break;

				case IL_META_ELEMTYPE_I8:
				case IL_META_ELEMTYPE_U8:
			#ifdef IL_NATIVE_INT64
				case IL_META_ELEMTYPE_I:
				case IL_META_ELEMTYPE_U:
			#endif
				{
					CHECK_SPACE(CVM_WORDS_PER_LONG);
					ILMemCpy(stacktop, *args, sizeof(ILInt64));
					++args;
					stacktop += CVM_WORDS_PER_LONG;
				}
				break;

				case IL_META_ELEMTYPE_R4:
				{
					CHECK_SPACE(CVM_WORDS_PER_NATIVE_FLOAT);
					tempFloat = (ILNativeFloat)(*((ILFloat *)(*args)));
					ILMemCpy(stacktop, &tempFloat, sizeof(ILNativeFloat));
					++args;
					stacktop += CVM_WORDS_PER_NATIVE_FLOAT;
				}
				break;

				case IL_META_ELEMTYPE_R8:
				{
					CHECK_SPACE(CVM_WORDS_PER_NATIVE_FLOAT);
					tempFloat = (ILNativeFloat)(*((ILDouble *)(*args)));
					ILMemCpy(stacktop, &tempFloat, sizeof(ILNativeFloat));
					++args;
					stacktop += CVM_WORDS_PER_NATIVE_FLOAT;
				}
				break;

				case IL_META_ELEMTYPE_R:
				{
					CHECK_SPACE(CVM_WORDS_PER_NATIVE_FLOAT);
					ILMemCpy(stacktop, *args, sizeof(ILNativeFloat));
					++args;
					stacktop += CVM_WORDS_PER_NATIVE_FLOAT;
				}
				break;

				case IL_META_ELEMTYPE_TYPEDBYREF:
				{
					CHECK_SPACE(CVM_WORDS_PER_TYPED_REF);
					ILMemCpy(stacktop, *args, sizeof(ILTypedRef));
					++args;
					stacktop += CVM_WORDS_PER_TYPED_REF;
				}
				break;
			}
		}
		else if(ILType_IsClass(paramType))
		{
			/* Process an object reference */
			CHECK_SPACE(1);
			stacktop->ptrValue = *((void **)(*args));
			++args;
			++stacktop;
		}
		else if(ILType_IsValueType(paramType))
		{
			/* Process a value type which was passed by value */
			ptr = *args;
			++args;
			size = ILSizeOfType(thread, paramType);
			sizeInWords = ((size + sizeof(CVMWord) - 1) / sizeof(CVMWord));
			CHECK_SPACE(sizeInWords);
			ILMemCpy(stacktop, ptr, size);
			stacktop += sizeInWords;
		}
		else if(paramType != 0 && ILType_IsComplex(paramType) &&
				(ILType_Kind(paramType) == IL_TYPE_COMPLEX_BYREF || 
				 ILType_Kind(paramType) == IL_TYPE_COMPLEX_PTR))
		{
			/* Process a value that is being passed by reference */
			CHECK_SPACE(1);
			stacktop->ptrValue = *((void **)(*args));
			++args;
			++stacktop;
		}
		else
		{
			/* Assume that everything else is an object reference */
			CHECK_SPACE(1);
			stacktop->ptrValue = *args;
			++args;
			++stacktop;
		}
	}

	/* Update the stack top */
	thread->stackTop = stacktop;
	return 0;
}
/*!
******************************************************************************

 @Function	PVRSRVGetMiscInfoKM

 @Description
	Retrieves misc. info.

 @Output PVRSRV_MISC_INFO

 @Return   PVRSRV_ERROR :

******************************************************************************/
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo)
{
	SYS_DATA *psSysData;

	if(!psMiscInfo)
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	psMiscInfo->ui32StatePresent = 0;

	/* do a basic check for uninitialised request flag */
	if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT
										|PVRSRV_MISC_INFO_CLOCKGATE_PRESENT
										|PVRSRV_MISC_INFO_MEMSTATS_PRESENT
										|PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT
										|PVRSRV_MISC_INFO_DDKVERSION_PRESENT
										|PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT
										|PVRSRV_MISC_INFO_RESET_PRESENT
										|PVRSRV_MISC_INFO_FREEMEM_PRESENT
										|PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT
										|PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT
										|PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT))
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	SysAcquireData(&psSysData);

	/* return SOC Timer registers */
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
		(psSysData->pvSOCTimerRegisterKM != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
		psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle;
	}
	else
	{
		psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL;
	}

	/* return SOC Clock Gating registers */
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
		(psSysData->pvSOCClockGateRegsBase != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
		psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase;
		psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize;
	}

	/* memory stats */
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
		(psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		RA_ARENA			**ppArena;
/*		BM_HEAP				*psBMHeap;
		BM_CONTEXT			*psBMContext;
		PVRSRV_DEVICE_NODE	*psDeviceNode;*/
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;

		/* Local backing stores */
		ppArena = &psSysData->apsLocalDevMemArena[0];
		while(*ppArena)
		{
			CHECK_SPACE(ui32StrLen);
			i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

			RA_GetStats(*ppArena,
							&pszStr,
							&ui32StrLen);
			/* advance through the array */
			ppArena++;
		}

		/* per device */
/*		psDeviceNode = psSysData->psDeviceNodeList;*/

		/*triple loop; devices:contexts:heaps*/
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_MEMSTATS_PRESENT);

		/* attach a new line and string terminate */
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	/* Lean version of mem stats: only show free mem on each RA */
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0)
		&& psMiscInfo->pszMemoryStr)
	{
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;
		
		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;
  
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FREEMEM_PRESENT;

		/* triple loop over devices:contexts:heaps */
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_FREEMEM_PRESENT);
		
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
		(psSysData->psGlobalEventObject != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
		psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject;
	}

	/* DDK version and memstats not supported in same call to GetMiscInfo */

	if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL)
		&& ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL)
		&& (psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		IMG_CHAR	*pszStr;
		IMG_UINT32	ui32StrLen;
		IMG_UINT32 	ui32LenStrPerNum = 12; /* string length per UI32: 10 digits + '.' + '\0' = 12 bytes */
		IMG_INT32	i32Count;
		IMG_INT i;
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;

		/* construct DDK string */
		psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ;
		psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN;
		psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BUILD_HI;
		psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD_LO;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		for (i=0; i<4; i++)
		{
			if (ui32StrLen < ui32LenStrPerNum)
			{
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%u", psMiscInfo->aui32DDKVersion[i]);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			if (i != 3)
			{
				i32Count = OSSNPrintf(pszStr, 2, ".");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			}
		}
	}

	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT) != 0UL)
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT;

		if(psMiscInfo->sCacheOpCtl.bDeferOp)
		{
			/* For now, assume deferred ops are "full" cache ops,
			 * and we don't need (or expect) a meminfo.
			 */
			psSysData->ePendingCacheOpType = psMiscInfo->sCacheOpCtl.eCacheOpType;
		}
		else
		{
			PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
			PVRSRV_PER_PROCESS_DATA *psPerProc;

			if(!psMiscInfo->sCacheOpCtl.u.psKernelMemInfo)
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Ignoring non-deferred cache op with no meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			if(psSysData->ePendingCacheOpType != PVRSRV_MISC_INFO_CPUCACHEOP_NONE)
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Deferred cache op is pending. It is unlikely you want "
						 "to combine deferred cache ops with immediate ones"));
			}

			psPerProc = PVRSRVFindPerProcessData();

			if(PVRSRVLookupHandle(psPerProc->psHandleBase,
								  (IMG_PVOID *)&psKernelMemInfo,
								  psMiscInfo->sCacheOpCtl.u.psKernelMemInfo,
								  PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
			{
				PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
						 "Can't find kernel meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH)
			{
				if(!OSFlushCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
										   0,
										   psMiscInfo->sCacheOpCtl.pvBaseVAddr,
										   psMiscInfo->sCacheOpCtl.ui32Length))
				{
					return PVRSRV_ERROR_CACHEOP_FAILED;
				}
			}
			else if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN)
			{
				if(psMiscInfo->sCacheOpCtl.ui32Length!=0)
				{
					if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
											   0,
											   psMiscInfo->sCacheOpCtl.pvBaseVAddr,
											   psMiscInfo->sCacheOpCtl.ui32Length))
					{
						return PVRSRV_ERROR_CACHEOP_FAILED;
					}
				}
			}
		}
	}

	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT) != 0UL)
	{
		PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
		PVRSRV_PER_PROCESS_DATA *psPerProc;

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT;

		psPerProc = PVRSRVFindPerProcessData();

		if(PVRSRVLookupHandle(psPerProc->psHandleBase,
							  (IMG_PVOID *)&psKernelMemInfo,
							  psMiscInfo->sGetRefCountCtl.u.psKernelMemInfo,
							  PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
		{
			PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
									"Can't find kernel meminfo"));
			return PVRSRV_ERROR_INVALID_PARAMS;
		}

		psMiscInfo->sGetRefCountCtl.ui32RefCount = psKernelMemInfo->ui32RefCount;
	}

	if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT) != 0UL)
	{
		psMiscInfo->ui32PageSize = HOST_PAGESIZE();
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT;
	}

#if defined(PVRSRV_RESET_ON_HWTIMEOUT)
	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL)
	{
		PVR_LOG(("User requested OS reset"));
		OSPanic();
	}
#endif /* #if defined(PVRSRV_RESET_ON_HWTIMEOUT) */

#if defined(SUPPORT_PVRSRV_DEVICE_CLASS)
	if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT) != 0UL)
	{
		PVRSRVProcessQueues(IMG_TRUE);
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT;
	}
#endif /* defined(SUPPORT_PVRSRV_DEVICE_CLASS) */

	return PVRSRV_OK;
}
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo)
#endif
{
	SYS_DATA *psSysData;

	if(!psMiscInfo)
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	psMiscInfo->ui32StatePresent = 0;

	
	if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT
										|PVRSRV_MISC_INFO_CLOCKGATE_PRESENT
										|PVRSRV_MISC_INFO_MEMSTATS_PRESENT
										|PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT
										|PVRSRV_MISC_INFO_DDKVERSION_PRESENT
										|PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT
										|PVRSRV_MISC_INFO_RESET_PRESENT
										|PVRSRV_MISC_INFO_FREEMEM_PRESENT))
	{
		PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	SysAcquireData(&psSysData);

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
		(psSysData->pvSOCTimerRegisterKM != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
		psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle;
	}
	else
	{
		psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL;
		psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
		(psSysData->pvSOCClockGateRegsBase != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
		psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase;
		psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize;
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
		(psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		RA_ARENA			**ppArena;
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;

		
		ppArena = &psSysData->apsLocalDevMemArena[0];
		while(*ppArena)
		{
			CHECK_SPACE(ui32StrLen);
			i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);

			RA_GetStats(*ppArena,
							&pszStr,
							&ui32StrLen);
			
			ppArena++;
		}

		
		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_MEMSTATS_PRESENT);

		
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	
	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0)
		&& psMiscInfo->pszMemoryStr)
	{
		IMG_CHAR			*pszStr;
		IMG_UINT32			ui32StrLen;
		IMG_INT32			i32Count;
		
		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;
  
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FREEMEM_PRESENT;

		
		List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
													&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
													&ui32StrLen,
													&i32Count,
													&pszStr,
													PVRSRV_MISC_INFO_FREEMEM_PRESENT);
		
		i32Count = OSSNPrintf(pszStr, 100, "\n");
		UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
	}

	if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
		(psSysData->psGlobalEventObject != IMG_NULL))
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
		psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject;
	}

	

	if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL)
		&& ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL)
		&& (psMiscInfo->pszMemoryStr != IMG_NULL))
	{
		IMG_CHAR	*pszStr;
		IMG_UINT32	ui32StrLen;
		IMG_UINT32 	ui32LenStrPerNum = 12; 
		IMG_INT32	i32Count;
		IMG_INT i;
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;

		
		psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ;
		psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN;
		psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BRANCH;
		psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD;

		pszStr = psMiscInfo->pszMemoryStr;
		ui32StrLen = psMiscInfo->ui32MemoryStrLen;

		for (i=0; i<4; i++)
		{
			if (ui32StrLen < ui32LenStrPerNum)
			{
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%u", psMiscInfo->aui32DDKVersion[i]);
			UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			if (i != 3)
			{
				i32Count = OSSNPrintf(pszStr, 2, ".");
				UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
			}
		}
	}

	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT) != 0UL)
	{
		psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT;

		if(psMiscInfo->sCacheOpCtl.bDeferOp)
		{
			
			psSysData->ePendingCacheOpType = psMiscInfo->sCacheOpCtl.eCacheOpType;
		}
		else
		{
#if defined (SUPPORT_SID_INTERFACE)
			PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo = psMiscInfo->sCacheOpCtl.psKernelMemInfo;

			if(!psMiscInfo->sCacheOpCtl.psKernelMemInfo)
#else
			PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
			PVRSRV_PER_PROCESS_DATA *psPerProc;

			if(!psMiscInfo->sCacheOpCtl.u.psKernelMemInfo)
#endif
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Ignoring non-deferred cache op with no meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}

			if(psSysData->ePendingCacheOpType != PVRSRV_MISC_INFO_CPUCACHEOP_NONE)
			{
				PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
						 "Deferred cache op is pending. It is unlikely you want "
						 "to combine deferred cache ops with immediate ones"));
			}

#if defined (SUPPORT_SID_INTERFACE)
			PVR_DBG_BREAK
#else
			
			psPerProc = PVRSRVFindPerProcessData();

			if(PVRSRVLookupHandle(psPerProc->psHandleBase,
								  (IMG_PVOID *)&psKernelMemInfo,
								  psMiscInfo->sCacheOpCtl.u.psKernelMemInfo,
								  PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
			{
				PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
						 "Can't find kernel meminfo"));
				return PVRSRV_ERROR_INVALID_PARAMS;
			}
#endif

			if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH)
			{
				if(!OSFlushCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
										   psMiscInfo->sCacheOpCtl.pvBaseVAddr,
										   psMiscInfo->sCacheOpCtl.ui32Length))
				{
					return PVRSRV_ERROR_CACHEOP_FAILED;
				}
			}
			else if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN)
			{
				if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
										   psMiscInfo->sCacheOpCtl.pvBaseVAddr,
										   psMiscInfo->sCacheOpCtl.ui32Length))
				{
					return PVRSRV_ERROR_CACHEOP_FAILED;
				}
			}
/* FIXME: Temporary fix needs to be revisited
 * LinuxMemArea struct listing is not registered for memory areas
 * wrapped through PVR2DMemWrap() call. For now, we are doing
 * cache flush/inv by grabbing the physical pages through
 * get_user_pages() for every blt call.
 */
			else if (psMiscInfo->sCacheOpCtl.eCacheOpType ==
						PVRSRV_MISC_INFO_CPUCACHEOP_CUSTOM_FLUSH)
			{
#if defined(CONFIG_OUTER_CACHE) && defined(PVR_NO_FULL_CACHE_OPS)
				if (1)
				{
					IMG_SIZE_T 	uPageOffset, uPageCount;
					IMG_VOID	*pvPageAlignedCPUVAddr;
					IMG_SYS_PHYADDR	 	*psIntSysPAddr = IMG_NULL;
					IMG_HANDLE	hOSWrapMem = IMG_NULL;
					PVRSRV_ERROR eError;
					int i;

					uPageOffset = (IMG_UINTPTR_T)psMiscInfo->sCacheOpCtl.pvBaseVAddr & (HOST_PAGESIZE() - 1);
					uPageCount =
						HOST_PAGEALIGN(psMiscInfo->sCacheOpCtl.ui32Length + uPageOffset)/HOST_PAGESIZE();
					pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINTPTR_T)psMiscInfo->sCacheOpCtl.pvBaseVAddr - uPageOffset);

					if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
						uPageCount * sizeof(IMG_SYS_PHYADDR),
						(IMG_VOID **)&psIntSysPAddr, IMG_NULL,
						"Array of Page Addresses") != PVRSRV_OK)
					{
						PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: Failed to alloc memory for block"));
						return PVRSRV_ERROR_OUT_OF_MEMORY;
					}

					eError = OSAcquirePhysPageAddr(pvPageAlignedCPUVAddr,
										uPageCount * HOST_PAGESIZE(),
										psIntSysPAddr,
										&hOSWrapMem);
					for (i = 0; i < uPageCount; i++)
					{
						outer_flush_range(psIntSysPAddr[i].uiAddr, psIntSysPAddr[i].uiAddr + HOST_PAGESIZE() -1);
					}

					OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
						uPageCount * sizeof(IMG_SYS_PHYADDR),
						psIntSysPAddr, IMG_NULL);

					OSReleasePhysPageAddr(hOSWrapMem);

				}
#else
				OSFlushCPUCacheKM();
#endif /* CONFIG_OUTER_CACHE && PVR_NO_FULL_CACHE_OPS*/
			}
			else if (psMiscInfo->sCacheOpCtl.eCacheOpType ==
							PVRSRV_MISC_INFO_CPUCACHEOP_CUSTOM_INV)
			{
#if defined(CONFIG_OUTER_CACHE)
				/* TODO: Need to check full cache invalidation, but
				 * currently it is not exported through
				 * outer_cache interface.
				 */
				if (1)
				{
					IMG_SIZE_T 	uPageOffset, uPageCount;
					IMG_VOID	*pvPageAlignedCPUVAddr;
					IMG_SYS_PHYADDR	 	*psIntSysPAddr = IMG_NULL;
					IMG_HANDLE	hOSWrapMem = IMG_NULL;
					PVRSRV_ERROR eError;
					int i;

					uPageOffset = (IMG_UINTPTR_T)psMiscInfo->sCacheOpCtl.pvBaseVAddr & (HOST_PAGESIZE() - 1);
					uPageCount =
						HOST_PAGEALIGN(psMiscInfo->sCacheOpCtl.ui32Length + uPageOffset)/HOST_PAGESIZE();
					pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINTPTR_T)psMiscInfo->sCacheOpCtl.pvBaseVAddr - uPageOffset);

					if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
						uPageCount * sizeof(IMG_SYS_PHYADDR),
						(IMG_VOID **)&psIntSysPAddr, IMG_NULL,
						"Array of Page Addresses") != PVRSRV_OK)
					{
						PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: Failed to alloc memory for block"));
						return PVRSRV_ERROR_OUT_OF_MEMORY;
					}

					eError = OSAcquirePhysPageAddr(pvPageAlignedCPUVAddr,
										uPageCount * HOST_PAGESIZE(),
										psIntSysPAddr,
										&hOSWrapMem);
					for (i = 0; i < uPageCount; i++)
					{
						outer_inv_range(psIntSysPAddr[i].uiAddr, psIntSysPAddr[i].uiAddr + HOST_PAGESIZE() -1);
					}

					OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
						uPageCount * sizeof(IMG_SYS_PHYADDR),
						psIntSysPAddr, IMG_NULL);

					OSReleasePhysPageAddr(hOSWrapMem);

				}

#endif /* CONFIG_OUTER_CACHE */
			}

		}
	}

#if defined(PVRSRV_RESET_ON_HWTIMEOUT)
	if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL)
	{
		PVR_LOG(("User requested OS reset"));
		OSPanic();
	}
#endif 

	return PVRSRV_OK;
}
Exemple #17
0
static size_t
xstrftime(
    char *str,			/* output buffer */
    size_t bsz,			/* space available */
    const char *fmt,
    struct tm *tm)
{
    size_t l = 0;			/* chars written so far */

    char *s = str;

    memset(s, '\0', bsz);

    while (*fmt != '\0') {
        if (*fmt != '%') {
            if (l >= bsz)
                return (0);
            *s++ = *fmt++;
            l++;
        } else {
            /* set up format modifiers */
            int w = 0;
            int z = 0;

            if (*++fmt == '0') {
                z = 1;
                ++fmt;
            }
            while (*fmt >= '0' && *fmt <= '9') {
                w = w * 10 + (*fmt - '0');
                ++fmt;
            }

            switch (*fmt++) {

                /* some shorthands : check that there is space in the
                 * output string. */
#define CHECK_SPACE(n) do {				\
		    if ((l+(n)) > bsz) return 0;	\
		} while (0)

                /* copy a fixed string, checking that there's room */
#define COPY_STRING(z) do {			\
		    CHECK_SPACE(strlen(z)) ;	\
		    strcpy(s, z);		\
		} while (0)

                /* format a string, using default spec if none given w
                 * and z are width and zero-flag dw and dz are the
                 * defaults for these In fact, CHECK_SPACE(w) is not a
                 * sufficient test, since sprintf("%2d", 365) outputs
                 * three characters
                 */
#define FORMAT_STRING(dz, dw, x) do {				\
		    if (w==0) {					\
			w=(dw);					\
			if (!z)					\
			    z=(dz);				\
		    }						\
		    CHECK_SPACE(w);				\
		    sprintf(s, z ? "%0*d" : "%*d", w, (x));	\
		} while(0)

            case '%':
                CHECK_SPACE(1);
                *s = '%';
                break;

            case 'a':
                COPY_STRING(abbrev_day_names[tm->tm_wday]);
                break;

            case 'A':
                COPY_STRING(full_day_names[tm->tm_wday]);
                break;

            case 'b':
            case 'h':
                COPY_STRING(abbrev_month_names[tm->tm_mon]);
                break;

            case 'B':
                COPY_STRING(full_month_names[tm->tm_mon]);
                break;


#if 0
            /* %x not currently supported, so neither is c */
            case 'c':
                if (!xstrftime(s, bsz - l, "%x %X", tm))
                    return (0);
                break;
#endif

            case 'd':
                FORMAT_STRING(1, 2, tm->tm_mday);	/* %02d */
                break;

            case 'D':
                if (!xstrftime(s, bsz - l, "%m/%d/%y", tm))
                    return (0);
                break;

            case 'F':
                if (!xstrftime(s, bsz - l, "%Y-%m-%d", tm))
                    return (0);
                break;

            case 'H':
                FORMAT_STRING(1, 2, tm->tm_hour);	/* %02d */
                break;

            case 'I':
                FORMAT_STRING(1, 2, (tm->tm_hour + 11) % 12 + 1); /* %02d */
                break;

            case 'j':
                FORMAT_STRING(1, 3, tm->tm_yday + 1);	/* %03d */
                break;

            /* not in linux strftime man page. Not really needed now */
            case 'k':
                FORMAT_STRING(0, 2, tm->tm_hour);	/* %2d */
                break;

            case 'l':
                FORMAT_STRING(0, 2, (tm->tm_hour + 11) % 12 + 1); /* %2d */
                break;

            case 'm':
                FORMAT_STRING(1, 2, tm->tm_mon + 1);	/* %02d */
                break;

            case 'M':
                FORMAT_STRING(1, 2, tm->tm_min);	/* %02d */
                break;

            case 'p':
                CHECK_SPACE(2);
                strcpy(s, (tm->tm_hour < 12) ? "am" : "pm");
                break;

            case 'r':
                if (!xstrftime(s, bsz - l, "%I:%M:%S %p", tm))
                    return (0);
                break;

            case 'R':
                if (!xstrftime(s, bsz - l, "%H:%M", tm))
                    return (0);
                break;

            case 'S':
                FORMAT_STRING(1, 2, tm->tm_sec);	/* %02d */
                break;

            case 'T':
                if (!xstrftime(s, bsz - l, "%H:%M:%S", tm))
                    return (0);
                break;

            case 'W':		/* mon 1 day of week */
            {
                int week;
                if (tm->tm_yday <= tm->tm_wday) {
                    week = 1;

                    if ((tm->tm_mday - tm->tm_yday) > 4) {
                        week = 52;
                    }
                    if (tm->tm_yday == tm->tm_wday && tm->tm_wday == 0)
                        week = 52;

                } else {

                    /* sun prev week */
                    int bw = tm->tm_yday - tm->tm_wday;

                    if (tm->tm_wday > 0)
                        bw += 7;	/* sun end of week */

                    week = (int) bw / 7;

                    if ((bw % 7) > 2)	/* jan 1 is before friday */
                        week++;
                }
                FORMAT_STRING(1, 2, week);	/* %02d */
                break;
            }

            case 'U':		/* sun 1 day of week */
            {
                int week, bw;

                if (tm->tm_yday <= tm->tm_wday) {
                    week = 1;
                    if ((tm->tm_mday - tm->tm_yday) > 4) {
                        week = 52;
                    }
                } else {
                    /* sat prev week */
                    bw = tm->tm_yday - tm->tm_wday - 1;
                    if (tm->tm_wday >= 0)
                        bw += 7;	/* sat end of week */
                    week = (int) bw / 7;
                    if ((bw % 7) > 1) {	/* jan 1 is before friday */
                        week++;
                    }
                }
                FORMAT_STRING(1, 2, week);	/* %02d */
                break;
            }

            case 'w':		/* day of week, sun=0 */
                FORMAT_STRING(1, 2, tm->tm_wday);	/* %02d */
                break;

            case 'y':
                FORMAT_STRING(1, 2, tm->tm_year % 100);		/* %02d */
                break;

            case 'Y':
                FORMAT_STRING(1, 4, tm->tm_year);	/* %04d */
                break;

#if 0
            case 'Z':
                COPY_STRING(tm->tm_zone);
                break;
#endif
            }			/* switch */

            while (*s != '\0') {
                s++;
                l++;
            }
#undef CHECK_SPACE
#undef COPY_STRING
#undef FORMAT_STRING
        } /* switch(fmt letter) */
    } /* if(fmt letter not '%') */
    return (l);
}