2014-06-08 10:51:01 +04:00
|
|
|
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
2014-06-08 10:58:31 +04:00
|
|
|
* This file is part of ToaruOS and is released under the terms
|
2014-06-08 10:13:29 +04:00
|
|
|
* of the NCSA / University of Illinois License - see LICENSE.md
|
|
|
|
* Copyright (C) 2014 Kevin Lange
|
2012-09-18 09:22:25 +04:00
|
|
|
*
|
|
|
|
* Bochs VBE / QEMU vga=std Graphics Driver
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <system.h>
|
|
|
|
#include <fs.h>
|
2014-04-06 03:36:17 +04:00
|
|
|
#include <printf.h>
|
2012-09-18 09:22:25 +04:00
|
|
|
#include <types.h>
|
|
|
|
#include <logging.h>
|
2013-12-13 11:40:52 +04:00
|
|
|
#include <pci.h>
|
2014-03-20 05:56:07 +04:00
|
|
|
#include <boot.h>
|
|
|
|
#include <args.h>
|
|
|
|
#include <tokenize.h>
|
|
|
|
#include <module.h>
|
|
|
|
#include <video.h>
|
2016-08-30 09:45:58 +03:00
|
|
|
#include <pipe.h>
|
|
|
|
#include <mouse.h>
|
2012-09-18 09:22:25 +04:00
|
|
|
|
2014-05-11 06:12:31 +04:00
|
|
|
#include "../userspace/gui/terminal/terminal-font.h"
|
|
|
|
|
2012-09-18 09:22:25 +04:00
|
|
|
#define PREFERRED_VY 4096
|
|
|
|
#define PREFERRED_B 32
|
2014-03-20 05:56:07 +04:00
|
|
|
/* Generic (pre-set, 32-bit, linear frame buffer) */
|
|
|
|
static void graphics_install_preset(uint16_t, uint16_t);
|
2012-09-18 09:22:25 +04:00
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
static uint16_t lfb_resolution_x = 0;
|
|
|
|
static uint16_t lfb_resolution_y = 0;
|
|
|
|
static 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);
|
2012-09-18 09:22:25 +04:00
|
|
|
|
2016-08-30 09:45:58 +03:00
|
|
|
static void vbox_check(void);
|
|
|
|
static pid_t display_change_recipient = 0;
|
|
|
|
|
2012-09-18 09:22:25 +04:00
|
|
|
/*
|
|
|
|
* Address of the linear frame buffer.
|
|
|
|
* This can move, so it's a pointer instead of
|
|
|
|
* #define.
|
|
|
|
*/
|
2014-03-20 05:56:07 +04:00
|
|
|
static 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 */
|
|
|
|
|
|
|
|
switch (request) {
|
|
|
|
case IO_VID_WIDTH:
|
|
|
|
validate(argp);
|
|
|
|
*((size_t *)argp) = lfb_resolution_x;
|
|
|
|
return 0;
|
|
|
|
case IO_VID_HEIGHT:
|
|
|
|
validate(argp);
|
|
|
|
*((size_t *)argp) = lfb_resolution_y;
|
|
|
|
return 0;
|
|
|
|
case IO_VID_DEPTH:
|
|
|
|
validate(argp);
|
|
|
|
*((size_t *)argp) = lfb_resolution_b;
|
|
|
|
return 0;
|
|
|
|
case IO_VID_ADDR:
|
|
|
|
validate(argp);
|
|
|
|
*((uintptr_t *)argp) = (uintptr_t)lfb_vid_memory;
|
|
|
|
return 0;
|
2016-08-30 09:45:58 +03:00
|
|
|
case IO_VID_SIGNAL:
|
|
|
|
/* ioctl to register for a signal (vid device change? idk) on display change */
|
|
|
|
display_change_recipient = getpid();
|
|
|
|
return 0;
|
2014-03-20 05:56:07 +04:00
|
|
|
default:
|
|
|
|
return -1; /* TODO EINV... something or other */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-11 01:46:18 +04:00
|
|
|
static int vignette_at(int x, int y) {
|
|
|
|
int amount = 0;
|
|
|
|
int level = 100;
|
|
|
|
if (x < level) amount += (level - x);
|
|
|
|
if (x > lfb_resolution_x - level) amount += (level - (lfb_resolution_x - x));
|
|
|
|
if (y < level) amount += (level - y);
|
|
|
|
if (y > lfb_resolution_y - level) amount += (level - (lfb_resolution_y - y));
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
2014-05-11 06:12:31 +04:00
|
|
|
#define char_height 12
|
|
|
|
#define char_width 8
|
|
|
|
|
|
|
|
static void set_point(int x, int y, uint32_t value) {
|
|
|
|
uint32_t * disp = (uint32_t *)lfb_vid_memory;
|
|
|
|
uint32_t * cell = &disp[y * lfb_resolution_x + x];
|
|
|
|
*cell = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_char(int x, int y, int val, uint32_t color) {
|
|
|
|
if (val > 128) {
|
|
|
|
val = 4;
|
|
|
|
}
|
|
|
|
uint8_t * c = number_font[val];
|
|
|
|
for (uint8_t i = 0; i < char_height; ++i) {
|
|
|
|
for (uint8_t j = 0; j < char_width; ++j) {
|
|
|
|
if (c[i] & (1 << (8-j))) {
|
|
|
|
set_point(x+j,y+i,color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-11 01:03:13 +04:00
|
|
|
#define _RED(color) ((color & 0x00FF0000) / 0x10000)
|
|
|
|
#define _GRE(color) ((color & 0x0000FF00) / 0x100)
|
|
|
|
#define _BLU(color) ((color & 0x000000FF) / 0x1)
|
|
|
|
#define _ALP(color) ((color & 0xFF000000) / 0x1000000)
|
2014-05-11 06:12:31 +04:00
|
|
|
static void lfb_video_panic(char ** msgs) {
|
2014-05-11 01:03:13 +04:00
|
|
|
/* Desaturate the display */
|
|
|
|
uint32_t * disp = (uint32_t *)lfb_vid_memory;
|
|
|
|
for (int y = 0; y < lfb_resolution_y; y++) {
|
|
|
|
for (int x = 0; x < lfb_resolution_x; x++) {
|
|
|
|
uint32_t * cell = &disp[y * lfb_resolution_x + x];
|
|
|
|
|
|
|
|
int r = _RED(*cell);
|
|
|
|
int g = _GRE(*cell);
|
|
|
|
int b = _BLU(*cell);
|
|
|
|
|
2014-05-11 01:46:18 +04:00
|
|
|
int l = 3 * r + 6 * g + 1 * b;
|
|
|
|
r = (l) / 10;
|
|
|
|
g = (l) / 10;
|
|
|
|
b = (l) / 10;
|
|
|
|
|
|
|
|
r = r > 255 ? 255 : r;
|
|
|
|
g = g > 255 ? 255 : g;
|
|
|
|
b = b > 255 ? 255 : b;
|
|
|
|
|
|
|
|
int amount = vignette_at(x,y);
|
|
|
|
r = (r - amount < 0) ? 0 : r - amount;
|
|
|
|
g = (g - amount < 0) ? 0 : g - amount;
|
|
|
|
b = (b - amount < 0) ? 0 : b - amount;
|
2014-05-11 01:03:13 +04:00
|
|
|
|
2014-05-11 01:46:18 +04:00
|
|
|
*cell = 0xFF000000 + ((0xFF & r) * 0x10000) + ((0xFF & g) * 0x100) + ((0xFF & b) * 0x1);
|
2014-05-11 01:03:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-11 06:12:31 +04:00
|
|
|
/* Now print the message, divided on line feeds, into the center of the screen */
|
|
|
|
int num_entries = 0;
|
|
|
|
for (char ** m = msgs; *m; m++, num_entries++);
|
|
|
|
int y = (lfb_resolution_y - (num_entries * char_height)) / 2;
|
|
|
|
for (char ** message = msgs; *message; message++) {
|
|
|
|
int x = (lfb_resolution_x - (strlen(*message) * char_width)) / 2;
|
|
|
|
for (char * c = *message; *c; c++) {
|
|
|
|
write_char(x+1, y+1, *c, 0xFF000000);
|
|
|
|
write_char(x, y, *c, 0xFFFF0000);
|
|
|
|
x += char_width;
|
|
|
|
}
|
|
|
|
y += char_height;
|
|
|
|
}
|
|
|
|
|
2014-05-11 01:03:13 +04:00
|
|
|
}
|
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
static fs_node_t * lfb_video_device_create(void /* TODO */) {
|
|
|
|
fs_node_t * fnode = malloc(sizeof(fs_node_t));
|
|
|
|
memset(fnode, 0x00, sizeof(fs_node_t));
|
|
|
|
sprintf(fnode->name, "fb0"); /* TODO */
|
|
|
|
fnode->length = lfb_resolution_x * lfb_resolution_y * (lfb_resolution_b / 8);
|
|
|
|
fnode->flags = FS_BLOCKDEVICE;
|
|
|
|
fnode->ioctl = ioctl_vid;
|
|
|
|
return fnode;
|
|
|
|
}
|
2012-09-18 09:22:25 +04:00
|
|
|
|
2012-09-18 09:46:43 +04:00
|
|
|
static void finalize_graphics(uint16_t x, uint16_t y, uint16_t b) {
|
|
|
|
lfb_resolution_x = x;
|
|
|
|
lfb_resolution_y = y;
|
|
|
|
lfb_resolution_b = b;
|
2014-03-20 05:56:07 +04:00
|
|
|
fs_node_t * fb_device = lfb_video_device_create();
|
|
|
|
vfs_mount("/dev/fb0", fb_device);
|
2014-05-11 01:03:13 +04:00
|
|
|
debug_video_crash = lfb_video_panic;
|
2012-09-18 09:46:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Bochs support {{{ */
|
2014-03-20 05:56:07 +04:00
|
|
|
static uintptr_t current_scroll = 0;
|
2012-09-18 09:22:25 +04:00
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
static void bochs_set_y_offset(uint16_t y) {
|
2012-09-18 09:22:25 +04:00
|
|
|
outports(0x1CE, 0x9);
|
|
|
|
outports(0x1CF, y);
|
|
|
|
current_scroll = y;
|
|
|
|
}
|
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
static uint16_t bochs_current_scroll(void) {
|
2012-09-18 09:22:25 +04:00
|
|
|
return current_scroll;
|
|
|
|
}
|
|
|
|
|
2014-04-11 10:34:55 +04:00
|
|
|
static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
|
2015-04-04 22:18:09 +03:00
|
|
|
if ((v == 0x1234 && d == 0x1111) ||
|
|
|
|
(v == 0x80EE && d == 0xBEEF)) {
|
2013-12-13 11:40:52 +04:00
|
|
|
uintptr_t t = pci_read_field(device, PCI_BAR0, 4);
|
|
|
|
if (t > 0) {
|
2014-04-11 10:34:55 +04:00
|
|
|
*((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0);
|
2013-12-13 11:40:52 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
|
2012-12-08 06:33:07 +04:00
|
|
|
debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller...");
|
2014-03-20 05:56:07 +04:00
|
|
|
|
2016-08-30 09:45:58 +03:00
|
|
|
vbox_check();
|
|
|
|
|
2012-09-18 09:22:25 +04:00
|
|
|
outports(0x1CE, 0x00);
|
|
|
|
uint16_t i = inports(0x1CF);
|
|
|
|
if (i < 0xB0C0 || i > 0xB0C6) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
outports(0x1CF, 0xB0C4);
|
|
|
|
i = inports(0x1CF);
|
|
|
|
/* Disable VBE */
|
|
|
|
outports(0x1CE, 0x04);
|
|
|
|
outports(0x1CF, 0x00);
|
|
|
|
/* Set X resolution to 1024 */
|
|
|
|
outports(0x1CE, 0x01);
|
|
|
|
outports(0x1CF, resolution_x);
|
|
|
|
/* Set Y resolution to 768 */
|
|
|
|
outports(0x1CE, 0x02);
|
|
|
|
outports(0x1CF, resolution_y);
|
|
|
|
/* Set bpp to 32 */
|
|
|
|
outports(0x1CE, 0x03);
|
|
|
|
outports(0x1CF, PREFERRED_B);
|
|
|
|
/* Set Virtual Height to stuff */
|
|
|
|
outports(0x1CE, 0x07);
|
|
|
|
outports(0x1CF, PREFERRED_VY);
|
|
|
|
/* Re-enable VBE */
|
|
|
|
outports(0x1CE, 0x04);
|
|
|
|
outports(0x1CF, 0x41);
|
|
|
|
|
2014-04-11 10:34:55 +04:00
|
|
|
pci_scan(bochs_scan_pci, -1, &lfb_vid_memory);
|
2012-09-18 09:22:25 +04:00
|
|
|
|
2013-12-13 11:40:52 +04:00
|
|
|
if (lfb_vid_memory) {
|
2012-09-18 09:22:25 +04:00
|
|
|
/* Enable the higher memory */
|
2013-12-13 11:40:52 +04:00
|
|
|
uintptr_t fb_offset = (uintptr_t)lfb_vid_memory;
|
2012-09-18 09:22:25 +04:00
|
|
|
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
|
|
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
|
|
|
}
|
|
|
|
|
2013-12-13 11:40:52 +04:00
|
|
|
goto mem_found;
|
|
|
|
} else {
|
|
|
|
/* XXX: Massive hack */
|
|
|
|
|
|
|
|
uint32_t * text_vid_mem = (uint32_t *)0xA0000;
|
|
|
|
text_vid_mem[0] = 0xA5ADFACE;
|
|
|
|
|
|
|
|
for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
|
|
|
|
/* Enable the higher memory */
|
|
|
|
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
|
|
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
2012-09-18 09:22:25 +04:00
|
|
|
}
|
|
|
|
|
2013-12-13 11:40:52 +04:00
|
|
|
/* Go find it */
|
|
|
|
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
|
|
|
|
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
|
|
|
|
lfb_vid_memory = (uint8_t *)x;
|
|
|
|
goto mem_found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-18 09:22:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
mem_found:
|
2015-05-04 04:36:02 +03:00
|
|
|
if (lfb_vid_memory + 4 * resolution_x * resolution_y > lfb_vid_memory + 0xFF0000) {
|
2015-05-18 01:00:49 +03:00
|
|
|
for (uintptr_t i = (uintptr_t)lfb_vid_memory + 0xFF1000; i <= (uintptr_t)lfb_vid_memory + 4 * resolution_x * resolution_y; i += 0x1000) {
|
2015-05-04 04:36:02 +03:00
|
|
|
debug_print(WARNING, "Also mapping 0x%x", i);
|
|
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
|
|
|
}
|
|
|
|
}
|
2012-09-18 09:22:25 +04:00
|
|
|
finalize_graphics(resolution_x, resolution_y, PREFERRED_B);
|
|
|
|
}
|
|
|
|
|
2012-09-18 09:46:43 +04:00
|
|
|
/* }}} end bochs support */
|
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
static void graphics_install_preset(uint16_t w, uint16_t h) {
|
2012-12-08 06:33:07 +04:00
|
|
|
debug_print(NOTICE, "Graphics were pre-configured (thanks, bootloader!), locating video memory...");
|
2012-09-18 09:22:25 +04:00
|
|
|
uint16_t b = 32; /* If you are 24 bit, go away, we really do not support you. */
|
|
|
|
|
|
|
|
/* XXX: Massive hack */
|
|
|
|
uint32_t * herp = (uint32_t *)0xA0000;
|
|
|
|
herp[0] = 0xA5ADFACE;
|
2012-12-03 10:41:40 +04:00
|
|
|
herp[1] = 0xFAF42943;
|
|
|
|
|
2012-12-03 11:28:29 +04:00
|
|
|
if (lfb_vid_memory) {
|
|
|
|
for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + 0xFF0000; i += 0x1000) {
|
|
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
|
|
|
}
|
|
|
|
if (((uintptr_t *)lfb_vid_memory)[0] == 0xA5ADFACE && ((uintptr_t *)lfb_vid_memory)[1] == 0xFAF42943) {
|
|
|
|
debug_print(INFO, "Was able to locate video memory at 0x%x without dicking around.", lfb_vid_memory);
|
|
|
|
goto mem_found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-03 10:41:40 +04:00
|
|
|
for (int i = 2; i < 1000; i += 2) {
|
|
|
|
herp[i] = 0xFF00FF00;
|
|
|
|
herp[i+1] = 0x00FF00FF;
|
|
|
|
}
|
2012-09-18 09:22:25 +04:00
|
|
|
|
|
|
|
for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
|
|
|
|
/* Enable the higher memory */
|
|
|
|
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
|
|
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Go find it */
|
|
|
|
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
|
2012-12-03 10:41:40 +04:00
|
|
|
if (((uintptr_t *)x)[0] == 0xA5ADFACE && ((uintptr_t *)x)[1] == 0xFAF42943) {
|
2012-09-18 09:46:43 +04:00
|
|
|
lfb_vid_memory = (uint8_t *)x;
|
2012-12-03 11:28:29 +04:00
|
|
|
debug_print(INFO, "Had to futz around, but found video memory at 0x%x", lfb_vid_memory);
|
2012-09-18 09:22:25 +04:00
|
|
|
goto mem_found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-03 10:41:40 +04:00
|
|
|
for (int i = 2; i < 1000; i += 2) {
|
|
|
|
herp[i] = 0xFF00FF00;
|
|
|
|
herp[i+1] = 0xFF00FF00;
|
|
|
|
}
|
|
|
|
|
2012-10-17 10:31:55 +04:00
|
|
|
debug_print(WARNING, "Failed to locate video memory. This could end poorly.");
|
|
|
|
|
2012-09-18 09:22:25 +04:00
|
|
|
mem_found:
|
|
|
|
finalize_graphics(w,h,b);
|
2012-09-18 09:58:49 +04:00
|
|
|
|
|
|
|
for (uint16_t y = 0; y < h; y++) {
|
|
|
|
for (uint16_t x = 0; x < w; x++) {
|
|
|
|
uint8_t f = y % 255;
|
|
|
|
((uint32_t *)lfb_vid_memory)[x + y * w] = 0xFF000000 | (f * 0x10000) | (f * 0x100) | f;
|
|
|
|
}
|
|
|
|
}
|
2012-09-18 09:22:25 +04:00
|
|
|
}
|
|
|
|
|
2016-08-30 09:45:58 +03:00
|
|
|
#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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-30 08:49:14 +03:00
|
|
|
#define SVGA_IO_BASE (vmware_io)
|
|
|
|
#define SVGA_IO_MUL 1
|
|
|
|
#define SVGA_INDEX_PORT 0
|
|
|
|
#define SVGA_VALUE_PORT 1
|
|
|
|
|
|
|
|
#define SVGA_REG_ID 0
|
|
|
|
#define SVGA_REG_ENABLE 1
|
|
|
|
#define SVGA_REG_WIDTH 2
|
|
|
|
#define SVGA_REG_HEIGHT 3
|
|
|
|
#define SVGA_REG_BITS_PER_PIXEL 7
|
|
|
|
#define SVGA_REG_FB_START 13
|
|
|
|
|
|
|
|
static uint32_t vmware_io = 0;
|
|
|
|
|
|
|
|
static void vmware_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
|
|
|
|
if ((v == 0x15ad && d == 0x0405)) {
|
|
|
|
uintptr_t t = pci_read_field(device, PCI_BAR0, 4);
|
|
|
|
if (t > 0) {
|
|
|
|
*((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vmware_write(int reg, int value) {
|
|
|
|
outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg);
|
|
|
|
outportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t vmware_read(int reg) {
|
|
|
|
outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg);
|
|
|
|
return inportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (!vmware_io) {
|
|
|
|
debug_print(ERROR, "No vmware device found?");
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
debug_print(WARNING, "vmware io base: 0x%x", vmware_io);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
uint32_t fb_addr = vmware_read(SVGA_REG_FB_START);
|
|
|
|
debug_print(WARNING, "vmware fb address: 0x%x", fb_addr);
|
|
|
|
|
|
|
|
lfb_vid_memory = (uint8_t *)fb_addr;
|
|
|
|
|
|
|
|
uintptr_t fb_offset = (uintptr_t)lfb_vid_memory;
|
|
|
|
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
|
|
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
finalize_graphics(w,h,32);
|
|
|
|
}
|
|
|
|
|
2016-08-30 09:42:29 +03:00
|
|
|
struct disp_mode {
|
|
|
|
int16_t x;
|
|
|
|
int16_t y;
|
|
|
|
int set;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void auto_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
|
|
|
|
struct disp_mode * mode = extra;
|
|
|
|
if (mode->set) return;
|
|
|
|
if ((v == 0x1234 && d == 0x1111) ||
|
|
|
|
(v == 0x80EE && d == 0xBEEF)) {
|
|
|
|
mode->set = 1;
|
|
|
|
graphics_install_bochs(mode->x, mode->y);
|
|
|
|
} else if ((v == 0x15ad && d == 0x0405)) {
|
|
|
|
mode->set = 1;
|
|
|
|
graphics_install_vmware(mode->x, mode->y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-30 08:49:14 +03:00
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
static int init(void) {
|
|
|
|
|
|
|
|
if (mboot_ptr->vbe_mode_info) {
|
|
|
|
lfb_vid_memory = (uint8_t *)((vbe_info_t *)(mboot_ptr->vbe_mode_info))->physbase;
|
|
|
|
}
|
|
|
|
|
|
|
|
char * c;
|
|
|
|
if ((c = args_value("vid"))) {
|
|
|
|
debug_print(NOTICE, "Video mode requested: %s", c);
|
|
|
|
|
|
|
|
char * arg = strdup(c);
|
|
|
|
char * argv[10];
|
|
|
|
int argc = tokenize(arg, ",", argv);
|
|
|
|
|
|
|
|
uint16_t x, y;
|
|
|
|
if (argc < 3) {
|
|
|
|
x = 1024;
|
|
|
|
y = 768;
|
|
|
|
} else {
|
|
|
|
x = atoi(argv[1]);
|
|
|
|
y = atoi(argv[2]);
|
|
|
|
}
|
|
|
|
|
2016-08-30 09:42:29 +03:00
|
|
|
if (!strcmp(argv[0], "auto")) {
|
|
|
|
/* Attempt autodetection */
|
|
|
|
debug_print(WARNING, "Autodetect is in beta, this may not work.");
|
|
|
|
struct disp_mode mode = {x,y,0};
|
|
|
|
pci_scan(auto_scan_pci, -1, &mode);
|
|
|
|
if (!mode.set) {
|
|
|
|
graphics_install_preset(x,y);
|
|
|
|
}
|
|
|
|
} else if (!strcmp(argv[0], "qemu")) {
|
2014-03-20 05:56:07 +04:00
|
|
|
/* Bochs / Qemu Video Device */
|
|
|
|
graphics_install_bochs(x,y);
|
|
|
|
} else if (!strcmp(argv[0],"preset")) {
|
|
|
|
graphics_install_preset(x,y);
|
2016-08-30 08:49:14 +03:00
|
|
|
} else if (!strcmp(argv[0],"vmware")) {
|
|
|
|
graphics_install_vmware(x,y);
|
2014-03-20 05:56:07 +04:00
|
|
|
} else {
|
|
|
|
debug_print(WARNING, "Unrecognized video adapter: %s", argv[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fini(void) {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-18 09:22:25 +04:00
|
|
|
|
2014-03-20 05:56:07 +04:00
|
|
|
MODULE_DEF(lfbvideo, init, fini);
|