Progettazione e Realizzazione di un Emulatore di Xerox Alto per Raspberry Pi - Dipartimento di Matematica e Informatica Corso di Laurea in Informatica

Pagina creata da Gianluca Guidi
 
CONTINUA A LEGGERE
Progettazione e Realizzazione di un Emulatore di Xerox Alto per Raspberry Pi - Dipartimento di Matematica e Informatica Corso di Laurea in Informatica
Dipartimento di Matematica e Informatica
                 Corso di Laurea in Informatica

 Progettazione e Realizzazione di un
    Emulatore di Xerox Alto per
            Raspberry Pi

Relatore:
Prof. Federico Bergenti
                                                       Candidato:
                                                 Beretta Davide
                                                 Matricola: 222565

                     Anno Accademico 2013/2014
Progettazione e Realizzazione di un Emulatore di Xerox Alto per Raspberry Pi - Dipartimento di Matematica e Informatica Corso di Laurea in Informatica
Indice

Prefazione                                                                                                         1
1 Descrizione del progetto                                                                                         3
  1.1 Xerox Alto . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 3
      1.1.1 Tastiera . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 4
      1.1.2 Mouse . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 4
      1.1.3 Display graco . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 5
      1.1.4 Disco sso/processore         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 5
      1.1.5 Software . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 5
  1.2 Salto . . . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 6
      1.2.1 Architettura di Salto .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 9
  1.3 Raspberry Pi . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 11
  1.4 Strumenti . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 13
2 Sviluppo di piAlto                                                                                              16
  2.1 Bare metal su Raspberry Pi . . .            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
  2.2 Il kernel . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   22
  2.3 Newlib . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
  2.4 Salto . . . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   29
      2.4.1 Il le salto.c . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   30
      2.4.2 Analisi e modica di Salto            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33
  2.5 CSUD . . . . . . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   43
Conclusioni                                                                                                       51
Bibliograa                                                                                                       53
Prefazione
In questo testo verrà descritto lo sviluppo di piAlto, un emulatore del
personal computer Xerox Alto pensato per funzionare su Raspberry Pi (un
mini PC ARM) in ambiente bare metal, ovvero senza sistema operativo
residente. La scelta di utilizzare il Raspberry Pi in questo modo nasce dalla
volontà di ottenere un comportamento nale del sistema il più simile
possibile a quello dello Xerox Alto in quanto si riducono i tempi di avvio e
non ci sono altri elementi che possono far capire all'utente che
eettivamente non si tratta della macchina originale.
Date le dimensioni del PC scelto infatti è possibile, reperendo l'hardware
adatto, riprodurre anche esteticamente l'aspetto dello Xerox Alto per
esempio collegando un vecchio monitor CRT girato su di un anco al
Raspberry Pi ed utilizzando un mouse ed una tastiera somiglianti a quelli
dell'epoca.
Il progetto piAlto è stato infatti concepito allo scopo di costruire una
macchina da poter collocare nel Museo del Dipartimento di Matematica e
Informatica. Nel caso non fosse possibile riprodurre in modo fedele
l'aspetto della macchina originale si potrebbe utilizzare un normale
monitor LCD ed un mouse e tastiera USB standard oppure modicare
hardware recente per farlo sembrare storico, anche se quest'ultima ipotesi
comporterebbe una quantità di lavoro non indierente.
É stato scelto proprio l'Alto a causa del numero limitato di esemplari
funzionanti al mondo, il che lo rende estremamente raro, e perché fu un
computer molto innovativo, in particolar modo dal punto di vista
dell'interazione con l'utente. Lo Xerox Alto rappresenta una importante
tappa storica dell'informatica moderna, con lo sviluppo di questo computer
infatti vennero introdotte le prime interfacce grache così come le
conosciamo oggi.
La parte del progetto che eettivamente riproduce il comportamento dello
Xerox Alto non è stata scritta da zero ma si è partiti da un emulatore
scritto in C già parzialmente funzionante scaricabile dal Web: Salto ([11]).
É un progetto che non è più attivo da tempo ma emula già sucientemente
bene le varie parti della macchina; non si tratta di un emulatore funzionale
in quanto all'interno cerca di riprodurre in modo fedele il comportamento
delle varie parti dell'Alto compreso la gestione dei task.

                                     1
INDICE

