irq handler get complete CPU state in arguments

This commit is contained in:
Mathieu Maret 2021-10-07 23:11:17 +02:00
parent d2417ef349
commit 4e14b05f72
6 changed files with 54 additions and 18 deletions

View File

@ -1,8 +1,10 @@
#pragma once #pragma once
#include "stdarg.h" #include "stdarg.h"
#include "cpu_context.h"
// c.f. intel software-developer-vol-1 6.4.1 // c.f. intel software-developer-vol-1 6.4.1
struct interrupt_frame { struct interrupt_frame {
/* Stacked by the CPU */
uint32_t eip; uint32_t eip;
uint32_t cs; uint32_t cs;
uint32_t eflags; uint32_t eflags;

View File

@ -15,13 +15,13 @@ int irqSetup()
// Assembly defined array. This is used to wrap C function than cannot: // Assembly defined array. This is used to wrap C function than cannot:
// * get some cpu state // * get some cpu state
// * return using "iret" instead of "ret" without some compiler __attribute__ // * 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] = { irq_handler irq_handler_array[IRQ_NUM] = {
NULL, 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) { if (0 > interrupt || IRQ_NUM <= interrupt) {
pr_err("Trying to handle unknow interrupt %d\n", 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); irq_handler_array[interrupt](frame);
} }
int irqSetRoutine(int irq, irq_handler handler) int irqSetRoutine(int irq, native_irq_handler handler)
{ {
uint32_t flags; uint32_t flags;
if ((irq < 0) || irq >= IRQ_NUM) if ((irq < 0) || irq >= IRQ_NUM)
@ -42,11 +42,9 @@ int irqSetRoutine(int irq, irq_handler handler)
disable_IRQs(flags); disable_IRQs(flags);
irq_handler_array[irq] = handler;
if (handler != NULL) { if (handler != NULL) {
int ret = idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq, int ret = idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq,
(unsigned int)irq_handler_array[irq], 0); (unsigned int)handler, 0);
if (!ret) if (!ret)
enableIrq(irq); enableIrq(irq);
} }

View File

@ -35,9 +35,10 @@
// https://wiki.osdev.org/Interrupt_Service_Routines That's why we use wrapper around them or // https://wiki.osdev.org/Interrupt_Service_Routines That's why we use wrapper around them or
// the gcc interrupt attribut // the gcc interrupt attribut
// __attribute__((interrupt)) void (*irq_handler)(int irq); // __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(); int irqSetup();
// For C coded handler (The interrupt specific part is managed by a wrapper) // For C coded handler (The interrupt specific part is managed by a wrapper)
int irqSetRoutineWrapped(int irq, irq_handler handler); int irqSetRoutineWrapped(int irq, irq_handler handler);
// For ASM handler taking care of the special instruction needed by an IRQ 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);

View File

@ -16,19 +16,54 @@
/* uint32_t ip */ /* uint32_t ip */
/* uint32_t cs; */ /* uint32_t cs; */
/* uint32_t flags */ /* uint32_t flags */
/* uint32_t sp; */ /* Pushes the other reg to save same and look like a struct cpu_state*/
/* uint32_t ss; */ /* Fake error code */
/* Pushes the general purpose registers to the stack */ pushl $0
pushal
/* Interrupt frame end */ /* Backup the actual context */
pushl %esp 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 pushl $\irq
call interrupt_handler_pic call interrupt_handler_pic
addl $8, %esp 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 iret
.endm .endm
.set i, 0 .set i, 0
.rept 0x10 .rept 0x10
interrupt_pic %i interrupt_pic %i

View File

@ -48,9 +48,9 @@ void serialPutc(char a)
outb(PORT, a); outb(PORT, a);
} }
void serialDoIrq(struct interrupt_frame *level) void serialDoIrq(struct cpu_state *state)
{ {
(void)level; (void)state;
char c = inb(PORT); char c = inb(PORT);
serialPutc(c); serialPutc(c);
} }

View File

@ -3,4 +3,4 @@
void serialSetup(int speed); void serialSetup(int speed);
void serialPutc(char a); void serialPutc(char a);
void serialDoIrq(struct interrupt_frame *frame); void serialDoIrq(struct cpu_state *state);