2011-03-26 06:29:54 +03:00
|
|
|
/*
|
|
|
|
* vim:tabstop=4
|
|
|
|
* vim:noexpandtab
|
|
|
|
*
|
|
|
|
* Bochs VBE / QEMU vga=std Graphics Driver
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <system.h>
|
2011-03-26 21:30:08 +03:00
|
|
|
#include <fs.h>
|
2011-03-26 06:29:54 +03:00
|
|
|
|
2011-03-27 22:41:00 +04:00
|
|
|
#define PREFERRED_X 1024
|
|
|
|
#define PREFERRED_Y 768
|
|
|
|
#define PREFERRED_B 32
|
|
|
|
|
|
|
|
uint16_t bochs_resolution_x = 0;
|
|
|
|
uint16_t bochs_resolution_y = 0;
|
|
|
|
uint16_t bochs_resolution_b = 0;
|
2011-03-26 07:24:22 +03:00
|
|
|
uint16_t bochs_current_bank = 0;
|
|
|
|
|
|
|
|
#define BOCHS_BANK_SIZE 16384
|
|
|
|
#define BOCHS_VID_MEMORY ((uint32_t *)0xA0000)
|
2011-03-27 21:43:08 +04:00
|
|
|
#define BOCHS_BANKS (bochs_resolution_x * bochs_resolution_y * bochs_resolution_b / (BOCHS_BANK_SIZE * 32))
|
2011-03-26 07:24:22 +03:00
|
|
|
|
2011-03-26 06:29:54 +03:00
|
|
|
void
|
|
|
|
graphics_install_bochs() {
|
|
|
|
outports(0x1CE, 0x00);
|
2011-03-27 21:43:08 +04:00
|
|
|
uint16_t i = inports(0x1CF);
|
|
|
|
if (i < 0xB0C0 || i > 0xB0C6) {
|
|
|
|
kprintf("[bochs] You are not a Bochs VBE pseudo-card!\n");
|
|
|
|
kprintf("[bochs] 0x%x is totally wrong!\n", (unsigned int)i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kprintf("[bochs] Successfully detected a Bochs VBE setup!\n");
|
|
|
|
kprintf("[bochs] You are using QEMU or Bochs and I love you.\n");
|
2011-03-26 06:29:54 +03:00
|
|
|
outports(0x1CF, 0xB0C4);
|
2011-03-27 21:43:08 +04:00
|
|
|
i = inports(0x1CF);
|
2011-03-26 07:24:22 +03:00
|
|
|
kprintf("[bochs] Enabling 1024x768x32 graphics mode!\n");
|
2011-03-26 06:29:54 +03:00
|
|
|
/* Disable VBE */
|
|
|
|
outports(0x1CE, 0x04);
|
|
|
|
outports(0x1CF, 0x00);
|
|
|
|
/* Set X resolution to 1024 */
|
|
|
|
outports(0x1CE, 0x01);
|
2011-03-27 22:41:00 +04:00
|
|
|
outports(0x1CF, PREFERRED_X);
|
|
|
|
bochs_resolution_x = PREFERRED_X;
|
2011-03-26 06:29:54 +03:00
|
|
|
/* Set Y resolution to 768 */
|
|
|
|
outports(0x1CE, 0x02);
|
2011-03-27 22:41:00 +04:00
|
|
|
outports(0x1CF, PREFERRED_Y);
|
|
|
|
bochs_resolution_y = PREFERRED_Y;
|
2011-03-26 21:47:58 +03:00
|
|
|
/* Set bpp to 32 */
|
2011-03-26 06:29:54 +03:00
|
|
|
outports(0x1CE, 0x03);
|
2011-03-27 22:41:00 +04:00
|
|
|
outports(0x1CF, PREFERRED_B);
|
|
|
|
bochs_resolution_b = PREFERRED_B;
|
2011-03-26 06:29:54 +03:00
|
|
|
/* Re-enable VBE */
|
|
|
|
outports(0x1CE, 0x04);
|
2011-03-26 07:24:22 +03:00
|
|
|
outports(0x1CF, 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bochs_set_bank(
|
|
|
|
uint16_t bank
|
|
|
|
) {
|
|
|
|
if (bank == bochs_current_bank) {
|
|
|
|
/* We are already in this bank, stop wasting cycles */
|
|
|
|
return;
|
2011-03-26 06:29:54 +03:00
|
|
|
}
|
2011-03-26 07:24:22 +03:00
|
|
|
outports(0x1CE, 0x05); /* Bank */
|
|
|
|
outports(0x1CF, bank);
|
|
|
|
bochs_current_bank = bank;
|
|
|
|
}
|
|
|
|
|
2011-03-29 00:18:48 +04:00
|
|
|
static void
|
|
|
|
bochs_set_point(
|
|
|
|
uint16_t x,
|
|
|
|
uint16_t y,
|
|
|
|
uint32_t color
|
|
|
|
) {
|
|
|
|
BOCHS_VID_MEMORY[(y * bochs_resolution_x + x) % BOCHS_BANK_SIZE] = color;
|
|
|
|
}
|
|
|
|
|
2011-03-26 07:24:22 +03:00
|
|
|
void
|
|
|
|
bochs_set_coord(
|
|
|
|
uint16_t x,
|
|
|
|
uint16_t y,
|
|
|
|
uint32_t color
|
|
|
|
) {
|
|
|
|
uint32_t location = y * bochs_resolution_x + x;
|
|
|
|
bochs_set_bank(location / BOCHS_BANK_SIZE);
|
|
|
|
uint32_t offset = location % BOCHS_BANK_SIZE;
|
|
|
|
BOCHS_VID_MEMORY[offset] = color;
|
2011-03-26 06:29:54 +03:00
|
|
|
}
|
2011-03-26 21:30:08 +03:00
|
|
|
|
2011-03-26 22:15:24 +03:00
|
|
|
void
|
|
|
|
bochs_scroll() {
|
|
|
|
__asm__ __volatile__ ("cli");
|
|
|
|
uint32_t * bank_store = malloc(sizeof(uint32_t) * BOCHS_BANK_SIZE);
|
2011-03-28 09:26:35 +04:00
|
|
|
for (int i = 1; i < BOCHS_BANKS; ++i) {
|
2011-03-26 22:15:24 +03:00
|
|
|
bochs_set_bank(i);
|
|
|
|
memcpy(bank_store, BOCHS_VID_MEMORY, sizeof(uint32_t) * BOCHS_BANK_SIZE);
|
|
|
|
bochs_set_bank(i - 1);
|
|
|
|
memcpy(BOCHS_VID_MEMORY, bank_store, sizeof(uint32_t) * BOCHS_BANK_SIZE);
|
|
|
|
}
|
|
|
|
free(bank_store);
|
|
|
|
__asm__ __volatile__ ("sti");
|
|
|
|
}
|
|
|
|
|
2011-03-26 21:30:08 +03:00
|
|
|
void
|
2011-03-27 22:41:00 +04:00
|
|
|
bochs_draw_logo(char * filename) {
|
2011-03-27 21:43:08 +04:00
|
|
|
/* This is slow and ineffecient, but it's also dead simple. */
|
2011-03-27 22:41:00 +04:00
|
|
|
if (!bochs_resolution_x) { return; }
|
|
|
|
fs_node_t * file = kopen(filename,0);
|
|
|
|
if (!file) { return; }
|
2011-03-26 21:30:08 +03:00
|
|
|
char *bufferb = malloc(file->length);
|
2011-03-27 21:43:08 +04:00
|
|
|
/* Read the boot logo */
|
2011-03-26 21:30:08 +03:00
|
|
|
size_t bytes_read = read_fs(file, 0, file->length, (uint8_t *)bufferb);
|
2011-03-27 21:43:08 +04:00
|
|
|
uint16_t x = 0; /* -> 212 */
|
|
|
|
uint16_t y = 0; /* -> 68 */
|
|
|
|
/* Get the width / height of the image */
|
|
|
|
signed int *bufferi = (signed int *)((uintptr_t)bufferb + 2);
|
|
|
|
uint32_t width = bufferi[4];
|
|
|
|
uint32_t height = bufferi[5];
|
2011-03-28 03:08:41 +04:00
|
|
|
uint32_t row_width = (24 * width + 31) / 32 * 4;
|
2011-03-27 21:43:08 +04:00
|
|
|
/* Skip right to the important part */
|
2011-03-28 03:08:41 +04:00
|
|
|
size_t i = bufferi[2];
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
|
|
for (x = 0; x < width; ++x) {
|
2011-03-28 04:41:31 +04:00
|
|
|
if (i > bytes_read) return;
|
2011-03-28 03:08:41 +04:00
|
|
|
/* Extract the color */
|
|
|
|
uint32_t color = bufferb[i + 3 * x] +
|
|
|
|
bufferb[i+1 + 3 * x] * 0x100 +
|
|
|
|
bufferb[i+2 + 3 * x] * 0x10000;
|
|
|
|
/* Set our point */
|
|
|
|
bochs_set_coord((bochs_resolution_x - width) / 2 + x, (bochs_resolution_y - height) / 2 + (height - y), color);
|
2011-03-26 21:30:08 +03:00
|
|
|
}
|
2011-03-28 03:08:41 +04:00
|
|
|
i += row_width;
|
2011-03-26 21:30:08 +03:00
|
|
|
}
|
|
|
|
}
|
2011-03-29 00:18:48 +04:00
|
|
|
|
|
|
|
void
|
|
|
|
bochs_fill_rect(
|
|
|
|
uint16_t x,
|
|
|
|
uint16_t y,
|
|
|
|
uint16_t w,
|
|
|
|
uint16_t h,
|
|
|
|
uint32_t color
|
|
|
|
) {
|
|
|
|
for (uint16_t i = y; i < h + y; ++i) {
|
|
|
|
bochs_set_bank(y * bochs_resolution_x / BOCHS_BANK_SIZE);
|
|
|
|
for (uint16_t j = x; j < w + x; ++j) {
|
|
|
|
bochs_set_point(j,i,color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-03-29 01:29:59 +04:00
|
|
|
bochs_write_char(
|
2011-03-29 00:18:48 +04:00
|
|
|
uint8_t val,
|
|
|
|
uint16_t x,
|
|
|
|
uint16_t y,
|
|
|
|
uint32_t fg,
|
|
|
|
uint32_t bg
|
|
|
|
) {
|
2011-03-29 01:33:07 +04:00
|
|
|
uint8_t * c = number_font[val - 0x20];
|
2011-03-29 00:18:48 +04:00
|
|
|
for (uint8_t i = 0; i < 12; ++i) {
|
|
|
|
bochs_set_bank((y+i) * bochs_resolution_x / BOCHS_BANK_SIZE);
|
|
|
|
if (c[i] & 0x80) { bochs_set_point(x,y+i,fg); } else { bochs_set_point(x,y+i,bg); }
|
|
|
|
if (c[i] & 0x40) { bochs_set_point(x+1,y+i,fg); } else { bochs_set_point(x+1,y+i,bg); }
|
|
|
|
if (c[i] & 0x20) { bochs_set_point(x+2,y+i,fg); } else { bochs_set_point(x+2,y+i,bg); }
|
|
|
|
if (c[i] & 0x10) { bochs_set_point(x+3,y+i,fg); } else { bochs_set_point(x+3,y+i,bg); }
|
|
|
|
if (c[i] & 0x08) { bochs_set_point(x+4,y+i,fg); } else { bochs_set_point(x+4,y+i,bg); }
|
|
|
|
if (c[i] & 0x04) { bochs_set_point(x+5,y+i,fg); } else { bochs_set_point(x+5,y+i,bg); }
|
|
|
|
if (c[i] & 0x02) { bochs_set_point(x+6,y+i,fg); } else { bochs_set_point(x+6,y+i,bg); }
|
|
|
|
if (c[i] & 0x01) { bochs_set_point(x+7,y+i,fg); } else { bochs_set_point(x+7,y+i,bg); }
|
|
|
|
}
|
|
|
|
}
|