É stato quindi necessario adattare Salto in modo che potesse funzionare sul
dispositivo nale, per fare questo è stato necessario implementare la parte
di sistema che gestisce il boot del Raspberry Pi.
Dato che l'emulatore utilizza le librerie SDL per la scrittura a video è stato
poi necessario scrivere le funzioni per la gestione del framebuer che
andassero a sostituire le librerie originali.
Un altro problema è stata l'assenza delle librerie standard del C; per
evitare di riscrivere funzioni scritte ad hoc non ottimizzate sono state
utilizzate Newlib (https://sourceware.org/newlib), un set di librerie
standard per ambiente embedded.
Nel prossimo capitolo verrà descritta la macchina oggetto dell'emulazione
ovvero lo Xerox Alto, successivamente sarà più dettagliatamente spiegato il
funzionamento di Salto e le applicazioni disponibili. Verrà poi fatta una
piccola introduzione sul Raspberry Pi ed inne saranno introdotti gli
strumenti utilizzati per lo sviluppo di piAlto.
Nel capitolo 3 sarà invece descritto lo sviluppo eettivo e verrà inizialmente
spiegato quindi cosa signica sviluppare per la piattaforma utilizzata senza
sistema operativo. In seguito è presente la documentazione riguardante il
kernel sviluppato a supporto di Salto ed i problemi riscontrati nello
sviluppo. Inne si parlerà dell'integrazione del progetto con Newlib e delle
modiche apportate all'emulatore per ottenere un prodotto funzionante.
Nel capitolo 4 verranno inne tratte le conclusioni e saranno introdotti
possibili aggiustamenti e funzionalità aggiuntive per piAlto.
Occorre evidenziare che sarebbe stato estremamente dicile documentare
ogni prova fatta per cui quello che si cerca di fare in questo testo è di
presentare un riassunto riguardante lo sviluppo delle parti importanti del
progetto.

                                      2
Capitolo 1

Descrizione del progetto
In questo capitolo sarà prima presentata la storia e l'architettura dello
Xerox Alto, in seguito verrà descritto l'emulatore Salto presente in rete e le
applicazioni da questo supportate.
Verrà poi fatta una piccola introduzione sul Raspberry Pi, il dispositivo
hardware per il quale è stato sviluppato piAlto. Inne verranno presentati
gli strumenti utilizzati per lo sviluppo come il compilatore e l'emulatore.

1.1    Xerox Alto

Lo Xerox Alto fu uno dei primi computer ad essere pensati per uso
individuale, quello che noi oggi chiamiamo Personal Computer. Fu prodotto
nel 1972 da Xerox Corporation per motivi di ricerca e il suo nome deriva
dal centro dove fu sviluppato (Xerox PARC).
L'obbiettivo era quello di ottenere un dispositivo che fosse abbastanza
piccolo da poter stare in un ucio ma abbastanza potente da poter
supportare un sistema operativo stabile e di alta qualità oltre ad un display
graco. Lo Xerox Alto era concepito per provvedere a tutte le necessità
dell'utente ed in particolare per permettere agli utilizzatori di scambiarsi
informazioni facilmente. Non era pensato per la produzione di massa e il
costo era proibitivo per permetterne l'utilizzo privato, i pochi esemplari
prodotti (circa 2000) vennero utilizzati perlopiù nelle università e nei centri
di ricerca.
I progettisti dello Xerox PARC si ispirarono all'oN Line System di Douglas
Engelbart e anche se non fu mai realmente commercializzato molte idee
introdotte con l'Alto si ritrovano anche nei computer dei giorni nostri. Lo
Xerox Alto è stato ad esempio il primo computer della storia ad utilizzare
la metafora della scrivania: nacque infatti l'interfaccia graca di tipo
WIMP (Window, Icon, Menu e Pointing device), oggi la norma nella
maggior parte dei computer. Molte altre furono le innovazioni
implementate per la prima volta, come ad esempio la tecnologia Ethernet.

                                      3
1.1 Xerox Alto

A livello hardware l'Alto consiste in 4 parti principali: la tastiera, il mouse,
il display graco e il disco sso/processore. Il cabinet è metallico di color
beige, ben progettato ed il tutto era pensato per stare su di una scrivania o
un tavolo da lavoro.

                           Figura 1.1: Xerox Alto

1.1.1 Tastiera
La tastiera a prima vista è simile a quelle delle macchine da scrivere con
l'aggiunta di alcuni tasti speciali. É removibile ed abbastanza comoda per
scrivere; ha la particolarità per cui i tasti non sono codicati per cui è
presente un segnale apposito per ogni pulsante, il che permette ai
programmi di sapere facilmente se due o più tasti sono premuti
contemporaneamente.

1.1.2 Mouse
Il mouse è una piccola scatola con tre bottoni al di sopra e diverse rotelle
al di sotto, un cavo sottile lo collega all'Alto e i bottoni sono chiamati red,
yellow e blue. Il movimento viene rilevato usando le sfere presenti al di sotto
della scatola ed è riportato in modo che sia elaborato dalla macchina. Molte
applicazioni possono essere controllate esclusivamente con il mouse ed anche
in questo caso i tasti non sono codicati.

                                       4
1.1 Xerox Alto

1.1.3 Display graco
Il display è forse la parte più impressionante della macchina, le dimensioni
siche sono 8 pollici di larghezza e 10 di altezza con una risoluzione di
606x808 in bianco e nero. É di tipo bit-mapped raster scan, il che signica
che ogni punto sul display è indirizzabile come un bit in memoria ed anche
se la RAM richiesta è maggiore il rendering risulta più veloce. Questa
tecnica mette a disposizione dell'utente un metodo conveniente per
l'accesso al display e permette di controllare in ogni momento cosa viene
visualizzato.
L'Alto può gestire 60 linee di 90 caratteri ciascuna ed il rendering non è
realizzato in hardware. Un set di caratteri può essere creato dall'utente e
visualizzato ed è possibile utilizzare font di dimensioni e forme diverse
contemporaneamente. Essendo ogni punto rappresentato in memoria come
un bit non esiste la possibilità di visualizzare le varie tonalità di grigio che
però possono essere rappresentate combinando i colori nero e bianco per
formare una sorta di texture che assomigli al colore desiderato.

1.1.4 Disco sso/processore
Il processore e il disco sso sono montati in un contenitore grande circa come
un piccolo frigorifero, l'Alto dispone di due dischi ssi da 3 MB ciascuno
mentre la CPU è a 16 bit costruita su misura utilizzando circuiti integrati
TTL. Il processore può eseguire circa 400000 istruzioni per secondo e la
macchina dispone di 128 KB di RAM (espandibile no a 512 KB). Lo Xerox
Alto può eseguire no a 16 task in modo concorrente ma l'utente ha il pieno
controllo solo del proprio; essendo questo il processo a più bassa priorità
gli altri task (controllo tastiera, mouse, disco, rete) possono interromperlo
quando necessario.

1.1.5 Software
L'Alto ha la particolarità di utilizzare il software per eseguire delle
operazioni tipicamente svolte in hardware. La macchina può eseguire tutto
il software utilizzando la rete ed è presente una ROM contente un piccolo
programma che imposta la rete locale utilizzata nel caso qualche parte dei
programmi di sistema non funzioni. Il sistema operativo è scritto in BCPL
(il linguaggio da cui deriva il C) ed è chiamato Alto Operating System,
questo provvede a fornire delle semplicazioni nella comunicazione tra gli
applicativi ed il dispositivo. Uno dei programmi principali che operano
sotto il controllo dell'Alto OS è l'Executive che provvede a interfacciarsi
direttamente con l'utente permettendo l'esecuzione di altri programmi e la
manipolazione di le. Una funzionalità molto interessante dell'Executive è
l'autocompletamento dei nomi; per sfruttare questa caratteristica si scrive
parzialmente il nome di un le o di un programma e si digita un Escape, se

                                       5
1.2 Salto

l'Executive è in grado di identicare in modo univoco il le allora il suo
nome viene completato in automatico. Se invece è digitato `?' allora viene
mostrata la lista di tutti i le che possono corrispondere alla ricerca.
Le funzionalità più interessanti dell'Alto sono relative all'interfaccia utente.
Lo schermo infatti può essere diviso in nestre ed è possibile usare mouse o
tastiera per controllare le applicazioni. Per esempio si possono selezionare
voci ed elementi semplicemente premendo un tasto ed il cursore del mouse
cambia forma nel passare da una zona ad un'altra dello schermo. Sono
presenti programmi per i compiti più comuni come text editor, calcolatrice,
gestore dei le e addirittura un programma di disegno per la creazione e
manipolazione di immagini fatte di punti, curve e testo.

1.2     Salto

Salto è un emulatore dello Xerox Alto scaricabile dal Web che realizza le
principali funzioni della macchina originale cercando di emulare il più
precisamente possibile tutti i componenti della stessa.
Sfortunatamente non è perfettamente stabile e le applicazioni possono
chiudersi inaspettatamente, inoltre presenta dei problemi con il cursore del
mouse che sfarfalla in modo anomalo. Non implementa funzionalità di rete
e non si possono fare scritture permanenti di dati tuttavia è uno strumento
abbastanza completo e permette di rendersi conto sucientemente bene del
funzionamento della macchina originale. Dopo l'avvio di Salto viene
eseguito Alto Executive. Come già detto l'Executive è un interprete a riga
di comandi utilizzato per gestire i le ed eseguire i programmi. Sono
disponibili diverse versioni: Executive/7 (14/10/1976), Executive/11
(26/06/1980) e Executive/12 (8/01/1983).
    Input e output del programma sono gestiti solamente in una nestra di
16 linee e si possono usare le wildcard per riferirsi ai le e rendere più facile
l'utilizzo del sistema. Lo Xerox Alto è un ambiente monotasking dove le
applicazioni prendono il completo controllo della macchina durante
l'esecuzione.
    Siccome la risoluzione dello Xerox Alto era 606x808 e Salto apre una
nestra che ha almeno queste dimensioni (è presente anche un pannello con
alcuni pulsanti), questo richiede un monitor con una risoluzione di almeno
1280x1024 per poter visualizzare tutta la nestra. La velocità di Salto è
dipendente dalla macchina su cui lo si esegue per cui su computer più lenti
si avranno prestazioni inferiori e viceversa. Questo è dovuto al fatto che il
ciclo macchina principale è implementato utilizzando un concetto di tempo
virtuale legato all'uso di contatori che rappresentano nanosecondi.

                                       6
1.2 Salto

             Figura 1.2: Salto con Executive in attesa di input

    Saranno di seguito descritte le principali applicazioni disponibili per
Salto:
    Neptune è un le manager graco che permette di gestire drive e
cartelle utilizzando esclusivamente il mouse; altre applicazioni per Alto
invece lo utilizzano solo per puntare e richiedono poi la tastiera per iniziare
l'operazione. É presente una scrollbar per gestire la lista di voci e il cursore
cambia icona se ci si trova in quest'area. Il programma permette anche di
modicare o creare un le di testo. Esistevano diversi tipi di mouse per lo
Xerox Alto: quello più conosciuto aveva tre tasti orizzontali, ognuno di un
diverso colore e tutti i manuali fanno riferimento a questo modello in
particolare.

   Bravo è un word processor ed era il primo editor del tipo         What You
See Is What You Get. Il testo è formattato tenendo conto dei font e delle
relative dimensioni. Le modiche al documento sono visibili
immediatamente sullo schermo e, a dierenza dei moderni editor, per
abilitare l'input era necessario immettere un comando da tastiera e non
c'erano menù da poter utilizzare. La lista dei comandi disponibili era
presente sui manuali. Il mouse era prevalentemente usato per selezionare
testo e, come nel caso di Neptune, è disponibile una scrollbar sulla sinistra
dello schermo per scorrere i documenti.

                                       7
1.2 Salto

          Figura 1.3: Neptune (alla sinistra) e Bravo (alla destra)

   Draw è un programma di disegno vettoriale. Invece di trattare le
immagini come griglie di pixel queste vengono viste come un insieme di
punti connessi con le loro proprietà e si può copiare e trasformare ogni
oggetto indipendentemente. É presente un insieme di tool utilizzabili sul
lato sinistro dello schermo e si può selezionare qualsiasi strumento tramite
il mouse. Come nel caso di Bravo per utilizzare funzionalità avanzate è
necessario immettere comandi con la tastiera (vengono usate anche
combinazioni di tasti sfruttando il tasto Control) ed anche in questo caso la
lista di comandi si trova sul manuale.

    Markup è un programma di disegno i cui le immagini sono viste come
griglie di pixel. Per eettuare operazioni è possibile, a dierenza di altre
applicazioni, usare menù che vengono richiamati tramite il tasto centrale.
Su Salto questa applicazione è molto instabile.

    Laurel è un client e-mail per Xerox Alto che permette l'invio e la
ricezione di e-mail da parte di altri utenti attraverso un server
centralizzato. Questo programma non è utilizzabile in Salto in quanto le
funzionalità di rete non sono implementate; è tuttavia presente un le
e-mail di esempio. L'interfaccia graca è caratterizzata da interessanti
funzionalità: è possibile utilizzare parte del testo come pulsante
selezionabile per lanciare un comando e la toolbar si espande o meno a
seconda si faccia richiesta di informazioni aggiuntive.

                                     8
1.2 Salto

            Figura 1.4: Bravo (alla sinistra) e Laurel (alla destra)

    Sono inoltre disponibili una calcolatrice (Calculator), un programma di
utilità per la gestione dei dischi (DIEX) e diversi giochi tra cui Galaxian,
Maze, Pac-Man e Astro-roids (un clone di Asteroids).

1.2.1 Architettura di Salto
Sul Web è possibile scaricare i sorgenti oppure la versione precompilata di
Salto per Windows. Utilizzando Linux sono stati scaricati i sorgenti ed
essendo Salto scritto in C sono stati compilati utilizzando GCC
preinstallato nel sistema. Perché la compilazione vada a buon ne occorre
che siano installate almeno le librerie SDL e i relativi le di sviluppo
(tipicamente il pacchetto libsdlxx-dev, dove xx è la versione desiderata).
All'interno del progetto Salto, una volta eseguito GCC, è possibile trovare
diversi eseguibili: aar, aasm, adasm, aldump, convbdf, dumpdsk, edasm,
ppm2c, salto.
Quest'ultimo è l'emulatore vero e proprio mentre gli altri sono semplici
utilità di supporto.
Salto ore molte funzionalità al di là della semplice emulazione, permette
infatti di eettuare screenshot oltre a poter registrare la nestra per
produrre video. Permette inoltre di fare il dump della memoria su di un le

                                       9
1.2 Salto

    Figura 1.5: Draw (alla sinistra) e un clone di Galaxian (alla destra)

ed è presente anche una modalità di debug che mostra in tempo reale il
contenuto della RAM e dei registri.
L'emulatore utilizza diversi le di ROM che carica all'avvio e richiede
all'utente di specicare un'immagine del contenuto del disco. Questo
conterrà quindi dati e applicazioni da poter eseguire. Sul Web sono presenti
diversi le di questo tipo, ognuno contenente uno specico insieme di
programmi, dai giochi no alle applicazioni da ucio. Sono presenti in
tutto 48 le rappresentanti la ROM dello Xerox Alto e 9 le contenenti
applicazioni.
É possibile poi cambiare l'associazione tra i pulsanti della propria tastiera e
quella della macchina emulata semplicemente scrivendo nel le
keyboard.conf, oltre a poter metter in pausa l'emulatore in qualsiasi
momento e far procedere l'esecuzione per passi.
Dato che è possibile utilizzare come immagini del contenuto del disco anche
le compressi, Salto utilizza internamente le librerie zlib (http://zlib.net)
per la decompressione ove necessario. Durante la compilazione è possibile
poi decidere se attivare la modalità di debug, la quale prevede molto più
output testuale sulla console di sistema durante l'esecuzione, ed è anche
possibile decidere se attivare o meno il pannello presente in alto nella
nestra da dove si abilita o meno l'utilizzo del mouse e le funzioni di
registrazioni video. Sullo stesso pannello sono presenti a destra due
indicatori dell'utilizzo del disco.

                                      10
1.3 Raspberry Pi

1.3    Raspberry Pi

                         Figura 1.6: Raspberry Pi
    Il Raspberry Pi è un computer a basso costo delle dimensioni di una
carta di credito che può utilizzare monitor dotati di ingresso HDMI o RCA.
Utilizza mouse e tastiere USB standard ed è stato concepito per motivare
persone di tutte le età ad esplorare il mondo della programmazione
attraverso i linguaggi Python e Scratch. É capace di assolvere a tutte le
principali funzioni richieste ad un PC desktop anche se le prestazioni sono
comunque limitate.
Proprio per come è stato concepito il Raspberry Pi viene molto utilizzato
per progetti dove il rapporto costo-prestazioni è importante. É stato scelto
come piattaforma di sviluppo proprio per le dimensioni, il costo basso e la
essibilità nell'impiego. É un computer che è stato pensato per far
sperimentare ed imparare le persone e questo è stato un motivo in più per
utilizzarlo.
A livello software sono presenti diverse distribuzioni Linux come Raspbian
(Debian), Arch Linux, Pidora (Fedora) ed anche alcune in grado di
trasformare il dispositivo in un player audio o addirittura un media center
completo. É disponibile inoltre un porting ancora non uciale di Android.
Sono presenti in rete diversi progetti che mostrano come possa essere usato
nei modi più disparati, dal server BitTorrent alla stazione meteo no ad
arrivare al cluster di Raspberry Pi per creare un (mini) supercomputer.

                                    11
1.3 Raspberry Pi

    Le speciche tecniche sono di seguito riportate:
                     Modello A                   Modello B
       SoC         Broadcom BCM2835 (CPU + GPU + DSP + SDRAM)
      CPU             700 MHz ARM1176JZF-S core (famiglia ARM11)
      GPU         Broadcom VideoCore IV, OpenGL ES 2.0, 1080p30 H.264
      RAM             256 MB                       512 MB
   Porte USB             1                            2
  Output Video                        RCA e HDMI
  Output Audio              3,5 mm jack e audio tramite HDMI
     Memoria                             Slot SD
 Rete (Ethernet)      Nessuna             Ethernet 10/100 (RJ-45)
   Periferiche             SSPI, I C, UART, 2x13 pin di GPIO
                                  2

      RTC                              Non presente
Potenza assorbita 300 mA, (1,5 W)             700 mA, (3,5 W)
  Alimentazione            5 V tramite MicroUSB oppure GPIO
    Dimesioni                     85,60 mm × 53,98 mm

      Come è possibile notare guardando la tabella, a livello hardware sono
 presenti numerose periferiche utilizzabili. Un'altra cosa molto interessante è
 il fatto che la fase di boot è controllata dalla GPU la quale carica il rmware
 dalla scheda SD; in questo modo aggiornare il rmware non è un'operazione
 dicile o pericolosa in quanto basta sostituire pochi le sulla scheda.
 Tutte le prove sono state eettuate utilizzando un Raspberry Pi modello B in
 quanto dotato di due porte USB: una per il mouse e l'altra per la tastiera. Per
 l'alimentazione è stato usato un alimentatore dedicato a 1.25A mentre per la
 scheda è stata usata una microSD da 16Gb classe 6 con relativo adattatore.
 La macchina è stata collegata ad un Monitor TV tramite HDMI.
 Per eettuare le prove è stata prima installata Raspbian sulla scheda SD,
 in questo modo si è partiti da una congurazione funzionante. Una volta
 completata l'installazione la scheda è suddivisa in due partizioni FAT32:
 una di boot e l'altra contenente i rimanenti le di sistema. I le di avvio più
 importanti sono 4:
      ˆ bootloader.bin: il bootloader caricato nella GPU all'avvio.
    ˆ   start.elf : il rmware proprietario del SoC Broadcom.
    ˆ   kernel.img: il le contenente il kernel linux il quale viene caricato dal
        rmware all'avvio della macchina.
    ˆ   cong.txt: viene usato per congurare il PC e permette tra l'altro
        di decidere la frequenza di lavoro della CPU, quella della RAM, la
        risoluzione del monitor e molte altre cose. Utilizzando questo le e le
        informazioni presenti in [6] è stato congurato il monitor in modo da
        visualizzare correttamente la nestra di Salto.

                                        12
1.4 Strumenti

Sfruttando il meccanismo del le di congurazione è possibile togliere della
complessità al sistema operativo che non è obbligato nella fase di boot a
congurare l'intera macchina.
Per vericare il comportamento di piAlto basta sostituire al le kernel.img
originale quello generato dal processo di compilazione. Un grosso svantaggio
di questo metodo è che per sostituire il kernel occorre ogni volta estrarre
dal Raspberry la scheda SD e reinserirla una volta nito; tutto questo può
portare all'usura del lettore presente sul dispositivo.

1.4     Strumenti

Prima di iniziare lo sviluppo eettivo è stato necessario stabilire quali
strumenti software utilizzare. Invece di eettuare le compilazioni
direttamente sul dispositivo nale si è deciso di utilizzare un notebook con
installato Linux (Xubuntu 14.04) ed un cross-compilatore. In questo modo
è stato molto più semplice e veloce eettuare le prove avendo a disposizione
solamente un Raspberry Pi. Durante la prima fase dello sviluppo è stato
usato un emulatore dell'hardware nale per velocizzare ancora di più lo
sviluppo. Come cross-compilatore è stato scelto GCC perché è open source,
ben integrato in Linux ed è quello più utilizzato dalla comunità di
sviluppatori del Raspberry Pi.
Salto utilizza le librerie standard C per cui era indispensabile ottenere
anche solo un sottoinsieme di queste funzionanti per ARM bare metal. Per
risolvere questo problema sono state prese in considerazione le librerie
Newlib essendo queste open source e molto usate nel mondo embedded.
Sono stati quindi individuati dei le di esempio per vericare il
funzionamento di GCC, questi non utilizzano le librerie standard e sono
scaricabili portandosi nella cartella di destinazione usando il terminale e
digitando il comando:

git clone https://github.com/brianwiddas/pi-baremetal.git.

I sorgenti utilizzati congurano lo stack, la paginazione, gli interrupt ed il
framebuer. Una volta preparato il tutto vengono eettuate a schermo
delle stampe e viene vericato il corretto funzionamento degli interrupt.
Questi le sono stati molto utili per capire il funzionamento ed il dialogo
con la CPU e la GPU di sistema.
Facendo delle ricerche sono state scaricate e provate due versioni della
toolchain (l'insieme degli strumenti per la compilazione e l'assemblaggio dei
sorgenti) precompilate per ARM bare metal e quindi con target
arm-none-eabi . Entrambe sono state scartate in quanto il più delle volte
riuscivano a compilare gli esempi in modo corretto ma quando venivano
inserite chiamate alle librerie standard venivano restituiti errori per cui si è

                                      13
1.4 Strumenti

deciso di scaricare i sorgenti di GCC e Newlib per compilare e congurare
tutto in modo corretto. Basandosi su commenti, guide presenti in rete e
facendo prove con parametri di congurazione diversi si è poi giunti al
risultato ed inne, allo scopo di rendere il tutto il più ripetibile, si è creato
uno script che in automatico scarica tutti i componenti necessari, provvede
alle corrette congurazioni e compila il tutto ottenendo una toolchain
completa e funzionante. Partendo da una installazione di Xubuntu 14.04
prima di eseguire lo script è necessario installare i pacchetti Texinfo, m4 e
g++.
I componenti utilizzati per l'installazione sono Gnu Mpc 1.0.1, GMP 5.1.1,
GCC 4.8.0, Binutils 2.23.2, Gnu Mpfr 3.1.2 e Newlib 1.2.0.
Sullo stesso sistema Linux possono coesistere più toolchain, è suciente che
la cartella di installazione sia dierente; a questo punto occorre modicare
il le bash.rc nella home dell'utente inserendo il percorso della cartella
contenente gli eseguibili del compilatore e degli altri strumenti che si vuole
utilizzare.
Una volta ottenuta la toolchain funzionante, allo scopo eettuare più
velocemente le prove ed evitare di scrivere continuamente la scheda SD,
sono state eettuate delle ricerche per ottenere un emulatore di Raspberry
Pi funzionante. Per tutte le prove fatte in questo senso sono stati utilizzati
i le di esempio compilati con GCC.
La prima prova è stata fatta utilizzando QEMU, in particolare
qemu-system-arm presente tra i repository del sistema ospite. Come
risultato l'emulazione si bloccava in modo anomalo; questo è dovuto al
fatto che, come scoperto successivamente, QEMU non supporta ancora
direttamente il Raspberry Pi. Per la prova successiva sono stati scaricati
direttamente i sorgenti dell'emulatore e si è cercato di compilarli per
l'architettura desiderata; in questo caso è emerso in modo ancora più
evidente come QEMU non supporti l'hardware scelto in quanto
l'architettura disponibile che si avvicina di più a quella desiderata è
VersatilePCB, molto generica e non soddisfacente. Utilizzando la versione
compilata in questo modo infatti l'emulatore rimane inattivo e la nestra
principale risulta completamente nera.
Scartate queste due opzioni sono state fatte ricerche ed è stato individuato
un progetto interessante raggiungibile all'indirizzo:

https://github.com/Torlus/qemu/tree/rpi.

Questo progetto consiste in una versione di QEMU modicata che aggiunge
il supporto al Raspberry Pi; il tutto è ancora sperimentale e non fa parte
del codice sorgente uciale. Anche se è ancora in fase di sviluppo gestisce
correttamente il framebuer e le parti principali dell'ARM tuttavia non è
ancora completo il supporto per il controller USB. Per questo motivo
questo strumento è stato utilizzato solamente nella prima parte dello

                                       14
1.4 Strumenti

sviluppo di piAlto; quando è stato invece necessario implementare la parte
relativa al mouse e alla tastiera è stato utilizzato il dispositivo sico. Per la
gestione del codice sorgente del progetto è stato usato un repository SVN
privato in rete. Anche se piAlto è stato sviluppato da una singola persona
l'utilizzo di questo strumento permette di avere una sola copia di
riferimento ed evita che esistano più versioni con date dierenti che
potrebbero portare confusione. Un altro motivo per cui si è scelto di
utilizzare Subversion è la possibilità di tenere la storia dello sviluppo e di
poter ottenere le versioni precedenti in modo facile e ripetibile.

                                       15
Capitolo 2

Sviluppo di piAlto
In questo capitolo verrà prima introdotta l'architettura del SoC Broadcom
nel dettaglio e successivamente verranno descritte in modo più completo le
due parti principali di piAlto: il kernel e le modiche fatte a Salto per ottenere
un eseguibile funzionante. Verrà inoltre descritta l'integrazione del progetto
con le librerie Newlib e il driver USB.

2.1     Bare metal su Raspberry Pi

Studiando i sorgenti di esempio precedentemente citati e utilizzando la
documentazione online (wiki, esempi e manuale dell'ARM) è stato possibile
capire il funzionamento generale del Raspberry Pi.
A dierenza di altre architetture ore ben 7 modalità di funzionamento:
User, Fast Interrupt, Interrupt, Supervisor, Undened, Abort, e System
Mode. Tutte le modalità tranne quella User sono privilegiate, il che signica
che è possibile eseguire operazioni per la gestione degli interrupt,
controllare la paginazione e operare su registri tipicamente non accessibili
all'utente. Ogni modalità ha un suo stack pointer che all'avvio non è
impostato automaticamente. Al boot la CPU si trova in Supervisor Mode
per cui nel caso sia necessario lavorare sempre senza sistema operativo
residente basta rimanere in questa modalità ed impostare lo stack pointer
per poter eettuare chiamate a funzione.
Per la gestione degli interrupt l'ARMv4+ prevede la presenza di 7 vettori
in memoria a dierenza dell'architettura x86 che ne prevede 256. Non è
inoltre possibile utilizzare l'istruzione int N ma si deve usare il comando
SWI (SofWare Interrupt) in quanto è presente un solo vettore che identica
il gestore per l'interrupt software.
A dierenza dell'architettura x86 dove ogni vettore aveva un livello di
privilegio associato è stata introdotta l'idea di dierenziare le modalità di
funzionamento della CPU; quando l'istruzione SWI viene eseguita l'ARM
passa automaticamente in Supervisor Mode e, utilizzando il vettore di

                                       16
2.1 Bare metal su Raspberry Pi

indirizzi fornito dal kernel, viene individuato ed eseguito il gestore corretto.
Le rimanenti modalità sono utilizzate per gli scopi più specici:
   ˆ   System Mode: è una via di mezzo tra la modalità Supervisor e la
       User in quanto permette il livello di privilegio massimo nonostante
       condivida il set di registri della modalità User.
   ˆ   User Mode: è l'unica modalità non privilegiata ed è stata concepita
       per permettere l'esecuzione di codice utente senza il rischio di
       compromettere l'integrità del sistema operativo.
   ˆ   Abort Mode: è utilizzata nel caso ci sia un fallimento nel
       caricamento di un istruzione (Prefetch Abort) oppure di dati (Data
       Abort). In quest'ultimo caso si verica l'abort prima che l'istruzione
       alteri lo stato del sistema.
   ˆ   Fast Interrupt Mode (FIQ Mode): è usata per gestire gli interrupt
       che necessitano di velocità elevate e ha un set di registri diverso dalla
       IRQ Mode. Gli interrupt gestiti tramite FIQ hanno priorità maggiore
       rispetto a quelli più lenti e possono interrompere questi ultimi se
       necessario.
   ˆ   Interrupt Mode (IRQ Mode): l'altra modalità lecita per la gestione
       degli interrupt, in particolare tutti quelli che non richiedono velocità
       elevate usano questa modalità.
   ˆ   Undened Mode: è usata per gestire l'esecuzione di istruzioni non
       denite.
    Come già accennato il boot del Raspberry Pi è gestito dalla GPU che
carica il rmware e successivamente il le kernel.img all'indirizzo 0x8000. A
questo punto la GPU passa il controllo dell'esecuzione al le appena caricato
che deve preoccuparsi di portare il sistema ad uno stato consistente prima
di poter eettuare altre operazioni.
La prima operazione da fare all'avvio è impostare quindi lo stack pointer;
dato che lo stack cresce in memoria verso il basso è comodo tenerlo al di
sotto del punto in cui è stato caricato il kernel; subito dopo si può procedere
alla congurazione della memoria, del framebuer e degli interrupt.

Gestione della memoria
La gestione della memoria a un livello così basso di astrazione richiede di
tenere in considerazione sia gli indirizzi sici che quelli virtuali. Sfogliando
il manuale di riferimento del SoC utilizzato si può vedere come i primi
siano organizzati in due parti: la memoria di sistema e quella dedicata alle
periferiche. La prima parte è denita dall'indirizzo 0 no a 256MB o
512MB di RAM a seconda del modello del Raspberry Pi utilizzato. La

                                       17
2.1 Bare metal su Raspberry Pi

memoria dedicata alle periferiche invece è posizionata al di sopra in un'area
non sicamente utilizzabile dal sistema operativo. In questa zona è
possibile accedere ai registri di controllo per le periferiche ed quindi
comunicare con queste. Per esempio si possono usare i registri per
impostare un timer, controllare i LED presenti sul PC o altro ancora.
Durante la prima parte dello sviluppo si è pensato di utilizzare un prolo
della memoria di tipo at dove l'indirizzo virtuale è uguale a quello sico e
senza utilizzare la paginazione, per fare questo semplicemente non veniva
abilitata l'MMU di sistema.
L'idea di fondo era che senza l'utilizzo della paginazione si avrebbe avuto
un guadagno di prestazioni dovuto al fatto che non era necessario sprecare
accessi alla memoria per via delle traduzioni necessarie. Probabilmente
questa convinzione avrebbe portato al risultato sperato su architettura x86
ma non lavorando con ARM. Su questa architettura infatti il
funzionamento dell'MMU è un requisito fondamentale per l'abilitazione
della cache di sistema. L'utilizzo della cache può incidere in modo pesante
sulle prestazioni complessive della macchina in modo particolare quando si
eettuano numerosi accessi in modo continuo a dati globali o statici per i
quali non vale il meccanismo dello stack.
Una soluzione semplice a questo problema è abilitare la paginazione e
applicare l'identity paging ovvero fare in modo che l'indirizzo sico e quello
virtuale siano lo stesso; in questo modo l'inizializzazione è semplice e
trasparente alle altre parti del programma. La paginazione può essere ad un
livello o a due, in base alla nezza che si vuole ottenere nella mappatura.
Possono per esempio essere utilizzate pagine rappresentanti 4096 byte ma
anche di 1MB (dette sezioni ). Possono essere impostate pagine che
rappresentano addirittura 16MB di RAM e vengono dette super section.
Si è scelto di utilizzare pagine di 1MB perché dovendo semplicemente fare
identity paging non era necessario utilizzarne di dimensioni più piccole. Per
abilitare l'MMU è quindi necessaria una sola tabella con 4096 voci, questo
perché lo spazio di indirizzamento su architettura a 32 bit è 4 GB (una
voce per ogni MB di memoria).
La tabella deve essere allineata alla parola cioè ad un multiplo di 4 byte e
sono presenti diversi registri appositamente predisposti per congurare la
paginazione.
Nel caso si utilizzino pagine di 1MB la voce corrispondente in tabella è di 4
byte di cui i 20 bit più signicativi identicano l'inizio dell'area di memoria
da associare all'indirizzo virtuale. Gli altri bit identicano le proprietà
denite per quella zona di RAM. I bit particolarmente importanti sono
10:11 (AP), 2 (B) e 3 (C); i primi servono per impostare i permessi di
lettura/scrittura per la sezione mentre i bit C e B indicano se per la pagina
deve essere abilitata la cache o se questa debba essere messa in un buer. I
bit di AP sono stati impostati a 1 entrambi per tutte le pagine per poterle
sia leggere che scrivere.

                                      18
2.1 Bare metal su Raspberry Pi

La procedura di inizializzazione consiste quindi nel costruire la tabella di
4096 voci impostando le proprietà per tutte le sezioni. Si può decidere
quindi la politica di caching per la sezione utilizzando i bit C e B oltre a
12:14 (TEX). Per esempio impostando TEX = b000 e CB = b10 la pagina
è trattata come memoria normale con cache abilitata mentre impostando
TEX = b000 e CB = b01 la zona di memoria associata viene considerata
dedicata a periferiche condivise per la quale è quindi disabilitato il caching.
Sfruttando questo meccanismo è quindi possibile ottenere aree di RAM
disponibili per eventuali buer utili alla comunicazione con le periferiche
(come il controller USB) le quali, anché il trasferimento di informazioni
vada a buon ne, necessitano appunto che la cache non sia usata.
Subito dopo aver creato e riempito la tabella vengono modicati due
registri di controllo (System Control Register e Auxiliary Control Register )
per assicurare che i campi TEX e AP siano strutturati secondo quanto
detto nora. Occorre poi impostare un registro di controllo che contiene
l'indirizzo della tabella e invalidare il contenuto della cache perchè non
possa essere utilizzata in seguito. Viene inne scritto nuovamente il System
Control Register per abilitare la data cache, l'instruction cache e il program
ow prediction oltre all'MMU stessa.
Una volta terminata la procedura di inizializzazione sono quindi abilitate
tutte le ottimizzazioni principali disponibili ed il tutto risulta trasparente
alle altre parti del programma.

Il framebuer
Il framebuer può essere visto semplicemente come una matrice di pixel le
cui dimensioni variano in base alla risoluzione selezionata, ogni pixel
occupa una quantità di memoria che dipende dal bpp (bit per pixel ). Nel
caso si utilizzino 32 bpp si ha che ogni pixel occupa una zona di memoria di
4 byte; per colorare il pixel sullo schermo basta scrivere il valore associato
al colore utilizzando un opportuna codica dipendente dal bpp.
Per congurare il framebuer occorre comunicare con la GPU tramite il
meccanismo delle mailbox ([7]) il quale permette una comunicazione di tipo
request-response tra il programma e il VideoCore (GPU di sistema).
Utilizzando questa interfaccia è possibile non solo impostare il framebuer
ma anche ottenere informazioni importanti come dimensione della memoria
RAM usabile per il sistema o dedicata alla GPU, controllare l'overclocking
e molto altro.
La comunicazione avviene fornendo un buer che contiene le richieste
(ognuna identicata da un tag) e gli argomenti specici per quella richiesta;
è quindi possibile, tramite questo meccanismo, eettuare request multiple
con un unico trasferimento di informazioni.
É implementato il meccanismo dei canali: ne esistono 16 ed ognuno deve
essere utilizzato per realizzare un tipo di comunicazione. In particolare i

                                      19
2.1 Bare metal su Raspberry Pi

canali 8 e 9 vengono usati rispettivamente per la comunicazione tra ARM e
VideoCore e viceversa.
Lo scambio di dati deve avvenire rispettando le seguenti regole:
   ˆ La risposta sovrascrive la richiesta.

   ˆ Il buer usato per la comunicazione deve essere allineato a 16 byte in
     quanto solo i 28 bit più signicativi sono trasmessi mentre i rimanenti
     4 bit identicano il canale.
   ˆ I tag sconosciuti vengono ignorati.

   ˆ La risposta può contenere tag non richiesti.

   ˆ La lunghezza del tag di risposta può essere più lunga di quanto ci si
     aspetti in quanto informazioni aggiuntive potranno essere fornite in
     futuro.
   ˆ Tutti i valori senza segno a 16/32/64 bit sono ordinati in base
     all'architettura ospite (little o big endian).
   ˆ I tag devono essere processati in ordine ad eccezione del caso in cui
     l'interfaccia richieda tag multipli per una singola operazione.
    Per iniziare la comunicazione occorre quindi allocare il buer e
formattare la richiesta al suo interno tenendo conto delle regole appena
citate. Di seguito verrà presentato come il contenuto del buer deve essere
organizzato, indicando con il presso u e s un intero rispettivamente senza
segno e con segno.
   ˆ u32: dimensione del buer in byte includendo header, tag nale e
     padding
   ˆ u32: codice della richiesta/risposta

     Richiesta
          0x00000000: richiesta da processare
          Tutti gli altri valori sono riservati

     Risposta
          0x80000000: richiesta completata con successo
          0x80000001: errore nel parsing della richiesta
          Tutti gli altri valori sono riservati

   ˆ u8: sequenza di tag concatenati

                                      20
2.1 Bare metal su Raspberry Pi

   ˆ ...
   ˆ u32: 0 (tag nale)
   ˆ u8: padding
   ˆ ...
   Ogni tag è invece organizzato internamente in questo modo:
   ˆ u32: identicatore del tag
   ˆ u32: dimensione del buer del value buer in byte
   ˆ u32: 1 bit (MSB) che indica una richiesta (0) oppure una risposta (1)
     e i rimanenti 31 bit rappresentano la lunghezza del valore
   ˆ u8: sequenza di byte che rappresentano il value buer
   ˆ ...
   Il value buer deve essere allineato a 32 bit per cui viene aggiunto del
padding alla ne quando necessario.

Gestione degli interrupt
All'avvio gli interrupt sono disabilitati e prima di poterli abilitare occorre
fornire gli opportuni gestori. Questi non sono altro che funzioni le quali
vengono chiamate quando l'interruzione è intercettata.
Come già detto esistono 7 tipi di interrupt e sono: Reset, Data Abort, FIQ,
IRQ, Prefetch Abort, SWI, Undened Istruction. Il primo avviene nel caso
di reset del core ARM; Data Abort e Prefetch Abort servono per gestire le
analoghe situazioni precedentemente descritte mentre FIQ e IRQ gestiscono
gli interrupt hardware veloci e non rispettivamente. Inne SWI viene
utilizzato per gestire le interruzioni software e Undened Instruction, come
suggerisce il nome, tratta l'esecuzione di istruzioni non riconosciute. Per
poter impostare i gestori richiesti esiste un apposito registro ed occorre
utilizzare il coprocessore CP15 il quale si occupa di controllare e fornire
informazioni di status per le funzioni del processore ARM. Il coprocessore
dispone di diversi registri, in particolare il registro Vector Base Address
Register permette di impostare l'indirizzo del vettore contenente gli
indirizzi dei gestori. É possibile usare un'unica istruzione assembly per
eettuare quanto detto:
asm volatile ( " mcr p15 , 0 , %[ addr ] , c12 , c0 , 0 " : : [ addr ] " r "
    (& interrupt_vectors ) ) ;

dove addr è l'indirizzo del vettore. Per abilitare gli interrupt invece basta
utilizzare l'istruzione apposita cpsid:
asm volatile ( " cpsid i " ) ;

                                      21
2.2 Il kernel

2.2     Il kernel

Il piccolo kernel sviluppato per supportare Salto è composto da solamente
da 12 le: 1 le assembly e 10 le C, oltre ad un ulteriore le C che permette
l'integrazione con le librerie Newlib. Sono stati creati poi un linker script
e un Makele ; il primo è necessario per indicare al linker come deve essere
assemblato l'eseguibile mentre il secondo è utile per rendere automatica e
veloce la compilazione del progetto. Saranno in seguito descritti in dettaglio
tutti questi le allo scopo di spiegarne lo scopo e come questi interagiscano.

linkscript
Un eseguibile è composto tipicamente da varie parti, in particolare le più
comuni sono data, bss, rodata e text. La sezione data contiene tutti i dati
inizializzati, rodata i dati costanti, text il codice eseguibile e bss tutti i dati
non inizializzati. Questi ultimi sono tipicamente tutti i dati globali o statici
che, in caso sia presente un sistema ospite, vengono sempre inizializzati in
automatico a 0. Nel caso si programmi senza sistema operativo residente
questo non avviene e deve essere fatto manualmente. Questo le serve per
comunicare al linker come devono essere disposte le varie parti
dell'eseguibile in memoria, in particolare kernel.elf (con cui vine creato
kernel.img) deve essere caricato all'indirizzo 0x8000.
Le sezioni vengono caricate in ordine ed allineate a 4096 byte (dimensione
tipica di una pagina) e l'ordine scelto è text, data, rodata e bss. Nel le
vengono dichiarati dei simboli preceduti da `_', questi sono visibili dai le
sorgente e sono utili per ricavare gli indirizzi di inizio e ne delle varie
sezioni. Per esempio se si vuole stabilire dove la memoria utilizzata nisce
basta leggere il valore di _bssend che indica appunto la ne della sezione
bss cioè l'ultima presente in RAM.

Makele
Per eettuare la compilazione e l'assemblaggio dell'eseguibile si è sin
dall'inizio utilizzato il comando make ed un makele. Questo però era
molto semplice ed ogni volta che veniva usato tutti i le oggetto venivano
cancellati ed il progetto era ricompilato completamente.
Con il crescere delle dimensioni del codice sorgente è diventato necessario
riscrivere questo le da zero in modo da ottenere che solamente i le
modicati vengano ricompilati accorciando i tempi necessari per lo
sviluppo ed i test.

                                        22
2.2 Il kernel

start.s
Questo le è l'unico scritto completamente in assembly e si occupa solamente
di impostare lo stack pointer e abilitare la FPU per poi passare il controllo
dell'esecuzione alle funzioni di inizializzazione scritte in C.
Viene denito il simbolo globale _start che è utilizzato dal linker in fase
di assemblaggio dell'eseguibile, in questo modo si indica che quel punto è
l'inizio della sezione contenente il codice eseguibile e le istruzioni successive
dovranno essere le prime ad essere eseguite una volta avviato il dispositivo.
É stato necessario abilitare la FPU in quanto sono stati riscontrati problemi
con la funzione printf(), questa al suo interno fa uso di tipi oating point
per cui se la FPU è disabilitata e si cerca di utilizzare la funzione quello che
si ottiene è il blocco del programma.

libgcc.a
Il SoC Broadcom utilizzato ha la particolarità di non implementare le
operazioni di divisione e modulo tra interi in hardware, queste operazioni
devono essere riprodotte tramite software.
GGC fornisce la libreria di basso livello libgcc.a per alcune piattaforme e
genera le chiamate alle funzioni in questa libreria durante la compilazione
per sostituire quelle operazioni troppo complicate da implementare con
funzioni inline.
Oltre ad implementare divisione e modulo tra interi per alcune piattaforme
vengono fornite tutte le operazioni tra oating point e xed point oltre a
routine per la gestione delle eccezioni e molto altro. La maggior parte delle
funzionalità sono implementate in codice C indipendente dalla macchina
mentre una parte deve essere scritta in assembly quando l'architettura di
destinazione lo richiede.

divby0.c
Il le contiene un'unica funzione chiamata raise() la quale viene chiamata
ogni volta che viene eettuata una divisione per 0. Quello che si è scelto
di fare per gestire questa situazione è semplicemente segnalare il problema
tramite delle stampe opportune e bloccare la macchina tramite un ciclo.

initsys.c
Questo sorgente C contiene le prime due funzioni di inizializzazione del
dispositivo: la prima, chiamata get_info(), utilizza il meccanismo delle
mailbox per ottenere informazioni come la quantità di RAM destinata alla
CPU e quella invece riservata al VideoCore. Queste informazioni sono utili
per poter impostare la quantità massima di heap utilizzabile dal sistema.
La parte di RAM compresa tra la ne della sezione bss dell'eseguibile e la

                                       23
2.2 Il kernel

ne della RAM riservata alla CPU ARM è infatti utilizzabile come stack
oppure come heap e, dato che si è deciso di sistemare lo stack al di sotto
del sistema in memoria, questa zona si può considerare totalmente
utilizzabile per allocazione dinamica. L'altra funzione di inizializzazione è
initsys() la quale viene chiamata alla ne del le start.s ; questa
semplicemente si occupa di preservare gli argomenti passati dalla CPU nei
registri r0, r1, r2 (utilizzati in seguito), inizializzare la sezione bss con 0
utilizzando i simboli preparati dal linker e chiamare get_info(). In seguito
il controllo viene dato ad un'altra funzione di nome kmain().

led.c
Contiene alcune funzioni per l'inizializzazione ed il controllo dei LED presenti
su Raspberry Pi. Questo le originariamente faceva parte degli esempi C di
partenza e non è stato modicato. Anche se non è utilizzato in piAlto è stato
mantenuto nel caso in futuro sia necessario l'output tramite i LED presenti
sul dispositivo.

atags.c
La CPU ARM all'avvio prepara una serie di informazioni in memoria per il
sistema operativo se queste vengono richieste (per disabilitare questa
funzionalità occorre modicare il le cong.txt ). Queste informazioni sono
organizzate tramite tag e sono dette ATAGS (ARM TAGS). Il le atags.c
contiene una serie di funzioni utilizzate allo scopo di stampare le
informazioni a video; questo le faceva parte degli esempi di partenza e è
stato mantenuto per permettere in caso di bisogno di ricavare le
informazioni necessarie. Tramite queste funzioni è infatti possibile capire
come sono strutturati gli ATAGS in memoria e come accedervi.

textutils.c
Contiene solamente due funzioni: tohex() e todec(). La prima converte un
intero senza segno in una stringa che è la sua rappresentazione in esadecimale
mentre la seconda eettua la stessa cosa con la dierenza che la stringa
generata è la rappresentazione in decimale dell'intero. Queste due funzioni
venivano utilizzate negli esempi per eettuare stampe di interi e sono state
quasi ovunque sostituite tramite printf(). Vengono ancora usate solamente
quando non è possibile utilizzare le funzioni delle librerie standard ovvero
nelle system call.

interrupts.c
In questo le sono deniti i gestori per i 7 tipi di interrupt e una piccola
funzione di inizializzazione. In particolare esistono i gestori per gli interrupt

                                       24
2.2 Il kernel

di Abort (Data e Prefetch) che visualizzano stampe di debug e non
ripristinano la macchina. É presente un gestore per gli IRQ ma, non essedo
questo utile per piAlto, non fa nulla di rilevante e uno simile per gli
interrupt software (SWI). Tutti gli altri tipi di interrupt vengono gestiti
come situazione anomala da un'unica funzione che, in caso venga chiamata,
blocca il Raspberry Pi.

mailbox.c
Contiene due funzioni per leggere e scrivere le mailbox usando dei registri
appositi mappati in RAM. Normalmente tali registri hanno indirizzi
0x2000B880, 0x2000B898 e 0x2000B8A0. Il primo viene utilizzato per
leggere la mailbox, il secondo per scriverla ed il terzo per vericarne lo
stato. É importante sottolineare che se viene abilitata la cache di sistema
utilizzando questi registri possono sorgere problemi. Lo spazio di
indirizzamento del Raspberry è stato diviso in 4 parti e in ogni zona è
mappata la stessa memoria, cambia solo la modalità di accesso. É possibile
quindi accedere agli stessi registri senza che la cache venga utilizzata
semplicemente usando indirizzi diversi (utilizzando quindi i registri
0xE000B880, 0xE000B898 e 0xE000B8A0).

framebuer.c
Prima di poter visualizzare oggetti e testo sullo schermo occorre impostare
la risoluzione e la nestra di lavoro. Tutto questo è gestito da due funzioni:
fb_init() e fb_setup(). La prima si occupa di impostare la risoluzione
ottimale che, in caso l'esecuzione sia eettuata per mezzo dell'emulatore è
di 640x480 (il massimo possibile su QEMU al momento) mentre
normalmente viene scelta 800x600 in quanto, abilitando la rotazione dello
schermo a 90 gradi, è molto simile a quella originale dello Xerox Alto
(606x808). Una volta impostata la risoluzione tramite mailbox si
memorizzano tutte le informazioni relative allo schermo (pitch, bpp,
indirizzo sico e dimensione del framebuer).
La funzione fb_setup() si occupa di restringere lo spazio disponibile sullo
schermo a dimensioni pressate in modo che siano gestiti correttamente i
casi in cui la risoluzione dello Xerox Alto sia diversa da quella oerta dal
monitor usato. Per esempio se si decide di usare un monitor con una
risoluzione di 1024x768 viene creata una nestra di dimensioni 606x768
centrata in larghezza e solo all'interno di questa nestra sarà possibile la
visualizzazione. Tutto il software di gestione del video è stato pensato in
questo modo per cui usando qualsiasi delle funzioni grache presenti il
comportamento deve essere coerente a quanto detto.
Si è pensato di implementare anche la rotazione dello schermo tramite
software; è possibile abilitarla prima della compilazione agendo su di un

                                     25
2.2 Il kernel

ag globale. Si è scoperto in seguito che questa funzionalità è implementata
anche in hardware dal Raspberry Pi ed è attivabile modicando il le
cong.txt ma, nonostante questo, si è deciso di lasciare il codice di gestione
della rotazione per completezza. Una volta completata la congurazione
dello schermo la nestra viene riempita con il colore di sfondo di default
(bianco).

graphics.c
Il servizio principale che il kernel deve fornire a Salto oltre a inizializzare
correttamente il Raspberry Pi è l'output a video. Sono state sviluppate
diverse funzioni per implementare le operazioni più basilari anche se molte
di queste non sono direttamente utilizzate da Salto ma sono state inserite
per permettere la stampa di testo da parte del kernel o per rendere il lavoro
più completo. La funzione di base è quella per colorare un pixel, usando
questa è stata implementata la stampa di un carattere. Sfruttando
quest'ultima sono state implementate due funzioni per la stampa di testo,
una permette la visualizzazione in un punto qualsiasi della nestra mentre
l'altra implementa il comportamento classico di una shell di sistema per cui
è gestito il newline, lo scroll e la posizione del testo è calcolata in modo
automatico. Sono state inoltre implementate diverse utilità per cambiare il
colore di sfondo o del carattere, per riempire la nestra di un colore o per
impostare la console in modalità debug. Questa è abilitata prima dell'avvio
di Salto e utilizza solo l'ultima riga disponibile nella nestra per la stampa
di informazioni di debug durante l'esecuzione dell'emulatore. In questo
modo è possibile usare Salto e visualizzare anche informazioni utili che
normalmente sarebbero mostrate sulla shell dal quale l'eseguibile è stato
lanciato.
La funzione maggiormente utilizzata da Salto durante l'esecuzione è
fb_write(), la quale è implementata usando put_pixel() e non fa altro che
visualizzare un array di 16 pixel contigui sulla nestra. Il fatto che molte
funzioni siano state scritte usandone altre più semplici rende il tutto molto
più essibile.

main.c
Questo è il le principale del kernel, al suo interno sono presenti 4 funzioni:
print_info(), MMU_init(), test(), kmain(). Prima di lanciare Salto deve
avvenire l'ultima parte di inizializzazione del Raspberry Pi. Questa è
implementata da kmain() che si occupa di inizializzare interrupt e
framebuer tramite le funzioni descritte precedentemente. Viene inoltre
inizializzato il driver USB, abilitata e congurata la MMU (usando la
funzione MMU_init()) e vengono stampate informazioni utili all'avvio. La
routine kmain() utilizza i registri r0, r1 e r2 ; questi sono stati preservati

                                      26
Puoi anche leggere