From 6ad90542ac516beafedf45530a3b77d1ff95c8b7 Mon Sep 17 00:00:00 2001 From: subhobhai943 Date: Tue, 18 Aug 2026 12:14:40 +0530 Subject: [PATCH] fix(userland): Fix 'clear' command, backspace keycodes (0x7F/0x08), serial keyboard input & make run target - Add 'clear' and 'cls' builtin handlers in LazyBox shell - Output ANSI \033[2J\033[H sequence on tty_clear() to clear serial/UART terminals - Support both ASCII 0x7F (DEL) and 0x08 (BS) for Backspace in shell and nano editor - Connect 16550 serial input to keyboard_get_key() on x86_64 for headless terminals - Add ANSI escape sequence decoding for arrow keys (Up/Down/Left/Right/Home/End/Del) - Update Makefile 'make run' and 'make qemu' with -display none for smooth terminal execution - Add 'make run-gui' target for optional graphical SDL/GTK window --- Makefile | 13 ++++++- drivers/char/keyboard.c | 82 +++++++++++++++++++++++++++++++++++---- drivers/char/tty.c | 31 +++++++++++---- include/config/autoconf.h | 4 +- kernel/main.c | 3 -- userland/lazybox/nano.c | 3 +- userland/lazybox/shell.c | 5 ++- 7 files changed, 118 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 7e0b4b4..a8e9326 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ ifeq ($(ARCH), x86_64) TARGET = $(IMAGE) QEMU_CMD = qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \ -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \ - -device e1000,netdev=net0 -serial stdio + -device e1000,netdev=net0 -serial stdio -display none else ifneq ($(filter $(ARCH), aarch64 arm64),) CROSS_COMPILE ?= aarch64-linux-gnu- @@ -375,6 +375,17 @@ $(IMAGE): $(BUILD_DIR)/boot/boot.bin $(BUILD_DIR)/boot/stage2.bin $(BUILD_DIR)/k run qemu: $(TARGET) $(QEMU_CMD) +run-gui: $(TARGET) +ifeq ($(ARCH), x86_64) + qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \ + -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \ + -device e1000,netdev=net0 -serial stdio +else ifneq ($(filter $(ARCH), aarch64 arm64),) + qemu-system-aarch64 -M virt -cpu cortex-a57 -m 128M -kernel $(BUILD_DIR)/kernel.elf -serial stdio +else + qemu-system-arm -M virt -cpu cortex-a15 -m 128M -kernel $(BUILD_DIR)/kernel.elf -serial stdio +endif + run-server: $(IMAGE) qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \ -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \ diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index cce6fe5..1b7a05a 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -2,6 +2,14 @@ #include #include +#if defined(__x86_64__) +#include +#elif defined(__aarch64__) +#include +#elif defined(__arm__) || defined(__armv8i__) +#include +#endif + #define KEYBOARD_DATA_PORT 0x60 #define KEYBOARD_STATUS_PORT 0x64 #define KEYBOARD_BUFFER_SIZE 128 @@ -123,14 +131,10 @@ void keyboard_init(void) { #endif } -#if defined(__aarch64__) -#include -#elif defined(__arm__) || defined(__armv8i__) -#include -#endif - bool keyboard_has_key(void) { -#if defined(__aarch64__) || defined(__arm__) || defined(__armv8i__) +#if defined(__x86_64__) + if (serial_received()) return true; +#elif defined(__aarch64__) || defined(__arm__) || defined(__armv8i__) if (uart_pl011_has_data()) return true; #endif return buffer_head != buffer_tail; @@ -140,13 +144,75 @@ uint16_t keyboard_get_key(void) { while (!keyboard_has_key()) { arch_halt(); } -#if defined(__aarch64__) || defined(__arm__) || defined(__armv8i__) + +#if defined(__x86_64__) + if (serial_received()) { + char c = serial_read_char(); + if ((uint8_t)c == 0x1B) { // Escape sequence + for (volatile int t = 0; t < 2000; t++) { + if (serial_received()) { + char c2 = serial_read_char(); + if (c2 == '[') { + for (volatile int t2 = 0; t2 < 2000; t2++) { + if (serial_received()) { + char c3 = serial_read_char(); + if (c3 == 'A') return KEY_UP; + if (c3 == 'B') return KEY_DOWN; + if (c3 == 'C') return KEY_RIGHT; + if (c3 == 'D') return KEY_LEFT; + if (c3 == 'H') return KEY_HOME; + if (c3 == 'F') return KEY_END; + if (c3 == '3') { + if (serial_received() && serial_read_char() == '~') return KEY_DELETE; + } + break; + } + } + } + break; + } + } + return 0x1B; + } + if (c == '\r') c = '\n'; + if ((uint8_t)c == 0x7F || c == 0x08) c = '\b'; + return (uint16_t)(uint8_t)c; + } +#elif defined(__aarch64__) || defined(__arm__) || defined(__armv8i__) if (uart_pl011_has_data()) { char c = uart_pl011_getc(); + if ((uint8_t)c == 0x1B) { // Escape sequence + for (volatile int t = 0; t < 2000; t++) { + if (uart_pl011_has_data()) { + char c2 = uart_pl011_getc(); + if (c2 == '[') { + for (volatile int t2 = 0; t2 < 2000; t2++) { + if (uart_pl011_has_data()) { + char c3 = uart_pl011_getc(); + if (c3 == 'A') return KEY_UP; + if (c3 == 'B') return KEY_DOWN; + if (c3 == 'C') return KEY_RIGHT; + if (c3 == 'D') return KEY_LEFT; + if (c3 == 'H') return KEY_HOME; + if (c3 == 'F') return KEY_END; + if (c3 == '3') { + if (uart_pl011_has_data() && uart_pl011_getc() == '~') return KEY_DELETE; + } + break; + } + } + } + break; + } + } + return 0x1B; + } if (c == '\r') c = '\n'; + if ((uint8_t)c == 0x7F || c == 0x08) c = '\b'; return (uint16_t)(uint8_t)c; } #endif + uint16_t key = key_buffer[buffer_tail]; buffer_tail = (buffer_tail + 1) % KEYBOARD_BUFFER_SIZE; return key; diff --git a/drivers/char/tty.c b/drivers/char/tty.c index db7ddb9..2e0e7c2 100644 --- a/drivers/char/tty.c +++ b/drivers/char/tty.c @@ -1,6 +1,7 @@ #include #include #include +#include typedef struct { uint16_t buffer[TTY_HEIGHT][TTY_WIDTH]; @@ -42,7 +43,7 @@ static void tty_scroll(tty_t* t) { } } for (int x = 0; x < TTY_WIDTH; x++) { - t->buffer[TTY_HEIGHT - 1][x] = vga_entry(' ', t->current_color); + t->buffer[TTY_HEIGHT - 1][x] = vga_entry(' ', t->current_color ? t->current_color : 0x07); } t->cursor_row = TTY_HEIGHT - 1; } @@ -51,12 +52,15 @@ void tty_clear(void) { tty_t* t = &ttys[current_tty]; for (int y = 0; y < TTY_HEIGHT; y++) { for (int x = 0; x < TTY_WIDTH; x++) { - t->buffer[y][x] = vga_entry(' ', t->current_color); + t->buffer[y][x] = vga_entry(' ', t->current_color ? t->current_color : 0x07); } } t->cursor_row = 0; t->cursor_col = 0; tty_render_current(); + + // Send standard ANSI terminal clear screen sequence to serial / UART + printk("\033[2J\033[H"); } void tty_set_cursor(int row, int col) { @@ -74,7 +78,7 @@ void tty_write(const char* data, size_t size) { for (size_t i = 0; i < size; i++) { char c = data[i]; - // Basic ANSI escape sequence parser (e.g. \033[31m) + // ANSI escape sequence parser if (c == '\033' && i + 1 < size && data[i + 1] == '[') { i += 2; int code = 0; @@ -91,7 +95,7 @@ void tty_write(const char* data, size_t size) { else if (code == 35) t->current_color = 0x05; // Magenta else if (code == 36) t->current_color = 0x03; // Cyan else if (code == 37) t->current_color = 0x07; // White - else if (code == 90) t->current_color = 0x08; // Bright Black (Dark Grey) + else if (code == 90) t->current_color = 0x08; // Bright Black else if (code == 91) t->current_color = 0x0C; // Bright Red else if (code == 92) t->current_color = 0x0A; // Bright Green else if (code == 93) t->current_color = 0x0E; // Bright Yellow @@ -102,8 +106,21 @@ void tty_write(const char* data, size_t size) { } else if (i < size && data[i] == 'K') { // Clear from cursor to end of line for (int x = t->cursor_col; x < TTY_WIDTH; x++) { - t->buffer[t->cursor_row][x] = vga_entry(' ', t->current_color); + t->buffer[t->cursor_row][x] = vga_entry(' ', t->current_color ? t->current_color : 0x07); } + } else if (i < size && data[i] == 'J') { + // Clear entire screen buffer + for (int y = 0; y < TTY_HEIGHT; y++) { + for (int x = 0; x < TTY_WIDTH; x++) { + t->buffer[y][x] = vga_entry(' ', t->current_color ? t->current_color : 0x07); + } + } + t->cursor_row = 0; + t->cursor_col = 0; + } else if (i < size && data[i] == 'H') { + // Cursor Home + t->cursor_row = 0; + t->cursor_col = 0; } else if (i < size && data[i] == 'D') { // Move cursor left if (t->cursor_col > 0) t->cursor_col--; @@ -132,10 +149,10 @@ void tty_write(const char* data, size_t size) { } else if (c == '\b') { if (t->cursor_col > 0) { t->cursor_col--; - t->buffer[t->cursor_row][t->cursor_col] = vga_entry(' ', t->current_color); + t->buffer[t->cursor_row][t->cursor_col] = vga_entry(' ', t->current_color ? t->current_color : 0x07); } } else { - t->buffer[t->cursor_row][t->cursor_col] = vga_entry(c, t->current_color); + t->buffer[t->cursor_row][t->cursor_col] = vga_entry(c, t->current_color ? t->current_color : 0x07); if (++t->cursor_col >= TTY_WIDTH) { t->cursor_col = 0; if (++t->cursor_row >= TTY_HEIGHT) { diff --git a/include/config/autoconf.h b/include/config/autoconf.h index 60cb873..fa3de24 100644 --- a/include/config/autoconf.h +++ b/include/config/autoconf.h @@ -2,8 +2,8 @@ #ifndef _AUTOCONF_H #define _AUTOCONF_H -#define CONFIG_ARCH "armv8i" -#define CONFIG_ARCH_ARMV8I 1 +#define CONFIG_ARCH "x86_64" +#define CONFIG_ARCH_X86_64 1 #define CONFIG_BPF_VM 1 #define CONFIG_DRV_AHCI 1 #define CONFIG_DRV_ATA 1 diff --git a/kernel/main.c b/kernel/main.c index 1a4ab14..b78cbf5 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -195,9 +195,6 @@ static void subos_modular_core_boot(void) { printk(ANSI_BRIGHT_GREEN "ACTIVE\n" ANSI_RESET); // Launch Shell -#if defined(__x86_64__) - tty_clear(); -#endif shell_run(); while (1) { diff --git a/userland/lazybox/nano.c b/userland/lazybox/nano.c index 49f15f0..d87f249 100644 --- a/userland/lazybox/nano.c +++ b/userland/lazybox/nano.c @@ -287,7 +287,8 @@ int nano_main(int argc, char** argv) { } break; - case '\b': // Backspace + case '\b': // Backspace (0x08) + case 0x7F: // DEL if (nano_cursor_col > 0) { memmove(&nano_lines[nano_cursor_row][nano_cursor_col - 1], &nano_lines[nano_cursor_row][nano_cursor_col], diff --git a/userland/lazybox/shell.c b/userland/lazybox/shell.c index 1df1c20..371db36 100644 --- a/userland/lazybox/shell.c +++ b/userland/lazybox/shell.c @@ -287,6 +287,8 @@ static void shell_process(const char* cmd) { int idx = (history_head - history_count + i + HISTORY_SIZE) % HISTORY_SIZE; printk(" %2d: %s\n", i + 1, history[idx]); } + } else if (strcmp(argv[0], "clear") == 0 || strcmp(argv[0], "cls") == 0) { + tty_clear(); } else if (strcmp(argv[0], "reboot") == 0) { printk(ANSI_YELLOW "Rebooting...\n" ANSI_RESET); pit_sleep(200); @@ -392,7 +394,7 @@ void shell_run(void) { printk("%s%s", prompt, cmd_buffer); continue; } - if (c == '\b') { + if (c == '\b' || (unsigned char)c == 0x7F || c == 0x08) { if (cursor_pos > 0) { for (size_t i = cursor_pos - 1; i < cmd_len - 1; i++) cmd_buffer[i] = cmd_buffer[i + 1]; cmd_len--; @@ -400,6 +402,7 @@ void shell_run(void) { cmd_buffer[cmd_len] = '\0'; redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos); } + continue; } else if (c == '\t') { if (cmd_len > 0) { int matches = 0;