diff --git a/Makefile b/Makefile index 3bcd457..55c5b06 100644 --- a/Makefile +++ b/Makefile @@ -25,5 +25,5 @@ compile_bootloader: compile_kernel: nasm -felf32 kernel/wrapper.asm -o target/kernel/wrapper.o - i686-elf-gcc -g -c kernel/kernel.c -o target/kernel/kernel.o -std=gnu99 -ffreestanding -O2 -Wall -Wextra -mno-80387 -mgeneral-regs-only -mno-red-zone - i686-elf-gcc -g -T kernel/linker.ld -o target/kernel/kernel.bin -ffreestanding -O2 -nostdlib target/kernel/wrapper.o target/kernel/kernel.o -lgcc + i686-elf-gcc -g -c kernel/kernel.c -o target/kernel/kernel.o -std=gnu99 -ffreestanding -Og -Wall -Wextra -mno-80387 -mgeneral-regs-only -mno-red-zone + i686-elf-gcc -g -T kernel/linker.ld -o target/kernel/kernel.bin -ffreestanding -Og -nostdlib target/kernel/wrapper.o target/kernel/kernel.o -lgcc diff --git a/README.md b/README.md index 9c9ee55..c87c33b 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ The kernel is based on [the bare bones kernel from the OSDev wiki](https://wiki. - [x] Terminal output (with newlines!) - [x] _Very_ basic memory management -- [ ] Interrupt handling -- [ ] Keyboard input +- [x] Interrupt handling +- [x] Keyboard input - [ ] Filesystem interaction - [ ] Better memory management diff --git a/kernel/drivers/keyboard/keyboard.c b/kernel/drivers/keyboard/keyboard.c new file mode 100644 index 0000000..3fc8b27 --- /dev/null +++ b/kernel/drivers/keyboard/keyboard.c @@ -0,0 +1,82 @@ +#ifndef DRIVERS_KEYBOARD_C +#define DRIVERS_KEYBOARD_C + +#include +#include + +#include "keycodes.c" +#include "../../util/fifo.c" +#include "keymaps/DUMMY_azerty.c" + +#define KEY_QUEUE_EMPTY FIFO_QUEUE_EMPTY + +bool keyboard_shift_state = false; +bool keyboard_caps_state = false; + +fifo* key_queue = NULL; + +int scancode_to_char(unsigned char scancode) { + keycode keycode = get_keycode(scancode); + + if (keycode == KEYCODE_UNKNOWN) { + return -1; + } else if (keycode == KEYCODE_SHIFT_DOWN) { + keyboard_shift_state = true; + return -1; + } else if (keycode == KEYCODE_SHIFT_UP) { + keyboard_shift_state = false; + return -1; + } else if (keycode == KEYCODE_CAPS_UP) { + keyboard_caps_state = !keyboard_caps_state; + return -1; + } else if (keycode == KEYCODE_CAPS_DOWN) { + return -1; + } else if (keycode >= KEYCODE_A && keycode <= KEYCODE_Z) { + if (keyboard_shift_state ^ keyboard_caps_state) { + return (char) keycode; // Upper case + } else { + return ((char) keycode) + 32; // Lower case + } + } else { + return (char) keycode; + } + +} + +void handle_scancode(unsigned char scancode) { + int keycode = scancode_to_char(scancode); + if (keycode == -1) { + return; + } else { + fifo_enqueue(key_queue, (char) keycode); + } +} + +__attribute__((interrupt)) void keyboard_handler(struct interrupt_frame* frame) { + unsigned char scan_code = inb(0x60); + outb(0x20, 0x20); + + handle_scancode(scan_code); +} + +int getchar_nonblocking() { + return fifo_dequeue(key_queue); +} + +char getchar() { + int curr = KEY_QUEUE_EMPTY; + while ((curr = getchar_nonblocking()) == KEY_QUEUE_EMPTY) {} + return (char) curr; +} + +void keyboard_init() { + key_queue = fifo_new(); + + uint8_t mask = inb(0x21); + + mask = mask & ~(1 << 1); + + outb(0x21 , mask); +} + +#endif //DRIVERS_KEYBOARD_C \ No newline at end of file diff --git a/kernel/drivers/keyboard/keycodes.c b/kernel/drivers/keyboard/keycodes.c new file mode 100644 index 0000000..545dda1 --- /dev/null +++ b/kernel/drivers/keyboard/keycodes.c @@ -0,0 +1,42 @@ +#ifndef DRIVERS_KEYBOARD_KEYCODES_C +#define DRIVERS_KEYBOARD_KEYCODES_C + +typedef enum keycode_enum { + KEYCODE_A = 'A', + KEYCODE_B = 'B', + KEYCODE_C = 'C', + KEYCODE_D = 'D', + KEYCODE_E = 'E', + KEYCODE_F = 'F', + KEYCODE_G = 'G', + KEYCODE_H = 'H', + KEYCODE_I = 'I', + KEYCODE_J = 'J', + KEYCODE_K = 'K', + KEYCODE_L = 'L', + KEYCODE_M = 'M', + KEYCODE_N = 'N', + KEYCODE_O = 'O', + KEYCODE_P = 'P', + KEYCODE_Q = 'Q', + KEYCODE_R = 'R', + KEYCODE_S = 'S', + KEYCODE_T = 'T', + KEYCODE_U = 'U', + KEYCODE_V = 'V', + KEYCODE_W = 'W', + KEYCODE_X = 'X', + KEYCODE_Y = 'Y', + KEYCODE_Z = 'Z', + + KEYCODE_SPACE = ' ', + + KEYCODE_SHIFT_UP, + KEYCODE_SHIFT_DOWN, + KEYCODE_CAPS_UP, + KEYCODE_CAPS_DOWN, + + KEYCODE_UNKNOWN +} keycode; + +#endif //DRIVERS_KEYBOARD_KEYCODES_C \ No newline at end of file diff --git a/kernel/drivers/keyboard/keymaps/DUMMY_azerty.c b/kernel/drivers/keyboard/keymaps/DUMMY_azerty.c new file mode 100644 index 0000000..1665995 --- /dev/null +++ b/kernel/drivers/keyboard/keymaps/DUMMY_azerty.c @@ -0,0 +1,80 @@ +#ifndef DRIVERS_KEYBOARD_KEYMAPS_DUMMY_AZERTY_C +#define DRIVERS_KEYBOARD_KEYMAPS_DUMMY_AZERTY_C + +#include "../keycodes.c" + +keycode get_keycode(unsigned char scancode) { + switch (scancode) + { + case 0x10: + return KEYCODE_A; + case 0x30: + return KEYCODE_B; + case 0x2e: + return KEYCODE_C; + case 0x20: + return KEYCODE_D; + case 0x12: + return KEYCODE_E; + case 0x21: + return KEYCODE_F; + case 0x22: + return KEYCODE_G; + case 0x23: + return KEYCODE_H; + case 0x17: + return KEYCODE_I; + case 0x24: + return KEYCODE_J; + case 0x25: + return KEYCODE_K; + case 0x26: + return KEYCODE_L; + case 0x27: + return KEYCODE_M; + case 0x31: + return KEYCODE_N; + case 0x18: + return KEYCODE_O; + case 0x19: + return KEYCODE_P; + case 0x1e: + return KEYCODE_Q; + case 0x13: + return KEYCODE_R; + case 0x1f: + return KEYCODE_S; + case 0x14: + return KEYCODE_T; + case 0x16: + return KEYCODE_U; + case 0x2f: + return KEYCODE_V; + case 0x2c: + return KEYCODE_W; + case 0x2d: + return KEYCODE_X; + case 0x15: + return KEYCODE_Y; + case 0x11: + return KEYCODE_Z; + case 0x39: + return KEYCODE_SPACE; + case 0x2a: + return KEYCODE_SHIFT_DOWN; + case 0xaa: + return KEYCODE_SHIFT_UP; + case 0x36: + return KEYCODE_SHIFT_DOWN; + case 0xb6: + return KEYCODE_SHIFT_UP; + case 0x3a: + return KEYCODE_CAPS_DOWN; + case 0xba: + return KEYCODE_CAPS_UP; + default: + return KEYCODE_UNKNOWN; + } +} + +#endif //DRIVERS_KEYBOARD_KEYMAPS_DUMMY_AZERTY_C \ No newline at end of file diff --git a/kernel/interrupts.c b/kernel/interrupts.c index 31506f4..895b2b8 100644 --- a/kernel/interrupts.c +++ b/kernel/interrupts.c @@ -7,6 +7,7 @@ #include "memory.c" #include "terminal.c" #include "inline_asm.c" +#include "drivers/keyboard/keyboard.c" typedef struct idt_entry_struct { uint16_t offset_1; // offset bits 0..15 @@ -36,7 +37,6 @@ struct interrupt_frame { }; idt_entry IDT[256]; -int count = 1; void interrupt_new_handler(int intnum, void (*handler)(struct interrupt_frame*)) { uint32_t handler_address = (uint32_t) handler; @@ -47,22 +47,6 @@ void interrupt_new_handler(int intnum, void (*handler)(struct interrupt_frame*)) IDT[intnum].offset_2 = (uint16_t) ((handler_address & 0xffff0000) >> 16); } -void kb_init() { - uint8_t mask = inb(0x21); - - mask = mask & ~(1 << 1); - - outb(0x21 , mask); -} - -__attribute__((interrupt)) void keyboard_handler(struct interrupt_frame* frame) { - outb(0x20, 0x20); - - char* result = "XXXXXX"; - itoa(frame->eip, result, 16); - terminal_writestring(result); -} - void interrupt_init() { /* ICW1 - begin initialization */ outb(0x20, 0x11); @@ -88,21 +72,9 @@ void interrupt_init() { uint16_t size = (sizeof(idt_entry) * 256); - terminal_writestring("Size = 0x"); - char* result = "XXXXX"; - itoa(size, result, 16); - terminal_writestring(result); - lidt(IDT, size); - kb_init(); - - uint8_t mask = inb(0x21); - - terminal_writestring(" mask = 0b"); - result = "XXXXXXXX"; - itoa(mask, result, 2); - terminal_writestring(result); + keyboard_init(); } #endif //INTERRUPTS_C \ No newline at end of file diff --git a/kernel/kernel.c b/kernel/kernel.c index e15dc11..60f50db 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -60,5 +60,8 @@ void kernel_main(void) interrupt_init(); - while(true) {} + for(;;) { + char curr_char = getchar(); + terminal_putchar(curr_char); + } } \ No newline at end of file diff --git a/kernel/util/fifo.c b/kernel/util/fifo.c new file mode 100644 index 0000000..f875582 --- /dev/null +++ b/kernel/util/fifo.c @@ -0,0 +1,60 @@ +#ifndef UTIL_FIFO_C +#define UTIL_FIFO_C + +#define FIFO_INITIAL_SIZE 128 +#define FIFO_QUEUE_EMPTY -1 + +#include +#include +#include + +#include "../memory.c" + +typedef struct fifo_struct { + int num_elems; + int max_elems; + uint8_t* head; + uint8_t* curr_elem; +} fifo; + +fifo* fifo_new() { + fifo* ret = alloc(sizeof(fifo)); + void* head = alloc(sizeof(uint8_t) * FIFO_INITIAL_SIZE); + ret->num_elems = 0; + ret->max_elems = FIFO_INITIAL_SIZE; + ret->head = head; + ret->curr_elem = head; + return ret; +} + +void fifo_optimize(fifo* queue) { + if (queue->head == queue->curr_elem) { + // resize, not implemented yet (blocked by reallocarray) + } else { + // move all items to the beginning of the list + for(int i = 0; i < queue->num_elems; i++) { + queue->head[i] = queue->curr_elem[i]; + } + queue->curr_elem = queue->head; + } +} + +void fifo_enqueue(fifo* queue, uint8_t value) { + if (queue->num_elems == queue->max_elems) { + fifo_optimize(queue); + } + queue->curr_elem[queue->num_elems] = value; + queue->num_elems++; +} + +int16_t fifo_dequeue(fifo* queue) { + if (queue->num_elems <= 0) { + return FIFO_QUEUE_EMPTY; + } + uint8_t ret = queue->curr_elem[0]; + queue->curr_elem++; + queue->num_elems--; + return ret; +} + +#endif //UTIL_FIFO_C \ No newline at end of file