Implement logic for graphical terminal
diff --git a/limine.bin b/limine.bin
index 7b95fbce..e6bb1327 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/src/drivers/vbe.c b/src/drivers/vbe.c
index deb7ff47..5fac9b83 100644
--- a/src/drivers/vbe.c
+++ b/src/drivers/vbe.c
@@ -1,10 +1,170 @@
#include <stddef.h>
#include <stdint.h>
+#include <stdbool.h>
#include <drivers/vbe.h>
+#include <lib/memmap.h>
+#include <lib/libc.h>
#include <lib/blib.h>
#include <lib/real.h>
#include <lib/print.h>
+#define VGA_FONT_WIDTH 8
+#define VGA_FONT_HEIGHT 16
+#define VGA_FONT_GLYPHS 256
+#define VGA_FONT_MAX (VGA_FONT_HEIGHT * VGA_FONT_GLYPHS)
+
+static uint8_t *vga_font;
+
+static void vga_font_retrieve(void) {
+ struct rm_regs r = {0};
+
+ r.eax = 0x1130;
+ r.ebx = 0x06;
+ rm_int(0x10, &r, &r);
+
+ vga_font = ext_mem_balloc(VGA_FONT_MAX);
+
+ memcpy(vga_font, (void *)rm_desegment(r.es, r.ebp), VGA_FONT_MAX);
+}
+
+static uint32_t *vbe_framebuffer;
+static uint16_t vbe_pitch;
+static uint16_t vbe_width = 0;
+static uint16_t vbe_height = 0;
+static uint16_t vbe_bpp = 0;
+
+void vbe_plot_px(int x, int y, uint32_t hex) {
+ size_t fb_i = x + (vbe_pitch / sizeof(uint32_t)) * y;
+
+ vbe_framebuffer[fb_i] = hex;
+}
+
+void vbe_plot_char(struct vbe_char c, int x, int y) {
+ int orig_x = x;
+ uint8_t *glyph = &vga_font[c.c * VGA_FONT_HEIGHT];
+
+ for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
+ for (int j = VGA_FONT_WIDTH - 1; j >= 0; j--)
+ vbe_plot_px(x++, y, (glyph[i] & (1 << j)) ? c.fg : c.bg);
+ y++;
+ x = orig_x;
+ }
+}
+
+static struct vbe_char *grid;
+
+static bool cursor_status = true;
+
+static int cursor_x;
+static int cursor_y;
+
+static uint32_t cursor_fg = 0x00000000;
+static uint32_t cursor_bg = 0x00ffffff;
+static uint32_t text_fg = 0x00ffffff;
+static uint32_t text_bg = 0x00000000;
+
+static int rows;
+static int cols;
+
+static void plot_char_grid(struct vbe_char c, int x, int y) {
+ vbe_plot_char(c, x * VGA_FONT_WIDTH, y * VGA_FONT_HEIGHT);
+ grid[x + y * cols] = c;
+}
+
+static void clear_cursor(void) {
+ if (cursor_status) {
+ vbe_plot_char(grid[cursor_x + cursor_y * cols],
+ cursor_x * VGA_FONT_WIDTH, cursor_y * VGA_FONT_HEIGHT);
+ }
+}
+
+static void draw_cursor(void) {
+ struct vbe_char c = grid[cursor_x + cursor_y * cols];
+ c.fg = cursor_fg;
+ c.bg = cursor_bg;
+ if (cursor_status)
+ vbe_plot_char(c, cursor_x * VGA_FONT_WIDTH, cursor_y * VGA_FONT_HEIGHT);
+}
+
+void vbe_scroll(void) {
+ clear_cursor();
+
+ for (int i = cols; i < rows * cols; i++) {
+ plot_char_grid(grid[i], (i - cols) % cols, (i - cols) / cols);
+ }
+
+ // Clear the last line of the screen.
+ struct vbe_char empty;
+ empty.c = ' ';
+ empty.fg = text_fg;
+ empty.bg = text_bg;
+ for (int i = rows * cols - cols; i < rows * cols; i++) {
+ plot_char_grid(empty, i % cols, i / cols);
+ }
+
+ draw_cursor();
+}
+
+void vbe_clear(void) {
+ clear_cursor();
+
+ struct vbe_char empty;
+ empty.c = ' ';
+ empty.fg = text_fg;
+ empty.bg = text_bg;
+ for (int i = 0; i < rows * cols; i++) {
+ plot_char_grid(empty, i % cols, i / cols);
+ }
+
+ cursor_x = 0;
+ cursor_y = 0;
+
+ draw_cursor();
+}
+
+void vbe_enable_cursor(void) {
+ cursor_status = true;
+ draw_cursor();
+}
+
+void vbe_disable_cursor(void) {
+ clear_cursor();
+ cursor_status = false;
+}
+
+void vbe_set_cursor_pos(int x, int y) {
+ clear_cursor();
+ cursor_x = x;
+ cursor_y = y;
+ draw_cursor();
+}
+
+void vbe_get_cursor_pos(int *x, int *y) {
+ *x = cursor_x;
+ *y = cursor_y;
+}
+
+void vbe_set_text_attributes(uint32_t fg, uint32_t bg) {
+ text_fg = fg;
+ text_bg = bg;
+}
+
+void vbe_set_cursor_attributes(uint32_t fg, uint32_t bg) {
+ clear_cursor();
+ cursor_fg = fg;
+ cursor_bg = bg;
+ draw_cursor();
+}
+
+void vbe_tty_init(void) {
+ init_vbe(&vbe_framebuffer, &vbe_pitch, &vbe_width, &vbe_height, &vbe_bpp);
+ vga_font_retrieve();
+ cols = vbe_width / VGA_FONT_WIDTH;
+ rows = vbe_height / VGA_FONT_HEIGHT;
+ grid = ext_mem_balloc(rows * cols * sizeof(struct vbe_char));
+ vbe_clear();
+}
+
struct vbe_info_struct {
char signature[4];
uint8_t version_min;
@@ -119,7 +279,7 @@ static struct resolution fallback_resolutions[] = {
{ 640, 480, 32 }
};
-int init_vbe(uint64_t *framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height, uint16_t *target_bpp) {
+int init_vbe(uint32_t **framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height, uint16_t *target_bpp) {
print("vbe: Initialising...\n");
size_t current_fallback = 0;
@@ -166,7 +326,7 @@ retry:;
&& vbe_mode_info.res_y == *target_height
&& vbe_mode_info.bpp == *target_bpp) {
print("vbe: Found matching mode %x, attempting to set\n", vid_modes[i]);
- *framebuffer = (uint64_t)vbe_mode_info.framebuffer;
+ *framebuffer = (uint32_t *)vbe_mode_info.framebuffer;
*pitch = (int)vbe_mode_info.pitch;
print("vbe: Framebuffer address: %x\n", vbe_mode_info.framebuffer);
set_vbe_mode(vid_modes[i]);
diff --git a/src/drivers/vbe.h b/src/drivers/vbe.h
index 180deb1a..af9fa30e 100644
--- a/src/drivers/vbe.h
+++ b/src/drivers/vbe.h
@@ -1,6 +1,14 @@
#ifndef __DRIVERS__VBE_H__
#define __DRIVERS__VBE_H__
-int init_vbe(uint64_t *framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height, uint16_t *target_bpp);
+#include <stdint.h>
+
+struct vbe_char {
+ char c;
+ uint32_t fg;
+ uint32_t bg;
+};
+
+int init_vbe(uint32_t **framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height, uint16_t *target_bpp);
#endif
diff --git a/src/lib/memmap.c b/src/lib/memmap.c
index 1cd14e3d..321fea73 100644
--- a/src/lib/memmap.c
+++ b/src/lib/memmap.c
@@ -168,7 +168,7 @@ void init_memmap(void) {
static size_t ext_mem_balloc_base = 0x100000;
void *ext_mem_balloc(size_t count) {
- ext_mem_balloc_aligned(count, 4);
+ return ext_mem_balloc_aligned(count, 4);
}
// TODO: this basically only works for the 1st extended memory entry in the
@@ -186,7 +186,7 @@ void *ext_mem_balloc_aligned(size_t count, size_t alignment) {
if (base >= entry_base && base < entry_top &&
top >= entry_base && top < entry_top) {
ext_mem_balloc_base = base + count;
- return (void *)base;
+ return (void *)(size_t)base;
}
}
diff --git a/src/protos/stivale.c b/src/protos/stivale.c
index 305191be..ebf10fce 100644
--- a/src/protos/stivale.c
+++ b/src/protos/stivale.c
@@ -225,11 +225,13 @@ void stivale_load(char *cmdline, int boot_drive) {
stivale_struct.framebuffer_bpp = stivale_hdr.framebuffer_bpp;
if (stivale_hdr.flags & (1 << 0)) {
- init_vbe(&stivale_struct.framebuffer_addr,
+ uint32_t *fb32;
+ init_vbe(&fb32,
&stivale_struct.framebuffer_pitch,
&stivale_struct.framebuffer_width,
&stivale_struct.framebuffer_height,
&stivale_struct.framebuffer_bpp);
+ stivale_struct.framebuffer_addr = (uint64_t)(size_t)fb32;
} else {
deinit_vga_textmode();
}
diff --git a/src/protos/stivale2.c b/src/protos/stivale2.c
index 5f812872..b7a1fd46 100644
--- a/src/protos/stivale2.c
+++ b/src/protos/stivale2.c
@@ -374,11 +374,13 @@ void stivale2_load(char *cmdline, int boot_drive) {
tag->framebuffer_height = hdrtag->framebuffer_height;
tag->framebuffer_bpp = hdrtag->framebuffer_bpp;
- init_vbe(&tag->framebuffer_addr,
+ uint32_t *fb32;
+ init_vbe(&fb32,
&tag->framebuffer_pitch,
&tag->framebuffer_width,
&tag->framebuffer_height,
&tag->framebuffer_bpp);
+ tag->framebuffer_addr = (uint64_t)(size_t)fb32;
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
}
