vbox.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2016-2018 K. Lange
  5. *
  6. * VirtualBox Guest Additions driver
  7. */
  8. #include <kernel/system.h>
  9. #include <kernel/fs.h>
  10. #include <kernel/printf.h>
  11. #include <kernel/types.h>
  12. #include <kernel/logging.h>
  13. #include <kernel/pci.h>
  14. #include <kernel/module.h>
  15. #include <kernel/video.h>
  16. #include <kernel/pipe.h>
  17. #include <kernel/mouse.h>
  18. #include <kernel/args.h>
  19. #define VBOX_VENDOR_ID 0x80EE
  20. #define VBOX_DEVICE_ID 0xCAFE
  21. static void vbox_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
  22. if (v == VBOX_VENDOR_ID && d == VBOX_DEVICE_ID) {
  23. *((uint32_t *)extra) = device;
  24. }
  25. }
  26. #define VMM_GetMouseState 1
  27. #define VMM_SetMouseState 2
  28. #define VMM_SetPointerShape 3
  29. #define VMM_AcknowledgeEvents 41
  30. #define VMM_ReportGuestInfo 50
  31. #define VMM_GetDisplayChangeRequest 51
  32. #define VMM_ReportGuestCapabilities 55
  33. #define VMM_VideoSetVisibleRegion 72
  34. #define VMMCAP_SeamlessMode (1 << 0)
  35. #define VMMCAP_HostWindows (1 << 1)
  36. #define VMMCAP_Graphics (1 << 2)
  37. #define VMMDEV_VERSION 0x00010003
  38. #define VBOX_REQUEST_HEADER_VERSION 0x10001
  39. struct vbox_header {
  40. uint32_t size;
  41. uint32_t version;
  42. uint32_t requestType;
  43. int32_t rc;
  44. uint32_t reserved1;
  45. uint32_t reserved2;
  46. };
  47. struct vbox_guest_info {
  48. struct vbox_header header;
  49. uint32_t version;
  50. uint32_t ostype;
  51. };
  52. struct vbox_guest_caps {
  53. struct vbox_header header;
  54. uint32_t caps;
  55. };
  56. struct vbox_ack_events {
  57. struct vbox_header header;
  58. uint32_t events;
  59. };
  60. struct vbox_display_change {
  61. struct vbox_header header;
  62. uint32_t xres;
  63. uint32_t yres;
  64. uint32_t bpp;
  65. uint32_t eventack;
  66. };
  67. struct vbox_mouse {
  68. struct vbox_header header;
  69. uint32_t features;
  70. int32_t x;
  71. int32_t y;
  72. };
  73. struct vbox_rtrect {
  74. int32_t xLeft;
  75. int32_t yTop;
  76. int32_t xRight;
  77. int32_t yBottom;
  78. };
  79. struct vbox_visibleregion {
  80. struct vbox_header header;
  81. uint32_t count;
  82. struct vbox_rtrect rect[1];
  83. };
  84. struct vbox_pointershape {
  85. struct vbox_header header;
  86. uint32_t flags;
  87. uint32_t xHot;
  88. uint32_t yHot;
  89. uint32_t width;
  90. uint32_t height;
  91. unsigned char data[];
  92. };
  93. #define EARLY_LOG_DEVICE 0x504
  94. static uint32_t _vbox_write(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) {
  95. for (unsigned int i = 0; i < size; ++i) {
  96. outportb(EARLY_LOG_DEVICE, buffer[i]);
  97. }
  98. return size;
  99. }
  100. static fs_node_t vb = { .write = &_vbox_write };
  101. static uint32_t vbox_device = 0;
  102. static uint32_t vbox_port = 0x0;
  103. static int vbox_irq = 0;
  104. static struct vbox_ack_events * vbox_irq_ack;
  105. static uint32_t vbox_phys_ack;
  106. static struct vbox_display_change * vbox_disp;
  107. static uint32_t vbox_phys_disp;
  108. static struct vbox_mouse * vbox_m;
  109. static uint32_t vbox_phys_mouse;
  110. static struct vbox_mouse * vbox_mg;
  111. static uint32_t vbox_phys_mouse_get;
  112. static struct vbox_visibleregion * vbox_visibleregion;
  113. static uint32_t vbox_phys_visibleregion;
  114. static struct vbox_pointershape * vbox_pointershape = NULL;
  115. static uint32_t vbox_phys_pointershape;
  116. static volatile uint32_t * vbox_vmmdev = 0;
  117. static fs_node_t * mouse_pipe;
  118. static fs_node_t * rect_pipe;
  119. static fs_node_t * pointer_pipe;
  120. static int mouse_state;
  121. #define PACKETS_IN_PIPE 1024
  122. #define DISCARD_POINT 32
  123. static int vbox_irq_handler(struct regs *r) {
  124. if (!vbox_vmmdev[2]) return 0;
  125. vbox_irq_ack->events = vbox_vmmdev[2];
  126. outportl(vbox_port, vbox_phys_ack);
  127. irq_ack(vbox_irq);
  128. outportl(vbox_port, vbox_phys_mouse_get);
  129. unsigned int x, y;
  130. if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y && vbox_mg->x && vbox_mg->y) {
  131. x = ((unsigned int)vbox_mg->x * lfb_resolution_x) / 0xFFFF;
  132. y = ((unsigned int)vbox_mg->y * lfb_resolution_y) / 0xFFFF;
  133. } else {
  134. x = vbox_mg->x;
  135. y = vbox_mg->y;
  136. }
  137. mouse_device_packet_t packet;
  138. packet.magic = MOUSE_MAGIC;
  139. packet.x_difference = x;
  140. packet.y_difference = y;
  141. packet.buttons = 0;
  142. mouse_device_packet_t bitbucket;
  143. while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) {
  144. read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket);
  145. }
  146. write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet);
  147. outportl(vbox_port, vbox_phys_disp);
  148. if (lfb_resolution_x && vbox_disp->xres && (vbox_disp->xres != lfb_resolution_x || vbox_disp->yres != lfb_resolution_y)) {
  149. lfb_set_resolution(vbox_disp->xres, vbox_disp->yres);
  150. }
  151. return 1;
  152. }
  153. void vbox_set_log(void) {
  154. debug_file = &vb;
  155. }
  156. #define VBOX_MOUSE_ON (1 << 0) | (1 << 4)
  157. #define VBOX_MOUSE_OFF (0)
  158. static void mouse_on_off(unsigned int status) {
  159. mouse_state = status;
  160. vbox_m->header.size = sizeof(struct vbox_mouse);
  161. vbox_m->header.version = VBOX_REQUEST_HEADER_VERSION;
  162. vbox_m->header.requestType = VMM_SetMouseState;
  163. vbox_m->header.rc = 0;
  164. vbox_m->header.reserved1 = 0;
  165. vbox_m->header.reserved2 = 0;
  166. vbox_m->features = status;
  167. vbox_m->x = 0;
  168. vbox_m->y = 0;
  169. outportl(vbox_port, vbox_phys_mouse);
  170. }
  171. static int ioctl_mouse(fs_node_t * node, int request, void * argp) {
  172. if (request == 1) {
  173. /* Disable */
  174. mouse_on_off(VBOX_MOUSE_OFF);
  175. return 0;
  176. }
  177. if (request == 2) {
  178. /* Enable */
  179. mouse_on_off(VBOX_MOUSE_ON);
  180. return 0;
  181. }
  182. if (request == 3) {
  183. return mouse_state == (VBOX_MOUSE_ON);
  184. }
  185. return -1;
  186. }
  187. uint32_t write_pointer(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) {
  188. if (!mouse_state) {
  189. return -1;
  190. }
  191. memcpy(&vbox_pointershape->data[288], buffer, 48*48*4);
  192. outportl(vbox_port, vbox_phys_pointershape);
  193. return size;
  194. }
  195. uint32_t write_rectpipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) {
  196. (void)node;
  197. (void)offset;
  198. /* TODO should check size */
  199. /* This is kinda special and always assumes everything was written at once. */
  200. uint32_t count = ((uint32_t *)buffer)[0];
  201. vbox_visibleregion->count = count;
  202. if (count > 254) count = 254; /* enforce maximum */
  203. #if 0
  204. fprintf(&vb, "Writing %d rectangles\n", count);
  205. #endif
  206. buffer += sizeof(uint32_t);
  207. for (unsigned int i = 0; i < count; ++i) {
  208. memcpy(&vbox_visibleregion->rect[i], buffer, sizeof(struct vbox_rtrect));
  209. #if 0
  210. fprintf(&vb, "Rectangle %d is [%d,%d,%d,%d]\n",
  211. i,
  212. vbox_visibleregion->rect[i].xLeft,
  213. vbox_visibleregion->rect[i].yTop,
  214. vbox_visibleregion->rect[i].xRight,
  215. vbox_visibleregion->rect[i].yBottom);
  216. #endif
  217. buffer += sizeof(struct vbox_rtrect);
  218. }
  219. vbox_visibleregion->header.size = sizeof(struct vbox_header) + sizeof(uint32_t) + sizeof(int32_t) * count * 4;
  220. outportl(vbox_port, vbox_phys_visibleregion);
  221. return size;
  222. }
  223. static int vbox_check(void) {
  224. pci_scan(vbox_scan_pci, -1, &vbox_device);
  225. if (vbox_device) {
  226. fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n");
  227. if (args_present("vboxdebug")) {
  228. vbox_set_log();
  229. }
  230. fprintf(&vb, "HELLO WORLD\n");
  231. uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4);
  232. if (t > 0) {
  233. vbox_port = (t & 0xFFFFFFF0);
  234. }
  235. uint16_t c = pci_read_field(vbox_device, PCI_COMMAND, 2);
  236. fprintf(&vb, "Command register: 0x%4x\n", c);
  237. if (!!(c & (1 << 10))) {
  238. fprintf(&vb, "Interrupts are disabled\n");
  239. }
  240. mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE);
  241. mouse_pipe->flags = FS_CHARDEVICE;
  242. mouse_pipe->ioctl = ioctl_mouse;
  243. vfs_mount("/dev/absmouse", mouse_pipe);
  244. vbox_irq = pci_get_interrupt(vbox_device);
  245. debug_print(WARNING, "(vbox) device IRQ is set to %d", vbox_irq);
  246. fprintf(&vb, "irq line is %d\n", vbox_irq);
  247. irq_install_handler(vbox_irq, vbox_irq_handler, "vbox");
  248. uint32_t vbox_phys = 0;
  249. struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys);
  250. packet->header.size = sizeof(struct vbox_guest_info);
  251. packet->header.version = VBOX_REQUEST_HEADER_VERSION;
  252. packet->header.requestType = VMM_ReportGuestInfo;
  253. packet->header.rc = 0;
  254. packet->header.reserved1 = 0;
  255. packet->header.reserved2 = 0;
  256. packet->version = VMMDEV_VERSION;
  257. packet->ostype = 0;
  258. outportl(vbox_port, vbox_phys);
  259. struct vbox_guest_caps * caps = (void*)kvmalloc_p(0x1000, &vbox_phys);
  260. caps->header.size = sizeof(struct vbox_guest_caps);
  261. caps->header.version = VBOX_REQUEST_HEADER_VERSION;
  262. caps->header.requestType = VMM_ReportGuestCapabilities;
  263. caps->header.rc = 0;
  264. caps->header.reserved1 = 0;
  265. caps->header.reserved2 = 0;
  266. caps->caps = VMMCAP_Graphics | (args_present("novboxseamless") ? 0 : VMMCAP_SeamlessMode);
  267. outportl(vbox_port, vbox_phys);
  268. vbox_irq_ack = (void*)kvmalloc_p(0x1000, &vbox_phys_ack);
  269. vbox_irq_ack->header.size = sizeof(struct vbox_ack_events);
  270. vbox_irq_ack->header.version = VBOX_REQUEST_HEADER_VERSION;
  271. vbox_irq_ack->header.requestType = VMM_AcknowledgeEvents;
  272. vbox_irq_ack->header.rc = 0;
  273. vbox_irq_ack->header.reserved1 = 0;
  274. vbox_irq_ack->header.reserved2 = 0;
  275. vbox_irq_ack->events = 0;
  276. vbox_disp = (void*)kvmalloc_p(0x1000, &vbox_phys_disp);
  277. vbox_disp->header.size = sizeof(struct vbox_display_change);
  278. vbox_disp->header.version = VBOX_REQUEST_HEADER_VERSION;
  279. vbox_disp->header.requestType = VMM_GetDisplayChangeRequest;
  280. vbox_disp->header.rc = 0;
  281. vbox_disp->header.reserved1 = 0;
  282. vbox_disp->header.reserved2 = 0;
  283. vbox_disp->xres = 0;
  284. vbox_disp->yres = 0;
  285. vbox_disp->bpp = 0;
  286. vbox_disp->eventack = 1;
  287. vbox_m = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse);
  288. mouse_on_off(VBOX_MOUSE_ON);
  289. /* For use with later receives */
  290. vbox_mg = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse_get);
  291. vbox_mg->header.size = sizeof(struct vbox_mouse);
  292. vbox_mg->header.version = VBOX_REQUEST_HEADER_VERSION;
  293. vbox_mg->header.requestType = VMM_GetMouseState;
  294. vbox_mg->header.rc = 0;
  295. vbox_mg->header.reserved1 = 0;
  296. vbox_mg->header.reserved2 = 0;
  297. if (!args_present("novboxpointer")) {
  298. vbox_pointershape = (void*)kvmalloc_p(0x4000, &vbox_phys_pointershape);
  299. if (vbox_pointershape) {
  300. fprintf(&vb, "Got a valid set of pages to load up a cursor.\n");
  301. vbox_pointershape->header.version = VBOX_REQUEST_HEADER_VERSION;
  302. vbox_pointershape->header.requestType = VMM_SetPointerShape;
  303. vbox_pointershape->header.rc = 0;
  304. vbox_pointershape->header.reserved1 = 0;
  305. vbox_pointershape->header.reserved2 = 0;
  306. vbox_pointershape->flags = (1 << 0) | (1 << 1) | (1 << 2);
  307. vbox_pointershape->xHot = 26;
  308. vbox_pointershape->yHot = 26;
  309. vbox_pointershape->width = 48;
  310. vbox_pointershape->height = 48;
  311. unsigned int mask_bytes = ((vbox_pointershape->width + 7) / 8) * vbox_pointershape->height;
  312. for (uint32_t i = 0; i < mask_bytes; ++i) {
  313. vbox_pointershape->data[i] = 0x00;
  314. }
  315. while (mask_bytes & 3) {
  316. mask_bytes++;
  317. }
  318. int base = mask_bytes;
  319. fprintf(&vb, "mask_bytes = %d\n", mask_bytes);
  320. vbox_pointershape->header.size = sizeof(struct vbox_pointershape) + (48*48*4)+mask_bytes; /* update later */
  321. for (int i = 0; i < 48 * 48; ++i) {
  322. vbox_pointershape->data[base+i*4] = 0x00; /* blue */
  323. vbox_pointershape->data[base+i*4+1] = 0x00; /* red */
  324. vbox_pointershape->data[base+i*4+2] = 0x00; /* green */
  325. vbox_pointershape->data[base+i*4+3] = 0x00; /* alpha */
  326. }
  327. outportl(vbox_port, vbox_phys_pointershape);
  328. if (vbox_pointershape->header.rc < 0) {
  329. fprintf(&vb, "Bad response code: -%d\n", -vbox_pointershape->header.rc);
  330. } else {
  331. /* Success, let's install the device file */
  332. fprintf(&vb, "Successfully initialized cursor, going to allow compositor to set it.\n");
  333. pointer_pipe = malloc(sizeof(fs_node_t));
  334. memset(pointer_pipe, 0, sizeof(fs_node_t));
  335. pointer_pipe->mask = 0666;
  336. pointer_pipe->flags = FS_CHARDEVICE;
  337. pointer_pipe->write = write_pointer;
  338. vfs_mount("/dev/vboxpointer", pointer_pipe);
  339. }
  340. }
  341. }
  342. if (!args_present("novboxseamless")) {
  343. vbox_visibleregion = (void*)kvmalloc_p(0x1000, &vbox_phys_visibleregion);
  344. vbox_visibleregion->header.size = sizeof(struct vbox_header) + sizeof(uint32_t) + sizeof(int32_t) * 4; /* TODO + more for additional rects? */
  345. vbox_visibleregion->header.version = VBOX_REQUEST_HEADER_VERSION;
  346. vbox_visibleregion->header.requestType = VMM_VideoSetVisibleRegion;
  347. vbox_visibleregion->header.rc = 0;
  348. vbox_visibleregion->header.reserved1 = 0;
  349. vbox_visibleregion->header.reserved2 = 0;
  350. vbox_visibleregion->count = 1;
  351. vbox_visibleregion->rect[0].xLeft = 0;
  352. vbox_visibleregion->rect[0].yTop = 0;
  353. vbox_visibleregion->rect[0].xRight = 1440;
  354. vbox_visibleregion->rect[0].yBottom = 900;
  355. outportl(vbox_port, vbox_phys_visibleregion);
  356. rect_pipe = malloc(sizeof(fs_node_t));
  357. memset(rect_pipe, 0, sizeof(fs_node_t));
  358. rect_pipe->mask = 0666;
  359. rect_pipe->flags = FS_CHARDEVICE;
  360. rect_pipe->write = write_rectpipe;
  361. vfs_mount("/dev/vboxrects", rect_pipe);
  362. }
  363. /* device memory region mapping? */
  364. {
  365. uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4);
  366. fprintf(&vb, "mapping vmm_dev = 0x%x\n", t);
  367. if (t > 0) {
  368. vbox_vmmdev = (void *)(t & 0xFFFFFFF0);
  369. }
  370. uintptr_t fb_offset = (uintptr_t)vbox_vmmdev;
  371. for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) {
  372. dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
  373. }
  374. }
  375. vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */
  376. }
  377. return 0;
  378. }
  379. static int fini(void) {
  380. return 0;
  381. }
  382. MODULE_DEF(vboxguest, vbox_check, fini);
  383. MODULE_DEPENDS(lfbvideo);