• Non ci sono risultati.

3.3 Analisi del codice sorgente

3.3.2 Modiche generali

Si raccolgono inne in questa sezione una serie di modiche eettuate al codice di SimCPU.

3.3.2.1 Protezione del buer video

Come tutte le risorse globali, accessibili da più thread contemporaneamente, an-che il terminale video deve essere gestito in maniera tale an-che non vengano eettua-te coneettua-temporaneameneettua-te chiamaeettua-te a funzioni di stampa. Questo infatti compor-terebbe una perdita di informazione dovuta al fatto che l'accesso contemporaneo al buer video causa la sovrastampa di uno o l'altro messaggio. Il problema è stato risolto mediante l'introduzione di un nuovo semaforo a protezione della scrittura a video. La stampa sul terminale deve avvenire solamente mediante la chiamata della funzione message() (la quale riceve come argomento una stringa) che si occupa della stampa a video mediante printf(), opportunamente protetta dal semaforo suddetto. L'accesso contemporaneo alla funzione message(), ed in particolare a printf() è dunque regolato dal semaforo di protezione che impedisce che il terminale venga utilizzato in maniera non mutuamente esclusiva.

3.3.2.2 Argomento NOTRACE per le funzioni più utilizzate

Com'è noto dalla versione didattica, l'esecuzione di un programma in modalità Trace mode Extended, causa la stampa a video di ogni passaggio che concerne la messa in opera di ogni singola istruzione. Tuttavia, con la complicazione delle fun-zioni, spesso, le informazioni stampate a video risultavano eccessive e ridondanti, comportando confusione invece che chiarezza. Si è deciso dunque di aggiungere un argomento alle funzioni più utilizzate (lettura dei registri e settaggio e lettu-ra dei ags) con i quali decidere eettivamente in quali occasioni elettu-ra opportuno realizzare la stampa a video ed in quali no. Se la funzione riceve come ingresso la costante TRACE, l'esecuzione dell'istruzione in modalità Extended che passa per quel determinato punto comporterà la stampa a video, altrimenti, se la costante in ingresso è NOTRACE, la stampa del passaggio si ritiene ridondante e viene evitata. Un esempio di utilizzo può essere riconosciuto nelle funzioni di lettura e scrittura del ag di kernel riportate qui di seguito.

3.3.2.3 Nuova congurazione per le subroutine di lettura e scrittura dei ag

Considerata la modica strutturale eettuata alla posizione dei ag di sistema, i quali nella nuova versione di SimCPU risiedono direttamente all'interno di un registro speciale, è stato necessario rivedere completamente le relative funzioni che vi accedevano. Nella fattispecie, sarà preso in esame il setting e la lettura del ag di kernel, ad esso corrispondono le seguenti funzioni.

byte read_flag_kernel_mode ( int t r a c e ) {

byte t ;

t = ( byte ) ( ( r e a d _ s p e c i a l _ r e g i s t e r (FLAG_REGISTER, NOTRACE) & FLAG_KER_MASK) >> FLAG_KER_POS) ; i f ( trace_mode == TRACE_MODE_EXTENDED && t r a c e == 1) {

char s [MAXMSGLEN] ;

s p r i n t f ( s , "TRACE: %1X read from f l a g kernel_mode" , ( unsigned int ) t ) ;

message ( s ) ; }

return t ; }

void set_flag_kernel_mode ( byte value ) {

word t ;

i f ( trace_mode == TRACE_MODE_EXTENDED) {

char s [MAXMSGLEN] ;

s p r i n t f ( s , "TRACE: f l a g kernel_mode s e t to %1X\n" , ( unsigned int ) value ) ; message ( s ) ;

}

i f ( value )

s e t _ s p e c i a l _ r e g i s t e r (FLAG_REGISTER,

t = r e a d _ s p e c i a l _ r e g i s t e r (FLAG_REGISTER, NOTRACE) | FLAG_KER_MASK) ; else

s e t _ s p e c i a l _ r e g i s t e r (FLAG_REGISTER,

t = r e a d _ s p e c i a l _ r e g i s t e r (FLAG_REGISTER, NOTRACE) & ~FLAG_KER_MASK) ; return ;

}

Dove le costanti FLAG_KER_MASK e FLAG_KER_POS identicano ri-spettivamente la maschera da applicare al registro per il settaggio del bit di kernel e la posizione del bit di kernel all'interno del FLAG REGISTER facendo partire il conteggio da zero. Le denizioni per ogni ag sono qui di seguito riportate:

/∗ f l a g p o s i t i o n d e f i n i t i o n s ∗/ #define FLAG_ZER_POS 0 #define FLAG_ZER_MASK 0 x0001 #define FLAG_NEG_POS 1 #define FLAG_NEG_MASK 0 x0002

