summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2022-03-26 21:06:07 +0100
committerdzwdz2022-03-26 21:06:07 +0100
commit38d1712e31e60de9f2afe85873b2174e002e3e99 (patch)
tree19c402747631d6df2dbd7c9222d7871b941e94ee /src/kernel
parent96f021e783f1e99a1ce7d34c0dfeaef524abc2d1 (diff)
kernel: IRQs; PS/2 keyboard support
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/arch/i386/boot.c3
-rw-r--r--src/kernel/arch/i386/interrupts/irq.c41
-rw-r--r--src/kernel/arch/i386/interrupts/irq.h8
-rw-r--r--src/kernel/arch/i386/interrupts/isr.c8
-rw-r--r--src/kernel/arch/i386/tty/keyboard.c117
-rw-r--r--src/kernel/arch/i386/tty/keyboard.h5
-rw-r--r--src/kernel/arch/i386/tty/serial.c8
-rw-r--r--src/kernel/arch/i386/tty/serial.h3
-rw-r--r--src/kernel/arch/i386/tty/tty.c11
9 files changed, 198 insertions, 6 deletions
diff --git a/src/kernel/arch/i386/boot.c b/src/kernel/arch/i386/boot.c
index 94e9e2f..c25a848 100644
--- a/src/kernel/arch/i386/boot.c
+++ b/src/kernel/arch/i386/boot.c
@@ -3,6 +3,7 @@
#include <kernel/arch/i386/boot.h>
#include <kernel/arch/i386/gdt.h>
#include <kernel/arch/i386/interrupts/idt.h>
+#include <kernel/arch/i386/interrupts/irq.h>
#include <kernel/arch/i386/multiboot.h>
#include <kernel/main.h>
#include <kernel/panic.h>
@@ -16,6 +17,8 @@ void kmain_early(struct multiboot_info *multiboot) {
gdt_init();
tty_const("idt...");
idt_init();
+ tty_const("irq...");
+ irq_init();
tty_const("ata...");
ata_init();
diff --git a/src/kernel/arch/i386/interrupts/irq.c b/src/kernel/arch/i386/interrupts/irq.c
new file mode 100644
index 0000000..cb33bc8
--- /dev/null
+++ b/src/kernel/arch/i386/interrupts/irq.c
@@ -0,0 +1,41 @@
+#include <kernel/arch/i386/interrupts/irq.h>
+#include <kernel/arch/i386/port_io.h>
+#include <stdint.h>
+
+static const int PIC1 = 0x20;
+static const int PIC2 = 0xA0;
+
+static void irq_unmask(uint8_t line) {
+ uint16_t pic = line < 8 ? PIC1 : PIC2;
+ line &= 7;
+
+ port_out8(pic+1, port_in8(pic+1) & ~(1 << line));
+}
+
+void irq_init(void) {
+ port_out8(PIC1, 0x11); /* start init sequence */
+ port_out8(PIC2, 0x11);
+
+ port_out8(PIC1+1, 0x20); /* interrupt offsets */
+ port_out8(PIC2+1, 0x30);
+
+ port_out8(PIC1+1, 0x4); /* just look at the osdev wiki lol */
+ port_out8(PIC2+1, 0x2);
+
+ port_out8(PIC1+1, 0x1); /* 8086 mode */
+ port_out8(PIC2+1, 0x1);
+
+ port_out8(PIC1+1, 0xfd); /* mask */
+ port_out8(PIC2+1, 0xff);
+}
+
+void irq_eoi(uint8_t line) {
+ port_out8(PIC1, 0x20);
+ if (line >= 8)
+ port_out8(PIC2, 0x20);
+}
+
+void irq_interrupt_flag(bool flag) {
+ if (flag) asm("sti" : : : "memory");
+ else asm("cli" : : : "memory");
+}
diff --git a/src/kernel/arch/i386/interrupts/irq.h b/src/kernel/arch/i386/interrupts/irq.h
new file mode 100644
index 0000000..73d4af2
--- /dev/null
+++ b/src/kernel/arch/i386/interrupts/irq.h
@@ -0,0 +1,8 @@
+#pragma once
+#include <stdbool.h>
+#include <stdint.h>
+
+void irq_init(void);
+void irq_eoi(uint8_t line);
+
+void irq_interrupt_flag(bool flag);
diff --git a/src/kernel/arch/i386/interrupts/isr.c b/src/kernel/arch/i386/interrupts/isr.c
index 9d8bb6c..1448f44 100644
--- a/src/kernel/arch/i386/interrupts/isr.c
+++ b/src/kernel/arch/i386/interrupts/isr.c
@@ -1,4 +1,7 @@
+#include <kernel/arch/i386/interrupts/irq.h>
#include <kernel/arch/i386/interrupts/isr.h>
+#include <kernel/arch/i386/port_io.h>
+#include <kernel/arch/i386/tty/keyboard.h>
#include <kernel/arch/io.h>
#include <kernel/panic.h>
#include <kernel/proc.h>
@@ -16,6 +19,11 @@ void isr_stage3(int interrupt) {
isr_test_interrupt_called = true;
return;
+ case 0x21:; // keyboard irq
+ keyboard_recv(port_in8(0x60));
+ irq_eoi(1);
+ return;
+
default:
// TODO check if the exception was in the kernel
process_kill(process_current, interrupt);
diff --git a/src/kernel/arch/i386/tty/keyboard.c b/src/kernel/arch/i386/tty/keyboard.c
new file mode 100644
index 0000000..628c3a0
--- /dev/null
+++ b/src/kernel/arch/i386/tty/keyboard.c
@@ -0,0 +1,117 @@
+#include <kernel/arch/i386/tty/keyboard.h>
+
+static volatile bool keyboard_pressed = false;
+static volatile char keyboard_char;
+
+static bool keys[0x80] = {0};
+
+void keyboard_recv(char s) {
+ char c = 0, d = 0;
+ bool down = !(s & 0x80);
+ keys[s & 0x7f] = down;
+
+ switch (s & 0x7f) {
+ case 0x01: /* esc */ break;
+ case 0x02: c = '1'; d = '!'; break;
+ case 0x03: c = '2'; d = '@'; break;
+ case 0x04: c = '3'; d = '#'; break;
+ case 0x05: c = '4'; d = '$'; break;
+ case 0x06: c = '5'; d = '%'; break;
+ case 0x07: c = '6'; d = '^'; break;
+ case 0x08: c = '7'; d = '&'; break;
+ case 0x09: c = '8'; d = '*'; break;
+ case 0x0A: c = '9'; d = '('; break;
+ case 0x0B: c = '0'; d = ')'; break;
+ case 0x0C: c = '-'; d = '_'; break;
+ case 0x0D: c = '='; d = '+'; break;
+ case 0x0E: c = '\b'; d = '\b'; break;
+ case 0x0F: c = '\t'; d = '\t'; break;
+ case 0x10: c = 'q'; d = 'Q'; break;
+ case 0x11: c = 'w'; d = 'W'; break;
+ case 0x12: c = 'e'; d = 'E'; break;
+ case 0x13: c = 'r'; d = 'R'; break;
+ case 0x14: c = 't'; d = 'T'; break;
+ case 0x15: c = 'y'; d = 'Y'; break;
+ case 0x16: c = 'u'; d = 'U'; break;
+ case 0x17: c = 'i'; d = 'I'; break;
+ case 0x18: c = 'o'; d = 'O'; break;
+ case 0x19: c = 'p'; d = 'P'; break;
+ case 0x1A: c = '['; d = '{'; break;
+ case 0x1B: c = ']'; d = '}'; break;
+ case 0x1C: c = '\r'; d = '\r'; break;
+ case 0x1D: /*lctrl*/ break;
+ case 0x1E: c = 'a'; d = 'A'; break;
+ case 0x1F: c = 's'; d = 'S'; break;
+ case 0x20: c = 'd'; d = 'D'; break;
+ case 0x21: c = 'f'; d = 'F'; break;
+ case 0x22: c = 'g'; d = 'G'; break;
+ case 0x23: c = 'h'; d = 'H'; break;
+ case 0x24: c = 'j'; d = 'J'; break;
+ case 0x25: c = 'k'; d = 'K'; break;
+ case 0x26: c = 'l'; d = 'L'; break;
+ case 0x27: c = ';'; d = ':'; break;
+ case 0x28: c = '\''; d = '"'; break;
+ case 0x29: c = '`'; d = '~'; break;
+ case 0x2A: /*lshift */ break;
+ case 0x2B: c = '\\'; d = '|'; break;
+ case 0x2C: c = 'z'; d = 'Z'; break;
+ case 0x2D: c = 'x'; d = 'X'; break;
+ case 0x2E: c = 'c'; d = 'C'; break;
+ case 0x2F: c = 'v'; d = 'V'; break;
+ case 0x30: c = 'b'; d = 'B'; break;
+ case 0x31: c = 'n'; d = 'N'; break;
+ case 0x32: c = 'm'; d = 'M'; break;
+ case 0x33: c = ','; d = '<'; break;
+ case 0x34: c = '.'; d = '>'; break;
+ case 0x35: c = '/'; d = '?'; break;
+ case 0x36: /*rshift*/ break;
+ case 0x38: /*lalt*/ break;
+ case 0x39: c = ' '; d = ' '; break;
+ case 0x3A: /*caps*/ break;
+ case 0x3B: /* F1 */ break;
+ case 0x3C: /* F2 */ break;
+ case 0x3D: /* F3 */ break;
+ case 0x3E: /* F4 */ break;
+ case 0x3F: /* F5 */ break;
+ case 0x40: /* F6 */ break;
+ case 0x41: /* F7 */ break;
+ case 0x42: /* F8 */ break;
+ case 0x43: /* F9 */ break;
+ case 0x44: /* F10 */ break;
+ case 0x45: /*numlock*/ break;
+ case 0x46: /*scroll^*/ break;
+ case 0x57: /* F11 */ break;
+ case 0x58: /* F12 */ break;
+
+ /* keypad */
+ case 0x37: c = '*'; d = '*'; break;
+ case 0x47: c = '7'; d = '7'; break;
+ case 0x48: c = '8'; d = '8'; break;
+ case 0x49: c = '9'; d = '9'; break;
+ case 0x4A: c = '-'; d = '-'; break;
+ case 0x4B: c = '4'; d = '4'; break;
+ case 0x4C: c = '5'; d = '5'; break;
+ case 0x4D: c = '6'; d = '6'; break;
+ case 0x4E: c = '+'; d = '+'; break;
+ case 0x4F: c = '1'; d = '1'; break;
+ case 0x50: c = '2'; d = '2'; break;
+ case 0x51: c = '3'; d = '3'; break;
+ case 0x52: c = '0'; d = '0'; break;
+ case 0x53: c = '.'; d = '.'; break;
+ }
+
+ if (c && down) {
+ bool shift = keys[0x2A] || keys[0x36];
+ keyboard_pressed = true;
+ keyboard_char = shift ? d : c;
+ }
+}
+
+bool keyboard_poll_read(char *c) {
+ if (!keyboard_pressed) return false;
+ keyboard_pressed = false;
+ *c = keyboard_char;
+ return true;
+}
+
+
diff --git a/src/kernel/arch/i386/tty/keyboard.h b/src/kernel/arch/i386/tty/keyboard.h
new file mode 100644
index 0000000..8f2ebf2
--- /dev/null
+++ b/src/kernel/arch/i386/tty/keyboard.h
@@ -0,0 +1,5 @@
+#pragma once
+#include <stdbool.h>
+
+bool keyboard_poll_read(char *c);
+void keyboard_recv(char scancode);
diff --git a/src/kernel/arch/i386/tty/serial.c b/src/kernel/arch/i386/tty/serial.c
index f9bb252..e77ff5c 100644
--- a/src/kernel/arch/i386/tty/serial.c
+++ b/src/kernel/arch/i386/tty/serial.c
@@ -35,9 +35,11 @@ static void serial_putchar(char c) {
port_out8(COM1, c);
}
-char serial_read(void) {
- while ((port_in8(COM1 + 5) & 0x01) == 0); // wait for DR
- return port_in8(COM1);
+bool serial_poll_read(char *c) {
+ if ((port_in8(COM1 + 5) & 0x01) == 0) // needs DR
+ return false;
+ *c = port_in8(COM1);
+ return true;
}
void serial_write(const char *buf, size_t len) {
diff --git a/src/kernel/arch/i386/tty/serial.h b/src/kernel/arch/i386/tty/serial.h
index 751e528..808f1aa 100644
--- a/src/kernel/arch/i386/tty/serial.h
+++ b/src/kernel/arch/i386/tty/serial.h
@@ -1,6 +1,7 @@
#pragma once
+#include <stdbool.h>
#include <stddef.h>
-char serial_read(void);
+bool serial_poll_read(char *c);
void serial_write(const char *buf, size_t len);
void serial_init(void);
diff --git a/src/kernel/arch/i386/tty/tty.c b/src/kernel/arch/i386/tty/tty.c
index 5a65221..f3fecf3 100644
--- a/src/kernel/arch/i386/tty/tty.c
+++ b/src/kernel/arch/i386/tty/tty.c
@@ -1,3 +1,5 @@
+#include <kernel/arch/i386/interrupts/irq.h>
+#include <kernel/arch/i386/tty/keyboard.h>
#include <kernel/arch/i386/tty/serial.h>
#include <kernel/arch/i386/tty/vga.h>
#include <kernel/arch/io.h>
@@ -12,8 +14,13 @@ void tty_init(void) {
}
void tty_read(char *buf, size_t len) {
- for (size_t i = 0; i < len; i++)
- buf[i] = serial_read();
+ irq_interrupt_flag(true);
+ for (size_t i = 0; i < len; i++) {
+ for (;;) {
+ if (serial_poll_read(&buf[i])) break;
+ if (keyboard_poll_read(&buf[i])) break;
+ }
+ }
}
void tty_write(const char *buf, size_t len) {