Emulazione di Linus Torvalds: crea il tuo sistema operativo da zero (VI)

Bene, dopo una piccola parentesi continuiamo con la nostra serie di tutorial. Se torniamo al codice precedente, dobbiamo avere l'ISR della divisione per zero. Ora dobbiamo compilare il resto degli ISR ​​per i quali avevamo pubblicato un messaggio (i primi 32). Bene, ora continueremo a programmare le interruzioni, faremo gli IRQ noti anche come Richieste di interruzioni. Questi IRQ sono generati da dispositivi hardware come tastiere, mouse, stampanti, ecc. Inizialmente i primi 8 IRQ vengono mappati automaticamente sulle posizioni IDT 8-15, poiché abbiamo usato i primi 32 per le eccezioni, ora dobbiamo rimapparli. Metteremo l'IRQ da 32 a 45. Per questo dobbiamo prima rimappare gli 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);
}

Ora creiamo una funzione per installare gli 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");
}

La frase di asm sti attiviamo gli IRQ. Bene, ora andiamo con qualcosa di simile a ISR. Le funzioni di un IRQ di base:

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

Una parte comune (uguale all'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"
);
}

E un gestore di base:

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);
}

Con questo dovremmo già avere gli IRQ attivati ​​anche se ancora non fanno nulla. Nel prossimo capitolo vedremo come ottenere dati da questi IRQ come l'orologio o la tastiera.

SuccessivoDivel-IRQ


E con questo finisce il post di oggi. Come puoi vedere ora scrivo meno regolarmente a causa di altri problemi. Anche così continuerò finché non avrò un sistema operativo più completo


Lascia un tuo commento

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati con *

*

