diff --git a/Makefile b/Makefile index b96797ed..835bd4a0 100644 --- a/Makefile +++ b/Makefile @@ -83,6 +83,7 @@ BOOT_MODULES += ext2 BOOT_MODULES += debug_shell BOOT_MODULES += ps2mouse ps2kbd BOOT_MODULES += lfbvideo +BOOT_MODULES += vidset BOOT_MODULES += packetfs BOOT_MODULES += snd BOOT_MODULES += pcspkr diff --git a/kernel/include/video.h b/kernel/include/video.h index ab41ba68..b8f50146 100644 --- a/kernel/include/video.h +++ b/kernel/include/video.h @@ -7,4 +7,12 @@ #define IO_VID_ADDR 0x5004 #define IO_VID_SIGNAL 0x5005 +#ifdef _KERNEL_ +extern void lfb_set_resolution(uint16_t x, uint16_t y); +extern uint16_t lfb_resolution_x; +extern uint16_t lfb_resolution_y; +extern uint16_t lfb_resolution_b; +extern uint8_t * lfb_vid_memory; +#endif + #endif diff --git a/modules/lfbvideo.c b/modules/lfbvideo.c index 377406f9..b16eaa13 100644 --- a/modules/lfbvideo.c +++ b/modules/lfbvideo.c @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include "../userspace/gui/terminal/terminal-font.h" @@ -27,16 +25,15 @@ /* Generic (pre-set, 32-bit, linear frame buffer) */ static void graphics_install_preset(uint16_t, uint16_t); -static uint16_t lfb_resolution_x = 0; -static uint16_t lfb_resolution_y = 0; -static uint16_t lfb_resolution_b = 0; +uint16_t lfb_resolution_x = 0; +uint16_t lfb_resolution_y = 0; +uint16_t lfb_resolution_b = 0; /* BOCHS / QEMU VBE Driver */ static void graphics_install_bochs(uint16_t, uint16_t); static void bochs_set_y_offset(uint16_t y); static uint16_t bochs_current_scroll(void); -static void vbox_check(void); static pid_t display_change_recipient = 0; /* @@ -44,7 +41,7 @@ static pid_t display_change_recipient = 0; * This can move, so it's a pointer instead of * #define. */ -static uint8_t * lfb_vid_memory = (uint8_t *)0xE0000000; +uint8_t * lfb_vid_memory = (uint8_t *)0xE0000000; static int ioctl_vid(fs_node_t * node, int request, void * argp) { /* TODO: Make this actually support multiple video devices */ @@ -199,11 +196,42 @@ static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra } } +static void (*lfb_resolution_impl)(uint16_t,uint16_t) = NULL; + +void lfb_set_resolution(uint16_t x, uint16_t y) { + + if (lfb_resolution_impl) { + lfb_resolution_impl(x,y); + if (display_change_recipient) { + send_signal(display_change_recipient, SIGWINEVENT); + debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient); + } + } + +} + +static void res_change_bochs(uint16_t x, uint16_t y) { + + outports(0x1CE, 0x04); + outports(0x1CF, 0x00); + /* Uh oh, here we go. */ + outports(0x1CE, 0x01); + outports(0x1CF, x); + /* Set Y resolution to 768 */ + outports(0x1CE, 0x02); + outports(0x1CF, y); + /* Turn it back on */ + outports(0x1CE, 0x04); + outports(0x1CF, 0x41); + + lfb_resolution_x = x; + lfb_resolution_y = y; +} + + static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) { debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller..."); - vbox_check(); - outports(0x1CE, 0x00); uint16_t i = inports(0x1CF); if (i < 0xB0C0 || i > 0xB0C6) { @@ -232,6 +260,8 @@ static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) pci_scan(bochs_scan_pci, -1, &lfb_vid_memory); + lfb_resolution_impl = &res_change_bochs; + if (lfb_vid_memory) { /* Enable the higher memory */ uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; @@ -332,231 +362,6 @@ mem_found: } } -#define VBOX_VENDOR_ID 0x80EE -#define VBOX_DEVICE_ID 0xCAFE - -static void vbox_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { - if (v == VBOX_VENDOR_ID && d == VBOX_DEVICE_ID) { - *((uint32_t *)extra) = device; - } -} - -#define VMMDEV_VERSION 0x00010003 -#define VBOX_REQUEST_HEADER_VERSION 0x10001 -struct vbox_header { - uint32_t size; - uint32_t version; - uint32_t requestType; - int32_t rc; - uint32_t reserved1; - uint32_t reserved2; -}; - -struct vbox_guest_info { - struct vbox_header header; - uint32_t version; - uint32_t ostype; -}; - -struct vbox_guest_caps { - struct vbox_header header; - uint32_t caps; -}; - -struct vbox_ack_events { - struct vbox_header header; - uint32_t events; -}; - -struct vbox_display_change { - struct vbox_header header; - uint32_t xres; - uint32_t yres; - uint32_t bpp; - uint32_t eventack; -}; - -struct vbox_mouse { - struct vbox_header header; - uint32_t features; - int32_t x; - int32_t y; -}; - - -#define EARLY_LOG_DEVICE 0x504 -static uint32_t _vbox_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - for (unsigned int i = 0; i < size; ++i) { - outportb(EARLY_LOG_DEVICE, buffer[i]); - } - return size; -} -static fs_node_t vb = { .write = &_vbox_write }; - -static uint32_t vbox_device = 0; -static uint32_t vbox_port = 0x0; -static int vbox_irq = 0; - -static struct vbox_ack_events * vbox_irq_ack; -static uint32_t vbox_phys_ack; -static struct vbox_display_change * vbox_disp; -static uint32_t vbox_phys_disp; -static struct vbox_mouse * vbox_m; -static uint32_t vbox_phys_mouse; -static uint32_t * vbox_vmmdev = 0; - -static fs_node_t * mouse_pipe; - -#define PACKETS_IN_PIPE 1024 -#define DISCARD_POINT 32 - -static int vbox_irq_handler(struct regs *r) { - // debug_print(WARNING, "(vbox-toaru) irq received; pending events are 0x%x", vbox_vmmdev[4]); - outportl(vbox_port, vbox_phys_disp); - outportl(vbox_port, vbox_phys_mouse); - outportl(vbox_port, vbox_phys_ack); - irq_ack(vbox_irq); - // debug_print(WARNING, "Display stuff: %d %d %d\n", vbox_disp->xres, vbox_disp->yres, vbox_disp->bpp); - - if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y && vbox_m->x && vbox_m->y) { - // debug_print(WARNING, "Mouse stuff: 0x%x 0x%x 0x%x\n", vbox_m->features, vbox_m->x, vbox_m->y); - - unsigned int x = ((unsigned int)vbox_m->x * lfb_resolution_x) / 0xFFFF; - unsigned int y = ((unsigned int)vbox_m->y * lfb_resolution_y) / 0xFFFF; - - mouse_device_packet_t packet; - packet.magic = MOUSE_MAGIC; - packet.x_difference = x; - packet.y_difference = y; - packet.buttons = 0; - - mouse_device_packet_t bitbucket; - while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { - read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); - } - write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); - } - - - if (lfb_resolution_x && vbox_disp->xres && (vbox_disp->xres != lfb_resolution_x || vbox_disp->yres != lfb_resolution_y)) { - outports(0x1CE, 0x04); - outports(0x1CF, 0x00); - /* Uh oh, here we go. */ - outports(0x1CE, 0x01); - outports(0x1CF, vbox_disp->xres); - /* Set Y resolution to 768 */ - outports(0x1CE, 0x02); - outports(0x1CF, vbox_disp->yres); - /* Turn it back on */ - outports(0x1CE, 0x04); - outports(0x1CF, 0x41); - lfb_resolution_x = vbox_disp->xres; - lfb_resolution_y = vbox_disp->yres; - - if (display_change_recipient) { - send_signal(display_change_recipient, SIGWINEVENT); - debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient); - } - - } - return 1; -} - -static void vbox_check(void) { - pci_scan(vbox_scan_pci, -1, &vbox_device); - - if (vbox_device) { - fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n"); - debug_file = &vb; - - uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4); - if (t > 0) { - vbox_port = (t & 0xFFFFFFF0); - } - - mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); - mouse_pipe->flags = FS_CHARDEVICE; - - vfs_mount("/dev/absmouse", mouse_pipe); - - vbox_irq = pci_read_field(vbox_device, PCI_INTERRUPT_LINE, 1); - debug_print(WARNING, "(vbox) device IRQ is set to %d\n", vbox_irq); - irq_install_handler(vbox_irq, vbox_irq_handler); - - uint32_t vbox_phys = 0; - struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys); - packet->header.size = sizeof(struct vbox_guest_info); - packet->header.version = VBOX_REQUEST_HEADER_VERSION; - packet->header.requestType = 50; - packet->header.rc = 0; - packet->header.reserved1 = 0; - packet->header.reserved2 = 0; - packet->version = VMMDEV_VERSION; - packet->ostype = 0; - - outportl(vbox_port, vbox_phys); - - struct vbox_guest_caps * caps = (void*)kvmalloc_p(0x1000, &vbox_phys); - caps->header.size = sizeof(struct vbox_guest_caps); - caps->header.version = VBOX_REQUEST_HEADER_VERSION; - caps->header.requestType = 55; - caps->header.rc = 0; - caps->header.reserved1 = 0; - caps->header.reserved2 = 0; - caps->caps = 1 << 2; - outportl(vbox_port, vbox_phys); - - vbox_irq_ack = (void*)kvmalloc_p(0x1000, &vbox_phys_ack); - vbox_irq_ack->header.size = sizeof(struct vbox_ack_events); - vbox_irq_ack->header.version = VBOX_REQUEST_HEADER_VERSION; - vbox_irq_ack->header.requestType = 41; - vbox_irq_ack->header.rc = 0; - vbox_irq_ack->header.reserved1 = 0; - vbox_irq_ack->header.reserved2 = 0; - vbox_irq_ack->events = 0; - - vbox_disp = (void*)kvmalloc_p(0x1000, &vbox_phys_disp); - vbox_disp->header.size = sizeof(struct vbox_display_change); - vbox_disp->header.version = VBOX_REQUEST_HEADER_VERSION; - vbox_disp->header.requestType = 51; - vbox_disp->header.rc = 0; - vbox_disp->header.reserved1 = 0; - vbox_disp->header.reserved2 = 0; - vbox_disp->xres = 0; - vbox_disp->yres = 0; - vbox_disp->bpp = 0; - vbox_disp->eventack = 1; - - vbox_m = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse); - vbox_m->header.size = sizeof(struct vbox_mouse); - vbox_m->header.version = VBOX_REQUEST_HEADER_VERSION; - vbox_m->header.requestType = 2; - vbox_m->header.rc = 0; - vbox_m->header.reserved1 = 0; - vbox_m->header.reserved2 = 0; - vbox_m->features = (1 << 0) | (1 << 4); - vbox_m->x = 0; - vbox_m->y = 0; - outportl(vbox_port, vbox_phys_mouse); - - vbox_m->header.requestType = 1; - - /* device memory region mapping? */ - { - uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4); - if (t > 0) { - vbox_vmmdev = (void *)(t & 0xFFFFFFF0); - } - uintptr_t fb_offset = (uintptr_t)vbox_vmmdev; - for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - } - - vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */ - } -} - #define SVGA_IO_BASE (vmware_io) #define SVGA_IO_MUL 1 #define SVGA_INDEX_PORT 0 @@ -590,6 +395,18 @@ static uint32_t vmware_read(int reg) { return inportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE); } +static void vmware_set_mode(uint16_t w, uint16_t h) { + vmware_write(SVGA_REG_ENABLE, 0); + vmware_write(SVGA_REG_ID, 0); + vmware_write(SVGA_REG_WIDTH, w); + vmware_write(SVGA_REG_HEIGHT, h); + vmware_write(SVGA_REG_BITS_PER_PIXEL, 32); + vmware_write(SVGA_REG_ENABLE, 1); + + lfb_resolution_x = w; + lfb_resolution_y = h; +} + static void graphics_install_vmware(uint16_t w, uint16_t h) { debug_print(WARNING, "Please note that the `vmware` display driver is experimental."); pci_scan(vmware_scan_pci, -1, &vmware_io); @@ -607,6 +424,8 @@ static void graphics_install_vmware(uint16_t w, uint16_t h) { vmware_write(SVGA_REG_BITS_PER_PIXEL, 32); vmware_write(SVGA_REG_ENABLE, 1); + lfb_resolution_impl = &vmware_set_mode; + uint32_t fb_addr = vmware_read(SVGA_REG_FB_START); debug_print(WARNING, "vmware fb address: 0x%x", fb_addr); diff --git a/modules/vboxguest.c b/modules/vboxguest.c new file mode 100644 index 00000000..0c13f30e --- /dev/null +++ b/modules/vboxguest.c @@ -0,0 +1,231 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016 Kevin Lange + * + * VirtualBox Guest Additions driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VBOX_VENDOR_ID 0x80EE +#define VBOX_DEVICE_ID 0xCAFE + +static void vbox_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { + if (v == VBOX_VENDOR_ID && d == VBOX_DEVICE_ID) { + *((uint32_t *)extra) = device; + } +} + +#define VMMDEV_VERSION 0x00010003 +#define VBOX_REQUEST_HEADER_VERSION 0x10001 +struct vbox_header { + uint32_t size; + uint32_t version; + uint32_t requestType; + int32_t rc; + uint32_t reserved1; + uint32_t reserved2; +}; + +struct vbox_guest_info { + struct vbox_header header; + uint32_t version; + uint32_t ostype; +}; + +struct vbox_guest_caps { + struct vbox_header header; + uint32_t caps; +}; + +struct vbox_ack_events { + struct vbox_header header; + uint32_t events; +}; + +struct vbox_display_change { + struct vbox_header header; + uint32_t xres; + uint32_t yres; + uint32_t bpp; + uint32_t eventack; +}; + +struct vbox_mouse { + struct vbox_header header; + uint32_t features; + int32_t x; + int32_t y; +}; + + +#define EARLY_LOG_DEVICE 0x504 +static uint32_t _vbox_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + for (unsigned int i = 0; i < size; ++i) { + outportb(EARLY_LOG_DEVICE, buffer[i]); + } + return size; +} +static fs_node_t vb = { .write = &_vbox_write }; + +static uint32_t vbox_device = 0; +static uint32_t vbox_port = 0x0; +static int vbox_irq = 0; + +static struct vbox_ack_events * vbox_irq_ack; +static uint32_t vbox_phys_ack; +static struct vbox_display_change * vbox_disp; +static uint32_t vbox_phys_disp; +static struct vbox_mouse * vbox_m; +static uint32_t vbox_phys_mouse; +static uint32_t * vbox_vmmdev = 0; + +static fs_node_t * mouse_pipe; + +#define PACKETS_IN_PIPE 1024 +#define DISCARD_POINT 32 + +static int vbox_irq_handler(struct regs *r) { + outportl(vbox_port, vbox_phys_disp); + outportl(vbox_port, vbox_phys_mouse); + outportl(vbox_port, vbox_phys_ack); + irq_ack(vbox_irq); + + if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y && vbox_m->x && vbox_m->y) { + unsigned int x = ((unsigned int)vbox_m->x * lfb_resolution_x) / 0xFFFF; + unsigned int y = ((unsigned int)vbox_m->y * lfb_resolution_y) / 0xFFFF; + + mouse_device_packet_t packet; + packet.magic = MOUSE_MAGIC; + packet.x_difference = x; + packet.y_difference = y; + packet.buttons = 0; + + mouse_device_packet_t bitbucket; + while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { + read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); + } + write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); + } + + + if (lfb_resolution_x && vbox_disp->xres && (vbox_disp->xres != lfb_resolution_x || vbox_disp->yres != lfb_resolution_y)) { + + lfb_set_resolution(vbox_disp->xres, vbox_disp->yres); + } + return 1; +} + +static int vbox_check(void) { + pci_scan(vbox_scan_pci, -1, &vbox_device); + + if (vbox_device) { + fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n"); + debug_file = &vb; + + uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4); + if (t > 0) { + vbox_port = (t & 0xFFFFFFF0); + } + + mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); + mouse_pipe->flags = FS_CHARDEVICE; + + vfs_mount("/dev/absmouse", mouse_pipe); + + vbox_irq = pci_read_field(vbox_device, PCI_INTERRUPT_LINE, 1); + debug_print(WARNING, "(vbox) device IRQ is set to %d\n", vbox_irq); + irq_install_handler(vbox_irq, vbox_irq_handler); + + uint32_t vbox_phys = 0; + struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys); + packet->header.size = sizeof(struct vbox_guest_info); + packet->header.version = VBOX_REQUEST_HEADER_VERSION; + packet->header.requestType = 50; + packet->header.rc = 0; + packet->header.reserved1 = 0; + packet->header.reserved2 = 0; + packet->version = VMMDEV_VERSION; + packet->ostype = 0; + + outportl(vbox_port, vbox_phys); + + struct vbox_guest_caps * caps = (void*)kvmalloc_p(0x1000, &vbox_phys); + caps->header.size = sizeof(struct vbox_guest_caps); + caps->header.version = VBOX_REQUEST_HEADER_VERSION; + caps->header.requestType = 55; + caps->header.rc = 0; + caps->header.reserved1 = 0; + caps->header.reserved2 = 0; + caps->caps = 1 << 2; + outportl(vbox_port, vbox_phys); + + vbox_irq_ack = (void*)kvmalloc_p(0x1000, &vbox_phys_ack); + vbox_irq_ack->header.size = sizeof(struct vbox_ack_events); + vbox_irq_ack->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_irq_ack->header.requestType = 41; + vbox_irq_ack->header.rc = 0; + vbox_irq_ack->header.reserved1 = 0; + vbox_irq_ack->header.reserved2 = 0; + vbox_irq_ack->events = 0; + + vbox_disp = (void*)kvmalloc_p(0x1000, &vbox_phys_disp); + vbox_disp->header.size = sizeof(struct vbox_display_change); + vbox_disp->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_disp->header.requestType = 51; + vbox_disp->header.rc = 0; + vbox_disp->header.reserved1 = 0; + vbox_disp->header.reserved2 = 0; + vbox_disp->xres = 0; + vbox_disp->yres = 0; + vbox_disp->bpp = 0; + vbox_disp->eventack = 1; + + vbox_m = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse); + vbox_m->header.size = sizeof(struct vbox_mouse); + vbox_m->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_m->header.requestType = 2; + vbox_m->header.rc = 0; + vbox_m->header.reserved1 = 0; + vbox_m->header.reserved2 = 0; + vbox_m->features = (1 << 0) | (1 << 4); + vbox_m->x = 0; + vbox_m->y = 0; + outportl(vbox_port, vbox_phys_mouse); + + vbox_m->header.requestType = 1; + + /* device memory region mapping? */ + { + uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4); + if (t > 0) { + vbox_vmmdev = (void *)(t & 0xFFFFFFF0); + } + uintptr_t fb_offset = (uintptr_t)vbox_vmmdev; + for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + } + + vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */ + } + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(vboxguest, vbox_check, fini); +MODULE_DEPENDS(lfbvideo); diff --git a/modules/vidset.c b/modules/vidset.c new file mode 100644 index 00000000..90ca244f --- /dev/null +++ b/modules/vidset.c @@ -0,0 +1,43 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016 Kevin Lange + * + * Module to provide a debug shell command to set display mode. + */ +#include +#include +#include +#include +#include + +#include +#include + +DEFINE_SHELL_FUNCTION(set_mode, "Set display mode") { + if (argc < 3) { + fprintf(tty, "set_mode \n"); + return 1; + } + int x = atoi(argv[1]); + int y = atoi(argv[2]); + fprintf(tty, "Setting mode to %dx%d.\n", x, y); + lfb_set_resolution(x,y); + return 0; +} + +static int hello(void) { + BIND_SHELL_FUNCTION(set_mode); + + return 0; +} + +static int goodbye(void) { + return 0; +} + +MODULE_DEF(test, hello, goodbye); +MODULE_DEPENDS(debugshell); +MODULE_DEPENDS(lfbvideo); + + diff --git a/util/cdrom/boot/grub/grub.cfg b/util/cdrom/boot/grub/grub.cfg index b8e87aeb..0ceef6c1 100644 --- a/util/cdrom/boot/grub/grub.cfg +++ b/util/cdrom/boot/grub/grub.cfg @@ -43,6 +43,8 @@ function load_modules { module /mod/ps2kbd.ko module /mod/ps2mouse.ko module /mod/lfbvideo.ko + module /mod/vboxguest.ko + module /mod/vidset.ko module /mod/packetfs.ko module /mod/snd.ko module /mod/ac97.ko