From 4e14b05f72e1bf192496ad6667ca5c98b0c73f18 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 7 Oct 2021 23:11:17 +0200 Subject: [PATCH] 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);