#include #include #include #include #include #include #include #include #include #include #include #include #include "xf86drm.h" #define DRM_PVR_RESERVED1 (DRM_COMMAND_BASE + 0) #define DRM_PVR_RESERVED2 (DRM_COMMAND_BASE + 1) #define DRM_PVR_RESERVED3 (DRM_COMMAND_BASE + 2) #define DRM_PVR_RESERVED4 (DRM_COMMAND_BASE + 3) #define DRM_PVR_RESERVED5 (DRM_COMMAND_BASE + 4) #define DRM_PVR_RESERVED6 (DRM_COMMAND_BASE + 5) /* PVR includes */ #define SUPPORT_MEMINFO_IDS #define SUPPORT_DRI_DRM_EXT #include #include #include #include #include #include #include #include #include #define DRM_IOCTL_PVR_SRVKM DRM_IOWR(PVR_DRM_SRVKM_CMD, PVRSRV_BRIDGE_PACKAGE) #include "pvr_ioctl.h" static int false_fd = 10241024; #define PROLOG(func) \ static typeof(func) *orig_##func = NULL; \ if(!orig_##func) \ orig_##func = dlsym(RTLD_NEXT, #func); int open64(const char *pathname, int flags, ...) { printf("Called open64 on %s (%d)\n", pathname, flags); PROLOG(open64); int fd = orig_open64(pathname, flags); if (strcmp(pathname, "/dev/dri/renderD128") == 0) { printf("Spoofing FD!\n"); return false_fd; } return fd; } int fcntl(int fd, int op, int arg) { printf("Called fcntl on %d\n", fd); PROLOG(fcntl); if (fd == false_fd) return 0; return orig_fcntl(fd, op, arg); } PVRSRV_HEAP_INFO pvr_heaps[] = { { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_HEAP_ID), .hDevMemHeap = (void*)1, .sDevVAddrBase = {SGX_GENERAL_HEAP_BASE}, .ui32HeapByteSize = SGX_GENERAL_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_TADATA_HEAP_ID), .hDevMemHeap = (void*)2, .sDevVAddrBase = {SGX_TADATA_HEAP_BASE}, .ui32HeapByteSize = SGX_TADATA_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_CODE_HEAP_ID), .hDevMemHeap = (void*)3, .sDevVAddrBase = {SGX_KERNEL_CODE_HEAP_BASE}, .ui32HeapByteSize = SGX_KERNEL_CODE_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_DATA_HEAP_ID), .hDevMemHeap = (void*)4, .sDevVAddrBase = {SGX_KERNEL_DATA_HEAP_BASE}, .ui32HeapByteSize = SGX_KERNEL_DATA_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PIXELSHADER_HEAP_ID), .hDevMemHeap = (void*)5, .sDevVAddrBase = {SGX_PIXELSHADER_HEAP_BASE}, .ui32HeapByteSize = SGX_PIXELSHADER_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_VERTEXSHADER_HEAP_ID), .hDevMemHeap = (void*)6, .sDevVAddrBase = {SGX_VERTEXSHADER_HEAP_BASE}, .ui32HeapByteSize = SGX_VERTEXSHADER_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PDSPIXEL_CODEDATA_HEAP_ID), .hDevMemHeap = (void*)7, .sDevVAddrBase = {SGX_PDSPIXEL_CODEDATA_HEAP_BASE}, .ui32HeapByteSize = SGX_PDSPIXEL_CODEDATA_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PDSVERTEX_CODEDATA_HEAP_ID), .hDevMemHeap = (void*)8, .sDevVAddrBase = {SGX_PDSVERTEX_CODEDATA_HEAP_BASE}, .ui32HeapByteSize = SGX_PDSVERTEX_CODEDATA_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_SYNCINFO_HEAP_ID), .hDevMemHeap = (void*)9, .sDevVAddrBase = {SGX_SYNCINFO_HEAP_BASE}, .ui32HeapByteSize = SGX_SYNCINFO_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_SHARED_3DPARAMETERS_HEAP_ID), .hDevMemHeap = (void*)10, .sDevVAddrBase = {SGX_SHARED_3DPARAMETERS_HEAP_BASE}, .ui32HeapByteSize = SGX_SHARED_3DPARAMETERS_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS, }, { .ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PERCONTEXT_3DPARAMETERS_HEAP_ID), .hDevMemHeap = (void*)11, .sDevVAddrBase = {SGX_PERCONTEXT_3DPARAMETERS_HEAP_BASE}, .ui32HeapByteSize = SGX_PERCONTEXT_3DPARAMETERS_HEAP_SIZE, .ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS, }, }; #define DEV_NAME "pvr" #define DEV_DATE "20110701" #define DEV_DESC "Imagination Technologies PVR DRM" void get_misc_info(SGX_MISC_INFO *info) { switch(info->eRequest) { case SGX_MISC_INFO_REQUEST_DRIVER_SGXREV: info->uData.sSGXFeatures.ui32BuildOptions = SGX_BUILD_OPTIONS; info->uData.sSGXFeatures.ui32DDKBuild = 3759903; info->uData.sSGXFeatures.ui32DDKVersion = (1 << 16) | (14 << 8); break; default: printf("Unimplemented misc req %d\n", info->eRequest); assert(false); break; } } static bool pvrsrv_ioctl(int fd, PVRSRV_BRIDGE_PACKAGE *bridge_package) { int ioctl_nr = _IOC_NR(bridge_package->ui32BridgeID); printf(">>> pvr_ioctl(%s)(0x%x)\n", pvrsrv_ioctl_names[ioctl_nr], bridge_package->ui32BridgeID); switch(ioctl_nr) { case _IOC_NR(PVRSRV_BRIDGE_CONNECT_SERVICES): { PVRSRV_BRIDGE_OUT_CONNECT_SERVICES *data = bridge_package->pvParamOut; data->eError = PVRSRV_OK; data->hKernelServices = (void*)0x2; break; } case _IOC_NR(PVRSRV_BRIDGE_ENUM_DEVICES): { PVRSRV_BRIDGE_OUT_ENUMDEVICE *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->ui32NumDevices = 1; out->asDeviceIdentifier[0].eDeviceType = PVRSRV_DEVICE_TYPE_SGX; out->asDeviceIdentifier[0].eDeviceClass = PVRSRV_DEVICE_CLASS_3D; out->asDeviceIdentifier[0].ui32DeviceIndex = 0; out->asDeviceIdentifier[0].pszPDumpDevName = NULL; out->asDeviceIdentifier[0].pszPDumpRegName = NULL; break; } case _IOC_NR(PVRSRV_BRIDGE_ACQUIRE_DEVICEINFO): { PVRSRV_BRIDGE_OUT_ACQUIRE_DEVICEINFO *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->hDevCookie = (void*)0x1; break; } case _IOC_NR(PVRSRV_BRIDGE_SGX_GETMISCINFO): { printf("Get misc info!\n"); PVRSRV_BRIDGE_IN_SGXGETMISCINFO *in = bridge_package->pvParamIn; PVRSRV_BRIDGE_RETURN *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; get_misc_info(in->psMiscInfo); break; } case _IOC_NR(PVRSRV_BRIDGE_SGX_GETCLIENTINFO): { PVRSRV_BRIDGE_OUT_GETCLIENTINFO *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->sClientInfo.ui32ProcessID = getpid();; out->sClientInfo.pvProcess = NULL; PVRSRV_MISC_INFO *misc = &out->sClientInfo.sMiscInfo; misc->ui32StatePresent = 0; break; } case _IOC_NR(PVRSRV_BRIDGE_ENUM_CLASS): { PVRSRV_BRIDGE_OUT_ENUMDEVICE *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->ui32NumDevices = 1; out->asDeviceIdentifier[0].eDeviceType = PVRSRV_DEVICE_TYPE_SGX; out->asDeviceIdentifier[0].eDeviceClass = PVRSRV_DEVICE_CLASS_3D; out->asDeviceIdentifier[0].ui32DeviceIndex = 0; out->asDeviceIdentifier[0].pszPDumpDevName = ""; out->asDeviceIdentifier[0].pszPDumpRegName = ""; break; } case _IOC_NR(PVRSRV_BRIDGE_CREATE_DEVMEMCONTEXT): { PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->hDevMemContext = (void*)0x2; out->ui32ClientHeapCount = sizeof(pvr_heaps)/sizeof(*pvr_heaps); memcpy(out->sHeapInfo, pvr_heaps, sizeof(pvr_heaps)); break; } case _IOC_NR(PVRSRV_BRIDGE_OPEN_DISPCLASS_DEVICE): { PVRSRV_BRIDGE_OUT_OPEN_DISPCLASS_DEVICE *out = bridge_package->pvParamOut; out->hDeviceKM = (void*)0x1; break; } case _IOC_NR(PVRSRV_BRIDGE_GET_DISPCLASS_INFO): { PVRSRV_BRIDGE_OUT_GET_DISPCLASS_INFO *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->sDisplayInfo.ui32MaxSwapChains = 3; out->sDisplayInfo.ui32MaxSwapChainBuffers = 3; out->sDisplayInfo.ui32MinSwapInterval = 0; out->sDisplayInfo.ui32MaxSwapInterval = 1; out->sDisplayInfo.ui32PhysicalWidthmm = 256; out->sDisplayInfo.ui32PhysicalHeightmm = 256; strcpy(out->sDisplayInfo.szDisplayName, "Display"); break; } case _IOC_NR(PVRSRV_BRIDGE_ENUM_DISPCLASS_FORMATS): { PVRSRV_BRIDGE_OUT_ENUM_DISPCLASS_FORMATS *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->ui32Count = 1; out->asFormat[0].pixelformat = PVRSRV_PIXEL_FORMAT_A8R8G8B8_UNORM; break; } case _IOC_NR(PVRSRV_BRIDGE_ENUM_DISPCLASS_DIMS): { PVRSRV_BRIDGE_OUT_ENUM_DISPCLASS_DIMS *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->ui32Count = 1; out->asDim[0].ui32ByteStride = 256; out->asDim[0].ui32Width = 256; out->asDim[0].ui32Height = 256; break; } case _IOC_NR(PVRSRV_BRIDGE_GET_DISPCLASS_SYSBUFFER): { PVRSRV_BRIDGE_OUT_GET_DISPCLASS_SYSBUFFER *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->hBuffer = (void*)0x1234; break; } case _IOC_NR(PVRSRV_BRIDGE_MAP_DEVICECLASS_MEMORY): { PVRSRV_BRIDGE_IN_MAP_DEVICECLASS_MEMORY *in = bridge_package->pvParamIn; PVRSRV_BRIDGE_OUT_MAP_DEVICECLASS_MEMORY *out = bridge_package->pvParamOut; printf("Attempting map 0x%x\n", (uint32_t)in->hDeviceClassBuffer); out->eError = PVRSRV_OK; out->sClientMemInfo.hMappingInfo = (void*)0x43214321; //out->sClientSyncInfo = 0; out->psKernelMemInfo = (void*)0xDEADBEEF; out->hMappingInfo = (void*)0x12341234; break; } case _IOC_NR(PVRSRV_BRIDGE_MHANDLE_TO_MMAP_DATA): { PVRSRV_BRIDGE_IN_MHANDLE_TO_MMAP_DATA *in = bridge_package->pvParamIn; PVRSRV_BRIDGE_OUT_MHANDLE_TO_MMAP_DATA *out = bridge_package->pvParamOut; printf("Attempting mhandle map 0x%x\n", (uint32_t)in->hMHandle); //out->eError = PVRSRV_OK; //out->sClientMemInfo = ; //out->sClientSyncInfo = 0; //out->psKernelMemInfo = (void*)0xDEADBEEF; //out->hMappingInfo = (void*)0x1; break; } #if 0 case _IOC_NR(PVRSRV_BRIDGE_SGX_DEVINITPART2): { PVRSRV_BRIDGE_OUT_SGXDEVINITPART2 *out = bridge_package->pvParamOut; out->eError = PVRSRV_OK; out->ui32KMBuildOptions = SGX_BUILD_OPTIONS; printf("Input size is 0x%x\n", bridge_package->ui32InBufferSize); printf("Build options 0x%x\n", SGX_BUILD_OPTIONS); //out->ui32KMBuildOptions = 0x36a118; break; } #endif default: printf("Unimplemented pvrsrv ioctl %d, may be %s\n", ioctl_nr, pvrsrv_ioctl_names[ioctl_nr]); assert(false); break; } return false; } static bool spoof_ioctl(int fd, int request, void *ptr) { int ioctl_nr = _IOC_NR(request); switch(ioctl_nr) { case _IOC_NR(DRM_IOCTL_VERSION): { printf("Spoofing device info\n"); drmVersionPtr version = (drmVersionPtr)ptr; version->version_major = 1; version->version_minor = 13; version->version_patchlevel = 3341330; version->name_len = sizeof(DEV_NAME); version->date_len = sizeof(DEV_DATE); version->desc_len = sizeof(DEV_DESC); if (version->name) strcpy(version->name, DEV_NAME); if (version->date) strcpy(version->date, DEV_DATE); if (version->desc) strcpy(version->desc, DEV_DESC); break; } #if 0 case _IOC_NR(DRM_IOCTL_GET_MAGIC): printf(">>> ioctl(DRM_IOCTL_GET_MAGIC)\n"); break; case _IOC_NR(DRM_IOCTL_GET_UNIQUE): printf(">>> ioctl(DRM_IOCTL_GET_UNIQUE)\n"); break; case _IOC_NR(DRM_IOCTL_SET_VERSION): printf(">>> ioctl(DRM_IOCTL_SET_VERSION)\n"); { struct drm_set_version *data = ptr; printf("\t%d %d %d %d\n", data->drm_di_major, data->drm_di_minor, data->drm_dd_major, data->drm_dd_minor); } break; #endif case _IOC_NR(DRM_IOCTL_DROP_MASTER): printf(">>> ioctl(DRM_IOCTL_DROP_MASTER)\n"); return 0; case PVR_DRM_SRVKM_CMD: //fwrite(ptr, 1, sizeof(PVRSRV_BRIDGE_PACKAGE), log_file); //PPRINT(stdout, ptr, PVRSRV_BRIDGE_PACKAGE); return pvrsrv_ioctl(fd, ptr); break; case PVR_DRM_IS_MASTER_CMD: printf(">>> ioctl(PVR_DRM_IS_MASTER_CMD) 0x%x\n", PVR_DRM_SRVKM_CMD); /* From KMD source code this seems to always return 0 */ break; default: printf("Unimplemented ioctl 0x%x\n", ioctl_nr); assert(false); break; } return 0; } int ioctl(int fd, int request, ...) { PROLOG(ioctl); int ioc_size = _IOC_SIZE(request); bool pvr = fd == false_fd; //printf("Size is %d\n", ioc_size); void *ptr = NULL; if(ioc_size) { va_list args; va_start(args, request); ptr = va_arg(args, void *); va_end(args); } printf("Got ioctl %d!\n", fd); if (pvr) return spoof_ioctl(fd, request, ptr); else return orig_ioctl(fd, request, ptr); } int open(const char *pathname, int flags, mode_t mode) { printf("Called open on %s (%d)\n", pathname, flags); PROLOG(open); return orig_open(pathname, flags, mode); } int openat(int dirfd, const char *pathname, int flags, ...) { printf("Called openat on %s (%d) (%d)\n", pathname, dirfd, flags); PROLOG(openat); return orig_openat(dirfd, pathname, flags); } int openat64(int fd, const char * path, int oflag, ...) { printf("Called openat64 %s\n", path); PROLOG(openat64); return orig_openat64(fd, path, oflag); } DIR *opendir(const char *dirname) { printf("Opening dir %s\n", dirname); PROLOG(opendir); return orig_opendir(dirname); } struct dirent *readdir(DIR *dirp) { PROLOG(readdir); struct dirent *out = orig_readdir(dirp); if (out) { //printf("Reading %d %d %s\n", (int)out->d_type, (int)out->d_reclen, (char*)out->d_name); } return out; }