term: Mass backport changes done in Vinix upstream
diff --git a/stage23/Makefile b/stage23/Makefile
index 02c936dc..95114a49 100644
--- a/stage23/Makefile
+++ b/stage23/Makefile
@@ -61,6 +61,7 @@ INTERNAL_CFLAGS := \
-fno-omit-frame-pointer \
-fno-lto \
-fno-pic \
+ -Wno-stringop-overflow \
-Wno-address-of-packed-member \
-Wshadow \
-mno-80387 \
diff --git a/stage23/drivers/vga_textmode.h b/stage23/drivers/vga_textmode.h
index 41ef5c18..8ad55d64 100644
--- a/stage23/drivers/vga_textmode.h
+++ b/stage23/drivers/vga_textmode.h
@@ -2,24 +2,33 @@
#define __DRIVERS__VGA_TEXTMODE_H__
#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
-void init_vga_textmode(int *rows, int *cols, bool managed);
+void init_vga_textmode(size_t *rows, size_t *cols, bool managed);
void text_putchar(uint8_t c);
void text_clear(bool move);
void text_enable_cursor(void);
bool text_disable_cursor(void);
-void text_set_cursor_pos(int x, int y);
-void text_get_cursor_pos(int *x, int *y);
-void text_set_text_fg(int fg);
-void text_set_text_bg(int bg);
+void text_set_cursor_pos(size_t x, size_t y);
+void text_get_cursor_pos(size_t *x, size_t *y);
+void text_set_text_fg(size_t fg);
+void text_set_text_bg(size_t bg);
+void text_set_text_fg_bright(size_t fg);
void text_set_text_fg_default(void);
void text_set_text_bg_default(void);
bool text_scroll_disable(void);
void text_scroll_enable(void);
-void text_move_character(int new_x, int new_y, int old_x, int old_y);
+void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
+void text_scroll(void);
+void text_swap_palette(void);
void text_double_buffer(bool state);
void text_double_buffer_flush(void);
+uint64_t text_context_size(void);
+void text_context_save(uint64_t ptr);
+void text_context_restore(uint64_t ptr);
+
#endif
diff --git a/stage23/drivers/vga_textmode.s2.c b/stage23/drivers/vga_textmode.s2.c
index 61784eda..2ae68322 100644
--- a/stage23/drivers/vga_textmode.s2.c
+++ b/stage23/drivers/vga_textmode.s2.c
@@ -7,6 +7,7 @@
#include <sys/cpu.h>
#include <lib/real.h>
#include <lib/libc.h>
+#include <lib/blib.h>
#include <lib/term.h>
#include <mm/pmm.h>
@@ -14,16 +15,25 @@
#define VD_COLS (80 * 2)
#define VD_ROWS 25
-static uint8_t *back_buffer = NULL;
-static uint8_t *front_buffer = NULL;
static uint8_t *video_mem = (uint8_t *)0xb8000;
-static uint8_t *current_buffer;
+static uint8_t *back_buffer = NULL;
+static uint8_t *front_buffer = NULL;
-static size_t cursor_offset;
-static int cursor_status;
-static uint8_t text_palette;
-static uint8_t cursor_palette;
+static struct context {
+ uint8_t *current_buffer;
+#define current_buffer context.current_buffer
+ size_t cursor_offset;
+#define cursor_offset context.cursor_offset
+ bool cursor_status;
+#define cursor_status context.cursor_status
+ uint8_t text_palette;
+#define text_palette context.text_palette
+ uint8_t cursor_palette;
+#define cursor_palette context.cursor_palette
+ bool scroll_enabled;
+#define scroll_enabled context.scroll_enabled
+} context;
static void clear_cursor(void) {
if (cursor_status) {
@@ -37,7 +47,9 @@ static void draw_cursor(void) {
}
}
-static bool scroll_enabled = true;
+void text_swap_palette(void) {
+ text_palette = (text_palette << 4) | (text_palette >> 4);
+}
bool text_scroll_disable(void) {
bool ret = scroll_enabled;
@@ -49,20 +61,22 @@ void text_scroll_enable(void) {
scroll_enabled = true;
}
-static void scroll(void) {
+void text_scroll(void) {
// move the text up by one row
- for (size_t i = 0; i <= VIDEO_BOTTOM - VD_COLS; i++) {
+ for (size_t i = term_context.scroll_top_margin * VD_COLS;
+ i < (term_context.scroll_bottom_margin - 1) * VD_COLS; i++) {
current_buffer[i] = current_buffer[i + VD_COLS];
if (current_buffer == front_buffer)
video_mem[i] = current_buffer[i + VD_COLS];
}
// clear the last line of the screen
- for (size_t i = VIDEO_BOTTOM; i > VIDEO_BOTTOM - VD_COLS; i -= 2) {
- current_buffer[i] = text_palette;
- current_buffer[i - 1] = ' ';
+ for (size_t i = (term_context.scroll_bottom_margin - 1) * VD_COLS;
+ i < term_context.scroll_bottom_margin * VD_COLS; i += 2) {
+ current_buffer[i] = ' ';
+ current_buffer[i + 1] = text_palette;
if (current_buffer == front_buffer) {
- video_mem[i] = text_palette;
- video_mem[i - 1] = ' ';
+ video_mem[i] = ' ';
+ video_mem[i + 1] = text_palette;
}
}
}
@@ -84,19 +98,55 @@ void text_clear(bool move) {
}
void text_enable_cursor(void) {
- cursor_status = 1;
+ cursor_status = true;
draw_cursor();
return;
}
bool text_disable_cursor(void) {
- bool ret = cursor_status != 0;
+ bool ret = cursor_status;
clear_cursor();
- cursor_status = 0;
+ cursor_status = false;
return ret;
}
-void init_vga_textmode(int *_rows, int *_cols, bool managed) {
+uint64_t text_context_size(void) {
+ uint64_t ret = 0;
+
+ ret += sizeof(struct context);
+ ret += VD_ROWS * VD_COLS; // back buffer
+ ret += VD_ROWS * VD_COLS; // front buffer
+
+ return ret;
+}
+
+void text_context_save(uint64_t ptr) {
+ memcpy32to64(ptr, (uint64_t)(uintptr_t)&context, sizeof(struct context));
+ ptr += sizeof(struct context);
+
+ memcpy32to64(ptr, (uint64_t)(uintptr_t)back_buffer, VD_ROWS * VD_COLS);
+ ptr += VD_ROWS * VD_COLS;
+
+ memcpy32to64(ptr, (uint64_t)(uintptr_t)front_buffer, VD_ROWS * VD_COLS);
+}
+
+void text_context_restore(uint64_t ptr) {
+ memcpy32to64((uint64_t)(uintptr_t)&context, ptr, sizeof(struct context));
+ ptr += sizeof(struct context);
+
+ memcpy32to64((uint64_t)(uintptr_t)back_buffer, ptr, VD_ROWS * VD_COLS);
+ ptr += VD_ROWS * VD_COLS;
+
+ memcpy32to64((uint64_t)(uintptr_t)front_buffer, ptr, VD_ROWS * VD_COLS);
+
+ for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) {
+ video_mem[i] = current_buffer[i];
+ }
+
+ draw_cursor();
+}
+
+void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) {
if (current_video_mode != -1) {
struct rm_regs r = {0};
r.eax = 0x0003;
@@ -105,15 +155,17 @@ void init_vga_textmode(int *_rows, int *_cols, bool managed) {
current_video_mode = -1;
}
- back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
- front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
+ if (back_buffer == NULL)
+ back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
+ if (front_buffer == NULL)
+ front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
+ current_buffer = front_buffer;
cursor_offset = 0;
- cursor_status = 1;
+ cursor_status = true;
text_palette = 0x07;
cursor_palette = 0x70;
-
- text_double_buffer(false);
+ scroll_enabled = true;
text_clear(false);
@@ -165,48 +217,49 @@ void text_double_buffer_flush(void) {
draw_cursor();
}
-static int text_get_cursor_pos_y(void) {
- return cursor_offset / VD_COLS;
-}
-
-void text_get_cursor_pos(int *x, int *y) {
+void text_get_cursor_pos(size_t *x, size_t *y) {
*x = (cursor_offset % VD_COLS) / 2;
*y = cursor_offset / VD_COLS;
}
-void text_move_character(int new_x, int new_y, int old_x, int old_y) {
+void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
+ if (old_x >= VD_COLS / 2 || old_y >= VD_ROWS
+ || new_x >= VD_COLS / 2 || new_y >= VD_ROWS) {
+ return;
+ }
+
current_buffer[new_y * VD_COLS + new_x * 2] = current_buffer[old_y * VD_COLS + old_x * 2];
if (current_buffer == front_buffer) {
video_mem[new_y * VD_COLS + new_x * 2] = current_buffer[old_y * VD_COLS + old_x * 2];
}
}
-void text_set_cursor_pos(int x, int y) {
+void text_set_cursor_pos(size_t x, size_t y) {
clear_cursor();
- if (x < 0) {
- x = 0;
- } else if (x >= VD_COLS / 2) {
+ if (x >= VD_COLS / 2) {
x = VD_COLS / 2 - 1;
}
- if (y < 0) {
- y = 0;
- } else if (y >= VD_ROWS) {
+ if (y >= VD_ROWS) {
y = VD_ROWS - 1;
}
cursor_offset = y * VD_COLS + x * 2;
draw_cursor();
}
-static uint8_t ansi_colours[] = { 0, 4, 2, 0x0e, 1, 5, 3, 7 };
+static uint8_t ansi_colours[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
-void text_set_text_fg(int fg) {
+void text_set_text_fg(size_t fg) {
text_palette = (text_palette & 0xf0) | ansi_colours[fg];
}
-void text_set_text_bg(int bg) {
+void text_set_text_bg(size_t bg) {
text_palette = (text_palette & 0x0f) | (ansi_colours[bg] << 4);
}
+void text_set_text_fg_bright(size_t fg) {
+ text_palette = (text_palette & 0xf0) | (ansi_colours[fg] | (1 << 3));
+}
+
void text_set_text_fg_default(void) {
text_palette = (text_palette & 0xf0) | 7;
}
@@ -216,46 +269,25 @@ void text_set_text_bg_default(void) {
}
void text_putchar(uint8_t c) {
- switch (c) {
- case '\b':
- if (cursor_offset) {
- clear_cursor();
- cursor_offset -= 2;
- draw_cursor();
- }
- break;
- case '\r':
- text_set_cursor_pos(0, text_get_cursor_pos_y());
- break;
- case '\n':
- if (text_get_cursor_pos_y() == (VD_ROWS - 1)) {
- if (scroll_enabled) {
- clear_cursor();
- scroll();
- text_set_cursor_pos(0, (VD_ROWS - 1));
- }
- } else {
- text_set_cursor_pos(0, (text_get_cursor_pos_y() + 1));
- }
- break;
- default:
- clear_cursor();
- current_buffer[cursor_offset] = c;
- current_buffer[cursor_offset+1] = text_palette;
- if (current_buffer == front_buffer) {
- video_mem[cursor_offset] = c;
- video_mem[cursor_offset+1] = text_palette;
- }
- if (cursor_offset >= (VIDEO_BOTTOM - 1)) {
- if (scroll_enabled) {
- scroll();
- cursor_offset = VIDEO_BOTTOM - (VD_COLS - 1);
- }
- } else {
- cursor_offset += 2;
- }
- draw_cursor();
+ clear_cursor();
+ current_buffer[cursor_offset] = c;
+ current_buffer[cursor_offset + 1] = text_palette;
+ if (current_buffer == front_buffer) {
+ video_mem[cursor_offset] = c;
+ video_mem[cursor_offset + 1] = text_palette;
}
+ if (cursor_offset / VD_COLS == term_context.scroll_bottom_margin - 1
+ && cursor_offset % VD_COLS == VD_COLS - 2) {
+ if (scroll_enabled) {
+ text_scroll();
+ cursor_offset -= cursor_offset % VD_COLS;
+ }
+ } else if (cursor_offset >= (VIDEO_BOTTOM - 1)) {
+ cursor_offset -= cursor_offset % VD_COLS;
+ } else {
+ cursor_offset += 2;
+ }
+ draw_cursor();
}
#endif
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index 97bbda42..44745ecf 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -20,13 +20,13 @@ UINTN efi_mmap_size = 0, efi_desc_size = 0, efi_desc_ver = 0;
bool verbose = false;
-bool parse_resolution(int *width, int *height, int *bpp, const char *buf) {
- int res[3] = {0};
+bool parse_resolution(size_t *width, size_t *height, size_t *bpp, const char *buf) {
+ size_t res[3] = {0};
const char *first = buf;
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
const char *last;
- int x = strtoui(first, &last, 10);
+ size_t x = strtoui(first, &last, 10);
if (first == last)
break;
res[i] = x;
diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h
index da7de349..d9ce48ae 100644
--- a/stage23/lib/blib.h
+++ b/stage23/lib/blib.h
@@ -6,6 +6,7 @@
#include <stdbool.h>
#include <fs/file.h>
#include <lib/part.h>
+#include <lib/libc.h>
#if uefi == 1
# include <efi.h>
#endif
@@ -30,7 +31,7 @@ extern bool stage3_loaded;
extern bool verbose;
-bool parse_resolution(int *width, int *height, int *bpp, const char *buf);
+bool parse_resolution(size_t *width, size_t *height, size_t *bpp, const char *buf);
uint64_t sqrt(uint64_t a_nInput);
size_t get_trailing_zeros(uint64_t val);
@@ -44,6 +45,12 @@ int pit_sleep_and_quit_on_keypress(int seconds);
uint64_t strtoui(const char *s, const char **end, int base);
+#if defined (__i386__)
+void memcpy32to64(uint64_t, uint64_t, uint64_t);
+#elif defined (__x86_64__)
+# define memcpy32to64(X, Y, Z) memcpy((void *)(uintptr_t)(X), (void *)(uintptr_t)(Y), Z)
+#endif
+
#define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b))
#define ALIGN_UP(x, a) ({ \
diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c
index 56ea1e27..d11bc6b8 100644
--- a/stage23/lib/gterm.c
+++ b/stage23/lib/gterm.c
@@ -31,7 +31,7 @@ static uint32_t ansi_colours[8];
static uint32_t ansi_bright_colours[8];
static uint32_t default_fg, default_bg;
-static int frame_height, frame_width;
+static size_t frame_height, frame_width;
static struct image *background;
@@ -49,12 +49,22 @@ static uint32_t text_fg, text_bg;
static bool cursor_status = true;
-static int cursor_x;
-static int cursor_y;
+static size_t cursor_x;
+static size_t cursor_y;
-static int rows;
-static int cols;
-static int margin_gradient;
+static size_t rows;
+static size_t cols;
+static size_t margin_gradient;
+
+void gterm_swap_palette(void) {
+ uint32_t tmp = text_bg;
+ text_bg = text_fg;
+ if (tmp == 0xffffffff) {
+ text_fg = default_bg;
+ } else {
+ text_fg = tmp;
+ }
+}
#define A(rgb) (uint8_t)(rgb >> 24)
#define R(rgb) (uint8_t)(rgb >> 16)
@@ -73,14 +83,14 @@ static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
return ARGB(0, r, g, b);
}
-void gterm_plot_px(int x, int y, uint32_t hex) {
+void gterm_plot_px(size_t x, size_t y, uint32_t hex) {
size_t fb_i = x + (gterm_pitch / sizeof(uint32_t)) * y;
gterm_framebuffer[fb_i] = hex;
}
-static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, uint32_t hex) {
- int distance, x_distance, y_distance;
+static uint32_t blend_gradient_from_box(size_t x, size_t y, uint32_t bg_px, uint32_t hex) {
+ size_t distance, x_distance, y_distance;
if (x < frame_width)
x_distance = frame_width - x;
@@ -110,22 +120,22 @@ static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, uint32_t h
return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px);
}
-typedef int fixedp6; // the last 6 bits are the fixed point part
-static int fixedp6_to_int(fixedp6 value) { return value / 64; }
-static fixedp6 int_to_fixedp6(int value) { return value * 64; }
+typedef size_t fixedp6; // the last 6 bits are the fixed point part
+static size_t fixedp6_to_int(fixedp6 value) { return value / 64; }
+static fixedp6 int_to_fixedp6(size_t value) { return value * 64; }
// Draw rect at coordinates, copying from the image to the fb and canvas, applying fn on every pixel
-__attribute__((always_inline)) static inline void genloop(int xstart, int xend, int ystart, int yend, uint32_t (*blend)(int x, int y, uint32_t orig)) {
+__attribute__((always_inline)) static inline void genloop(size_t xstart, size_t xend, size_t ystart, size_t yend, uint32_t (*blend)(size_t x, size_t y, uint32_t orig)) {
uint8_t *img = background->img;
- const int img_width = background->img_width, img_height = background->img_height, img_pitch = background->pitch, colsize = background->bpp / 8;
+ const size_t img_width = background->img_width, img_height = background->img_height, img_pitch = background->pitch, colsize = background->bpp / 8;
switch (background->type) {
case IMAGE_TILED:
- for (int y = ystart; y < yend; y++) {
- int image_y = y % img_height, image_x = xstart % img_width;
+ for (size_t y = ystart; y < yend; y++) {
+ size_t image_y = y % img_height, image_x = xstart % img_width;
const size_t off = img_pitch * (img_height - 1 - image_y);
- int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
- for (int x = xstart; x < xend; x++) {
+ size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
+ for (size_t x = xstart; x < xend; x++) {
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
uint32_t i = blend(x, y, img_pixel);
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
@@ -135,20 +145,20 @@ __attribute__((always_inline)) static inline void genloop(int xstart, int xend,
break;
case IMAGE_CENTERED:
- for (int y = ystart; y < yend; y++) {
- int image_y = y - background->y_displacement;
+ for (size_t y = ystart; y < yend; y++) {
+ size_t image_y = y - background->y_displacement;
const size_t off = img_pitch * (img_height - 1 - image_y);
- int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
- if ((image_y < 0) || (image_y >= background->y_size)) { /* external part */
- for (int x = xstart; x < xend; x++) {
+ size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
+ if (image_y >= background->y_size) { /* external part */
+ for (size_t x = xstart; x < xend; x++) {
uint32_t i = blend(x, y, background->back_colour);
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
}
}
else { /* internal part */
- for (int x = xstart; x < xend; x++) {
- int image_x = (x - background->x_displacement);
- bool x_external = (image_x < 0) || (image_x >= background->x_size);
+ for (size_t x = xstart; x < xend; x++) {
+ size_t image_x = (x - background->x_displacement);
+ bool x_external = image_x >= background->x_size;
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
uint32_t i = blend(x, y, x_external ? background->back_colour : img_pixel);
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
@@ -160,14 +170,14 @@ __attribute__((always_inline)) static inline void genloop(int xstart, int xend,
// hence x = xstart * ratio + i * ratio
// so you can set x = xstart * ratio, and increment by ratio at each iteration
case IMAGE_STRETCHED:
- for (int y = ystart; y < yend; y++) {
- int img_y = (y * img_height) / gterm_height; // calculate Y with full precision
- int off = img_pitch * (img_height - 1 - img_y);
- int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
+ for (size_t y = ystart; y < yend; y++) {
+ size_t img_y = (y * img_height) / gterm_height; // calculate Y with full precision
+ size_t off = img_pitch * (img_height - 1 - img_y);
+ size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
size_t ratio = int_to_fixedp6(img_width) / gterm_width;
fixedp6 img_x = ratio * xstart;
- for (int x = xstart; x < xend; x++) {
+ for (size_t x = xstart; x < xend; x++) {
uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off);
uint32_t i = blend(x, y, img_pixel);
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
@@ -177,18 +187,18 @@ __attribute__((always_inline)) static inline void genloop(int xstart, int xend,
break;
}
}
-static uint32_t blend_external(int x, int y, uint32_t orig) { (void)x; (void)y; return orig; }
-static uint32_t blend_internal(int x, int y, uint32_t orig) { (void)x; (void)y; return colour_blend(default_bg, orig); }
-static uint32_t blend_margin(int x, int y, uint32_t orig) { return blend_gradient_from_box(x, y, orig, default_bg); }
+static uint32_t blend_external(size_t x, size_t y, uint32_t orig) { (void)x; (void)y; return orig; }
+static uint32_t blend_internal(size_t x, size_t y, uint32_t orig) { (void)x; (void)y; return colour_blend(default_bg, orig); }
+static uint32_t blend_margin(size_t x, size_t y, uint32_t orig) { return blend_gradient_from_box(x, y, orig, default_bg); }
-static void loop_external(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_external); }
-static void loop_margin(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_margin); }
-static void loop_internal(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_internal); }
+static void loop_external(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_external); }
+static void loop_margin(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_margin); }
+static void loop_internal(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_internal); }
void gterm_generate_canvas(void) {
if (background) {
- const int frame_height_end = frame_height + VGA_FONT_HEIGHT * rows, frame_width_end = frame_width + VGA_FONT_WIDTH * cols;
- const int fheight = frame_height - margin_gradient, fheight_end = frame_height_end + margin_gradient,
+ const size_t frame_height_end = frame_height + VGA_FONT_HEIGHT * rows, frame_width_end = frame_width + VGA_FONT_WIDTH * cols;
+ const size_t fheight = frame_height - margin_gradient, fheight_end = frame_height_end + margin_gradient,
fwidth = frame_width - margin_gradient, fwidth_end = frame_width_end + margin_gradient;
loop_external(0, gterm_width, 0, fheight);
@@ -205,8 +215,8 @@ void gterm_generate_canvas(void) {
loop_internal(frame_width, frame_width_end, frame_height, frame_height_end);
} else {
- for (int y = 0; y < gterm_height; y++) {
- for (int x = 0; x < gterm_width; x++) {
+ for (size_t y = 0; y < gterm_height; y++) {
+ for (size_t x = 0; x < gterm_width; x++) {
bg_canvas[y * gterm_width + x] = default_bg;
gterm_plot_px(x, y, default_bg);
}
@@ -220,12 +230,12 @@ struct gterm_char {
uint32_t bg;
};
-void gterm_plot_char(struct gterm_char *c, int x, int y) {
+void gterm_plot_char(struct gterm_char *c, size_t x, size_t y) {
bool *glyph = &vga_font_bool[c->c * VGA_FONT_HEIGHT * VGA_FONT_WIDTH];
- for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
+ for (size_t i = 0; i < VGA_FONT_HEIGHT; i++) {
uint32_t *fb_line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4);
uint32_t *canvas_line = bg_canvas + x + (y + i) * gterm_width;
- for (int j = 0; j < VGA_FONT_WIDTH; j++) {
+ for (size_t j = 0; j < VGA_FONT_WIDTH; j++) {
uint32_t bg = c->bg == 0xffffffff ? canvas_line[j] : c->bg;
bool draw = glyph[i * VGA_FONT_WIDTH + j];
fb_line[j] = draw ? c->fg : bg;
@@ -233,13 +243,13 @@ void gterm_plot_char(struct gterm_char *c, int x, int y) {
}
}
-void gterm_plot_char_fast(struct gterm_char *old, struct gterm_char *c, int x, int y) {
+void gterm_plot_char_fast(struct gterm_char *old, struct gterm_char *c, size_t x, size_t y) {
bool *new_glyph = &vga_font_bool[c->c * VGA_FONT_HEIGHT * VGA_FONT_WIDTH];
bool *old_glyph = &vga_font_bool[old->c * VGA_FONT_HEIGHT * VGA_FONT_WIDTH];
- for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
+ for (size_t i = 0; i < VGA_FONT_HEIGHT; i++) {
uint32_t *fb_line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4);
uint32_t *canvas_line = bg_canvas + x + (y + i) * gterm_width;
- for (int j = 0; j < VGA_FONT_WIDTH; j++) {
+ for (size_t j = 0; j < VGA_FONT_WIDTH; j++) {
uint32_t bg = c->bg == 0xffffffff ? canvas_line[j] : c->bg;
bool old_draw = old_glyph[i * VGA_FONT_WIDTH + j];
bool new_draw = new_glyph[i * VGA_FONT_WIDTH + j];
@@ -250,11 +260,11 @@ void gterm_plot_char_fast(struct gterm_char *old, struct gterm_char *c, int x, i
}
}
-static void plot_char_grid_force(struct gterm_char *c, int x, int y) {
+static void plot_char_grid_force(struct gterm_char *c, size_t x, size_t y) {
gterm_plot_char(c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT);
}
-static void plot_char_grid(struct gterm_char *c, int x, int y) {
+static void plot_char_grid(struct gterm_char *c, size_t x, size_t y) {
if (!double_buffer_enabled) {
struct gterm_char *old = &grid[x + y * cols];
@@ -302,10 +312,11 @@ void gterm_scroll_enable(void) {
scroll_enabled = true;
}
-static void scroll(void) {
+void gterm_scroll(void) {
clear_cursor();
- for (int i = cols; i < rows * cols; i++) {
+ for (size_t i = (term_context.scroll_top_margin + 1) * cols;
+ i < term_context.scroll_bottom_margin * cols; i++) {
if (!compare_char(&grid[i], &grid[i - cols]))
plot_char_grid(&grid[i], (i - cols) % cols, (i - cols) / cols);
}
@@ -315,7 +326,8 @@ static void scroll(void) {
empty.c = ' ';
empty.fg = text_fg;
empty.bg = text_bg;
- for (int i = rows * cols - cols; i < rows * cols; i++) {
+ for (size_t i = (term_context.scroll_bottom_margin - 1) * cols;
+ i < term_context.scroll_bottom_margin * cols; i++) {
if (!compare_char(&grid[i], &empty))
plot_char_grid(&empty, i % cols, i / cols);
}
@@ -330,7 +342,7 @@ void gterm_clear(bool move) {
empty.c = ' ';
empty.fg = text_fg;
empty.bg = text_bg;
- for (int i = 0; i < rows * cols; i++) {
+ for (size_t i = 0; i < rows * cols; i++) {
plot_char_grid(&empty, i % cols, i / cols);
}
@@ -354,16 +366,12 @@ bool gterm_disable_cursor(void) {
return ret;
}
-void gterm_set_cursor_pos(int x, int y) {
+void gterm_set_cursor_pos(size_t x, size_t y) {
clear_cursor();
- if (x < 0) {
- x = 0;
- } else if (x >= cols) {
+ if (x >= cols) {
x = cols - 1;
}
- if (y < 0) {
- y = 0;
- } else if (y >= rows) {
+ if (y >= rows) {
y = rows - 1;
}
cursor_x = x;
@@ -371,12 +379,17 @@ void gterm_set_cursor_pos(int x, int y) {
draw_cursor();
}
-void gterm_get_cursor_pos(int *x, int *y) {
+void gterm_get_cursor_pos(size_t *x, size_t *y) {
*x = cursor_x;
*y = cursor_y;
}
-void gterm_move_character(int new_x, int new_y, int old_x, int old_y) {
+void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
+ if (old_x >= cols || old_y >= rows
+ || new_x >= cols || new_y >= rows) {
+ return;
+ }
+
if (!double_buffer_enabled) {
gterm_plot_char(&grid[old_x + old_y * cols],
frame_width + new_x * VGA_FONT_WIDTH,
@@ -385,19 +398,19 @@ void gterm_move_character(int new_x, int new_y, int old_x, int old_y) {
grid[new_x + new_y * cols] = grid[old_x + old_y * cols];
}
-void gterm_set_text_fg(int fg) {
+void gterm_set_text_fg(size_t fg) {
text_fg = ansi_colours[fg];
}
-void gterm_set_text_bg(int bg) {
+void gterm_set_text_bg(size_t bg) {
text_bg = ansi_colours[bg];
}
-void gterm_set_text_fg_bright(int fg) {
+void gterm_set_text_fg_bright(size_t fg) {
text_fg = ansi_bright_colours[fg];
}
-void gterm_set_text_bg_bright(int bg) {
+void gterm_set_text_bg_bright(size_t bg) {
text_bg = ansi_bright_colours[bg];
}
@@ -416,8 +429,8 @@ void gterm_double_buffer_flush(void) {
front_grid[i] = grid[i];
- int x = i % cols;
- int y = i / cols;
+ size_t x = i % cols;
+ size_t y = i / cols;
gterm_plot_char(&grid[i], x * VGA_FONT_WIDTH + frame_width,
y * VGA_FONT_HEIGHT + frame_height);
@@ -440,54 +453,24 @@ void gterm_double_buffer(bool state) {
}
void gterm_putchar(uint8_t c) {
- switch (c) {
- case '\b':
- if (cursor_x || cursor_y) {
- clear_cursor();
- if (cursor_x) {
- cursor_x--;
- } else {
- cursor_y--;
- cursor_x = cols - 1;
- }
- draw_cursor();
- }
- break;
- case '\r':
- gterm_set_cursor_pos(0, cursor_y);
- break;
- case '\n':
- if (cursor_y == (rows - 1)) {
- if (scroll_enabled) {
- gterm_set_cursor_pos(0, rows - 1);
- scroll();
- }
- } else {
- gterm_set_cursor_pos(0, cursor_y + 1);
- }
- break;
- default: {
- clear_cursor();
- struct gterm_char ch;
- ch.c = c;
- ch.fg = text_fg;
- ch.bg = text_bg;
- plot_char_grid(&ch, cursor_x++, cursor_y);
- if (cursor_x == cols && (cursor_y < rows - 1 || scroll_enabled)) {
- cursor_x = 0;
- cursor_y++;
- }
- if (cursor_y == rows) {
- cursor_y--;
- scroll();
- }
- draw_cursor();
- break;
- }
+ clear_cursor();
+ struct gterm_char ch;
+ ch.c = c;
+ ch.fg = text_fg;
+ ch.bg = text_bg;
+ plot_char_grid(&ch, cursor_x++, cursor_y);
+ if (cursor_x == cols && ((size_t)cursor_y < term_context.scroll_bottom_margin - 1 || scroll_enabled)) {
+ cursor_x = 0;
+ cursor_y++;
}
+ if ((size_t)cursor_y == term_context.scroll_bottom_margin) {
+ cursor_y--;
+ gterm_scroll();
+ }
+ draw_cursor();
}
-bool gterm_init(int *_rows, int *_cols, int width, int height) {
+bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) {
if (current_video_mode >= 0
&& fbinfo.default_res == true
&& width == 0
@@ -518,7 +501,7 @@ bool gterm_init(int *_rows, int *_cols, int width, int height) {
return false;
// default scheme
- int margin = 64;
+ size_t margin = 64;
margin_gradient = 4;
default_bg = 0x00000000; // background (black)
@@ -538,7 +521,7 @@ bool gterm_init(int *_rows, int *_cols, int width, int height) {
colours = config_get_value(NULL, 0, "THEME_COLORS");
if (colours != NULL) {
const char *first = colours;
- int i;
+ size_t i;
for (i = 0; i < 10; i++) {
const char *last;
uint32_t col = strtoui(first, &last, 16);
@@ -571,7 +554,7 @@ bool gterm_init(int *_rows, int *_cols, int width, int height) {
bright_colours = config_get_value(NULL, 0, "THEME_BRIGHT_COLORS");
if (bright_colours != NULL) {
const char *first = bright_colours;
- int i;
+ size_t i;
for (i = 0; i < 8; i++) {
const char *last;
uint32_t col = strtoui(first, &last, 16);
@@ -672,8 +655,8 @@ bool gterm_init(int *_rows, int *_cols, int width, int height) {
for (size_t i = 0; i < VGA_FONT_GLYPHS; i++) {
uint8_t *glyph = &vga_font_bits[i * VGA_FONT_HEIGHT];
- for (int y = 0; y < VGA_FONT_HEIGHT; y++) {
- for (int x = 0; x < VGA_FONT_WIDTH; x++) {
+ for (size_t y = 0; y < VGA_FONT_HEIGHT; y++) {
+ for (size_t x = 0; x < VGA_FONT_WIDTH; x++) {
size_t offset = i * VGA_FONT_HEIGHT * VGA_FONT_WIDTH + y * VGA_FONT_WIDTH + x;
if ((glyph[y] & (0x80 >> x))) {
vga_font_bool[offset] = true;
diff --git a/stage23/lib/gterm.h b/stage23/lib/gterm.h
index 9859f493..56a6bb5b 100644
--- a/stage23/lib/gterm.h
+++ b/stage23/lib/gterm.h
@@ -8,23 +8,25 @@
extern struct fb_info fbinfo;
-bool gterm_init(int *_rows, int *_cols, int width, int height);
+bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height);
void gterm_putchar(uint8_t c);
void gterm_clear(bool move);
void gterm_enable_cursor(void);
bool gterm_disable_cursor(void);
-void gterm_set_cursor_pos(int x, int y);
-void gterm_get_cursor_pos(int *x, int *y);
-void gterm_set_text_fg(int fg);
-void gterm_set_text_bg(int bg);
-void gterm_set_text_fg_bright(int fg);
-void gterm_set_text_bg_bright(int bg);
+void gterm_set_cursor_pos(size_t x, size_t y);
+void gterm_get_cursor_pos(size_t *x, size_t *y);
+void gterm_set_text_fg(size_t fg);
+void gterm_set_text_bg(size_t bg);
+void gterm_set_text_fg_bright(size_t fg);
+void gterm_set_text_bg_bright(size_t bg);
void gterm_set_text_fg_default(void);
void gterm_set_text_bg_default(void);
bool gterm_scroll_disable(void);
void gterm_scroll_enable(void);
-void gterm_move_character(int new_x, int new_y, int old_x, int old_y);
+void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
+void gterm_scroll(void);
+void gterm_swap_palette(void);
void gterm_double_buffer_flush(void);
void gterm_double_buffer(bool state);
diff --git a/stage23/lib/image.h b/stage23/lib/image.h
index 4731c908..8c7a506c 100644
--- a/stage23/lib/image.h
+++ b/stage23/lib/image.h
@@ -6,16 +6,16 @@
struct image {
struct file_handle *file;
- int x_size;
- int y_size;
+ size_t x_size;
+ size_t y_size;
int type;
uint8_t *img;
int bpp;
int pitch;
- int img_width; // x_size = scaled size, img_width = bitmap size
- int img_height;
- int x_displacement;
- int y_displacement;
+ size_t img_width; // x_size = scaled size, img_width = bitmap size
+ size_t img_height;
+ size_t x_displacement;
+ size_t y_displacement;
uint32_t back_colour;
};
diff --git a/stage23/lib/libgcc.s2.asm b/stage23/lib/libgcc.s2.asm
index 743f11f8..a9496aa9 100644
--- a/stage23/lib/libgcc.s2.asm
+++ b/stage23/lib/libgcc.s2.asm
@@ -55,3 +55,38 @@ __divmoddi4:
mov dword [ecx+4], 0
xor edx, edx
ret
+
+global memcpy32to64
+memcpy32to64:
+bits 32
+ push ebp
+ mov ebp, esp
+
+ push esi
+ push edi
+
+ push 0x28
+ call .p1
+ .p1:
+ add dword [esp], .mode64 - .p1
+ retfd
+
+bits 64
+ .mode64:
+ mov rdi, [rbp + 8]
+ mov rsi, [rbp + 16]
+ mov rcx, [rbp + 24]
+ rep movsb
+
+ push 0x18
+ call .p2
+ .p2:
+ add qword [rsp], .mode32 - .p2
+ retfq
+
+bits 32
+ .mode32:
+ pop edi
+ pop esi
+ pop ebp
+ ret
diff --git a/stage23/lib/print.s2.c b/stage23/lib/print.s2.c
index 05c8cd45..8f83e83e 100644
--- a/stage23/lib/print.s2.c
+++ b/stage23/lib/print.s2.c
@@ -184,7 +184,7 @@ void vprint(const char *fmt, va_list args) {
}
out:
- term_write(print_buf, print_buf_i);
+ term_write((uint64_t)(uintptr_t)print_buf, print_buf_i);
for (size_t i = 0; i < print_buf_i; i++) {
if (E9_OUTPUT) {
diff --git a/stage23/lib/readline.c b/stage23/lib/readline.c
index 7b58729e..bd4a5525 100644
--- a/stage23/lib/readline.c
+++ b/stage23/lib/readline.c
@@ -143,98 +143,3 @@ again:
return ret;
}
#endif
-
-static void reprint_string(int x, int y, const char *s) {
- int orig_x, orig_y;
- disable_cursor();
- get_cursor_pos(&orig_x, &orig_y);
- set_cursor_pos(x, y);
- term_write(s, strlen(s));
- set_cursor_pos(orig_x, orig_y);
- enable_cursor();
-}
-
-static void cursor_back(void) {
- int x, y;
- get_cursor_pos(&x, &y);
- if (x) {
- x--;
- } else if (y) {
- y--;
- x = term_cols - 1;
- }
- set_cursor_pos(x, y);
-}
-
-static void cursor_fwd(void) {
- int x, y;
- get_cursor_pos(&x, &y);
- if (x < term_cols - 1) {
- x++;
- } else if (y < term_rows - 1) {
- y++;
- x = 0;
- }
- set_cursor_pos(x, y);
-}
-
-void readline(const char *orig_str, char *buf, size_t limit) {
- size_t orig_str_len = strlen(orig_str);
- memmove(buf, orig_str, orig_str_len);
- buf[orig_str_len] = 0;
-
- int orig_x, orig_y;
- get_cursor_pos(&orig_x, &orig_y);
-
- term_write(orig_str, orig_str_len);
-
- for (size_t i = orig_str_len; ; ) {
- int c = getchar();
- switch (c) {
- case GETCHAR_CURSOR_LEFT:
- if (i) {
- i--;
- cursor_back();
- }
- continue;
- case GETCHAR_CURSOR_RIGHT:
- if (i < strlen(buf)) {
- i++;
- cursor_fwd();
- }
- continue;
- case '\b':
- if (i) {
- i--;
- cursor_back();
- case GETCHAR_DELETE:;
- size_t j;
- for (j = i; ; j++) {
- buf[j] = buf[j+1];
- if (!buf[j]) {
- buf[j] = ' ';
- break;
- }
- }
- reprint_string(orig_x, orig_y, buf);
- buf[j] = 0;
- }
- continue;
- case '\n':
- term_write("\n", 1);
- return;
- default:
- if (strlen(buf) < limit - 1) {
- for (size_t j = strlen(buf); ; j--) {
- buf[j+1] = buf[j];
- if (j == i)
- break;
- }
- buf[i] = c;
- i++;
- cursor_fwd();
- reprint_string(orig_x, orig_y, buf);
- }
- }
- }
-}
diff --git a/stage23/lib/term.c b/stage23/lib/term.c
index b5124a36..2ed68b69 100644
--- a/stage23/lib/term.c
+++ b/stage23/lib/term.c
@@ -8,7 +8,7 @@
bool early_term = false;
-void term_vbe(int width, int height) {
+void term_vbe(size_t width, size_t height) {
term_backend = NOT_READY;
if (!gterm_init(&term_rows, &term_cols, width, height)) {
@@ -19,6 +19,8 @@ void term_vbe(int width, int height) {
return;
}
+ term_reinit();
+
raw_putchar = gterm_putchar;
clear = gterm_clear;
enable_cursor = gterm_enable_cursor;
@@ -34,6 +36,8 @@ void term_vbe(int width, int height) {
scroll_disable = gterm_scroll_disable;
scroll_enable = gterm_scroll_enable;
term_move_character = gterm_move_character;
+ term_scroll = gterm_scroll;
+ term_swap_palette = gterm_swap_palette;
term_double_buffer = gterm_double_buffer;
term_double_buffer_flush = gterm_double_buffer_flush;
diff --git a/stage23/lib/term.h b/stage23/lib/term.h
index d95f3500..ea8dd2d4 100644
--- a/stage23/lib/term.h
+++ b/stage23/lib/term.h
@@ -2,45 +2,88 @@
#define __LIB__TERM_H__
#include <stddef.h>
+#include <stdint.h>
#include <stdbool.h>
#include <lib/image.h>
+#define TERM_TABSIZE (8)
+#define MAX_ESC_VALUES (16)
+
+extern struct term_context {
+ bool control_sequence;
+ bool csi;
+ bool escape;
+ bool rrr;
+ bool discard_next;
+ bool bold;
+ bool reverse_video;
+ bool dec_private;
+ bool insert_mode;
+ uint8_t g_select;
+ uint8_t charsets[2];
+ size_t current_charset;
+ size_t escape_offset;
+ size_t esc_values_i;
+ size_t saved_cursor_x;
+ size_t saved_cursor_y;
+ size_t current_primary;
+ size_t scroll_top_margin;
+ size_t scroll_bottom_margin;
+ uint32_t esc_values[MAX_ESC_VALUES];
+} term_context;
+
+enum {
+ NOT_READY,
+ VBE,
+ TEXTMODE
+};
+
+extern int current_video_mode;
+extern int term_backend;
+extern size_t term_rows, term_cols;
+extern bool term_runtime;
+extern bool early_term;
+
+void term_reinit(void);
+void term_deinit(void);
+void term_vbe(size_t width, size_t height);
+void term_textmode(void);
+void term_putchar(uint8_t c);
+void term_write(uint64_t buf, uint64_t count);
+
extern void (*raw_putchar)(uint8_t c);
extern void (*clear)(bool move);
extern void (*enable_cursor)(void);
extern bool (*disable_cursor)(void);
-extern void (*set_cursor_pos)(int x, int y);
-extern void (*get_cursor_pos)(int *x, int *y);
-extern void (*set_text_fg)(int fg);
-extern void (*set_text_bg)(int bg);
-extern void (*set_text_fg_bright)(int fg);
-extern void (*set_text_bg_bright)(int bg);
+extern void (*set_cursor_pos)(size_t x, size_t y);
+extern void (*get_cursor_pos)(size_t *x, size_t *y);
+extern void (*set_text_fg)(size_t fg);
+extern void (*set_text_bg)(size_t bg);
+extern void (*set_text_fg_bright)(size_t fg);
+extern void (*set_text_bg_bright)(size_t bg);
extern void (*set_text_fg_default)(void);
extern void (*set_text_bg_default)(void);
extern bool (*scroll_disable)(void);
extern void (*scroll_enable)(void);
-extern void (*term_move_character)(int new_x, int new_y, int old_x, int old_y);
+extern void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
+extern void (*term_scroll)(void);
+extern void (*term_swap_palette)(void);
extern void (*term_double_buffer)(bool status);
extern void (*term_double_buffer_flush)(void);
-void term_vbe(int width, int height);
-void term_textmode(void);
-void term_write(const char *buf, size_t count);
+extern uint64_t (*term_context_size)(void);
+extern void (*term_context_save)(uint64_t ptr);
+extern void (*term_context_restore)(uint64_t ptr);
-void term_deinit(void);
+#define TERM_CB_DEC 10
+#define TERM_CB_BELL 20
+#define TERM_CB_PRIVATE_ID 30
-extern int term_rows, term_cols;
+#define TERM_CTX_SIZE ((uint64_t)(-1))
+#define TERM_CTX_SAVE ((uint64_t)(-2))
+#define TERM_CTX_RESTORE ((uint64_t)(-3))
-enum {
- NOT_READY,
- VBE,
- TEXTMODE
-};
-
-extern int term_backend;
-extern int current_video_mode;
-
-extern bool early_term;
+extern void (*term_callback)(uint64_t type, uint64_t extra, uint64_t esc_val_count, uint64_t esc_values);
#endif
diff --git a/stage23/lib/term.s2.c b/stage23/lib/term.s2.c
index a89e4ea1..26a8f9da 100644
--- a/stage23/lib/term.s2.c
+++ b/stage23/lib/term.s2.c
@@ -6,37 +6,93 @@
#include <lib/image.h>
#include <lib/blib.h>
#include <drivers/vga_textmode.h>
+#include <lib/print.h>
// Tries to implement this standard for terminfo
// https://man7.org/linux/man-pages/man4/console_codes.4.html
-#define TERM_TABSIZE (8)
-#define MAX_ESC_VALUES (256)
-
int current_video_mode = -1;
-
int term_backend = NOT_READY;
+size_t term_rows, term_cols;
+bool term_runtime = false;
+
+static bool old_cur_stat;
void (*raw_putchar)(uint8_t c);
void (*clear)(bool move);
void (*enable_cursor)(void);
bool (*disable_cursor)(void);
-void (*set_cursor_pos)(int x, int y);
-void (*get_cursor_pos)(int *x, int *y);
-void (*set_text_fg)(int fg);
-void (*set_text_bg)(int bg);
-void (*set_text_fg_bright)(int fg);
-void (*set_text_bg_bright)(int bg);
+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)(int new_x, int new_y, int old_x, int old_y);
+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_swap_palette)(void);
void (*term_double_buffer)(bool status);
void (*term_double_buffer_flush)(void);
-int term_rows, term_cols;
+uint64_t (*term_context_size)(void);
+void (*term_context_save)(uint64_t ptr);
+void (*term_context_restore)(uint64_t ptr);
+
+void (*term_callback)(uint64_t type, uint64_t extra, uint64_t esc_val_count, uint64_t esc_values) = 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 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;
+}
#if bios == 1
void term_textmode(void) {
@@ -44,6 +100,8 @@ void term_textmode(void) {
init_vga_textmode(&term_rows, &term_cols, true);
+ term_reinit();
+
raw_putchar = text_putchar;
clear = text_clear;
enable_cursor = text_enable_cursor;
@@ -52,17 +110,23 @@ void term_textmode(void) {
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;
+ set_text_fg_bright = text_set_text_fg_bright;
set_text_bg_bright = text_set_text_bg;
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_swap_palette = text_swap_palette;
term_double_buffer = text_double_buffer;
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_backend = TEXTMODE;
}
#endif
@@ -71,41 +135,86 @@ void term_deinit(void) {
term_backend = NOT_READY;
}
-static void term_putchar(uint8_t c);
+static uint64_t context_size(void) {
+ uint64_t ret = 0;
-static bool old_cur_stat;
+ ret += sizeof(struct term_context);
+ ret += term_context_size();
-void term_write(const char *buf, size_t count) {
- if (term_backend == NOT_READY)
- return;
- old_cur_stat = disable_cursor();
- for (size_t i = 0; i < count; i++)
- term_putchar(buf[i]);
- if (old_cur_stat)
- enable_cursor();
+ return ret;
}
-static int get_cursor_pos_x(void) {
- int x, y;
- get_cursor_pos(&x, &y);
- return x;
+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 int get_cursor_pos_y(void) {
- int x, y;
- get_cursor_pos(&x, &y);
- return y;
+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);
}
-static bool control_sequence = false;
-static bool escape = false;
-static bool rrr = false;
-static bool bold = false;
-static bool dec_private = false;
-static int32_t esc_values[MAX_ESC_VALUES];
-static size_t esc_values_i = 0;
-static int saved_cursor_x = 0, saved_cursor_y = 0;
-static int current_fg = -1;
+#if defined (__i386__)
+#define TERM_XFER_CHUNK 8192
+
+static char xfer_buf[TERM_XFER_CHUNK];
+#endif
+
+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;
+ }
+ }
+
+ bool native = false;
+#if defined (__x86_64__)
+ native = true;
+#endif
+
+ if (!term_runtime || native) {
+ const char *s = (const char *)(uintptr_t)buf;
+
+ old_cur_stat = disable_cursor();
+ for (size_t i = 0; i < count; i++)
+ term_putchar(s[i]);
+ if (old_cur_stat)
+ enable_cursor();
+ } else {
+#if defined (__i386__)
+ while (count != 0) {
+ uint64_t chunk = count % TERM_XFER_CHUNK;
+ memcpy32to64((uint64_t)(uintptr_t)xfer_buf, buf, chunk);
+
+ old_cur_stat = disable_cursor();
+ for (size_t i = 0; i < chunk; i++)
+ term_putchar(xfer_buf[i]);
+ if (old_cur_stat)
+ enable_cursor();
+
+ count -= chunk;
+ buf += chunk;
+ }
+#endif
+ }
+}
static void sgr(void) {
size_t i = 0;
@@ -114,65 +223,144 @@ static void sgr(void) {
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_fg = -1;
+ current_primary = (size_t)-1;
set_text_bg_default();
set_text_fg_default();
continue;
}
- if (esc_values[i] == 1) {
+ else if (esc_values[i] == 1) {
bold = true;
- if (current_fg != -1) {
- set_text_fg_bright(current_fg);
+ if (current_primary != (size_t)-1) {
+ if (!reverse_video) {
+ set_text_fg_bright(current_primary);
+ } else {
+ set_text_bg_bright(current_primary);
+ }
}
continue;
}
- if (esc_values[i] == 22) {
+ else if (esc_values[i] == 22) {
bold = false;
- if (current_fg != -1) {
- set_text_fg(current_fg);
+ if (current_primary != (size_t)-1) {
+ if (!reverse_video) {
+ set_text_fg(current_primary);
+ } else {
+ set_text_bg(current_primary);
+ }
}
continue;
}
- if (esc_values[i] >= 30 && esc_values[i] <= 37) {
- current_fg = esc_values[i] - 30;
- if (bold) {
- set_text_fg_bright(esc_values[i] - 30);
+ 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] - 30);
+ set_text_fg(esc_values[i] - offset);
}
continue;
}
- if (esc_values[i] >= 40 && esc_values[i] <= 47) {
- set_text_bg(esc_values[i] - 40);
+ 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;
}
- if (esc_values[i] >= 90 && esc_values[i] <= 97) {
- current_fg = esc_values[i] - 90;
- set_text_fg_bright(esc_values[i] - 90);
+ 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;
}
- if (esc_values[i] >= 100 && esc_values[i] <= 107) {
- set_text_bg_bright(esc_values[i] - 100);
+ 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;
}
- if (esc_values[i] == 39) {
- current_fg = -1;
+ 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;
}
- if (esc_values[i] == 49) {
+ 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;
}
}
@@ -181,100 +369,169 @@ def:
static void dec_private_parse(uint8_t c) {
dec_private = false;
- if (esc_values_i > 0) {
- switch (esc_values[0]) {
- case 25: {
- switch (c) {
- case 'h': old_cur_stat = true; return;
- case 'l': old_cur_stat = false; return;
- }
- }
- }
+ 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:
+ old_cur_stat = set; return;
+ }
+
+ if (term_callback != NULL)
+ term_callback(TERM_CB_DEC, c, esc_values_i, (uintptr_t)esc_values);
}
-static void control_sequence_parse(uint8_t c) {
- if (c == '?') {
- dec_private = true;
+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;
+ }
+}
+
+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;
- } else {
- if (rrr == true) {
- esc_values_i++;
- rrr = false;
- if (c == ';')
- return;
- } else if (c == ';') {
- esc_values[esc_values_i] = 1;
- esc_values_i++;
+ }
+
+ 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;
}
- int esc_default;
+ size_t esc_default;
switch (c) {
case 'J': esc_default = 0; break;
case 'K': esc_default = 0; break;
default: esc_default = 1; break;
}
- for (int i = esc_values_i; i < MAX_ESC_VALUES; i++)
+ 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 'A':
- if (esc_values[0] > get_cursor_pos_y())
- esc_values[0] = get_cursor_pos_y();
- set_cursor_pos(get_cursor_pos_x(), get_cursor_pos_y() - esc_values[0]);
+ 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 'B':
- if ((get_cursor_pos_y() + esc_values[0]) > (term_rows - 1))
- esc_values[0] = (term_rows - 1) - get_cursor_pos_y();
- set_cursor_pos(get_cursor_pos_x(), get_cursor_pos_y() + esc_values[0]);
+ }
+ case 'E':
+ x = 0;
+ // FALLTHRU
+ 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 'C':
- if ((get_cursor_pos_x() + esc_values[0]) > (term_cols - 1))
- esc_values[0] = (term_cols - 1) - get_cursor_pos_x();
- set_cursor_pos(get_cursor_pos_x() + esc_values[0], get_cursor_pos_y());
+ 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] > get_cursor_pos_x())
- esc_values[0] = get_cursor_pos_x();
- set_cursor_pos(get_cursor_pos_x() - esc_values[0], get_cursor_pos_y());
- break;
- case 'E':
- if (get_cursor_pos_y() + esc_values[0] >= term_rows)
- set_cursor_pos(0, term_rows - 1);
- else
- set_cursor_pos(0, get_cursor_pos_y() + esc_values[0]);
- break;
- case 'F':
- if (get_cursor_pos_y() - esc_values[0] < 0)
- set_cursor_pos(0, 0);
- else
- set_cursor_pos(0, get_cursor_pos_y() - esc_values[0]);
+ if (esc_values[0] > x)
+ esc_values[0] = x;
+ set_cursor_pos(x - esc_values[0], y);
break;
case 'd':
+ esc_values[0] -= 1;
if (esc_values[0] >= term_rows)
- break;
- set_cursor_pos(get_cursor_pos_x(), esc_values[0]);
+ 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)
- break;
- set_cursor_pos(esc_values[0], get_cursor_pos_y());
+ esc_values[0] = term_cols - 1;
+ set_cursor_pos(esc_values[0], y);
break;
case 'H':
case 'f':
@@ -289,31 +546,23 @@ static void control_sequence_parse(uint8_t c) {
case 'J':
switch (esc_values[0]) {
case 0: {
- int x, y;
- get_cursor_pos(&x, &y);
- int rows_remaining = term_rows - (y + 1);
- int cols_diff = term_cols - (x + 1);
+ 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;
- bool r = scroll_disable();
for (size_t i = 0; i < to_clear; i++) {
raw_putchar(' ');
}
set_cursor_pos(x, y);
- if (r)
- scroll_enable();
break;
}
case 1: {
- int x, y;
- get_cursor_pos(&x, &y);
- bool r = scroll_disable();
set_cursor_pos(0, 0);
bool b = false;
- for (int yc = 0; yc < term_rows; yc++) {
- for (int xc = 0; xc < term_cols; xc++) {
+ 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) {
- raw_putchar('\b');
+ set_cursor_pos(x, y);
b = true;
break;
}
@@ -321,31 +570,33 @@ static void control_sequence_parse(uint8_t c) {
if (b == true)
break;
}
- if (r)
- scroll_enable();
break;
}
case 2:
+ case 3:
clear(false);
break;
- default:
+ }
+ 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': {
- bool r = scroll_disable();
- int x, y;
- get_cursor_pos(&x, &y);
- for (int i = x + esc_values[0]; i < term_cols; i++)
+ 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);
- for (int i = 0; i < esc_values[0]; i++)
+ for (size_t i = 0; i < esc_values[0]; i++)
raw_putchar(' ');
set_cursor_pos(x, y);
- if (r)
- scroll_enable();
break;
- }
case 'm':
sgr();
break;
@@ -355,89 +606,253 @@ static void control_sequence_parse(uint8_t c) {
case 'u':
set_cursor_pos(saved_cursor_x, saved_cursor_y);
break;
- case 'K': {
- bool r = scroll_disable();
- int x, y;
- get_cursor_pos(&x, &y);
+ case 'K':
switch (esc_values[0]) {
case 0: {
- for (int i = x; i < term_cols; i++)
+ 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 (int i = 0; i < x; i++)
+ for (size_t i = 0; i < x; i++)
raw_putchar(' ');
break;
}
case 2: {
set_cursor_pos(0, y);
- for (int i = 0; i < term_cols; i++)
+ for (size_t i = 0; i < term_cols; i++)
raw_putchar(' ');
set_cursor_pos(x, y);
break;
}
}
- if (r)
- scroll_enable();
break;
- }
- default:
+ case 'r':
+ scroll_top_margin = 0;
+ scroll_bottom_margin = 0;
+ 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 >= (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;
}
+ if (r)
+ scroll_enable();
+
cleanup:
control_sequence = false;
escape = false;
}
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 '\e':
- escape = false;
- raw_putchar(c);
- break;
case '[':
- for (int i = 0; i < MAX_ESC_VALUES; i++)
+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 'c':
+ term_reinit();
+ clear(true);
break;
- default:
- escape = false;
+ 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"
+ set_cursor_pos(x, y - 1);
+ break;
+ case 'Z':
+ 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;
}
-static void term_putchar(uint8_t c) {
+void term_putchar(uint8_t c) {
+ if (discard_next || 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 '\0':
- break;
+ case 0x7f:
+ return;
+ case 0x9b:
+ csi = true;
+ // FALLTHRU
case '\e':
- escape = 1;
+ escape_offset = 0;
+ escape = true;
return;
case '\t':
- if ((get_cursor_pos_x() / TERM_TABSIZE + 1) >= term_cols)
- break;
- set_cursor_pos((get_cursor_pos_x() / TERM_TABSIZE + 1) * TERM_TABSIZE, get_cursor_pos_y());
- break;
+ 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;
- default:
- raw_putchar(c);
- break;
+ case CHARSET_DEC_SPECIAL:
+ c = dec_special_to_cp437(c);
}
+
+ raw_putchar(c);
}
diff --git a/stage23/menu.c b/stage23/menu.c
index ef270cb5..c5ce73cb 100644
--- a/stage23/menu.c
+++ b/stage23/menu.c
@@ -117,7 +117,7 @@ static int validate_line(const char *buffer) {
if (buffer[0] == '#')
return TOK_COMMENT;
char keybuf[64];
- int i;
+ size_t i;
for (i = 0; buffer[i] && i < 64; i++) {
if (buffer[i] == '=') goto found_equals;
keybuf[i] = buffer[i];
@@ -176,7 +176,7 @@ refresh:
clear(true);
disable_cursor();
{
- int x, y;
+ size_t x, y;
print("\n");
get_cursor_pos(&x, &y);
set_cursor_pos(term_cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y);
@@ -187,7 +187,7 @@ refresh:
print(" \e[32mESC\e[0m Discard and Exit \e[32mF10\e[0m Boot\n");
print("\n\xda");
- for (int i = 0; i < term_cols - 2; i++) {
+ for (size_t i = 0; i < term_cols - 2; i++) {
switch (i) {
case 1: case 2: case 3:
if (window_offset > 0) {
@@ -196,7 +196,7 @@ refresh:
}
// FALLTHRU
default: {
- int title_length = strlen(title);
+ size_t title_length = strlen(title);
if (i == (term_cols / 2) - DIV_ROUNDUP(title_length, 2) - 1) {
print("%s", title);
i += title_length - 1;
@@ -208,7 +208,7 @@ refresh:
}
print("\xbf\xb3");
- int cursor_x, cursor_y;
+ size_t cursor_x, cursor_y;
size_t current_line = 0, line_offset = 0, window_size = _window_size;
bool printed_cursor = false;
int token_type = validate_line(buffer);
@@ -217,7 +217,7 @@ refresh:
if (buffer[i] == '\n'
&& current_line < window_offset + window_size
&& current_line >= window_offset) {
- int x, y;
+ size_t x, y;
get_cursor_pos(&x, &y);
if (i == cursor_offset) {
cursor_x = x;
@@ -305,7 +305,7 @@ refresh:
// syntax error alert
if (validation_enabled) {
- int x, y;
+ size_t x, y;
get_cursor_pos(&x, &y);
set_cursor_pos(0, term_rows-1);
scroll_disable();
@@ -319,7 +319,7 @@ refresh:
}
if (current_line - window_offset < window_size) {
- int x, y;
+ size_t x, y;
for (size_t i = 0; i < (window_size - (current_line - window_offset)) - 1; i++) {
get_cursor_pos(&x, &y);
set_cursor_pos(term_cols - 1, y);
@@ -330,7 +330,7 @@ refresh:
print("\xb3\xc0");
}
- for (int i = 0; i < term_cols - 2; i++) {
+ for (size_t i = 0; i < term_cols - 2; i++) {
switch (i) {
case 1: case 2: case 3:
if (current_line - window_offset >= window_size) {
@@ -419,10 +419,10 @@ refresh:
goto refresh;
}
-static int print_tree(const char *shift, int level, int base_index, int selected_entry,
+static size_t print_tree(const char *shift, size_t level, size_t base_index, size_t selected_entry,
struct menu_entry *current_entry,
struct menu_entry **selected_menu_entry) {
- int max_entries = 0;
+ size_t max_entries = 0;
bool no_print = false;
if (shift == NULL) {
@@ -434,15 +434,18 @@ static int print_tree(const char *shift, int level, int base_index, int selected
break;
if (!no_print) print("%s", shift);
if (level) {
- for (int i = level - 1; i > 0; i--) {
+ for (size_t i = level - 1; ; i--) {
struct menu_entry *actual_parent = current_entry;
- for (int j = 0; j < i; j++)
+ for (size_t j = 0; j < i; j++)
actual_parent = actual_parent->parent;
if (actual_parent->next != NULL) {
if (!no_print) print(" \xb3");
} else {
if (!no_print) print(" ");
}
+ if (i == 0) {
+ break;
+ }
}
if (current_entry->next == NULL) {
if (!no_print) print(" \xc0");
@@ -482,7 +485,7 @@ char *menu(char **cmdline) {
bool skip_timeout = false;
struct menu_entry *selected_menu_entry = NULL;
- int selected_entry = 0;
+ size_t selected_entry = 0;
char *default_entry = config_get_value(NULL, 0, "DEFAULT_ENTRY");
if (default_entry != NULL) {
selected_entry = strtoui(default_entry, NULL, 10);
@@ -490,7 +493,7 @@ char *menu(char **cmdline) {
selected_entry--;
}
- int timeout = 5;
+ size_t timeout = 5;
char *timeout_config = config_get_value(NULL, 0, "TIMEOUT");
if (timeout_config != NULL) {
if (!strcmp(timeout_config, "no"))
@@ -522,7 +525,7 @@ char *menu(char **cmdline) {
char *graphics = "yes";
#endif
if (graphics != NULL && !strcmp(graphics, "yes")) {
- int req_width = 0, req_height = 0, req_bpp = 0;
+ size_t req_width = 0, req_height = 0, req_bpp = 0;
char *menu_resolution = config_get_value(NULL, 0, "MENU_RESOLUTION");
if (menu_resolution != NULL)
@@ -538,7 +541,7 @@ char *menu(char **cmdline) {
refresh:
clear(true);
{
- int x, y;
+ size_t x, y;
print("\n");
get_cursor_pos(&x, &y);
set_cursor_pos(term_cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y);
@@ -563,16 +566,16 @@ refresh:
}
{ // Draw box around boot menu
- int x, y;
+ size_t x, y;
get_cursor_pos(&x, &y);
print("\xda");
- for (int i = 0; i < term_cols - 2; i++) {
+ for (size_t i = 0; i < term_cols - 2; i++) {
print("\xc4");
}
print("\xbf");
- for (int i = y + 1; i < term_rows - 2; i++) {
+ for (size_t i = y + 1; i < term_rows - 2; i++) {
set_cursor_pos(0, i);
print("\xb3");
set_cursor_pos(term_cols - 1, i);
@@ -580,7 +583,7 @@ refresh:
}
print("\xc0");
- for (int i = 0; i < term_cols - 2; i++) {
+ for (size_t i = 0; i < term_cols - 2; i++) {
print("\xc4");
}
print("\xd9");
@@ -588,11 +591,11 @@ refresh:
set_cursor_pos(x, y + 2);
}
- int max_entries = print_tree("\xb3 ", 0, 0, selected_entry, menu_tree,
+ size_t max_entries = print_tree("\xb3 ", 0, 0, selected_entry, menu_tree,
&selected_menu_entry);
{
- int x, y;
+ size_t x, y;
get_cursor_pos(&x, &y);
set_cursor_pos(0, 3);
if (editor_enabled && selected_menu_entry->sub == NULL) {
@@ -611,7 +614,7 @@ refresh:
if (skip_timeout == false) {
print("\n\n");
- for (int i = timeout; i; i--) {
+ for (size_t i = timeout; i; i--) {
set_cursor_pos(0, term_rows - 1);
scroll_disable();
print("\e[32mBooting automatically in \e[92m%u\e[32m, press any key to stop the countdown...\e[0m", i);
@@ -641,8 +644,10 @@ refresh:
timeout_aborted:
switch (c) {
case GETCHAR_CURSOR_UP:
- if (--selected_entry == -1)
+ if (selected_entry == 0)
selected_entry = max_entries - 1;
+ else
+ selected_entry--;
goto refresh;
case GETCHAR_CURSOR_DOWN:
if (++selected_entry == max_entries)
diff --git a/stage23/protos/chainload.c b/stage23/protos/chainload.c
index a0f2bd92..1e3fb648 100644
--- a/stage23/protos/chainload.c
+++ b/stage23/protos/chainload.c
@@ -97,7 +97,7 @@ void chainload(char *config) {
drive = val;
}
- int rows, cols;
+ size_t rows, cols;
init_vga_textmode(&rows, &cols, false);
struct volume *p = volume_get_by_coord(false, drive, part);
@@ -131,7 +131,7 @@ void chainload(char *config) {
term_deinit();
- int req_width = 0, req_height = 0, req_bpp = 0;
+ size_t req_width = 0, req_height = 0, req_bpp = 0;
char *resolution = config_get_value(config, 0, "RESOLUTION");
if (resolution != NULL)
diff --git a/stage23/protos/linux.c b/stage23/protos/linux.c
index f8e001ed..d8dc1038 100644
--- a/stage23/protos/linux.c
+++ b/stage23/protos/linux.c
@@ -488,7 +488,7 @@ void linux_load(char *config, char *cmdline) {
struct screen_info *screen_info = &boot_params->screen_info;
- int req_width = 0, req_height = 0, req_bpp = 0;
+ size_t req_width = 0, req_height = 0, req_bpp = 0;
char *resolution = config_get_value(config, 0, "RESOLUTION");
if (resolution != NULL)
diff --git a/stage23/protos/multiboot1.c b/stage23/protos/multiboot1.c
index 4541be13..d89780b0 100644
--- a/stage23/protos/multiboot1.c
+++ b/stage23/protos/multiboot1.c
@@ -180,9 +180,9 @@ void multiboot1_load(char *config, char *cmdline) {
term_deinit();
if (header.flags & (1 << 2)) {
- int req_width = header.fb_width;
- int req_height = header.fb_height;
- int req_bpp = header.fb_bpp;
+ size_t req_width = header.fb_width;
+ size_t req_height = header.fb_height;
+ size_t req_bpp = header.fb_bpp;
if (header.fb_mode == 0) {
char *resolution = config_get_value(config, 0, "RESOLUTION");
@@ -209,7 +209,7 @@ void multiboot1_load(char *config, char *cmdline) {
#if uefi == 1
panic("multiboot1: Cannot use text mode with UEFI.");
#elif bios == 1
- int rows, cols;
+ size_t rows, cols;
init_vga_textmode(&rows, &cols, false);
multiboot1_info.fb_addr = 0xB8000;
@@ -228,7 +228,7 @@ void multiboot1_load(char *config, char *cmdline) {
#if uefi == 1
panic("multiboot1: Cannot use text mode with UEFI.");
#elif bios == 1
- int rows, cols;
+ size_t rows, cols;
init_vga_textmode(&rows, &cols, false);
#endif
}
diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index 0f6224d0..03b0e7b2 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -249,9 +249,9 @@ void stivale_load(char *config, char *cmdline) {
term_deinit();
if (stivale_hdr.flags & (1 << 0)) {
- int req_width = stivale_hdr.framebuffer_width;
- int req_height = stivale_hdr.framebuffer_height;
- int req_bpp = stivale_hdr.framebuffer_bpp;
+ size_t req_width = stivale_hdr.framebuffer_width;
+ size_t req_height = stivale_hdr.framebuffer_height;
+ size_t req_bpp = stivale_hdr.framebuffer_bpp;
char *resolution = config_get_value(config, 0, "RESOLUTION");
if (resolution != NULL)
@@ -281,7 +281,7 @@ void stivale_load(char *config, char *cmdline) {
#if uefi == 1
panic("stivale: Cannot use text mode with UEFI.");
#elif bios == 1
- int rows, cols;
+ size_t rows, cols;
init_vga_textmode(&rows, &cols, false);
#endif
}
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index 945f962c..414906d2 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -57,7 +57,8 @@ static void *get_tag(struct stivale2_header *s, uint64_t id) {
#if defined (__i386__)
extern symbol stivale2_term_write_entry;
void *stivale2_rt_stack = NULL;
-void *stivale2_term_buf = NULL;
+uint64_t stivale2_term_callback_ptr = 0;
+void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t);
#endif
void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table) {
@@ -381,7 +382,7 @@ failed_to_load_header_section:
struct stivale2_header_tag_framebuffer *hdrtag = get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_FRAMEBUFFER_ID);
- int req_width = 0, req_height = 0, req_bpp = 0;
+ size_t req_width = 0, req_height = 0, req_bpp = 0;
if (hdrtag != NULL) {
req_width = hdrtag->framebuffer_width;
@@ -393,20 +394,42 @@ failed_to_load_header_section:
parse_resolution(&req_width, &req_height, &req_bpp, resolution);
}
+ char *textmode_str = config_get_value(config, 0, "TEXTMODE");
+ bool textmode = textmode_str != NULL && strcmp(textmode_str, "yes") == 0;
+
struct stivale2_header_tag_terminal *terminal_hdr_tag = get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_TERMINAL_ID);
- if (bits == 64 && terminal_hdr_tag != NULL && hdrtag != NULL) {
- term_vbe(req_width, req_height);
+ if (bits == 64 && terminal_hdr_tag != NULL && (hdrtag != NULL || textmode)) {
+ if (textmode) {
+#if bios == 1
+ term_textmode();
+#elif uefi == 1
+ panic("stivale2: Text mode not supported on UEFI");
+#endif
+ } else {
+ term_vbe(req_width, req_height);
- if (current_video_mode < 0) {
- panic("stivale2: Failed to initialise terminal");
- }
+ if (current_video_mode < 0) {
+ panic("stivale2: Failed to initialise terminal");
+ }
- fb = &fbinfo;
+ fb = &fbinfo;
+ }
struct stivale2_struct_tag_terminal *tag = ext_mem_alloc(sizeof(struct stivale2_struct_tag_terminal));
tag->tag.identifier = STIVALE2_STRUCT_TAG_TERMINAL_ID;
+ if (terminal_hdr_tag->flags & (1 << 0)) {
+ // We provide callback
+ tag->flags |= (1 << 2);
+#if defined (__i386__)
+ term_callback = stivale2_term_callback;
+ stivale2_term_callback_ptr = terminal_hdr_tag->callback;
+#elif defined (__x86_64__)
+ term_callback = (void *)terminal_hdr_tag->callback;
+#endif
+ }
+
// We provide max allowed string length
tag->flags |= (1 << 1);
@@ -415,15 +438,13 @@ failed_to_load_header_section:
stivale2_rt_stack = ext_mem_alloc(8192);
}
- stivale2_term_buf = ext_mem_alloc(8192);
-
tag->term_write = (uintptr_t)(void *)stivale2_term_write_entry;
- tag->max_length = 8192;
#elif defined (__x86_64__)
tag->term_write = (uintptr_t)term_write;
- tag->max_length = 0;
#endif
+ tag->max_length = 0;
+
// We provide rows and cols
tag->flags |= (1 << 0);
tag->cols = term_cols;
@@ -431,7 +452,13 @@ failed_to_load_header_section:
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
- goto skip_modeset;
+ if (textmode) {
+#if bios == 1
+ goto have_tm_tag;
+#endif
+ } else {
+ goto have_fb_tag;
+ }
} else {
fb = &_fb;
}
@@ -441,7 +468,7 @@ failed_to_load_header_section:
term_deinit();
if (fb_init(fb, req_width, req_height, req_bpp)) {
-skip_modeset:;
+have_fb_tag:;
struct stivale2_struct_tag_framebuffer *tag = ext_mem_alloc(sizeof(struct stivale2_struct_tag_framebuffer));
tag->tag.identifier = STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID;
@@ -468,9 +495,10 @@ skip_modeset:;
#if uefi == 1
panic("stivale2: Cannot use text mode with UEFI.");
#elif bios == 1
- int rows, cols;
+ size_t rows, cols;
init_vga_textmode(&rows, &cols, false);
+have_tm_tag:;
struct stivale2_struct_tag_textmode *tmtag = ext_mem_alloc(sizeof(struct stivale2_struct_tag_textmode));
tmtag->tag.identifier = STIVALE2_STRUCT_TAG_TEXTMODE_ID;
@@ -628,7 +656,9 @@ skip_modeset:;
}
// Clear terminal for kernels that will use the stivale2 terminal
- term_write("\e[2J\e[H", 7);
+ term_write((uint64_t)(uintptr_t)("\e[2J\e[H"), 7);
+
+ term_runtime = true;
stivale_spinup(bits, want_5lv, &pagemap, entry_point,
REPORTED_ADDR((uint64_t)(uintptr_t)&stivale2_struct),
diff --git a/stage23/protos/stivale2_rt.asm b/stage23/protos/stivale2_rt.asm
index 26517ca5..b5c05e8b 100644
--- a/stage23/protos/stivale2_rt.asm
+++ b/stage23/protos/stivale2_rt.asm
@@ -8,17 +8,64 @@ user_ds: resq 1
user_es: resq 1
user_ss: resq 1
-%define MAX_TERM_BUF 8192
-
section .text
extern term_write
-extern stivale2_term_buf
extern stivale2_rt_stack
+extern stivale2_term_callback_ptr
+
+global stivale2_term_callback
+stivale2_term_callback:
+bits 32
+ push ebp
+ mov ebp, esp
+
+ push ebx
+ push esi
+ push edi
+ ; Go 64
+ push 0x28
+ push .mode64
+ retfd
bits 64
+ .mode64:
+ mov eax, 0x30
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov rdi, [rbp + 8]
+ mov rsi, [rbp + 16]
+ mov rdx, [rbp + 24]
+ mov rcx, [rbp + 32]
+
+ mov rbx, rsp
+ mov rsp, [user_stack]
+ call [stivale2_term_callback_ptr]
+ mov rsp, rbx
+
+ ; Go 32
+ push 0x18
+ push .mode32
+ retfq
+bits 32
+ .mode32:
+ mov eax, 0x20
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+
+ ret
+
global stivale2_term_write_entry
stivale2_term_write_entry:
+bits 64
push rbx
push rbp
push r12
@@ -35,14 +82,7 @@ stivale2_term_write_entry:
mov word [user_ss], ss
push rsi
- mov rcx, rsi
- mov rax, MAX_TERM_BUF
- cmp rcx, rax
- cmovg rcx, rax
- mov rsi, rdi
- mov edi, [stivale2_term_buf]
- rep movsb
- pop rsi
+ push rdi
push 0x18
push .mode32
@@ -53,10 +93,10 @@ bits 32
mov ds, ax
mov es, ax
mov ss, ax
- push esi
- push dword [stivale2_term_buf]
+
call term_write
- add esp, 8
+ add esp, 16
+
push dword [user_cs]
push .mode64
retfd
diff --git a/stage23/protos/stivale2_rt.asm32 b/stage23/protos/stivale2_rt.asm32
index d39e5a3b..723a92aa 100644
--- a/stage23/protos/stivale2_rt.asm32
+++ b/stage23/protos/stivale2_rt.asm32
@@ -10,13 +10,69 @@ user_ds: resq 1
user_es: resq 1
user_ss: resq 1
-%define MAX_TERM_BUF 8192
-
section .text
extern term_write
-extern stivale2_term_buf
extern stivale2_rt_stack
+extern stivale2_term_callback_ptr
+
+global stivale2_term_callback
+stivale2_term_callback:
+bits 32
+ push ebp
+ mov ebp, esp
+
+ push ebx
+ push esi
+ push edi
+
+ ; Go 64
+ push 0x28
+ call .p1
+ .p1:
+ add dword [esp], .mode64 - .p1
+ retfd
+bits 64
+ .mode64:
+ mov eax, 0x30
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov rdi, [rbp + 8]
+ mov rsi, [rbp + 16]
+ mov rdx, [rbp + 24]
+ mov rcx, [rbp + 32]
+
+ call .get_got
+ .get_got:
+ pop rax
+ add rax, _GLOBAL_OFFSET_TABLE_ + $$ - .get_got wrt ..gotpc
+
+ mov rbx, rsp
+ mov rsp, [rax + user_stack wrt ..gotoff]
+ call [rax + stivale2_term_callback_ptr wrt ..gotoff]
+ mov rsp, rbx
+
+ ; Go 32
+ push 0x18
+ call .p2
+ .p2:
+ add qword [rsp], .mode32 - .p2
+ retfq
+bits 32
+ .mode32:
+ mov eax, 0x20
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+
+ ret
bits 64
global stivale2_term_write_entry
@@ -42,21 +98,12 @@ stivale2_term_write_entry:
mov word [rbx + user_ss wrt ..gotoff], ss
push rsi
- mov rcx, rsi
- mov rax, MAX_TERM_BUF
- cmp rcx, rax
- cmovg rcx, rax
- mov rsi, rdi
- mov edi, [rbx + stivale2_term_buf wrt ..gotoff]
- rep movsb
- pop rsi
+ push rdi
push 0x18
call .p1
.p1:
- pop rax
- add rax, 8
- push rax
+ add qword [rsp], .mode32 - .p1
retfq
bits 32
.mode32:
@@ -64,16 +111,14 @@ bits 32
mov ds, ax
mov es, ax
mov ss, ax
- push esi
- push dword [ebx + stivale2_term_buf wrt ..gotoff]
+
call term_write
- add esp, 8
+ add esp, 16
+
push dword [ebx + user_cs wrt ..gotoff]
call .p2
.p2:
- pop eax
- add eax, 6
- push eax
+ add dword [esp], .mode64 - .p2
retfd
bits 64
.mode64:
