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 #include #include +#if bios == 1 +#include +#endif #include +#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 #include #include +#include #include #include #include +#include +#include #include 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// 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 = .; }