From ddc0c4c84a2cf05cc558118a76d1384ff44c0ac1 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 7 Oct 2021 21:23:32 +0200 Subject: [PATCH 1/4] Wrap IRQ with ASM --- Makefile | 4 +--- README.md | 2 +- arch/x86/interrupt.h | 3 --- arch/x86/irq.c | 41 +++++++++++++++++++++++++++++++++++++++++ arch/x86/irq.h | 3 +++ arch/x86/irq_handler.c | 29 ----------------------------- core/klibc.h | 1 + core/main.c | 3 ++- drivers/serial.c | 2 +- 9 files changed, 50 insertions(+), 38 deletions(-) delete mode 100644 arch/x86/irq_handler.c diff --git a/Makefile b/Makefile index cbea915..540c435 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ CPPFLAGS += $(foreach dir, $(SUBDIRS), -I$(dir)) asmsrc=$(wildcard arch/$(ARCH)/boot/*.asm) asmobj=$(asmsrc:%.asm=%.o) csrc=$(shell find $(SUBDIRS) -type f -name "*.c")# $(wildcard *.c) -cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o +cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o arch/$(ARCH)/irq_wrappers.o deps = $(csrc:%.c=%.d) kernel kernel.sym &: $(asmobj) $(cobj) linker.ld @@ -37,8 +37,6 @@ disk.img: #https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes arch/$(ARCH)/exception_handler.o:arch/$(ARCH)/exception_handler.c $(CC) $(CFLAGS) $(CPPFLAGS) -mgeneral-regs-only -c $< -o $@ -arch/$(ARCH)/irq_handler.o:arch/$(ARCH)/irq_handler.c - $(CC) $(CFLAGS) $(CPPFLAGS) -mgeneral-regs-only -c $< -o $@ %.o:%.asm $(AS) $(ASFLAGS) -o $@ $< diff --git a/README.md b/README.md index 0b85547..31a046d 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ To generate iso image you can also test it - `make self_test` + `make test` # Debug diff --git a/arch/x86/interrupt.h b/arch/x86/interrupt.h index 5b27cd9..3c0c49f 100644 --- a/arch/x86/interrupt.h +++ b/arch/x86/interrupt.h @@ -52,6 +52,3 @@ DECLARE_INTERRUPT(EXCEPTION_RESERVED_11) // IRQ void pit_handler(struct interrupt_frame *frame); -void keyboard_handler(struct interrupt_frame *frame); -void timer_handler(struct interrupt_frame *frame); -void serial_handler(struct interrupt_frame *frame); diff --git a/arch/x86/irq.c b/arch/x86/irq.c index 9b57d1e..8785c49 100644 --- a/arch/x86/irq.c +++ b/arch/x86/irq.c @@ -1,7 +1,10 @@ #include "irq.h" #include "idt.h" +#include "io.h" +#include "klibc.h" #include "pic.h" #include "stdarg.h" +#include "types.h" int irqSetup() { @@ -9,10 +12,28 @@ int irqSetup() return 0; } +// Assembly defined array. This is used to wrap C function than cannot: +// * get some cpu state +// * return using "iret" instead of "ret" without some compiler __attribute__ +extern vaddr_t irq_handler_wrapper_array[IRQ_NUM]; + irq_handler irq_handler_array[IRQ_NUM] = { NULL, }; +void interrupt_handler_pic(int interrupt, struct interrupt_frame *frame) +{ + if (0 > interrupt || IRQ_NUM <= interrupt) { + pr_err("Trying to handle unknow interrupt %d\n", interrupt); + return; + } + + EOIIrq(interrupt); + + if (irq_handler_array[interrupt] != NULL) + irq_handler_array[interrupt](frame); +} + int irqSetRoutine(int irq, irq_handler handler) { uint32_t flags; @@ -32,3 +53,23 @@ int irqSetRoutine(int irq, irq_handler handler) restore_IRQs(flags); return 0; } + +int irqSetRoutineWrapped(int irq, irq_handler handler) +{ + uint32_t flags; + if ((irq < 0) || irq >= IRQ_NUM) + return -1; + + disable_IRQs(flags); + + irq_handler_array[irq] = handler; + + if (handler != NULL) { + int ret = idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq, + (unsigned int)irq_handler_wrapper_array[irq], 0); + if (!ret) + enableIrq(irq); + } + restore_IRQs(flags); + return 0; +} diff --git a/arch/x86/irq.h b/arch/x86/irq.h index 1bbebd5..285dfee 100644 --- a/arch/x86/irq.h +++ b/arch/x86/irq.h @@ -37,4 +37,7 @@ // __attribute__((interrupt)) void (*irq_handler)(int irq); typedef void (*irq_handler)(struct interrupt_frame *frame); int irqSetup(); +// For C coded handler (The interrupt specific part is managed by a wrapper) +int irqSetRoutineWrapped(int irq, irq_handler handler); +// For ASM handler taking care of the special instruction needed by an IRQ handler int irqSetRoutine(int irq, irq_handler handler); diff --git a/arch/x86/irq_handler.c b/arch/x86/irq_handler.c deleted file mode 100644 index 77b9a41..0000000 --- a/arch/x86/irq_handler.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "interrupt.h" -#include "io.h" -#include "irq.h" -#include "keyboard.h" -#include "pic.h" -#include "serial.h" -#include "vga.h" - -// Need GCC > 6 -__attribute__((interrupt)) void keyboard_handler(struct interrupt_frame *frame) -{ - EOIIrq(IRQ_KEYBOARD); - keyboard_do_irq(); - (void)frame; -} - -__attribute__((interrupt)) void timer_handler(struct interrupt_frame *frame) -{ - static int timeCnt = 0; - EOIIrq(IRQ_TIMER); - VGAPrintf(RED, BLACK, 20, VGA_HEIGHT - 1, "IRQ %d", timeCnt++); - (void)frame; -} - -__attribute__((interrupt)) void serial_handler(struct interrupt_frame *frame) -{ - EOIIrq(IRQ_COM1); - serialDoIrq(frame); -} diff --git a/core/klibc.h b/core/klibc.h index c4a5490..9d5e41b 100644 --- a/core/klibc.h +++ b/core/klibc.h @@ -1,4 +1,5 @@ #pragma once +#include "assert.h" #include "stdarg.h" #include "minmax.h" diff --git a/core/main.c b/core/main.c index 44e99a8..e173311 100644 --- a/core/main.c +++ b/core/main.c @@ -7,6 +7,7 @@ #include "interrupt.h" #include "io.h" #include "irq.h" +#include "keyboard.h" #include "klibc.h" #include "kthread.h" #include "mem.h" @@ -134,7 +135,7 @@ void kmain(unsigned long magic, unsigned long addr) } printf("Setting up IRQ handlers\n"); - irqSetRoutine(IRQ_KEYBOARD, keyboard_handler); + irqSetRoutineWrapped(IRQ_KEYBOARD, keyboard_do_irq); printf("Enabling HW interrupts\n"); // Enabling the HW interrupts diff --git a/drivers/serial.c b/drivers/serial.c index 03586de..959f8bd 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -32,7 +32,7 @@ void serialSetup(int speed) UART_1_STOP_BIT); // 8 bits, no parity, one stop bit outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set - irqSetRoutine(IRQ_COM1, serial_handler); + irqSetRoutineWrapped(IRQ_COM1, serialDoIrq); } int isTransmitEmpty() From d2417ef349a0bf07b21c01f56740d415b3824aab Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 7 Oct 2021 21:53:25 +0200 Subject: [PATCH 2/4] esp and ss are push for x86_64 --- arch/x86/interrupt.h | 4 +--- arch/x86/irq_wrappers.S | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 arch/x86/irq_wrappers.S diff --git a/arch/x86/interrupt.h b/arch/x86/interrupt.h index 3c0c49f..9a98439 100644 --- a/arch/x86/interrupt.h +++ b/arch/x86/interrupt.h @@ -6,9 +6,7 @@ struct interrupt_frame { uint32_t eip; uint32_t cs; uint32_t eflags; - uint32_t esp; - uint32_t ss; -}; +} __attribute__((packed)); // Exception #define DECLARE_INTERRUPT(int_nb) \ diff --git a/arch/x86/irq_wrappers.S b/arch/x86/irq_wrappers.S new file mode 100644 index 0000000..1cfe133 --- /dev/null +++ b/arch/x86/irq_wrappers.S @@ -0,0 +1,49 @@ +#define ASM_SOURCE 1 +.file "irq_wrappers.S" +.text + +.extern interrupt_handler_pic +.globl irq_handler_wrapper_array + +.altmacro + + +.macro interrupt_pic irq + int_wrapper_\irq: + .type int_wrapper_\irq,@function + /* INTERRUPT FRAME START */ + /* ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT */ + /* uint32_t ip */ + /* uint32_t cs; */ + /* uint32_t flags */ + /* uint32_t sp; */ + /* uint32_t ss; */ + /* Pushes the general purpose registers to the stack */ + pushal + /* Interrupt frame end */ + pushl %esp + pushl $\irq + call interrupt_handler_pic + addl $8, %esp + popal + iret +.endm + +.set i, 0 +.rept 0x10 + interrupt_pic %i + .set i, i+1 +.endr + +.macro ref_int_wrapper irq + .long int_wrapper_\irq +.endm + +.section ".rodata" +.p2align 5, 0x0 +irq_handler_wrapper_array: +.set i, 0x0 +.rept 0x10 + ref_int_wrapper %i + .set i, i+1 +.endr From 4e14b05f72e1bf192496ad6667ca5c98b0c73f18 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 7 Oct 2021 23:11:17 +0200 Subject: [PATCH 3/4] irq handler get complete CPU state in arguments --- arch/x86/interrupt.h | 2 ++ arch/x86/irq.c | 10 ++++----- arch/x86/irq.h | 5 +++-- arch/x86/irq_wrappers.S | 49 +++++++++++++++++++++++++++++++++++------ drivers/serial.c | 4 ++-- drivers/serial.h | 2 +- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/arch/x86/interrupt.h b/arch/x86/interrupt.h index 9a98439..8f5e274 100644 --- a/arch/x86/interrupt.h +++ b/arch/x86/interrupt.h @@ -1,8 +1,10 @@ #pragma once #include "stdarg.h" +#include "cpu_context.h" // c.f. intel software-developer-vol-1 6.4.1 struct interrupt_frame { + /* Stacked by the CPU */ uint32_t eip; uint32_t cs; uint32_t eflags; diff --git a/arch/x86/irq.c b/arch/x86/irq.c index 8785c49..83ff880 100644 --- a/arch/x86/irq.c +++ b/arch/x86/irq.c @@ -15,13 +15,13 @@ int irqSetup() // Assembly defined array. This is used to wrap C function than cannot: // * get some cpu state // * return using "iret" instead of "ret" without some compiler __attribute__ -extern vaddr_t irq_handler_wrapper_array[IRQ_NUM]; +extern native_irq_handler irq_handler_wrapper_array[IRQ_NUM]; irq_handler irq_handler_array[IRQ_NUM] = { NULL, }; -void interrupt_handler_pic(int interrupt, struct interrupt_frame *frame) +void interrupt_handler_pic(int interrupt, struct cpu_state *frame) { if (0 > interrupt || IRQ_NUM <= interrupt) { pr_err("Trying to handle unknow interrupt %d\n", interrupt); @@ -34,7 +34,7 @@ void interrupt_handler_pic(int interrupt, struct interrupt_frame *frame) irq_handler_array[interrupt](frame); } -int irqSetRoutine(int irq, irq_handler handler) +int irqSetRoutine(int irq, native_irq_handler handler) { uint32_t flags; if ((irq < 0) || irq >= IRQ_NUM) @@ -42,11 +42,9 @@ int irqSetRoutine(int irq, irq_handler handler) disable_IRQs(flags); - irq_handler_array[irq] = handler; - if (handler != NULL) { int ret = idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq, - (unsigned int)irq_handler_array[irq], 0); + (unsigned int)handler, 0); if (!ret) enableIrq(irq); } diff --git a/arch/x86/irq.h b/arch/x86/irq.h index 285dfee..4aada14 100644 --- a/arch/x86/irq.h +++ b/arch/x86/irq.h @@ -35,9 +35,10 @@ // https://wiki.osdev.org/Interrupt_Service_Routines That's why we use wrapper around them or // the gcc interrupt attribut // __attribute__((interrupt)) void (*irq_handler)(int irq); -typedef void (*irq_handler)(struct interrupt_frame *frame); +typedef void (*irq_handler)(struct cpu_state *frame); +typedef void (*native_irq_handler)(struct interrupt_frame *frame); int irqSetup(); // For C coded handler (The interrupt specific part is managed by a wrapper) int irqSetRoutineWrapped(int irq, irq_handler handler); // For ASM handler taking care of the special instruction needed by an IRQ handler -int irqSetRoutine(int irq, irq_handler handler); +int irqSetRoutine(int irq, native_irq_handler handler); diff --git a/arch/x86/irq_wrappers.S b/arch/x86/irq_wrappers.S index 1cfe133..a9bce0b 100644 --- a/arch/x86/irq_wrappers.S +++ b/arch/x86/irq_wrappers.S @@ -16,19 +16,54 @@ /* uint32_t ip */ /* uint32_t cs; */ /* uint32_t flags */ - /* uint32_t sp; */ - /* uint32_t ss; */ - /* Pushes the general purpose registers to the stack */ - pushal - /* Interrupt frame end */ - pushl %esp + /* Pushes the other reg to save same and look like a struct cpu_state*/ + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + push %esp pushl $\irq call interrupt_handler_pic addl $8, %esp - popal + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + iret .endm + .set i, 0 .rept 0x10 interrupt_pic %i diff --git a/drivers/serial.c b/drivers/serial.c index 959f8bd..8407388 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -48,9 +48,9 @@ void serialPutc(char a) outb(PORT, a); } -void serialDoIrq(struct interrupt_frame *level) +void serialDoIrq(struct cpu_state *state) { - (void)level; + (void)state; char c = inb(PORT); serialPutc(c); } diff --git a/drivers/serial.h b/drivers/serial.h index 0a129e3..c46e45a 100644 --- a/drivers/serial.h +++ b/drivers/serial.h @@ -3,4 +3,4 @@ void serialSetup(int speed); void serialPutc(char a); -void serialDoIrq(struct interrupt_frame *frame); +void serialDoIrq(struct cpu_state *state); From 5c7242e4dc608c49c4062befa1aa475ca6d7ce8e Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 7 Oct 2021 23:54:46 +0200 Subject: [PATCH 4/4] Use ASM exception wrapper --- Makefile | 6 +-- arch/x86/exception.c | 89 ++++++++++++++++++----------------- arch/x86/exception.h | 5 +- arch/x86/exception_handler.c | 71 ---------------------------- arch/x86/exception_wrappers.S | 84 +++++++++++++++++++++++++++++++++ arch/x86/interrupt.h | 40 ---------------- drivers/pic.c | 2 +- 7 files changed, 136 insertions(+), 161 deletions(-) delete mode 100644 arch/x86/exception_handler.c create mode 100644 arch/x86/exception_wrappers.S diff --git a/Makefile b/Makefile index 540c435..cda784a 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ CPPFLAGS += $(foreach dir, $(SUBDIRS), -I$(dir)) asmsrc=$(wildcard arch/$(ARCH)/boot/*.asm) asmobj=$(asmsrc:%.asm=%.o) csrc=$(shell find $(SUBDIRS) -type f -name "*.c")# $(wildcard *.c) -cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o arch/$(ARCH)/irq_wrappers.o +cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o arch/$(ARCH)/irq_wrappers.o arch/$(ARCH)/exception_wrappers.o deps = $(csrc:%.c=%.d) kernel kernel.sym &: $(asmobj) $(cobj) linker.ld @@ -34,10 +34,6 @@ fd.iso: kernel disk.img: qemu-img create -f qcow2 disk.img 32M -#https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes -arch/$(ARCH)/exception_handler.o:arch/$(ARCH)/exception_handler.c - $(CC) $(CFLAGS) $(CPPFLAGS) -mgeneral-regs-only -c $< -o $@ - %.o:%.asm $(AS) $(ASFLAGS) -o $@ $< diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 51fe56d..5b3d9a8 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -1,12 +1,29 @@ #include "exception.h" +#include "cpu_context.h" #include "idt.h" #include "interrupt.h" #include "irq.h" +#include "klibc.h" +#include "kthread.h" +#include "vga.h" exception_handler exception_handler_array[EXCEPTION_NUM] = { NULL, }; +extern vaddr_t exception_handler_wrapper_array[EXCEPTION_NUM]; + +void exception_handler_wrap(int intr, struct cpu_state *frame) +{ + if (0 > intr || EXCEPTION_NUM <= intr) { + pr_err("Trying to handle unknow exception %d\n", intr); + return; + } + + if (exception_handler_array[intr] != NULL) + exception_handler_array[intr](frame, intr); +} + int exceptionSetRoutine(int exception, exception_handler handler) { uint32_t flags; @@ -17,54 +34,42 @@ int exceptionSetRoutine(int exception, exception_handler handler) exception_handler_array[exception] = handler; - idt_set_handler(EXCEPTION_INTERRUPT_BASE_ADDRESS + exception, (unsigned int)handler, 0); + idt_set_handler(EXCEPTION_INTERRUPT_BASE_ADDRESS + exception, + (unsigned int)exception_handler_wrapper_array[exception], 0); restore_IRQs(flags); return 0; } +void print_handler(struct cpu_state *frame, ulong intr) +{ + int intNbInt = intr; + VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d %d", intNbInt, intr); + printf("Exception %d (Err %d) at 0x%x\n", intr, intr, + cpu_context_get_PC(frame)); + asm("hlt"); +} + +void pagefault_handler(struct cpu_state *frame, ulong intr) +{ + // A page fault has occurred. + // The faulting address is stored in the CR2 register. + uint32_t faulting_address; + asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); + + struct kthread *current = getCurrentThread(); + printf("page fault while in thread %s at 0x%x 0x%x\n", current->name, faulting_address, + cpu_context_get_PC(frame)); + VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr); + (void)intr; + for (;;) + continue; +} + int exceptionSetup() { - exceptionSetRoutine(EXCEPTION_DOUBLE_FAULT, ACCESS_INTERRUPT(EXCEPTION_DOUBLE_FAULT)); - exceptionSetRoutine(EXCEPTION_DIVIDE_ZERO, ACCESS_INTERRUPT(EXCEPTION_DIVIDE_ZERO)); - // Used by the DBG - // exceptionSetRoutine(EXCEPTION_DEBUG, ACCESS_INTERRUPT(EXCEPTION_DEBUG)); - exceptionSetRoutine(EXCEPTION_NMI, ACCESS_INTERRUPT(EXCEPTION_NMI)); - exceptionSetRoutine(EXCEPTION_BREAKPOINT, ACCESS_INTERRUPT(EXCEPTION_BREAKPOINT)); - exceptionSetRoutine(EXCEPTION_OVERFLOW, ACCESS_INTERRUPT(EXCEPTION_OVERFLOW)); - exceptionSetRoutine(EXCEPTION_BOUND_RANGE_EXCEEDED, - ACCESS_INTERRUPT(EXCEPTION_BOUND_RANGE_EXCEEDED)); - exceptionSetRoutine(EXCEPTION_INVALID_OPCODE, ACCESS_INTERRUPT(EXCEPTION_INVALID_OPCODE)); - exceptionSetRoutine(EXCEPTION_DEVICE_NOT_AVAILABLE, - ACCESS_INTERRUPT(EXCEPTION_DEVICE_NOT_AVAILABLE)); - exceptionSetRoutine(EXCEPTION_COPRO_OVERRUN, ACCESS_INTERRUPT(EXCEPTION_COPRO_OVERRUN)); - exceptionSetRoutine(EXCEPTION_INVALID_TSS, ACCESS_INTERRUPT(EXCEPTION_INVALID_TSS)); - exceptionSetRoutine(EXCEPTION_SEGMENT_NOT_PRESENT, - ACCESS_INTERRUPT(EXCEPTION_SEGMENT_NOT_PRESENT)); - exceptionSetRoutine(EXCEPTION_STACK_SEGMENT_FAULT, - ACCESS_INTERRUPT(EXCEPTION_STACK_SEGMENT_FAULT)); - exceptionSetRoutine(EXCEPTION_GENERAL_PROTECTION_FAULT, - ACCESS_INTERRUPT(EXCEPTION_GENERAL_PROTECTION_FAULT)); - exceptionSetRoutine(EXCEPTION_PAGE_FAULT, ACCESS_INTERRUPT(EXCEPTION_PAGE_FAULT)); - exceptionSetRoutine(EXCEPTION_RESERVED_1, ACCESS_INTERRUPT(EXCEPTION_RESERVED_1)); - exceptionSetRoutine(EXCEPTION_X87_FP_EXCEPTION, - ACCESS_INTERRUPT(EXCEPTION_X87_FP_EXCEPTION)); - exceptionSetRoutine(EXCEPTION_ALIGNMENT_CHECK, - ACCESS_INTERRUPT(EXCEPTION_ALIGNMENT_CHECK)); - exceptionSetRoutine(EXCEPTION_MACHINE_CHECK, ACCESS_INTERRUPT(EXCEPTION_MACHINE_CHECK)); - exceptionSetRoutine(EXCEPTION_SIMD_FP, ACCESS_INTERRUPT(EXCEPTION_SIMD_FP)); - exceptionSetRoutine(EXCEPTION_VIRTUALIZATION, ACCESS_INTERRUPT(EXCEPTION_VIRTUALIZATION)); - exceptionSetRoutine(EXCEPTION_RESERVED_2, ACCESS_INTERRUPT(EXCEPTION_RESERVED_2)); - exceptionSetRoutine(EXCEPTION_RESERVED_3, ACCESS_INTERRUPT(EXCEPTION_RESERVED_3)); - exceptionSetRoutine(EXCEPTION_RESERVED_4, ACCESS_INTERRUPT(EXCEPTION_RESERVED_4)); - exceptionSetRoutine(EXCEPTION_RESERVED_5, ACCESS_INTERRUPT(EXCEPTION_RESERVED_5)); - exceptionSetRoutine(EXCEPTION_RESERVED_6, ACCESS_INTERRUPT(EXCEPTION_RESERVED_6)); - exceptionSetRoutine(EXCEPTION_RESERVED_7, ACCESS_INTERRUPT(EXCEPTION_RESERVED_7)); - exceptionSetRoutine(EXCEPTION_RESERVED_8, ACCESS_INTERRUPT(EXCEPTION_RESERVED_8)); - exceptionSetRoutine(EXCEPTION_RESERVED_9, ACCESS_INTERRUPT(EXCEPTION_RESERVED_9)); - exceptionSetRoutine(EXCEPTION_RESERVED_10, ACCESS_INTERRUPT(EXCEPTION_RESERVED_10)); - exceptionSetRoutine(EXCEPTION_SECURITY, ACCESS_INTERRUPT(EXCEPTION_SECURITY)); - exceptionSetRoutine(EXCEPTION_RESERVED_11, ACCESS_INTERRUPT(EXCEPTION_RESERVED_11)); - + for (int i = 0; i < EXCEPTION_NUM; i++) { + exceptionSetRoutine(i, print_handler); + } exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler); return 0; } diff --git a/arch/x86/exception.h b/arch/x86/exception.h index 9b7e2be..39da7a6 100644 --- a/arch/x86/exception.h +++ b/arch/x86/exception.h @@ -1,4 +1,5 @@ #pragma once +#include "cpu_context.h" #include "interrupt.h" #include "stdarg.h" @@ -39,8 +40,8 @@ #define EXCEPTION_SECURITY 30 #define EXCEPTION_RESERVED_11 31 -#define EXCEPTION_NUM 32 +#define EXCEPTION_NUM 0x20 -typedef void (*exception_handler)(struct interrupt_frame *frame, ulong error_code); +typedef void (*exception_handler)(struct cpu_state *frame, ulong intr_number); int exceptionSetRoutine(int exception, exception_handler handler); int exceptionSetup(); diff --git a/arch/x86/exception_handler.c b/arch/x86/exception_handler.c deleted file mode 100644 index f68795c..0000000 --- a/arch/x86/exception_handler.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "exception.h" -#include "klibc.h" -#include "kthread.h" -#include "vga.h" -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -// Need GCC > 6 -#define DEFINE_INTERRUPT(int_nb) \ - __attribute__((interrupt)) void print_handler_##int_nb(struct interrupt_frame *frame, \ - ulong error_code) \ - { \ - int intNbInt = int_nb; \ - VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d %d", intNbInt, error_code); \ - printf("Exception %d (Err %d) at 0x%x\n", int_nb, error_code, frame->eip); \ - asm("hlt"); \ - } - -DEFINE_INTERRUPT(EXCEPTION_DOUBLE_FAULT) -DEFINE_INTERRUPT(EXCEPTION_DIVIDE_ZERO) -DEFINE_INTERRUPT(EXCEPTION_DEBUG) -DEFINE_INTERRUPT(EXCEPTION_NMI) -DEFINE_INTERRUPT(EXCEPTION_BREAKPOINT) -DEFINE_INTERRUPT(EXCEPTION_OVERFLOW) -DEFINE_INTERRUPT(EXCEPTION_BOUND_RANGE_EXCEEDED) -DEFINE_INTERRUPT(EXCEPTION_INVALID_OPCODE) -DEFINE_INTERRUPT(EXCEPTION_DEVICE_NOT_AVAILABLE) -DEFINE_INTERRUPT(EXCEPTION_COPRO_OVERRUN) -DEFINE_INTERRUPT(EXCEPTION_INVALID_TSS) -DEFINE_INTERRUPT(EXCEPTION_SEGMENT_NOT_PRESENT) -DEFINE_INTERRUPT(EXCEPTION_STACK_SEGMENT_FAULT) -DEFINE_INTERRUPT(EXCEPTION_GENERAL_PROTECTION_FAULT) -DEFINE_INTERRUPT(EXCEPTION_PAGE_FAULT) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_1) -DEFINE_INTERRUPT(EXCEPTION_X87_FP_EXCEPTION) -DEFINE_INTERRUPT(EXCEPTION_ALIGNMENT_CHECK) -DEFINE_INTERRUPT(EXCEPTION_MACHINE_CHECK) -DEFINE_INTERRUPT(EXCEPTION_SIMD_FP) -DEFINE_INTERRUPT(EXCEPTION_VIRTUALIZATION) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_2) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_3) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_4) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_5) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_6) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_7) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_8) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_9) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_10) -DEFINE_INTERRUPT(EXCEPTION_SECURITY) -DEFINE_INTERRUPT(EXCEPTION_RESERVED_11) -// c.f. https://wiki.osdev.org/Paging#Handling -// error_code bit0: Present ? -// bit1: Trying to write ? -// bit2: User page try to access? -__attribute__((interrupt)) void pagefault_handler(struct interrupt_frame *frame, - ulong error_code) -{ - // A page fault has occurred. - // The faulting address is stored in the CR2 register. - uint32_t faulting_address; - asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); - - struct kthread *current = getCurrentThread(); - printf("page fault while in thread %s at 0x%x\n", current->name, faulting_address); - VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", error_code); - (void)faulting_address; - (void)frame; - (void)error_code; - for(;;) - continue; -} diff --git a/arch/x86/exception_wrappers.S b/arch/x86/exception_wrappers.S new file mode 100644 index 0000000..23f16ac --- /dev/null +++ b/arch/x86/exception_wrappers.S @@ -0,0 +1,84 @@ +#define ASM_SOURCE 1 +.file "irq_wrappers.S" +.text + +.extern exception_handler_wrap +.globl exception_handler_wrapper_array + +.altmacro + + +.macro exception_mac id + exception_wrapper_\id: + .type exception_wrapper_\id,@function + /* INTERRUPT FRAME START */ + /* ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT */ + /* uint32_t ip */ + /* uint32_t cs; */ + /* uint32_t flags */ + /* Pushes the other reg to save same and look like a struct cpu_state*/ + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + push %esp + pushl $\id + call exception_handler_wrap + addl $8, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + + iret +.endm + + +.set i, 0 +.rept 0x20 + exception_mac %i + .set i, i+1 +.endr + +.macro ref_exception_wrapper id + .long exception_wrapper_\id +.endm + +.section ".rodata" +.p2align 5, 0x0 +exception_handler_wrapper_array: +.set i, 0x0 +.rept 0x20 + ref_exception_wrapper %i + .set i, i+1 +.endr diff --git a/arch/x86/interrupt.h b/arch/x86/interrupt.h index 8f5e274..324ec3e 100644 --- a/arch/x86/interrupt.h +++ b/arch/x86/interrupt.h @@ -10,45 +10,5 @@ struct interrupt_frame { uint32_t eflags; } __attribute__((packed)); -// Exception -#define DECLARE_INTERRUPT(int_nb) \ - void print_handler_##int_nb(struct interrupt_frame *frame, ulong error_code); - -#define ACCESS_INTERRUPT(int_nb) print_handler_##int_nb - -void pagefault_handler(struct interrupt_frame *frame, ulong error_code); -DECLARE_INTERRUPT(EXCEPTION_DOUBLE_FAULT) -DECLARE_INTERRUPT(EXCEPTION_DIVIDE_ZERO) -DECLARE_INTERRUPT(EXCEPTION_DEBUG) -DECLARE_INTERRUPT(EXCEPTION_NMI) -DECLARE_INTERRUPT(EXCEPTION_BREAKPOINT) -DECLARE_INTERRUPT(EXCEPTION_OVERFLOW) -DECLARE_INTERRUPT(EXCEPTION_BOUND_RANGE_EXCEEDED) -DECLARE_INTERRUPT(EXCEPTION_INVALID_OPCODE) -DECLARE_INTERRUPT(EXCEPTION_DEVICE_NOT_AVAILABLE) -DECLARE_INTERRUPT(EXCEPTION_COPRO_OVERRUN) -DECLARE_INTERRUPT(EXCEPTION_INVALID_TSS) -DECLARE_INTERRUPT(EXCEPTION_SEGMENT_NOT_PRESENT) -DECLARE_INTERRUPT(EXCEPTION_STACK_SEGMENT_FAULT) -DECLARE_INTERRUPT(EXCEPTION_GENERAL_PROTECTION_FAULT) -DECLARE_INTERRUPT(EXCEPTION_PAGE_FAULT) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_1) -DECLARE_INTERRUPT(EXCEPTION_X87_FP_EXCEPTION) -DECLARE_INTERRUPT(EXCEPTION_ALIGNMENT_CHECK) -DECLARE_INTERRUPT(EXCEPTION_MACHINE_CHECK) -DECLARE_INTERRUPT(EXCEPTION_SIMD_FP) -DECLARE_INTERRUPT(EXCEPTION_VIRTUALIZATION) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_2) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_3) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_4) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_5) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_6) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_7) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_8) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_9) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_10) -DECLARE_INTERRUPT(EXCEPTION_SECURITY) -DECLARE_INTERRUPT(EXCEPTION_RESERVED_11) - // IRQ void pit_handler(struct interrupt_frame *frame); diff --git a/drivers/pic.c b/drivers/pic.c index 707ebc9..442a454 100644 --- a/drivers/pic.c +++ b/drivers/pic.c @@ -42,7 +42,7 @@ void initPic(void) outb(PIC_SLAVE_DATA, 0xFF); } -void EOIIrq(int irq) +inline void EOIIrq(int irq) { if (irq >= 8) outb(PIC_SLAVE_CMD, PIC_EOI);