feat: add interrupt-driven PS/2 keyboard input
Co-authored-by: aider (openrouter/moonshotai/kimi-k2.6) <aider@aider.chat>
This commit is contained in:
+99
-3
@@ -36,6 +36,10 @@ static inline uint8_t inb(uint16_t port) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void io_wait(void) {
|
||||
__asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0), "Nd"((uint16_t)0x80));
|
||||
}
|
||||
|
||||
static void serial_init(void) {
|
||||
outb(0x3F8 + 1, 0x00);
|
||||
outb(0x3F8 + 3, 0x80);
|
||||
@@ -46,6 +50,83 @@ static void serial_init(void) {
|
||||
outb(0x3F8 + 4, 0x0B);
|
||||
}
|
||||
|
||||
static uint64_t idt_entries[256][2];
|
||||
|
||||
static void idt_set_gate(int vector, uint64_t offset, uint16_t selector, uint8_t type_attr) {
|
||||
uint64_t low = (offset & 0xFFFFULL) |
|
||||
((uint64_t)selector << 16) |
|
||||
((uint64_t)(type_attr & 0xFF) << 40) |
|
||||
((offset & 0xFFFF0000ULL) << 32);
|
||||
uint64_t high = offset >> 32;
|
||||
idt_entries[vector][0] = low;
|
||||
idt_entries[vector][1] = high;
|
||||
}
|
||||
|
||||
static struct {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} __attribute__((packed)) idt_ptr;
|
||||
|
||||
static void pic_remap(void) {
|
||||
uint8_t a1 = inb(0x21);
|
||||
uint8_t a2 = inb(0xA1);
|
||||
|
||||
outb(0x20, 0x11);
|
||||
io_wait();
|
||||
outb(0xA0, 0x11);
|
||||
io_wait();
|
||||
outb(0x21, 0x20);
|
||||
io_wait();
|
||||
outb(0xA1, 0x28);
|
||||
io_wait();
|
||||
outb(0x21, 0x04);
|
||||
io_wait();
|
||||
outb(0xA1, 0x02);
|
||||
io_wait();
|
||||
outb(0x21, 0x01);
|
||||
io_wait();
|
||||
outb(0xA1, 0x01);
|
||||
io_wait();
|
||||
|
||||
outb(0x21, a1);
|
||||
outb(0xA1, a2);
|
||||
}
|
||||
|
||||
static void pic_unmask_keyboard(void) {
|
||||
uint8_t mask = inb(0x21);
|
||||
mask &= ~(1 << 1);
|
||||
outb(0x21, mask);
|
||||
}
|
||||
|
||||
#define KEYBUF_SIZE 256
|
||||
static volatile char keybuf[KEYBUF_SIZE];
|
||||
static volatile int keybuf_head = 0;
|
||||
static volatile int keybuf_tail = 0;
|
||||
|
||||
static const char scancode_map[] = {
|
||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
|
||||
0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,
|
||||
'*', 0, ' ', 0
|
||||
};
|
||||
|
||||
void keyboard_handler(void) {
|
||||
uint8_t scancode = inb(0x60);
|
||||
if (scancode < sizeof(scancode_map)) {
|
||||
char c = scancode_map[scancode];
|
||||
if (c) {
|
||||
int next = (keybuf_tail + 1) % KEYBUF_SIZE;
|
||||
if (next != keybuf_head) {
|
||||
keybuf[keybuf_tail] = c;
|
||||
keybuf_tail = next;
|
||||
forth_putchar(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
|
||||
void forth_putchar(char c) {
|
||||
vga_putchar(c);
|
||||
while ((inb(0x3F8 + 5) & 0x20) == 0) { }
|
||||
@@ -53,10 +134,12 @@ void forth_putchar(char c) {
|
||||
}
|
||||
|
||||
int forth_getchar(void) {
|
||||
if ((inb(0x3F8 + 5) & 1) == 0) {
|
||||
return FORTH_EOF;
|
||||
while (keybuf_head == keybuf_tail) {
|
||||
__asm__ volatile ("pause");
|
||||
}
|
||||
return inb(0x3F8);
|
||||
char c = keybuf[keybuf_head];
|
||||
keybuf_head = (keybuf_head + 1) % KEYBUF_SIZE;
|
||||
return (int)c;
|
||||
}
|
||||
|
||||
void forth_fflush(void) {
|
||||
@@ -136,7 +219,20 @@ void forth_printf(const char* fmt, ...) {
|
||||
}
|
||||
|
||||
void kernel_main(void) {
|
||||
extern void isr_keyboard(void);
|
||||
|
||||
serial_init();
|
||||
|
||||
idt_set_gate(0x21, (uint64_t)isr_keyboard, 0x08, 0x8E);
|
||||
idt_ptr.limit = sizeof(idt_entries) - 1;
|
||||
idt_ptr.base = (uint64_t)idt_entries;
|
||||
__asm__ volatile ("lidt %0" : : "m"(idt_ptr));
|
||||
|
||||
pic_remap();
|
||||
pic_unmask_keyboard();
|
||||
|
||||
__asm__ volatile ("sti");
|
||||
|
||||
forth_printf("Kernel started\n");
|
||||
forth_run();
|
||||
forth_panic();
|
||||
|
||||
Reference in New Issue
Block a user