3.3. ANALISI DEL CODICE SORGENTE 55 #define FLAG_CAR_POS 2 #define FLAG_CAR_MASK 0 x0004 #define FLAG_OWF_POS 3 #define FLAG_OWF_MASK 0 x0008 #define FLAG_KER_POS 4 #define FLAG_KER_MASK 0 x0010 #define FLAG_PAG_POS 5 #define FLAG_PAG_MASK 0 x0020 #define FLAG_TLB_POS 6 #define FLAG_TLB_MASK 0 x0040 #define FLAG_INT_POS 7 #define FLAG_INT_MASK 0 x0080

Se si tiene presente la considerazione per la quale il ag di kernel è il quinto bit meno signicativo allora risulta evidente il signicato del codice. Per quanto riguarda la lettura, il byte t assume esattamente il valore del bit di kernel, il quale si ottiene applicando una maschera al ag register per estrarne il valore. Lo shift a destra di un numero di posizioni opportune permette che venga restituito in t il valore del ag di kernel.

Per quanto riguarda il settaggio del ag, il procedimento si dierenzia in funzione del valore da settare. Le maschere da utilizzare, infatti, sono dierenti a seconda che il valore sia uno o zero. In particolare, l'impostazione del bit ad uno si realizza facendo la OR del registro con la maschera, l'impostazione a zero, invece è generata facendo la AND del registro col negato della maschera.

Figura 3.4: Mappa dei ag nel FLAG REGISTER

3.3.2.4 Modalità di stampa a video per il thread del monitor

La stampa a video di un carattere all'interno del thread del monitor viene eseguita in due diverse modalità a seconda del tipo di esecuzione in cui è impostato il simulatore. In T E e in T I, la stampa di un carattere viene seguita dalla stampa di una linea riportante la traccia dell'operazione. In T D, invece, viene eseguita una stampa a singolo carattere, seguita dalla funzione ush() che ne garantisce la visualizzazione a video svuotandone il buer. Questa dierente trattazione rende molto più realistica la simulazione in run forever rispetto a quanto non fosse precedentemente. Nella versione didattica, infatti, la stampa a video in qualsiasi modalità veniva eettuata posponendone una stringa recante la traccia dell'operazione.

3.4 Sviluppi futuri

L'attuale congurazione hardware di SimCPU si presta ad uno svariato numero di modiche e ottimizzazioni, a partire dal thread della tastiera.

TASTIERA: Attualmente il thread della tastiera ne simula solo in minima parte il reale funzionamento. In realtà anche la tastiera dovrebbe essere in grado di generare delle interruzioni, sia quando vengono premuti i tasti, sia quando si riempie il buer. A questo genere di gestione si aanca la necessità di scrivere le relative routine software per la gestione di queste interruzioni. Il punto di vista a basso livello del principale dispositivo di input implementato in questa versione di SimCPU, mette dunque a dispo-sizione la possibilità di ampliare le trap dedicate alla tastiera. Si possono facilmente realizzare trap per la lettura di stringhe e per la lettura con echo, nonché gestire facilmente tasti quali F1-F12 ed attribuirgli funzioni particolari.

PARALLELISMO: Portare a 32 bit il parallelismo della CPU comporta es-senzialmente un aumento del numero di registri, un aumento della grandez-za delle word (che da 2 passano a 4 byte), un adeguamento dell'Instruction Set oltre a tante altre piccole modiche. Nonostante l'adeguamento del parallelismo ai 32 bit sia da un lato prematuro nei confronti di un'architet-tura semplicistica come quella di SimCPU, dall'altro garantirebbe almeno la possibilità di poter indirizzare completamente in maniera assoluta ogni locazione di memoria principale. La limitazione fondamentale di un siste-ma da 16 bit con una memoria da 1 MB, è il fatto che l'architettura non può indirizzare completamente ogni locazione di memoria, ma soltanto i primi 64kB. Ciò rappresenta uno scoglio nei confronti del sistema operativo il quale in teoria deve poter agire in maniera assoluta su ogni locazione di memoria per poter ottimizzare al meglio le sue funzionalità.

DMA: Dal punto di vista hardware, sarebbe interessante poter introdur-re un dispositivo che introdur-regoli la trasmissione di dati in maniera continuata, svincolando il sistema ad operare su un solo carattere. La necessità di trasmettere più byte durante la stessa comunicazione, è legata al fatto che, per dispositivi veloci quali ad esempio l'hard disk, una trasmissione a carat-tere (una interruzione per ogni caratcarat-tere) implicherebbe un rallentamento signicativo delle prestazioni del dispositivo di memoria esterno. Il DMA sarebbe il primo passo verso la denizione di un le system e la simulazione dei dispositivi di memoria secondaria, i quali comporterebbero la possibilità di iniziare a pensare all'implementazione di un sistema operativo dinamico per SimCPU.

