From ddc0c4c84a2cf05cc558118a76d1384ff44c0ac1 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 7 Oct 2021 21:23:32 +0200 Subject: [PATCH] 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()