Approfondimenti sulla programmazione delle CPU x86

Introduzione

Qui trovate il codice sorgente di un programma che ho scritto nel lontano 1997 per il mio nuovo AMD K5 a 100Mhz.
Il programma non è completo, ma è comunque utile per chi è interessato alla programmazione a basso livello ed a capire come funziona l'indirizzamento virtuale delle cpu x86 a 32 bit. Nel codice c'è sicuramente un pò di confusione, ma il risultato è la creazione di un task a 32 bit puro e un altro v86 in grado cioè di eseguire codice a 16 bit sotto la supervisione del task a 32 bit.
Con qualche modifica al codice di questa pagina sono riuscito ad eseguire un'intera copia di ms-dos sotto il task v86.
Le specifiche ufficiali sul funzionamento delle cpu le trovate al sito Intel.

Tools utilizzati

Il programma e` diviso in due parti nettamente separate:
  • Il loader e` scritto parte in Borland Turbo Pascal 7.0 e parte in assembler
  • Il vero programma (kernel) a 32 bit scritto in C compilato e linkato coi tool presenti assieme al compilatore djgpp. E` presente anche una parte in assembler.
  • Il codice assembler e` compilato con nasm

    Il loader

    Il loader e` un programma per ms-dos, la sua funzione e` quella di caricare il kernel in memoria, portare la CPU in modo protetto e cedere il controllo al kernel. Al ritono riporta la CPU in modo reale e ritorna al DOS.
    Vedi Sorgente:
    stub.pas
    Questo e` la parte principale del loader in pascal. Non pensate che la parte in pascal sia piu` facile, credo che questo sia uno dei programmi piu` assurdi scritto col vecchio pascal: alcune procedure sono in assembler, altre anche se in pascal vengono chiamate quando la CPU e` gia` in modo protetto, ed inoltre vengono creati 6 array per la tabella di traduzione degli indirizzi sulla memoria video.
    nxms.asm
    Qui sono scritte alcune procedure in assembler principalmente per portare la CPU in modo protetto a 32 bit
    NB: Questo programma richiede l'accesso totale alla CPU, percio` e` necessario laciarlo da DOS (non windows!) oppure con un emulatore (bochs o vmware sotto linux, non dosemu).
    download del loader

    Il kernel

    Questo e` il vero programma che viene caricato dal loader.
    crt0.asm
    Questo e` il codice iniziale richiamato dal loader. Ci sono alcune routine per rilevare il tipo di CPU, per impostare il controller degli interrupt, ed alcuni registri di sistema (IDT,GDT,TSS,..). Il listato e` sufficientemente commentato.
    main.c
    L'esecuzione di crt0.asm termina con una chimata alla procedura start() che mostra a video alcune informazioni sulla CPU, e continua con diverse inizializzazioni:
    ph_memory_setup in phmem.c
    Inizializzazione pagine di memoria
    systab_setup in systab.c
    Inizializzazione tabelle di sistema (IDT, GDT)
    sched_setup in sched.c
    Imposta le strutture dati usati per le informazioni sui task.
    base_task_setup in excpt.c
    Crea alcuni task che gestiscono le eccezioni di CPU
    Con una chiamata a jmp_task faccio partire il task del kernel, che corrisponde alla procedura start_kernel, che esegue queste operazioni:
    kmalloc_startup in kmalloc.c
    Imposta struttura dati per le chiamate a kmalloc e kfree
    irq_setup in irq.c
    Imposta i vettori di interrupt per gli irq.
    Crea il task e lancia il debugger debugg.c
    Questo dovrebbe essere il debugger, ma in realta` si limita a scrivere sullo schermo i tasti premuti sulla tastiera.
    Crea il task v86 vm86.c
    Questa parte di codice (racchiusa fra #if 0/#endif) serve per lanciare un task in emulazione 8086.
    download del kernel
    Nota come ho detto ho provato il tutto su un K5: sono quasi sicuro che il codice non funzionera` correttamente sulle CPU che non hanno le pagine da 4Mb (PSE), l'emulazione del flag di interrupt (VME), e forse anche le pagine globali (PGE). Queste 3 feature sono presenti in tutte le CPU Pentium PRO e superiori, ma non in tutti i Pentium (poi dicono che i k5 sono scarsi! ;) )
    Altri file sorgente presenti:
    console.c
    gestione I/O su video
    debug.asm
    Codice asm per l'eccezione di debug
    excpasm.asm
    Codice asm per le eccezioni della CPU e gli IRQ
    paging.c
    Diverse procedure per traduzione indirizzi fisici/virtuali
    v86.asm
    codice include per il task v86 a 16 bit
    v86i.asm
    vero codice per il task v86 a 16 bit.
    link.lnk
    questo e` lo script per il linker