From 15bdb4743aa0fb3c7823500964179e0eb878672d Mon Sep 17 00:00:00 2001 From: 0x35c Date: Tue, 10 Sep 2024 20:03:33 +0200 Subject: [PATCH] feature: functional shell with help and merdella commands TOOD: reboot, poweroff, echo, color --- .gitignore | 1 + headers/keyboard.h | 11 ++++- headers/shell.h | 49 ++++++++++++++++++++ headers/terminal.h | 9 +++- src/kernel.c | 12 ++--- src/shell/exec.c | 111 +++++++++++++++++++++++++++++++++++++++++++++ src/terminal/get.c | 15 +++--- src/terminal/put.c | 43 ++++++++++++++++++ 8 files changed, 232 insertions(+), 19 deletions(-) create mode 100644 headers/shell.h diff --git a/.gitignore b/.gitignore index c57157f..6d4378c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build obj .* compile_commands.json +tags diff --git a/headers/keyboard.h b/headers/keyboard.h index 66b31e5..3234270 100644 --- a/headers/keyboard.h +++ b/headers/keyboard.h @@ -1,5 +1,7 @@ #pragma once +#include + static const char *keymap[128] = { [2] = "1!", [3] = "2@", [4] = "3#", [5] = "4$", [6] = "5%", [7] = "6^", [8] = "7&", [9] = "8*", [10] = "9(", [11] = "0)", @@ -93,6 +95,11 @@ static const char *keymap[128] = { #define KEY_RIGHT 0x4D #define KEY_SPACE 0x39 #define KEY_UP 0x48 -#define KET_LEFT_SHIFT 0x2A +#define KEY_LEFT_SHIFT 0x2A #define KEY_RIGHT_SHIFT 0x36 -#define KEY_CAPSLOCK 0x3A \ No newline at end of file +#define KEY_CAPSLOCK 0x3A + +struct key_event { + uint8_t c; + uint8_t scan_code; +}; diff --git a/headers/shell.h b/headers/shell.h new file mode 100644 index 0000000..47f4f72 --- /dev/null +++ b/headers/shell.h @@ -0,0 +1,49 @@ +#pragma once + +#define PROMPT "> " + +static const char *POOP = + " / ____/ / _ \\\n" + " _/ ___/_ / / \\___ \\_\n" + " / _/'-, `---._ / / \\_ \\\n" + " / ______/(0} `, , ` , ) / / \\_ \\\n" + " / V ; ` , ` ( / / ,'~~~~~~`, \\\n" + " | `.____,- ' (, ` , ) / / :`,-'\"\"`. \"; " + "|\n" + " | `-------._); , ` `, / / \\;: )``: |\n" + " / / ) ) ; ` ,, : / / `` : '; " + "\\\n" + "/ / ( (`;: ; ` ;:\\ / / ;;;, " + "\\\n" + "| / (: )``;:;;)`'`'`--./ / ____ _,-';;` " + "|\n" + "| | :` )`;)`)`' : / / ~~~~~ ~~~`--',.;;;| " + "|\n" + "| | `--;~~~~~ ` / /, \" \" \"` \",, \\ ;`` | " + " |\n" + "| | ( ; , / / ; `; ; | " + "|\n" + "| | (; ; ; ` / / ,` ` : | " + "><\n" + "| | (; / / / ` ; ; : |\n" + "| \\ ;(_; ; : / /` ; ; ,,,\"\"\";} `; / " + "><\n" + "\\ \\ : `; `; ` / /,;,'''' );;`); ; / >< " + " ><\n" + " \\ | ;' :; ;/ / (;` :( ; , ; | " + "><\n" + " | | |, `;; ,/ / `)`; `(; ` `; | " + "(`\\\n" + " | \\ ; ;; ``: / `).:` \\;, `. / _> " + ")_\n" + " \\ \\_ ,-' ;`;;:;` / ;;'`;; `) )/ ,-' " + ",-. `;\n" + " \\ \\_ ~~~,-`;`;,\" / ~~~~~ ,-' ; " + "`\"\"/ /\"\"\n" + " \\_ \\___\"\"\"/\"\" / `\"\"/\"\" " + "\n"; + +typedef enum { HELP, REBOOT, POWEROFF, ECHO, COLOR, MERDELLA, ERROR } CMD_TOK; + +void reboot(void); +void shell_init(void); diff --git a/headers/terminal.h b/headers/terminal.h index 2243650..8997c65 100644 --- a/headers/terminal.h +++ b/headers/terminal.h @@ -1,5 +1,6 @@ #pragma once +#include "keyboard.h" #include #include #include @@ -14,6 +15,7 @@ struct screen { size_t column; uint8_t color; uint16_t buffer[VGA_WIDTH * VGA_HEIGHT]; + char line[256]; }; enum vga_color { @@ -35,13 +37,16 @@ enum vga_color { VGA_COLOR_WHITE = 15, }; +enum cursor_direction { LEFT, RIGHT, UP, DOWN }; + void terminal_initialize(void); void terminal_setcolor(uint8_t color); -void terminal_putentryat(char c, uint8_t color, size_t x, size_t y); int terminal_putchar(char c); int terminal_write(const char *data, size_t size); int terminal_writestring(const char *data); int terminal_writelong(long number); void terminal_set_screen(int pos); -uint8_t terminal_getkey(void); +struct key_event terminal_getkey(void); void update_cursor(void); +void move_cursor(int direction); +struct screen *get_screen(void); diff --git a/src/kernel.c b/src/kernel.c index 800cd23..1ddc371 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,4 +1,5 @@ -#include "kprintf.h" +#include "gdt.h" +#include "shell.h" #include "terminal.h" #include @@ -21,11 +22,6 @@ void kernel_main(void) /* Initialize terminal interface */ terminal_initialize(); - /* Newline support is left as an exercise. */ - for (int i = 100; i; i--) - kprintf(0, "%d\n", i); - void initGdt(); - kprintf(0, "mange ta mere avec ton argument a kprintf fdp\n"); - while (true) - terminal_getkey(); + /* initGdt(); */ + shell_init(); } diff --git a/src/shell/exec.c b/src/shell/exec.c index e69de29..e67c8d5 100644 --- a/src/shell/exec.c +++ b/src/shell/exec.c @@ -0,0 +1,111 @@ +#include "kprintf.h" +#include "shell.h" +#include "string.h" +#include "terminal.h" + +extern struct screen *screen; + +static CMD_TOK find_command(char *line) +{ + size_t i = 0; + bool uwu = false; + CMD_TOK command = ERROR; + + if (!line[0]) + return command; + while (line[i]) { + if (line[i] == ' ') { + uwu = true; + break; + } + i++; + } + line[i] = '\0'; + if (!strcmp(line, "help")) + command = HELP; + else if (!strcmp(line, "reboot")) + command = REBOOT; + else if (!strcmp(line, "poweroff")) + command = POWEROFF; + else if (!strcmp(line, "echo")) + command = ECHO; + else if (!strcmp(line, "color")) + command = COLOR; + else if (!strcmp(line, "merdella")) + command = MERDELLA; + else + kprintf(0, "invalid command: %s\n", line); + if (uwu) + line[i] = ' '; + return command; +} + +static void read_line(char *buf, size_t size) +{ + size_t i = 0; + struct key_event ev; + uint8_t prev_scan_code = 0; + + while (1) { + ev = terminal_getkey(); + if (ev.c == '\n') + break; + if (prev_scan_code != ev.scan_code && ev.scan_code) { + if (ev.scan_code == KEY_BACKSPACE && i) { + buf[--i] = '\0'; + move_cursor(LEFT); + terminal_putchar(' '); + move_cursor(LEFT); + } + if (ev.c && i < size - 1) { + kprintf(0, "%c", ev.c); + buf[i++] = ev.c; + } + if (i >= size) + break; + } + prev_scan_code = ev.scan_code; + } + kprintf(0, "\n"); + buf[i] = '\0'; +} + +void shell_init(void) +{ + while (1) { + kprintf(0, PROMPT); + read_line(screen->line, sizeof(screen->line)); + switch (find_command(screen->line)) { + case HELP: + kprintf(0, "Welcome to bozOShell, the shell of " + "bozOS\nAvailable commands: help, reboot, " + "poweroff, echo, color, merdella\n"); + break; + case REBOOT: + kprintf(0, "rebooting\n"); + break; + case POWEROFF: + kprintf(0, "powering off\n"); + break; + case ECHO: + kprintf(0, "echoing\n"); + break; + case COLOR: + kprintf(0, "coloring\n"); + break; + case MERDELLA: { + kprintf(0, POOP); + if (!strcmp("--credits", strchr(screen->line, ' ') + 1)) + kprintf( + 0, + "\nThis ascii masterpiece has been created " + "by Targon (/)\n"); + break; + } + case ERROR: + break; + default: + break; + } + } +} diff --git a/src/terminal/get.c b/src/terminal/get.c index eb927dc..8eea7fc 100644 --- a/src/terminal/get.c +++ b/src/terminal/get.c @@ -1,31 +1,32 @@ #include #include "keyboard.h" -#include "kprintf.h" #include "sys/io.h" #include "terminal.h" -uint8_t terminal_getkey(void) +struct key_event terminal_getkey(void) { static bool caps_mode = false; static uint8_t prev_scan_code = 0; + struct key_event ev = {0}; uint8_t scan_code; scan_code = inb(KEYBOARD_PORT); if (scan_code == 0x3A || scan_code == 0x58) { caps_mode = !caps_mode; outb(0xED, (caps_mode << 2)); // turn on/off capslock led - } - else if (scan_code == KEY_RIGHT_SHIFT || scan_code == KET_LEFT_SHIFT) + } else if (scan_code == KEY_RIGHT_SHIFT || scan_code == KEY_LEFT_SHIFT) caps_mode = true; - else if (scan_code == KEY_RIGHT_SHIFT + 128 || scan_code == KET_LEFT_SHIFT + 128) + else if (scan_code == KEY_RIGHT_SHIFT + 128 || + scan_code == KEY_LEFT_SHIFT + 128) caps_mode = false; else if (scan_code != prev_scan_code && prev_scan_code != 0) { if (scan_code < 128 && keymap[scan_code]) - kprintf(0, "%c", keymap[scan_code][caps_mode]); + ev.c = keymap[scan_code][caps_mode]; if (scan_code >= KEY_F1 && scan_code <= KEY_F10) terminal_set_screen(scan_code - KEY_F1); } prev_scan_code = scan_code; - return scan_code; + ev.scan_code = scan_code; + return ev; } diff --git a/src/terminal/put.c b/src/terminal/put.c index d8246bb..c9aa3a3 100644 --- a/src/terminal/put.c +++ b/src/terminal/put.c @@ -129,3 +129,46 @@ void update_cursor(void) outb(0x3D4, 0x0E); outb(0x3D5, (pos >> 8) & 0xFF); } + +void move_cursor(int direction) +{ + + switch (direction) { + case LEFT: + if (screen->column) { + screen->column--; + } else if (screen->row) { + screen->column = VGA_WIDTH - 1; + screen->row--; + } + break; + case RIGHT: + if (screen->column < VGA_WIDTH - 1) { + screen->column++; + } else if (screen->row < VGA_HEIGHT - 1) { + screen->column = 0; + screen->row++; + } else { + terminal_new_line(); + } + break; + case UP: + break; + case DOWN: + break; + default: + break; + } + + uint16_t pos = screen->row * VGA_WIDTH + screen->column; + + outb(0x3D4, 0x0F); + outb(0x3D5, pos & 0xFF); + outb(0x3D4, 0x0E); + outb(0x3D5, (pos >> 8) & 0xFF); +} + +struct screen *get_screen(void) +{ + return screen; +}