Εξομοίωση Linus Torvalds: Δημιουργήστε το δικό σας λειτουργικό σύστημα από το μηδέν (VI)

Εντάξει, μετά από ένα σύντομο διάλειμμα, ας συνεχίσουμε με τη σειρά των μαθημάτων μας. Αν επιστρέψουμε στον προηγούμενο κώδικα, θα πρέπει να έχουμε το ISR για τη διαίρεση με το μηδέν. Τώρα πρέπει να συμπληρώσουμε τα υπόλοιπα ISR για τα οποία είχαμε ορίσει προηγουμένως ένα μήνυμα (τα πρώτα 32). Τώρα θα συνεχίσουμε να προγραμματίζουμε διακοπές. Θα δημιουργήσουμε IRQ, γνωστά και ως Αιτήματα Διακοπής. Αυτά τα IRQ δημιουργούνται από συσκευές υλικού όπως πληκτρολόγια, ποντίκια, εκτυπωτές κ.λπ. Αρχικά, τα πρώτα 8 IRQ αντιστοιχίζονται αυτόματα στις θέσεις IDT 8 έως 15. Δεδομένου ότι χρησιμοποιήσαμε τα πρώτα 32 για εξαιρέσεις, τώρα πρέπει να τα αντιστοιχίσουμε ξανά. Θα αντιστοιχίσουμε IRQ από 32 έως 45. Για να το κάνουμε αυτό, πρέπει πρώτα να αντιστοιχίσουμε ξανά τα IRQ:

void ND::IRQ::Remap(int pic1, int pic2)
{
#define PIC1 0x20
#define PIC2 0xA0
#define ICW1 0x11
#define ICW4 0x01
/* send ICW1 */
ND::Ports::OutputB(PIC1, ICW1);
ND::Ports::OutputB(PIC2, ICW1);
/* send ICW2 */
ND::Ports::OutputB(PIC1 + 1, pic1); /* remap */
ND::Ports::OutputB(PIC2 + 1, pic2); /* pics */
/* send ICW3 */
ND::Ports::OutputB(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
ND::Ports::OutputB(PIC2 + 1, 2);
/* send ICW4 */
ND::Ports::OutputB(PIC1 + 1, ICW4);
ND::Ports::OutputB(PIC2 + 1, ICW4);
/* disable all IRQs */
ND::Ports::OutputB(PIC1 + 1, 0xFF);
}

Τώρα δημιουργούμε μια συνάρτηση για την εγκατάσταση των IRQ:

void ND::IRQ::Install()
{
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_BLACK);
ND::Screen::PutString("\nInstalling IRQ...");
ND::IRQ::Remap(0x20,0x28);
ND::IDT::SetGate(32,(unsigned)ND::IRQ::IRQ1,0x08,0x8E);
ND::IDT::SetGate(33,(unsigned)ND::IRQ::IRQ2,0x08,0x8E);
ND::IDT::SetGate(34,(unsigned)ND::IRQ::IRQ3,0x08,0x8E);
ND::IDT::SetGate(35,(unsigned)ND::IRQ::IRQ4,0x08,0x8E);
ND::IDT::SetGate(36,(unsigned)ND::IRQ::IRQ5,0x08,0x8E);
ND::IDT::SetGate(37,(unsigned)ND::IRQ::IRQ6,0x08,0x8E);
ND::IDT::SetGate(38,(unsigned)ND::IRQ::IRQ7,0x08,0x8E);
ND::IDT::SetGate(39,(unsigned)ND::IRQ::IRQ8,0x08,0x8E);
ND::IDT::SetGate(40,(unsigned)ND::IRQ::IRQ9,0x08,0x8E);
ND::IDT::SetGate(41,(unsigned)ND::IRQ::IRQ10,0x08,0x8E);
ND::IDT::SetGate(42,(unsigned)ND::IRQ::IRQ11,0x08,0x8E);
ND::IDT::SetGate(43,(unsigned)ND::IRQ::IRQ12,0x08,0x8E);
ND::IDT::SetGate(44,(unsigned)ND::IRQ::IRQ13,0x08,0x8E);
ND::IDT::SetGate(45,(unsigned)ND::IRQ::IRQ14,0x08,0x8E);
ND::IDT::SetGate(46,(unsigned)ND::IRQ::IRQ15,0x08,0x8E);
ND::IDT::SetGate(47,(unsigned)ND::IRQ::IRQ16,0x08,0x8E);
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_GREEN);
ND::Screen::PutString("done");
asm volatile("sti");
}

Η πρόταση του asm sti ενεργοποιούμε τα IRQ. Λοιπόν τώρα πηγαίνουμε με κάτι παρόμοιο με το ISR. Οι λειτουργίες ενός βασικού IRQ:

void ND::IRQ::IRQ1()
{
asm volatile(
"cli \n"
"pushl 0\n"
"pushl 32\n"
"jmp ND_IRQ_Common"
);
}

Ένα κοινό μέρος (ίδιο με το ISR):

extern "C"
void ND_IRQ_Common()
{
asm volatile(
"pusha \n"
"push %ds\n"
"push %es\n"
"push %fs\n"
"push %gs\n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movl %esp, %eax \n"
"push %eax \n"
"movl $ND_IRQ_Handler, %eax \n"
"call *%eax \n"
"popl %eax \n"
"popl %ds \n"
"popl %es \n"
"popl %fs \n"
"popl %gs \n"
"popa \n"
"addl 8, %esp \n"
"iret \n"
);
}

Και ένας βασικός χειριστής:

extern "C"
void ND_IRQ_Handler(struct regs* r)
{
void (*handler)(struct regs *r);
if(r->int_no >= 40)
{
ND::Ports::OutputB(0xA0,0x20);
}
ND::Ports::OutputB(0x20,0x20);
}

Με αυτό θα πρέπει να έχουμε ήδη ενεργοποιήσει το IRQ ακόμα και αν δεν κάνουν τίποτα. Στο επόμενο κεφάλαιο θα δούμε πώς να λαμβάνουμε δεδομένα από αυτά τα IRQ, όπως το ρολόι ή το πληκτρολόγιο.

NextDivel-IRQ


Και με αυτό τελειώνει η σημερινή ανάρτηση. Όπως μπορείτε να δείτε τώρα γράφω λιγότερο τακτικά λόγω άλλων ζητημάτων. Ακόμα κι έτσι θα συνεχίσω έως ότου έχω ένα πιο ολοκληρωμένο λειτουργικό σύστημα


Προσθήκη ως προτιμώμενης πηγής στην Google