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