*

  1. Responsabile dei dati: Miguel Ángel Gatón
  2. Scopo dei dati: controllo SPAM, gestione commenti.
  3. Legittimazione: il tuo consenso
  4. Comunicazione dei dati: I dati non saranno oggetto di comunicazione a terzi se non per obbligo di legge.
  5. Archiviazione dati: database ospitato da Occentus Networks (UE)
  6. Diritti: in qualsiasi momento puoi limitare, recuperare ed eliminare le tue informazioni.

  1.   aitor_cz suddetto

    Grazie mille Adrian, appena avrò un po 'di tempo (ora sono abbastanza impegnato, tra l'altro anche con un sistema operativo) inizierò a testare il tutorial passo dopo passo.

  2.   Ruby suddetto

    Grazie mille per il tute.

  3.   sasuke suddetto

    Una domanda sto facendo un progetto basato su questi linguaggi di programmazione
    * Html5
    * Css3
    *Giava
    La mia domanda è che vorrei che questo progetto fosse eseguibile, in modo che gli utenti lo utilizzino in sistemi operativi come Linux e Windows, potresti dirmi come lo faccio

    1.    AdrianArroyoStreet suddetto

      Non ha niente a che fare con questo ma ti rispondo comunque. Presumo che sarà HTML5, CSS3 e JavaScript non Java, poiché HTML5 e Java vanno d'accordo fatalmente. Con HTML5 puoi creare siti web come prima a cui si accede da Internet. Se vuoi renderlo locale, puoi impacchettarlo come app per Firefox OS e Chrome OS. Se quello che vuoi è che in ogni sistema operativo ci sia un eseguibile dai un'occhiata a XUL Runner che è uno strumento per eseguire XUL (e quindi HTML5 all'interno dell'elemento) con il motore Gecko.

    2.    Soid perez suddetto

      Java frame o panel è un'ottima opzione Ho creato alcune app eseguibili in finestra utilizzando le classi java frame come browser web ma invece di usarlo per qualsiasi pagina gli do un percorso diretto nel codice e con php eseguo frasi java attraverso un .jar che si prende cura dell'acciaio. Anche se consiglierei di utilizzare HTML5, CSS3 e JavaScript poiché, come dice Adrian Java, è fatale con Html5 e mi ha dato molti grattacapi

  4.   urbano suddetto

    Un tutorial su come creare il tuo linguaggio di programmazione sarebbe carino

  5.   Ivan suddetto

    Ottima questa serie di articoli su come costruire un sistema operativo, si imparano tante cose. Non vedo l'ora che arrivi la prossima voce, voglio già avere una tastiera nel sistema operativo. Ho scherzato con il codice git e non l'ho fatto funzionare con le porte 0x60 e 0x64. Anche se pensavo che per la tastiera ci fosse un'interruzione che ti dava il tasto premuto.

    1.    AdrianArroyoStreet suddetto

      Puoi effettivamente ottenere l'input dalla tastiera senza interruzioni, ma devi leggere con ND :: Ports :: InputB sulla porta 0x60. Tuttavia, il modo ideale per farlo è con gli interrupt IRQ. Attualmente sto cercando di farlo e ci vuole un po 'più di tempo per continuare a causa di questo.

      1.    carlosorta suddetto

        Ciao Adrian, ho controllato il codice e sono impressionato da quello che fa e da quanto mi abbia aiutato a capire alcune cose.

        Ho alcune piccole domande su come funziona e la fonte è quella che ho ricevuto dal tuo GIT:

        1.- Nella parte IRQ, hai menzionato che le posizioni da 0 a 32 dell'IDT sono state utilizzate per le eccezioni e da 32 (0x20) a 45 (0x2D) per IRQ, ma gli IRQ sono 16 in totale, la rimappatura non sarebbe da 0x20 a 0x30?

        2.- Nella parte IRQ, notare che i setgate sono stati inviati alla sezione IDT; Quando li separa, nota che non produce più l'eccezione della divisione per 0, quindi è necessario aggiungere IDT Flush () per ogni modifica che viene effettuata. Perché l'IDT cambia quando si imposta il timer e la divisione tra 0 smette di funzionare?

        3.- Stavo cercando di tracciare il codice con un po 'di stampa da prendere come indicazione di ciò che sta eseguendo (in modo da non eseguire il debug passo dopo passo) e mi sono reso conto che nessun IRQ è in esecuzione, devo registrare qualcos'altro agli interrupt IRQ generati?

        1.    carlosorta suddetto

          Ho dimenticato di dire che ho trovato questi link con informazioni:
          http://arstechnica.com/civis/viewtopic.php?f=20&t=899001
          http://www.superfrink.net/athenaeum/OS-FAQ/os-faq-pics.html
          http://orga2.exp.dc.uba.ar/data/downloads/clasespracticas/interrupciones2_clase_17.pdf
          http://www.intel-assembler.it/PORTALE/4/231468_8259A_PIC.pdf

          Apparentemente, per gestire gli IRQ, è necessario tenere conto del tipo di gestore utilizzato se, PIC, APIC, IOAPIC. . .eccetera. C'è un modo per fare una dinamica di gestione degli IRQ o hai bisogno di tentare la fortuna?

  6.   carlosorta suddetto

    Buon pomeriggio Adrian.

    Ho visto che avevo problemi con gli IRQ ed è per questo che il codice non poteva essere avanzato, ho preso una copia del progetto e ho iniziato ad analizzarlo; Ho aggiunto una funzione alla serigrafia per stampare i reg record di struct reg, al momento di fare le interruzioni; Ho trovato diverse cose, tra cui che è in esecuzione un registro e ancora non riesco a trovare il motivo; cambia l'interruzione del timer per l'interruzione della tastiera per provare e fare quello che dovrebbe ma non riesco a trovare il problema, potresti aiutarmi e continuare con questo buon post? 😀

    Lascio il link (ha alcune modifiche perché uso Mageia e utilizzo Grub2, sto usando VirtualBox per testarlo)
    https://www.mediafire.com/?93psrgaoozatse8

    In attesa della tua risposta attenta e se hai domande o hai bisogno di qualcosa, vorrei aiutarti 🙂

    1.    carlosorta suddetto

      Ho dimenticato di dire che ho anche controllato il KernelPanic perché gli ISR ​​non funzionavano e ho lo stesso problema in cima allo stack un valore perde e non so se è il mio compilatore o c'è un problema, lo uso GCC 4.8.2 con Mageia 4

    2.    AdrianArroyoStreet suddetto

      Mi piace molto che tu mi aiuti nel progetto. Sono rimasto davvero bloccato nel timer e non capisco perché non funziona. Ho fatto dei test modificando parecchie cose e non ha funzionato. Al momento non riesco a modificare il codice (sono in vacanza) ma lo guarderò bene appena possibile. Ti do un link con informazioni su questo problema che sembra essere qualcosa di comune: http://wiki.osdev.org/I_Cant_Get_Interrupts_Working

      Per quanto riguarda le eccezioni, penso di ricordare che devi fare una chiamata a "sti" in ASM per attivarle anche se è chiaro che c'è qualcosa che non va da qualche parte.

      1.    carlosorta suddetto

        Grazie per la tua risposta e sì, davvero. Gli interrupt fallivano ma si è verificato un problema nell'inserimento dei codici nello stack e nel casting, controllerò il collegamento e farò dei test. Se lo risolvo ti farò sapere e in caso contrario ti informerò dei progressi. Buone vacanze 🙂

      2.    carlosorta suddetto

        Non ci sarà modo di vedere il codice assemblato? Succede qualcosa di strano e non riesco a trovare cosa? Guarda questa schermata (metto il link alla fine), è qualcosa di strano dato che nella funzione IRQ 2 (la tastiera ) inserisce nello Stack il valore 0 e 0x20 (32, quindi adattalo al test) quindi pushal (i registri GPR a 32 bit) seguito dai registri di segmentazione e quindi in cima allo stack e quindi chiama IRQ Handler. Ho iniziato a vedere ogni stack e apparentemente è nell'ordine ma se puoi vedere l'output della VM puoi vedere che impila un altro elemento, non riesco a trovare dove, so solo che è uno 0x10 e il la struttura è fuori uso. Questa è la struttura del record.

        struct regs {
        uint32_t gs, fs, es, ds; / * ha spinto i secondi per ultimi * /
        uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; / * spinto da 'pushal' * /
        uint32_t int_no, err_code; /* Codice di errore */
        uint32_t eip, cs, eflags, useresp, ss; / * Stacked on break * /
        };

        Mi dà fastidio che metta un elemento in più in alto e non riesco a trovare dove impilarlo se apparentemente tutto è impilato come dovrebbe essere. Hai idea di cosa potrebbe essere?

        http://www.subeimagenes.com/img/sin-titulo-1036729.jpg

  7.   carlosorta suddetto

    Fa in modo che l'interruzione della tastiera funzioni ma non quella del timer; l'errore era nel modo in cui è stato compilato, ho usato objdump per vedere l'oggetto finale e si è scoperto che ogni funzione inserita anche usando "asm volatile" era anche accompagnata da un pushl ebp, mov ebp, esp. Quindi aggiungi un popl ebp ad esso per ripristinare lo stack iniziale e passerà gli argomenti senza errori. Qui allego il codice per chi vuole verificarlo e se riesce a scoprire perché l'interruzione non è generata dal Timer, mi piacerebbe saperlo e allego un link dove si parla di multitasking http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html
    Prossima immersione
    https://www.mediafire.com/?kmo83dxyzc7c3cz

    1.    AdrianArroyoStreet suddetto

      Capito. Era un bug in un altro sito che influiva sull'attivazione del Timer PIC, nello specifico nella rimappatura IRQ c'erano due righe che dovevo modificare. Grazie al fatto che ho potuto vedere un codice su un sito web che a quel punto aveva qualcosa di diverso e cliccare! Il cambiamento è stato sulla falsariga di:
      ND :: Porte :: UscitaB (PIC1 + 1, 0xFF);
      ND :: Porte :: UscitaB (PIC2 + 1, 0xFF);

      Dovevi cambiare il valore di 0xFF (direi che indica disabilitato) a 0x00 (direi che indica abilitato) anche se non ne sono proprio sicuro, ma funziona. Ho aggiornato il codice su GitHub. Grazie mille per avermi aiutato con il progetto che avevo un po 'abbandonato a causa di questo problema. H

      1.    carlosorta suddetto

        Prego, attendo con ansia il prossimo aggiornamento dell'argomento e puoi contare su di me per qualsiasi cosa 🙂 (Y)

      2.    carlosorta suddetto

        Modificare la routine di acquisizione delle stringhe della tastiera; perché sta leggendo quando viene rilasciato il tasto e monta uno 0 nel buffer, che dà problemi nella lettura e alla fine il '\ n' lo cambia in »in modo che la stampa corretta funzioni

  8.   Soid perez suddetto

    Ciao, ho letto tutto il tuo post, anche se in pratica non è più di 2 post, è davvero molto buono, salva tutto, ma avrò davvero bisogno di studiare c ++ e posix per capirlo perché so di "c" (Sono affascinato da quel linguaggio di programmazione) ma sebbene c ++ sia c OO non ci ho mai veramente lavorato, leggimi alcuni tutorial in google e poi torno questo molto interessante e una domanda, l'avvio della finestra è simile a linux?

    1.    AdrianArroyoStreet suddetto

      L'avvio in Windows è simile nel senso che questo è il modo per avviare un sistema con un processore x86 e il sistema operativo costruito su di esso ha poca influenza. Non ci stiamo comunque avviando da soli, sta avviando GRUB per noi. GRUB, progettato per avviare Linux, può avviare Windows e in questo caso NextDivel.

      1.    suono suddetto

        ok grazie vuol dire che quello che voglio fare è possibile sto già studiando c ++ e ho creato delle app e installato il tuo sistema su una pendrive e lo sto studiando più in dettaglio è un ottimo post