Capitolo 4

SimOS - implementazione software

A questo punto è stato dunque modicato l'hardware del processore sulla base di scenari plausibili di implementazione del sistema operativo e non resta altro da fare che discuterne il codice. Come già accennato nell'introduzione, sia la scrittura del codice vero e proprio che parte delle modiche hardware introdotte, sono state realizzate in concordanza con un'altra tesi parallela a questa. Le varie parti del sistema operativo realizzate in queste due tesi, sono state unite per giungere ad un risultato nale del quale se ne testerà dapprima il funzionamento lasco (solo compilazione), ed in seguito, nel prossimo capitolo, il corretto funzionamento robusto. In questo capitolo, dunque verranno descritte approfonditamente le routine assembly introdotte che sono eettivamente parte integrante del sistema operativo e ad esse verrà aggiunta per completezza una descrizione sommaria delle routine trattate nella tesi parallela.

4.1 Il modello statico

Nel capitolo 2 è stata introdotta la distinzione tra sistema operativo statico e sistema operativo dinamico. In questa sezione si analizzeranno le caratteristiche principali di un ambiente statico, quale quello che verrà eettivamente utilizzato per SimOS.

La necessità di aggirare il problema dell'assenza del simulatore di un disposi-tivo di memoria secondaria si traduce nella conseguenza che non potranno esse scritte delle routine software in grado di prelevare programmi dalla memoria se-condaria per trasferirli in memoria principale. In altre parole, all'avvio del sistema operativo, tutta la memoria principale dovrà essere già mappata completamente e non potranno essere caricati (e dunque creati) ulteriori programmi oltre a quelli scelti all'inizio. Questa limitazione è eettivamente molto pesante; tuttavia, rea-lizzare una simulazione del le system, della DMA e della memoria secondaria, nonché di una shell minimale, sarebbe andato ben troppo al di là degli scopi di questo progetto. Con questo sistema operativo si vuole tuttavia porre le basi per sviluppi futuri, ovvero realizzare uno scheletro robusto, costituito da gestione delle interrupt, delle trap e scheduler, sul quale poi sviluppare le parti mancanti.

In via del tutto transitoria, la mappatura della memoria è stata adata ad un programma esterno denominato Loader. Il Loader riceve come parametri il nome del le eseguibile (*.exx) contenente il listato di SimOS, il nome degli eseguibili dei programmi utente che si intende eseguire e il nome del le di uscita conte-nente la mappatura della memoria (estensione *.kxx). La dierente estensione scelta per il le contenente la mappatura della memoria è dovuta al fatto che il simulatore deve poter permettere l'esecuzione sia dei programmi singoli, come in passato, sia del sistema operativo. I due meccanismi di funzionamento necessitano di inizializzazioni profondamente diverse, a partire dalle dierenti congurazioni dei ag di paginazione e di TLB, oltre al fatto che il thread del timer, durante l'esecuzione di un singolo programma, non deve venire nemmeno abilitato perché la gestione delle interruzioni e delle trap è esclusiva del sistema operativo. Una spiegazione più approfondita sulle dierenti modalità di esecuzione di SimCPU è riportata in appendice C.

Il programma Loader è dunque adibito a mappare le pagine dei programmi e del sistema operativo all'interno della memoria sica. Lo stesso programma si occupa di creare ed inizializzare le tabelle delle pagine, le PCB, le variabili globali del sistema e di disporre coerentemente le pagine dei programmi nei frame liberi a partire da opportune locazioni di memoria. Sia le tabelle delle pagine, sia quelle delle PCB, sono state mappate all'interno del segmento del kernel a locazioni predenite.

La prima pagina del sistema operativo, è stata mappata nel primo frame della memoria principale, questo per simulare il caricamento, da parte del Bios, del primo blocco di memoria secondaria nella memoria principale. Il primo frame salta semplicemente alla locazione di memoria che realizza la fase di boot del sistema operativo. Trattandosi di un sistema statico ed essendo la memoria sica già mappata, l'unica operazione svolta nella fase di boot è quella di realizzare il dispatching del primo programma per consentirne poi l'esecuzione.

Nelle prossime sezioni saranno valutate prima di tutto le scelte che sono state eettuate per quanto concerne le tabelle delle pagine e le PCB, e poi si andrà ad analizzare il codice del sistema operativo, con particolare accento posto sulle routine di interruzione e sulle routine di trap oggetto di questa trattazione.

Documenti correlati