From 57c5eceb846f3109d017b4e6d4cbd7c507c0d098 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Sat, 14 Mar 2015 16:16:53 +0100 Subject: Begin implement escape sequence handling in terminal. --- Makefile | 4 +- src/kernel/config.h | 1 + src/kernel/core/freemem.c | 2 + src/kernel/core/kmalloc.c | 10 ++- src/kernel/core/thread.c | 2 +- src/kernel/user/process.c | 2 + src/sysbin/shell/main.c | 4 +- src/sysbin/terminal/main.c | 209 +++++++++++++++++++++++++++++++++++---------- 8 files changed, 184 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 0304f5f..05b0372 100644 --- a/Makefile +++ b/Makefile @@ -30,10 +30,10 @@ cdrom.iso: all make_cdrom.sh ./make_cdrom.sh run_qemu: cdrom.iso - qemu-system-i386 -cdrom cdrom.iso -serial stdio -m 16 + qemu-system-i386 -cdrom cdrom.iso -serial stdio -m 12 run_qemu_debug: cdrom.iso - qemu-system-i386 -cdrom cdrom.iso -serial stdio -m 16 -s -S & \ + qemu-system-i386 -cdrom cdrom.iso -serial stdio -m 12 -s -S & \ (sleep 0.1; gdb src/kernel/kernel.bin -x gdb_cmd) run_bochs_debug: cdrom.iso diff --git a/src/kernel/config.h b/src/kernel/config.h index 4d5d01f..1792d52 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -31,5 +31,6 @@ #define SPAM_WAIT_RESUME_ON 0 // trace wait_on and resume_on calls #define SPAM_FS_REF 0 // show reference inc/dec on VFS items #define SPAM_BEGIN_EXIT 1 // trace thread creation/deletion && process begin/exit +#define SPAM_OOM_REASON 1 // print a message saying where we are when calling free_some_memory /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/core/freemem.c b/src/kernel/core/freemem.c index 153ec7a..18cc740 100644 --- a/src/kernel/core/freemem.c +++ b/src/kernel/core/freemem.c @@ -1,8 +1,10 @@ #include #include #include +#include void free_some_memory() { + dbg_print_frame_stats(); dbg_printf("Currently out of memory ; free_some_memory not implemented. Waiting.\n"); usleep(1000000); // Hope someone will do something... } diff --git a/src/kernel/core/kmalloc.c b/src/kernel/core/kmalloc.c index 53ac83c..95347b3 100644 --- a/src/kernel/core/kmalloc.c +++ b/src/kernel/core/kmalloc.c @@ -10,7 +10,14 @@ void* page_alloc_fun_for_kmalloc(size_t bytes) { void* addr = region_alloc(bytes, "Core kernel heap"); - if (addr == 0) return 0; + if (addr == 0) { + if (SPAM_OOM_REASON) { + dbg_printf("Could not allocate region for kmalloc.\n"); + dbg_print_frame_stats(); + dbg_print_region_info(); + } + return 0; + } // Map physical memory for (void* i = addr; i < addr + bytes; i += PAGE_SIZE) { @@ -74,6 +81,7 @@ void* malloc(size_t sz) { int tries = 0; while ((res = malloc0(sz)) == 0 && (tries++) < 3) { + if (SPAM_OOM_REASON) dbg_printf("OOM in kmalloc\n"); free_some_memory(); } diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index fab4eef..f2ddf9b 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -176,7 +176,7 @@ thread_t *new_thread(entry_t entry, void* data) { uint32_t f; int tries = 0; while ((f = frame_alloc(1)) == 0 && (tries++) < 3) { - dbg_printf("thread stack alloc OOM\n"); + if (SPAM_OOM_REASON) dbg_printf("OOM when allocating thread stack\n"); free_some_memory(); } if (f == 0) { diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index d96b486..7b0c351 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -794,11 +794,13 @@ void proc_usermem_pf(void* p, registers_t *regs, void* addr) { do { frame = pager_get_frame(r->pager, addr - r->addr + r->offset); if (frame == 0) { + if (SPAM_OOM_REASON) dbg_printf("Pager OOM\n"); free_some_memory(); } } while (frame == 0); while(!pd_map_page(addr, frame, (r->mode & MM_WRITE) != 0)) { + if (SPAM_OOM_REASON) dbg_printf("pd_map_page OOM\n"); free_some_memory(); } } diff --git a/src/sysbin/shell/main.c b/src/sysbin/shell/main.c index b093430..e35d700 100644 --- a/src/sysbin/shell/main.c +++ b/src/sysbin/shell/main.c @@ -53,9 +53,11 @@ int main(int argc, char **argv) { while(true) { char buf[256]; - printf("\n%s> ", getcwd(buf, 256)); + printf("\n\e[36m%s>\e[33m ", getcwd(buf, 256)); getline(buf, 256); + + printf("\e[39m"); if (!strncmp(buf, "cd ", 3)) { chdir(buf + 3); } else if (!strcmp(buf, "ls")) { diff --git a/src/sysbin/terminal/main.c b/src/sysbin/terminal/main.c index 1174305..f0e77e3 100644 --- a/src/sysbin/terminal/main.c +++ b/src/sysbin/terminal/main.c @@ -7,6 +7,27 @@ #include #include +#define NCOLORS 16 + +const int vga_colors[NCOLORS] = { + 0x000000, + 0x0000AA, + 0x00AA00, + 0x00AAAA, + 0xAA0000, + 0xAA00AA, + 0xAA5500, + 0xAAAAAA, + 0x555555, + 0x5555FF, + 0x55FF55, + 0x55FFFF, + 0xFF5555, + 0xFF55FF, + 0xFFFF55, + 0xFFFFFF, +}; + typedef char tchar_t; typedef struct { @@ -18,7 +39,12 @@ typedef struct { font_t *font; int cw, ch; // size of a character - color_t fg, bg; + + color_t colors[NCOLORS]; + color_t fg, bg, csr_bg; + + char esc_seq[10]; // current escape sequence + int esc_seq_len; // current escape sequence length keyboard_t *kb; @@ -32,16 +58,17 @@ typedef struct { char wr_c_buf; } term_t; -void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m); -void c_key_down(gip_handler_t *s, gip_msg_header *p); -void c_key_up(gip_handler_t *s, gip_msg_header *p); -void c_unknown_msg(gip_handler_t *s, gip_msg_header *p); -void c_fd_error(gip_handler_t *s); +void gip_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m); +void gip_key_down(gip_handler_t *s, gip_msg_header *p); +void gip_key_up(gip_handler_t *s, gip_msg_header *p); +void gip_unknown_msg(gip_handler_t *s, gip_msg_header *p); +void gip_fd_error(gip_handler_t *s); + +void gip_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata); void term_on_rd_c(mainloop_fd_t *fd); void term_app_on_error(mainloop_fd_t *fd); -void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata); gip_handler_callbacks_t term_gip_cb = { .reset = 0, @@ -52,13 +79,13 @@ gip_handler_callbacks_t term_gip_cb = { .disable_features = 0, .query_mode = 0, .set_mode = 0, - .buffer_info = c_buffer_info, + .buffer_info = gip_buffer_info, .mode_info = 0, .buffer_damage = 0, - .key_down = c_key_down, - .key_up = c_key_up, - .unknown_msg = c_unknown_msg, - .fd_error = c_fd_error, + .key_down = gip_key_down, + .key_up = gip_key_up, + .unknown_msg = gip_unknown_msg, + .fd_error = gip_fd_error, }; @@ -89,7 +116,7 @@ int main(int argc, char **argv) { mainloop_expect(&term.app, &term.rd_c_buf, 1, term_on_rd_c); gip_msg_header reset_msg = { .code = GIPC_RESET, .arg = 0 }; - gip_cmd(h, &reset_msg, 0, c_async_initiate, 0); + gip_cmd(h, &reset_msg, 0, gip_async_initiate, 0); mainloop_run(); @@ -100,7 +127,7 @@ int main(int argc, char **argv) { void term_draw_c(term_t *t, int l, int c) { color_t bg = t->bg; - if (l == t->csrl && c == t->csrc) bg = g_color_rgb(t->fb, 0, 100, 0); + if (l == t->csrl && c == t->csrc) bg = t->csr_bg; char ss[2]; ss[0] = t->scr_chars[l * t->w + c]; @@ -120,6 +147,13 @@ void term_move_cursor(term_t *t, int l, int c) { term_draw_c(t, l, c); } +void term_put_at(term_t *t, int l, int c, tchar_t ch) { + if (t->scr_chars[l * t->w + c] == ch) return; + + t->scr_chars[l * t->w + c] = ch; + term_draw_c(t, l, c); +} + void term_clear_screen(term_t *t) { t->csr_visible = true; @@ -146,32 +180,111 @@ void term_scroll1(term_t *t) { } void term_putc(term_t *t, int c) { - int nl = t->csrl, nc = t->csrc; - if (c == '\n') { - nl++; nc = 0; - } else if (c == '\b') { - if (nc > 0) { - nc--; - } else { + if (t->esc_seq_len > 0 || c == '\e') { + t->esc_seq[t->esc_seq_len++] = c; + + // parse escape sequence + if (t->esc_seq_len >= 2) { + if (t->esc_seq[1] == '[') { + int n = 0, m = -1; + int i = 2; + for (; i < t->esc_seq_len && t->esc_seq[i] >= '0' && t->esc_seq[i] <= '9'; i++) { + n = (n * 10) + (t->esc_seq[i] - '0'); + } + if (i == t->esc_seq_len) return; // incomplete sequence + if (t->esc_seq[i] == ';') { + i++; + m = 0; + for (; i < t->esc_seq_len && t->esc_seq[i] >= '0' && t->esc_seq[i] <= '9'; i++) { + m = (m * 10) + (t->esc_seq[i] - 0); + } + if (i == t->esc_seq_len) return; // incomplete sequence + } + // TODO implement escape sequence handling + if (t->esc_seq[i] == 'A') { + // move cursor up + } else if (t->esc_seq[i] == 'B') { + // move cursor down + } else if (t->esc_seq[i] == 'C') { + // move cursor forward + } else if (t->esc_seq[i] == 'D') { + // move cursor back + } else if (t->esc_seq[i] == 'E') { + // move cursor n lines down to begin of line + } else if (t->esc_seq[i] == 'F') { + // move cursor n lines up to begin of line + } else if (t->esc_seq[i] == 'H' || t->esc_seq[i] == 'f') { + // move cursor to position (n, m) + } else if (t->esc_seq[i] == 'J' || t->esc_seq[i] == 'K') { + // erase data/line + } else if (t->esc_seq[i] == 'S') { + // scroll up n lines + } else if (t->esc_seq[i] == 'T') { + // scroll down n lines + } else if (t->esc_seq[i] == 'm') { + // select graphic rendition (ie color) + if (n == 0) { + t->fg = t->colors[7]; + t->bg = t->colors[0]; + } else if (n >= 30 && n <= 37) { + t->fg = t->colors[n - 30]; + } else if (n == 39) { + t->fg = t->colors[7]; + } else if (n >= 40 && n <= 47) { + t->bg = t->colors[n - 40]; + } else if (n == 49) { + t->bg = t->colors[0]; + } + } else if (t->esc_seq[i] == 'n') { + // device status report + } else if (t->esc_seq[i] == 's') { + // save cursor position + } else if (t->esc_seq[i] == 'p') { + // restore cursor position + } + } + t->esc_seq_len = 0; // sequence finished + } + } else { + int nl = t->csrl, nc = t->csrc; + if (c == '\n') { + nl++; nc = 0; + } else if (c == '\r') { + while (nc > 0) { + nc--; + term_put_at(t, nl, nc, ' '); + } + nc = 0; + } else if (c == '\f') { + term_clear_screen(t); + return; + } else if (c == '\b') { + if (nc > 0) { + nc--; + } else { + nl--; + nc = t->w - 1; + } + term_put_at(t, nl, nc, ' '); + } else if (c == '\t') { + while (nc % 8 != 0) { + term_put_at(t, nl, nc, ' '); + nc++; + } + } else if (c >= ' ' && c < 128) { + term_put_at(t, nl, nc, c); + nc++; + } + if (nc >= t->w) { + nc = 0; + nl++; + } + if (nl >= t->h) { + term_scroll1(t); nl--; - nc = t->w - 1; } - t->scr_chars[nl * t->w + nc] = ' '; - } else if (c == '\t') { - while (nc % 4 != 0) nc++; - } else if (c >= ' ' && c < 128) { - t->scr_chars[nl * t->w + nc] = c; - nc++; - } - if (nc >= t->w) { - nc = 0; - nl++; + term_move_cursor(t, nl, nc); } - if (nl >= t->h) { - term_scroll1(t); - nl--; - } - term_move_cursor(t, nl, nc); } void term_puts(term_t *t, char* s) { @@ -183,7 +296,7 @@ void term_puts(term_t *t, char* s) { // GIP client connection -void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) { +void gip_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) { dbg_printf("[terminal] Got buffer info msg\n"); term_t *c = (term_t*)s->data; @@ -215,8 +328,14 @@ void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) c->fb = g_fb_from_file(c->fd, &m->geom); if (c->fb != 0) { - c->bg = g_color_rgb(c->fb, 0, 0, 0); - c->fg = g_color_rgb(c->fb, 200, 200, 200); + for (int i = 0; i < NCOLORS; i++) { + c->colors[i] = g_color_rgb(c->fb, (vga_colors[i] >> 16) & 0xFF, + (vga_colors[i] >> 8) & 0xFF, vga_colors[i] & 0xFF); + } + c->bg = c->colors[0]; + c->fg = c->colors[7]; + c->csr_bg = c->colors[2]; + term_clear_screen(c); mainloop_rm_fd(&c->app); @@ -228,7 +347,7 @@ void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) } } -void c_key_down(gip_handler_t *s, gip_msg_header *p) { +void gip_key_down(gip_handler_t *s, gip_msg_header *p) { term_t *c = (term_t*)s->data; key_t k = keyboard_press(c->kb, p->arg); @@ -244,17 +363,17 @@ void c_key_down(gip_handler_t *s, gip_msg_header *p) { mainloop_nonblocking_write(&c->app, &c->wr_c_buf, 1, false); } -void c_key_up(gip_handler_t *s, gip_msg_header *p) { +void gip_key_up(gip_handler_t *s, gip_msg_header *p) { term_t *c = (term_t*)s->data; keyboard_release(c->kb, p->arg); } -void c_unknown_msg(gip_handler_t *s, gip_msg_header *p) { +void gip_unknown_msg(gip_handler_t *s, gip_msg_header *p) { // TODO } -void c_fd_error(gip_handler_t *s) { +void gip_fd_error(gip_handler_t *s) { // TODO } @@ -268,7 +387,7 @@ void term_app_on_error(mainloop_fd_t *fd) { // TODO } -void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata) { +void gip_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata) { term_t *c = (term_t*)s->data; c->sv_features = p->arg; -- cgit v1.2.3