From 4c29e4b83e52f1e4afa3a8b4784be046592d8e4c Mon Sep 17 00:00:00 2001 From: Lucas Fryzek Date: Fri, 2 Aug 2024 23:33:44 +0100 Subject: drv: Add custom userspace driver Add userspace driver that we will eventually use to try and replay the command dumps coming from the wrap library. --- src/drv.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pprint.c | 58 ++++++++-- src/wrap.c | 9 +- 3 files changed, 403 insertions(+), 8 deletions(-) create mode 100644 src/drv.c (limited to 'src') diff --git a/src/drv.c b/src/drv.c new file mode 100644 index 0000000..b5d5943 --- /dev/null +++ b/src/drv.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 + +#define DRM_IOCTL_PVR_SRVKM DRM_IOWR(PVR_DRM_SRVKM_CMD, PVRSRV_BRIDGE_PACKAGE) + +#include + +#define UNUSED(x) (void)x + +struct driver_state { + int fd; + IMG_HANDLE kernel_services; + IMG_UINT32 device_idx; + IMG_HANDLE dev_cookie; + IMG_HANDLE dev_mem_context; + IMG_HANDLE global_eventobject; + + PVRSRV_HEAP_INFO kernel_heap; + PVRSRV_BRIDGE_OUT_ALLOCDEVICEMEM ccb_buffer; +}; + +static void check_pvr_error(PVRSRV_ERROR error) { + if(error != PVRSRV_OK) { + printf("Got error %s\n", PPRINT(NULL, error, PVRSRV_ERROR)); + assert(false); + } +} + +static void check_ioctl(int fd, long request, void *data) { + int ret = drmIoctl(fd, request, data); + if(ret != 0) { + printf("IOCTL ret value %d, %d, %s\n", ret, errno, strerror(errno)); + assert(ret == 0); + } +} + +static void connect_service(struct driver_state *state) { + PVRSRV_BRIDGE_IN_CONNECT_SERVICES in = { + .ui32BridgeFlags = 0xDEADBEEF + }; + PVRSRV_BRIDGE_OUT_CONNECT_SERVICES out = {.eError = 0}; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_CONNECT_SERVICES, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = 0, + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + //PPRINT(stdout, &out, PVRSRV_BRIDGE_OUT_CONNECT_SERVICES); + check_pvr_error(out.eError); + state->kernel_services = out.hKernelServices; +} + +static void enum_devices(struct driver_state *state) { + PVRSRV_BRIDGE_OUT_ENUMDEVICE out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_ENUM_DEVICES, + .ui32Size = sizeof(data), + .pvParamIn = NULL, + .ui32InBufferSize = 0, + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); + + bool gpu_found = false; + for(uint32_t i = 0; i < out.ui32NumDevices; i++) { + PVRSRV_DEVICE_IDENTIFIER *di = &out.asDeviceIdentifier[i]; + if(di->eDeviceType == PVRSRV_DEVICE_TYPE_SGX && di->eDeviceClass == PVRSRV_DEVICE_CLASS_3D) { + state->device_idx = di->ui32DeviceIndex; + gpu_found = true; + break; + } + } + + assert(gpu_found); +} + +static void acquire_devinfo(struct driver_state *state) { + PVRSRV_BRIDGE_IN_ACQUIRE_DEVICEINFO in = { + .uiDevIndex = state->device_idx, + .eDeviceType = PVRSRV_DEVICE_TYPE_UNKNOWN, + }; + PVRSRV_BRIDGE_OUT_ACQUIRE_DEVICEINFO out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_ACQUIRE_DEVICEINFO, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); + + state->dev_cookie = out.hDevCookie; +} + +static void sgx_get_misc_info(struct driver_state *state) { + SGX_MISC_INFO misc_info = { + .eRequest = SGX_MISC_INFO_REQUEST_DRIVER_SGXREV, + }; + PVRSRV_BRIDGE_IN_SGXGETMISCINFO in = { + .hDevCookie = state->dev_cookie, + .psMiscInfo = &misc_info, + }; + PVRSRV_BRIDGE_RETURN out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_SGX_GETMISCINFO, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services, + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); + + /* TODO figure out what we do with misc info */ + PPRINT(stdout, &in, PVRSRV_BRIDGE_IN_SGXGETMISCINFO); + fprintf(stdout, "\n"); + PPRINT(stdout, &in.psMiscInfo->uData.sSGXFeatures, PVRSRV_SGX_MISCINFO_FEATURES); + fprintf(stdout, "\n"); +} + +static void create_devmemcontext(struct driver_state *state) { + PVRSRV_BRIDGE_IN_CREATE_DEVMEMCONTEXT in = { + .hDevCookie = state->dev_cookie + }; + PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_CREATE_DEVMEMCONTEXT, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); + PPRINT(stdout, &out, PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT); + + state->dev_mem_context = out.hDevMemContext; +} + +static void get_clientinfo(struct driver_state *state) { + PVRSRV_BRIDGE_IN_GETCLIENTINFO in = { + .hDevCookie = state->dev_cookie, + }; + PVRSRV_BRIDGE_OUT_GETCLIENTINFO out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_SGX_GETCLIENTINFO, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); + //PPRINT(stdout, &out, PVRSRV_BRIDGE_OUT_GETCLIENTINFO); +} + +static void get_miscinfo(struct driver_state *state) { + PVRSRV_BRIDGE_IN_GET_MISC_INFO in = { + .sMiscInfo = { + .ui32StateRequest = PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT | PVRSRV_MISC_INFO_TIMER_PRESENT, + }, + }; + PVRSRV_BRIDGE_OUT_GET_MISC_INFO out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_GET_MISC_INFO, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); + + state->global_eventobject = out.sMiscInfo.sGlobalEventObject.hOSEventKM; +} + +static void open_eventobject(struct driver_state *state) { + PVRSRV_BRIDGE_IN_EVENT_OBJECT_OPEN in = { + .sEventObject = { + .szName = "PVRSRV_GLOBAL_EVENTOBJECT", + .hOSEventKM = state->global_eventobject, + } + }; + + PVRSRV_BRIDGE_OUT_EVENT_OBJECT_OPEN out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_EVENT_OBJECT_OPEN, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); +} + +static void get_dev_mem_heapinfo(struct driver_state *state) { + PVRSRV_BRIDGE_IN_GET_DEVMEM_HEAPINFO in = { + .hDevCookie = state->dev_cookie, + .hDevMemContext = state->dev_mem_context, + }; + PVRSRV_BRIDGE_OUT_GET_DEVMEM_HEAPINFO out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_GET_DEVMEM_HEAPINFO, + .ui32Size = sizeof(data), + .pvParamIn = &in, + .ui32InBufferSize = sizeof(in), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + check_pvr_error(out.eError); + + for (int i = 0; i < out.ui32ClientHeapCount; i++) { + //PPRINT(stdout, &out.sHeapInfo[i], PVRSRV_HEAP_INFO); + if (out.sHeapInfo[i].ui32HeapID == HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_DATA_HEAP_ID)) { + state->kernel_heap = out.sHeapInfo[i]; + } + } + + assert(state->kernel_heap.ui32HeapID != 0); +} + +static PVRSRV_BRIDGE_OUT_ALLOCDEVICEMEM allocate_memobj(struct driver_state *state, PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM *alloc) { + PVRSRV_BRIDGE_OUT_ALLOCDEVICEMEM out; + PVRSRV_BRIDGE_PACKAGE data = { + .ui32BridgeID = PVRSRV_BRIDGE_ALLOC_DEVICEMEM, + .ui32Size = sizeof(data), + .pvParamIn = &alloc, + .ui32InBufferSize = sizeof(alloc), + .pvParamOut = &out, + .ui32OutBufferSize = sizeof(out), + .hKernelServices = state->kernel_services + }; + + printf("Allocating from %p %p 0x%x\n", alloc->hDevCookie, alloc->hDevMemHeap, alloc->uSize); + check_ioctl(state->fd, DRM_IOCTL_PVR_SRVKM, &data); + + check_pvr_error(out.eError); + return out; +} + +static void allocate_memory(struct driver_state *state) { + PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM alloc_CCB = { + .hDevCookie = state->dev_cookie, + .hDevMemHeap = state->kernel_heap.hDevMemHeap, + .ui32Attribs = PVRSRV_MEM_READ | PVRSRV_MEM_WRITE | PVRSRV_MEM_CACHE_CONSISTENT | PVRSRV_MEM_NO_SYNCOBJ | PVRSRV_MEM_EDM_PROTECT, + .uSize = 0x86a4, + .uAlignment = 0x1000, + }; + + state->ccb_buffer = allocate_memobj(state, &alloc_CCB); +} + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + printf("Hello world!\n"); + struct driver_state state; + + state.fd = open("/dev/dri/renderD128", O_RDWR); + assert(state.fd != -1 && "Failed to device file"); + + drmVersionPtr version = drmGetVersion(state.fd); + assert(version && "drmGetVersion failed"); + + printf("Driver: %s\n", version->name); + printf("Version %d.%d.%d\n", version->version_major, version->version_minor, version->version_patchlevel); + printf("Date: %s\n", version->date); + printf("Desc: %s\n", version->desc); + printf("Uniq: %s\n", drmGetBusid(state.fd)); + + //printf("DRM_IOCTL_VERSION = 0x%x\n", DRM_IOCTL_VERSION); + //printf("PVR_DRM_SRVKM_CMD = 0x%x\n", DRM_IOCTL_PVR_SRVKM); + connect_service(&state); + enum_devices(&state); + acquire_devinfo(&state); + sgx_get_misc_info(&state); + create_devmemcontext(&state); + get_clientinfo(&state); + get_miscinfo(&state); + open_eventobject(&state); + get_dev_mem_heapinfo(&state); + allocate_memory(&state); + + close(state.fd); + + return 0; +} diff --git a/src/pprint.c b/src/pprint.c index 17c3ece..1a72fb4 100644 --- a/src/pprint.c +++ b/src/pprint.c @@ -364,23 +364,18 @@ static void pprint_PVRSRV_BRIDGE_OUT_ACQUIRE_DEVICEINFO(FILE *fp, PVRSRV_BRIDGE_ PPRINT(fp, data->eError, PVRSRV_ERROR), data->hDevCookie); } -#if 0 static void pprint_PVRSRV_SGX_MISCINFO_FEATURES(FILE *fp, PVRSRV_SGX_MISCINFO_FEATURES *data) { fprintf(fp, "{\n.ui32CoreRev = 0x%x,\n.ui32CoreID = 0x%x,\n.ui32DDKVersion = 0%x,\n.ui32DDBBuild = 0x%x\n.ui32CoreIdSW = 0x%x,\n.uiCoreRevSW = 0x%x,\n.ui32BuildOptions = 0x%x,\n}", data->ui32CoreRev, data->ui32CoreID, data->ui32DDKVersion, data->ui32DDKBuild, data->ui32CoreIdSW, data->ui32CoreRevSW, data->ui32BuildOptions); } -#endif -#if 0 static void pprint_PVRSRV_HEAP_INFO(FILE *fp, PVRSRV_HEAP_INFO *data) { fprintf(fp, "{\n.ui32HeapID = 0x%x,\n.hDevMemHeap = %p,\n.sDevVAddrBase = 0x%x,\n.ui32HeapByteSize = 0x%x,\n.ui32Attribs = 0x%x,\n.ui32XTileStride = 0x%x\n}", data->ui32HeapID, data->hDevMemHeap, data->sDevVAddrBase.uiAddr, data->ui32HeapByteSize, data->ui32Attribs, data->ui32XTileStride); } -#endif -#if 0 static void pprint_PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT(FILE *fp, PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT *data) { fprintf(fp, "{\n.eError = %s,\n.hDevMemContext = %p,\n.ui32ClientHeapCount = %d,\n.sHeapInfo = {\n", PPRINT(fp, data->eError, PVRSRV_ERROR), data->hDevMemContext, data->ui32ClientHeapCount); @@ -390,10 +385,55 @@ static void pprint_PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT(FILE *fp, PVRSRV_BRIDG } fprintf(fp, "}"); } -#endif + +static void pprint_mem_alloc_flags(FILE *fp, uint32_t ui32Attribs) { +#define PRINTBIT(value, bit) if ((value) & (bit)) { \ + fprintf(fp, "%s", #bit); \ + (value) &= ~(bit); \ + if((value) != 0) \ + fprintf(fp, "%s", " | "); \ + } + PRINTBIT(ui32Attribs, PVRSRV_MEM_READ); + PRINTBIT(ui32Attribs, PVRSRV_MEM_WRITE); + PRINTBIT(ui32Attribs, PVRSRV_MEM_CACHE_CONSISTENT); + PRINTBIT(ui32Attribs, PVRSRV_MEM_NO_SYNCOBJ); + PRINTBIT(ui32Attribs, PVRSRV_MEM_INTERLEAVED); + PRINTBIT(ui32Attribs, PVRSRV_MEM_DUMMY); + PRINTBIT(ui32Attribs, PVRSRV_MEM_EDM_PROTECT); + PRINTBIT(ui32Attribs, PVRSRV_MEM_ZERO); + PRINTBIT(ui32Attribs, PVRSRV_MEM_USER_SUPPLIED_DEVVADDR); + PRINTBIT(ui32Attribs, PVRSRV_MEM_RAM_BACKED_ALLOCATION); + PRINTBIT(ui32Attribs, PVRSRV_MEM_NO_RESMAN); + PRINTBIT(ui32Attribs, PVRSRV_MEM_EXPORTED); + + PRINTBIT(ui32Attribs, PVRSRV_HAP_CACHED); + PRINTBIT(ui32Attribs, PVRSRV_HAP_UNCACHED); + PRINTBIT(ui32Attribs, PVRSRV_HAP_WRITECOMBINE); + PRINTBIT(ui32Attribs, PVRSRV_HAP_KERNEL_ONLY); + PRINTBIT(ui32Attribs, PVRSRV_HAP_SINGLE_PROCESS); + PRINTBIT(ui32Attribs, PVRSRV_HAP_MULTI_PROCESS); + PRINTBIT(ui32Attribs, PVRSRV_HAP_FROM_EXISTING_PROCESS); + PRINTBIT(ui32Attribs, PVRSRV_HAP_NO_CPU_VIRTUAL); + + assert(ui32Attribs == 0); +} + +static void pprint_PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM(FILE *fp, PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM*in) { + fprintf(fp, "{\n.ui32BridgeFlags = 0x%x,\n.hDevCookie = 0x%x,\n.hDevMemHeap = 0x%x,\n.ui32Attribs = ", + (uint32_t)in->ui32BridgeFlags, (uint32_t)in->hDevCookie, (uint32_t)in->hDevMemHeap); + pprint_mem_alloc_flags(fp, in->ui32Attribs); + + fprintf(fp, ",\n.uSize = 0x%x,\n.uAlignment = 0x%x,\n.pvPrivData = %p,\n.ui32PrivDataLength = 0x%x,\n" + ".ui32ChunkSize = 0x%x,\n.ui32NumVirtChunks = 0x%x,\n.ui32NumPhysChunks = 0x%x,\n" + ".pabMapChunk = %p\n}\n", + (uint32_t)in->uSize, (uint32_t)in->uAlignment, in->pvPrivData, + in->ui32PrivDataLength, in->ui32ChunkSize, in->ui32NumVirtChunks, in->ui32NumPhysChunks, + in->pabMapChunk); +} static void pprint_drmVersion(FILE *fp, drmVersion *drm) { - fprintf(fp, "{\n.version_major = %d,\n.version_minor = %d,\n.version_patchlevel = %d\n.name_len = %d,\n.name = \"%s\",\n.date_len = %d,\n.date = \"%s\",\n.desc_len = %d,\n.desc = \"%s\"\n}", + fprintf(fp, "{\n.version_major = %d,\n.version_minor = %d,\n.version_patchlevel = %d\n.name_len = %d,\n" + ".name = \"%s\",\n.date_len = %d,\n.date = \"%s\",\n.desc_len = %d,\n.desc = \"%s\"\n}\n", (int)drm->version_major, (int)drm->version_minor, (int)drm->version_patchlevel, (int)drm->name_len, drm->name, (int)drm->date_len, drm->date, @@ -406,3 +446,7 @@ static void pprint_SGXMKIF_COMMAND(FILE *fp, SGXMKIF_COMMAND *in) { in->ui32Data[0], in->ui32Data[1], in->ui32Data[2], in->ui32Data[3], in->ui32Data[4], in->ui32Data[5]); } + +static void pprint_PVRSRV_EVENTOBJECT(FILE *fp, PVRSRV_EVENTOBJECT *in) { + fprintf(fp, "{\n.szName = \"%s\",\n.hOSEventKM = %p\n}\n", in->szName, in->hOSEventKM); +} diff --git a/src/wrap.c b/src/wrap.c index 0423c34..6b96f36 100644 --- a/src/wrap.c +++ b/src/wrap.c @@ -216,6 +216,7 @@ static void clear_mem(struct mem_entry *mem) { IMG_HANDLE handle = mem->mem_info.hKernelMemInfo; bool is_special_heap = (uintptr_t)handle == 0x14; if(mem->type == MEM_TYPE_NORMAL && (valid_heap || is_special_heap)) { + printf("Clearing heap\n"); for (int i = 0; i < 2; i++) if (mem->data[i]) memset(mem->data[i], 0x00, mem->mem_info.uAllocSize); @@ -736,6 +737,7 @@ static bool pvrsrv_ioctl(int fd, PVRSRV_BRIDGE_PACKAGE *bridge_package) { } #endif + PPRINT(stdout, mem_data, PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM); printf("Alloc #%d %p\n", current_alloc, mem_data); current_alloc++; } @@ -939,9 +941,14 @@ static bool pvrsrv_ioctl(int fd, PVRSRV_BRIDGE_PACKAGE *bridge_package) { PPRINT(stdout, bridge_package->pvParamIn, PVRSRV_BRIDGE_IN_GETCLIENTINFO); //fwrite(bridge_package->pvParamIn, 1, sizeof(PVRSRV_BRIDGE_IN_GETCLIENTINFO), log_file); break; + case _IOC_NR(PVRSRV_BRIDGE_EVENT_OBJECT_OPEN): + { + PVRSRV_BRIDGE_IN_EVENT_OBJECT_OPEN *in = bridge_package->pvParamIn; + PPRINT(stdout, &in->sEventObject, PVRSRV_EVENTOBJECT); + break; + } case _IOC_NR(PVRSRV_BRIDGE_MAP_DMABUF): case _IOC_NR(PVRSRV_BRIDGE_GET_MISC_INFO): - case _IOC_NR(PVRSRV_BRIDGE_EVENT_OBJECT_OPEN): case _IOC_NR(PVRSRV_BRIDGE_GET_DEVMEM_HEAPINFO): case _IOC_NR(PVRSRV_BRIDGE_SGX_UNREGISTER_HW_RENDER_CONTEXT): case _IOC_NR(PVRSRV_BRIDGE_EVENT_OBJECT_CLOSE): -- cgit