Autor Thema: Problem mit IRQ  (Gelesen 5086 mal)

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« 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.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 19. December 2009, 17:25 »
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.
Dieser Text wird unter jedem Beitrag angezeigt.

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 19. December 2009, 17:30 »
Stimmt, klingt logisch. Scheint zu funktionieren. Vielen dank!!!

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 19. December 2009, 19:19 »
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.
« Letzte Änderung: 19. December 2009, 19:21 von MNemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 19. December 2009, 20:25 »
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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 20. December 2009, 09:54 »
Ah, ok. Danke!

 

Einloggen