I writing an operating system project and I’m currently in the process of dealing with IRQs. I have a file (named irq.cpp) where I define the ISR for the keyboard and the timer, which are very simple functions. I also have a header file named “irq.h” that declares the functions I will be using.
here is irq.cpp:
// In this file we will handle the hardware interrupts received from components such as keyboard and timer
#include "irq.h"
void __attribute__((cdecl)) keyboard(Registers* state)
{
printf((uint8_t*)".");
if (state->interrupt < 0xA0) PIC_sendEOI(state->interrupt - PIC1); // The input is the irq number
else PIC_sendEOI(state->interrupt - PIC2);
}
void __attribute__((cdecl)) timer(Registers* state)
{
printf((uint8_t*)".");
PIC_sendEOI(state->interrupt - PIC1);
}
void populate_irq_entries()
{
ISR_RegisterHandler(PIC1 + 0, timer);
ISR_RegisterHandler(PIC1 + 1, keyboard);
}
The code inside the functions themselves isn’t relevant.
Here is the header file – irq.h:
#ifndef __IRQ_H
#define __IRQ_H
#include "../isr.h"
#include "../../../port/pic.h"
void __attribute__((cdecl)) keyboard(Registers* state);
void __attribute__((cdecl)) timer(Registers* state);
void populate_irq_entries();
#endif
This header file includes a different header file named “isr.h” in which I define a struct that represents the state of the registers before the ISR call:
here is the isr.h:
#ifndef __ISR_H
#define __ISR_H
#include "../../types.h"
#include "../idt.h"
#include "../../gdt/gdt.h"
#include "../../kernel.h"
#include "isrgen.h"
typedef struct
{
// A useful struct that is used to represnt the values of the registers when pushed into the stack
// The general ISR_Handler receives a struct of this type and using the values inside it, it deciphers which ISR was called
uint32_t ds; // data segment pushed by us
uint32_t edi, esi, ebp, useless, ebx, edx, ecx, eax; // pusha
uint32_t interrupt, error; // we push interrupt, error is pushed automatically (or dummy)
uint32_t eip, cs, eflags, esp, ss; // pushed automatically by CPU
} __attribute__((packed)) Registers;
typedef void (*ISRHandler)(Registers* regs); // We define a new type - ISRHANDLER is a pointer to a void function that receives the Registers struct as input
ISRHandler ISRHandlers[256]; // Each element in this array is a pointer to a void function - a single isr that receives as input the state of the registers
extern "C" void ISR_Initialize();
void ISR_RegisterHandler(int interrupt, ISRHandler handler);
extern "C" void __attribute__((cdecl)) ISR_Handler(Registers* regs); // cdecl is a calling convention in function. The way it works is that variables are pushed to the stack from right to left and the function is responsible for cleaning in the end of the run
#endif
Most of it isn’t relevant, I just want to show that I define the Registers struct.
When I try to compile the code I get the following error:
In file included from idt/isr/../../kernel.h:13,
from idt/isr/isr.h:13,
from idt/isr/isr.cpp:1:
idt/isr/../../idt/isr/irq/irq.h:5:29: error: variable or field ‘keyboard’ declared void
5 | void __attribute__((cdecl)) keyboard(Registers* state);
| ^~~~~~~~
idt/isr/../../idt/isr/irq/irq.h:5:38: error: ‘Registers’ was not declared in this scope; did you mean ‘register’?
5 | void __attribute__((cdecl)) keyboard(Registers* state);
| ^~~~~~~~~
| register
idt/isr/../../idt/isr/irq/irq.h:5:49: error: ‘state’ was not declared in this scope; did you mean ‘static’?
5 | void __attribute__((cdecl)) keyboard(Registers* state);
| ^~~~~
| static
idt/isr/../../idt/isr/irq/irq.h:6:29: error: variable or field ‘timer’ declared void
6 | void __attribute__((cdecl)) timer(Registers* state);
| ^~~~~
idt/isr/../../idt/isr/irq/irq.h:6:35: error: ‘Registers’ was not declared in this scope; did you mean ‘register’?
6 | void __attribute__((cdecl)) timer(Registers* state);
| ^~~~~~~~~
| register
idt/isr/../../idt/isr/irq/irq.h:6:46: error: ‘state’ was not declared in this scope; did you mean ‘static’?
6 | void __attribute__((cdecl)) timer(Registers* state);
| ^~~~~
| static
Does anyone have any idea?
Thanks!