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
#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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

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