Autor Thema: PIC Problem...  (Gelesen 5793 mal)

DaCodaaa

  • Gast
Gespeichert
« am: 15. August 2009, 20:24 »
moin,

Ich habe in dem Tut "Brans kernel development tuturial" die Kapittel über die Interrupts durgearbeitet, weil ich es wesentlich eleganter finde sie in C zu definieren(z.T wegen mangelnder asm Erfahrung).
Mit den isrs ist auch alles in ordnung, die funktionieren, aber mit dem PIC klappts nich sonderlich... :cry:

Hier der Code:
#include "System.h"

/* These are function prototypes for all of the exception
*  handlers: The first 32 entries in the IDT are reserved
*  by Intel, and are designed to service exceptions! */
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
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();


/* This is a very repetitive function... it's not hard, it's
*  just annoying. As you can see, we set the first 32 entries
*  in the IDT to the first 32 ISRs. We can't use a for loop
*  for this, because there is no way to get the function names
*  that correspond to that given entry. We set the access
*  flags to 0x8E. This means that the entry is present, is
*  running in ring 0 (kernel level), and has the lower 5 bits
*  set to the required '14', which is represented by 'E' in
*  hex. */
void isrs_install()
{
    set_idt_entry(0, (unsigned)isr0, 0x08, 0x8E);
    set_idt_entry(1, (unsigned)isr1, 0x08, 0x8E);
    set_idt_entry(2, (unsigned)isr2, 0x08, 0x8E);
    set_idt_entry(3, (unsigned)isr3, 0x08, 0x8E);
set_idt_entry(4, (unsigned)isr4, 0x08, 0x8E);
set_idt_entry(5, (unsigned)isr5, 0x08, 0x8E);
set_idt_entry(6, (unsigned)isr6, 0x08, 0x8E);
set_idt_entry(7, (unsigned)isr7, 0x08, 0x8E);
set_idt_entry(8, (unsigned)isr8, 0x08, 0x8E);
set_idt_entry(9, (unsigned)isr9, 0x08, 0x8E);
set_idt_entry(10, (unsigned)isr10, 0x08, 0x8E);
set_idt_entry(11, (unsigned)isr11, 0x08, 0x8E);
set_idt_entry(12, (unsigned)isr12, 0x08, 0x8E);
set_idt_entry(13, (unsigned)isr13, 0x08, 0x8E);
set_idt_entry(14, (unsigned)isr14, 0x08, 0x8E);
set_idt_entry(15, (unsigned)isr15, 0x08, 0x8E);
set_idt_entry(16, (unsigned)isr16, 0x08, 0x8E);
set_idt_entry(17, (unsigned)isr17, 0x08, 0x8E);
set_idt_entry(18, (unsigned)isr18, 0x08, 0x8E);
set_idt_entry(19, (unsigned)isr19, 0x08, 0x8E);
set_idt_entry(20, (unsigned)isr20, 0x08, 0x8E);
set_idt_entry(21, (unsigned)isr21, 0x08, 0x8E);
set_idt_entry(22, (unsigned)isr22, 0x08, 0x8E);
set_idt_entry(23, (unsigned)isr23, 0x08, 0x8E);
set_idt_entry(24, (unsigned)isr24, 0x08, 0x8E);
set_idt_entry(25, (unsigned)isr25, 0x08, 0x8E);
set_idt_entry(26, (unsigned)isr26, 0x08, 0x8E);
set_idt_entry(27, (unsigned)isr27, 0x08, 0x8E);
set_idt_entry(28, (unsigned)isr28, 0x08, 0x8E);
set_idt_entry(29, (unsigned)isr29, 0x08, 0x8E);
set_idt_entry(30, (unsigned)isr30, 0x08, 0x8E);
    set_idt_entry(31, (unsigned)isr31, 0x08, 0x8E);
}


