Ejemplo n.º 1
0
PVRSRV_ERROR
PhysmemImportIon(CONNECTION_DATA *psConnection,
				 IMG_INT fd,
				 PVRSRV_MEMALLOCFLAGS_T uiFlags,
				 PMR **ppsPMRPtr,
				 IMG_DEVMEM_SIZE_T *puiSize,
				 IMG_DEVMEM_ALIGN_T *puiAlign)
{
	PMR_ION_DATA *psPrivData = IMG_NULL;
	IMG_HANDLE hPDumpAllocInfo = IMG_NULL;
	ENV_CONNECTION_DATA *psEnvConnectionData;
	PMR *psPMR = IMG_NULL;
	PMR_FLAGS_T uiPMRFlags;
    IMG_BOOL bZero;
    IMG_BOOL bPoisonOnAlloc;
    IMG_BOOL bPoisonOnFree;
	IMG_BOOL bMappingTable = IMG_TRUE;
	PVRSRV_ERROR eError;

    if (uiFlags & PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC)
    {
        bZero = IMG_TRUE;
    }
    else
    {
        bZero = IMG_FALSE;
    }

    if (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_ALLOC)
    {
        bPoisonOnAlloc = IMG_TRUE;
    }
    else
    {
        bPoisonOnAlloc = IMG_FALSE;
    }

    if (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_FREE)
    {
        bPoisonOnFree = IMG_TRUE;
    }
    else
    {
        bPoisonOnFree = IMG_FALSE;
    }

    if ((uiFlags & PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC) &&
        (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_ALLOC))
    {
        /* Zero on Alloc and Poison on Alloc are mutually exclusive */
        eError = PVRSRV_ERROR_INVALID_PARAMS;
        goto fail_params;
    }

	psPrivData = kmalloc(sizeof(*psPrivData), GFP_KERNEL);
	if (psPrivData == NULL)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto fail_privalloc;
	}

	/*
		Get the physical heap for this PMR
		
		Note:
		While we have no way to determine the type of the buffer
		we just assume that all Ion buffers are from the same
		physical heap.
	*/
	eError = PhysHeapAcquire(IonPhysHeapID(), &psPrivData->psPhysHeap);
	if (eError != PVRSRV_OK)
	{
		goto fail_physheap;
	}

	/* Get the ion client from this connection */
	psEnvConnectionData = PVRSRVConnectionPrivateData(psConnection);
	psPrivData->psIonClient = EnvDataIonClientGet(psEnvConnectionData);

	/* Get the buffer handle */
	psPrivData->psIonHandle = ion_import_fd(psPrivData->psIonClient, fd);
	if (psPrivData->psIonHandle == IMG_NULL)
	{
		/* FIXME: add ion specific error? */
		eError = PVRSRV_ERROR_BAD_MAPPING;
		goto fail_ionimport;
	}

	/*
		Note:

		We could defer the import until lock address time but we
		do it here as then we can detect any errors at import time.
		Also we need to know the ion buffer size here and there seems
		to be no other way to find that other then map the buffer for dma.
	*/
	eError = IonPhysAddrAcquire(psPrivData,
							   fd);
	if (eError != PVRSRV_OK)
	{
		goto fail_acquire;
	}

	if (bZero || bPoisonOnAlloc)
	{
		IMG_PVOID pvKernAddr;

		pvKernAddr = ion_map_kernel(psPrivData->psIonClient, psPrivData->psIonHandle);

		if (IS_ERR(pvKernAddr))
		{
			eError = PVRSRV_ERROR_PMR_NO_KERNEL_MAPPING;
			goto fail_kernelmap;
		}

		if (bZero)
		{
			memset(pvKernAddr, 0, psPrivData->uiSize);
		}
		else
		{
			_Poison(pvKernAddr,
					psPrivData->uiSize,
					_AllocPoison,
					_AllocPoisonSize);
		}

		ion_unmap_kernel(psPrivData->psIonClient, psPrivData->psIonHandle);
	}

	psPrivData->bPoisonOnFree = bPoisonOnFree;

	uiPMRFlags = (PMR_FLAGS_T)(uiFlags & PVRSRV_MEMALLOCFLAGS_PMRFLAGSMASK);
	/* check no significant bits were lost in cast due to different
	   bit widths for flags */
	PVR_ASSERT(uiPMRFlags == (uiFlags & PVRSRV_MEMALLOCFLAGS_PMRFLAGSMASK));

	eError = PMRCreatePMR(psPrivData->psPhysHeap,
						  psPrivData->uiSize,
                          psPrivData->uiSize,
                          1,
                          1,
                          &bMappingTable,
						  PAGE_SHIFT,
						  uiPMRFlags,
						  "PMRION",
						  &_sPMRIonFuncTab,
						  psPrivData,
						  &psPMR);
	if (eError != PVRSRV_OK)
	{
		goto fail_pmrcreate;
	}

	_PDumpPMRMalloc(psPMR,
					psPrivData->uiSize,
					PAGE_SIZE,
					&hPDumpAllocInfo);
	psPrivData->hPDumpAllocInfo = hPDumpAllocInfo;
	psPrivData->bPDumpMalloced = IMG_TRUE;

	*ppsPMRPtr = psPMR;
	*puiSize = psPrivData->uiSize;
	*puiAlign = PAGE_SIZE;
	return PVRSRV_OK;

fail_pmrcreate:
fail_kernelmap:
	IonPhysAddrRelease(psPrivData);
fail_acquire:
	ion_free(psPrivData->psIonClient, psPrivData->psIonHandle);
fail_ionimport:
	PhysHeapRelease(psPrivData->psPhysHeap);
fail_physheap:
	kfree(psPrivData);

fail_privalloc:
fail_params:
	PVR_ASSERT(eError != PVRSRV_OK);
	return eError;
}
PVRSRV_ERROR OSSecureExport(CONNECTION_DATA *psConnection,
							IMG_PVOID pvData,
							IMG_SECURE_TYPE *phSecure,
							CONNECTION_DATA **ppsSecureConnection)
{
	ENV_CONNECTION_DATA *psEnvConnection;
	CONNECTION_DATA *psSecureConnection;
	struct file *connection_file;
	struct file *secure_file;
	struct dentry *secure_dentry;
	struct vfsmount *secure_mnt;
	int secure_fd;
	IMG_BOOL bPmrUnlocked = IMG_FALSE;
	PVRSRV_ERROR eError;

	/* Obtain the current connections struct file */
	psEnvConnection = PVRSRVConnectionPrivateData(psConnection);
	connection_file = LinuxFileFromEnvConnection(psEnvConnection);

	/* Allocate a fd number */
	secure_fd = get_unused_fd();
	if (secure_fd < 0)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto e0;
	}

	/*
		Get a reference to the dentry so when close is called we don't
		drop the last reference too early and delete the file
	*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
	secure_dentry = dget(connection_file->f_path.dentry);
	secure_mnt = mntget(connection_file->f_path.mnt);
#else
	secure_dentry = dget(connection_file->f_dentry);
	secure_mnt = mntget(connection_file->f_vfsmnt);
#endif

	/* PMR lock needs to be released before bridge lock to keep lock hierarchy
	* and avoid deadlock situation.
	* OSSecureExport() can be called from functions that are not acquiring
	* PMR lock (e.g. by PVRSRVSyncPrimServerSecureExportKM()) so we have to
	* check if PMR lock is locked. */
	if (PMRIsLockedByMe())
	{
		PMRUnlock();
		bPmrUnlocked = IMG_TRUE;
	}
	OSReleaseBridgeLock();

	/* Open our device (using the file information from our current connection) */
	secure_file = dentry_open(
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
					  &connection_file->f_path,
#else
					  connection_file->f_dentry,
					  connection_file->f_vfsmnt,
#endif
					  connection_file->f_flags,
					  current_cred());

	OSAcquireBridgeLock();
	if (bPmrUnlocked)
		PMRLock();

	/* Bail if the open failed */
	if (IS_ERR(secure_file))
	{
		put_unused_fd(secure_fd);
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto e0;
	}

	/* Bind our struct file with it's fd number */
	fd_install(secure_fd, secure_file);

	/* Return the new services connection our secure data created */
#if defined(SUPPORT_DRM)
	psSecureConnection = LinuxConnectionFromFile(PVR_DRM_FILE_FROM_FILE(secure_file));
#else
	psSecureConnection = LinuxConnectionFromFile(secure_file);
#endif

	/* Save the private data */
	PVR_ASSERT(psSecureConnection->hSecureData == IMG_NULL);
	psSecureConnection->hSecureData = pvData;

	*phSecure = secure_fd;
	*ppsSecureConnection = psSecureConnection;
	return PVRSRV_OK;

e0:
	PVR_ASSERT(eError != PVRSRV_OK);
	return eError;
}
Ejemplo n.º 3
0
PVRSRV_ERROR OSSecureExport(CONNECTION_DATA *psConnection,
							IMG_PVOID pvData,
							IMG_SECURE_TYPE *phSecure,
							CONNECTION_DATA **ppsSecureConnection)
{
	ENV_CONNECTION_DATA *psEnvConnection;
	CONNECTION_DATA *psSecureConnection;
	struct file *connection_file;
	struct file *secure_file;
	struct dentry *secure_dentry;
	struct vfsmount *secure_mnt;
	int secure_fd;
	PVRSRV_ERROR eError;

	/* Obtain the current connections struct file */
	psEnvConnection = PVRSRVConnectionPrivateData(psConnection);
	connection_file = LinuxFileFromEnvConnection(psEnvConnection);

	/* Allocate a fd number */
	secure_fd = get_unused_fd();
	if (secure_fd < 0)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto e0;
	}

	/*
		Get a reference to the dentry so when close is called we don't
		drop the last reference too early and delete the file
	*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
	secure_dentry = dget(connection_file->f_path.dentry);
	secure_mnt = mntget(connection_file->f_path.mnt);
#else
	secure_dentry = dget(connection_file->f_dentry);
	secure_mnt = mntget(connection_file->f_vfsmnt);
#endif

	
	mutex_unlock(&gPVRSRVLock);

	/* Open our device (using the file information from our current connection) */
	secure_file = dentry_open(
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
					  &connection_file->f_path,
#else
					  connection_file->f_dentry,
					  connection_file->f_vfsmnt,
#endif
					  connection_file->f_flags,
					  current_cred());

	mutex_lock(&gPVRSRVLock);

	/* Bail if the open failed */
	if (IS_ERR(secure_file))
	{
		put_unused_fd(secure_fd);
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto e0;
	}

	/* Bind our struct file with it's fd number */
	fd_install(secure_fd, secure_file);

	/* Return the new services connection our secure data created */
#if defined(SUPPORT_DRM)
	psSecureConnection = LinuxConnectionFromFile(PVR_DRM_FILE_FROM_FILE(secure_file));
#else
	psSecureConnection = LinuxConnectionFromFile(secure_file);
#endif

	/* Save the private data */
	PVR_ASSERT(psSecureConnection->hSecureData == IMG_NULL);
	psSecureConnection->hSecureData = pvData;

	*phSecure = secure_fd;
	*ppsSecureConnection = psSecureConnection;
	return PVRSRV_OK;

e0:
	PVR_ASSERT(eError != PVRSRV_OK);
	return eError;
}