Interrupt and keyboard support
This commit is contained in:
parent
1069a04ca3
commit
2177fa1bc9
8 changed files with 274 additions and 35 deletions
4
Makefile
4
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
82
kernel/drivers/keyboard/keyboard.c
Normal file
82
kernel/drivers/keyboard/keyboard.c
Normal 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
|
42
kernel/drivers/keyboard/keycodes.c
Normal file
42
kernel/drivers/keyboard/keycodes.c
Normal 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
|
80
kernel/drivers/keyboard/keymaps/DUMMY_azerty.c
Normal file
80
kernel/drivers/keyboard/keymaps/DUMMY_azerty.c
Normal 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
|
|
@ -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
|
|
@ -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
60
kernel/util/fifo.c
Normal 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
|
Loading…
Reference in a new issue