/* This is a simple string array. It contains the message that
*  corresponds to each and every exception. We get the correct
*  message by accessing like:
*  exception_message[interrupt_number] */
char *exception_messages[] =
{
    "Division By Zero",
    "Debug",
    "Non Maskable Interrupt",
"Non Maskable Interrupt",
  "Breakpoint",
  "Into Detected Overflow",
  "Out of Bounds",
  "Invalid Opcode",
  "No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
  "Bad TSS"
  "Segment Not Present"
  "Stack Fault",
  "General Protection Fault",
  "Page Fault",
  "Unknown Interrupt",
  "Coprocessor Fault",
  "Alignment Check",
"Machine Check",
    "Reserved",
    "Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};

/* This array is actually an array of function pointers. We use
*  this to handle custom IRQ handlers for a given IRQ */
void *irq_routines[16] =
{
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0
};

/* This installs a custom IRQ handler for the given IRQ */
void irq_install_handler(int irq, void (*handler)(struct regs *r))
{
    irq_routines[irq] = handler;
}

/* This clears the handler for a given IRQ */
void irq_uninstall_handler(int irq)
{
    irq_routines[irq] = 0;
}

/* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
*  is a problem in protected mode, because IDT entry 8 is a
*  Double Fault! Without remapping, every time IRQ0 fires,
*  you get a Double Fault Exception, which is NOT actually
*  what's happening. We send commands to the Programmable
*  Interrupt Controller (PICs - also called the 8259's) in
*  order to make IRQ0 to 15 be remapped to IDT entries 32 to
*  47 */
void irq_remap(void)
{
    outb(0x20, 0x11);
    outb(0xA0, 0x11);
    outb(0x21, 0x20);
    outb(0xA1, 0x28);
    outb(0x21, 0x04);
    outb(0xA1, 0x02);
    outb(0x21, 0x01);
    outb(0xA1, 0x01);
    outb(0x21, 0x0);
    outb(0xA1, 0x0);
}

/* We first remap the interrupt controllers, and then we install
*  the appropriate ISRs to the correct entries in the IDT. This
*  is just like installing the exception handlers */
void irq_install()
{
    irq_remap();

    set_idt_entry(32, (unsigned)irq0, 0x08, 0x8E);
    set_idt_entry(33, (unsigned)irq1, 0x08, 0x8E);
set_idt_entry(34, (unsigned)irq2, 0x08, 0x8E);
set_idt_entry(35, (unsigned)irq3, 0x08, 0x8E);
set_idt_entry(36, (unsigned)irq4, 0x08, 0x8E);
set_idt_entry(37, (unsigned)irq5, 0x08, 0x8E);
set_idt_entry(38, (unsigned)irq6, 0x08, 0x8E);
set_idt_entry(39, (unsigned)irq7, 0x08, 0x8E);
set_idt_entry(40, (unsigned)irq8, 0x08, 0x8E);
set_idt_entry(41, (unsigned)irq9, 0x08, 0x8E);
set_idt_entry(42, (unsigned)irq10, 0x08, 0x8E);
set_idt_entry(43, (unsigned)irq12, 0x08, 0x8E);
set_idt_entry(44, (unsigned)irq13, 0x08, 0x8E);
set_idt_entry(45, (unsigned)irq14, 0x08, 0x8E);
set_idt_entry(46, (unsigned)irq15, 0x08, 0x8E);
}



/* All of our Exception handling Interrupt Service Routines will
*  point to this function. This will tell us what exception has
*  happened! Right now, we simply halt the system by hitting an
*  endless loop. All ISRs disable interrupts while they are being
*  serviced as a 'locking' mechanism to prevent an IRQ from
*  happening and messing up kernel data structures */
void fault_handler(struct regs *r)
{
    /* Is this a fault whose number is from 0 to 31? */
    if (r->int_no < 32)
    {
        /* Display the description for the Exception that occurred.
        *  In this tutorial, we will simply halt the system using an
        *  infinite loop */
newline();newline(); //2 Zeilen frilassen
        printkcolor(exception_messages[r->int_no],0x04);
        printkcolor(" Exception. System Halted!\n",0x04);
        for (;;);
    }
}

/* Each of the IRQ ISRs point to this function, rather than
*  the 'fault_handler' in 'isrs.c'. The IRQ Controllers need
*  to be told when you are done servicing them, so you need
*  to send them an "End of Interrupt" command (0x20). There
*  are two 8259 chips: The first exists at 0x20, the second
*  exists at 0xA0. If the second controller (an IRQ from 8 to
*  15) gets an interrupt, you need to acknowledge the
*  interrupt at BOTH controllers, otherwise, you only send
*  an EOI command to the first controller. If you don't send
*  an EOI, you won't raise any more IRQs */
void irq_handler(struct regs *r)
{
    /* This is a blank function pointer */
    void (*handler)(struct regs *r);

    /* Find out if we have a custom handler to run for this
    *  IRQ, and then finally, run it */
    handler = irq_routines[r->int_no - 32];
    if (handler)
    {
        handler(r);
    }

    /* If the IDT entry that was invoked was greater than 40
    *  (meaning IRQ8 - 15), then we need to send an EOI to
    *  the slave controller */
    if (r->int_no >= 40)
    {
        outb(0xA0, 0x20);
    }

    /* In either case, we need to send an EOI to the master
    *  interrupt controller too */
    outb(0x20, 0x20);
}
:?

Wie gesagt ist noch alles Orginalzustand aus dem tut.
Ich wär sehr dankbar, wenn mir jemand Verbesserungsvorschläge machen würde.

DaCodaaa

  • Gast
Gespeichert
« Antwort #1 am: 17. August 2009, 21:05 »
Ok, hat sich erledigt...
nach langem probieren hab ich den Fehler gefunden:

Ich habe den non maskable Interrupt 2 mal in die Tabelle geschrieben und habe damit alle Weiteren Interrupts um eine Stelle nach hinten gerückt. :oops:
dabei war das so offensichtlich:
char *exception_messages[] =
{
    "Division By Zero",
    "Debug",
    "Non Maskable Interrupt",
    "Non Maskable Interrupt",
    "Breakpoint",
    ...

sry wegen dem Eintrag.

Aber ich habe noch immer ein problem mit dem pit:

Ich hatte mir ein wenig code geschrieben um den pit zu bedienen:

unsigned long long ticks = 0;
char second = 0;
char seconds = 0;
char minutes = 0;
char hours = 0;

void timer_handler(struct regs *r)
{
printk("tick");
        second++
ticks++;

if(second == 100);
{
seconds++;
                second = 0;
}
if(seconds == 60)
{
seconds = 0;
minutes++;
}
if(minutes == 60)
{
minutes = 0;
hours++;
}
if(hours == 24)
{
hours = 0;
days++;
}
}

Diese Funktion wird durch einen Interrupt auf Irq 0 ausgelöst.
Dann habe ich eine Funktion die nur wartet:

void timer_wait(long long int wait_ticks)
{
    long long eticks;

    eticks = ticks + wait_ticks;
    while(ticks < eticks);
}

Mein Problem ist jetzt, das zwar der Handler ständig ausgeführt wird, aber meine warten-Methode still steht.
also immer wenn ich timer_wait(...) ausführe macht der Recher nur munter meinen Bildschirm voll, aber er tut sonst nix mehr.

Kann mir bitte jemand helfen?
Danke im voraus.

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #2 am: 18. August 2009, 08:24 »
Wie und wo rufst du denn die Funktion "timer_wait" auf?
 
Eigentlich sollte das funktionieren, da der Timer-Handler die Variable ticks immer erhöht und dieses irgendwann größer als der Wert von eticks ist.
 
Kurze Anmerkung: Wenn du die Initialisierung aus Bran's Kernels Development Tutorial übernommen hast, sind immer 18 Ticks eine Sekunde, es sei denn, ich habe da was falsch gelesen...

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 18. August 2009, 09:18 »
Hast du mal geschaut, was gcc da an Code produziert? Ich könnte mir vorstellen, dass das einfach zu einer Endlosschleife optimiert wird. ticks als volatile deklarieren sollte dann helfen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

DaCodaaa

  • Gast
Gespeichert
« Antwort #4 am: 18. August 2009, 09:44 »
@ChristianF
Dass der auf hundert wartet ist schon richtig, denn ich habe den pit auf 100hz gestellt, daher ist die Funktion timer_wait schon richtig.
der handler wird auch immer wieder aufgerufen, daher wird auch tick laufend inkrementiert.
Das ist ja gerade der grund warum es mich so verwirrt :?

@taljeth
danke für den tipp, werde es bei nächster gelegenheit ausprobieren.

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #5 am: 18. August 2009, 11:42 »
Nun ja, man müsste schauen, ob ticks wirklich inkrementiert wird.
Gebe doch einfach mal ticks innerhalb der while-Schleife von timer_wait aus, anstatt diese leer laufen zu lassen...

DaCodaaa

  • Gast
Gespeichert
« Antwort #6 am: 18. August 2009, 15:10 »
Ok, super jetzt hängt er nichtmehr in ner endlosschleife. anschieinend war es wohl gcc.  :x

Alerdings wartet der länger als geplant aber das liegt wohl eher an dem emulierten pit von Bochs als an dem programm.

danke für die Hilfe.

EDIT: ach, da fällt mir noch ein, ich habe in irgendeinem Forum mal was ähnliches gelesen. anscheinend macht gcc irgendwas mit long longs falsch.
« Letzte Änderung: 18. August 2009, 15:17 von DaCodaaa »

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 18. August 2009, 15:44 »
ach, da fällt mir noch ein, ich habe in irgendeinem Forum mal was ähnliches gelesen. anscheinend macht gcc irgendwas mit long longs falsch.
Dass gcc das zu einer Endlosschleife optimiert ist kein Fehler, und es liegt auch nicht am long long.

es handelt sich tatsächlich um ein Feature. gcc erkennt das die beiden variablen nirgends verändert werden, und folgert daraus, dass wenn die Bedingung einmal erfüllt ist, sie immer erfüllt sein wird, und prüft deshalb nur einmal, alles andere wäre 0xd00f.

Dass die eine variable auch außerhalb des normalen Programmflusses verändert werden kann, muss du gcc mit dem Schlüsselwort "volatile" erklären.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

DaCodaaa

  • Gast
Gespeichert
« Antwort #8 am: 18. August 2009, 18:34 »
thx, wieder mal was dazugelernt :-).

 

Einloggen