From 52bb2609aed6a541997c5acd1b4dded07e4c55fe Mon Sep 17 00:00:00 2001 From: ice-bit Date: Mon, 8 Jul 2019 18:43:45 +0200 Subject: [PATCH] Now this should be complete Added basic shell and fixed various bugs...now iceos should be "complete". --- README.md | 6 +-- build.sh | 4 ++ kernel/drivers/isr.c | 1 - kernel/drivers/keyboard.c | 101 +++++++++++++++++++++++++++++++++++++- kernel/drivers/keyboard.h | 44 +---------------- kernel/drivers/ports.h | 2 +- kernel/drivers/tty.c | 10 ++-- kernel/kernel_main.c | 14 ++---- kernel/libc/stdio.c | 7 ++- kernel/libc/stdio.h | 1 + kernel/shell/Makefile | 10 ++++ kernel/shell/shell.c | 87 ++++++++++++++++++++++++++++++++ kernel/shell/shell.h | 20 ++++++++ 13 files changed, 243 insertions(+), 64 deletions(-) create mode 100644 kernel/shell/Makefile create mode 100644 kernel/shell/shell.c create mode 100644 kernel/shell/shell.h diff --git a/README.md b/README.md index 84d6e7a..bdf5dc8 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,10 @@ iceOS already have/will have the following features: - [x] Bare metal booting; - [x] VGA driver; - [x] Interrupts implementation; -- [ ] PIC & PIT implementation; -- [ ] PS2 driver; +- [x] PIC & PIT implementation; +- [x] PS2 driver; - [x] Support for x86 architecture; - [x] GRUB as bootloader; -- [ ] Paging; -- [ ] Dynamic memory allocation(heap). ## Resources This project is made with different kind of resources and different kind of knowledges, before starting it i read/studied the following resources: diff --git a/build.sh b/build.sh index 7ece108..d9c146c 100755 --- a/build.sh +++ b/build.sh @@ -27,6 +27,10 @@ cp kernel/drivers/*.o obj/ make -C kernel/libc cp kernel/libc/*.o obj/ +# Shell +make -C kernel/shell +cp kernel/shell/*.o obj/ + # Linking i686-elf-ld -melf_i386 -nostdlib -O2 -T link.ld -o isodir/boot/iceOS.bin obj/*.o diff --git a/kernel/drivers/isr.c b/kernel/drivers/isr.c index 6e02fee..f65e7b6 100644 --- a/kernel/drivers/isr.c +++ b/kernel/drivers/isr.c @@ -63,7 +63,6 @@ void isr_handler(registers_t regs) { WHITE, BLACK ); - kprint((uint8_t*)"\n"); } } diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c index e193e14..94d89b6 100644 --- a/kernel/drivers/keyboard.c +++ b/kernel/drivers/keyboard.c @@ -9,11 +9,110 @@ * This device should not exists anymore in any modern computer * motherboard; however the CPU(or the motherboard?) should be able to * simulate it even if we're using some USB keyboard. + * Apart of that the keyboard will be listen on IRQ1(33), + * so we have to register an ISR for that. */ #include "keyboard.h" #include "isr.h" #include "ports.h" #include "tty.h" -#include "../libc/string.h" +#include "../shell/shell.h" #include "../libc/stdio.h" + +static void keyboard_callback(); + +/* Keyboard scan codes map , layout is: standard US keyboard */ +uint8_t keyboard_scan_codes[] = { + 0, (uint8_t)27, (uint8_t)'1', (uint8_t)'2', (uint8_t)'3', (uint8_t)'4', (uint8_t)'5', (uint8_t)'6', (uint8_t)'7', (uint8_t)'8', + (uint8_t)'0', (uint8_t)'0', (uint8_t)'-', (uint8_t)'=', (uint8_t)'\b', + (uint8_t)'\t', + (uint8_t)'q', (uint8_t)'w', (uint8_t)'e', (uint8_t)'r', + (uint8_t)'t', (uint8_t)'y', (uint8_t)'u', (uint8_t)'i', (uint8_t)'o', (uint8_t)'p', (uint8_t)'[', (uint8_t)']', (uint8_t)'\n', + 0, + (uint8_t)'a', (uint8_t)'s', (uint8_t)'d', (uint8_t)'f', (uint8_t)'g', (uint8_t)'h', (uint8_t)'j', (uint8_t)'k', (uint8_t)'l', (uint8_t)';', + (uint8_t)'\'', (uint8_t)'`', 0, + (uint8_t)'\\', (uint8_t)'z', (uint8_t)'x', (uint8_t)'c', (uint8_t)'v', (uint8_t)'b', (uint8_t)'n', + (uint8_t)'m', (uint8_t)',', (uint8_t)'.', (uint8_t)'/', 0, + (uint8_t)'*', + + 0, // Alt + (uint8_t)' ', // Spacebar + 0, // Caps lock + 0, // 59 - F1 key + 0, // 59 - F1 key + 0, 0, 0, 0, 0, 0, 0, 0, + 0, // F10 + 0, // 69 - Num lock + 0, // Scroll lock + 0, // Home key + 0, // Up arrow + 0, // Page up + (uint8_t)'-', + 0, // Left arrow + 0, + 0, // Right arrow + (uint8_t)'+', + 0, // 79 End key + 0, // Down arrow + 0, // Page down + 0, // Insert key + 0, // Delete key + 0, 0, 0, + 0, // F11 key + 0, // F12 key + 0 // Others key are undefined +}; + +uint8_t command[512]; // Max length of a single command +uint8_t temp[512]; +uint32_t cmd_index = 0; +uint32_t shiftdown = 0; + +void clear() { + for(uint16_t i = 0; i < 512; i++) + command[i] = 0; +} + +void clear_tmp(void) { + for(uint16_t i = 0; i < 512; i++) + command[i] = 0; +} + +static void keyboard_callback() { + uint8_t scan_code = inb(KB_DATA_PORT); // Read from keyboard + uint8_t keycode = keyboard_scan_codes[scan_code]; // Get ASCII value + + if(scan_code & 0x80) { + if(scan_code == 0xAA || scan_code == 0x86) + shiftdown = 0; + } else { + // Handle backspace + if(keycode == 0x08) { + if(cmd_index <= 0) // If at start of the prompt + return; // Do not delete it. + cmd_index--; // Otherwise go back + + for(uint32_t i = 0; i < cmd_index; ++i) + temp[i] = command[i]; + clear(); + for(uint32_t i = 0; i < cmd_index; ++i) + command[i] = temp[i]; + clear_tmp(); + backspace(); + } else if(keycode == 0x0A) { // Handle Enter + processCommand(command); + cmd_index = 0; + clear(); + init_prompt(); + } else { + printf("%c", keycode); + command[cmd_index] = keycode; + cmd_index++; + } + } +} + +void init_keyboard() { + register_interrupt_handler(IRQ1, &keyboard_callback); +} \ No newline at end of file diff --git a/kernel/drivers/keyboard.h b/kernel/drivers/keyboard.h index 62ddedb..f191399 100644 --- a/kernel/drivers/keyboard.h +++ b/kernel/drivers/keyboard.h @@ -10,48 +10,8 @@ #include +#define KB_DATA_PORT 0x60 // Keyboard serial port + void init_keyboard(); -/* Keyboard scan codes map */ -uint8_t *keyboard_scan_codes[] = { - 0, (uint8_t*)27, (uint8_t*)'1', (uint8_t*)'2', (uint8_t*)'3', (uint8_t*)'4', (uint8_t*)'5', (uint8_t*)'6', (uint8_t*)'7', (uint8_t*)'8', - (uint8_t*)'0', (uint8_t*)'0', (uint8_t*)'-', (uint8_t*)'=', (uint8_t*)'\b', - (uint8_t*)'\t', - (uint8_t*)'q', (uint8_t*)'w', (uint8_t*)'e', (uint8_t*)'r', - (uint8_t*)'t', (uint8_t*)'y', (uint8_t*)'u', (uint8_t*)'i', (uint8_t*)'o', (uint8_t*)'p', (uint8_t*)'[', (uint8_t*)']', (uint8_t*)'\n', - 0, - (uint8_t*)'a', (uint8_t*)'s', (uint8_t*)'d', (uint8_t*)'f', (uint8_t*)'g', (uint8_t*)'h', (uint8_t*)'j', (uint8_t*)'k', (uint8_t*)'l', (uint8_t*)';', - (uint8_t*)'\'', (uint8_t*)'`', 0, - (uint8_t*)'\\', (uint8_t*)'z', (uint8_t*)'x', (uint8_t*)'c', (uint8_t*)'v', (uint8_t*)'b', (uint8_t*)'n', - (uint8_t*)'m', (uint8_t*)',', (uint8_t*)'.', (uint8_t*)'/', 0, - (uint8_t*)'*', - - 0, // Alt - (uint8_t*)' ', // Spacebar - 0, // Caps lock - 0, // 59 - F1 key - 0, // 59 - F1 key - 0, 0, 0, 0, 0, 0, 0, 0, - 0, // F10 - 0, // 69 - Num lock - 0, // Scroll lock - 0, // Home key - 0, // Up arrow - 0, // Page up - (uint8_t*)'-', - 0, // Left arrow - 0, - 0, // Right arrow - (uint8_t*)'+', - 0, // 79 End key - 0, // Down arrow - 0, // Page down - 0, // Insert key - 0, // Delete key - 0, 0, 0, - 0, // F11 key - 0, // F12 key - 0 // Others key are undefined -}; - #endif \ No newline at end of file diff --git a/kernel/drivers/ports.h b/kernel/drivers/ports.h index 0f792e6..52afac2 100644 --- a/kernel/drivers/ports.h +++ b/kernel/drivers/ports.h @@ -8,7 +8,7 @@ * @param port: Output port to send data to. * @param data: The actual data to send to port */ -void outb(uint16_t port, uint8_t data); +void outb(uint16_t port, uint16_t data); /* inb: * Fetch data from a port, return a char diff --git a/kernel/drivers/tty.c b/kernel/drivers/tty.c index f4c08e6..144e47b 100644 --- a/kernel/drivers/tty.c +++ b/kernel/drivers/tty.c @@ -6,7 +6,7 @@ // Also define a 2 byte pointer because cells are 16 bits wide #define UVGA_PTR ((uint16_t *)VIDEO_MEM_ADDR) -static uint32_t fb_col = 0; // X +static uint32_t fb_col = 1; // X static uint32_t fb_row = 0; // Y void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg) { @@ -70,12 +70,12 @@ void kprint(uint8_t *buf) { } void init_prompt() { - uint8_t *prompt = (uint8_t*)"\nuser@iceOS-$ "; - kprint_c(prompt, strlen(prompt), LIGHT_GREEN, BLACK); + uint8_t *prompt = (uint8_t*)"\nring0@iceOS-$ "; + kprint_c(prompt, strlen(prompt), LIGHT_RED, BLACK); } void clear_prompt() { - fb_col = 0; + fb_col = 1; fb_row = 0; for(uint32_t i = 0; i < (VGA_WIDTH * VGA_HEIGHT); i++) @@ -100,6 +100,6 @@ void newline() { else // Otherwise scroll framebuffer scroll(); - fb_col = 0; + fb_col = 1; move_cursor(fb_col + (fb_row * VGA_WIDTH)); } \ No newline at end of file diff --git a/kernel/kernel_main.c b/kernel/kernel_main.c index ae0afb0..5ea48c1 100644 --- a/kernel/kernel_main.c +++ b/kernel/kernel_main.c @@ -9,21 +9,17 @@ #include "drivers/gdt.h" #include "drivers/idt.h" #include "drivers/timer.h" -#include "libc/stdio.h" +#include "drivers/keyboard.h" +#include "shell/shell.h" void kernel_main() { gdt_setup(); // Setup Global Descriptor Table idt_setup(); // Setup Interrupt Descriptor Table clear_prompt(); + iceos_ascii_logo(); init_prompt(); // Initialize frame buffer - //puts("Hello World!"); - init_timer(1); + init_keyboard(); // Initialize keyboard driver - /* - // Testing some interrupts - asm("int $0"); // Division by zero - asm("int $4"); // Stack overflow - asm("int $1"); // Page fault - */ + // init_timer(1); // Only for debug purposes } \ No newline at end of file diff --git a/kernel/libc/stdio.c b/kernel/libc/stdio.c index 4d360e8..e1d9225 100644 --- a/kernel/libc/stdio.c +++ b/kernel/libc/stdio.c @@ -32,7 +32,7 @@ int printf(const char *format, ...) { kprint(buf); break; case 'c': - s = va_arg(ap, uint8_t*); + c = (uint8_t)va_arg(ap, uint32_t); kprint_c(&c, 1, WHITE, BLACK); break; case 's': @@ -49,6 +49,11 @@ int printf(const char *format, ...) { return 0; } +int printf_color(const char *format, uint8_t fg, uint8_t bg) { + kprint_c((uint8_t*)format, strlen((uint8_t*)format), fg, bg); + return 0; +} + void puts(const char *buf) { printf("%s\n", buf); } diff --git a/kernel/libc/stdio.h b/kernel/libc/stdio.h index 81bd41e..087885c 100644 --- a/kernel/libc/stdio.h +++ b/kernel/libc/stdio.h @@ -14,6 +14,7 @@ #include int printf(const char *format, ...); +int printf_color(const char *format, uint8_t fg, uint8_t bg); // Only for string for now void puts(const char *buf); #endif \ No newline at end of file diff --git a/kernel/shell/Makefile b/kernel/shell/Makefile new file mode 100644 index 0000000..3f1da65 --- /dev/null +++ b/kernel/shell/Makefile @@ -0,0 +1,10 @@ +OBJS = shell.o + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c + + +all:${OBJS} + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ \ No newline at end of file diff --git a/kernel/shell/shell.c b/kernel/shell/shell.c new file mode 100644 index 0000000..9f23faa --- /dev/null +++ b/kernel/shell/shell.c @@ -0,0 +1,87 @@ +#include "shell.h" +#include "../libc/string.h" +#include "../libc/stdio.h" +#include "../drivers/tty.h" +#include "../drivers/ports.h" + +void helper() { + puts("\nList of available commands:\n" + "\nhelp - Print this helper" + "\nint - Test some interrupts" + "\nbanner - Show banner" + "\nclear, cls - Clear the screen" + "\nabout - About this kernel" + "\nreboot - Reboot the system" + ); +} + +void test_interrupts() { + // Testing some interrupts + asm("int $0"); // Division by zero + asm("int $4"); // Stack overflow + asm("int $1"); // Page fault +} + +void about() { + printf_color("\n====== IceOS v0.0.1 (c) 2019 Marco 'icebit' Cetica ======\n\n", + LIGHT_CYAN, BLACK); + printf_color( + "iceOS is a x86 monolithic kernel written in C from scratch.\n" + "This project doesn't aim to be a fully functional operating system\n" + "with tons of drivers and graphical applications,\nit's just a learning tool" + "to teach myself concepts like\nOperating Systems, Computer Architecture and Digital Electronics.\n" + "\n\n" + "iceOS comes with the following features:\n" + "- Bare metal booting;\n" + "- VGA driver;\n" + "- Interrupts implementation;\n" + "- PIC & PIT implementation;\n" + "- PS2 driver;\n" + "- Support for x86 architecture;\n" + "- GRUB as bootloader;\n", + LIGHT_GREEN, BLACK); +} + +void reboot() { + uint8_t tmp; + asm("cli"); // First disable all interrupts + + // Clear keyboard buffers + do { + tmp = inb(0x64); // Keyboard interface + if(check_flag(tmp, 0) != 0) + inb(0x60); // Clear keyboard data + } while(check_flag(tmp, 1) != 0); + + outb(0x64, 0xFE); // Reset the CPU +} + +void iceos_ascii_logo() { + printf_color( +"\n\n### ##### ####### ####### #####\n" +" # # # # # # # #\n" +" # # # # # # \n" +" # # ##### # # ##### \n" +" # # # # # # \n" +" # # # # # # # # \n" +"### ##### ####### ####### ##### \n" +"\n (c) Marco Cetica 2019\n", + LIGHT_MAGENTA, BLACK); + } + +void processCommand(uint8_t *cmd) { + if(strcmp(cmd, (uint8_t*)"help") == 0) + helper(); + else if(strcmp(cmd, (uint8_t*)"int") == 0) + test_interrupts(); + else if(strcmp(cmd, (uint8_t*)"clear") == 0 || strcmp(cmd, (uint8_t*)"cls") == 0) + clear_prompt(); + else if(strcmp(cmd, (uint8_t*)"about") == 0) + about(); + else if(strcmp(cmd, (uint8_t*)"banner") == 0) + iceos_ascii_logo(); + else if(strcmp(cmd, (uint8_t*)"reboot") == 0) + reboot(); + else + puts("\nCommand not found!"); +} \ No newline at end of file diff --git a/kernel/shell/shell.h b/kernel/shell/shell.h new file mode 100644 index 0000000..570557d --- /dev/null +++ b/kernel/shell/shell.h @@ -0,0 +1,20 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ +#ifndef _SHELL_H_ +#define _SHELL_H_ + +#include + +#define bit(n) (1 << (n)) +#define check_flag(flags, n) ((flags) & bit(n)) + +void helper(); +void processCommand(uint8_t *cmd); +void iceos_ascii_logo(); + +#endif \ No newline at end of file