Now About Social Code
summaryrefslogtreecommitdiff
path: root/src/drvemu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drvemu.c')
-rw-r--r--src/drvemu.c212
1 files changed, 187 insertions, 25 deletions
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 <string.h>
#include <assert.h>
#include <dlfcn.h>
+#include <poll.h>
#include <dirent.h>
#include <sys/mman.h>
#include <sys/syscall.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <asm-generic/ioctl.h>
@@ -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);
}