From 59d7b06117db9ecf3e91599260d75f09866df4ba Mon Sep 17 00:00:00 2001 From: lucic71 Date: Tue, 28 Jun 2022 19:40:51 +0300 Subject: [PATCH] Implemented irq and isr --- kernel/arch/i386/irq/irq.c | 98 ++++++++++++++++++++++ kernel/arch/i386/irq/irq_gate.S | 66 +++++++++++++++ kernel/arch/i386/irq/pic.c | 54 ++++++++++++ kernel/arch/i386/isr/isr.c | 143 ++++++++++++++++++++++++++++++++ kernel/arch/i386/isr/isr_gate.S | 89 ++++++++++++++++++++ 5 files changed, 450 insertions(+) create mode 100644 kernel/arch/i386/irq/irq.c create mode 100644 kernel/arch/i386/irq/irq_gate.S create mode 100644 kernel/arch/i386/irq/pic.c create mode 100644 kernel/arch/i386/isr/isr.c create mode 100644 kernel/arch/i386/isr/isr_gate.S diff --git a/kernel/arch/i386/irq/irq.c b/kernel/arch/i386/irq/irq.c new file mode 100644 index 0000000..7ba41d8 --- /dev/null +++ b/kernel/arch/i386/irq/irq.c @@ -0,0 +1,98 @@ +#include "i386/irq.h" +#include "i386/pic.h" + +#include "i386/idt.h" +#include "i386/context.h" + +#include + +/* Extern symbol defined in idt.c */ + +extern idt_entry_t idt_entries[256]; + +/* External Interrupt Service Routines. */ + +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +/* + * irq_init: + * --------- + * + * Remap PIC pins to match the IRQ starting from 32. + * + */ + +void irq_init(void) { + + pic_remap(IRQ0, IRQ8); + + idt_entries[32] = idt_set_gate( (uint32_t) irq0, 0x08, 0x8E); + idt_entries[33] = idt_set_gate( (uint32_t) irq1, 0x08, 0x8E); + idt_entries[34] = idt_set_gate( (uint32_t) irq2, 0x08, 0x8E); + idt_entries[35] = idt_set_gate( (uint32_t) irq3, 0x08, 0x8E); + idt_entries[36] = idt_set_gate( (uint32_t) irq4, 0x08, 0x8E); + idt_entries[37] = idt_set_gate( (uint32_t) irq5, 0x08, 0x8E); + idt_entries[38] = idt_set_gate( (uint32_t) irq6, 0x08, 0x8E); + idt_entries[39] = idt_set_gate( (uint32_t) irq7, 0x08, 0x8E); + idt_entries[40] = idt_set_gate( (uint32_t) irq8, 0x08, 0x8E); + idt_entries[41] = idt_set_gate( (uint32_t) irq9, 0x08, 0x8E); + idt_entries[42] = idt_set_gate( (uint32_t) irq10, 0x08, 0x8E); + idt_entries[43] = idt_set_gate( (uint32_t) irq11, 0x08, 0x8E); + idt_entries[44] = idt_set_gate( (uint32_t) irq12, 0x08, 0x8E); + idt_entries[45] = idt_set_gate( (uint32_t) irq13, 0x08, 0x8E); + idt_entries[46] = idt_set_gate( (uint32_t) irq14, 0x08, 0x8E); + idt_entries[47] = idt_set_gate( (uint32_t) irq15, 0x08, 0x8E); + +} + +/* + * register_irq: + * ------------- + * + * Register a handler in intrpt_handlers array. + * + */ + +irq_t intrpt_handlers[256]; + +void register_irq(uint8_t irq_no, irq_t handler) { + + intrpt_handlers[irq_no] = handler; + +} + +/* + * irq_handler: + * ------------ + * + * Using the intrpt number present in context, choose the appropiate handler. + * The routine should also send and EOI signal to PIC. + * + */ + +void irq_handler(context_t context) { + + pic_send_eoi(context.int_no); + + irq_t handler = intrpt_handlers[context.int_no]; + if (handler) + handler(context); + else + puts("Unhandled interrupt"); + +} diff --git a/kernel/arch/i386/irq/irq_gate.S b/kernel/arch/i386/irq/irq_gate.S new file mode 100644 index 0000000..12ba0d3 --- /dev/null +++ b/kernel/arch/i386/irq/irq_gate.S @@ -0,0 +1,66 @@ +.extern irq_handler + +/* Macro that defines an IRQ gate using the irq number and its corresponding IDT index. */ + +.macro IRQ _irq_nr, _idt_nr +.global irq\_irq_nr +irq\_irq_nr: + cli + push $0x00 + push $\_idt_nr + jmp irq_common_stub +.endm + +/* Define the gates. */ + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +/* + * Common stub that saves the context on the stack and restores it after + * the handler is done + * + * To see a more comprehensibile layout of the data saved on the stack, please + * check context.h + * + */ + +irq_common_stub: + + pusha + + mov %ds, %ax + push %eax + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + call irq_handler + + pop %ebx + mov %bx, %ds + mov %bx, %es + mov %bx, %fs + mov %bx, %gs + + popa + add $0x08, %esp + sti + iret diff --git a/kernel/arch/i386/irq/pic.c b/kernel/arch/i386/irq/pic.c new file mode 100644 index 0000000..2cdbf66 --- /dev/null +++ b/kernel/arch/i386/irq/pic.c @@ -0,0 +1,54 @@ +#include "i386/pic.h" +#include "i386/irq.h" + +#include + +/* + * pic_remap: + * ---------- + * + * Save the state of the data ports. Initialize the PICs, write the vector + * offsets, tell the master PIC about the slave and inform the slave about + * its identity; and set the PICs in 8086 mode. + * + */ + +void pic_remap(uint8_t offset1, uint8_t offset2) { + + uint8_t d1, d2; + + d1 = inb(PIC1_DATA); + d2 = inb(PIC2_DATA); + + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + + outb(PIC1_DATA, offset1); + outb(PIC2_DATA, offset2); + + outb(PIC1_DATA, ICW3_SLAVE_IRQ); + outb(PIC2_DATA, ICW3_SLAVE_ID); + + outb(PIC1_DATA, ICW4_8086); + outb(PIC2_DATA, ICW4_8086); + + outb(PIC1_DATA, d1); + outb(PIC2_DATA, d2); + +} + +/* + * pic_send_eoi: + * ------------- + * + * + */ + +void pic_send_eoi(uint8_t irq) { + + if (irq >= IRQ8) + outb(PIC2_COMMAND, PIC_EOI); + + outb(PIC1_COMMAND, PIC_EOI); + +} diff --git a/kernel/arch/i386/isr/isr.c b/kernel/arch/i386/isr/isr.c new file mode 100644 index 0000000..bf61663 --- /dev/null +++ b/kernel/arch/i386/isr/isr.c @@ -0,0 +1,143 @@ +#include "i386/isr.h" + +#include "i386/idt.h" +#include "i386/context.h" + +#include +#include + +/* Extern symbol defined in idt.c */ + +extern idt_entry_t idt_entries[256]; + +/* External Interrupt Service Routines. */ + +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +/* + * isr_init: + * --------- + * + * Fill the first 32 entries in IDT. + * + */ + +void isr_init(void) { + + idt_entries[0] = idt_set_gate((uint32_t) isr0, 0x08, 0x8E); + idt_entries[1] = idt_set_gate((uint32_t) isr1, 0x08, 0x8E); + idt_entries[2] = idt_set_gate((uint32_t) isr2, 0x08, 0x8E); + idt_entries[3] = idt_set_gate((uint32_t) isr3, 0x08, 0x8E); + idt_entries[4] = idt_set_gate((uint32_t) isr4, 0x08, 0x8E); + idt_entries[5] = idt_set_gate((uint32_t) isr5, 0x08, 0x8E); + idt_entries[6] = idt_set_gate((uint32_t) isr6, 0x08, 0x8E); + idt_entries[7] = idt_set_gate((uint32_t) isr7, 0x08, 0x8E); + idt_entries[8] = idt_set_gate((uint32_t) isr8, 0x08, 0x8E); + idt_entries[9] = idt_set_gate((uint32_t) isr9, 0x08, 0x8E); + idt_entries[10] = idt_set_gate( (uint32_t) isr10, 0x08, 0x8E); + idt_entries[11] = idt_set_gate( (uint32_t) isr11, 0x08, 0x8E); + idt_entries[12] = idt_set_gate( (uint32_t) isr12, 0x08, 0x8E); + idt_entries[13] = idt_set_gate( (uint32_t) isr13, 0x08, 0x8E); + idt_entries[14] = idt_set_gate( (uint32_t) isr14, 0x08, 0x8E); + idt_entries[15] = idt_set_gate( (uint32_t) isr15, 0x08, 0x8E); + idt_entries[16] = idt_set_gate( (uint32_t) isr16, 0x08, 0x8E); + idt_entries[17] = idt_set_gate( (uint32_t) isr17, 0x08, 0x8E); + idt_entries[18] = idt_set_gate( (uint32_t) isr18, 0x08, 0x8E); + idt_entries[19] = idt_set_gate( (uint32_t) isr19, 0x08, 0x8E); + idt_entries[20] = idt_set_gate( (uint32_t) isr20, 0x08, 0x8E); + idt_entries[21] = idt_set_gate( (uint32_t) isr21, 0x08, 0x8E); + idt_entries[22] = idt_set_gate( (uint32_t) isr22, 0x08, 0x8E); + idt_entries[23] = idt_set_gate( (uint32_t) isr23, 0x08, 0x8E); + idt_entries[24] = idt_set_gate( (uint32_t) isr24, 0x08, 0x8E); + idt_entries[25] = idt_set_gate( (uint32_t) isr25, 0x08, 0x8E); + idt_entries[26] = idt_set_gate( (uint32_t) isr26, 0x08, 0x8E); + idt_entries[27] = idt_set_gate( (uint32_t) isr27, 0x08, 0x8E); + idt_entries[28] = idt_set_gate( (uint32_t) isr28, 0x08, 0x8E); + idt_entries[29] = idt_set_gate( (uint32_t) isr29, 0x08, 0x8E); + idt_entries[30] = idt_set_gate( (uint32_t) isr30, 0x08, 0x8E); + idt_entries[31] = idt_set_gate( (uint32_t) isr31, 0x08, 0x8E); + +} + +/* Exception messages for unhandled faults. */ + +char *exception_messages[] = { + "Division by zero", + "Debug", + "Non-maskable interrupt", + "Breakpoint", + "Detected overflow", + "Out-of-bounds", + "Invalid opcode", + "No coprocessor", + "Double fault", + "Coprocessor segment overrun", + "Bad TSS", + "Segment not present", + "Stack fault", + "General protection fault", + "Page fault", + "Unknown interrupt", + "Coprocessor fault", + "Alignment check", + "Machine check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +/* isr_handler: + * Handles an incomming request by calling the appropiate handler or printing + * an exception message. + * + * @param context - the context of the caller + * + */ + +void isr_handler(context_t context) { + + printf("Unhandled exception: %s\n", exception_messages[context.int_no]); + +} + diff --git a/kernel/arch/i386/isr/isr_gate.S b/kernel/arch/i386/isr/isr_gate.S new file mode 100644 index 0000000..524bc69 --- /dev/null +++ b/kernel/arch/i386/isr/isr_gate.S @@ -0,0 +1,89 @@ +.extern isr_handler + +/* Macros that define the entry point in ISRs with and without an error code. */ + +.macro ISR_NO_ERRCODE _isr_nr +.global isr\_isr_nr +isr\_isr_nr: + cli + push $0x00 + push $\_isr_nr + jmp isr_common_stub +.endm + +.macro ISR_ERRCODE _isr_nr +.global isr\_isr_nr +isr\_isr_nr: + cli + push $\_isr_nr + jmp isr_common_stub +.endm + +/* Expandation of the above mentioned macros. */ + +ISR_NO_ERRCODE 0 +ISR_NO_ERRCODE 1 +ISR_NO_ERRCODE 2 +ISR_NO_ERRCODE 3 +ISR_NO_ERRCODE 4 +ISR_NO_ERRCODE 5 +ISR_NO_ERRCODE 6 +ISR_NO_ERRCODE 7 +ISR_ERRCODE 8 +ISR_NO_ERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NO_ERRCODE 15 +ISR_NO_ERRCODE 16 +ISR_NO_ERRCODE 17 +ISR_NO_ERRCODE 18 +ISR_NO_ERRCODE 19 +ISR_NO_ERRCODE 20 +ISR_NO_ERRCODE 21 +ISR_NO_ERRCODE 22 +ISR_NO_ERRCODE 23 +ISR_NO_ERRCODE 24 +ISR_NO_ERRCODE 25 +ISR_NO_ERRCODE 26 +ISR_NO_ERRCODE 27 +ISR_NO_ERRCODE 28 +ISR_NO_ERRCODE 29 +ISR_NO_ERRCODE 30 +ISR_NO_ERRCODE 31 + +/* + * Stub for ISRs. It must push the context on the stack and change the PL. + * After the isr_handler was called the context will be restored and the + * error code and the request number will be cleared from the stack. + * + */ + +isr_common_stub: + + pusha + + mov %ds, %ax + push %eax + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + call isr_handler + + pop %eax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + popa + add $0x08, %esp + + sti + iret