From 002d188745dfda13d16061ed521acea67c75ff23 Mon Sep 17 00:00:00 2001 From: Lucas Fryzek Date: Sat, 27 Jul 2024 11:49:40 +0100 Subject: drvemu: Add some X11 emulation to get application to run --- meson.build | 2 +- src/drvemu.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 188 insertions(+), 26 deletions(-) diff --git a/meson.build b/meson.build index 6b1d047..5ff15bd 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('drvemu', 'c', - default_options : ['c_std=gnu99']) + default_options : ['c_std=gnu99', 'buildtype=debug']) add_project_arguments('-D_GNU_SOURCE', language: 'c') dl = dependency('dl') diff --git a/src/drvemu.c b/src/drvemu.c index 04a9efc..de721a0 100644 --- a/src/drvemu.c +++ b/src/drvemu.c @@ -23,11 +23,14 @@ #include #include #include +#include #include #include #include +#include +#include #include @@ -75,6 +78,8 @@ struct memory_allocation { static struct memory_allocation allocations[MAX_ALLOCATIONS]; static int false_fd = 10241024; +static int false_disp = 10241025; +static int spoof_socket = -1; #define PROLOG(func) \ static typeof(func) *orig_##func = NULL; \ @@ -254,7 +259,8 @@ static void *create_handle_helper(int size, const char *msg, const char *file, i } #define DEV_NAME "pvr" -#define DEV_DATE "20110701" +#define DISP_NAME "jz4780" +#define DEV_DATE "2014545384" #define DEV_DESC "Imagination Technologies PVR DRM" static void get_misc_info(SGX_MISC_INFO *info) { @@ -610,14 +616,21 @@ static bool spoof_ioctl(int fd, int request, void *ptr) { LOG("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->version_minor = 14; + version->version_patchlevel = 544606452; + if (fd == false_disp) + version->name_len = sizeof(DISP_NAME); + else + 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->name) { + if (fd == false_disp) + strcpy(version->name, DISP_NAME); + else + strcpy(version->name, DEV_NAME); + } if (version->date) strcpy(version->date, DEV_DATE); if (version->desc) @@ -625,29 +638,20 @@ static bool spoof_ioctl(int fd, int request, void *ptr) { 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); - } + case _IOC_NR(DRM_IOCTL_SET_VERSION): { + //return -1; break; -#endif + } + case _IOC_NR(DRM_IOCTL_GET_MAGIC): { + struct drm_auth *auth = ptr; + auth->magic = 036; + break; + } case _IOC_NR(DRM_IOCTL_DROP_MASTER): LOG(">>> ioctl(DRM_IOCTL_DROP_MASTER)\n"); return 0; case PVR_DRM_SRVKM_CMD: + //LOG(">>> ioctl(PVR_DRM_SRVKM_CMD)\n"); //fwrite(ptr, 1, sizeof(PVRSRV_BRIDGE_PACKAGE), log_file); //PPRINT(stdout, ptr, PVRSRV_BRIDGE_PACKAGE); return pvrsrv_ioctl(fd, ptr); @@ -667,7 +671,8 @@ static bool spoof_ioctl(int fd, int request, void *ptr) { int ioctl(int fd, int request, ...) { PROLOG(ioctl); int ioc_size = _IOC_SIZE(request); - bool pvr = fd == false_fd; + bool pvr = fd == false_fd || + fd == false_disp; //printf("Size is %d\n", ioc_size); void *ptr = NULL; @@ -686,9 +691,166 @@ int ioctl(int fd, int request, ...) { return orig_ioctl(fd, request, ptr); } +struct iovec_spoof { + struct iovec request[3]; + struct iovec response[1]; + size_t response_len; +}; + +struct iovec_spoof spoofed_response[] = { + { + {{"b\0\3\0\4\0\0\0", 8}, {"DRI2", 4}, {"", 0}}, + {{"\1\0\7\0\0\0\0\0\1\232f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}}, + 32, + }, + { + {{"b\0\10\0\27\0\0\0", 8}, {"Generic Event Extension", 23}, {"\0", 1}}, + {{"\1\0\10\0\0\0\0\0\1\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}}, + 32, + }, + { + {{"\200\0\2\0\1\0\0\0", 8}, {NULL, 0}, {"", 0}}, + {{"\1\0\t\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}}, + 32, + }, + { + {{"\232\0\3\0\1\0\0\0\4\0\0\0", 12}, {NULL, 0}, {"", 0}}, + {{"\1\0\n\0\0\0\0\0\1\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}}, + 32, + }, + { + {{"\232\1\3\0\211\0\0\0\0\0\0\0", 12}, {NULL, 0}, {"", 0}}, + {{"\1\0\v\0\6\0\0\0\6\0\0\0\16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0jz4780\0\0/dev/dri/card0\0\0", 4096}}, + 56, + }, + /* TODO I'm not so sure this one is right */ + { + {{"\232\1\3\0000\4\0\0\0\0\0\0", 12}, {NULL, 0}, {NULL, 0}}, + {{"\1\0\v\0\6\0\0\0\3\0\0\0\21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0pvr\0\0/dev/dri/renderD128\0\0", 4096}}, + 61, + }, + { + {{"\232\2\3\0000\4\0\0\36\0\0\0", 12}, {NULL, 0}, {"", 0}}, + {{"\1\0\f\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}}, + 32, + }, +}; + +static struct iovec_spoof *iovec_response = NULL; +static bool do_poll = false; +static int recv_sent = 0; + +int connect(int sockfd, const struct sockaddr_un *addr, socklen_t addrlen) { + PROLOG(connect); + + /* No idea why I need to offset socket path by 1 */ + if (addr->sun_family == AF_LOCAL && + strcmp(addr->sun_path+1, "/tmp/.X11-unix/X0") == 0) { + LOG("Tracking socket %d for spoofing\n", sockfd); + spoof_socket = sockfd; + } + + return orig_connect(sockfd, addr, addrlen); +} + +static struct iovec_spoof *compare_iov(const struct iovec *iov, int iovcnt) { + for (size_t i = 0; i < ARRAY_SIZE(spoofed_response); i++) { + struct iovec *req = spoofed_response[i].request; + + /* TODO all requests might not have length of 3 */ + if (iovcnt != 3) + continue; + + bool same = true; + for (size_t j = 0; j < iovcnt; j++) { + if (req[j].iov_len != iov[j].iov_len || + memcmp(req[j].iov_base, iov[j].iov_base, iov[j].iov_len) != 0) { + same = false; + break; + } + } + + if (same) { + LOG("Spoofing with response %d\n", i); + return &spoofed_response[i]; + } + } + return NULL; +} + +int writev(int fd, const struct iovec *iov, int iovcnt) { + PROLOG(writev); + int ret = orig_writev(fd, iov, iovcnt); + if (fd == spoof_socket) { + iovec_response = compare_iov(iov, iovcnt); + + //LOG("Trying to spoof and got %p\n", iovec_response); + /* TODO this is hardcoding the response + * really compare_iov should give us more information + */ + if (iovec_response != NULL) { + do_poll = true; + recv_sent = 3; + return iov[0].iov_len + iov[1].iov_len + iov[2].iov_len; + } + } + + return ret; +} + +ssize_t recvmsg(int socket, struct msghdr *message, int flags) { + PROLOG(recvmsg); + int ret = orig_recvmsg(socket, message, flags); + if (socket == spoof_socket && iovec_response) { + //orig_recvmsg(socket, message, flags); + LOG("Spoofing response\n"); + uint16_t seq_num = ((uint16_t*)message->msg_iov->iov_base)[1]; + memcpy(message->msg_iov->iov_base, iovec_response->response[0].iov_base, iovec_response[0].response_len); + ((uint16_t*)message->msg_iov->iov_base)[1] = seq_num; + message->msg_iov->iov_len = iovec_response[0].response_len; + message->msg_name = NULL; + message->msg_controllen = 0; + message->msg_flags = 0; + int ret_len = iovec_response->response_len; + iovec_response = NULL; + recv_sent--; + do_poll = true; + LOG("Returning %d\n", ret_len); + return ret_len; + } + +#if 0 + if (recv_sent > 0) { + recv_sent--; + return -1; + } +#endif + + return ret; +} + +int poll(struct pollfd *fds, nfds_t nfds, int timeout) { + PROLOG(poll); + + if (nfds == 1 && fds[0].fd == spoof_socket && do_poll) { + LOG("Spoofed poll 0x%x\n", fds[0].events); + fds[0].revents = fds[0].events == (POLLIN|POLLOUT) ? POLLOUT : POLLIN; + //do_poll = false; + return 1; + } + + return orig_poll(fds, nfds, timeout); +} + int open(const char *pathname, int flags, mode_t mode) { LOG("Called open on %s (%d)\n", pathname, flags); PROLOG(open); + + if (strcmp(pathname, "/dev/dri/card0") == 0) { + LOG("Spoofing FD!\n"); + return false_disp; + } + return orig_open(pathname, flags, mode); } -- cgit