942 lines
21 KiB
C
942 lines
21 KiB
C
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
|
*
|
|
* Bochs VBE / QEMU vga=std Graphics Driver
|
|
*/
|
|
|
|
#include <system.h>
|
|
#include <fs.h>
|
|
#include <types.h>
|
|
#include <vesa.h>
|
|
#include <logging.h>
|
|
|
|
#define PROMPT_FOR_MODE 0
|
|
|
|
/* Friggin' frick, this should be a config option
|
|
* because it's 4096 on some instances of Qemu,
|
|
* ie the one on my laptop, but it's 2048 on
|
|
* the EWS machines. */
|
|
#define BOCHS_BUFFER_SIZE 2048
|
|
#define PREFERRED_VY 4096
|
|
#define PREFERRED_B 32
|
|
|
|
uint16_t bochs_resolution_x = 0;
|
|
uint16_t bochs_resolution_y = 0;
|
|
uint16_t bochs_resolution_b = 0;
|
|
|
|
/*
|
|
* Address of the linear frame buffer.
|
|
* This can move, so it's a pointer instead of
|
|
* #define.
|
|
*/
|
|
uint8_t * bochs_vid_memory = (uint8_t *)0xE0000000;
|
|
|
|
static short term_width = 128;
|
|
static short term_height = 64;
|
|
|
|
static short csr_x = 0;
|
|
static short csr_y = 0;
|
|
static uint8_t * term_buffer = NULL;
|
|
static uint8_t current_fg = 7;
|
|
static uint8_t current_bg = 0;
|
|
static uint16_t current_scroll = 0;
|
|
static uint8_t cursor_on = 1;
|
|
|
|
void
|
|
bochs_set_y_offset(uint16_t y) {
|
|
outports(0x1CE, 0x9);
|
|
outports(0x1CF, y);
|
|
current_scroll = y;
|
|
}
|
|
|
|
uint16_t
|
|
bochs_current_scroll() {
|
|
return current_scroll;
|
|
}
|
|
|
|
uintptr_t
|
|
bochs_get_address() {
|
|
return (uintptr_t)bochs_vid_memory;
|
|
}
|
|
|
|
typedef struct sprite {
|
|
uint16_t width;
|
|
uint16_t height;
|
|
uint32_t * bitmap;
|
|
uint32_t * masks;
|
|
uint32_t blank;
|
|
uint8_t alpha;
|
|
} sprite_t;
|
|
|
|
sprite_t * wallpaper = NULL;
|
|
|
|
#define _RED(color) ((color & 0x00FF0000) / 0x10000)
|
|
#define _GRE(color) ((color & 0x0000FF00) / 0x100)
|
|
#define _BLU(color) ((color & 0x000000FF) / 0x1)
|
|
|
|
void
|
|
bochs_screenshot(char * filename) {
|
|
if (filename) {
|
|
kprintf("Error: Writing screenshots to a file is not currently supported.\n");
|
|
return;
|
|
}
|
|
uint8_t * buf = malloc(1024 * 768 * 4);
|
|
uint32_t * bufi = (uint32_t *)buf;
|
|
uint32_t x, y, i;
|
|
for (x = 0; x < 1024; ++x) {
|
|
for (y = 0; y < 768; ++y) {
|
|
uint32_t color = bochs_vid_memory[((y + current_scroll) * bochs_resolution_x + x)];
|
|
bufi[y * 1024 + x] = _BLU(color) * 0x10000 +
|
|
_GRE(color) * 0x100 +
|
|
_RED(color) * 0x1 +
|
|
0xFF000000;
|
|
}
|
|
}
|
|
i = 0;
|
|
while (i < 6144) {
|
|
ide_write_sector(0x170, 0, i, (uint8_t *)((uint32_t)buf + i * 512));
|
|
++i;
|
|
PAUSE;
|
|
}
|
|
free(buf);
|
|
}
|
|
|
|
void
|
|
bochs_install_wallpaper(char * filename) {
|
|
blog("Loading wallpaper...");
|
|
fs_node_t * image = kopen(filename, 0);
|
|
if (!image) {
|
|
bfinish(2);
|
|
kprintf("[NOTICE] Failed to load wallpaper `%s`.\n", filename);
|
|
return;
|
|
}
|
|
size_t image_size= 0;
|
|
|
|
image_size = image->length;
|
|
|
|
/* Alright, we have the length */
|
|
char * bufferb = malloc(image_size);
|
|
read_fs(image, 0, image_size, (uint8_t *)bufferb);
|
|
close_fs(image);
|
|
|
|
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];
|
|
uint16_t bpp = bufferi[6] / 0x10000;
|
|
uint32_t row_width = (bpp * width + 31) / 32 * 4;
|
|
/* Skip right to the important part */
|
|
size_t i = bufferi[2];
|
|
|
|
wallpaper = malloc(sizeof(sprite_t));
|
|
wallpaper->width = width;
|
|
wallpaper->height = height;
|
|
wallpaper->bitmap = malloc(sizeof(uint32_t) * width * height);
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
for (x = 0; x < width; ++x) {
|
|
/* Extract the color */
|
|
uint32_t color;
|
|
if (bpp == 24) {
|
|
color = bufferb[i + 3 * x] +
|
|
bufferb[i+1 + 3 * x] * 0x100 +
|
|
bufferb[i+2 + 3 * x] * 0x10000;
|
|
} else if (bpp == 32) {
|
|
color = bufferb[i + 4 * x] * 0x1000000 +
|
|
bufferb[i+1 + 4 * x] * 0x100 +
|
|
bufferb[i+2 + 4 * x] * 0x10000 +
|
|
bufferb[i+3 + 4 * x] * 0x1;
|
|
}
|
|
/* Set our point */
|
|
wallpaper->bitmap[(height - y - 1) * width + x] = color;
|
|
}
|
|
i += row_width;
|
|
}
|
|
|
|
free(bufferb);
|
|
bfinish(0);
|
|
}
|
|
|
|
static void finalize_graphics(uint16_t x, uint16_t y, uint16_t b) {
|
|
bochs_resolution_x = x;
|
|
bochs_resolution_y = y;
|
|
bochs_resolution_b = b;
|
|
|
|
term_width = bochs_resolution_x / 8;
|
|
term_height = bochs_resolution_y / 12;
|
|
|
|
/* Buffer contains characters, fg (of 256), bg (same), flags (one byte) */
|
|
term_buffer = (uint8_t *)malloc(sizeof(uint8_t) * 4 * term_width * term_height);
|
|
ansi_init(&bochs_write, 128, 64, &bochs_set_colors, &bochs_set_csr, &bochs_get_csr_x, &bochs_get_csr_y, &bochs_set_cell, &bochs_term_clear, &bochs_redraw_cursor);
|
|
}
|
|
|
|
void
|
|
graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
|
|
blog("Setting up BOCHS/QEMU graphics controller...");
|
|
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);
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* Go find it */
|
|
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
|
|
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
|
|
bochs_vid_memory = (uint8_t *)x;
|
|
goto mem_found;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
mem_found:
|
|
finalize_graphics(resolution_x, resolution_y, PREFERRED_B);
|
|
bfinish(0);
|
|
}
|
|
|
|
#include "../v8086/rme.h"
|
|
|
|
void
|
|
graphics_install_vesa(uint16_t x, uint16_t y) {
|
|
blog("Setting up VESA video controller...");
|
|
|
|
/* VESA Structs */
|
|
struct VesaControllerInfo *info = (void*)0x10000;
|
|
struct VesaModeInfo *modeinfo = (void*)0x9000;
|
|
|
|
/* 8086 Emulator Status */
|
|
tRME_State *emu;
|
|
void * lowCache;
|
|
lowCache = malloc(RME_BLOCK_SIZE);
|
|
memcpy(lowCache, NULL, RME_BLOCK_SIZE);
|
|
emu = RME_CreateState();
|
|
emu->Memory[0] = lowCache;
|
|
for (int i = RME_BLOCK_SIZE; i < 0x100000; i += RME_BLOCK_SIZE) {
|
|
emu->Memory[i/RME_BLOCK_SIZE] = (void*)i;
|
|
}
|
|
int ret, mode;
|
|
|
|
/* Find modes */
|
|
uint16_t * modes;
|
|
memcpy(info->Signature, "VBE2", 4);
|
|
emu->AX.W = 0x4F00;
|
|
emu->ES = 0x1000;
|
|
emu->DI.W = 0;
|
|
ret = RME_CallInt(emu, 0x10);
|
|
if (info->Version < 0x200 || info->Version > 0x300) {
|
|
bfinish(2);
|
|
kprintf("\033[JYou have attempted to use the VESA/VBE2 driver\nwith a card that does not support VBE2.\n");
|
|
kprintf("\nSystem responded to VBE request with version: 0x%x\n", info->Version);
|
|
|
|
STOP;
|
|
}
|
|
modes = (void*)FP_TO_LINEAR(info->Videomodes.Segment,info->Videomodes.Offset);
|
|
|
|
uint16_t best_x = 0;
|
|
uint16_t best_y = 0;
|
|
uint16_t best_b = 0;
|
|
uint16_t best_mode = 0;
|
|
|
|
for (int i = 1; modes[i] != 0xFFFF; ++i) {
|
|
emu->AX.W = 0x4F01;
|
|
emu->CX.W = modes[i];
|
|
emu->ES = 0x0900;
|
|
emu->DI.W = 0x0000;
|
|
RME_CallInt(emu, 0x10);
|
|
#if PROMPT_FOR_MODE
|
|
kprintf("%d = %dx%d:%d\n", i, modeinfo->Xres, modeinfo->Yres, modeinfo->bpp);
|
|
}
|
|
|
|
kprintf("Please select a mode: ");
|
|
char buf[10];
|
|
kgets(buf, 10);
|
|
mode = atoi(buf);
|
|
#else
|
|
if ((abs(modeinfo->Xres - x) < abs(best_x - x)) && (abs(modeinfo->Yres - y) < abs(best_y - y))) {
|
|
best_mode = i;
|
|
best_x = modeinfo->Xres;
|
|
best_y = modeinfo->Yres;
|
|
best_b = modeinfo->bpp;
|
|
}
|
|
}
|
|
for (int i = 1; modes[i] != 0xFFFF; ++i) {
|
|
emu->AX.W = 0x4F01;
|
|
emu->CX.W = modes[i];
|
|
emu->ES = 0x0900;
|
|
emu->DI.W = 0x0000;
|
|
RME_CallInt(emu, 0x10);
|
|
if (modeinfo->Xres == best_x && modeinfo->Yres == best_y) {
|
|
if (modeinfo->bpp > best_b) {
|
|
best_mode = i;
|
|
best_b = modeinfo->bpp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (best_b < 24) {
|
|
kprintf("!!! Rendering at this bit depth (%d) is not currently supported.\n", best_b);
|
|
STOP;
|
|
}
|
|
|
|
|
|
mode = best_mode;
|
|
|
|
#endif
|
|
|
|
emu->AX.W = 0x4F01;
|
|
if (mode < 100) {
|
|
emu->CX.W = modes[mode];
|
|
} else {
|
|
emu->CX.W = mode;
|
|
}
|
|
emu->ES = 0x0900;
|
|
emu->DI.W = 0x0000;
|
|
RME_CallInt(emu, 0x10);
|
|
|
|
emu->AX.W = 0x4F02;
|
|
emu->BX.W = modes[mode];
|
|
RME_CallInt(emu, 0x10);
|
|
|
|
uint16_t actual_x = modeinfo->Xres;
|
|
uint16_t actual_y = modeinfo->Yres;
|
|
uint16_t actual_b = modeinfo->bpp;
|
|
|
|
bochs_vid_memory = (uint8_t *)modeinfo->physbase;
|
|
|
|
if (!bochs_vid_memory) {
|
|
uint32_t * herp = (uint32_t *)0xA0000;
|
|
herp[0] = 0xA5ADFACE;
|
|
|
|
/* Enable the higher memory */
|
|
for (uintptr_t i = 0xE0000000; i <= 0xE0FF0000; i += 0x1000) {
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
|
}
|
|
for (uintptr_t i = 0xF0000000; i <= 0xF0FF0000; i += 0x1000) {
|
|
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
|
}
|
|
|
|
|
|
/* Go find it */
|
|
for (uintptr_t x = 0xE0000000; x < 0xE0FF0000; x += 0x1000) {
|
|
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
|
|
bochs_vid_memory = (uint8_t *)x;
|
|
goto mem_found;
|
|
}
|
|
}
|
|
for (uintptr_t x = 0xF0000000; x < 0xF0FF0000; x += 0x1000) {
|
|
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
|
|
bochs_vid_memory = (uint8_t *)x;
|
|
goto mem_found;
|
|
}
|
|
}
|
|
}
|
|
mem_found:
|
|
|
|
/*
|
|
* Finalize the graphics setup with the actual selected resolution.
|
|
*/
|
|
finalize_graphics(actual_x, actual_y, actual_b);
|
|
bfinish(0);
|
|
}
|
|
|
|
static inline void
|
|
bochs_set_point(
|
|
uint16_t x,
|
|
uint16_t y,
|
|
uint32_t color
|
|
) {
|
|
if (bochs_resolution_b == 32) {
|
|
*((uint32_t *)&bochs_vid_memory[((y + current_scroll) * bochs_resolution_x + x) * 4]) = color;
|
|
} else if (bochs_resolution_b == 24) {
|
|
bochs_vid_memory[((y + current_scroll) * bochs_resolution_x + x) * 3 + 2] = _RED(color);
|
|
bochs_vid_memory[((y + current_scroll) * bochs_resolution_x + x) * 3 + 1] = _GRE(color);
|
|
bochs_vid_memory[((y + current_scroll) * bochs_resolution_x + x) * 3 + 0] = _BLU(color);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
bochs_set_point_bg(
|
|
uint16_t x,
|
|
uint16_t y,
|
|
uint32_t color
|
|
) {
|
|
if (!color && wallpaper && y < wallpaper->height && x < wallpaper->width) {
|
|
bochs_set_point(x,y,wallpaper->bitmap[wallpaper->width * y + x]);
|
|
} else {
|
|
bochs_set_point(x,y,color);
|
|
}
|
|
}
|
|
|
|
void
|
|
bochs_scroll() {
|
|
uint32_t size = bochs_resolution_b * bochs_resolution_x * (bochs_resolution_y - 12);
|
|
memmove((void *)bochs_vid_memory, (void *)((uintptr_t)bochs_vid_memory + bochs_resolution_x * 12 * bochs_resolution_b), size);
|
|
}
|
|
|
|
void
|
|
bochs_draw_logo(char * filename) {
|
|
/* This is slow and ineffecient, but it's also dead simple. */
|
|
if (!bochs_resolution_x) { return; }
|
|
fs_node_t * file = kopen(filename,0);
|
|
if (!file) { return; }
|
|
char *bufferb = malloc(file->length);
|
|
/* Read the boot logo */
|
|
size_t bytes_read = read_fs(file, 0, file->length, (uint8_t *)bufferb);
|
|
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];
|
|
uint32_t row_width = (24 * width + 31) / 32 * 4;
|
|
/* Skip right to the important part */
|
|
size_t i = bufferi[2];
|
|
for (y = 0; y < height; ++y) {
|
|
for (x = 0; x < width; ++x) {
|
|
if (i > bytes_read) return;
|
|
/* 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_point((bochs_resolution_x - width) / 2 + x, (bochs_resolution_y - height) / 2 + (height - y), color);
|
|
}
|
|
i += row_width;
|
|
}
|
|
free(bufferb);
|
|
}
|
|
|
|
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) {
|
|
for (uint16_t j = x; j < w + x; ++j) {
|
|
bochs_set_point(j,i,color);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
bochs_write_char(
|
|
uint8_t val,
|
|
uint16_t x,
|
|
uint16_t y,
|
|
uint32_t fg,
|
|
uint32_t bg
|
|
) {
|
|
if (val > 131) {
|
|
val = ' ';
|
|
}
|
|
uint8_t * c = number_font[val];
|
|
for (uint8_t i = 0; i < 12; ++i) {
|
|
if (c[i] & 0x80) { bochs_set_point(x,y+i,fg); } else { bochs_set_point_bg(x,y+i,bg); }
|
|
if (c[i] & 0x40) { bochs_set_point(x+1,y+i,fg); } else { bochs_set_point_bg(x+1,y+i,bg); }
|
|
if (c[i] & 0x20) { bochs_set_point(x+2,y+i,fg); } else { bochs_set_point_bg(x+2,y+i,bg); }
|
|
if (c[i] & 0x10) { bochs_set_point(x+3,y+i,fg); } else { bochs_set_point_bg(x+3,y+i,bg); }
|
|
if (c[i] & 0x08) { bochs_set_point(x+4,y+i,fg); } else { bochs_set_point_bg(x+4,y+i,bg); }
|
|
if (c[i] & 0x04) { bochs_set_point(x+5,y+i,fg); } else { bochs_set_point_bg(x+5,y+i,bg); }
|
|
if (c[i] & 0x02) { bochs_set_point(x+6,y+i,fg); } else { bochs_set_point_bg(x+6,y+i,bg); }
|
|
if (c[i] & 0x01) { bochs_set_point(x+7,y+i,fg); } else { bochs_set_point_bg(x+7,y+i,bg); }
|
|
}
|
|
}
|
|
|
|
/* This is mapped to ANSI */
|
|
uint32_t bochs_colors[256] = {
|
|
/* black */ 0x000000,
|
|
/* red */ 0xcc0000,
|
|
/* green */ 0x3e9a06,
|
|
/* brown */ 0xc4a000,
|
|
/* navy */ 0x3465a4,
|
|
/* purple */ 0x75507b,
|
|
/* d cyan */ 0x06989a,
|
|
/* gray */ 0xeeeeec,
|
|
/* d gray */ 0x555753,
|
|
/* red */ 0xef2929,
|
|
/* green */ 0x8ae234,
|
|
/* yellow */ 0xfce94f,
|
|
/* blue */ 0x729fcf,
|
|
/* magenta*/ 0xad7fa8,
|
|
/* cyan */ 0x34e2e2,
|
|
/* white */ 0xFFFFFF,
|
|
0x000000,
|
|
0x00005f,
|
|
0x000087,
|
|
0x0000af,
|
|
0x0000d7,
|
|
0x0000ff,
|
|
0x005f00,
|
|
0x005f5f,
|
|
0x005f87,
|
|
0x005faf,
|
|
0x005fd7,
|
|
0x005fff,
|
|
0x008700,
|
|
0x00875f,
|
|
0x008787,
|
|
0x0087af,
|
|
0x0087d7,
|
|
0x0087ff,
|
|
0x00af00,
|
|
0x00af5f,
|
|
0x00af87,
|
|
0x00afaf,
|
|
0x00afd7,
|
|
0x00afff,
|
|
0x00d700,
|
|
0x00d75f,
|
|
0x00d787,
|
|
0x00d7af,
|
|
0x00d7d7,
|
|
0x00d7ff,
|
|
0x00ff00,
|
|
0x00ff5f,
|
|
0x00ff87,
|
|
0x00ffaf,
|
|
0x00ffd7,
|
|
0x00ffff,
|
|
0x5f0000,
|
|
0x5f005f,
|
|
0x5f0087,
|
|
0x5f00af,
|
|
0x5f00d7,
|
|
0x5f00ff,
|
|
0x5f5f00,
|
|
0x5f5f5f,
|
|
0x5f5f87,
|
|
0x5f5faf,
|
|
0x5f5fd7,
|
|
0x5f5fff,
|
|
0x5f8700,
|
|
0x5f875f,
|
|
0x5f8787,
|
|
0x5f87af,
|
|
0x5f87d7,
|
|
0x5f87ff,
|
|
0x5faf00,
|
|
0x5faf5f,
|
|
0x5faf87,
|
|
0x5fafaf,
|
|
0x5fafd7,
|
|
0x5fafff,
|
|
0x5fd700,
|
|
0x5fd75f,
|
|
0x5fd787,
|
|
0x5fd7af,
|
|
0x5fd7d7,
|
|
0x5fd7ff,
|
|
0x5fff00,
|
|
0x5fff5f,
|
|
0x5fff87,
|
|
0x5fffaf,
|
|
0x5fffd7,
|
|
0x5fffff,
|
|
0x870000,
|
|
0x87005f,
|
|
0x870087,
|
|
0x8700af,
|
|
0x8700d7,
|
|
0x8700ff,
|
|
0x875f00,
|
|
0x875f5f,
|
|
0x875f87,
|
|
0x875faf,
|
|
0x875fd7,
|
|
0x875fff,
|
|
0x878700,
|
|
0x87875f,
|
|
0x878787,
|
|
0x8787af,
|
|
0x8787d7,
|
|
0x8787ff,
|
|
0x87af00,
|
|
0x87af5f,
|
|
0x87af87,
|
|
0x87afaf,
|
|
0x87afd7,
|
|
0x87afff,
|
|
0x87d700,
|
|
0x87d75f,
|
|
0x87d787,
|
|
0x87d7af,
|
|
0x87d7d7,
|
|
0x87d7ff,
|
|
0x87ff00,
|
|
0x87ff5f,
|
|
0x87ff87,
|
|
0x87ffaf,
|
|
0x87ffd7,
|
|
0x87ffff,
|
|
0xaf0000,
|
|
0xaf005f,
|
|
0xaf0087,
|
|
0xaf00af,
|
|
0xaf00d7,
|
|
0xaf00ff,
|
|
0xaf5f00,
|
|
0xaf5f5f,
|
|
0xaf5f87,
|
|
0xaf5faf,
|
|
0xaf5fd7,
|
|
0xaf5fff,
|
|
0xaf8700,
|
|
0xaf875f,
|
|
0xaf8787,
|
|
0xaf87af,
|
|
0xaf87d7,
|
|
0xaf87ff,
|
|
0xafaf00,
|
|
0xafaf5f,
|
|
0xafaf87,
|
|
0xafafaf,
|
|
0xafafd7,
|
|
0xafafff,
|
|
0xafd700,
|
|
0xafd75f,
|
|
0xafd787,
|
|
0xafd7af,
|
|
0xafd7d7,
|
|
0xafd7ff,
|
|
0xafff00,
|
|
0xafff5f,
|
|
0xafff87,
|
|
0xafffaf,
|
|
0xafffd7,
|
|
0xafffff,
|
|
0xd70000,
|
|
0xd7005f,
|
|
0xd70087,
|
|
0xd700af,
|
|
0xd700d7,
|
|
0xd700ff,
|
|
0xd75f00,
|
|
0xd75f5f,
|
|
0xd75f87,
|
|
0xd75faf,
|
|
0xd75fd7,
|
|
0xd75fff,
|
|
0xd78700,
|
|
0xd7875f,
|
|
0xd78787,
|
|
0xd787af,
|
|
0xd787d7,
|
|
0xd787ff,
|
|
0xd7af00,
|
|
0xd7af5f,
|
|
0xd7af87,
|
|
0xd7afaf,
|
|
0xd7afd7,
|
|
0xd7afff,
|
|
0xd7d700,
|
|
0xd7d75f,
|
|
0xd7d787,
|
|
0xd7d7af,
|
|
0xd7d7d7,
|
|
0xd7d7ff,
|
|
0xd7ff00,
|
|
0xd7ff5f,
|
|
0xd7ff87,
|
|
0xd7ffaf,
|
|
0xd7ffd7,
|
|
0xd7ffff,
|
|
0xff0000,
|
|
0xff005f,
|
|
0xff0087,
|
|
0xff00af,
|
|
0xff00d7,
|
|
0xff00ff,
|
|
0xff5f00,
|
|
0xff5f5f,
|
|
0xff5f87,
|
|
0xff5faf,
|
|
0xff5fd7,
|
|
0xff5fff,
|
|
0xff8700,
|
|
0xff875f,
|
|
0xff8787,
|
|
0xff87af,
|
|
0xff87d7,
|
|
0xff87ff,
|
|
0xffaf00,
|
|
0xffaf5f,
|
|
0xffaf87,
|
|
0xffafaf,
|
|
0xffafd7,
|
|
0xffafff,
|
|
0xffd700,
|
|
0xffd75f,
|
|
0xffd787,
|
|
0xffd7af,
|
|
0xffd7d7,
|
|
0xffd7ff,
|
|
0xffff00,
|
|
0xffff5f,
|
|
0xffff87,
|
|
0xffffaf,
|
|
0xffffd7,
|
|
0xffffff,
|
|
0x080808,
|
|
0x121212,
|
|
0x1c1c1c,
|
|
0x262626,
|
|
0x303030,
|
|
0x3a3a3a,
|
|
0x444444,
|
|
0x4e4e4e,
|
|
0x585858,
|
|
0x626262,
|
|
0x6c6c6c,
|
|
0x767676,
|
|
0x808080,
|
|
0x8a8a8a,
|
|
0x949494,
|
|
0x9e9e9e,
|
|
0xa8a8a8,
|
|
0xb2b2b2,
|
|
0xbcbcbc,
|
|
0xc6c6c6,
|
|
0xd0d0d0,
|
|
0xdadada,
|
|
0xe4e4e4,
|
|
0xeeeeee,
|
|
};
|
|
|
|
static void cell_set(uint16_t x, uint16_t y, uint8_t c, uint8_t fg, uint8_t bg, uint8_t flags) {
|
|
uint8_t * cell = (uint8_t *)((uintptr_t)term_buffer + (y * term_width + x) * 4);
|
|
cell[0] = c;
|
|
cell[1] = fg;
|
|
cell[2] = bg;
|
|
cell[3] = flags;
|
|
}
|
|
|
|
static uint16_t cell_ch(uint16_t x, uint16_t y) {
|
|
uint8_t * cell = (uint8_t *)((uintptr_t)term_buffer + (y * term_width + x) * 4);
|
|
return cell[0];
|
|
}
|
|
|
|
static uint16_t cell_fg(uint16_t x, uint16_t y) {
|
|
uint8_t * cell = (uint8_t *)((uintptr_t)term_buffer + (y * term_width + x) * 4);
|
|
return cell[1];
|
|
}
|
|
|
|
static uint16_t cell_bg(uint16_t x, uint16_t y) {
|
|
uint8_t * cell = (uint8_t *)((uintptr_t)term_buffer + (y * term_width + x) * 4);
|
|
return cell[2];
|
|
}
|
|
|
|
static void cell_redraw(uint16_t x, uint16_t y) {
|
|
uint8_t * cell = (uint8_t *)((uintptr_t)term_buffer + (y * term_width + x) * 4);
|
|
bochs_write_char(cell[0], x * 8, y * 12, bochs_colors[cell[1]], bochs_colors[cell[2]]);
|
|
}
|
|
|
|
void bochs_redraw() {
|
|
for (uint16_t y = 0; y < term_height; ++y) {
|
|
for (uint16_t x = 0; x < term_width; ++x) {
|
|
cell_redraw(x,y);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void bochs_redraw_all() {
|
|
for (uint16_t y = 0; y < term_height; ++y) {
|
|
for (uint16_t x = 0; x < term_width; ++x) {
|
|
cell_redraw(x,y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void bochs_term_scroll() {
|
|
/* Oh dear */
|
|
/* I'd really prefer the much-bigger 4096 - 768 */
|
|
#if 0
|
|
if (current_scroll + 12 >= BOCHS_BUFFER_SIZE - 768) {
|
|
/* And here's where it gets hacky */
|
|
uint32_t size = sizeof(uint32_t) * bochs_resolution_x * (bochs_resolution_y - 12);
|
|
memcpy((void *)bochs_vid_memory, (void *)((uintptr_t)bochs_vid_memory + bochs_resolution_x * (current_scroll + 12) * sizeof(uint32_t)), size);
|
|
bochs_set_y_offset(0);
|
|
} else {
|
|
bochs_set_y_offset(current_scroll + 12);
|
|
}
|
|
#else
|
|
for (uint16_t y = 0; y < term_height - 1; ++y) {
|
|
for (uint16_t x = 0; x < term_width; ++x) {
|
|
cell_set(x,y,cell_ch(x,y+1),cell_fg(x,y+1),cell_bg(x,y+1), 0);
|
|
}
|
|
}
|
|
for (uint16_t x = 0; x < term_width; ++x) {
|
|
cell_set(x, term_height-1,' ',current_fg, current_bg,0);
|
|
//cell_redraw(x, term_height-1);
|
|
}
|
|
bochs_redraw_all();
|
|
#endif
|
|
}
|
|
|
|
void bochs_term_clear() {
|
|
/* Oh dear */
|
|
csr_x = 0;
|
|
csr_y = 0;
|
|
memset((void *)term_buffer, 0x00,term_width * term_height * sizeof(uint8_t) * 4);
|
|
memset((void *)bochs_vid_memory, 0x00, sizeof(uint32_t) * bochs_resolution_x * bochs_resolution_y);
|
|
bochs_set_y_offset(0);
|
|
bochs_redraw_all();
|
|
}
|
|
|
|
void bochs_set_colors(uint8_t fg, uint8_t bg) {
|
|
current_fg = fg;
|
|
current_bg = bg;
|
|
}
|
|
|
|
void bochs_reset_colors() {
|
|
current_fg = 7;
|
|
current_bg = 0;
|
|
}
|
|
|
|
void draw_cursor() {
|
|
if (!cursor_on) return;
|
|
for (uint32_t x = 0; x < 8; ++x) {
|
|
bochs_set_point(csr_x * 8 + x, csr_y * 12 + 11, bochs_colors[current_fg]);
|
|
}
|
|
}
|
|
|
|
void bochs_redraw_cursor() {
|
|
if (term_buffer) {
|
|
draw_cursor();
|
|
}
|
|
}
|
|
|
|
void bochs_write(char c) {
|
|
cell_redraw(csr_x, csr_y);
|
|
if (c == '\n') {
|
|
for (uint16_t i = csr_x; i < term_width; ++i) {
|
|
/* I like this behaviour */
|
|
cell_set(i, csr_y, ' ',current_fg, current_bg, 0);
|
|
cell_redraw(i, csr_y);
|
|
}
|
|
csr_x = 0;
|
|
++csr_y;
|
|
} else if (c == '\r') {
|
|
cell_redraw(csr_x,csr_y);
|
|
csr_x = 0;
|
|
} else if (c == '\b') {
|
|
--csr_x;
|
|
cell_set(csr_x, csr_y, ' ',current_fg, current_bg, 0);
|
|
cell_redraw(csr_x, csr_y);
|
|
} else if (c == '\t') {
|
|
csr_x = (csr_x + 8) & ~(8 - 1);
|
|
} else {
|
|
cell_set(csr_x,csr_y, c, current_fg, current_bg, 0);
|
|
cell_redraw(csr_x,csr_y);
|
|
csr_x++;
|
|
}
|
|
if (csr_x == term_width) {
|
|
csr_x = 0;
|
|
++csr_y;
|
|
}
|
|
if (csr_y == term_height) {
|
|
bochs_term_scroll();
|
|
csr_y = term_height - 1;
|
|
}
|
|
draw_cursor();
|
|
}
|
|
|
|
|
|
void bochs_draw_line(uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1, uint32_t color) {
|
|
int deltax = abs(x1 - x0);
|
|
int deltay = abs(y1 - y0);
|
|
int sx = (x0 < x1) ? 1 : -1;
|
|
int sy = (y0 < y1) ? 1 : -1;
|
|
int error = deltax - deltay;
|
|
while (1) {
|
|
bochs_set_point(x0, y0, color);
|
|
if (x0 == x1 && y0 == y1) break;
|
|
int e2 = 2 * error;
|
|
if (e2 > -deltay) {
|
|
error -= deltay;
|
|
x0 += sx;
|
|
}
|
|
if (e2 < deltax) {
|
|
error += deltax;
|
|
y0 += sy;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
bochs_set_csr(int x, int y) {
|
|
cell_redraw(csr_x,csr_y);
|
|
csr_x = x;
|
|
csr_y = y;
|
|
}
|
|
|
|
int
|
|
bochs_get_csr_x() {
|
|
return csr_x;
|
|
}
|
|
|
|
int
|
|
bochs_get_csr_y() {
|
|
return csr_y;
|
|
}
|
|
|
|
void
|
|
bochs_set_csr_show(uint8_t on) {
|
|
cursor_on = on;
|
|
}
|
|
|
|
int
|
|
bochs_get_width() {
|
|
return bochs_resolution_x / 8;
|
|
}
|
|
|
|
int
|
|
bochs_get_height() {
|
|
return bochs_resolution_y / 12;
|
|
}
|
|
|
|
void
|
|
bochs_set_cell(int x, int y, char c) {
|
|
cell_set(x, y, c, current_fg, current_bg, 0);
|
|
cell_redraw(x, y);
|
|
}
|
|
|
|
void bochs_redraw_cell(int x, int y) {
|
|
if (x < 0 || y < 0 || x >= term_width || y >= term_height) return;
|
|
cell_redraw(x,y);
|
|
}
|