Interrupt and keyboard support

This commit is contained in:
Robbe Van Herck 2020-01-09 12:06:45 +01:00
parent 1069a04ca3
commit 2177fa1bc9
No known key found for this signature in database
GPG key ID: A66F76F7B81BD784
8 changed files with 274 additions and 35 deletions

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,82 @@
#ifndef DRIVERS_KEYBOARD_C
#define DRIVERS_KEYBOARD_C
#include <stdbool.h>
#include <stddef.h>
#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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -60,5 +60,8 @@ void kernel_main(void)
interrupt_init();
while(true) {}
for(;;) {
char curr_char = getchar();
terminal_putchar(curr_char);
}
}

60
kernel/util/fifo.c Normal file
View file

@ -0,0 +1,60 @@
#ifndef UTIL_FIFO_C
#define UTIL_FIFO_C
#define FIFO_INITIAL_SIZE 128
#define FIFO_QUEUE_EMPTY -1
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#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