From ddb45b819b4ef7adc5125c20082f3ce414e5f9b0 Mon Sep 17 00:00:00 2001 From: vanten-s Date: Fri, 9 Aug 2024 23:16:20 +0200 Subject: [PATCH] Added IRQs and little refactor :3 --- Makefile | 9 +- arch/i686/{ => interrupts}/idt.c | 22 +++-- arch/i686/{ => interrupts}/interrupt.c | 39 +++----- arch/i686/{ => interrupts}/interrupt.h | 1 + arch/i686/interrupts/pic.c | 49 +++++++++ arch/i686/io.h | 22 +++-- arch/i686/pic.c | 17 ---- arch/i686/pic.h | 0 arch/i686/userland.s | 16 +++ include/kernel/keyboard.h | 3 + include/kernel/pic.h | 1 + kernel/debugging.c | 127 ------------------------ kernel/elf.c | 21 +--- kernel/kernel.c | 54 ++++++---- kernel/keyboard.c | 132 +++++++++++++++++++++++++ 15 files changed, 284 insertions(+), 229 deletions(-) rename arch/i686/{ => interrupts}/idt.c (89%) rename arch/i686/{ => interrupts}/interrupt.c (71%) rename arch/i686/{ => interrupts}/interrupt.h (86%) create mode 100644 arch/i686/interrupts/pic.c delete mode 100644 arch/i686/pic.c delete mode 100644 arch/i686/pic.h create mode 100644 arch/i686/userland.s create mode 100644 include/kernel/keyboard.h create mode 100644 include/kernel/pic.h create mode 100644 kernel/keyboard.c diff --git a/Makefile b/Makefile index 57fb95d..09fa2e2 100644 --- a/Makefile +++ b/Makefile @@ -22,14 +22,17 @@ KERNEL_OBJS=\ kernel/kernel.o \ kernel/debugging.o \ kernel/elf.o \ +kernel/keyboard.o \ LIB_OBJS=\ $(ARCHDIR)/bootstrap.o \ $(ARCHDIR)/tty.o \ $(ARCHDIR)/strlib.o \ -$(ARCHDIR)/idt.o \ -$(ARCHDIR)/interrupt.o \ +$(ARCHDIR)/interrupts/idt.o \ +$(ARCHDIR)/interrupts/interrupt.o \ $(ARCHDIR)/gdt.o \ +$(ARCHDIR)/userland.o \ +$(ARCHDIR)/interrupts/pic.o \ OBJS=$(KERNEL_OBJS) $(LIB_OBJS) @@ -50,7 +53,7 @@ clean: rm -f myos.iso rm -f isodir/boot/myos.kernel -$(ARCHDIR)/interrupt.o: CFLAGS += -mgeneral-regs-only +$(ARCHDIR)/interrupts/interrupt.o: CFLAGS += -mgeneral-regs-only # kernel/elf.o: CFLAGS += -masm=intel %.o : %.c diff --git a/arch/i686/idt.c b/arch/i686/interrupts/idt.c similarity index 89% rename from arch/i686/idt.c rename to arch/i686/interrupts/idt.c index 8eb62f9..83c6f15 100644 --- a/arch/i686/idt.c +++ b/arch/i686/interrupts/idt.c @@ -4,7 +4,16 @@ #include "interrupt.h" #include #include -#include "io.h" +#include "../io.h" + +#define IRQ0 0x20 +#define IRQ1 (IRQ0 + 1) +#define IRQ2 (IRQ0 + 2) +#define IRQ3 (IRQ0 + 3) +#define IRQ4 (IRQ0 + 4) +#define IRQ5 (IRQ0 + 5) +#define IRQ6 (IRQ0 + 6) +#define IRQ7 (IRQ0 + 7) #define NUM_ENTRIES 0x100 @@ -104,7 +113,6 @@ struct InterruptDescriptor generate_entry(bool present, void isr(struct interrup void idt_init() { - terminal_initialize(); struct InterruptDescriptor entry; entry = generate_entry(true, exception, 0xF, 0, 0x8); @@ -122,18 +130,20 @@ void idt_init() entry = generate_entry(true, double_fault, 0xF, 0, 0x8); add_entry(entry, DoubleFault); - outb(0x21,0x20); // Tell the PIC to use interrupts 0x20 - 0x27 entry = generate_entry(true, irq, 0xE, 0, 0x8); - for (int i = 0x20; i < 0x28; i++) + for (int i = IRQ0; i <= IRQ7; i++) { add_entry(entry, i); } + entry = generate_entry(true, keyboard_interrupt, 0xE, 0, 0x8); + add_entry(entry, IRQ1); + struct InterruptDescriptor print_entry; print_entry.present = true; print_entry.offset = (uint32_t)print; print_entry.gate_type = 0xE; - print_entry.ring = 0; + print_entry.ring = 3; print_entry.selector = 0x8; add_entry(print_entry, 0x80); @@ -142,7 +152,7 @@ void idt_init() input_entry.present = true; input_entry.offset = (uint32_t)input; input_entry.gate_type = 0xE; - input_entry.ring = 0; + input_entry.ring = 3; input_entry.selector = 0x8; add_entry(input_entry, 0x81); diff --git a/arch/i686/interrupt.c b/arch/i686/interrupts/interrupt.c similarity index 71% rename from arch/i686/interrupt.c rename to arch/i686/interrupts/interrupt.c index ef1e758..166d79b 100644 --- a/arch/i686/interrupt.c +++ b/arch/i686/interrupts/interrupt.c @@ -1,7 +1,8 @@ #include #include #include -#include "io.h" +#include +#include "../io.h" struct interrupt_frame { uint32_t eflags; @@ -45,38 +46,14 @@ __attribute__((interrupt)) void double_fault(struct interrupt_frame* frame) __attribute__((interrupt)) void exception(struct interrupt_frame* frame) { terminal_writestring("Some weird error code stuff\n"); - /* terminal_writestring("Error code:\n"); - print_hex_bytes(frame, sizeof(frame)); - terminal_putchar('\n'); */ while (1) { } } __attribute__((interrupt)) void print(struct interrupt_frame* frame) { - /* terminal_initialize(); - terminal_putchar(test); - test++; */ - char* start; asm("mov %%edx, %0" : "=r" (start)); terminal_writestring(start); - - /* uint8_t* stack; - asm("mov %%esp, %0" : "=r" (stack)); - - terminal_writestring("\nSTACK:\n"); - print_hex_bytes(stack - 24, 4); - terminal_putchar('\n'); - print_hex_bytes(stack - 20, 4); - terminal_putchar('\n'); - print_hex_bytes(stack - 16, 4); - terminal_putchar('\n'); - print_hex_bytes(stack - 12, 4); - terminal_putchar('\n'); - print_hex_bytes(stack - 8, 4); - terminal_putchar('\n'); - print_hex_bytes(stack - 4, 4); - terminal_putchar('\n'); */ } __attribute__((interrupt)) void input(struct interrupt_frame* frame) @@ -84,7 +61,7 @@ __attribute__((interrupt)) void input(struct interrupt_frame* frame) char* buffer; asm("mov %%edx, %0" : "=r" (buffer)); - size_t index = 0; + /* size_t index = 0; char current_character = get_last_key_pressed(); while (current_character != '\n') { @@ -96,12 +73,18 @@ __attribute__((interrupt)) void input(struct interrupt_frame* frame) } current_character = tmp; } - buffer[index] = '\0'; + buffer[index] = '\0'; */ +} + +__attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame* frame) +{ + uint8_t scancode = inb(0x60); + handle_keyboard(scancode); + outb(0x20, 0x20); } __attribute__((interrupt)) void irq(struct interrupt_frame* frame) { - terminal_writestring("Test"); outb(0x20, 0x20); } diff --git a/arch/i686/interrupt.h b/arch/i686/interrupts/interrupt.h similarity index 86% rename from arch/i686/interrupt.h rename to arch/i686/interrupts/interrupt.h index 6c13bb0..f279846 100644 --- a/arch/i686/interrupt.h +++ b/arch/i686/interrupts/interrupt.h @@ -9,4 +9,5 @@ __attribute__((interrupt)) void exception(struct interrupt_frame* frame); __attribute__((interrupt)) void print(struct interrupt_frame* frame); __attribute__((interrupt)) void input(struct interrupt_frame* frame); +__attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame* frame); __attribute__((interrupt)) void irq(struct interrupt_frame* frame); diff --git a/arch/i686/interrupts/pic.c b/arch/i686/interrupts/pic.c new file mode 100644 index 0000000..2fbd998 --- /dev/null +++ b/arch/i686/interrupts/pic.c @@ -0,0 +1,49 @@ +#include "../io.h" + +#define PIC1 0x20 /* IO base address for master PIC */ +#define PIC2 0xA0 /* IO base address for slave PIC */ +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1+1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2+1) + +#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */ +#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ +#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ +#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ +#define ICW1_INIT 0x10 /* Initialization - required! */ + +#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ +#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ +#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ +#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ +#define ICW4_SFNM 0x10 /* Special fully nested (not) */ + +void init_pic() { + uint8_t a1, a2; + + a1 = inb(PIC1_DATA); // save masks + a2 = inb(PIC2_DATA); + + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode) + io_wait(); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + io_wait(); + outb(PIC1_DATA, 0x20); // ICW2: Master PIC vector offset + io_wait(); + outb(PIC2_DATA, 0xFF); // ICW2: Slave PIC vector offset + io_wait(); + outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) + io_wait(); + outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010) + io_wait(); + + outb(PIC1_DATA, ICW4_8086); // ICW4: have the PICs use 8086 mode (and not 8080 mode) + io_wait(); + outb(PIC2_DATA, ICW4_8086); + io_wait(); + + outb(PIC1_DATA, a1); // restore saved masks. + // outb(PIC2_DATA, a2); + outb(PIC2_DATA, 0xFF); +} diff --git a/arch/i686/io.h b/arch/i686/io.h index 03c63a7..b032831 100644 --- a/arch/i686/io.h +++ b/arch/i686/io.h @@ -3,17 +3,19 @@ static inline void outb(uint16_t port, uint8_t val) { __asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); - /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint). - * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint). - * The outb %al, %dx encoding is the only option for all other cases. - * %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */ } -static inline void inb(uint16_t port, uint8_t val) +static inline uint8_t inb(uint16_t port) { - __asm__ volatile ( "inb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); - /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint). - * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint). - * The outb %al, %dx encoding is the only option for all other cases. - * %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */ + uint8_t ret; + __asm__ volatile ( "inb %w1, %b0" + : "=a"(ret) + : "Nd"(port) + : "memory"); + return ret; +} + +static inline void io_wait(void) +{ + outb(0x80, 0); } diff --git a/arch/i686/pic.c b/arch/i686/pic.c deleted file mode 100644 index 2ebc53c..0000000 --- a/arch/i686/pic.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "io.h" - -#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */ -#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ -#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ -#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ -#define ICW1_INIT 0x10 /* Initialization - required! */ - -#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ -#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ -#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ -#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ -#define ICW4_SFNM 0x10 /* Special fully nested (not) */ - -void init_pic() { - -} diff --git a/arch/i686/pic.h b/arch/i686/pic.h deleted file mode 100644 index e69de29..0000000 diff --git a/arch/i686/userland.s b/arch/i686/userland.s new file mode 100644 index 0000000..97a8976 --- /dev/null +++ b/arch/i686/userland.s @@ -0,0 +1,16 @@ +.global jump_to_userspace +jump_to_userspace: +mov $0x20 | 0x3, %ax +movw %ax, %ds +movw %ax, %es +movw %ax, %fs +movw %ax, %gs +pushl $0x20 | 0x3 /* SS*/ +pushl $0x00c00100 /* ESP */ +pushf /* EFLAGS */ +popl %eax +orl $0x200, %eax +pushl %eax /* Set interrupts */ +pushl $0x18 | 0x3 /* CS */ +pushl $0x00800000 /* EIP */ +iret diff --git a/include/kernel/keyboard.h b/include/kernel/keyboard.h new file mode 100644 index 0000000..dc716be --- /dev/null +++ b/include/kernel/keyboard.h @@ -0,0 +1,3 @@ +#include + +void handle_keyboard(uint8_t scancode); diff --git a/include/kernel/pic.h b/include/kernel/pic.h new file mode 100644 index 0000000..25643e4 --- /dev/null +++ b/include/kernel/pic.h @@ -0,0 +1 @@ +void init_pic(); diff --git a/kernel/debugging.c b/kernel/debugging.c index 2e3a063..1d129f9 100644 --- a/kernel/debugging.c +++ b/kernel/debugging.c @@ -3,133 +3,6 @@ #include #include -static inline uint8_t inb(uint16_t port) -{ - uint8_t ret; - __asm__ volatile ( "inb %w1, %b0" - : "=a"(ret) - : "Nd"(port) - : "memory"); - return ret; -} - -static bool is_in_shift; - -static unsigned char keyboard_char(unsigned char scancode) -{ - if (0x01 < scancode && scancode < 0x0B) { - return scancode - 2 + '1'; - } - - if (scancode == 0x0B) { - return '0'; - } - - switch (scancode) { - case 0x10: - return 'Q'; - case 0x11: - return 'W'; - case 0x12: - return 'E'; - case 0x13: - return 'R'; - case 0x14: - return 'T'; - case 0x15: - return 'Y'; - case 0x16: - return 'U'; - case 0x17: - return 'I'; - case 0x18: - return 'O'; - case 0x19: - return 'P'; - case 0x1a: - return '['; - case 0x1b: - return ']'; - case 0x1c: - return '\n'; - case 0x1d: - return '\b'; - case 0x1e: - return 'A'; - case 0x1f: - return 'S'; - case 0x20: - return 'D'; - case 0x21: - return 'F'; - case 0x22: - return 'G'; - case 0x23: - return 'H'; - case 0x24: - return 'J'; - case 0x25: - return 'K'; - case 0x26: - return 'L'; - case 0x27: - return ';'; - case 0x28: - return '\''; - case 0x29: - return '`'; - case 0x2a: - is_in_shift = true; - break; - case 0x2b: - return '\\'; - case 0x2c: - return 'Z'; - case 0x2d: - return 'X'; - case 0x2e: - return 'C'; - case 0x2f: - return 'V'; - case 0x30: - return 'B'; - case 0x31: - return 'N'; - case 0x32: - return 'M'; - case 0x33: - return ','; - case 0x34: - return '.'; - case 0x35: - return '/'; - case 0x36: - is_in_shift = true; - break; - case 0x39: - return ' '; - case 0xaa: - is_in_shift = false; - break; - case 0xb6: - is_in_shift = false; - break; - } - - return -1; -} - -char get_last_key_pressed() -{ - char scancode = inb(0x60); - - if (is_in_shift) { - return keyboard_char(scancode); - } - - return to_lower_char(keyboard_char(scancode)); -} - void print_hex_digit(uint8_t digit) { digit = digit & 0xf; diff --git a/kernel/elf.c b/kernel/elf.c index ee8f045..cc04993 100644 --- a/kernel/elf.c +++ b/kernel/elf.c @@ -13,25 +13,12 @@ static void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t s return dstptr; } +extern void jump_to_userspace(); + void run_program(uint8_t* program, size_t length) { - uint8_t* userland_code = (uint8_t*) 0x0; + uint8_t* userland_code = (uint8_t*) 0x00800000; memcpy(userland_code, program, length); - print_hex_bytes(userland_code, 1); - terminal_putchar('\n'); - - asm ("\ - mov $0x20 | 0x3, %%ax;\ - movw %%ax, %%ds;\ - movw %%ax, %%es;\ - movw %%ax, %%fs;\ - movw %%ax, %%gs;\ - pushl $0x20 | 0x3; /* SS selector */ \ - pushl $0x00c00100; /* ESP */ \ - pushf; /* EFLAGS */ \ - popl %%eax; orl $0x200, %%eax; pushl %%eax; /* Set interrupts in USERPACE */\ - pushl $0x18 | 0x3; /* CS selector */\ - pushl $0x0; /* EIP */ \ - iret;":::"eax"); + jump_to_userspace(); } diff --git a/kernel/kernel.c b/kernel/kernel.c index aa33cb1..425ec67 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -2,6 +2,7 @@ #include #include #include +#include /* Check if the compiler thinks you are targeting the wrong operating system. */ #if defined(__linux__) @@ -9,34 +10,45 @@ #endif uint8_t program[] = { - 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, 0x0 (Just a simple NOP-like instruction) - 0xF4 // hlt (halts the CPU, should trap to kernel if interrupts enabled) + 0xba, 0x09, 0x00, 0x80, 0x00, // mov $string, %edx + 0xcd, 0x80, // int 0x80 + 0xeb, 0xfe, // jmp . + 'H', + 'e', + 'l', + 'l', + 'o', + ' ', + 'W', + 'o', + 'r', + 'l', + 'd', + ' ', + 'f', + 'r', + 'o', + 'm', + ' ', + 'r', + 'i', + 'n', + 'g', + ' ', + '3', + '!', + 0x00, }; void kernel_main(void) { /* Initialize terminal interface */ - // terminal_initialize(); + terminal_initialize(); + init_pic(); idt_init(); - - // asm("int $13"); - // asm("ljmp $0x18, $0x00c00100"); // Example: Far jump to user code segment with selector 0x18 - - print_hex_bytes(idt_init, 4); - terminal_putchar('\n'); - - run_program(program, 15); - - /* - char buf[100]; - + // run_program(program, sizeof(program)); while (true) { - asm("mov %0, %%edx" :: "r" (buf)); - asm("int $0x81"); - terminal_writestring("newline"); - terminal_putchar('\n'); - } - */ + } } diff --git a/kernel/keyboard.c b/kernel/keyboard.c new file mode 100644 index 0000000..e9fedcf --- /dev/null +++ b/kernel/keyboard.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +static bool is_in_shift; + +char buffer[100]; +static size_t i; + +static unsigned char keyboard_char(unsigned char scancode) +{ + if (0x01 < scancode && scancode < 0x0B) { + return scancode - 2 + '1'; + } + + if (scancode == 0x0B) { + return '0'; + } + + switch (scancode) { + case 0x10: + return 'Q'; + case 0x11: + return 'W'; + case 0x12: + return 'E'; + case 0x13: + return 'R'; + case 0x14: + return 'T'; + case 0x15: + return 'Y'; + case 0x16: + return 'U'; + case 0x17: + return 'I'; + case 0x18: + return 'O'; + case 0x19: + return 'P'; + case 0x1a: + return '['; + case 0x1b: + return ']'; + case 0x1c: + return '\n'; + case 0x1d: + return '\b'; + case 0x1e: + return 'A'; + case 0x1f: + return 'S'; + case 0x20: + return 'D'; + case 0x21: + return 'F'; + case 0x22: + return 'G'; + case 0x23: + return 'H'; + case 0x24: + return 'J'; + case 0x25: + return 'K'; + case 0x26: + return 'L'; + case 0x27: + return ';'; + case 0x28: + return '\''; + case 0x29: + return '`'; + case 0x2a: + is_in_shift = true; + break; + case 0x2b: + return '\\'; + case 0x2c: + return 'Z'; + case 0x2d: + return 'X'; + case 0x2e: + return 'C'; + case 0x2f: + return 'V'; + case 0x30: + return 'B'; + case 0x31: + return 'N'; + case 0x32: + return 'M'; + case 0x33: + return ','; + case 0x34: + return '.'; + case 0x35: + return '/'; + case 0x36: + is_in_shift = true; + break; + case 0x39: + return ' '; + case 0xaa: + is_in_shift = false; + break; + case 0xb6: + is_in_shift = false; + break; + } + + return -1; +} + +void handle_keyboard(uint8_t scancode) { + char character; + + if (is_in_shift) { + character = keyboard_char(scancode); + } else { + character = to_lower_char(keyboard_char(scancode)); + } + + if (character == -1) { + return; + } + + buffer[i] = character; + i++; + + terminal_putchar(character); +}