1. L'architettura di Von Neumann
• Architettura di riferimento dei moderni
calcolatori digitali (anni '40)
• Descrive un calcolatore general purpose
di tipo “stored program”
– Dati e programmi ospitati nella stessa
memoria (principale)
– Un processore esegue programmi che
elaborano dati
– Dispositivi I/O
• Implementazione di una macchina di
Turing universale
1
2. L'architettura di Von Neumann
Memoria
principale
Unità
Unità di
aritmetico
controllo
logica
Accumulatore
Input Output
2
3. Limiti dell'architettura di base
• Un solo dispositivo di ingresso-uscita
• Un solo registro (accumulatore)
• Componenti con velocità molto differenti
– necessità di sincronizzare la
comunicazione
• Collo di bottiglia di Von Neumann:
– la velocità di comunicazione
CPU/memoria è il fattore limitante
3
4. Estensioni del modello di
Von Neumann
• Utilizzo di bus per il collegamento e la
comunicazione efficiente di molteplici
periferiche
• Utilizzo di processori con caratteristiche
migliori
• Trasferimento dati asincrono
– Interruzioni
– Direct Memory Access (DMA)
4
5. BUS
• Sottosistema deputato a trasferire dati
fra unità periferiche
• Compiti:
– Fornire collegamenti di comunicazione
fra periferiche e memoria/CPU
– Arbitrare l'accesso ai collegamenti di
comunicazione
5
6. BUS
• Molteplici linee di comunicazione
– Address bus: trasporta gli indirizzi di
accesso alla memoria
– Data bus: trasporta I dati dalla/alla memoria
– Control bus: trasporta segnali di controllo
• Master (active) device: può iniziare azioni di
trasferimento
• Slave (passive) device: ascolta le richieste
– Comando: CPU master, disk slave
– Trasferimento dati: disk master, memoria
slave
• La memoria non può mai essere master!
6
7. Architettura con BUS
Address bus
Data bus Memoria
CPU
principale
Control bus
Unità I/O Unità I/O
7
8. BUS sincrono: lettura
CLK
ADDR A1
DATA
RD/WR
ENABLE
1. La CPU (master) scrive l'indirizzo
di memoria sulla linea ADDR
8
10. BUS sincrono: lettura
CLK
ADDR A1
DATA
RD/WR
ENABLE
3. La CPU aspetta un ciclo
1-0-1 su ENABLE prima di leggere DATA
10
11. BUS sincrono: lettura
CLK
ADDR A1
D1
DATA
RD/WR
ENABLE
4. Nel frattempo, la memoria (slave) riconosce
il suo indirizzo in ADDR e scrive il valore su
DATA 11
13. Tipologie di BUS comuni (IBM PC)
• Seriali (USB, SATA), paralleli (ATA, SCSI)
• Sincroni, asincroni
• Di sistema (processor-memory)
– Front-side bus
• Di I/O (periferica-memoria):
– ISA, EISA, PCI, PCI-Express, USB, Firewire,
AGP
• Bridge (interconnessione bus diversi)
• Backside (processore-cache L2)
Le periferiche si collegano ad un canale del bus!
13
14. Unità periferiche
• Controllore: è un circuito elettronico
responsabile del trasferimento dati
periferica-buffer locale
– gestione di un buffer di memoria locale
– gestione di un insieme di registri
speciali
♦registri di stato
♦registri di comando
• Periferica = Controllore + attuatore
(meccanico, ottico, elettromagnetico)
14
19. Il processore (Intel): registri
• Presenza di svariati registri (16, 32, 64 bit)
• Registri general purpose:
– EAX, EBX, ECX, EDX
• Instruction pointer:
– EIP
• Stack pointer:
– ESP, EBP
• Stato (overflow, segno, riporto):
– EFLAGS
19
20. Il processore (Intel): memoria
• Uso di svariate cache velocissime (L1, L2) per
ridurre l'effetto del collo di bottiglia di Von
Neumann
– memorie associative: TLB
• Due modelli di memoria possibili:
– Flat model ( un solo unico grande blocco)
– Segmentato (ciascun processo ha a
disposizione un proprio blocco di memoria)
• Modalità di indirizzamento:
– Registro (mov eax, ecx)
– Immediato (mov eax, 26)
– Registro diretto (mov eax, [esp])
– Spiazzamento (mov eax, [esp + 4])
20
21. Il processore (Intel): istruzioni
• Modello set istruzioni
– CISC: poche istruzioni, complesse
– RISC: molte istruzioni, semplici
• Flusso istruzioni superscalare:
– due pipeline a cinque stadi (Pentium)
♦ 1 generica, l'altra per op. su interi
– Fetch: prelievo opcode istruzione
– Decode: decodifica istruzione
– Operand fetch: prelievo operando
– Instruction execution: esecuzione istruzione
– Write back: scrittura del risultato
21
22. Il processore (Intel): parallelismo
• Hyperthreading:
– una copia della circuiteria per l'esecuzione
delle istruzioni
– più copie dei registri general purpose e di
controllo
– esecuzione simultanea di codice su dati
diversi
• Multi-core:
– presenza di più miniprocessori con cache L1
(detti core)
– unica cache L2 condivisa fra i vari core
22
24. Il processore (Intel): Pentium
Il processore
Lo schema architetturale
La ventola di raffreddamento
(CPU fan) 24
25. Meccanismi trasferimento dati
• Sistemi time-sharing e multiprogrammati
• Meccanismi per la sovrapposizione di:
– operazioni CPU
– operazioni I/O
• Meccanismi sofisticati di trasferimento
dati:
– basati su interruzioni
– basati su DMA
25
26. Trasferimento dati nei vecchi sistemi
• Trasferimento dati controllato da CPU
• Nessuna sovrapposizione CPU – I/O
Esempio: stampa dati dalla memoria
1.Controlla se stampante è pronta a ricevere il
carattere successivo
2.Se non è pronta, torna al passo 1.
3.Se è pronta, controlla se è necessario
stampare un altro carattere
4.Se c'è un altro carattere, torna al passo 1.
5.Se non ci sono altri caratteri->FINE
26
27. Trasferimento dati nei vecchi sistemi
• Busy waiting:
– la CPU controlla costatemente lo stato
relativo all'I/O, mantenendosi attiva
– Conseguentemente, la CPU non può
intraprendere alcuna altra operazione
– spreco di potenza di calcolo
– Soluzione: sistema di I/O basato sulle
interruzioni
27
28. Trasferimento dati basato su
interruzioni
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
Controllore di memoria
memoria
28
29. Trasferimento dati basato su
interruzioni: esempio
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
1. La CPU carica i registri di comando
Controllore di memoria
idonei all'interno del controllore e
continua l'esecuzione normale del
programma. memoria
29
30. Trasferimento dati basato su
interruzioni: esempio
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
?
Controllore di memoria
2. Il controllore esamina il contenuto dei
registri di comando per decidere l'opera-
zione da intraprendere (ad es., read).
memoria
30
31. Trasferimento dati basato su
interruzioni: esempio
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
Controllore di memoria
3. Il controllore pilota il trasferimento dei
dati dalla periferica opportuna al buffer
di dati locale.
memoria
31
32. Trasferimento dati basato su
interruzioni: esempio
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
Controllore di memoria
4. La periferica trasferisce i dati verso
il buffer locale nel controllore.
memoria
32
33. Trasferimento dati basato su
interruzioni: esempio
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
Controllore di memoria
5. Al termine del trasferimento, il
controllore segnala la presenza dei
dati tramite una interruzione.
memoria
33
34. Trasferimento dati basato su
interruzioni: esempio
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
6. La CPU interrompe ciò di memoria
Controllore che stava
facendo e trasferisce il controllo ad una
locazione fissa: procedura di servizio
della interruzione. memoria
34
35. Trasferimento dati basato su
interruzioni: esempio
7. La procedura di servizio dell'interruzione
trasferisce i dati dal buffer locale del
controllore alla memoria principale.
controllore controllore controllore
CPU unità di lettore unità
dischi schede nastri
Controllore di memoria
memoria
35
36. Trasferimento dati basato su
interruzioni: esempio
7. Terminato il trasferimento dati in
memoria, la CPU riprende i calcoli
interrotti. controllore
controllore controllore
CPU unità di lettore unità
dischi schede nastri
Controllore di memoria
memoria
36
37. Vettore delle interruzioni
• Una procedura di gestione per ciascuna
classe di controllori
• Dove sono memorizzati gli indirizzi delle
procedure di controllo?
• Vettore delle interruzioni: vettore degli
indirizzi delle procedure di controllo
– indicizzato da:
♦ un numero di dispositivo
♦ un identificatore della linea di interruzione
(IRQ)
– memorizzato nelle prime locazioni di
memoria
37
38. Nesting delle interruzioni
• Nei primi sistemi basati su interruzioni, durante la
gestione di una interruzione le altre interruzioni
vengono disabilitate
– evitare che più interrupt identiche possano operare
sugli stessi dati
• Le architetture più sofisticate permettono l'esecuzione
annidata (nesting) delle interruzioni
– assegnazione di priorità alle diverse interruzioni
– interruzioni di priorità superiore vengono servite
prima, anche in presenza di una interruzione di
priorità inferiore
– in quest'ultimo caso, vengono disabilitate tutte le
interruzioni di priorità inferiore a quella in
esecuzione
38
39. Eccezioni
• Eccezione: interruzione generata dal
software condizioni anomale
– divisione per zero
– accesso alla memoria non valido
• Trap: procedura di servizio associata ad
una eccezione
39
40. Salvataggio degli indirizzi di ritorno
• Poichè l'esecuzione di codice può essere
interrotta in maniera asincrona, è
necessario salvare l'indirizzo di ritorno
• Indirizzo di ritorno: indirizzo successivo
all'ultima istruzione eseguita prima della
interruzione
40
41. Salvataggio degli indirizzi di ritorno
• Indirizzo di ritorno memorizzato su una
pila (stack, ESP) di sistema
• Lo stack contiene una sequenza di stack
frame (EBP)
– indirizzo di ritorno, valore di alcuni registri
della CPU, parametri di ingresso e di uscita
• Al termine della procedura di servizio
della interruzione:
– valore dei registri CPU viene ripristinato
– esecuzione riprende da indirizzo di ritorno
41
42. Uso dello stack: un esempio
• Si supponga di avere un programma che
esegue la funzione DrawSquare(), che a sua
volta esegue la funzione DrawLine()
void DrawLine( ... ) {
...
}
void DrawSquare( ... ) {
DrawLine(...);
}
int main() {
DrawSquare( ... );
}
42
43. Uso dello stack: un esempio
• Quando DrawSquare() è in esecuzione (prima di
invocare DrawLine()), lo stack delle chiamate si
presenta nel modo seguente:
Stack pointer
Var. locali
DrawSquare()
Stack frame
DrawSquare() Frame pointer
Ind. Ritorno
Parametri
DrawSquare()
43
44. Uso dello stack: un esempio
• Quando DrawLine() è in esecuzione, lo stack delle
chiamate si presenta nel modo seguente:
Stack pointer
Var. locali
Stack frame DrawLine()
DrawLine()
Frame pointer
Ind. Ritorno
Parametri
DrawLine()
Var. locali
DrawSquare()
Stack frame
DrawSquare()
Ind. Ritorno
Parametri
DrawSquare()
44
45. Uso dello stack: un esempio
• Quando DrawSquare() ritorna in esecuzione (dopo la
chiamata a DrawLine()), lo stack delle chiamate si
presenta nel modo seguente:
Stack pointer
Var. locali
DrawSquare()
Stack frame
DrawSquare() Frame pointer
Ind. Ritorno
Parametri
DrawSquare()
45
46. Uso dello stack sull'INTEL
• Si prenda il sorgente prova.c allegato
– lo si compili: gcc -o prova prova.c
– Si generi l'assembly: gcc -S prova.c
• In alternativa, si disassembli prova:
– objdump –disassemble prova
(comprende gli stub della glibc)
• Si apra il file prova.s
• File suddiviso in “sezioni”
– Sezione: area di memoria deputata a
contenere codice, dati, quant'altro
– Ciascuna sezione ha una etichetta (label)
che la contraddistingue
46
47. Uso dello stack sull'INTEL
• Conoscenza necessaria dell'assembly x86
• movl: copia un valore a 32 bit da un
registro/memoria ad un altro registro/memoria
• pushl: inserisci un valore nello stack
• popl: rimuovi un valore dallo stack
• addl/subl: aggiunge/sottrae un valore a 32 bit da
un registro/memoria ad un altro registro/memoria
• leave: toglie il valore del frame pointer dallo stack
• ret: ritorno da funzione
• leal: carica indirizzo effettivo
• andl: and bit a bit (allinea a multipli di 16)
• call: chiamata a subroutine
47
48. Chiamata a funzione
• Viene effettuata una push di tutti gli argomenti,
dall'ultimo al primo
• Viene effettuata una chiamata alla
funzione
• f(a, b); diventa:
– pushl a
– bushl b
– call f
48
49. Scheletro funzione
• Lo scheletro di una tipica funzione in
Assembly è il seguente
– salvataggio valore corrente frame pointer
– impostazione frame pointer a stack pointer
corrente (1)
– creazione spazio per le variabili locali (2)
– backup registri da preservare (3)
– corpo della funzione (4)
– restore registri da preservare (5)
– rilascia spazio legato alle variabili locali (6)
– ripristina il valore precedente di frame pointer
(7)
– Return (8) 49
50. Scheletro funzione (Assembly)
pushl %ebp (1)
movl %esp, %ebp (1)
subl $N, %esp (2) (2) Nei sistemi Intel, lo stack
cresce verso gli indirizzi
pushl %ebx (3)
più bassi!
push %esi (3)
... (4)
popl %esi (5)
popl %ebx (5)
movl %ebp, %esp (6)
popl %ebp (7)
ret (8)
50
51. Impatto delle istruzioni sullo stack
Prima della chiamata f(a, b);
Stack frame ESP
precedente
EBP
51
62. Impatto delle istruzioni sullo stack
pushl %ebp L'istruzione ret estrae dallo stack
movl %esp, %ebp il solo indirizzo di ritorno, e non i
parametri a e b. Nella realtà,
subl $N, %esp
l'indirizzo iniziale dello stack
pushl %ebx viene salvato e ripristinato.
push %esi
...
popl %esi Il valore di ritorno della funzione
viene scritto nel registro %eax.
popl %ebx
movl %ebp, %esp
popl %ebp Stack frame ESP
ret precedente
EBP
62
63. Espressioni notevoli
• 16(%ebp): terzo parametro della funzione
• 12(%ebp): secondo parametro della funzione
• 8(%ebp): primo parametro della funzione
• 4(%ebp): vecchio instruction pointer
• 0(%ebp): vecchio frame pointer
• -4(%ebp): prima variabile locale
• -8(%ebp): seconda variabile locale
• -12(%ebp): terza variabile locale
63
64. Programmed I/O
• Tecnica originaria di trasferimento dati
• Il trasferimento avviene tramite funzioni
assembler (in()/out()) eseguite dal
processore
• Il processore aspetta il risultato della
chiamata, senza poter fare altro
• Utilizzata nei dischi IDE/ATA
64
65. Direct Memory Access (DMA)
• Problema: una periferica ad alta velocità
può generare una miriade di interruzioni
– CPU costantemente impegnata a trasferire
dati in memoria
• Soluzione: trasferire blocchi di dati ad
ogni interruzione senza ricorrere
all'ausilio della CPU
65
66. Direct Memory Access (DMA)
• Direct Memory Access
• Il controllore del dispositivo trasferisce
l'intero buffer di dati direttamente in
memoria
– device driver del dispositivo attiva il DMA
impostando alcuni registri del controllore
– nessun intervento da parte della CPU
durante la copia
– un'interruzione per buffer dati, non per byte
66
67. Interruzioni ed I/O
• Due modalità di richieste di I/O
– richieste bloccanti
– richieste non bloccanti
• Modalità bloccante: il controllo torna al
programma utente solo dopo che l'I/O è
stato completato
– al più un I/O completato alla volta
• Modalità non bloccante: il controllo torna
al programma utente immediatamente
– più richieste di I/O concorrenti
67
68. Interruzioni ed I/O
• Come fare a mantenere traccia di più
richieste di I/O simultanee (caso non
bloccante)?
• Tabella di stato dei dispositivi
– ogni elemento della tabella indica:
♦ il tipo di dispositivo
♦ l'indirizzo del dispositivo
♦ lo stato del dispositivo (attivo, inattivo,off)
– più richieste per un dato dispositivo
♦ ogni elemento della tabella di stato può
essere una lista
68
69. Interruzioni ed I/O
dispositivo: lettore di schede 1
stato: inattivo
richiesta per
stampante 3
dispositivo: stampante 3
indirizzo: 38546
stato: attivo
lunghezza: 1372
dispositivo: unità a dischi 1
stato: inattivo
dispositivo: unità a dischi 2
richiesta per
stato: inattivo
unità a dischi 3
file: xxx
dispositivo: unità a dischi 3 ...
operazione: read
stato: attivo
indirizzo: 43046
lunghezza: 20000
...
69
70. Interruzioni ed I/O
1. Programma esegue richiesta I/O
2. Richiesta viene accodata alla lista del dispositivo
opportuno nella tabella di stato
3. Periferica elabora la richiesta
4. Una interruzione segnala il completamento
5. Device driver identifica il dispositivo relativo
6. Viene scandita la lista del dispositivo
7. Viene aggiornata la struttura associata alla richiesta
8. Un programma stava attendendo quei dati? Se sì,
viene attivato.
9. Altrimenti, si ripristina lo stato precedente
all'interruzione
70
71. Interruzioni ed I/O
• I sistemi di I/O più sofisticati permettono di
ricevere dati prima di essere richiesti dal
programma
– esempio tipico: scrittura veloce su tastiera
• In questo caso, nella lista del dispositivo non
risulta alcuna richiesta da parte di programmi
• Vanno utilizzati ulteriori buffer per memorizza-
re dati in attesa che un programma li richieda
– un buffer per ciascun dispositivo di input
71
72. Meccanismi di protezione
• In un sistema multiprogrammato, un
programma potrebbe erroneamente modificare
arbitrariamente altre locazioni di memoria
• Molti errori vengono rilevati dall'hardware
– es. tentativo di eseguire istruzione illegale
• Cosa succede se l'errore non è rilevabile
dall'hardware?
– es. accesso da parte di un programma a dati
del SO
• Serve un meccanismo di protezione della
memoria
72
73. Modalità operativa duale
• Modalità duale: vengono previste due
modalità di funzionamento della
macchina.
– modo utente
– modo monitor (supervisor)
• All'hardware della macchina viene aggiunto un
bit: bit modo
– 0->monitor (operazione effettuata dal SO)
– 1->utente (operazione effettuata da utente)
73
74. Modalità operativa duale
• Ogni volta che si presenta una interruzione, si
passa in modo monitor:
bit modo = 0
• Prima di ripassare il controllo al programma
utente, viene impostato il modo utente:
bit modo = 1
• Alcune istruzioni, dette privilegiate, possono
essere eseguite solo in modo monitor
• Se si tenta di eseguire una istruzione privile-
giata in modo utente, viene sollevata una
eccezione: istruzione illegale
74
75. Protezioni hardware
• Un programma utente può danneggiare il
funzionamento del SO nei seguenti modi:
– emettendo istruzioni di I/O illegali
– accedendo a porzioni di memoria nel SO
– rifiutando il rilascio della CPU
• E' necessario impedire ciascuna di tali
operazioni maligne
75
76. Protezioni hardware
• Accessi a porzioni di memoria del SO
– per ciascun programma si definisce un
intervallo di indirizzi legali accedibili
– utilizzo di due registri CPU:
♦ registro base: contiene l'indirizzo più
basso accessibile al programma
♦ registro limite: contiene l'ampiezza
dell'intervallo degli indirizzi
– la CPU verifica che qualunque indirizzo
generato dall'utente rientri nell'intervallo
– indirizzo fuori intervallo->eccezione
– i registri base e limite sono caricati tramite
istruzioni privilegiate 76
77. Protezioni hardware
• Esecuzione di istruzioni di I/O illegali
– tutte le istruzioni di I/O vengono rese
privilegiate
– gli utenti possono eseguire I/O solamente
attraverso il sistema operativo
– OSS.: un programma che entra in monitor
mode potrebbe sovrascrivere il vettore delle
interruzioni ed eseguire codice arbitrario
– occorre allora proteggere il vettore delle
interruzioni e le procedure di servizio
– in realtà, viene protetto l'intero SO
– tecnica usata nella protezione: spazi di
indirizzamento seperati per SO ed utenti 77
78. Protezioni hardware
0
monitor
256000
job 1
300040
300040 registro base
job 2
420940
registro limite
120900
job 3
880000
job 4
1024000
78
79. Protezioni hardware
• Rifiuto del rilascio della CPU
– viene introdotto un timer che interrompe
l'esecuzione della CPU dopo un intervallo di
tempo prestabilito
– Il timer è incrementato da un clock di
sistema ad intervalli regolari
– quando scade il timer, viene generata una
interruzione che trasferisce l'esecuzione ad
un altro programma
– timer ragionevolmente piccolo->time sharing
♦ intervallo->quanto di tempo
79
80. Protezione nei processori Intel
• Ottenuta tramite molteplici componenti
elettronici
• Protezione dall'uso esclusivo di CPU:
– Programmable Interval Timer
• Protezione da accessi invalidi alla memoria:
– Segmentazione della memoria, privilege
levels
• Protezione da esecuzione istruzioni illegali:
– Privilege levels, execution rings
80
81. Programmable Interval Timer
• Timer programmabile integrato nel circuito che
gestisce il Southbridge (I8253, I8254)
• Tre contatori ad alta precisione:
– timeout ACPI (protocollo gestione risparmio
energetico)
– Interruzioni sul singolo processore; serve per
bilanciare le interruzioni equamente in sistemi
SMP (APIC)
– Time Stamp Counter (Pentium); un registro a 64
bit che conta il numero di colpi di clock
dall'ultimo reset
• Frequenza aggiornamento contatori: da 18.2Hz
a 1MHz
81
82. Programmable Interval Timer
• Diverse modalità di esecuzione
– Conteggio a 0
– Generazione di impulsi periodici (quanto di
tempo)
– Generazione di onde quadre
• Al termine di ogni evento, viene generata una
interruzione hardware (IRQ 0)
82
83. Gestione della memoria negli Intel
• L'architettura Intel fornisce due meccanismi
per accedere alle celle di memoria di un
calcolatore: segmentazione e paginazione
• Segmentazione:
– la memoria è vista come un insieme di aree
(segmenti), ciascuna con un proprio scopo
(codice, dati, stack)
– è facile controllare se un processo sta
accedendo ad un indirizzo che gli compete
oppure no (basta controllare che l'indirizzo
generato stia all'interno di uno dei segmenti di
competenza del processo)
83
84. Gestione della memoria negli Intel
• L'architettura Intel fornisce due meccanismi
per accedere alle celle di memoria di un
calcolatore: segmentazione e paginazione
• Paginazione:
– la memoria viene vista a blocchi di 4KB
(pagine)
– Permette il caricamento efficiente di programmi
da disco (“per pezzi”)
– permette una condivisione raffinata ed
efficiente di zone di memoria comuni
– permette l'implementazione della memoria
virtuale
84
85. I diversi tipi di indirizzi
• L'architettura Intel passa per diversi formati di
indirizzi intermedi, prima di poter prelevare
fisicamente il dato dalla RAM
• Questi formati sono il prodotto dei meccanismi
di segmentazione e paginazione
• Tre formati:
– Indirizzi logici
– Indirizzi lineari
– Indirizzi fisici
85
86. Indirizzi logici
• La memoria del calcolatore può essere vista
come un insieme di porzioni di memoria
piccole, dedicate ad un ben specifico scopo
(segmenti)
– Codice, dati, stack
• Un indirizzo logico di memoria identifica una
cella di memoria nel seguente modo:
– Identificatore di segmento (segment
selector)
– Offset all'interno del segmento
• L'indirizzo logico (detto anche far pointer) è
una coppia (selector, offset)
– 0000:00401000 86
87. Indirizzi logici
Memoria principale
Segment
selector
Segmento codice Segmento dati
/bin/bash /bin/bash
Segmento stack
offset /bin/bash
Cella di memoria
87
88. Registri di segmentazione
• Dove vengono memorizzate le coppie
(selector, offset) degli indirizzi logici?
• L'architettura Intel mette a disposizione
svariati registri segmento (segment registers)
– Indicano con QUALE segmento lavorare
– ss: stack segment
– cs: code segment
– ds, es, fs, gs: data segment
• L'offset è memorizzato nei registri indirizzo
classici (EIP, ESI, EDI)
• movl $42, %fs:(%eax)
88
89. Indirizzi lineari
• Sono la rappresentazione “classica” della
memoria
• La memoria viene vista come un array
gigantesco di 2^n celle, indirizzabile tramite
interi da 0 a 2^n-1
• Un indirizzo lineare è un intero da 0 a 2^n-1 che
punta alla cella di memoria corrispondente
89
91. Indirizzi fisici
• Sono simili strutturalmente agli indirizzi lineari
– Corrispondenza 1:1
• Non è detto che abbiano gli stessi valori
• Nel caso in cui sia attiva la paginazione:
– traduzione indirizzo lineare-indirizzo fisico
• Nel caso in cui NON sia attiva la paginazione:
– Gli indirizzi lineari sono usati direttamente
sulla linea ADDRESS del Northbridge, che ci
connette al front side bus
91
92. Schema traduzione indirizzi
• Da dove parto? Da un indirizzo logico
espresso nella forma (selector, offset) dove:
– selector è ottenibile da un segment register
– offset è un valore costante/contenuto di un
registro
• Dove devo arrivare? Alla generazione di un
indirizzo fisico da scrivere sul bus
Indirizzo logico Indirizzo fisico
92
93. Schema traduzione indirizzi
• Il modulo di traduzione degli indirizzi cambia
forme diverse a seconda della modalità di
lavoro della CPU
– Real mode: 286 sempre, 386 e superiori nella
fase iniziale del processo di avvio (fino
all'avvio di /sbin/init)
– Protected mode: 386 e superiori
• Da cosa nasce la diversità?
– Il 286 NON ha la paginazione
– Il 286 ha registri a 16 bit, il 386 e superiori ce
li hanno da 32 bit
93
94. Traduzione indirizzi: real mode
1. Supponiamo di dover eseguire l'istruzione
JMP 0x6025
2. La CPU legge il segment register cs e lo
interpreta come l'identificatore del segmento
3. L'identificatore viene trasformato in un
“indirizzo di partenza del segmento” tramite
una moltiplicazione x 16 (shift logico a sinistra
di 4 bit)
4. Viene sommato l'offset
5. Il risultato è l'indirizzo lineare; l'indirizzo
lineare coincide con l'indirizzo fisico (no
paging)
94
95. Traduzione indirizzi: real mode
Registro CS
0x1000
Indirizzo
fisico 0x16025
CS * 16
Istruzione
+ offset
JMP 0x6025
Northbridge
Offset
Front side
0x6025
bus
RAM
95
96. Traduzione indirizzi: protected mode
• In modalità protetta, il segment selector non è
più un numero intero, bensì l'indice di un
segment descriptor in una tabella
• Segment descriptor: struttura dati di 8 byte
contenente tutte le informazioni necessarie a
descrivere un segmento
– Base address: indirizzo lineare a 32 bit
indicante la locazione iniziale del segmento
– Limit: specifica la lunghezza del segmento
– DPL: Descriptor Privilege Level (0-3), descrive il
privilegio minimo per accedere al descrittore
• I segment descriptor acceduti più
frequentemente sono mantenuti in una cache
96
97. Traduzione indirizzi: protected mode
Segment descriptor
63 47 32
Limit
4 byte Base (24-31) DPL Base (16-23)
(16-19)
4 byte Base (0-15) Limit (0-15)
15 0
31
97
98. Traduzione indirizzi: protected mode
• I descrittori di segmento sono memorizzati in
due tabelle distinte: global descriptor table
(GDT) e local descriptor table (LDT)
– 64KB, 8192 entry da 8 byte
• Global Descriptor Table: contiene descrittori di
interesse “globale”
– Descrittori di aree di memoria contenenti LDT,
Task State Segment, Call Gate
• Local Descriptor Table: contiene descrittori di
interesse “locale”
– Ne esiste una per ciascun programma in
esecuzione
98
99. Traduzione indirizzi: protected mode
• Ciascuna CPU/core ha un registro gdtr
contenente l'indirizzo iniziale della GDT
• Per scegliere un segmento, bisogna caricare
un segment register con un segment selector
(analogamente a quanto visto in real mode)
• La differenza sta nel diverso formato del
segment selector:
– Index: identificatore intero del segmento
utilizzato (13 bit, 8192 segmenti possibili)
– TI: bit che identifica in quale tabella è
memorizzato il segmento (0: GDT, 1: LDT)
– RPL: Requested Privilege Level (0-3), descrive il
privilegio con cui si sta accedendo al
descrittore 99
101. Traduzione indirizzi: protected mode
1. Supponiamo di dover eseguire l'istruzione
JMP 0x08048393 (32 bit)
2. La CPU legge il segment selector dal segment
register cs
3. Controllo privilegi
4. Tramite il bit TI, viene identificata la tabella
(ad es. GDT) in cui il relativo segment descriptor è
memorizzato
5. Si individua l'indirizzo del segment descriptor=
gdtr + index * 8
6. Si estrae il base address dal segment descriptor
7. Si aggiunge l'offset
8. Il risultato è l'indirizzo lineare
101
102. Traduzione indirizzi: protected mode
GDT
Segment
descriptor
Base address: 0
Index * 8 Indirizzo
gdtr
+ gdtr lineare
0x08048393
Base address
+ offset
Index: 14 0 3 Al sistema di
paginazione
CS
Istruzione
JMP 0x08048393
Offset
0x08048393
102
103. Traduzione indirizzi: protected mode
• Meccanismo di segmentazione complesso
• I SO moderni tentano di evitarlo, limitando il
numero di segmenti generati
• Il kernel di Linux usa 4 segmenti:
– __KERNEL_CS: kernel code segment, base=0,
limit=4GB, DPL=0
– __KERNEL_DS: kernel data segment, base=0,
limit=4GB, DPL=0
– __USER_CS: user code segment, base=0,
limit=4GB, DPL=3
– __DATA_CS: user data segment, base=0,
limit=4GB, DPL=3
103
104. Traduzione indirizzi: protected mode
• Due segmenti distinti per kernel code e user
code, con DPL diversi
– Possibilità di proteggere il kernel da accessi
involontari/maliziosi fatti da user space!
• Un solo segmento di codice in ciascun mode
– Il meccanismo di segmentazione si alleggerisce
• Flat memory model
– Linux, Windows (da NT in poi)
104
105. Traduzione indirizzi: protected mode
• Non abbiamo mica finito; dall'indirizzo lineare
occorre arrivare all'indirizzo fisico!
• Meccanismo di paginazione; la memoria viene
vista a blocchi di 4KB
• Ciascun blocco può puntare a:
– memoria RAM fisica
– blocchi su un filesystem (memory mapping)
– area di swap (virtual memory)
• La traduzione indirizzo lineare-contenuto
avviene per mezzo di una tabella: page table
– Array (in memoria centrale) contenente gli
indirizzi fisici iniziali (32 bit) di ciascuna pagina
– Indirizzo iniziale nel registro di controllo CR3 105
106. Traduzione indirizzi: protected mode
• Un indirizzo lineare (0-4GB) viene suddiviso in
due porzioni
– I primi 20 bit rappresentano l'indice alla page
table
– Gli ultimi 12 bit rappresentano l'offset
dell'indirizzo fisico all'interno della pagina fisica
numero di pagina p offset di pagina d
n-m bit m bit
Dimensione di una pagina: 2n unità di indirizzamento
Dimensione dello spazio di indirizzi logici: 2m
n=20, m=12
106
107. Traduzione indirizzi: protected mode
Schema paginazione RAM
indirizzo lineare indirizzo fisico
Indirizzo d d
p f
lineare
+
CR3
f
tabella delle pagine
107
108. Traduzione indirizzi: protected mode
• Se la pagina richiesta non è presente in
memoria centrale, si genera una eccezione:
page fault
– La routine di servizio preleva la pagina da
memoria secondaria
• Per accedere ad una locazione di memoria
occorre:
– accedere alla tabella delle pagine, per trovare
l'indirizzo fisico a partire da quello logico
– accedere all'indirizzo fisico
• In realtà, ogni accesso alla memoria diventano
due accessi alla memoria!
– inefficienza
108
109. Traduzione indirizzi: protected mode
• Si usa una memoria associativa hardware,
detta Translation Lookaside Buffer
– accesso del tipo: chiave->valore
– la memoria associativa trova il valore in
tempo costante
– dimensione della memoria associativa molto
ridotta
• Il TLS mantiene in cache le porzioni più
accedute della tabella delle pagine
109
110. Traduzione indirizzi: protected mode
Schema paginazione RAM
con TLB
indirizzo lineare indirizzo fisico
Indirizzo d d
p f
lineare
+
TLB
CR3
f
tabella delle pagine
110
111. Traduzione indirizzi: protected mode
• Le moderne CPU Intel sono corredate con
Physical Address Extension (PAE)
– Schema di paginazione a tre livelli
– Presenti su Pentium Pro e successivi
– Supporto per indirizzare fino a 64GB, senza
cambiare le dimensioni della tabella di pagina e
dei blocchi di pagina
– Abilitabile impostando il bit 5 del registro di
controllo CR4
• Idea di base: trasformare indirizzi lineari a 32
bit in indirizzi fisici a 36 bit
111
112. Traduzione indirizzi: protected mode
• Il registro CR3 punta ad una piccola Page
Directory Pointer Table di 4 elementi
• Ciascun elemento della Page Directory Pointer
Table è una Page Directory
• Ciascun elemento della Page Directory è una
Page Table
• Il contenuto di un indirizzo lineare viene
suddiviso in tante porzioni, al fine di
identificare l'indirizzo fisico finale
112
113. Traduzione indirizzi: protected mode
• I bit 31,30 dell'indirizzo lineare sono l'indice
alla Page Directory Pointer Table
• I bit 29,...,21 dell'indirizzo lineare sono l'indice
alla Page Directory
• I bit 20,...,12 dell'indirizzo lineare sono l'indice
alla Page Table
• I bit 11,...,0 dell'indirizzo lineare sono l'offset
all'interno della Page Table
113
114. Traduzione indirizzi: protected mode
Schema paginazione multilivello-PAE
Indirizzo lineare
31 24 23 16 15 8 7 0
RAM
Page
PDPT
directory Page
...
Dir pointer table
...
4KB
Dir pointer ...
page
64 bit
+
Dir pointer PD entry 64 bit ...
PT entry
Dir pointer
...
...
CR3
114
115. Livelli di privilegio
• Meccanismo per difendersi da
istruzioni/accessi alla memoria illegali causati
da:
– malfunzionamenti hardware
– comportamenti maliziosi
• La CPU è dotata di 4 modi di utilizzo, disposti
“ad anello”
– Ring 3: applicazioni utente
– Ring 2: device driver
– Ring 1: device driver, hypervisor
– Ring 0: codice kernel
115
117. Livelli di privilegio
• Un SO “normale” utilizza solamente i livelli di
privilegio 0 (kernel) e 3 (user)
– Passaggio automatico tra codice eseguito per
conto del kernel e codice applicativo
• Il ring 1 viene usato nel contesto della
virtualizzazione
– Xen (dom-1)
117
118. Livelli di privilegio
• Alcune istruzioni macchina (inw()/outw()) sono
permesse solamente in ring 0
– Scrittura diretta sui dispositivi non è possibile
se non quando si esegue codice di kernel!
– Ovviamente, se il codice del kernel è scritto
male, ogni sorta di danno può accadere
• I livelli di privilegio sono utilizzati anche per
controllare i permessi di accesso ai selettori
• I segment selector contengono dei bit di
permesso che possono essere controllati
durante il processo di accesso al segmento
118
119. Livelli di privilegio
Data segment selector
Index (3-15) TI RPL
21 0
15 3
Code segment selector
Index (3-15) TI CPL
21 0
15 3
CPL: Current Privilege Level (livello di priviligio con
cui è eseguito il codice del segmento)
RPL: Request Privilege Level (livello di privilegio con
cui si sta tentando di accedere al segmento dati)
119
120. Livelli di privilegio
• Come avviene il controllo dei permessi sul
segmento?
• Si estrae il valore CPL dal code segment selector
• Si estrae il valore RPL dal data segment selector
• Si identifica il segment descriptor usando il campo
Index del data segment selector
• Si estrae il valore DPL dal segment descriptor
• Si calcola il privilegio più debole fra codice e
richiesta: max(CPL, RPL)
• Se max(CPL, RPL) <= DPL, allora l'accesso viene
garantito
• Altrimenti, viene generata una eccezione di tipo
General protection fault
120
121. Livelli di privilegio
Code segment
register
CPL True: segment
load
Data Segment descriptor
dei dati da caricare in memoria
max(CPL,RPL)
Index RPL
TI <=DPL?
Segment descriptor
DPL False: GPF
121