diff --git a/.gitignore b/.gitignore index 45fc17a3..40d5f11d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /limine-efi /freestanding-headers /libgcc-binaries +/common/term /ovmf* *.o *.d diff --git a/GNUmakefile.in b/GNUmakefile.in index 1ea0413d..830f18b7 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -251,6 +251,7 @@ dist: cp -r '$(call SHESCAPE,$(SRCDIR))'/.git '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)"/ cd '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)" && git checkout . cd '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)" && ./bootstrap + rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/common/term/.git" rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/freestanding-headers/.git" rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.git" rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.gitignore" @@ -287,7 +288,7 @@ distclean: clean .PHONY: maintainer-clean maintainer-clean: distclean - cd '$(call SHESCAPE,$(SRCDIR))' && rm -rf freestanding-headers libgcc-binaries limine-efi cross-detect configure build-aux *'~' autom4te.cache *.tar.xz *.tar.gz + cd '$(call SHESCAPE,$(SRCDIR))' && rm -rf common/term freestanding-headers libgcc-binaries limine-efi cross-detect configure build-aux *'~' autom4te.cache *.tar.xz *.tar.gz .PHONY: common-uefi-x86-64 common-uefi-x86-64: diff --git a/bootstrap b/bootstrap index 2376e6f6..f440d36a 100755 --- a/bootstrap +++ b/bootstrap @@ -7,6 +7,7 @@ test -z "$srcdir" && srcdir=. cd "$srcdir" +[ -d common/term ] || git clone https://github.com/limine-bootloader/terminal.git common/term [ -d cross-detect ] || git clone https://github.com/mintsuki/cross-detect.git [ -d freestanding-headers ] || git clone https://github.com/mintsuki/freestanding-headers.git [ -d limine-efi ] || git clone https://github.com/limine-bootloader/limine-efi.git diff --git a/common/drivers/vga_textmode.c b/common/drivers/vga_textmode.c index 9ed7da42..d5da701c 100644 --- a/common/drivers/vga_textmode.c +++ b/common/drivers/vga_textmode.c @@ -15,149 +15,99 @@ #define VD_COLS (80 * 2) #define VD_ROWS 25 -static volatile uint8_t *video_mem = (uint8_t *)0xb8000; - -static uint8_t *back_buffer = NULL; -static uint8_t *front_buffer = NULL; - -static struct context { - size_t cursor_offset; -#define cursor_offset context.cursor_offset - bool cursor_status; -#define cursor_status context.cursor_status - uint8_t text_palette; -#define text_palette context.text_palette - bool scroll_enabled; -#define scroll_enabled context.scroll_enabled - - uint8_t saved_state_text_palette; -#define saved_state_text_palette context.saved_state_text_palette - size_t saved_state_cursor_offset; -#define saved_state_cursor_offset context.saved_state_cursor_offset -} context; - -static size_t old_cursor_offset = 0; - -static void draw_cursor(void) { - uint8_t pal = back_buffer[cursor_offset + 1]; - video_mem[cursor_offset + 1] = ((pal & 0xf0) >> 4) | ((pal & 0x0f) << 4); +static void draw_cursor(struct textmode_context *ctx) { + uint8_t pal = ctx->back_buffer[ctx->cursor_offset + 1]; + ctx->video_mem[ctx->cursor_offset + 1] = ((pal & 0xf0) >> 4) | ((pal & 0x0f) << 4); } -void text_save_state(void) { - saved_state_text_palette = text_palette; - saved_state_cursor_offset = cursor_offset; +void text_save_state(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + ctx->saved_state_text_palette = ctx->text_palette; + ctx->saved_state_cursor_offset = ctx->cursor_offset; } -void text_restore_state(void) { - text_palette = saved_state_text_palette; - cursor_offset = saved_state_cursor_offset; +void text_restore_state(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette = ctx->saved_state_text_palette; + ctx->cursor_offset = ctx->saved_state_cursor_offset; } -void text_swap_palette(void) { - text_palette = (text_palette << 4) | (text_palette >> 4); +void text_swap_palette(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette = (ctx->text_palette << 4) | (ctx->text_palette >> 4); } -bool text_scroll_disable(void) { - bool ret = scroll_enabled; - scroll_enabled = false; - return ret; -} +void text_scroll(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; -void text_scroll_enable(void) { - scroll_enabled = true; -} - -void text_scroll(void) { // move the text up by one row - for (size_t i = term_context.scroll_top_margin * VD_COLS; - i < (term_context.scroll_bottom_margin - 1) * VD_COLS; i++) { - back_buffer[i] = back_buffer[i + VD_COLS]; + for (size_t i = _ctx->scroll_top_margin * VD_COLS; + i < (_ctx->scroll_bottom_margin - 1) * VD_COLS; i++) { + ctx->back_buffer[i] = ctx->back_buffer[i + VD_COLS]; } // clear the last line of the screen - for (size_t i = (term_context.scroll_bottom_margin - 1) * VD_COLS; - i < term_context.scroll_bottom_margin * VD_COLS; i += 2) { - back_buffer[i] = ' '; - back_buffer[i + 1] = text_palette; + for (size_t i = (_ctx->scroll_bottom_margin - 1) * VD_COLS; + i < _ctx->scroll_bottom_margin * VD_COLS; i += 2) { + ctx->back_buffer[i] = ' '; + ctx->back_buffer[i + 1] = ctx->text_palette; } } -void text_revscroll(void) { +void text_revscroll(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + // move the text up by one row - for (size_t i = (term_context.scroll_bottom_margin - 1) * VD_COLS - 2; ; i--) { - back_buffer[i + VD_COLS] = back_buffer[i]; - if (i == term_context.scroll_top_margin * VD_COLS) { + for (size_t i = (_ctx->scroll_bottom_margin - 1) * VD_COLS - 2; ; i--) { + ctx->back_buffer[i + VD_COLS] = ctx->back_buffer[i]; + if (i == _ctx->scroll_top_margin * VD_COLS) { break; } } // clear the first line of the screen - for (size_t i = term_context.scroll_top_margin * VD_COLS; - i < (term_context.scroll_top_margin + 1) * VD_COLS; i += 2) { - back_buffer[i] = ' '; - back_buffer[i + 1] = text_palette; + for (size_t i = _ctx->scroll_top_margin * VD_COLS; + i < (_ctx->scroll_top_margin + 1) * VD_COLS; i += 2) { + ctx->back_buffer[i] = ' '; + ctx->back_buffer[i + 1] = ctx->text_palette; } } -void text_clear(bool move) { +void text_clear(struct term_context *_ctx, bool move) { + struct textmode_context *ctx = (void *)_ctx; + for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) { - back_buffer[i] = ' '; - back_buffer[i + 1] = text_palette; + ctx->back_buffer[i] = ' '; + ctx->back_buffer[i + 1] = ctx->text_palette; + } + if (move) { + ctx->cursor_offset = 0; } - if (move) - cursor_offset = 0; } -void text_enable_cursor(void) { - cursor_status = true; +void text_enable_cursor(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + + ctx->cursor_status = true; } -bool text_disable_cursor(void) { - bool ret = cursor_status; - cursor_status = false; +bool text_disable_cursor(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + + bool ret = ctx->cursor_status; + ctx->cursor_status = false; return ret; } -uint64_t text_context_size(void) { - uint64_t ret = 0; - - ret += sizeof(struct context); - ret += VD_ROWS * VD_COLS; // front buffer - - return ret; -} - -void text_context_save(uint64_t ptr) { - memcpy32to64(ptr, (uint64_t)(uintptr_t)&context, sizeof(struct context)); - ptr += sizeof(struct context); - - memcpy32to64(ptr, (uint64_t)(uintptr_t)front_buffer, VD_ROWS * VD_COLS); -} - -void text_context_restore(uint64_t ptr) { - memcpy32to64((uint64_t)(uintptr_t)&context, ptr, sizeof(struct context)); - ptr += sizeof(struct context); - - memcpy32to64((uint64_t)(uintptr_t)front_buffer, ptr, VD_ROWS * VD_COLS); +void text_full_refresh(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) { - video_mem[i] = front_buffer[i]; - back_buffer[i] = front_buffer[i]; + ctx->video_mem[i] = ctx->front_buffer[i]; + ctx->back_buffer[i] = ctx->front_buffer[i]; } - if (cursor_status) { - draw_cursor(); - old_cursor_offset = cursor_offset; - } -} - -void text_full_refresh(void) { - for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) { - video_mem[i] = front_buffer[i]; - back_buffer[i] = front_buffer[i]; - } - - if (cursor_status) { - draw_cursor(); - old_cursor_offset = cursor_offset; + if (ctx->cursor_status) { + draw_cursor(ctx); + ctx->old_cursor_offset = ctx->cursor_offset; } } @@ -170,23 +120,26 @@ void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) { current_video_mode = 0x3; } - if (back_buffer == NULL) { - back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS); + struct textmode_context *ctx = (void *)term; + + if (ctx->back_buffer == NULL) { + ctx->back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS); } else { - memset(back_buffer, 0, VD_ROWS * VD_COLS); + memset(ctx->back_buffer, 0, VD_ROWS * VD_COLS); } - if (front_buffer == NULL) { - front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS); + if (ctx->front_buffer == NULL) { + ctx->front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS); } else { - memset(front_buffer, 0, VD_ROWS * VD_COLS); + memset(ctx->front_buffer, 0, VD_ROWS * VD_COLS); } - cursor_offset = 0; - cursor_status = true; - text_palette = 0x07; - scroll_enabled = true; + ctx->cursor_offset = 0; + ctx->cursor_status = true; + ctx->text_palette = 0x07; - text_clear(false); + ctx->video_mem = (volatile uint8_t *)0xb8000; + + text_clear(term, false); *_rows = VD_ROWS; *_cols = VD_COLS / 2; @@ -194,7 +147,7 @@ void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) { // VGA cursor code taken from: https://wiki.osdev.org/Text_Mode_Cursor if (!managed) { - text_disable_cursor(); + text_disable_cursor(term); outb(0x3d4, 0x0a); outb(0x3d5, (inb(0x3d5) & 0xc0) | 14); @@ -213,51 +166,59 @@ void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) { outb(0x3d5, 0x20); } - text_double_buffer_flush(); + text_double_buffer_flush(term); } -void text_double_buffer_flush(void) { - if (cursor_status) { - draw_cursor(); +void text_double_buffer_flush(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + + if (ctx->cursor_status) { + draw_cursor(ctx); } - if (cursor_offset != old_cursor_offset || cursor_status == false) { - video_mem[old_cursor_offset + 1] = back_buffer[old_cursor_offset + 1]; + if (ctx->cursor_offset != ctx->old_cursor_offset || ctx->cursor_status == false) { + ctx->video_mem[ctx->old_cursor_offset + 1] = ctx->back_buffer[ctx->old_cursor_offset + 1]; } for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) { - if (back_buffer[i] == front_buffer[i]) { + if (ctx->back_buffer[i] == ctx->front_buffer[i]) { continue; } - if (cursor_status && i == cursor_offset + 1) { + if (ctx->cursor_status && i == ctx->cursor_offset + 1) { continue; } - front_buffer[i] = back_buffer[i]; - video_mem[i] = back_buffer[i]; + ctx->front_buffer[i] = ctx->back_buffer[i]; + ctx->video_mem[i] = ctx->back_buffer[i]; } - if (cursor_status) { - old_cursor_offset = cursor_offset; + if (ctx->cursor_status) { + ctx->old_cursor_offset = ctx->cursor_offset; } } -void text_get_cursor_pos(size_t *x, size_t *y) { - *x = (cursor_offset % VD_COLS) / 2; - *y = cursor_offset / VD_COLS; +void text_get_cursor_pos(struct term_context *_ctx, size_t *x, size_t *y) { + struct textmode_context *ctx = (void *)_ctx; + + *x = (ctx->cursor_offset % VD_COLS) / 2; + *y = ctx->cursor_offset / VD_COLS; } -void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y) { +void text_move_character(struct term_context *_ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y) { + struct textmode_context *ctx = (void *)_ctx; + if (old_x >= VD_COLS / 2 || old_y >= VD_ROWS || new_x >= VD_COLS / 2 || new_y >= VD_ROWS) { return; } - back_buffer[new_y * VD_COLS + new_x * 2] = back_buffer[old_y * VD_COLS + old_x * 2]; + ctx->back_buffer[new_y * VD_COLS + new_x * 2] = ctx->back_buffer[old_y * VD_COLS + old_x * 2]; } -void text_set_cursor_pos(size_t x, size_t y) { +void text_set_cursor_pos(struct term_context *_ctx, size_t x, size_t y) { + struct textmode_context *ctx = (void *)_ctx; + if (x >= VD_COLS / 2) { if ((int)x < 0) { x = 0; @@ -272,48 +233,56 @@ void text_set_cursor_pos(size_t x, size_t y) { y = VD_ROWS - 1; } } - cursor_offset = y * VD_COLS + x * 2; + ctx->cursor_offset = y * VD_COLS + x * 2; } static uint8_t ansi_colours[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; -void text_set_text_fg(size_t fg) { - text_palette = (text_palette & 0xf0) | ansi_colours[fg]; +void text_set_text_fg(struct term_context *_ctx, size_t fg) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette = (ctx->text_palette & 0xf0) | ansi_colours[fg]; } -void text_set_text_bg(size_t bg) { - text_palette = (text_palette & 0x0f) | (ansi_colours[bg] << 4); +void text_set_text_bg(struct term_context *_ctx, size_t bg) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette = (ctx->text_palette & 0x0f) | (ansi_colours[bg] << 4); } -void text_set_text_fg_bright(size_t fg) { - text_palette = (text_palette & 0xf0) | (ansi_colours[fg] | (1 << 3)); +void text_set_text_fg_bright(struct term_context *_ctx, size_t fg) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette = (ctx->text_palette & 0xf0) | (ansi_colours[fg] | (1 << 3)); } -void text_set_text_bg_bright(size_t bg) { - text_palette = (text_palette & 0x0f) | ((ansi_colours[bg] | (1 << 3)) << 4); +void text_set_text_bg_bright(struct term_context *_ctx, size_t bg) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette = (ctx->text_palette & 0x0f) | ((ansi_colours[bg] | (1 << 3)) << 4); } -void text_set_text_fg_default(void) { - text_palette = (text_palette & 0xf0) | 7; +void text_set_text_fg_default(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette = (ctx->text_palette & 0xf0) | 7; } -void text_set_text_bg_default(void) { - text_palette &= 0x0f; +void text_set_text_bg_default(struct term_context *_ctx) { + struct textmode_context *ctx = (void *)_ctx; + ctx->text_palette &= 0x0f; } -void text_putchar(uint8_t c) { - back_buffer[cursor_offset] = c; - back_buffer[cursor_offset + 1] = text_palette; - if (cursor_offset / VD_COLS == term_context.scroll_bottom_margin - 1 - && cursor_offset % VD_COLS == VD_COLS - 2) { - if (scroll_enabled) { - text_scroll(); - cursor_offset -= cursor_offset % VD_COLS; +void text_putchar(struct term_context *_ctx, uint8_t c) { + struct textmode_context *ctx = (void *)_ctx; + + ctx->back_buffer[ctx->cursor_offset] = c; + ctx->back_buffer[ctx->cursor_offset + 1] = ctx->text_palette; + if (ctx->cursor_offset / VD_COLS == _ctx->scroll_bottom_margin - 1 + && ctx->cursor_offset % VD_COLS == VD_COLS - 2) { + if (_ctx->scroll_enabled) { + text_scroll(_ctx); + ctx->cursor_offset -= ctx->cursor_offset % VD_COLS; } - } else if (cursor_offset >= (VIDEO_BOTTOM - 1)) { - cursor_offset -= cursor_offset % VD_COLS; + } else if (ctx->cursor_offset >= (VIDEO_BOTTOM - 1)) { + ctx->cursor_offset -= ctx->cursor_offset % VD_COLS; } else { - cursor_offset += 2; + ctx->cursor_offset += 2; } } diff --git a/common/drivers/vga_textmode.h b/common/drivers/vga_textmode.h index 1c76c357..5d165c82 100644 --- a/common/drivers/vga_textmode.h +++ b/common/drivers/vga_textmode.h @@ -4,36 +4,48 @@ #include #include #include +#include + +struct textmode_context { + struct term_context term; + + volatile uint8_t *video_mem; + + uint8_t *back_buffer; + uint8_t *front_buffer; + + size_t cursor_offset; + size_t old_cursor_offset; + bool cursor_status; + uint8_t text_palette; + + uint8_t saved_state_text_palette; + size_t saved_state_cursor_offset; +}; void init_vga_textmode(size_t *rows, size_t *cols, bool managed); -void text_putchar(uint8_t c); -void text_clear(bool move); -void text_enable_cursor(void); -bool text_disable_cursor(void); -void text_set_cursor_pos(size_t x, size_t y); -void text_get_cursor_pos(size_t *x, size_t *y); -void text_set_text_fg(size_t fg); -void text_set_text_bg(size_t bg); -void text_set_text_fg_bright(size_t fg); -void text_set_text_bg_bright(size_t bg); -void text_set_text_fg_default(void); -void text_set_text_bg_default(void); -bool text_scroll_disable(void); -void text_scroll_enable(void); -void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y); -void text_scroll(void); -void text_revscroll(void); -void text_swap_palette(void); -void text_save_state(void); -void text_restore_state(void); - -void text_double_buffer(bool state); -void text_double_buffer_flush(void); - -uint64_t text_context_size(void); -void text_context_save(uint64_t ptr); -void text_context_restore(uint64_t ptr); -void text_full_refresh(void); +void text_putchar(struct term_context *ctx, uint8_t c); +void text_clear(struct term_context *ctx, bool move); +void text_enable_cursor(struct term_context *ctx); +bool text_disable_cursor(struct term_context *ctx); +void text_set_cursor_pos(struct term_context *ctx, size_t x, size_t y); +void text_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y); +void text_set_text_fg(struct term_context *ctx, size_t fg); +void text_set_text_bg(struct term_context *ctx, size_t bg); +void text_set_text_fg_bright(struct term_context *ctx, size_t fg); +void text_set_text_bg_bright(struct term_context *ctx, size_t bg); +void text_set_text_fg_default(struct term_context *ctx); +void text_set_text_bg_default(struct term_context *ctx); +bool text_scroll_disable(struct term_context *ctx); +void text_scroll_enable(struct term_context *ctx); +void text_move_character(struct term_context *ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y); +void text_scroll(struct term_context *ctx); +void text_revscroll(struct term_context *ctx); +void text_swap_palette(struct term_context *ctx); +void text_save_state(struct term_context *ctx); +void text_restore_state(struct term_context *ctx); +void text_double_buffer_flush(struct term_context *ctx); +void text_full_refresh(struct term_context *ctx); #endif diff --git a/common/lib/gterm.c b/common/lib/gterm.c index 386248ab..8f250c1f 100644 --- a/common/lib/gterm.c +++ b/common/lib/gterm.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -9,121 +8,23 @@ #include #include #include - -// Maximum allowed font size in bytes. 16kB should be enough as 9x32 is the -// largest font I've seen, and that would take 9*32 * 256 * 1/8 byte = -// 9216 bytes. -#define VGA_FONT_MAX 16384 -#define VGA_FONT_GLYPHS 256 - -#define DEFAULT_FONT_WIDTH 8 -#define DEFAULT_FONT_HEIGHT 16 - -static size_t vga_font_width; -static size_t vga_font_height; -static size_t glyph_width = 8; -static size_t glyph_height = 16; - -static size_t vga_font_scale_x = 1; -static size_t vga_font_scale_y = 1; - -static size_t offset_x, offset_y; +#include +#include +#include struct fb_info fbinfo; -static volatile uint32_t *gterm_framebuffer; -static uint16_t gterm_pitch; -static uint16_t gterm_width; -static uint16_t gterm_height; -static uint16_t gterm_bpp; -extern symbol _binary_font_bin_start; - -static uint8_t *vga_font_bits = NULL; -static size_t vga_font_bool_size = 0; -static bool *vga_font_bool = NULL; - -static uint32_t ansi_colours[8]; -static uint32_t ansi_bright_colours[8]; -static uint32_t default_fg, default_bg; +extern symbol _binary_font_bin_start, _binary_font_bin_size; static struct image *background; -static size_t bg_canvas_size = 0; -static uint32_t *bg_canvas = NULL; +static size_t margin = 64; +static size_t margin_gradient = 4; -static size_t rows; -static size_t cols; -static size_t margin; -static size_t margin_gradient; +static uint32_t default_bg, default_fg; -static size_t grid_size = 0; -static size_t queue_size = 0; -static size_t map_size = 0; - -struct gterm_char { - uint32_t c; - uint32_t fg; - uint32_t bg; -}; - -static struct gterm_char *grid = NULL; - -struct queue_item { - size_t x, y; - struct gterm_char c; -}; - -static struct queue_item *queue = NULL; -static size_t queue_i = 0; - -static struct queue_item **map = NULL; - -static struct context { - uint32_t text_fg; -#define text_fg context.text_fg - uint32_t text_bg; -#define text_bg context.text_bg - bool cursor_status; -#define cursor_status context.cursor_status - size_t cursor_x; -#define cursor_x context.cursor_x - size_t cursor_y; -#define cursor_y context.cursor_y - bool scroll_enabled; -#define scroll_enabled context.scroll_enabled - - uint32_t saved_state_text_fg; -#define saved_state_text_fg context.saved_state_text_fg - uint32_t saved_state_text_bg; -#define saved_state_text_bg context.saved_state_text_bg - size_t saved_state_cursor_x; -#define saved_state_cursor_x context.saved_state_cursor_x - size_t saved_state_cursor_y; -#define saved_state_cursor_y context.saved_state_cursor_y -} context; - -static size_t old_cursor_x = 0; -static size_t old_cursor_y = 0; - -void gterm_save_state(void) { - saved_state_text_fg = text_fg; - saved_state_text_bg = text_bg; - saved_state_cursor_x = cursor_x; - saved_state_cursor_y = cursor_y; -} - -void gterm_restore_state(void) { - text_fg = saved_state_text_fg; - text_bg = saved_state_text_bg; - cursor_x = saved_state_cursor_x; - cursor_y = saved_state_cursor_y; -} - -void gterm_swap_palette(void) { - uint32_t tmp = text_bg; - text_bg = text_fg; - text_fg = tmp; -} +static size_t bg_canvas_size; +static uint32_t *bg_canvas; #define A(rgb) (uint8_t)(rgb >> 24) #define R(rgb) (uint8_t)(rgb >> 16) @@ -142,20 +43,10 @@ static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) { return ARGB(0, r, g, b); } -static inline void gterm_plot_px(size_t x, size_t y, uint32_t hex) { - if (x >= gterm_width || y >= gterm_height) { - return; - } - - size_t fb_i = x + (gterm_pitch / sizeof(uint32_t)) * y; - - gterm_framebuffer[fb_i] = hex; -} - static uint32_t blend_gradient_from_box(size_t x, size_t y, uint32_t bg_px, uint32_t hex) { size_t distance, x_distance, y_distance; - size_t gradient_stop_x = gterm_width - margin; - size_t gradient_stop_y = gterm_height - margin; + size_t gradient_stop_x = fbinfo.framebuffer_width - margin; + size_t gradient_stop_y = fbinfo.framebuffer_height - margin; if (x < margin) x_distance = margin - x; @@ -199,11 +90,11 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t for (size_t y = ystart; y < yend; y++) { size_t image_y = y % img_height, image_x = xstart % img_width; const size_t off = img_pitch * (img_height - 1 - image_y); - size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y; + size_t canvas_off = fbinfo.framebuffer_width * y; for (size_t x = xstart; x < xend; x++) { uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); uint32_t i = blend(x, y, img_pixel); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; + bg_canvas[canvas_off + x] = i; if (image_x++ == img_width) image_x = 0; // image_x = x % img_width, but modulo is too expensive } } @@ -213,11 +104,11 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t for (size_t y = ystart; y < yend; y++) { size_t image_y = y - background->y_displacement; const size_t off = img_pitch * (img_height - 1 - image_y); - size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y; + size_t canvas_off = fbinfo.framebuffer_width * y; if (image_y >= background->y_size) { /* external part */ for (size_t x = xstart; x < xend; x++) { uint32_t i = blend(x, y, background->back_colour); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; + bg_canvas[canvas_off + x] = i; } } else { /* internal part */ @@ -226,7 +117,7 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t bool x_external = image_x >= background->x_size; uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); uint32_t i = blend(x, y, x_external ? background->back_colour : img_pixel); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; + bg_canvas[canvas_off + x] = i; } } } @@ -236,16 +127,16 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t // so you can set x = xstart * ratio, and increment by ratio at each iteration case IMAGE_STRETCHED: for (size_t y = ystart; y < yend; y++) { - size_t img_y = (y * img_height) / gterm_height; // calculate Y with full precision + size_t img_y = (y * img_height) / fbinfo.framebuffer_height; // calculate Y with full precision size_t off = img_pitch * (img_height - 1 - img_y); - size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y; + size_t canvas_off = fbinfo.framebuffer_width * y; - size_t ratio = int_to_fixedp6(img_width) / gterm_width; + size_t ratio = int_to_fixedp6(img_width) / fbinfo.framebuffer_width; fixedp6 img_x = ratio * xstart; for (size_t x = xstart; x < xend; x++) { uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off); uint32_t i = blend(x, y, img_pixel); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; + bg_canvas[canvas_off + x] = i; img_x += ratio; } } @@ -261,24 +152,27 @@ static void loop_external(size_t xstart, size_t xend, size_t ystart, size_t yend static void loop_margin(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_margin); } static void loop_internal(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_internal); } -static void gterm_generate_canvas(void) { +static void *generate_canvas(void) { if (background) { + bg_canvas_size = fbinfo.framebuffer_width * fbinfo.framebuffer_height * sizeof(uint32_t); + bg_canvas = ext_mem_alloc(bg_canvas_size); + int64_t margin_no_gradient = (int64_t)margin - margin_gradient; if (margin_no_gradient < 0) { margin_no_gradient = 0; } - size_t scan_stop_x = gterm_width - margin_no_gradient; - size_t scan_stop_y = gterm_height - margin_no_gradient; + size_t scan_stop_x = fbinfo.framebuffer_width - margin_no_gradient; + size_t scan_stop_y = fbinfo.framebuffer_height - margin_no_gradient; - loop_external(0, gterm_width, 0, margin_no_gradient); - loop_external(0, gterm_width, scan_stop_y, gterm_height); + loop_external(0, fbinfo.framebuffer_width, 0, margin_no_gradient); + loop_external(0, fbinfo.framebuffer_width, scan_stop_y, fbinfo.framebuffer_height); loop_external(0, margin_no_gradient, margin_no_gradient, scan_stop_y); - loop_external(scan_stop_x, gterm_width, margin_no_gradient, scan_stop_y); + loop_external(scan_stop_x, fbinfo.framebuffer_width, margin_no_gradient, scan_stop_y); - size_t gradient_stop_x = gterm_width - margin; - size_t gradient_stop_y = gterm_height - margin; + size_t gradient_stop_x = fbinfo.framebuffer_width - margin; + size_t gradient_stop_y = fbinfo.framebuffer_height - margin; if (margin_gradient) { loop_margin(margin_no_gradient, scan_stop_x, margin_no_gradient, margin); @@ -288,327 +182,17 @@ static void gterm_generate_canvas(void) { } loop_internal(margin, gradient_stop_x, margin, gradient_stop_y); - } else { - for (size_t y = 0; y < gterm_height; y++) { - for (size_t x = 0; x < gterm_width; x++) { - bg_canvas[y * gterm_width + x] = default_bg; - gterm_plot_px(x, y, default_bg); - } - } - } -} -static void plot_char(struct gterm_char *c, size_t x, size_t y) { - if (x >= cols || y >= rows) { - return; + return bg_canvas; } - x = offset_x + x * glyph_width; - y = offset_y + y * glyph_height; - - bool *glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width]; - // naming: fx,fy for font coordinates, gx,gy for glyph coordinates - for (size_t gy = 0; gy < glyph_height; gy++) { - uint8_t fy = gy / vga_font_scale_y; - volatile uint32_t *fb_line = gterm_framebuffer + x + (y + gy) * (gterm_pitch / 4); - uint32_t *canvas_line = bg_canvas + x + (y + gy) * gterm_width; - for (size_t fx = 0; fx < vga_font_width; fx++) { - bool draw = glyph[fy * vga_font_width + fx]; - for (size_t i = 0; i < vga_font_scale_x; i++) { - size_t gx = vga_font_scale_x * fx + i; - uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg; - uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg; - fb_line[gx] = draw ? fg : bg; - } - } - } -} - -static void plot_char_fast(struct gterm_char *old, struct gterm_char *c, size_t x, size_t y) { - if (x >= cols || y >= rows) { - return; - } - - x = offset_x + x * glyph_width; - y = offset_y + y * glyph_height; - - bool *new_glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width]; - bool *old_glyph = &vga_font_bool[old->c * vga_font_height * vga_font_width]; - for (size_t gy = 0; gy < glyph_height; gy++) { - uint8_t fy = gy / vga_font_scale_y; - volatile uint32_t *fb_line = gterm_framebuffer + x + (y + gy) * (gterm_pitch / 4); - uint32_t *canvas_line = bg_canvas + x + (y + gy) * gterm_width; - for (size_t fx = 0; fx < vga_font_width; fx++) { - bool old_draw = old_glyph[fy * vga_font_width + fx]; - bool new_draw = new_glyph[fy * vga_font_width + fx]; - if (old_draw == new_draw) - continue; - for (size_t i = 0; i < vga_font_scale_x; i++) { - size_t gx = vga_font_scale_x * fx + i; - uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg; - uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg; - fb_line[gx] = new_draw ? fg : bg; - } - } - } -} - -static inline bool compare_char(struct gterm_char *a, struct gterm_char *b) { - return !(a->c != b->c || a->bg != b->bg || a->fg != b->fg); -} - -static void push_to_queue(struct gterm_char *c, size_t x, size_t y) { - if (x >= cols || y >= rows) { - return; - } - - size_t i = y * cols + x; - - struct queue_item *q = map[i]; - - if (q == NULL) { - if (compare_char(&grid[i], c)) { - return; - } - q = &queue[queue_i++]; - q->x = x; - q->y = y; - map[i] = q; - } - - q->c = *c; -} - -bool gterm_scroll_disable(void) { - bool ret = scroll_enabled; - scroll_enabled = false; - return ret; -} - -void gterm_scroll_enable(void) { - scroll_enabled = true; -} - -void gterm_revscroll(void) { - for (size_t i = (term_context.scroll_bottom_margin - 1) * cols - 1; ; i--) { - struct gterm_char *c; - struct queue_item *q = map[i]; - if (q != NULL) { - c = &q->c; - } else { - c = &grid[i]; - } - push_to_queue(c, (i + cols) % cols, (i + cols) / cols); - if (i == term_context.scroll_top_margin * cols) { - break; - } - } - - // Clear the first line of the screen. - struct gterm_char empty; - empty.c = ' '; - empty.fg = text_fg; - empty.bg = text_bg; - for (size_t i = term_context.scroll_top_margin * cols; - i < (term_context.scroll_top_margin + 1) * cols; i++) { - push_to_queue(&empty, i % cols, i / cols); - } -} - -void gterm_scroll(void) { - for (size_t i = (term_context.scroll_top_margin + 1) * cols; - i < term_context.scroll_bottom_margin * cols; i++) { - struct gterm_char *c; - struct queue_item *q = map[i]; - if (q != NULL) { - c = &q->c; - } else { - c = &grid[i]; - } - push_to_queue(c, (i - cols) % cols, (i - cols) / cols); - } - - // Clear the last line of the screen. - struct gterm_char empty; - empty.c = ' '; - empty.fg = text_fg; - empty.bg = text_bg; - for (size_t i = (term_context.scroll_bottom_margin - 1) * cols; - i < term_context.scroll_bottom_margin * cols; i++) { - push_to_queue(&empty, i % cols, i / cols); - } -} - -void gterm_clear(bool move) { - struct gterm_char empty; - empty.c = ' '; - empty.fg = text_fg; - empty.bg = text_bg; - for (size_t i = 0; i < rows * cols; i++) { - push_to_queue(&empty, i % cols, i / cols); - } - - if (move) { - cursor_x = 0; - cursor_y = 0; - } -} - -void gterm_enable_cursor(void) { - cursor_status = true; -} - -bool gterm_disable_cursor(void) { - bool ret = cursor_status; - cursor_status = false; - return ret; -} - -void gterm_set_cursor_pos(size_t x, size_t y) { - if (x >= cols) { - if ((int)x < 0) { - x = 0; - } else { - x = cols - 1; - } - } - if (y >= rows) { - if ((int)y < 0) { - y = 0; - } else { - y = rows - 1; - } - } - cursor_x = x; - cursor_y = y; -} - -void gterm_get_cursor_pos(size_t *x, size_t *y) { - *x = cursor_x; - *y = cursor_y; -} - -void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y) { - if (old_x >= cols || old_y >= rows - || new_x >= cols || new_y >= rows) { - return; - } - - size_t i = old_x + old_y * cols; - - struct gterm_char *c; - struct queue_item *q = map[i]; - if (q != NULL) { - c = &q->c; - } else { - c = &grid[i]; - } - - push_to_queue(c, new_x, new_y); -} - -void gterm_set_text_fg(size_t fg) { - text_fg = ansi_colours[fg]; -} - -void gterm_set_text_bg(size_t bg) { - text_bg = ansi_colours[bg]; -} - -void gterm_set_text_fg_bright(size_t fg) { - text_fg = ansi_bright_colours[fg]; -} - -void gterm_set_text_bg_bright(size_t bg) { - text_bg = ansi_bright_colours[bg]; -} - -void gterm_set_text_fg_rgb(uint32_t fg) { - text_fg = fg; -} - -void gterm_set_text_bg_rgb(uint32_t bg) { - text_bg = bg; -} - -void gterm_set_text_fg_default(void) { - text_fg = default_fg; -} - -void gterm_set_text_bg_default(void) { - text_bg = 0xffffffff; -} - -static void draw_cursor(void) { - size_t i = cursor_x + cursor_y * cols; - struct gterm_char c; - struct queue_item *q = map[i]; - if (q != NULL) { - c = q->c; - } else { - c = grid[i]; - } - uint32_t tmp = c.fg; - c.fg = c.bg; - c.bg = tmp; - plot_char(&c, cursor_x, cursor_y); - if (q != NULL) { - grid[i] = q->c; - map[i] = NULL; - } -} - -void gterm_double_buffer_flush(void) { - if (cursor_status) { - draw_cursor(); - } - - for (size_t i = 0; i < queue_i; i++) { - struct queue_item *q = &queue[i]; - size_t offset = q->y * cols + q->x; - if (map[offset] == NULL) { - continue; - } - struct gterm_char *old = &grid[offset]; - if (q->c.bg == old->bg && q->c.fg == old->fg) { - plot_char_fast(old, &q->c, q->x, q->y); - } else { - plot_char(&q->c, q->x, q->y); - } - grid[offset] = q->c; - map[offset] = NULL; - } - - if ((old_cursor_x != cursor_x || old_cursor_y != cursor_y) || cursor_status == false) { - plot_char(&grid[old_cursor_x + old_cursor_y * cols], old_cursor_x, old_cursor_y); - } - - old_cursor_x = cursor_x; - old_cursor_y = cursor_y; - - queue_i = 0; -} - -void gterm_putchar(uint8_t c) { - struct gterm_char ch; - ch.c = c; - ch.fg = text_fg; - ch.bg = text_bg; - push_to_queue(&ch, cursor_x++, cursor_y); - if (cursor_x == cols && (cursor_y < term_context.scroll_bottom_margin - 1 || scroll_enabled)) { - cursor_x = 0; - cursor_y++; - } - if (cursor_y == term_context.scroll_bottom_margin) { - cursor_y--; - gterm_scroll(); - } + return NULL; } static bool last_serial = false; static char *last_config = NULL; -bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t height) { +bool gterm_init(char *config, size_t width, size_t height) { if (current_video_mode >= 0 #if defined (BIOS) && current_video_mode != 0x03 @@ -619,9 +203,7 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t && fbinfo.framebuffer_bpp == 32 && serial == last_serial && config == last_config) { - *_rows = rows; - *_cols = cols; - gterm_clear(true); + term->clear(term, true); return true; } @@ -634,9 +216,7 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t && fbinfo.framebuffer_bpp == 32 && serial == last_serial && config == last_config) { - *_rows = rows; - *_cols = cols; - gterm_clear(true); + term->clear(term, true); return true; } @@ -644,15 +224,23 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t if (!fb_init(&fbinfo, width, height, 32)) return false; - last_serial = serial; + // Ensure this is xRGB8888, we only support that for the menu + if (fbinfo.red_mask_size != 8 + || fbinfo.red_mask_shift != 16 + || fbinfo.green_mask_size != 8 + || fbinfo.green_mask_shift != 8 + || fbinfo.blue_mask_size != 8 + || fbinfo.blue_mask_shift != 0) + return false; - cursor_status = true; - scroll_enabled = true; + last_serial = serial; // default scheme margin = 64; margin_gradient = 4; + uint32_t ansi_colours[8]; + ansi_colours[0] = 0x00000000; // black ansi_colours[1] = 0x00aa0000; // red ansi_colours[2] = 0x0000aa00; // green @@ -678,6 +266,8 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t } } + uint32_t ansi_bright_colours[8]; + ansi_bright_colours[0] = 0x00555555; // black ansi_bright_colours[1] = 0x00ff5555; // red ansi_bright_colours[2] = 0x0055ff55; // green @@ -716,9 +306,6 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t default_fg = strtoui(theme_foreground, NULL, 16) & 0xffffff; } - text_fg = default_fg; - text_bg = 0xffffffff; - background = NULL; char *background_path = config_get_value(config, 0, "TERM_WALLPAPER"); if (background_path != NULL) { @@ -762,27 +349,14 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t } } - // Ensure this is xRGB8888, we only support that for the menu - if (fbinfo.red_mask_size != 8 - || fbinfo.red_mask_shift != 16 - || fbinfo.green_mask_size != 8 - || fbinfo.green_mask_shift != 8 - || fbinfo.blue_mask_size != 8 - || fbinfo.blue_mask_shift != 0) - return false; + size_t font_width = 8; + size_t font_height = 16; + size_t font_size = (font_width * font_height * FBTERM_FONT_GLYPHS) / 8; - gterm_framebuffer = (void *)(uintptr_t)fbinfo.framebuffer_addr; - gterm_width = fbinfo.framebuffer_width; - gterm_height = fbinfo.framebuffer_height; - gterm_bpp = fbinfo.framebuffer_bpp; - gterm_pitch = fbinfo.framebuffer_pitch; +#define FONT_MAX 16384 + uint8_t *font = ext_mem_alloc(FONT_MAX); - vga_font_width = DEFAULT_FONT_WIDTH, vga_font_height = DEFAULT_FONT_HEIGHT; - size_t font_bytes = (vga_font_width * vga_font_height * VGA_FONT_GLYPHS) / 8; - - vga_font_bits = ext_mem_alloc(VGA_FONT_MAX); - - memcpy(vga_font_bits, (void *)_binary_font_bin_start, VGA_FONT_MAX); + memcpy(font, (void *)_binary_font_bin_start, (uintptr_t)_binary_font_bin_size); size_t tmp_font_width, tmp_font_height; @@ -790,14 +364,14 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t if (menu_font_size != NULL) { parse_resolution(&tmp_font_width, &tmp_font_height, NULL, menu_font_size); - size_t tmp_font_bytes = (tmp_font_width * tmp_font_height * VGA_FONT_GLYPHS) / 8; + size_t tmp_font_size = (tmp_font_width * tmp_font_height * FBTERM_FONT_GLYPHS) / 8; - if (tmp_font_bytes > VGA_FONT_MAX) { - print("Font would be too large (%u bytes, %u bytes allowed). Not loading.\n", tmp_font_bytes, VGA_FONT_MAX); + if (tmp_font_size > FONT_MAX) { + print("Font would be too large (%u bytes, %u bytes allowed). Not loading.\n", tmp_font_size, FONT_MAX); goto no_load_font; } - font_bytes = tmp_font_bytes; + font_size = tmp_font_size; } char *menu_font = config_get_value(config, 0, "TERM_FONT"); @@ -806,10 +380,10 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t if ((f = uri_open(menu_font)) == NULL) { print("menu: Could not open font file.\n"); } else { - fread(f, vga_font_bits, 0, font_bytes); + fread(f, font, 0, font_size); if (menu_font_size != NULL) { - vga_font_width = tmp_font_width; - vga_font_height = tmp_font_height; + font_width = tmp_font_width; + font_height = tmp_font_height; } fclose(f); } @@ -822,138 +396,31 @@ no_load_font:; font_spacing = strtoui(font_spacing_str, NULL, 10); } - vga_font_width += font_spacing; - - vga_font_bool_size = VGA_FONT_GLYPHS * vga_font_height * vga_font_width * sizeof(bool); - vga_font_bool = ext_mem_alloc(vga_font_bool_size); - - for (size_t i = 0; i < VGA_FONT_GLYPHS; i++) { - uint8_t *glyph = &vga_font_bits[i * vga_font_height]; - - for (size_t y = 0; y < vga_font_height; y++) { - // NOTE: the characters in VGA fonts are always one byte wide. - // 9 dot wide fonts have 8 dots and one empty column, except - // characters 0xC0-0xDF replicate column 9. - for (size_t x = 0; x < 8; x++) { - size_t offset = i * vga_font_height * vga_font_width + y * vga_font_width + x; - - if ((glyph[y] & (0x80 >> x))) { - vga_font_bool[offset] = true; - } else { - vga_font_bool[offset] = false; - } - } - // fill columns above 8 like VGA Line Graphics Mode does - for (size_t x = 8; x < vga_font_width; x++) { - size_t offset = i * vga_font_height * vga_font_width + y * vga_font_width + x; - - if (i >= 0xC0 && i <= 0xDF) { - vga_font_bool[offset] = (glyph[y] & 1); - } else { - vga_font_bool[offset] = false; - } - } - } - } - - vga_font_scale_x = 1; - vga_font_scale_y = 1; + size_t font_scale_x = 1; + size_t font_scale_y = 1; char *menu_font_scale = config_get_value(config, 0, "TERM_FONT_SCALE"); if (menu_font_scale != NULL) { - parse_resolution(&vga_font_scale_x, &vga_font_scale_y, NULL, menu_font_scale); - if (vga_font_scale_x > 8 || vga_font_scale_y > 8) { - vga_font_scale_x = 1; - vga_font_scale_y = 1; + parse_resolution(&font_scale_x, &font_scale_y, NULL, menu_font_scale); + if (font_scale_x > 8 || font_scale_y > 8) { + font_scale_x = 1; + font_scale_y = 1; } } - glyph_width = vga_font_width * vga_font_scale_x; - glyph_height = vga_font_height * vga_font_scale_y; + uint32_t *canvas = generate_canvas(); - *_cols = cols = (gterm_width - margin * 2) / glyph_width; - *_rows = rows = (gterm_height - margin * 2) / glyph_height; + term->deinit(term, pmm_free); - offset_x = margin + ((gterm_width - margin * 2) % glyph_width) / 2; - offset_y = margin + ((gterm_height - margin * 2) % glyph_height) / 2; - - grid_size = rows * cols * sizeof(struct gterm_char); - grid = ext_mem_alloc(grid_size); - - queue_size = rows * cols * sizeof(struct queue_item); - queue = ext_mem_alloc(queue_size); - queue_i = 0; - - map_size = rows * cols * sizeof(struct queue_item *); - map = ext_mem_alloc(map_size); - - bg_canvas_size = gterm_width * gterm_height * sizeof(uint32_t); - bg_canvas = ext_mem_alloc(bg_canvas_size); - - gterm_generate_canvas(); - gterm_clear(true); - gterm_double_buffer_flush(); + term = fbterm_init(ext_mem_alloc, + (void *)(uintptr_t)fbinfo.framebuffer_addr, + fbinfo.framebuffer_width, fbinfo.framebuffer_height, fbinfo.framebuffer_pitch, + canvas, + ansi_colours, ansi_bright_colours, + &default_bg, &default_fg, + font, font_width, font_height, font_spacing, + font_scale_x, font_scale_y, + margin); return true; } - -void gterm_deinit(void) { - if (background != NULL) { - image_close(background); - } - pmm_free(vga_font_bits, VGA_FONT_MAX); - pmm_free(vga_font_bool, vga_font_bool_size); - pmm_free(grid, grid_size); - pmm_free(queue, queue_size); - pmm_free(map, map_size); - pmm_free(bg_canvas, bg_canvas_size); -} - -uint64_t gterm_context_size(void) { - uint64_t ret = 0; - - ret += sizeof(struct context); - ret += grid_size; - - return ret; -} - -void gterm_context_save(uint64_t ptr) { - memcpy32to64(ptr, (uint64_t)(uintptr_t)&context, sizeof(struct context)); - ptr += sizeof(struct context); - - memcpy32to64(ptr, (uint64_t)(uintptr_t)grid, grid_size); -} - -void gterm_context_restore(uint64_t ptr) { - memcpy32to64((uint64_t)(uintptr_t)&context, ptr, sizeof(struct context)); - ptr += sizeof(struct context); - - memcpy32to64((uint64_t)(uintptr_t)grid, ptr, grid_size); - - for (size_t i = 0; i < (size_t)rows * cols; i++) { - size_t x = i % cols; - size_t y = i / cols; - - plot_char(&grid[i], x, y); - } - - if (cursor_status) { - draw_cursor(); - } -} - -void gterm_full_refresh(void) { - gterm_generate_canvas(); - - for (size_t i = 0; i < (size_t)rows * cols; i++) { - size_t x = i % cols; - size_t y = i / cols; - - plot_char(&grid[i], x, y); - } - - if (cursor_status) { - draw_cursor(); - } -} diff --git a/common/lib/gterm.h b/common/lib/gterm.h index 6b3686a5..a680e7f2 100644 --- a/common/lib/gterm.h +++ b/common/lib/gterm.h @@ -1,44 +1,12 @@ #ifndef __LIB__GTERM_H__ #define __LIB__GTERM_H__ -#include +#include #include -#include -#include +#include extern struct fb_info fbinfo; -bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t height); -void gterm_deinit(void); - -void gterm_putchar(uint8_t c); -void gterm_clear(bool move); -void gterm_enable_cursor(void); -bool gterm_disable_cursor(void); -void gterm_set_cursor_pos(size_t x, size_t y); -void gterm_get_cursor_pos(size_t *x, size_t *y); -void gterm_set_text_fg(size_t fg); -void gterm_set_text_bg(size_t bg); -void gterm_set_text_fg_bright(size_t fg); -void gterm_set_text_bg_bright(size_t bg); -void gterm_set_text_fg_rgb(uint32_t fg); -void gterm_set_text_bg_rgb(uint32_t bg); -void gterm_set_text_fg_default(void); -void gterm_set_text_bg_default(void); -bool gterm_scroll_disable(void); -void gterm_scroll_enable(void); -void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y); -void gterm_scroll(void); -void gterm_revscroll(void); -void gterm_swap_palette(void); -void gterm_save_state(void); -void gterm_restore_state(void); - -void gterm_double_buffer_flush(void); - -uint64_t gterm_context_size(void); -void gterm_context_save(uint64_t ptr); -void gterm_context_restore(uint64_t ptr); -void gterm_full_refresh(void); +bool gterm_init(char *config, size_t width, size_t height); #endif diff --git a/common/lib/print.s2.c b/common/lib/print.s2.c index aeec7bb0..3c4f67b8 100644 --- a/common/lib/print.s2.c +++ b/common/lib/print.s2.c @@ -222,7 +222,7 @@ out: #if defined (BIOS) if (stage3_loaded) { #endif - term_write((uint64_t)(uintptr_t)print_buf, print_buf_i); + term_write(term, print_buf, print_buf_i); #if defined (BIOS) } else { s2_print(print_buf, print_buf_i); diff --git a/common/lib/readline.c b/common/lib/readline.c index c523a58c..a3e0b59f 100644 --- a/common/lib/readline.c +++ b/common/lib/readline.c @@ -348,32 +348,32 @@ again: static void reprint_string(int x, int y, const char *s) { size_t orig_x, orig_y; - disable_cursor(); - get_cursor_pos(&orig_x, &orig_y); + term->disable_cursor(term); + term->get_cursor_pos(term, &orig_x, &orig_y); set_cursor_pos_helper(x, y); print("%s", s); set_cursor_pos_helper(orig_x, orig_y); - enable_cursor(); + term->enable_cursor(term); } static void cursor_back(void) { size_t x, y; - get_cursor_pos(&x, &y); + term->get_cursor_pos(term, &x, &y); if (x) { x--; } else if (y) { y--; - x = term_cols - 1; + x = term->cols - 1; } set_cursor_pos_helper(x, y); } static void cursor_fwd(void) { size_t x, y; - get_cursor_pos(&x, &y); - if (x < term_cols - 1) { + term->get_cursor_pos(term, &x, &y); + if (x < term->cols - 1) { x++; - } else if (y < term_rows - 1) { + } else if (y < term->rows - 1) { y++; x = 0; } @@ -381,20 +381,20 @@ static void cursor_fwd(void) { } void readline(const char *orig_str, char *buf, size_t limit) { - bool prev_autoflush = term_autoflush; - term_autoflush = false; + bool prev_autoflush = term->autoflush; + term->autoflush = false; size_t orig_str_len = strlen(orig_str); memmove(buf, orig_str, orig_str_len); buf[orig_str_len] = 0; size_t orig_x, orig_y; - get_cursor_pos(&orig_x, &orig_y); + term->get_cursor_pos(term, &orig_x, &orig_y); print("%s", orig_str); for (size_t i = orig_str_len; ; ) { - term_double_buffer_flush(); + term->double_buffer_flush(term); int c = getchar(); switch (c) { case GETCHAR_CURSOR_LEFT: @@ -461,6 +461,6 @@ void readline(const char *orig_str, char *buf, size_t limit) { } out: - term_double_buffer_flush(); - term_autoflush = prev_autoflush; + term->double_buffer_flush(term); + term->autoflush = prev_autoflush; } diff --git a/common/lib/term.c b/common/lib/term.c index 46f75812..5fd4334f 100644 --- a/common/lib/term.c +++ b/common/lib/term.c @@ -12,54 +12,111 @@ int current_video_mode = -1; int term_backend = _NOT_READY; -size_t term_rows, term_cols; -bool term_runtime = false; -void (*raw_putchar)(uint8_t c); -void (*clear)(bool move); -void (*enable_cursor)(void); -bool (*disable_cursor)(void); -void (*set_cursor_pos)(size_t x, size_t y); -void (*get_cursor_pos)(size_t *x, size_t *y); -void (*set_text_fg)(size_t fg); -void (*set_text_bg)(size_t bg); -void (*set_text_fg_bright)(size_t fg); -void (*set_text_bg_bright)(size_t bg); -void (*set_text_fg_rgb)(uint32_t fg); -void (*set_text_bg_rgb)(uint32_t bg); -void (*set_text_fg_default)(void); -void (*set_text_bg_default)(void); -bool (*scroll_disable)(void); -void (*scroll_enable)(void); -void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y); -void (*term_scroll)(void); -void (*term_revscroll)(void); -void (*term_swap_palette)(void); -void (*term_save_state)(void); -void (*term_restore_state)(void); +struct term_context *term; -void (*term_double_buffer_flush)(void); +static struct textmode_context term_local_struct; -uint64_t (*term_context_size)(void); -void (*term_context_save)(uint64_t ptr); -void (*term_context_restore)(uint64_t ptr); -void (*term_full_refresh)(void); +// --- notready --- + +static void notready_raw_putchar(struct term_context *ctx, uint8_t c) { + (void)ctx; + (void)c; +} +static void notready_clear(struct term_context *ctx, bool move) { + (void)ctx; + (void)move; +} +static void notready_void(struct term_context *ctx) { + (void)ctx; +} +static void notready_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) { + (void)ctx; + (void)x; (void)y; +} +static void notready_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y) { + (void)ctx; + *x = 0; + *y = 0; +} +static void notready_size_t(struct term_context *ctx, size_t n) { + (void)ctx; + (void)n; +} +static bool notready_disable(struct term_context *ctx) { + (void)ctx; + return false; +} +static void notready_move_character(struct term_context *ctx, size_t a, size_t b, size_t c, size_t d) { + (void)ctx; + (void)a; (void)b; (void)c; (void)d; +} +static void notready_uint32_t(struct term_context *ctx, uint32_t n) { + (void)ctx; + (void)n; +} +static void notready_deinit(struct term_context *ctx, void (*_free)(void *, size_t)) { + (void)ctx; + (void)_free; +} + +void term_notready(void) { + if (term != NULL) { + term->deinit(term, pmm_free); + } + + term = &term_local_struct.term; + + term->raw_putchar = notready_raw_putchar; + term->clear = notready_clear; + term->enable_cursor = notready_void; + term->disable_cursor = notready_disable; + term->set_cursor_pos = notready_set_cursor_pos; + term->get_cursor_pos = notready_get_cursor_pos; + term->set_text_fg = notready_size_t; + term->set_text_bg = notready_size_t; + term->set_text_fg_bright = notready_size_t; + term->set_text_bg_bright = notready_size_t; + term->set_text_fg_rgb = notready_uint32_t; + term->set_text_bg_rgb = notready_uint32_t; + term->set_text_fg_default = notready_void; + term->set_text_bg_default = notready_void; + term->move_character = notready_move_character; + term->scroll = notready_void; + term->revscroll = notready_void; + term->swap_palette = notready_void; + term->save_state = notready_void; + term->restore_state = notready_void; + term->double_buffer_flush = notready_void; + term->full_refresh = notready_void; + term->deinit = notready_deinit; + + term->cols = 80; + term->rows = 24; + + term_backend = _NOT_READY; + term_context_reinit(term); + + term->in_bootloader = true; +} // --- fallback --- #if defined (BIOS) -static void fallback_raw_putchar(uint8_t c) { +static void fallback_raw_putchar(struct term_context *ctx, uint8_t c) { + (void)ctx; struct rm_regs r = {0}; r.eax = 0x0e00 | c; rm_int(0x10, &r, &r); } -static void fallback_set_cursor_pos(size_t x, size_t y); -static void fallback_get_cursor_pos(size_t *x, size_t *y); +static void fallback_set_cursor_pos(struct term_context *ctx, size_t x, size_t y); +static void fallback_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y); -static void fallback_clear(bool move) { +static void fallback_clear(struct term_context *ctx, bool move) { + (void)ctx; size_t x, y; - fallback_get_cursor_pos(&x, &y); + fallback_get_cursor_pos(NULL, &x, &y); struct rm_regs r = {0}; rm_int(0x11, &r, &r); switch ((r.eax >> 4) & 3) { @@ -80,10 +137,11 @@ static void fallback_clear(bool move) { if (move) { x = y = 0; } - fallback_set_cursor_pos(x, y); + fallback_set_cursor_pos(NULL, x, y); } -static void fallback_set_cursor_pos(size_t x, size_t y) { +static void fallback_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) { + (void)ctx; struct rm_regs r = {0}; r.eax = 0x0200; r.ebx = 0; @@ -91,7 +149,8 @@ static void fallback_set_cursor_pos(size_t x, size_t y) { rm_int(0x10, &r, &r); } -static void fallback_get_cursor_pos(size_t *x, size_t *y) { +static void fallback_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y) { + (void)ctx; struct rm_regs r = {0}; r.eax = 0x0300; r.ebx = 0; @@ -100,20 +159,22 @@ static void fallback_get_cursor_pos(size_t *x, size_t *y) { *y = r.edx >> 8; } -static void fallback_scroll(void) { +static void fallback_scroll(struct term_context *ctx) { + (void)ctx; size_t x, y; - fallback_get_cursor_pos(&x, &y); - fallback_set_cursor_pos(term_cols - 1, term_rows - 1); - fallback_raw_putchar(' '); - fallback_set_cursor_pos(x, y); + fallback_get_cursor_pos(NULL, &x, &y); + fallback_set_cursor_pos(NULL, term->cols - 1, term->rows - 1); + fallback_raw_putchar(NULL, ' '); + fallback_set_cursor_pos(NULL, x, y); } #elif defined (UEFI) static size_t cursor_x = 0, cursor_y = 0; -static void fallback_scroll(void) { - gST->ConOut->SetCursorPosition(gST->ConOut, term_cols - 1, term_rows - 1); +static void fallback_scroll(struct term_context *ctx) { + (void)ctx; + gST->ConOut->SetCursorPosition(gST->ConOut, term->cols - 1, term->rows - 1); CHAR16 string[2]; string[0] = ' '; string[1] = 0; @@ -121,21 +182,23 @@ static void fallback_scroll(void) { gST->ConOut->SetCursorPosition(gST->ConOut, cursor_x, cursor_y); } -static void fallback_raw_putchar(uint8_t c) { +static void fallback_raw_putchar(struct term_context *ctx, uint8_t c) { + (void)ctx; CHAR16 string[2]; string[0] = c; string[1] = 0; gST->ConOut->OutputString(gST->ConOut, string); - if (++cursor_x >= term_cols) { + if (++cursor_x >= term->cols) { cursor_x = 0; - if (++cursor_y >= term_rows) { + if (++cursor_y >= term->rows) { cursor_y--; } } gST->ConOut->SetCursorPosition(gST->ConOut, cursor_x, cursor_y); } -static void fallback_clear(bool move) { +static void fallback_clear(struct term_context *ctx, bool move) { + (void)ctx; gST->ConOut->ClearScreen(gST->ConOut); if (move) { cursor_x = cursor_y = 0; @@ -143,8 +206,9 @@ static void fallback_clear(bool move) { gST->ConOut->SetCursorPosition(gST->ConOut, cursor_x, cursor_y); } -static void fallback_set_cursor_pos(size_t x, size_t y) { - if (x >= term_cols || y >= term_rows) { +static void fallback_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) { + (void)ctx; + if (x >= term->cols || y >= term->rows) { return; } gST->ConOut->SetCursorPosition(gST->ConOut, x, y); @@ -152,7 +216,8 @@ static void fallback_set_cursor_pos(size_t x, size_t y) { cursor_y = y; } -static void fallback_get_cursor_pos(size_t *x, size_t *y) { +static void fallback_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y) { + (void)ctx; *x = cursor_x; *y = cursor_y; } @@ -164,156 +229,46 @@ void term_fallback(void) { #if defined (UEFI) if (!efi_boot_services_exited) { #endif - fallback_clear(true); + fallback_clear(NULL, true); #if defined (UEFI) gST->ConOut->EnableCursor(gST->ConOut, false); #endif - raw_putchar = fallback_raw_putchar; - clear = fallback_clear; - set_cursor_pos = fallback_set_cursor_pos; - get_cursor_pos = fallback_get_cursor_pos; - term_scroll = fallback_scroll; + term->raw_putchar = fallback_raw_putchar; + term->clear = fallback_clear; + term->set_cursor_pos = fallback_set_cursor_pos; + term->get_cursor_pos = fallback_get_cursor_pos; + term->scroll = fallback_scroll; #if defined (UEFI) UINTN uefi_term_x_size, uefi_term_y_size; gST->ConOut->QueryMode(gST->ConOut, gST->ConOut->Mode->Mode, &uefi_term_x_size, &uefi_term_y_size); - term_cols = uefi_term_x_size; - term_rows = uefi_term_y_size; + term->cols = uefi_term_x_size; + term->rows = uefi_term_y_size; #elif defined (BIOS) - term_cols = 80; - term_rows = 25; + term->cols = 80; + term->rows = 25; #endif term_backend = FALLBACK; - term_reinit(); + term_context_reinit(term); + + term->in_bootloader = true; #if defined (UEFI) } #endif } -// --- notready --- - -static void notready_raw_putchar(uint8_t c) { - (void)c; -} -static void notready_clear(bool move) { - (void)move; -} -static void notready_void(void) {} -static void notready_set_cursor_pos(size_t x, size_t y) { - (void)x; (void)y; -} -static void notready_get_cursor_pos(size_t *x, size_t *y) { - *x = 0; - *y = 0; -} -static void notready_size_t(size_t n) { - (void)n; -} -static bool notready_disable(void) { - return false; -} -static void notready_move_character(size_t a, size_t b, size_t c, size_t d) { - (void)a; (void)b; (void)c; (void)d; -} -static uint64_t notready_context_size(void) { - return 0; -} -static void notready_uint32_t(uint32_t n) { - (void)n; -} -static void notready_uint64_t(uint64_t n) { - (void)n; -} - -void term_notready(void) { - raw_putchar = notready_raw_putchar; - clear = notready_clear; - enable_cursor = notready_void; - disable_cursor = notready_disable; - set_cursor_pos = notready_set_cursor_pos; - get_cursor_pos = notready_get_cursor_pos; - set_text_fg = notready_size_t; - set_text_bg = notready_size_t; - set_text_fg_bright = notready_size_t; - set_text_bg_bright = notready_size_t; - set_text_fg_rgb = notready_uint32_t; - set_text_bg_rgb = notready_uint32_t; - set_text_fg_default = notready_void; - set_text_bg_default = notready_void; - scroll_disable = notready_disable; - scroll_enable = notready_void; - term_move_character = notready_move_character; - term_scroll = notready_void; - term_revscroll = notready_void; - term_swap_palette = notready_void; - term_save_state = notready_void; - term_restore_state = notready_void; - term_double_buffer_flush = notready_void; - term_context_size = notready_context_size; - term_context_save = notready_uint64_t; - term_context_restore = notready_uint64_t; - term_full_refresh = notready_void; - - term_cols = 80; - term_rows = 24; - - term_backend = _NOT_READY; -} - -static const uint32_t col256[] = { - 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 -}; - extern void reset_term(void); extern void set_cursor_pos_helper(size_t x, size_t y); -void term_deinit(void) { - switch (term_backend) { - case VBE: - gterm_deinit(); - } - - term_notready(); -} - void term_vbe(char *config, size_t width, size_t height) { if (term_backend != VBE) { - term_deinit(); + term->deinit(term, pmm_free); } if (quiet || allocations_disallowed) { return; } - if (!gterm_init(config, &term_rows, &term_cols, width, height)) { + if (!gterm_init(config, width, height)) { #if defined (BIOS) // Failed to set VBE properly, default to text mode term_textmode(); @@ -322,205 +277,82 @@ void term_vbe(char *config, size_t width, size_t height) { } if (serial) { - term_cols = term_cols > 80 ? 80 : term_cols; - term_rows = term_rows > 24 ? 24 : term_rows; + term->cols = term->cols > 80 ? 80 : term->cols; + term->rows = term->rows > 24 ? 24 : term->rows; } - term_reinit(); - - raw_putchar = gterm_putchar; - clear = gterm_clear; - enable_cursor = gterm_enable_cursor; - disable_cursor = gterm_disable_cursor; - set_cursor_pos = gterm_set_cursor_pos; - get_cursor_pos = gterm_get_cursor_pos; - set_text_fg = gterm_set_text_fg; - set_text_bg = gterm_set_text_bg; - set_text_fg_bright = gterm_set_text_fg_bright; - set_text_bg_bright = gterm_set_text_bg_bright; - set_text_fg_rgb = gterm_set_text_fg_rgb; - set_text_bg_rgb = gterm_set_text_bg_rgb; - set_text_fg_default = gterm_set_text_fg_default; - set_text_bg_default = gterm_set_text_bg_default; - scroll_disable = gterm_scroll_disable; - scroll_enable = gterm_scroll_enable; - term_move_character = gterm_move_character; - term_scroll = gterm_scroll; - term_revscroll = gterm_revscroll; - term_swap_palette = gterm_swap_palette; - term_save_state = gterm_save_state; - term_restore_state = gterm_restore_state; - - term_double_buffer_flush = gterm_double_buffer_flush; - - term_context_size = gterm_context_size; - term_context_save = gterm_context_save; - term_context_restore = gterm_context_restore; - term_full_refresh = gterm_full_refresh; - term_backend = VBE; -} -// Tries to implement this standard for terminfo -// https://man7.org/linux/man-pages/man4/console_codes.4.html - -uint64_t term_arg = 0; -void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) = NULL; - -struct term_context term_context; - -#define escape_offset term_context.escape_offset -#define control_sequence term_context.control_sequence -#define csi term_context.csi -#define escape term_context.escape -#define rrr term_context.rrr -#define discard_next term_context.discard_next -#define bold term_context.bold -#define reverse_video term_context.reverse_video -#define dec_private term_context.dec_private -#define esc_values term_context.esc_values -#define esc_values_i term_context.esc_values_i -#define saved_cursor_x term_context.saved_cursor_x -#define saved_cursor_y term_context.saved_cursor_y -#define current_primary term_context.current_primary -#define insert_mode term_context.insert_mode -#define scroll_top_margin term_context.scroll_top_margin -#define scroll_bottom_margin term_context.scroll_bottom_margin -#define current_charset term_context.current_charset -#define charsets term_context.charsets -#define g_select term_context.g_select - -#define saved_state_bold term_context.saved_state_bold -#define saved_state_reverse_video term_context.saved_state_reverse_video -#define saved_state_current_charset term_context.saved_state_current_charset -#define saved_state_current_primary term_context.saved_state_current_primary - -#define CHARSET_DEFAULT 0 -#define CHARSET_DEC_SPECIAL 1 - -void term_reinit(void) { - escape_offset = 0; - control_sequence = false; - csi = false; - escape = false; - rrr = false; - discard_next = false; - bold = false; - reverse_video = false; - dec_private = false; - esc_values_i = 0; - saved_cursor_x = 0; - saved_cursor_y = 0; - current_primary = (size_t)-1; - insert_mode = false; - scroll_top_margin = 0; - scroll_bottom_margin = term_rows; - current_charset = 0; - g_select = 0; - charsets[0] = CHARSET_DEFAULT; - charsets[1] = CHARSET_DEC_SPECIAL; - term_autoflush = true; + term->in_bootloader = true; } #if defined (BIOS) void term_textmode(void) { - term_deinit(); + term_notready(); if (quiet || allocations_disallowed) { return; } - init_vga_textmode(&term_rows, &term_cols, true); + init_vga_textmode(&term->rows, &term->cols, true); if (serial) { - term_cols = term_cols > 80 ? 80 : term_cols; - term_rows = term_rows > 24 ? 24 : term_rows; + term->cols = term->cols > 80 ? 80 : term->cols; + term->rows = term->rows > 24 ? 24 : term->rows; } - term_reinit(); - - raw_putchar = text_putchar; - clear = text_clear; - enable_cursor = text_enable_cursor; - disable_cursor = text_disable_cursor; - set_cursor_pos = text_set_cursor_pos; - get_cursor_pos = text_get_cursor_pos; - set_text_fg = text_set_text_fg; - set_text_bg = text_set_text_bg; - set_text_fg_bright = text_set_text_fg_bright; - set_text_bg_bright = text_set_text_bg_bright; - set_text_fg_default = text_set_text_fg_default; - set_text_bg_default = text_set_text_bg_default; - scroll_disable = text_scroll_disable; - scroll_enable = text_scroll_enable; - term_move_character = text_move_character; - term_scroll = text_scroll; - term_revscroll = text_revscroll; - term_swap_palette = text_swap_palette; - term_save_state = text_save_state; - term_restore_state = text_restore_state; - - term_double_buffer_flush = text_double_buffer_flush; - - term_context_size = text_context_size; - term_context_save = text_context_save; - term_context_restore = text_context_restore; - term_full_refresh = text_full_refresh; + term->raw_putchar = text_putchar; + term->clear = text_clear; + term->enable_cursor = text_enable_cursor; + term->disable_cursor = text_disable_cursor; + term->set_cursor_pos = text_set_cursor_pos; + term->get_cursor_pos = text_get_cursor_pos; + term->set_text_fg = text_set_text_fg; + term->set_text_bg = text_set_text_bg; + term->set_text_fg_bright = text_set_text_fg_bright; + term->set_text_bg_bright = text_set_text_bg_bright; + term->set_text_fg_default = text_set_text_fg_default; + term->set_text_bg_default = text_set_text_bg_default; + term->move_character = text_move_character; + term->scroll = text_scroll; + term->revscroll = text_revscroll; + term->swap_palette = text_swap_palette; + term->save_state = text_save_state; + term->restore_state = text_restore_state; + term->double_buffer_flush = text_double_buffer_flush; + term->full_refresh = text_full_refresh; + //term->deinit = text_deinit; term_backend = TEXTMODE; + term_context_reinit(term); + + term->in_bootloader = true; } #endif -static uint64_t context_size(void) { - uint64_t ret = 0; - - ret += sizeof(struct term_context); - ret += term_context_size(); - - return ret; -} - -static void context_save(uint64_t ptr) { - memcpy32to64(ptr, (uint64_t)(uintptr_t)&term_context, sizeof(struct term_context)); - ptr += sizeof(struct term_context); - - term_context_save(ptr); -} - -static void context_restore(uint64_t ptr) { - memcpy32to64((uint64_t)(uintptr_t)&term_context, ptr, sizeof(struct term_context)); - ptr += sizeof(struct term_context); - - term_context_restore(ptr); -} - #if defined (__i386__) #define TERM_XFER_CHUNK 8192 static uint8_t xfer_buf[TERM_XFER_CHUNK]; #endif -bool term_autoflush = true; - -static void term_putchar(uint8_t c); - -void term_write(uint64_t buf, uint64_t count) { +void _term_write(uint64_t buf, uint64_t count) { switch (count) { case TERM_CTX_SIZE: { - uint64_t ret = context_size(); - memcpy32to64(buf, (uint64_t)(uintptr_t)&ret, sizeof(uint64_t)); + //uint64_t ret = context_size(); + //memcpy32to64(buf, (uint64_t)(uintptr_t)&ret, sizeof(uint64_t)); return; } case TERM_CTX_SAVE: { - context_save(buf); + //context_save(buf); return; } case TERM_CTX_RESTORE: { - context_restore(buf); + //context_restore(buf); return; } case TERM_FULL_REFRESH: { - term_full_refresh(); + term->full_refresh(term); return; } } @@ -532,11 +364,13 @@ void term_write(uint64_t buf, uint64_t count) { #error Unknown architecture #endif - if (!term_runtime || native) { + bool autoflush = term->autoflush; + term->autoflush = false; + + if (term->in_bootloader || native) { const char *s = (const char *)(uintptr_t)buf; - for (size_t i = 0; i < count; i++) - term_putchar(s[i]); + term_write(term, s, count); } else { #if defined (__i386__) while (count != 0) { @@ -549,8 +383,7 @@ void term_write(uint64_t buf, uint64_t count) { memcpy32to64((uint64_t)(uintptr_t)xfer_buf, buf, chunk); - for (size_t i = 0; i < chunk; i++) - term_putchar(xfer_buf[i]); + term_write(term, (const char *)xfer_buf, chunk); count -= chunk; buf += chunk; @@ -558,825 +391,9 @@ void term_write(uint64_t buf, uint64_t count) { #endif } - if (term_autoflush) { - term_double_buffer_flush(); + if (autoflush) { + term->double_buffer_flush(term); } -} - -static void sgr(void) { - size_t i = 0; - - if (!esc_values_i) - goto def; - - for (; i < esc_values_i; i++) { - size_t offset; - - if (esc_values[i] == 0) { -def: - if (reverse_video) { - reverse_video = false; - term_swap_palette(); - } - bold = false; - current_primary = (size_t)-1; - set_text_bg_default(); - set_text_fg_default(); - continue; - } - - else if (esc_values[i] == 1) { - bold = true; - if (current_primary != (size_t)-1) { - if (!reverse_video) { - set_text_fg_bright(current_primary); - } else { - set_text_bg_bright(current_primary); - } - } - continue; - } - - else if (esc_values[i] == 22) { - bold = false; - if (current_primary != (size_t)-1) { - if (!reverse_video) { - set_text_fg(current_primary); - } else { - set_text_bg(current_primary); - } - } - continue; - } - - else if (esc_values[i] >= 30 && esc_values[i] <= 37) { - offset = 30; - current_primary = esc_values[i] - offset; - - if (reverse_video) { - goto set_bg; - } - -set_fg: - if (bold && !reverse_video) { - set_text_fg_bright(esc_values[i] - offset); - } else { - set_text_fg(esc_values[i] - offset); - } - continue; - } - - else if (esc_values[i] >= 40 && esc_values[i] <= 47) { - offset = 40; - if (reverse_video) { - goto set_fg; - } - -set_bg: - if (bold && reverse_video) { - set_text_bg_bright(esc_values[i] - offset); - } else { - set_text_bg(esc_values[i] - offset); - } - continue; - } - - else if (esc_values[i] >= 90 && esc_values[i] <= 97) { - offset = 90; - current_primary = esc_values[i] - offset; - - if (reverse_video) { - goto set_bg_bright; - } - -set_fg_bright: - set_text_fg_bright(esc_values[i] - offset); - continue; - } - - else if (esc_values[i] >= 100 && esc_values[i] <= 107) { - offset = 100; - if (reverse_video) { - goto set_fg_bright; - } - -set_bg_bright: - set_text_bg_bright(esc_values[i] - offset); - continue; - } - - else if (esc_values[i] == 39) { - current_primary = (size_t)-1; - - if (reverse_video) { - term_swap_palette(); - } - - set_text_fg_default(); - - if (reverse_video) { - term_swap_palette(); - } - - continue; - } - - else if (esc_values[i] == 49) { - if (reverse_video) { - term_swap_palette(); - } - - set_text_bg_default(); - - if (reverse_video) { - term_swap_palette(); - } - - continue; - } - - else if (esc_values[i] == 7) { - if (!reverse_video) { - reverse_video = true; - term_swap_palette(); - } - continue; - } - - else if (esc_values[i] == 27) { - if (reverse_video) { - reverse_video = false; - term_swap_palette(); - } - continue; - } - - // 256/RGB - else if (esc_values[i] == 38 || esc_values[i] == 48) { - bool fg = esc_values[i] == 38; - - i++; - if (i >= esc_values_i) { - break; - } - - switch (esc_values[i]) { - case 2: { // RGB - if (i + 3 >= esc_values_i) { - goto out; - } - - uint32_t rgb_value = 0; - - rgb_value |= esc_values[i + 1] << 16; - rgb_value |= esc_values[i + 2] << 8; - rgb_value |= esc_values[i + 3]; - - i += 3; - - fg ? set_text_fg_rgb(rgb_value) : set_text_bg_rgb(rgb_value); - - break; - } - case 5: { // 256 colors - if (i + 1 >= esc_values_i) { - goto out; - } - - uint32_t col = esc_values[i + 1]; - - i++; - - if (col < 8) { - fg ? set_text_fg(col) : set_text_bg(col); - } else if (col < 16) { - fg ? set_text_fg_bright(col - 8) : set_text_bg_bright(col - 8); - } else { - uint32_t rgb_value = col256[col - 16]; - fg ? set_text_fg_rgb(rgb_value) : set_text_bg_rgb(rgb_value); - } - - break; - } - default: continue; - } - } - } - -out:; -} - -static void dec_private_parse(uint8_t c) { - dec_private = false; - - if (esc_values_i == 0) { - return; - } - - bool set; - - switch (c) { - case 'h': - set = true; break; - case 'l': - set = false; break; - default: - return; - } - - switch (esc_values[0]) { - case 25: { - if (set) { - enable_cursor(); - } else { - disable_cursor(); - } - return; - } - } - - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_DEC, esc_values_i, (uintptr_t)esc_values, c); - } else { - term_callback(TERM_CB_DEC, esc_values_i, (uintptr_t)esc_values, c, 0); - } - } -} - -static void linux_private_parse(void) { - if (esc_values_i == 0) { - return; - } - - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_LINUX, esc_values_i, (uintptr_t)esc_values, 0); - } else { - term_callback(TERM_CB_LINUX, esc_values_i, (uintptr_t)esc_values, 0, 0); - } - } -} - -static void mode_toggle(uint8_t c) { - if (esc_values_i == 0) { - return; - } - - bool set; - - switch (c) { - case 'h': - set = true; break; - case 'l': - set = false; break; - default: - return; - } - - switch (esc_values[0]) { - case 4: - insert_mode = set; return; - } - - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_MODE, esc_values_i, (uintptr_t)esc_values, c); - } else { - term_callback(TERM_CB_MODE, esc_values_i, (uintptr_t)esc_values, c, 0); - } - } -} - -static void control_sequence_parse(uint8_t c) { - if (escape_offset == 2) { - switch (c) { - case '[': - discard_next = true; - goto cleanup; - case '?': - dec_private = true; - return; - } - } - - if (c >= '0' && c <= '9') { - if (esc_values_i == MAX_ESC_VALUES) { - return; - } - rrr = true; - esc_values[esc_values_i] *= 10; - esc_values[esc_values_i] += c - '0'; - return; - } - - if (rrr == true) { - esc_values_i++; - rrr = false; - if (c == ';') - return; - } else if (c == ';') { - if (esc_values_i == MAX_ESC_VALUES) { - return; - } - esc_values[esc_values_i] = 0; - esc_values_i++; - return; - } - - size_t esc_default; - switch (c) { - case 'J': case 'K': case 'q': - esc_default = 0; break; - default: - esc_default = 1; break; - } - - for (size_t i = esc_values_i; i < MAX_ESC_VALUES; i++) { - esc_values[i] = esc_default; - } - - if (dec_private == true) { - dec_private_parse(c); - goto cleanup; - } - - bool r = scroll_disable(); - size_t x, y; - get_cursor_pos(&x, &y); - - switch (c) { - case 'F': - x = 0; - // FALLTHRU - case 'A': { - if (esc_values[0] > y) - esc_values[0] = y; - size_t orig_y = y; - size_t dest_y = y - esc_values[0]; - bool will_be_in_scroll_region = false; - if ((scroll_top_margin >= dest_y && scroll_top_margin <= orig_y) - || (scroll_bottom_margin >= dest_y && scroll_bottom_margin <= orig_y)) { - will_be_in_scroll_region = true; - } - if (will_be_in_scroll_region && dest_y < scroll_top_margin) { - dest_y = scroll_top_margin; - } - set_cursor_pos(x, dest_y); - break; - } - case 'E': - x = 0; - // FALLTHRU - case 'e': - case 'B': { - if (y + esc_values[0] > term_rows - 1) - esc_values[0] = (term_rows - 1) - y; - size_t orig_y = y; - size_t dest_y = y + esc_values[0]; - bool will_be_in_scroll_region = false; - if ((scroll_top_margin >= orig_y && scroll_top_margin <= dest_y) - || (scroll_bottom_margin >= orig_y && scroll_bottom_margin <= dest_y)) { - will_be_in_scroll_region = true; - } - if (will_be_in_scroll_region && dest_y >= scroll_bottom_margin) { - dest_y = scroll_bottom_margin - 1; - } - set_cursor_pos(x, dest_y); - break; - } - case 'a': - case 'C': - if (x + esc_values[0] > term_cols - 1) - esc_values[0] = (term_cols - 1) - x; - set_cursor_pos(x + esc_values[0], y); - break; - case 'D': - if (esc_values[0] > x) - esc_values[0] = x; - set_cursor_pos(x - esc_values[0], y); - break; - case 'c': - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_PRIVATE_ID, 0, 0, 0); - } else { - term_callback(TERM_CB_PRIVATE_ID, 0, 0, 0, 0); - } - } - break; - case 'd': - esc_values[0] -= 1; - if (esc_values[0] >= term_rows) - esc_values[0] = term_rows - 1; - set_cursor_pos(x, esc_values[0]); - break; - case 'G': - case '`': - esc_values[0] -= 1; - if (esc_values[0] >= term_cols) - esc_values[0] = term_cols - 1; - set_cursor_pos(esc_values[0], y); - break; - case 'H': - case 'f': - esc_values[0] -= 1; - esc_values[1] -= 1; - if (esc_values[1] >= term_cols) - esc_values[1] = term_cols - 1; - if (esc_values[0] >= term_rows) - esc_values[0] = term_rows - 1; - set_cursor_pos(esc_values[1], esc_values[0]); - break; - case 'n': - switch (esc_values[0]) { - case 5: - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_STATUS_REPORT, 0, 0, 0); - } else { - term_callback(TERM_CB_STATUS_REPORT, 0, 0, 0, 0); - } - } - break; - case 6: - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_POS_REPORT, x + 1, y + 1, 0); - } else { - term_callback(TERM_CB_POS_REPORT, x + 1, y + 1, 0, 0); - } - } - break; - } - break; - case 'q': - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_KBD_LEDS, esc_values[0], 0, 0); - } else { - term_callback(TERM_CB_KBD_LEDS, esc_values[0], 0, 0, 0); - } - } - break; - case 'J': - switch (esc_values[0]) { - case 0: { - size_t rows_remaining = term_rows - (y + 1); - size_t cols_diff = term_cols - (x + 1); - size_t to_clear = rows_remaining * term_cols + cols_diff; - for (size_t i = 0; i < to_clear; i++) { - raw_putchar(' '); - } - set_cursor_pos(x, y); - break; - } - case 1: { - set_cursor_pos(0, 0); - bool b = false; - for (size_t yc = 0; yc < term_rows; yc++) { - for (size_t xc = 0; xc < term_cols; xc++) { - raw_putchar(' '); - if (xc == x && yc == y) { - set_cursor_pos(x, y); - b = true; - break; - } - } - if (b == true) - break; - } - break; - } - case 2: - case 3: - clear(false); - break; - } - break; - case '@': - for (size_t i = term_cols - 1; ; i--) { - term_move_character(i + esc_values[0], y, i, y); - set_cursor_pos(i, y); - raw_putchar(' '); - if (i == x) { - break; - } - } - set_cursor_pos(x, y); - break; - case 'P': - for (size_t i = x + esc_values[0]; i < term_cols; i++) - term_move_character(i - esc_values[0], y, i, y); - set_cursor_pos(term_cols - esc_values[0], y); - // FALLTHRU - case 'X': - for (size_t i = 0; i < esc_values[0]; i++) - raw_putchar(' '); - set_cursor_pos(x, y); - break; - case 'm': - sgr(); - break; - case 's': - get_cursor_pos(&saved_cursor_x, &saved_cursor_y); - break; - case 'u': - set_cursor_pos(saved_cursor_x, saved_cursor_y); - break; - case 'K': - switch (esc_values[0]) { - case 0: { - for (size_t i = x; i < term_cols; i++) - raw_putchar(' '); - set_cursor_pos(x, y); - break; - } - case 1: { - set_cursor_pos(0, y); - for (size_t i = 0; i < x; i++) - raw_putchar(' '); - break; - } - case 2: { - set_cursor_pos(0, y); - for (size_t i = 0; i < term_cols; i++) - raw_putchar(' '); - set_cursor_pos(x, y); - break; - } - } - break; - case 'r': - scroll_top_margin = 0; - scroll_bottom_margin = term_rows; - if (esc_values_i > 0) { - scroll_top_margin = esc_values[0] - 1; - } - if (esc_values_i > 1) { - scroll_bottom_margin = esc_values[1]; - } - if (scroll_top_margin >= term_rows - || scroll_bottom_margin > term_rows - || scroll_top_margin >= (scroll_bottom_margin - 1)) { - scroll_top_margin = 0; - scroll_bottom_margin = term_rows; - } - set_cursor_pos(0, 0); - break; - case 'l': - case 'h': - mode_toggle(c); - break; - case ']': - linux_private_parse(); - break; - } - - if (r) - scroll_enable(); - -cleanup: - control_sequence = false; - escape = false; -} - -static void restore_state(void) { - bold = saved_state_bold; - reverse_video = saved_state_reverse_video; - current_charset = saved_state_current_charset; - current_primary = saved_state_current_primary; - - term_restore_state(); -} - -static void save_state(void) { - term_save_state(); - - saved_state_bold = bold; - saved_state_reverse_video = reverse_video; - saved_state_current_charset = current_charset; - saved_state_current_primary = current_primary; -} - -static void escape_parse(uint8_t c) { - escape_offset++; - - if (control_sequence == true) { - control_sequence_parse(c); - return; - } - - if (csi == true) { - csi = false; - goto is_csi; - } - - size_t x, y; - get_cursor_pos(&x, &y); - - switch (c) { - case '[': -is_csi: - for (size_t i = 0; i < MAX_ESC_VALUES; i++) - esc_values[i] = 0; - esc_values_i = 0; - rrr = false; - control_sequence = true; - return; - case '7': - save_state(); - break; - case '8': - restore_state(); - break; - case 'c': - term_reinit(); - clear(true); - break; - case 'D': - if (y == scroll_bottom_margin - 1) { - term_scroll(); - set_cursor_pos(x, y); - } else { - set_cursor_pos(x, y + 1); - } - break; - case 'E': - if (y == scroll_bottom_margin - 1) { - term_scroll(); - set_cursor_pos(0, y); - } else { - set_cursor_pos(0, y + 1); - } - break; - case 'M': - // "Reverse linefeed" - if (y == scroll_top_margin) { - term_revscroll(); - set_cursor_pos(0, y); - } else { - set_cursor_pos(0, y - 1); - } - break; - case 'Z': - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_PRIVATE_ID, 0, 0, 0); - } else { - term_callback(TERM_CB_PRIVATE_ID, 0, 0, 0, 0); - } - } - break; - case '(': - case ')': - g_select = c - '\''; - break; - case '\e': - if (term_runtime == false) { - raw_putchar(c); - } - break; - } - - escape = false; -} - -static uint8_t dec_special_to_cp437(uint8_t c) { - switch (c) { - case '`': return 0x04; - case '0': return 0xdb; - case '-': return 0x18; - case ',': return 0x1b; - case '.': return 0x19; - case 'a': return 0xb1; - case 'f': return 0xf8; - case 'g': return 0xf1; - case 'h': return 0xb0; - case 'j': return 0xd9; - case 'k': return 0xbf; - case 'l': return 0xda; - case 'm': return 0xc0; - case 'n': return 0xc5; - case 'q': return 0xc4; - case 's': return 0x5f; - case 't': return 0xc3; - case 'u': return 0xb4; - case 'v': return 0xc1; - case 'w': return 0xc2; - case 'x': return 0xb3; - case 'y': return 0xf3; - case 'z': return 0xf2; - case '~': return 0xfa; - case '_': return 0xff; - case '+': return 0x1a; - case '{': return 0xe3; - case '}': return 0x9c; - } - - return c; -} - -static void term_putchar(uint8_t c) { - if (discard_next || (term_runtime == true && (c == 0x18 || c == 0x1a))) { - discard_next = false; - escape = false; - csi = false; - control_sequence = false; - g_select = 0; - return; - } - - if (escape == true) { - escape_parse(c); - return; - } - - if (g_select) { - g_select--; - switch (c) { - case 'B': - charsets[g_select] = CHARSET_DEFAULT; break; - case '0': - charsets[g_select] = CHARSET_DEC_SPECIAL; break; - } - g_select = 0; - return; - } - - size_t x, y; - get_cursor_pos(&x, &y); - - switch (c) { - case 0x00: - case 0x7f: - return; - case 0x9b: - csi = true; - // FALLTHRU - case '\e': - escape_offset = 0; - escape = true; - return; - case '\t': - if ((x / TERM_TABSIZE + 1) >= term_cols) { - set_cursor_pos(term_cols - 1, y); - return; - } - set_cursor_pos((x / TERM_TABSIZE + 1) * TERM_TABSIZE, y); - return; - case 0x0b: - case 0x0c: - case '\n': - if (y == scroll_bottom_margin - 1) { - term_scroll(); - set_cursor_pos(0, y); - } else { - set_cursor_pos(0, y + 1); - } - return; - case '\b': - set_cursor_pos(x - 1, y); - return; - case '\r': - set_cursor_pos(0, y); - return; - case '\a': - // The bell is handled by the kernel - if (term_callback != NULL) { - if (term_arg != 0) { - term_callback(term_arg, TERM_CB_BELL, 0, 0, 0); - } else { - term_callback(TERM_CB_BELL, 0, 0, 0, 0); - } - } - return; - case 14: - // Move to G1 set - current_charset = 1; - return; - case 15: - // Move to G0 set - current_charset = 0; - return; - } - - if (insert_mode == true) { - for (size_t i = term_cols - 1; ; i--) { - term_move_character(i + 1, y, i, y); - if (i == x) { - break; - } - } - } - - // Translate character set - switch (charsets[current_charset]) { - case CHARSET_DEFAULT: - break; - case CHARSET_DEC_SPECIAL: - c = dec_special_to_cp437(c); - } - - raw_putchar(c); + + term->autoflush = autoflush; } diff --git a/common/lib/term.h b/common/lib/term.h index 82ff658d..f7fdbf11 100644 --- a/common/lib/term.h +++ b/common/lib/term.h @@ -6,37 +6,7 @@ #include #include #include - -#define TERM_TABSIZE (8) -#define MAX_ESC_VALUES (16) - -extern struct term_context { - bool control_sequence; - bool csi; - bool escape; - bool rrr; - bool discard_next; - bool bold; - bool reverse_video; - bool dec_private; - bool insert_mode; - uint8_t g_select; - uint8_t charsets[2]; - size_t current_charset; - size_t escape_offset; - size_t esc_values_i; - size_t saved_cursor_x; - size_t saved_cursor_y; - size_t current_primary; - size_t scroll_top_margin; - size_t scroll_bottom_margin; - uint32_t esc_values[MAX_ESC_VALUES]; - - bool saved_state_bold; - bool saved_state_reverse_video; - size_t saved_state_current_charset; - size_t saved_state_current_primary; -} term_context; +#include enum { _NOT_READY, @@ -47,76 +17,29 @@ enum { extern int current_video_mode; extern int term_backend; -extern size_t term_rows, term_cols; -extern bool term_runtime; -void term_notready(void); -void term_fallback(void); - -void term_reinit(void); -void term_deinit(void); -void term_vbe(char *config, size_t width, size_t height); -void term_textmode(void); -void term_write(uint64_t buf, uint64_t count); - -extern void (*raw_putchar)(uint8_t c); -extern void (*clear)(bool move); -extern void (*enable_cursor)(void); -extern bool (*disable_cursor)(void); -extern void (*set_cursor_pos)(size_t x, size_t y); -extern void (*get_cursor_pos)(size_t *x, size_t *y); -extern void (*set_text_fg)(size_t fg); -extern void (*set_text_bg)(size_t bg); -extern void (*set_text_fg_bright)(size_t fg); -extern void (*set_text_bg_bright)(size_t bg); -extern void (*set_text_fg_rgb)(uint32_t fg); -extern void (*set_text_bg_rgb)(uint32_t bg); -extern void (*set_text_fg_default)(void); -extern void (*set_text_bg_default)(void); -extern bool (*scroll_disable)(void); -extern void (*scroll_enable)(void); -extern void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y); -extern void (*term_scroll)(void); -extern void (*term_revscroll)(void); -extern void (*term_swap_palette)(void); -extern void (*term_save_state)(void); -extern void (*term_restore_state)(void); - -extern void (*term_double_buffer_flush)(void); - -extern uint64_t (*term_context_size)(void); -extern void (*term_context_save)(uint64_t ptr); -extern void (*term_context_restore)(uint64_t ptr); -extern void (*term_full_refresh)(void); - -#define TERM_CB_DEC 10 -#define TERM_CB_BELL 20 -#define TERM_CB_PRIVATE_ID 30 -#define TERM_CB_STATUS_REPORT 40 -#define TERM_CB_POS_REPORT 50 -#define TERM_CB_KBD_LEDS 60 -#define TERM_CB_MODE 70 -#define TERM_CB_LINUX 80 +extern struct term_context *term; #define TERM_CTX_SIZE ((uint64_t)(-1)) #define TERM_CTX_SAVE ((uint64_t)(-2)) #define TERM_CTX_RESTORE ((uint64_t)(-3)) #define TERM_FULL_REFRESH ((uint64_t)(-4)) -extern uint64_t term_arg; -extern void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); - -extern bool term_autoflush; - inline void reset_term(void) { - term_autoflush = true; - enable_cursor(); + term->autoflush = true; + term->enable_cursor(term); print("\e[2J\e[H"); - term_double_buffer_flush(); + term->double_buffer_flush(term); } inline void set_cursor_pos_helper(size_t x, size_t y) { print("\e[%u;%uH", (int)y + 1, (int)x + 1); } +void term_fallback(void); +void term_vbe(char *config, size_t width, size_t height); +void term_textmode(void); + +void _term_write(uint64_t buf, uint64_t count); + #endif diff --git a/common/linker_bios.ld.in b/common/linker_bios.ld.in index 74562944..3e0132b4 100644 --- a/common/linker_bios.ld.in +++ b/common/linker_bios.ld.in @@ -43,6 +43,7 @@ SECTIONS term_write = .; term_backend = .; term_fallback = .; + term = .; stage3_addr = .; #else #ifdef LINKER_NOS2MAP diff --git a/common/menu.c b/common/menu.c index e56e8bed..34b8cb81 100644 --- a/common/menu.c +++ b/common/menu.c @@ -154,17 +154,17 @@ static void putchar_tokencol(int type, char c) { static bool editor_no_term_reset = false; char *config_entry_editor(const char *title, const char *orig_entry) { - term_autoflush = false; + term->autoflush = false; - enable_cursor(); + term->enable_cursor(term); print("\e[2J\e[H"); size_t cursor_offset = 0; size_t entry_size = strlen(orig_entry); - size_t _window_size = term_rows - 8; + size_t _window_size = term->rows - 8; size_t window_offset = 0; - size_t line_size = term_cols - 2; + size_t line_size = term->cols - 2; bool display_overflow_error = false; @@ -200,12 +200,12 @@ refresh: invalid_syntax = false; print("\e[2J\e[H"); - disable_cursor(); + term->disable_cursor(term); { size_t x, y; print("\n"); - get_cursor_pos(&x, &y); - set_cursor_pos_helper(term_cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); + term->get_cursor_pos(term, &x, &y); + set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); print("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding); print("\n\n"); } @@ -213,7 +213,7 @@ refresh: print(" \e[32mESC\e[0m Discard and Exit \e[32mF10\e[0m Boot\n\n"); print(serial ? "/" : "\xda"); - for (size_t i = 0; i < term_cols - 2; i++) { + for (size_t i = 0; i < term->cols - 2; i++) { switch (i) { case 1: case 2: case 3: if (window_offset > 0) { @@ -223,7 +223,7 @@ refresh: // FALLTHRU default: { size_t title_length = strlen(title); - if (i == (term_cols / 2) - DIV_ROUNDUP(title_length, 2) - 1) { + if (i == (term->cols / 2) - DIV_ROUNDUP(title_length, 2) - 1) { print("%s", title); i += title_length - 1; } else { @@ -234,7 +234,7 @@ refresh: } size_t tmpx, tmpy; - get_cursor_pos(&tmpx, &tmpy); + term->get_cursor_pos(term, &tmpx, &tmpy); print(serial ? "\\" : "\xbf"); set_cursor_pos_helper(0, tmpy + 1); print(serial ? "|" : "\xb3"); @@ -250,20 +250,20 @@ refresh: && current_line < window_offset + window_size && current_line >= window_offset) { size_t x, y; - get_cursor_pos(&x, &y); + term->get_cursor_pos(term, &x, &y); if (i == cursor_offset) { cursor_x = x; cursor_y = y; printed_cursor = true; } - set_cursor_pos_helper(term_cols - 1, y); + set_cursor_pos_helper(term->cols - 1, y); if (current_line == window_offset + window_size - 1) { - get_cursor_pos(&tmpx, &tmpy); + term->get_cursor_pos(term, &tmpx, &tmpy); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, tmpy + 1); print(serial ? "\\" : "\xc0"); } else { - get_cursor_pos(&tmpx, &tmpy); + term->get_cursor_pos(term, &tmpx, &tmpy); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, tmpy + 1); print(serial ? "|" : "\xb3"); @@ -281,7 +281,7 @@ refresh: if (current_line < window_offset + window_size && current_line >= window_offset) { if (i == cursor_offset) { - get_cursor_pos(&cursor_x, &cursor_y); + term->get_cursor_pos(term, &cursor_x, &cursor_y); printed_cursor = true; } if (syntax_highlighting_enabled) { @@ -291,8 +291,8 @@ refresh: } printed_early = true; size_t x, y; - get_cursor_pos(&x, &y); - if (y == term_rows - 3) { + term->get_cursor_pos(term, &x, &y); + if (y == term->rows - 3) { print(serial ? ">" : "\x1a"); set_cursor_pos_helper(0, y + 1); print(serial ? "\\" : "\xc0"); @@ -309,7 +309,7 @@ refresh: && current_line < window_offset + window_size && current_line >= window_offset && !printed_cursor) { - get_cursor_pos(&cursor_x, &cursor_y); + term->get_cursor_pos(term, &cursor_x, &cursor_y); printed_cursor = true; } @@ -356,35 +356,35 @@ refresh: // syntax error alert if (validation_enabled) { size_t x, y; - get_cursor_pos(&x, &y); - set_cursor_pos_helper(0, term_rows-1); - scroll_disable(); + term->get_cursor_pos(term, &x, &y); + set_cursor_pos_helper(0, term->rows - 1); + term->scroll_enabled = false; if (invalid_syntax) { print("\e[31mConfiguration is INVALID.\e[0m"); } else { print("\e[32mConfiguration is valid.\e[0m"); } - scroll_enable(); + term->scroll_enabled = true; set_cursor_pos_helper(x, y); } if (current_line - window_offset < window_size) { size_t x, y; for (size_t i = 0; i < (window_size - (current_line - window_offset)) - 1; i++) { - get_cursor_pos(&x, &y); - set_cursor_pos_helper(term_cols - 1, y); + term->get_cursor_pos(term, &x, &y); + set_cursor_pos_helper(term->cols - 1, y); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, y + 1); print(serial ? "|" : "\xb3"); } - get_cursor_pos(&x, &y); - set_cursor_pos_helper(term_cols - 1, y); + term->get_cursor_pos(term, &x, &y); + set_cursor_pos_helper(term->cols - 1, y); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, y + 1); print(serial ? "\\" : "\xc0"); } - for (size_t i = 0; i < term_cols - 2; i++) { + for (size_t i = 0; i < term->cols - 2; i++) { switch (i) { case 1: case 2: case 3: if (current_line - window_offset >= window_size) { @@ -396,22 +396,22 @@ refresh: print(serial ? "-" : "\xc4"); } } - get_cursor_pos(&tmpx, &tmpy); + term->get_cursor_pos(term, &tmpx, &tmpy); print(serial ? "/" : "\xd9"); set_cursor_pos_helper(0, tmpy + 1); if (display_overflow_error) { - scroll_disable(); + term->scroll_enabled = false; print("\e[31mText buffer not big enough, delete something instead."); - scroll_enable(); + term->scroll_enabled = true; display_overflow_error = false; } // Hack to redraw the cursor set_cursor_pos_helper(cursor_x, cursor_y); - enable_cursor(); + term->enable_cursor(term); - term_double_buffer_flush(); + term->double_buffer_flush(term); int c = getchar(); size_t buffer_len = strlen(buffer); @@ -692,16 +692,16 @@ noreturn void _menu(bool first_run) { menu_init_term(); refresh: - term_autoflush = false; + term->autoflush = false; - disable_cursor(); + term->disable_cursor(term); print("\e[2J\e[H"); { size_t x, y; print("\n"); - get_cursor_pos(&x, &y); - set_cursor_pos_helper(term_cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); + term->get_cursor_pos(term, &x, &y); + set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); print("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding); print("\n\n\n\n"); } @@ -710,14 +710,14 @@ refresh: if (quiet) { quiet = false; menu_init_term(); - term_autoflush = false; - disable_cursor(); + term->autoflush = false; + term->disable_cursor(term); } print("Config file %s.\n\n", config_ready ? "contains no valid entries" : "not found"); print("For information on the format of Limine config entries, consult CONFIG.md in\n"); print("the root of the Limine source repository.\n\n"); print("Press a key to enter the Limine console..."); - term_double_buffer_flush(); + term->double_buffer_flush(term); getchar(); reset_term(); console(); @@ -725,24 +725,24 @@ refresh: { // Draw box around boot menu size_t x, y; - get_cursor_pos(&x, &y); + term->get_cursor_pos(term, &x, &y); print(serial ? "/" : "\xda"); - for (size_t i = 0; i < term_cols - 2; i++) { + for (size_t i = 0; i < term->cols - 2; i++) { print(serial ? "-" : "\xc4"); } print(serial ? "\\" : "\xbf"); - for (size_t i = y + 1; i < term_rows - 2; i++) { + for (size_t i = y + 1; i < term->rows - 2; i++) { set_cursor_pos_helper(0, i); print(serial ? "|" : "\xb3"); - set_cursor_pos_helper(term_cols - 1, i); + set_cursor_pos_helper(term->cols - 1, i); print(serial ? "|" : "\xb3"); } - set_cursor_pos_helper(0, term_rows - 2); + set_cursor_pos_helper(0, term->rows - 2); print(serial ? "\\" : "\xc0"); - for (size_t i = 0; i < term_cols - 2; i++) { + for (size_t i = 0; i < term->cols - 2; i++) { print(serial ? "-" : "\xc4"); } print(serial ? "/" : "\xd9"); @@ -755,7 +755,7 @@ refresh: { size_t x, y; - get_cursor_pos(&x, &y); + term->get_cursor_pos(term, &x, &y); set_cursor_pos_helper(0, 3); if (editor_enabled && selected_menu_entry->sub == NULL) { print(" \e[32mARROWS\e[0m Select \e[32mENTER\e[0m Boot \e[32mE\e[0m Edit"); @@ -763,7 +763,7 @@ refresh: print(" \e[32mARROWS\e[0m Select \e[32mENTER\e[0m %s", selected_menu_entry->expanded ? "Collapse" : "Expand"); } - set_cursor_pos_helper(term_cols - 13, 3); + set_cursor_pos_helper(term->cols - 13, 3); print("\e[32mC\e[0m Console"); set_cursor_pos_helper(x, y); } @@ -776,11 +776,11 @@ refresh: if (skip_timeout == false) { print("\n\n"); for (size_t i = timeout; i; i--) { - set_cursor_pos_helper(0, term_rows - 1); - scroll_disable(); + set_cursor_pos_helper(0, term->rows - 1); + term->scroll_enabled = false; print("\e[2K\e[32mBooting automatically in \e[92m%u\e[32m, press any key to stop the countdown...\e[0m", i); - scroll_enable(); - term_double_buffer_flush(); + term->scroll_enabled = true; + term->double_buffer_flush(term); if ((c = pit_sleep_and_quit_on_keypress(1))) { skip_timeout = true; if (quiet) { @@ -789,21 +789,21 @@ refresh: goto timeout_aborted; } print("\e[2K"); - term_double_buffer_flush(); + term->double_buffer_flush(term); goto timeout_aborted; } } goto autoboot; } - set_cursor_pos_helper(0, term_rows - 1); + set_cursor_pos_helper(0, term->rows - 1); if (selected_menu_entry->comment != NULL) { - scroll_disable(); + term->scroll_enabled = false; print("\e[36m%s\e[0m", selected_menu_entry->comment); - scroll_enable(); + term->scroll_enabled = true; } - term_double_buffer_flush(); + term->double_buffer_flush(term); for (;;) { c = getchar(); diff --git a/common/protos/chainload.c b/common/protos/chainload.c index 80c57877..b2f0b716 100644 --- a/common/protos/chainload.c +++ b/common/protos/chainload.c @@ -217,7 +217,7 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) { pmm_free(_ptr, image->size); fclose(image); - term_deinit(); + term->deinit(term, pmm_free); size_t req_width = 0, req_height = 0, req_bpp = 0; diff --git a/common/protos/limine.c b/common/protos/limine.c index 2fd834cb..76c277b8 100644 --- a/common/protos/limine.c +++ b/common/protos/limine.c @@ -269,7 +269,7 @@ void limine_term_callback(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); static void term_write_shim(uint64_t context, uint64_t buf, uint64_t count) { (void)context; - term_write(buf, count); + _term_write(buf, count); } noreturn void limine_load(char *config, char *cmdline) { @@ -697,17 +697,15 @@ FEAT_START if (terminal_request->callback != 0) { #if defined (__i386__) - term_callback = limine_term_callback; + term->callback = (void *)limine_term_callback; limine_term_callback_ptr = terminal_request->callback; #elif defined (__x86_64__) || defined (__aarch64__) - term_callback = (void *)terminal_request->callback; + term->callback = (void *)terminal_request->callback; #else #error Unknown architecture #endif } - term_arg = reported_addr(terminal); - #if defined (__i386__) if (limine_rt_stack == NULL) { limine_rt_stack = ext_mem_alloc(16384) + 16384; @@ -723,8 +721,8 @@ FEAT_START term_fb_ptr = &terminal->framebuffer; - terminal->columns = term_cols; - terminal->rows = term_rows; + terminal->columns = term->cols; + terminal->rows = term->rows; uint64_t *term_list = ext_mem_alloc(1 * sizeof(uint64_t)); term_list[0] = reported_addr(terminal); @@ -737,7 +735,7 @@ FEAT_START goto skip_fb_init; FEAT_END - term_deinit(); + term->deinit(term, pmm_free); if (!fb_init(&fb, req_width, req_height, req_bpp)) { panic(true, "limine: Could not acquire framebuffer"); @@ -995,9 +993,9 @@ FEAT_START FEAT_END // Clear terminal for kernels that will use the Limine terminal - term_write((uint64_t)(uintptr_t)("\e[2J\e[H"), 7); + term_write(term, "\e[2J\e[H", 7); - term_runtime = true; + term->in_bootloader = false; #if defined (__x86_64__) || defined (__i386__) #if defined (BIOS) diff --git a/common/protos/linux.c b/common/protos/linux.c index f2a55d3c..8ff5c187 100644 --- a/common/protos/linux.c +++ b/common/protos/linux.c @@ -495,7 +495,7 @@ noreturn void linux_load(char *config, char *cmdline) { // Video /////////////////////////////////////// - term_deinit(); + term->deinit(term, pmm_free); struct screen_info *screen_info = &boot_params->screen_info; diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c index 16b86acc..0161f77e 100644 --- a/common/protos/multiboot1.c +++ b/common/protos/multiboot1.c @@ -302,7 +302,7 @@ noreturn void multiboot1_load(char *config, char *cmdline) { multiboot1_info->bootloader_name = (uint32_t)(size_t)lowmem_bootname - mb1_info_slide; multiboot1_info->flags |= (1 << 9); - term_deinit(); + term->deinit(term, pmm_free); if (header.flags & (1 << 2)) { size_t req_width = header.fb_width; diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c index b3edf4a3..0f221c05 100644 --- a/common/protos/multiboot2.c +++ b/common/protos/multiboot2.c @@ -505,7 +505,7 @@ noreturn void multiboot2_load(char *config, char* cmdline) { tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; tag->common.size = sizeof(struct multiboot_tag_framebuffer); - term_deinit(); + term->deinit(term, pmm_free); if (fbtag) { size_t req_width = fbtag->width;