Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: Hobby Programmiere am 19. December 2009, 17:23
-
Hi Leute,
ich habe schon wieder ein Problem. Ich wollte einen IRQ-Manager programmieren. Als Basis habe ich diese Tuts genommen http://www.osdever.net/bkerndev/Docs/irqs.htm und http://lowlevel.brainsware.org/wiki/index.php/ISR. Und hier habe ich auch schon eine Frage. Wieso wird in dem Tut von osdev mit cli die Interrupts ab, aber nicht wieder angeschaltet? Bei dem von lowlevel wird gar nichts deaktiviert. Ich habe mir dann mal folgenden Code geschrieben.
Kernel.c
// Test for Irq
void IRQ0_Test(struct SIRQParam Param)
{
kprintf("IRQ 0", 0, 10);
DeleteIRQHandler(0);
kprintf("IRQ0-handler deleted", 0, 12);
}
IRQ.c
// Defines
#define PCI1 0x20
#define PCI2 0xA0
#define PCI1_DATA (PCI1 + 1)
#define PCI2_DATA (PCI2 + 1)
#define PCI1_VECTOR 0x20
#define PCI2_VECTOR 0x28
// The 16 IRQ-functions (they are in IRQ.asm)
extern void IRQ0();
extern void IRQ1();
extern void IRQ2();
extern void IRQ3();
extern void IRQ4();
extern void IRQ5();
extern void IRQ6();
extern void IRQ7();
extern void IRQ8();
extern void IRQ9();
extern void IRQ10();
extern void IRQ11();
extern void IRQ12();
extern void IRQ13();
extern void IRQ14();
extern void IRQ15();
// The IRQHandler
void* IRQHandlers[16] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// Remap the entries
void Remap()
{
// Start the init process
OutPort(PCI1, 0x11);
OutPort(PCI2, 0x11);
// Remap the entries
OutPort(PCI1_DATA, 0x20);
OutPort(PCI2_DATA, 0x28);
OutPort(PCI2_DATA, 0x04);
OutPort(PCI1_DATA, 0x02);
OutPort(PCI2_DATA, 0x01);
OutPort(PCI1_DATA, 0x01);
OutPort(PCI2_DATA, 0x00);
OutPort(PCI1_DATA, 0x00);
}
// Init IRQ
int IRQInit()
{
// Remap the IRQ entries
Remap();
// Set the IRQ-Functions
IDTSetEntry(32, (unsigned long) IRQ0, 0x08, 0x8E);
IDTSetEntry(33, (unsigned long) IRQ1, 0x08, 0x8E);
IDTSetEntry(34, (unsigned long) IRQ2, 0x08, 0x8E);
IDTSetEntry(35, (unsigned long) IRQ3, 0x08, 0x8E);
IDTSetEntry(36, (unsigned long) IRQ4, 0x08, 0x8E);
IDTSetEntry(37, (unsigned long) IRQ5, 0x08, 0x8E);
IDTSetEntry(38, (unsigned long) IRQ6, 0x08, 0x8E);
IDTSetEntry(39, (unsigned long) IRQ7, 0x08, 0x8E);
IDTSetEntry(40, (unsigned long) IRQ8, 0x08, 0x8E);
IDTSetEntry(41, (unsigned long) IRQ9, 0x08, 0x8E);
IDTSetEntry(42, (unsigned long) IRQ10, 0x08, 0x8E);
IDTSetEntry(43, (unsigned long) IRQ11, 0x08, 0x8E);
IDTSetEntry(44, (unsigned long) IRQ12, 0x08, 0x8E);
IDTSetEntry(45, (unsigned long) IRQ13, 0x08, 0x8E);
IDTSetEntry(46, (unsigned long) IRQ14, 0x08, 0x8E);
IDTSetEntry(47, (unsigned long) IRQ15, 0x08, 0x8E);
// Enable the IRQ
asm volatile("sti");
// All was success
return 1;
}
// This function set an IRQHandler
void SetIRQHandler(void *pFunction, const unsigned int iIRQIndex)
{
IRQHandlers[iIRQIndex] = pFunction;
}
// This function delete an IRQHandler
void DeleteIRQHandler(const unsigned int iIRQIndex)
{
IRQHandlers[iIRQIndex] = 0;
}
// The IRQ-Handler which is called in IRQ.asm
void IRQHandler(struct SIRQParam Param)
{
// Call the IRQ-Handler
void (*pIRQHandler) (struct SIRQParam);
if (IRQHandlers[Param.iIRQ] != NULL)
{
pIRQHandler = IRQHandlers[Param.iIRQ];
pIRQHandler(Param);
}
// Tell the PCI that we finished with the interrupt
if (Param.iIRQ >= 8)
OutPort(PCI2, 0x20);
OutPort(PCI1, 0x20);
}
IRQ.asm
........
IRQ15:
cli
push byte 15
jmp IRQ_HANDLER
; The IRQ-Handler
extern IRQHandler
IRQ_HANDLER:
; Make sure that we are working with kernel privilegs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; Call the c-Handler
call IRQHandler
iret
Er funktioniert aber nicht richtig. Der IRQ-Handler aus Kernel.c wird zwar ausgerufen, aber sobald der IRQ-Manager diese Interrupt fertig bearbeitet hat, gibt es einen Reboot. Warum? Was habe ich falsch gemacht?
Ich hoffe ihr könnt mir helfen. Vielen dank schon mal.
-
Hi,
der Stack ist nicht ausgeglichen. Du hast da die 15 auf den Stack getan, aber holst sie nirgendwo wieder runter. Deswegen versuch das iret diese Zahl als Adresse zu interpretieren, was natürlich nur schiefgehen kann.
Du musst also noch die 15 wieder runternehmen, zum Beispiel indem du esp um 4 erhöhst.
-
Stimmt, klingt logisch. Scheint zu funktionieren. Vielen dank!!!
-
Wieso wird in dem Tut von osdev mit cli die Interrupts ab, aber nicht wieder angeschaltet?
Wenn ein Interrupt auftritt werden die Flags auf dem Stack gesichert, und mit einem IRET wieder hergestellt. Wenn man also in einer Interrupt -Routine mittels CLI das Interrupt-Enable-Flag löscht, wird es mit dem IRET wieder hergestellt.
-
Das cli am Anfang ist natürlich trotzdem Blödsinn. Man nimmt ja schließlich schon Interrupt Gates, damit die Interrupts während dem ISR aus sind. Das cli ist hier also effektiv ein nop.
-
Ah, ok. Danke!