



Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Libro di Michael Dahlin, Thomas Anderson tradotto in italiano (13 capitoli).
Tipologia: Appunti
1 / 5
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!




Lezione 2
Architettura del computer: Un modello semplificato.
Il sistema operativo si contrappone tra gli utenti e l’hardware. Quest’ultimo lo considereremo come hardware di base. Le ipotesi che faremo è di avere una CPU standard, una memoria principale, un set di periferiche, l’interazione attraverso gli interrupt e infine il bus DMA.
Composizione CPU:
•.1. Program Counter: Indirizzo dell’istruzione che si sta eseguendo
•.2. Il puntatore allo stack (SP), esso serve a memorizzare le informazioni di controllo, ovvero il buon funzionamento dell’esecuzione di un programma
•.3. Il registro che contiene la parola di stato (PS), è un registro che contiene tanti flag binari che dice cosa sta succedendo, o è successo durante l’esecuzione del programma.
Ciclo fetch-execute:
L’istruzione viene prelevate e poi eseguite. Una nota importante, ogni singola istruzione è atomica (questa non viene interrotta fin quando non è stata eseguita completamente). Le periferiche quando finiscono il loro lavoro lo segnalano attraverso le interruzioni (ovvero sospendere ciò che si sta facendo momentaneamente e passare alla gestione della periferica, Nota: Le interruzioni possono essere abilitate come disattivate attraverso un bit, ovviamente deve essere fatto in linguaggio macchina e non ad hardware (Possono essere eseguite in modalità Kernel)).
Le tecniche utilizzate per risolvere i problemi dei Sistemi Operativi, sono le stesse della nostra vita quotidiana. È importante capire come fermarsi e ripartire da dove si è stato interrotti. All’inizio si va a vedere se esiste un’interruzione, se questo è vero => si gestire l’interruzione. Se invece non esiste un’interruzione => viene caricata l’istruzione il cui indirizzo è nel Program Counter, si punta a quella successiva (tutte le istruzioni si ipotizza che sono di 4 byte), e viene eseguita l’istruzione precedente a quest’ultima.
Program Status Register: Contiene lo stato dell’ultima istruzione che è stata eseguita, se durante l’esecuzione di quella istruzione succede qualcosa di strano viene segnalato, altrimenti non si fa nulla (overflow, divisione per 0), e un altro bit per vedere se stiamo eseguendo in modalità Kernel o User chiamato EFLAGS.
Problemi principali del Kernel: La sfida principale del Kernel è quella di garantire una protezione. Il codice utente viene eseguito con privilegi ristretti poiché si vuole evitare che eventuali malfunzionamenti possono attaccare il sistema. Alcuni esempi di programmi che non possono essere eseguiti in modalità Kernel sono:
Processo: L’attività di esecuzione di un programma con uno stato particolare, con privilegi limitati. Nell’esempio del browser ho lo stesso programma, ma se avessi due schede, queste lavorerebbero su dati differenti. Tutti i dati del processo sono contenuti in una struttura dati del sistema operativo chiamata PROCESS CONTROL BLOCK (PCB). Tutti i PCB sono contenuti in una tabella (è un vettore come struttura dati nel quale sono salvati i diritti di un processo per esempio), la dimensione della tabella mi determina quanti processi possono essere eseguiti.
PCB: Contiene i puntatori ai thread, ha una memoria assegnata, e altre risorse. Il nome del processo è la posizione che occupa all’interno del PCB.
Poiché possono esserci tanti processi della stessa natura, conviene salvare il processo principale (es: il programma che tutti condividono) e dividere in thread le informazioni diverse tra di loro : in quest’ultimi ci sono solo le informazioni che mi permettono di eseguire il thread. È fondamentale che ogni processo deve poter accedere solo al suo spazio di memoria riservato.
Modalità utente vs Modalità kernel: L’utente ha dei privilegi ristretti, il kernel no. Dobbiamo poter passare da una modalità all’altra poiché per esempio l’utente può eseguire delle istruzioni non dannose, ma delle istruzioni particolare devono essere eseguite PER FORZA dal kernel. Nella modalità kernel il processo può utilizzare tutte le istruzioni macchina e utilizzare tutto l’hardware.
OSS: Per poter passare da una modalità all’altra abbiamo bisogno di ulteriore hardware che mi serve per scegliere tra due modalità.
Cambio di modalità: Quando si passa da utente a kernel?
Cambio di modalità in modo sicuro: Si ha un vettore di tanti elementi, ognuno dei quali punta alla routine di gestione di una particolare interruzione. Quando si va ad eseguire una nuova procedura viene cambiata il program counter, per poter ritornare al punto in cui sono stato interrotto devo salvarmi il vecchio program counter, la parola di stato, ed essendo un processo devo salvarmi anche il valore dello stack pointer. Tutto ciò viene salvato in uno stack chiamato INTERRUPT STACK (di cui il kernel ne è proprietario poiché sono informazioni estremamente delicate). Finché è in esecuzione un processo utente il kernel stack è vuoto. Quando si effettua un cambio di contesto, nello stack del kernel vengono memorizzate le informazioni citate precedentemente. I registri generali vengono salvati prima dell’esecuzione della prima istruzione della gestione dell’interruzione.
IL CAMBIO DI MODALITA’ DEVE ESSERE FATTO IN MODO ATOMICO.
Mascheramento interruzioni: Le interruzioni possono essere mascherate, questo viene fatto con un altro vettore davanti al vettore interruzioni, e attraverso un and vedo se l’interruzione è abilitata o meno. Dobbiamo agire sull’hardware => deve esserci un’istruzione privilegiata in linguaggio macchina. Nel caso del processore x86, il codice operativo CLI: disattiva le interruzioni, STI: le abilita.
OSS: Un processo per poter funzionare ha i propri registri generali. Appena vengono eseguite le prime istruzioni del gestore dell’interruzione, vengono salvati i registri generali nello stack del kernel e gestire l’interruzione. Quando ho finito riporto i registri generali al processore e soltanto dopo, riporto i valori dello stack pointer, program counter e parola di stato (in un'unica istruzione); l’istruzione IRET , mi permette di fare tutto ciò (in sostanza sto facendo l’operazione inversa).
Nel caso in cui metto un altro processo in esecuzione, i dati stanno nel PCB del nuovo processo. Questi li metto nello stack interrupt => i valori del processo precedente (che sono attualmente contenuti nello stack interrupt) vengono messi nel suo PCB.
System Call
Può darsi che io sia chiamato a interrompere il mio lavoro da un’interruzione “interna”. Ci sono varie cose che gli utenti non possono fare, per esempio agire direttamente sul disco, periferiche etc. L’utente allora può chiedere al sistema operativo di eseguire alcune operazioni (delicate e pericolose).
Es: Apertura di un file, chiediamo al sistema operativo di aprire un file, o scriverci dentro.
Quindi l’handler della system call:
Booting
Il sistema operativo risiede nel disco (la parte iniziale, la memoria è permanente quindi non la prendo). Per caricarlo, esiste un pezzo di programma corto BIOS (scritto all’interno della ROM), che copia, da una posizione fissa del disco, la prima parte del sistema operativo chiamata bootloader che viene messo in esecuzione. Quest’ultimo prende il kernel, istruzione e dati e li carica in memoria trasferendogli il controllo. Quest’ultimo esegue la login app, e da qui parte il tutto.
Upcall
In UNIX sono i “segnali”. Il kernel interrompe il processo utente, poiché deve fare qualcosa per sé.
Esempio: Quando arriva un email l’utente sta facendo altre cose (tra le preferenze ho che se arrivasse, questa mi verrebbe segnalata). Come fa a sapere il nostro user agent quando arriva un email? Il sistema operativo, quando ha un’interruzione dalla scheda di rete, interrompe l’esecuzione del processo e segnala all’utente che è arrivata una nuova email attraverso le Upcall. La gestione non è fatta dal kernel, ma dall’utente. Se volessimo utilizzare le UpCall, dobbiamo avere una porzione di codice che mi permette di fare. E’ esattamente come un’interruzione ma all’interno del nostro processo, quindi avrò uno stack signal nel mio processo.
Operazioni: