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; }
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; }