Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
UTOP.
Con il test della condizione vediamo se size è
multiplo di PGSIZE (se non lo è -> panic).
Nel ciclo for mappiamo lo spazio di memoria
virtuale che parte dall’indirizzo virtuale va per la
dimensione di size sull’indirizzo fisico che inizia
da pa. Utilizziamo la funzione pgdir_walk()
Più in dettaglio:
All’interno del ciclo, come già accennato, per mappare la memoria virtuale di dimensione size a partire
dall’indirizzo fisico, viene utilizzata la funzione pgdir_walk(), che restituisce a partire da una page directory
l’indirizzo dell’elemento di Page Table associato ad un determinato indirizzo logico va.
Quindi:
1 giro index = 0
Mappiamo l'indirizzo logico $va + index$ all'indirizzo fisico $pa + index$:
*(pgdir_walk(pgdir, (void *) (va + 0), 1)) = (pa + 0) | perm | PTE_P;
dopo di che incremento index di 4096 byte;
2 giro index = 4096
Mappiamo l'indirizzo logico va + index all'indirizzo fisico pa + index:
*(pgdir_walk(pgdir, (void*) (va + 4096), 1)) = (pa + 4096) | perm | PTE_P;
dopo di che incremento index di altri 4096 byte;
E continuiamo ad eseguire il mapping fino ad esaurire l'intero spazio.
Usando ora la procedura di boot_map_region() siamo ora in grado di allocare ed inizializzare gli spazi di
indirizzamento necessari al kernel di JOS:
- Map Kernbase
- Map Pages
- Map Envs (parte relativi ai PCB => processi)
- Map Kernel Stack
Per completare i passaggi:
Dopo avere creato la nuova Page Directory per caricare il nuovo riferimento è sufficiente caricare il suo
indirizzo all’interno del registro CR3, con indirizzo di riferimento PADDR(kern_pgdir).
A questo punto la Page Directory e le relative Page Table che abbiamo precedentemente costruito
diventano operative e la MMU e quindi il sistema inizierà a lavorare con la nuova Page Directory.
Altre funzioni: Page_insert() e Page_remove() Viene mappata la pagina fisica ‘pp’
all’indirizzo virtuale ‘va’.
Requisiti:
- Se c’è già una pagina mappata in
‘va’ dovrebbe essere rimossa
- Se necessario, allocare una page
table e inserirla in pgdir.
- Pp-> pp_ref dovrebbe essere
incrementato se l’inserimento va a
buon fine
- La TLB deve essere invalidata se la
pagina era precedentemente
presente al ‘va’
Ritorno:
- 0 per successo
- -E_NO_MEM se la pagina non può
essere allocata
In pte viene restituito l’indirizzo va, e se la
page table non è presente si potrà creare (in
caso non si possa istanziare se non fosse
ancora creata, restituito errore)
Verifico se la pagina è già presente:
Se lo è, verifichiamo se una pagina divera è
mappata sullo stesso indirizzo virtuale: se
così fosse, la rimuoviamo e la sostituiamo
incrementando il pp_ref visto che è usato
nel mapping e invalidiamo la TLB.
Se invece la pagina è già presente, ed è la
stessa, aggiorniamo gli eventuali permessi
che potrebbe cambiare.
Se non era già presente, aggiungiamo alla
fine la conversione in indirizzo fisico,
incrementando il riferimento.
Restituiamo 0 per l’avvenuto inserimento.
Toglie la pagine virtuale dalla posizione fisica.
Se non è presente nessuna pagina a quel
indirizzo fisico non fa nulla.
Dettagli:
- Il pp_ref deve essere decrementato
- L’indirizzo fisico deve essere liberato
se pp_ref = 0
- Se l’indirizzo virtuale corrisponde
nella pagetable a questo indirizzo
fisico dovrà essere settato a 0
- La TLB deve essere invalidata se viene
rimosso un entry table/dir
I processi in JOS (ENVS)
Concetti:
Processo => Con il termine processo denotiamo l’esecuzione di un programma (sequenza istruzioni), ossia
tutti gli oggetti usati dal sistema per eseguire qualsiasi attività richiesta dall’utente, nell’ambito di un
determinato ambiente esecutivo caratterizzato da:
- CPU
- Memoria
- File
I processi sono tra loro scorrelati (le risorse sono private tra ciascun processo)
Identificare un processo:
Le informazioni per identificare un processo:
- Identificatore del processo
- Identificatore del processo padre
- Identificatore dell’utente proprietario
Stato del processo:
Lo stato di un processo sono determinate da:
- Tutti i registri del processore
- PC (EIP)
- EFLAGS
- Variabili si stato => flag interrupt, excecution mode
- Stack pointer: puntatori allo stack associato al processo
Process Control Information:
- Stato del processo: running, ready, waiting, halted
- Priorità scheduling
- Informazioni per l’algoritmo di scheduling (tempo permanenza sistema, tempo CPU)
- Eventi: identificativo dell’evento di cui il processo è in attesa
- Campi di strutture dati: puntatori utilizzati quando il PCB è inserito in code di attesa
- Variabili comunicazione tra processi
- Eventuali privilegi concessi al processo: quantità memoria, risorse del sistema
- Gestione della memoria => tabella pagine e dei segmenti
- Risorse utilizzate => File aperti e/o creati
PCB => Process Control Block, è la struttura dati di un processo che contiene le informazioni essenziali per
la gestione del processo stesso
JOS PCB (ENVS) L’indirizzo di pgdir sarà
utilizzato dalla MMU (da
caricare in CR3) quando
dobbiamo usare il task
Le parti riquadrate
rappresentano:
env data structure
Analiziamo env_status:
- Env_free: Indica che Env Structure è inattiva, e quindi nella env_free_list
- Env_runnable: Indica che la Env Structure sta aspettando di essere eseguita dal processore
- Env_running: Indica che la Env Structure è nello stato di esecuzione
- Env_not_runnable: Indica che la Env Structure è attiva ma che non è pronta per essere eseguita
(esempio: perché sta aspettando un informazione da un altro processo (IPC , interprocess
comunication))
- Env_dying: Indica che la Env Structure rappresenta un processo zombie
Strutture Dati:
Il kernel mantiene tre variabili globali:
- Struct Env *envs = NULL Tutti i processi
- Struct Env *curenv = NULL Il processo corrente
- Static struct Env *env_free_list Lista dei processi liberi
Una volta che JOS è settato e in esecuzione, il puntatore envs punterà a un array di strutture Env dove
vengono rappresentati tutti i processi del sistema.
Il kernel JOS supporta un massimo numero di Env (NENV) simultaneamente attivi, sebbene verranno usati
molti meno processi rispetto a qualsiasi momento (NENV è una costante definita in => inc/env.h)
Una volta allocati, gli envs array conterranno una singola istanza di ogni processi istanziabile.
Il kernel JOS mantiene anche una lista di tutti i processi inattivi in env_free_list, permettendo di allocare o
deallocare facilmente un processo.
Il kernel usa curenv per tenere traccia del processo in esecuzione in quel momento. Durante
l’inizializzazione, prima che il primo processo venga istanziato, questo punterà a NULL.
Creazione spazio e inizializzazione:
Come visto precedentemente, allocheremo la
memoria necessaria per mezzo della procedura
mem_init(), dove viene dedicato uno spazio tanto
quanto possono essere il massimo numeri di
processi istanziabili.
Succesivamente andremo a mappare l’area di
memoria che avevamo istanziato.
Gestione dei Processi:
- Env_init(): Inizializza tutte le strutture Env contenute nell’array envs e le aggiungi a env_free_list.
(Richiama env_init_percpu configurano la segmentazione hardware con segmenti separati per livelli
di privilegio 0 (kernel) e livelli di privilegio 3 (user)).
- Env_setum_vm(): Alloca una page directory per ogni nuovo processo e inizializza la porzione di
kernel per il nuovo spazio di indirizzi del processo.
- Region_alloc(): Alloca e mappa la memoria fisica per un processo
- Load_icode(): Analizzata un immagine binaria ELF (come già fa il boot loader) e caricata il suo
contenuto all’interno di uno spazio utente di un nuovo processo.
- Env_create(): Viene allocato un processo con env_alloc() e chiamata load_icode() per caricargli un
file binario ELF
- Env_run(): Inizia l’esecuzione di un processo in user mode.
Analizziamo le diverse procedure: ENV_INIT
Settiamo tutti i processi in ‘envs’ come liberi, setta i loro
env_id a zero, e li inserisce nella env_free_list.
Dobbiamo essere sicuri che i processi nella free list siano
nello stesso ordine di ‘envs’.
Facciamo puntare ‘env_free_list’ ad ‘envs’ che è stato
precedentemente allocato.
Nel ciclo, settiamo tutte gli ambienti di processi con
IdProcess = 0, status = free e impostiamo il collegamento al
processo successivo.
Infine settiamo il collegamento dell’ultimo processo con
NULL.
Env_init_cpu => chiama l’inizializzazione hardware
Carichiamo GDT e descrittori di segmentazione
Lgdt(&gdt_pd) <- Caricata la nuova GDT (dobbiamo
aggiornare tutti i segment register per rendere effettiva la
modifica)
Il kernel non ha mai usato GS o FS, li lasciamo settare dal
data segment dell’utente.
Settiamo ES, DS, SS utilizzati dal kernel.
Dobbiamo caricare il code text segment in CS utilizzando
una ljmp (istruzione successiva) impostando GD_KT
Resettiamo la LocaDescriptorTable (non usata da JOS)
} Nuova GDT che permane per tutto il kernel. 6 segmenti
- 0x0 -> Segmento nullo, obbligatorio per architettura
Intel
- 0x8 -> Dopo otto byte, Kernel code segment
(lettura, non può essere modificato)
- 0x10 -> Kernel data, (con autorizzazione in scrittura)
- Successivamente User code e data
- Infine viene inizializzato il TSS a NULL
Note aggiuntive:
- La nuova GDT ha tutti i segmenti sovrapposti (da 0 a 0xFFFFFFFF) di 4G di ampiezza. La protezione
del kernel è implementata tramite le pagine (altrimenti i segmenti dovrebbero partire da aree di
memoria differenti) – La GDT inziale istanziava solo i primi 3 segmenti
- Kernel mode uso i primi 3 --- User mode uso gli altri 3
- GD_KT -> lo spiazzamento del segmento del codice di kernel all’interno della GDT
- TSS Task State Segment, si trovano i contesti di un processo. ENV_SETUP_VM
Inizializza il settaggio della memoria virtuale del
kernel per i processi e.
Alloca una page directory, settando e -> env_pgdir,
e inizializza la porzione di kernel del nuovo spazio
dei processi.
(non è ancora mappato nulla nella porzione utente
dello spazio virtuale dei processi)
In caso di successo: ritorna 0, o minore.
In caso di errore: -E_NO_MEM (se page directory o
table non può essere allocata)
Allochiamo una pagina per la page dir