bios: Move terminal entirely to stage 3
diff --git a/stage23/drivers/vga_textmode.s2.c b/stage23/drivers/vga_textmode.c
similarity index 99%
rename from stage23/drivers/vga_textmode.s2.c
rename to stage23/drivers/vga_textmode.c
index 1982f11b..0f9bbe8c 100644
--- a/stage23/drivers/vga_textmode.s2.c
+++ b/stage23/drivers/vga_textmode.c
@@ -15,7 +15,7 @@
#define VD_COLS (80 * 2)
#define VD_ROWS 25
-static uint8_t *video_mem = (uint8_t *)0xb8000;
+static volatile uint8_t *video_mem = (uint8_t *)0xb8000;
static uint8_t *back_buffer = NULL;
static uint8_t *front_buffer = NULL;
diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
index 7a1a13b9..46c1dfbf 100644
--- a/stage23/entry.s2.c
+++ b/stage23/entry.s2.c
@@ -49,7 +49,6 @@ static bool stage3_init(struct volume *part) {
stage3_found = true;
if (stage3->size != (size_t)limine_sys_size) {
- term_textmode();
print("limine.sys size incorrect.\n");
return false;
}
@@ -61,7 +60,6 @@ static bool stage3_init(struct volume *part) {
fclose(stage3);
if (memcmp(build_id_s2 + 16, build_id_s3 + 16, 20) != 0) {
- term_textmode();
print("limine.sys build ID mismatch.\n");
return false;
}
@@ -82,8 +80,6 @@ noreturn void entry(uint8_t boot_drive, int boot_from) {
if (!a20_enable())
panic(false, "Could not enable A20 line");
- term_notready();
-
struct rm_regs r = {0};
r.eax = 0x0003;
rm_int(0x10, &r, &r);
@@ -112,7 +108,6 @@ noreturn void entry(uint8_t boot_drive, int boot_from) {
);
if (!stage3_found) {
- term_textmode();
print("\n"
"!! Stage 3 file not found!\n"
"!! Have you copied limine.sys to the root or /boot directories of\n"
diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index 875d6266..ce630cfd 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -127,6 +127,8 @@ noreturn void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
#endif
noreturn void stage3_common(void) {
+ term_notready();
+
init_flush_irqs();
init_io_apics();
diff --git a/stage23/lib/panic.s2.c b/stage23/lib/panic.s2.c
index 70c2ebdf..71cf3d43 100644
--- a/stage23/lib/panic.s2.c
+++ b/stage23/lib/panic.s2.c
@@ -21,7 +21,11 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) {
quiet = false;
- if (term_backend == NOT_READY) {
+ if (
+#if bios == 1
+ stage3_loaded == true &&
+#endif
+ term_backend == NOT_READY) {
#if bios == 1
term_textmode();
#elif uefi == 1
@@ -29,11 +33,19 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) {
#endif
}
- if (term_backend == NOT_READY) {
+ if (
+#if bios == 1
+ stage3_loaded == true &&
+#endif
+ term_backend == NOT_READY) {
term_fallback();
}
- print("\033[31mPANIC\033[37;1m\033[0m: ");
+ if (stage3_loaded) {
+ print("\033[31mPANIC\033[37;1m\033[0m: ");
+ } else {
+ print("PANIC: ");
+ }
vprint(fmt, args);
va_end(args);
diff --git a/stage23/lib/print.s2.c b/stage23/lib/print.s2.c
index ca314e4a..4b0d5dc1 100644
--- a/stage23/lib/print.s2.c
+++ b/stage23/lib/print.s2.c
@@ -5,8 +5,34 @@
#include <lib/blib.h>
#include <lib/term.h>
#include <lib/libc.h>
+#if bios == 1
+#include <lib/real.h>
+#endif
#include <sys/cpu.h>
+#if bios == 1
+static void s2_print(const char *s, size_t len) {
+ for (size_t i = 0; i < len; i++) {
+ struct rm_regs r = {0};
+ char c = s[i];
+
+ switch (c) {
+ case '\n':
+ r.eax = 0x0e00 | '\r';
+ rm_int(0x10, &r, &r);
+ r = (struct rm_regs){0};
+ r.eax = 0x0e00 | '\n';
+ rm_int(0x10, &r, &r);
+ break;
+ default:
+ r.eax = 0x0e00 | s[i];
+ rm_int(0x10, &r, &r);
+ break;
+ }
+ }
+}
+#endif
+
static const char *base_digits = "0123456789abcdef";
#define PRINT_BUF_MAX 4096
@@ -187,7 +213,15 @@ void vprint(const char *fmt, va_list args) {
}
out:
- term_write((uint64_t)(uintptr_t)print_buf, print_buf_i);
+#if bios == 1
+ if (stage3_loaded) {
+#endif
+ term_write((uint64_t)(uintptr_t)print_buf, print_buf_i);
+#if bios == 1
+ } else {
+ s2_print(print_buf, print_buf_i);
+ }
+#endif
for (size_t i = 0; i < print_buf_i; i++) {
if (E9_OUTPUT) {
diff --git a/stage23/lib/term.c b/stage23/lib/term.c
index 91e612ee..a3fe07f0 100644
--- a/stage23/lib/term.c
+++ b/stage23/lib/term.c
@@ -2,9 +2,12 @@
#include <stddef.h>
#include <stdbool.h>
#include <lib/term.h>
+#include <lib/real.h>
#include <lib/image.h>
#include <lib/blib.h>
#include <lib/gterm.h>
+#include <drivers/vga_textmode.h>
+#include <lib/print.h>
#include <mm/pmm.h>
bool early_term = false;
@@ -65,3 +68,1137 @@ void term_vbe(size_t width, size_t height) {
term_backend = VBE;
}
+
+// Tries to implement this standard for terminfo
+// https://man7.org/linux/man-pages/man4/console_codes.4.html
+
+no_unwind int current_video_mode = -1;
+int term_backend = NOT_READY;
+size_t term_rows, term_cols;
+bool term_runtime = false;
+
+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_uint64_t(uint64_t n) {
+ (void)n;
+}
+
+void term_notready(void) {
+ term_backend = NOT_READY;
+
+ 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_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_rows = 100;
+ term_cols = 100;
+}
+
+#if bios == 1
+void fallback_raw_putchar(uint8_t c) {
+ struct rm_regs r = {0};
+ r.eax = 0x0e00 | c;
+ rm_int(0x10, &r, &r);
+}
+
+void fallback_clear(bool move) {
+ (void)move;
+ struct rm_regs r = {0};
+ rm_int(0x11, &r, &r);
+ switch ((r.eax >> 4) & 3) {
+ case 0:
+ r.eax = 3;
+ break;
+ case 1:
+ r.eax = 1;
+ break;
+ case 2:
+ r.eax = 3;
+ break;
+ case 3:
+ r.eax = 7;
+ break;
+ }
+ rm_int(0x10, &r, &r);
+}
+
+void fallback_set_cursor_pos(size_t x, size_t y) {
+ struct rm_regs r = {0};
+ r.eax = 0x0200;
+ r.ebx = 0;
+ r.edx = (y << 8) + x;
+ rm_int(0x10, &r, &r);
+}
+
+void fallback_get_cursor_pos(size_t *x, size_t *y) {
+ struct rm_regs r = {0};
+ r.eax = 0x0300;
+ r.ebx = 0;
+ rm_int(0x10, &r, &r);
+ *x = r.edx & 0xff;
+ *y = r.edx >> 8;
+}
+
+#elif uefi == 1
+static int cursor_x = 0, cursor_y = 0;
+
+void fallback_raw_putchar(uint8_t c) {
+ CHAR16 string[2];
+ string[0] = c;
+ string[1] = 0;
+ gST->ConOut->OutputString(gST->ConOut, string);
+ switch (c) {
+ case 0x08:
+ if (cursor_x > 0)
+ cursor_x--;
+ break;
+ case 0x0A:
+ cursor_x = 0;
+ break;
+ case 0x0D:
+ if (cursor_y < 24)
+ cursor_y++;
+ break;
+ default:
+ if (++cursor_x > 80) {
+ cursor_x = 0;
+ if (cursor_y < 24)
+ cursor_y++;
+ }
+ }
+}
+
+void fallback_clear(bool move) {
+ (void)move;
+ gST->ConOut->ClearScreen(gST->ConOut);
+ cursor_x = cursor_y = 0;
+}
+
+void fallback_set_cursor_pos(size_t x, size_t y) {
+ if (x >= 80 || y >= 25)
+ return;
+ gST->ConOut->SetCursorPosition(gST->ConOut, x, y);
+ cursor_x = x;
+ cursor_y = y;
+}
+
+void fallback_get_cursor_pos(size_t *x, size_t *y) {
+ *x = cursor_x;
+ *y = cursor_y;
+}
+#endif
+
+void term_fallback(void) {
+#if uefi == 1
+ if (!efi_boot_services_exited) {
+ gST->ConOut->Reset(gST->ConOut, false);
+ gST->ConOut->SetMode(gST->ConOut, 0);
+ cursor_x = cursor_y = 0;
+#elif bios == 1
+ fallback_clear(true);
+#endif
+ term_notready();
+ raw_putchar = fallback_raw_putchar;
+ clear = fallback_clear;
+ set_cursor_pos = fallback_set_cursor_pos;
+ get_cursor_pos = fallback_get_cursor_pos;
+ term_backend = FALLBACK;
+#if uefi == 1
+ }
+#endif
+}
+
+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_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);
+
+void (*term_double_buffer_flush)(void);
+
+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);
+
+void (*term_callback)(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;
+}
+
+#if bios == 1
+void term_textmode(void) {
+ term_notready();
+
+ if (quiet || allocations_disallowed) {
+ return;
+ }
+
+ init_vga_textmode(&term_rows, &term_cols, true);
+
+ 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_backend = TEXTMODE;
+}
+#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;
+
+void term_write(uint64_t buf, uint64_t count) {
+ if (term_backend == NOT_READY)
+ return;
+
+ switch (count) {
+ case TERM_CTX_SIZE: {
+ uint64_t ret = context_size();
+ memcpy32to64(buf, (uint64_t)(uintptr_t)&ret, sizeof(uint64_t));
+ return;
+ }
+ case TERM_CTX_SAVE: {
+ context_save(buf);
+ return;
+ }
+ case TERM_CTX_RESTORE: {
+ context_restore(buf);
+ return;
+ }
+ case TERM_FULL_REFRESH: {
+ term_full_refresh();
+ return;
+ }
+ }
+
+ bool native = false;
+#if defined (__x86_64__)
+ native = true;
+#endif
+
+ if (!term_runtime || native) {
+ const char *s = (const char *)(uintptr_t)buf;
+
+ for (size_t i = 0; i < count; i++)
+ term_putchar(s[i]);
+ } else {
+#if defined (__i386__)
+ while (count != 0) {
+ uint64_t chunk;
+ if (count > TERM_XFER_CHUNK) {
+ chunk = TERM_XFER_CHUNK;
+ } else {
+ chunk = count;
+ }
+
+ memcpy32to64((uint64_t)(uintptr_t)xfer_buf, buf, chunk);
+
+ for (size_t i = 0; i < chunk; i++)
+ term_putchar(xfer_buf[i]);
+
+ count -= chunk;
+ buf += chunk;
+ }
+#endif
+ }
+
+ if (term_autoflush) {
+ term_double_buffer_flush();
+ }
+}
+
+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;
+ }
+ }
+}
+
+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) {
+ term_callback(TERM_CB_DEC, esc_values_i, (uintptr_t)esc_values, c);
+ }
+}
+
+static void linux_private_parse(void) {
+ if (esc_values_i == 0) {
+ return;
+ }
+
+ if (term_callback != NULL) {
+ term_callback(TERM_CB_LINUX, esc_values_i, (uintptr_t)esc_values, 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) {
+ term_callback(TERM_CB_MODE, esc_values_i, (uintptr_t)esc_values, c);
+ }
+}
+
+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) {
+ term_callback(TERM_CB_PRIVATE_ID, 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) {
+ term_callback(TERM_CB_STATUS_REPORT, 0, 0, 0);
+ }
+ break;
+ case 6:
+ if (term_callback != NULL) {
+ term_callback(TERM_CB_POS_REPORT, x + 1, y + 1, 0);
+ }
+ break;
+ }
+ break;
+ case 'q':
+ if (term_callback != NULL) {
+ term_callback(TERM_CB_KBD_LEDS, esc_values[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) {
+ term_callback(TERM_CB_PRIVATE_ID, 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;
+}
+
+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) {
+ term_callback(TERM_CB_BELL, 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);
+}
diff --git a/stage23/lib/term.s2.c b/stage23/lib/term.s2.c
deleted file mode 100644
index 4622877c..00000000
--- a/stage23/lib/term.s2.c
+++ /dev/null
@@ -1,1144 +0,0 @@
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <lib/term.h>
-#include <lib/real.h>
-#include <lib/image.h>
-#include <lib/blib.h>
-#include <drivers/vga_textmode.h>
-#include <lib/print.h>
-#include <mm/pmm.h>
-
-// Tries to implement this standard for terminfo
-// https://man7.org/linux/man-pages/man4/console_codes.4.html
-
-no_unwind int current_video_mode = -1;
-int term_backend = NOT_READY;
-size_t term_rows, term_cols;
-bool term_runtime = false;
-
-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_uint64_t(uint64_t n) {
- (void)n;
-}
-
-void term_notready(void) {
- term_backend = NOT_READY;
-
- 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_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_rows = 100;
- term_cols = 100;
-}
-
-#if bios == 1
-void fallback_raw_putchar(uint8_t c) {
- struct rm_regs r = {0};
- r.eax = 0x0e00 | c;
- rm_int(0x10, &r, &r);
-}
-
-void fallback_clear(bool move) {
- (void)move;
- struct rm_regs r = {0};
- rm_int(0x11, &r, &r);
- switch ((r.eax >> 4) & 3) {
- case 0:
- r.eax = 3;
- break;
- case 1:
- r.eax = 1;
- break;
- case 2:
- r.eax = 3;
- break;
- case 3:
- r.eax = 7;
- break;
- }
- rm_int(0x10, &r, &r);
-}
-
-void fallback_set_cursor_pos(size_t x, size_t y) {
- struct rm_regs r = {0};
- r.eax = 0x0200;
- r.ebx = 0;
- r.edx = (y << 8) + x;
- rm_int(0x10, &r, &r);
-}
-
-void fallback_get_cursor_pos(size_t *x, size_t *y) {
- struct rm_regs r = {0};
- r.eax = 0x0300;
- r.ebx = 0;
- rm_int(0x10, &r, &r);
- *x = r.edx & 0xff;
- *y = r.edx >> 8;
-}
-
-#elif uefi == 1
-static int cursor_x = 0, cursor_y = 0;
-
-void fallback_raw_putchar(uint8_t c) {
- CHAR16 string[2];
- string[0] = c;
- string[1] = 0;
- gST->ConOut->OutputString(gST->ConOut, string);
- switch (c) {
- case 0x08:
- if (cursor_x > 0)
- cursor_x--;
- break;
- case 0x0A:
- cursor_x = 0;
- break;
- case 0x0D:
- if (cursor_y < 24)
- cursor_y++;
- break;
- default:
- if (++cursor_x > 80) {
- cursor_x = 0;
- if (cursor_y < 24)
- cursor_y++;
- }
- }
-}
-
-void fallback_clear(bool move) {
- (void)move;
- gST->ConOut->ClearScreen(gST->ConOut);
- cursor_x = cursor_y = 0;
-}
-
-void fallback_set_cursor_pos(size_t x, size_t y) {
- if (x >= 80 || y >= 25)
- return;
- gST->ConOut->SetCursorPosition(gST->ConOut, x, y);
- cursor_x = x;
- cursor_y = y;
-}
-
-void fallback_get_cursor_pos(size_t *x, size_t *y) {
- *x = cursor_x;
- *y = cursor_y;
-}
-#endif
-
-void term_fallback(void) {
-#if uefi == 1
- if (!efi_boot_services_exited) {
- gST->ConOut->Reset(gST->ConOut, false);
- gST->ConOut->SetMode(gST->ConOut, 0);
- cursor_x = cursor_y = 0;
-#elif bios == 1
- fallback_clear(true);
-#endif
- term_notready();
- raw_putchar = fallback_raw_putchar;
- clear = fallback_clear;
- set_cursor_pos = fallback_set_cursor_pos;
- get_cursor_pos = fallback_get_cursor_pos;
- term_backend = FALLBACK;
-#if uefi == 1
- }
-#endif
-}
-
-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_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);
-
-void (*term_double_buffer_flush)(void);
-
-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);
-
-void (*term_callback)(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;
-}
-
-#if bios == 1
-void term_textmode(void) {
- term_notready();
-
- if (quiet || allocations_disallowed) {
- return;
- }
-
- init_vga_textmode(&term_rows, &term_cols, true);
-
- 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_backend = TEXTMODE;
-}
-#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;
-
-void term_write(uint64_t buf, uint64_t count) {
- if (term_backend == NOT_READY)
- return;
-
- switch (count) {
- case TERM_CTX_SIZE: {
- uint64_t ret = context_size();
- memcpy32to64(buf, (uint64_t)(uintptr_t)&ret, sizeof(uint64_t));
- return;
- }
- case TERM_CTX_SAVE: {
- context_save(buf);
- return;
- }
- case TERM_CTX_RESTORE: {
- context_restore(buf);
- return;
- }
- case TERM_FULL_REFRESH: {
- term_full_refresh();
- return;
- }
- }
-
- bool native = false;
-#if defined (__x86_64__)
- native = true;
-#endif
-
- if (!term_runtime || native) {
- const char *s = (const char *)(uintptr_t)buf;
-
- for (size_t i = 0; i < count; i++)
- term_putchar(s[i]);
- } else {
-#if defined (__i386__)
- while (count != 0) {
- uint64_t chunk;
- if (count > TERM_XFER_CHUNK) {
- chunk = TERM_XFER_CHUNK;
- } else {
- chunk = count;
- }
-
- memcpy32to64((uint64_t)(uintptr_t)xfer_buf, buf, chunk);
-
- for (size_t i = 0; i < chunk; i++)
- term_putchar(xfer_buf[i]);
-
- count -= chunk;
- buf += chunk;
- }
-#endif
- }
-
- if (term_autoflush) {
- term_double_buffer_flush();
- }
-}
-
-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;
- }
- }
-}
-
-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) {
- term_callback(TERM_CB_DEC, esc_values_i, (uintptr_t)esc_values, c);
- }
-}
-
-static void linux_private_parse(void) {
- if (esc_values_i == 0) {
- return;
- }
-
- if (term_callback != NULL) {
- term_callback(TERM_CB_LINUX, esc_values_i, (uintptr_t)esc_values, 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) {
- term_callback(TERM_CB_MODE, esc_values_i, (uintptr_t)esc_values, c);
- }
-}
-
-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) {
- term_callback(TERM_CB_PRIVATE_ID, 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) {
- term_callback(TERM_CB_STATUS_REPORT, 0, 0, 0);
- }
- break;
- case 6:
- if (term_callback != NULL) {
- term_callback(TERM_CB_POS_REPORT, x + 1, y + 1, 0);
- }
- break;
- }
- break;
- case 'q':
- if (term_callback != NULL) {
- term_callback(TERM_CB_KBD_LEDS, esc_values[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) {
- term_callback(TERM_CB_PRIVATE_ID, 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;
-}
-
-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) {
- term_callback(TERM_CB_BELL, 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);
-}
diff --git a/stage23/linker_stage2only.ld b/stage23/linker_stage2only.ld
index 60ad1431..7ec516e5 100644
--- a/stage23/linker_stage2only.ld
+++ b/stage23/linker_stage2only.ld
@@ -36,6 +36,9 @@ SECTIONS
getchar_internal = .;
getchar = .;
menu = .;
+ term_write = .;
+ term_textmode = .;
+ term_fallback = .;
stage3_addr = .;
data_begin = .;
}
