|
@@ -23,8 +23,9 @@
|
|
|
#include <kernel/mouse.h>
|
|
|
#include <kernel/args.h>
|
|
|
|
|
|
-#define VMWARE_MAGIC 0x564D5868
|
|
|
-#define VMWARE_PORT 0x5658
|
|
|
+#define VMWARE_MAGIC 0x564D5868
|
|
|
+#define VMWARE_PORT 0x5658
|
|
|
+#define VMWARE_PORTHB 0x5659
|
|
|
|
|
|
#define PACKETS_IN_PIPE 1024
|
|
|
#define DISCARD_POINT 32
|
|
@@ -58,32 +59,15 @@ typedef struct {
|
|
|
} vmware_cmd;
|
|
|
|
|
|
static void vmware_io(vmware_cmd * cmd) {
|
|
|
- uint32_t dummy;
|
|
|
-
|
|
|
- /* Now how's THAT for a VM backdoor... */
|
|
|
-
|
|
|
- asm volatile(
|
|
|
- "pushl %%ebx\n"
|
|
|
- "pushl %%eax\n"
|
|
|
- "movl 20(%%eax), %%edi\n" /* Load data into registers */
|
|
|
- "movl 16(%%eax), %%esi\n"
|
|
|
- "movl 12(%%eax), %%edx\n"
|
|
|
- "movl 8(%%eax), %%ecx\n"
|
|
|
- "movl 4(%%eax), %%ebx\n"
|
|
|
- "movl (%%eax), %%eax\n"
|
|
|
- "inl %%dx, %%eax\n" /* Then trip a magic i/o port */
|
|
|
- "xchgl %%eax, (%%esp)\n"
|
|
|
- "movl %%edi, 20(%%eax)\n" /* Data also comes back out by registers */
|
|
|
- "movl %%esi, 16(%%eax)\n"
|
|
|
- "movl %%edx, 12(%%eax)\n"
|
|
|
- "movl %%ecx, 8(%%eax)\n"
|
|
|
- "movl %%ebx, 4(%%eax)\n"
|
|
|
- "popl (%%eax)\n"
|
|
|
- "popl %%ebx\n"
|
|
|
- : "=a"(dummy)
|
|
|
- : "0"(cmd)
|
|
|
- : "ecx", "edx", "esi", "edi", "memory" /* And vmware / qemu could trash anything they desire... */
|
|
|
- );
|
|
|
+ asm volatile("in %%dx, %0" : "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di));
|
|
|
+}
|
|
|
+
|
|
|
+static void vmware_io_hb_out(vmware_cmd * cmd) {
|
|
|
+ asm volatile("cld; rep; outsb" : "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di));
|
|
|
+}
|
|
|
+
|
|
|
+static void vmware_io_hb_in(vmware_cmd * cmd) {
|
|
|
+ asm volatile("cld; rep; insb" : "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di));
|
|
|
}
|
|
|
|
|
|
static void vmware_send(vmware_cmd * cmd) {
|
|
@@ -93,6 +77,20 @@ static void vmware_send(vmware_cmd * cmd) {
|
|
|
vmware_io(cmd);
|
|
|
}
|
|
|
|
|
|
+static void vmware_send_hb(vmware_cmd * cmd) {
|
|
|
+ cmd->magic = VMWARE_MAGIC;
|
|
|
+ cmd->port = VMWARE_PORTHB;
|
|
|
+
|
|
|
+ vmware_io_hb_out(cmd);
|
|
|
+}
|
|
|
+
|
|
|
+static void vmware_get_hb(vmware_cmd * cmd) {
|
|
|
+ cmd->magic = VMWARE_MAGIC;
|
|
|
+ cmd->port = VMWARE_PORTHB;
|
|
|
+
|
|
|
+ vmware_io_hb_in(cmd);
|
|
|
+}
|
|
|
+
|
|
|
static void mouse_on(void) {
|
|
|
vmware_cmd cmd;
|
|
|
|
|
@@ -244,21 +242,243 @@ static int detect_device(void) {
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static int ioctl_mouse(fs_node_t * node, int request, void * argp) {
|
|
|
- if (request == 1) {
|
|
|
- /* Disable */
|
|
|
- mouse_off();
|
|
|
- ps2_mouse_alternate = NULL;
|
|
|
- return 0;
|
|
|
+
|
|
|
+static int open_msg_channel(uint32_t proto) {
|
|
|
+ vmware_cmd cmd;
|
|
|
+ cmd.cx = 30 | 0x00000000; /* CMD_MESSAGE */
|
|
|
+ cmd.bx = proto;
|
|
|
+ vmware_send(&cmd);
|
|
|
+
|
|
|
+ if ((cmd.cx & 0x10000) == 0) {
|
|
|
+ return -1;
|
|
|
}
|
|
|
- if (request == 2) {
|
|
|
- /* Enable */
|
|
|
- ps2_mouse_alternate = vmware_mouse;
|
|
|
- mouse_on();
|
|
|
- mouse_absolute();
|
|
|
- return 0;
|
|
|
+
|
|
|
+ return cmd.dx >> 16;
|
|
|
+}
|
|
|
+
|
|
|
+static void msg_close(int channel) {
|
|
|
+ vmware_cmd cmd = {0};
|
|
|
+ cmd.cx = 30 | 0x00060000;
|
|
|
+ cmd.bx = 0;
|
|
|
+ cmd.dx = channel << 16;
|
|
|
+
|
|
|
+ vmware_send(&cmd);
|
|
|
+}
|
|
|
+
|
|
|
+static int open_rpci_channel(void) {
|
|
|
+ return open_msg_channel(0x49435052);
|
|
|
+}
|
|
|
+
|
|
|
+static int tclo_channel = 0;
|
|
|
+
|
|
|
+static int open_tclo_channel(void) {
|
|
|
+ if (tclo_channel) {
|
|
|
+ msg_close(tclo_channel);
|
|
|
+ }
|
|
|
+ tclo_channel = open_msg_channel(0x4f4c4354);
|
|
|
+ return tclo_channel;
|
|
|
+}
|
|
|
+
|
|
|
+static int msg_send(int channel, char * msg, size_t size) {
|
|
|
+ {
|
|
|
+ vmware_cmd cmd = {0};
|
|
|
+ cmd.cx = 30 | 0x00010000; /* CMD_MESSAGE size */
|
|
|
+ cmd.size = size;
|
|
|
+ cmd.dx = channel << 16;
|
|
|
+ vmware_send(&cmd);
|
|
|
+
|
|
|
+ if (size == 0) return 0;
|
|
|
+
|
|
|
+ if (((cmd.cx >> 16) & 0x0081) != 0x0081) {
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ vmware_cmd cmd = {0};
|
|
|
+ cmd.bx = 0x0010000;
|
|
|
+ cmd.cx = size;
|
|
|
+ cmd.dx = channel << 16;
|
|
|
+ cmd.si = (uint32_t)msg;
|
|
|
+ vmware_send_hb(&cmd);
|
|
|
+
|
|
|
+ if (!(cmd.bx & 0x0010000)) {
|
|
|
+ return -3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int msg_recv(int channel, char * buf, size_t bufsize) {
|
|
|
+ size_t size;
|
|
|
+ {
|
|
|
+ vmware_cmd cmd = {0};
|
|
|
+ cmd.cx = 30 | 0x00030000; /* CMD_MESSAGE receive ize */
|
|
|
+ cmd.dx = channel << 16;
|
|
|
+ vmware_send(&cmd);
|
|
|
+
|
|
|
+#if 0
|
|
|
+ if ((cmd.dx >> 16) != 0x0001) {
|
|
|
+ return -4;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ size = cmd.bx;
|
|
|
+ if (size == 0) return 0;
|
|
|
+ if (((cmd.cx >> 16) & 0x0083) != 0x0083) {
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+ if (size > bufsize) return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ vmware_cmd cmd = {0};
|
|
|
+ cmd.bx = 0x00010000;
|
|
|
+ cmd.cx = size;
|
|
|
+ cmd.dx = channel << 16;
|
|
|
+ cmd.di = (uint32_t)buf;
|
|
|
+
|
|
|
+ vmware_get_hb(&cmd);
|
|
|
+ if (!(cmd.bx & 0x00010000)) {
|
|
|
+ return -3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ vmware_cmd cmd = {0};
|
|
|
+ cmd.cx = 30 | 0x00050000;
|
|
|
+ cmd.bx = 0x0001;
|
|
|
+ cmd.dx = channel << 16;
|
|
|
+
|
|
|
+ vmware_send(&cmd);
|
|
|
+ }
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
+static int rpci_string(char * request) {
|
|
|
+ /* Open channel */
|
|
|
+ int channel = open_rpci_channel();
|
|
|
+ if (channel < 0) return channel;
|
|
|
+
|
|
|
+ size_t size = strlen(request) + 1;
|
|
|
+ msg_send(channel, request, size);
|
|
|
+
|
|
|
+ char buf[16];
|
|
|
+ int recv_size = msg_recv(channel, buf, 16);
|
|
|
+
|
|
|
+ msg_close(channel);
|
|
|
+
|
|
|
+ if (recv_size < 0) return recv_size;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int attempt_scale(void) {
|
|
|
+
|
|
|
+ int i;
|
|
|
+ int c = open_tclo_channel();
|
|
|
+ if (c < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ char buf[256];
|
|
|
+ if ((i = msg_send(c, buf, 0)) < 0) { return 1; }
|
|
|
+
|
|
|
+ int resend = 0;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ i = msg_recv(c, buf, 256);
|
|
|
+ if (i < 0) {
|
|
|
+ return 1;
|
|
|
+ } else if (i == 0) {
|
|
|
+ if (resend) {
|
|
|
+ if ((i = rpci_string("tools.capability.resolution_set 1")) < 0) { return 1; }
|
|
|
+ if ((i = rpci_string("tools.capability.resolution_server toolbox 1")) < 0) { return 1; }
|
|
|
+ if ((i = rpci_string("tools.capability.display_topology_set 1")) < 0) { return 1; }
|
|
|
+ if ((i = rpci_string("tools.capability.color_depth_set 1")) < 0) { return 1; }
|
|
|
+ if ((i = rpci_string("tools.capability.resolution_min 0 0")) < 0) { return 1; }
|
|
|
+ if ((i = rpci_string("tools.capability.unity 1")) < 0) { return 1; }
|
|
|
+ resend = 0;
|
|
|
+ } else {
|
|
|
+ unsigned long s, ss;
|
|
|
+ relative_time(0, 10, &s, &ss);
|
|
|
+ sleep_until((process_t *)current_process, s, ss);
|
|
|
+ switch_task(0);
|
|
|
+ }
|
|
|
+ if ((i = msg_send(c, buf, 0)) < 0) { return 1; }
|
|
|
+ } else {
|
|
|
+ buf[i] = '\0';
|
|
|
+ if (startswith(buf, "reset")) {
|
|
|
+ if ((i = msg_send(c, "OK ATR toolbox", strlen("OK ATR toolbox"))) < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ } else if (startswith(buf, "ping")) {
|
|
|
+ if ((i = msg_send(c, "OK ", strlen("OK "))) < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ } else if (startswith(buf, "Capabilities_Register")) {
|
|
|
+ if ((i = msg_send(c, "OK ", strlen("OK "))) < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ resend = 1;
|
|
|
+ } else if (startswith(buf, "Resolution_Set")) {
|
|
|
+ char * x = &buf[15];
|
|
|
+ char * y = strstr(x," ");
|
|
|
+ if (!y) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ *y = '\0';
|
|
|
+ y++;
|
|
|
+ int _x = atoi(x);
|
|
|
+ int _y = atoi(y);
|
|
|
+
|
|
|
+ if (lfb_resolution_x && _x && (_x != lfb_resolution_x || _y != lfb_resolution_y)) {
|
|
|
+ lfb_set_resolution(_x, _y);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((i = msg_send(c, "OK ", strlen("OK "))) < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ msg_close(c);
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ if ((i = msg_send(c, "ERROR Unknown command", strlen("ERROR Unknown command"))) < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void vmware_resize(void * data, char * name) {
|
|
|
+ while (1) {
|
|
|
+ attempt_scale();
|
|
|
+ unsigned long s, ss;
|
|
|
+ relative_time(1, 0, &s, &ss);
|
|
|
+ sleep_until((process_t *)current_process, s, ss);
|
|
|
+ switch_task(0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int ioctl_mouse(fs_node_t * node, int request, void * argp) {
|
|
|
+ switch (request) {
|
|
|
+ case 1:
|
|
|
+ /* Disable */
|
|
|
+ mouse_off();
|
|
|
+ ps2_mouse_alternate = NULL;
|
|
|
+ return 0;
|
|
|
+ case 2:
|
|
|
+ /* Enable */
|
|
|
+ ps2_mouse_alternate = vmware_mouse;
|
|
|
+ mouse_on();
|
|
|
+ mouse_absolute();
|
|
|
+ return 0;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
- return -1;
|
|
|
}
|
|
|
|
|
|
static int init(void) {
|
|
@@ -282,6 +502,10 @@ static int init(void) {
|
|
|
mouse_on();
|
|
|
mouse_absolute();
|
|
|
|
|
|
+ if (lfb_driver_name && !strcmp(lfb_driver_name, "vmware") && !args_present("novmwareresset")) {
|
|
|
+ create_kernel_tasklet(vmware_resize, "[vmware]", NULL);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
return 0;
|