1. A breve aggiorneremo la piattaforma di Reboot per risolvere alcuni problemi con i plug-in, quindi chiediamo ancora un po' di pazienza, Lo staff di Reboot

[Guida] Come creare un sistema operativo in C++ - Gli interrupt

Discussione in 'Software' iniziata da iostream, 25 Ago 2017.

  1. iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.913
    Like ricevuti:
    1.639
    [​IMG]

    Era tanto che non scrivevo un thread della guida di OSDev, oggi questo sarà un capitolo molto lungo e pieno di spiegazioni. Oggi parleremo di una delle cose essenziali per avere un kernel funzionante: gli interrupt.

    E' consigliato leggere la guida dall'introduzione per apprendere un pò di lessico

    Se questo è il primo capitolo che leggete, dovrete inziare dall'inzio (e da dove sennò, dalla fine?)


    Cosa sono gli interrupt, ISR e IRQ?

    Gli interrupt sono azioni che bloccano l'esecuzione di un programma per eseguire il loro codice.
    Gli ISR sono i gestori degli interrupt. La loro abbreviazione
    Gli IRQ sono degli interrupt causati da componenti del computer (es. tastiera o mouse). La loro abbreviazione significa Interrupt ReQuest


    La tabella IDT


    La tabella IDT è una tabella definita nel processore che definisce il codice che gli interrupt andranno ad eseguire quando uno avverrà. Una voce di questa tabella è fatta così:
    [/tr]
    Bit 0-15Bit 16-31Bit 32-39Bit 40-434445-464748-63
    Primi 16 bit del puntatore all'ISRSelettore del codice kernel mode(0x0008)Deve essere 0x00Tipo ISR (0xE)Impostare a 0Dice se l'interrupt va eseguito in kernel mode (puoi fare tutto sull'hardware) o in user mode (non puoi toccare quasi niente dell'hardware)Bit di presenzaUltimi 16 bit del puntatore all'ISR
    Quindi iniziamo a creare un file idt.cpp definendo una voce di IDT:
    Codice:
     struct IDTEntry {
        unsigned short offset_lo; // Primi 16 bit dell'indirizzo dell'ISR
        unsigned short sel;          // Selettore nella GDT (0x0008)
        unsigned char zero;         // Sempre 0x00
        unsigned short type_att;  // Tipo e attributi
        unsigned short offset_hi; // Ultimi 16 bit dell'indirizzo dell'ISR
    }__attribute__((packed));  // Serve a non fare ottimizzare al GCC la tabella

    Il processore, invece, immagazzina la tabella in modo molto semplice. Questa tabella servirà a farci capire come la CPU immagazzina l'IDT (e le altre tabelle):
    Bit 0-15Bit 16-31
    Dimensione della tabellaIndirizzo della tabella in memoria
    Quindi creiamo una struttura, dopo IDTEntry, che definisce il puntatore:
    Codice:
     struct IDTPtr {
        unsigned short size;  // Dimensione della tabella
        unsigned int offset;    // Indirizzo della tabella in memoria
    }__attribute__((packed)); 
    Adesso creiamo l'array della IDT e il suo puntatore:
    Codice:
     IDTEntry TableIDT[256];
    IDTPtr PointerIDT;
    E diciamo al compilatore che ci sono funzioni esterne:
    Codice:
    extern "C" { /* Usa il linking C perché in C++ i nomi sono diversi da quelli nel codice. Es. IDT::SetEntry diventa tipo Z11IDTz8SetEntryj4  (roba incomprensibile). */
        extern void setIDT();
        /* Aggiungeremo altro */
    }  // Non usare più il linker C
    Ora definiamo una funzione che permette di impostare facilmente una voce di IDT:
    Codice:
    void IDT::SetIDTEntry(int index, unsigned int offset, unsigned int selector, unsigned int type_attr) {
         // Dividi in due l'indirizzo dell'ISR e mettilo nella tabella
         TableIDT[index].offset_lo = offset & 0xFFFF;
         TableIDT[index] = (offset >> 16) & 0xFFFF;
    
         // Imposta le voci con quelle dei parametri
         TableIDT[index].sel = selector;
         TableIDT[index].type_attr = type_attr;
         TableIDT[index].zero = 0x00;
    }
    Ora creiamo una funzione che inizializza la IDT:
    Codice:
    void IDT::InitializeIDT() {
        // Imposta il puntatore
        PointerIDT.size = 2047; // La tabella IDT è grande 2k (- 1, perché la IDT dice così)
        PointerIDT.offset = (unsigned int)&TableIDT; // Ottieni l'indirizzo in memoria della IDT
    
        // Imposta a 0 il contenuto della IDT
        for (int i=0; i<256; ++i)
             SetEntry(i, 0, 0, 0);
    
        // Qui andranno impostati tutti gli ISR
        // -----
    
        // Dì al processore di caricare la nuova IDT
        setIDT();
    
         // Attiva gli IRQ
         asm("sti");
    }
    Header file della IDT

    Creiamo anche file idt.h e scriviamo:
    Codice:
    #ifndef IDT_INC
    #define IDT_INC
    
    namespace IDT {
        void SetIDTEntry(int index, unsigned int offset, unsigned int selector, unsigned int type_attr);
        void InitializeIDT();
    }
    #endif
    E cambiamo il kernel.cpp:
    Codice:
     #include "idt.h"
    void main() {
        IDT::InitializeIDT();
        Screen::PutString("IDT inizializzata!");
        return 0;
    }
    Conclusione

    Aggiungete al Makefile l'obiettivo per compilare idt.cpp (fatelo voi, ormai dovreste aver capito :smile:) e create la ISO. Purtroppo per questo articolo non ho potuto scrivere molto, ma sul prossimo (uscirà il 28) farò gli ISR e gli IRQ e faremo funzionare la tastiera

    Capitolo precedente
     
    #1
    Ultima modifica: 25 Ago 2017
    A alsacchi e MODD3R piace questo messaggio.
  2. alsacchi

    alsacchi Livello 7

    Iscritto:
    25 Gen 2017
    Messaggi:
    171
    Like ricevuti:
    83
    Continuo a pensare se non esistessero le librerie, per scrivere una stringa sullo schermo ci vorrebbero tante linee di codice, soprattutto se le devi fare pixel per pixel.
    Grazie librerie.
     
    #2
Sto caricando...

Condividi questa Pagina