Gestione degli I/O mediante interrupt
Questo metodo di gestione degli I/O prevede la presenza di un segnale hardware che indichi al controllore delle interruzioni che un dispositivo è pronto a trasmettere o a ricevere dei dati. In un sistema a polling è il controllore che testa un registro di stato, mentre con gli interrupt è il dispositivo che manda un segnale. Nella gestione ad interrupt i dati e le informazioni di ogni dispositivo vengono messe nei registri di dato/stato dell'interfaccia, mentre un segnale viene inviato al gestore degli interrupt.
Il gestore delle interruzioni ha il dovere di raccogliere queste informazioni e inviare al momento opportuna una richiesta alla CPU, in modo che venga gestita l'operazione di I/O.
I tempi per valutare la bontà di un sistema di interrupt sono i seguenti:
-tempo di latenza (tl), cioè il tempo che intercorre tra il momento della richiesta di interruzione e il trasferimento del dato. Nel caso peggiore esso è dato dalla somma di tre fattori:
--tempo per il completamento dell'istruzione corrente (tic).
--tempo di attivazione della routine di interrupt (tar).
--tempo di avvio del trasferimento, cioè il tempo che intercorre tra l'inizio della routine e l'istruzione di inizio trasferimento dati (tat).
-transfer rate (TR), per cui vale la relazione 1/TR>tl, che indica la velocità dei periferici in questione. Un TR alto indica un periferico veloce e che quindi ha il potere di interrompere un dispositivo più lento. Nel caso in cui il tempo di latenza sia maggiore dell'inverso del TR non si farebbe in tempo a leggere tutti i dati del dispositivo.
Interrupt in 8086
Nell'80x86 esistono 256 tipi diversi di interrupt, divisi in gruppi con priorità diverse:
-interrupt interni (trap), che sono prodotti dal processore stesso. Si trovano all'interno della interrupt vector table nella parte bassa poichè sono quelli a priorità maggiore. Essi rilevano la presenza di situazioni anomale nella gestione dei processi del processore. Sono differenziati a seconda della modalità attiva (reale o protetta). Esempi sono dati dalla divisione per 0 o dall'overflow.
-interrupt non mascherabili (NMI), sono positive edge triggered e attivano procedure in cui NMI deve essere attivo per 2 colpi di clock. Sono attivati tramite il pin NMI e non sono mascherabili mediante il flag IF. Ad essi è associato il vettore all'indirizzo 0008H e sono utilizzati in connessione con eventi come la caduta dell'alimentazione o un errore di lettura in memoria.
-interrupt software, che servono per la gestione dei servizi del sistema operativo. Essi sono chiamati tramite istruzioni speciali (INT n).
-interrupt hw esterno (mascherabili), che dipendono dall'architettura. Il flag IF permette di abilitare/disabilitare gli interrupt hardware esterni. IF può essere modificato via software per mezzo delle istruzioni Assembler CLI e STI. IF è automaticamente resettato nel momento dell'attivazione di una routine di interrupt.
La gestione degli interrupt mediante interrupt vector table avviene per mezzo di entry (da 4B in real mode, da 8B in protected mode) alle procedure di interrupt corrispondenti. In real mode le entry contengono 2B che contengono l'offset (IP) e 2B di segmento (CS), che consentono di ottenere l'indirizzo reale alla procedura di interrupt. In protected mode sono presenti anche flag (Segment present, DPL, Type, Padding…) e un selettore di segmento. E' presente una tabella di puntatori, in quanto le istruzioni da eseguire variano a seconda del sistema operativo.
Il protocollo di interrupt prevede diverse fasi:
-un dispositivo effettua la richiesta di interrupt su INTR
-la CPU rileva durante l'ultimo colpo di clock dell'ultima istruzione eseguita, che INTR è attivo
-la CPU manda un ACK su INTA
-La CPU invia un secondo ACK su INTA, richiedendo il numero di interrupt richiesto sul data bus.
-La CPU legge 1B sul data bus
-La CPU salva nello stack PSW, IP e CS
-IF e TF vengono disabilitati
-La CPU accede all'interrupt vector table nella posizione richiesta
-Ad IP e CS vengono assegnati i valori contenuti nella entry della interrupt vector table.
Mappa degli interrupt:
-0, divisione per zero.
-1, single step, che permette il debug step by step in protected mode. La procedura 0004H viene lanciata dopo ogni istruzione se TF è 1. L'inserimento di breakpoint avviene chiamando la funzione INT senza parametri. Essa viene codificata su un solo byte e causa la routine di interrupt 000CH.
-2, NMI
-3, Breakpoint. Utile per il debug, in quanto viene testato dopo ogni operazione. Per gestire il debugging ci sono due tecniche. La prima prevedeva di intercettare il valore del program counter nel momento in cui passava sull'ABUS e in base a questo valore inviare un INT3. Al giorno d'oggi non è più attuabile in quanto il PC non passa più sull'ABUS. La seconda prevede di inserire delle CALL speciali con un numero di byte pari all'istruzione con minor numero di byte (1Byte). In realtà gli interrupt prevedono l'utilizzo di 2 Byte (1B per l'operazione+1B per il valore), anche se poi vengono codificati su un unico Byte.
-4, Overflow
-5:31, Riservati protected mode. Tra questi:
--6, invalid opcode
--11, segment not present
--13, general protection
--14, page fault. Si attiva nel caso in cui si cerchi di accedere ad un indirizzo non mappato. Questa situazione anomala viene rilevata dall'hardware che manda una INT 14, affinchè la CPU abortisca l'operazione in modo da gestire il meccanismo di pagina.
-32:255, Bios e OS.
8259A
La gestione dell'interrupt nell'8086 è affidata per la parte hardware al dispositivo 8259. In questo modo il codice viene minimizzato e vengono migliorati i tempi di risposta. Grazie a questo dispositivo è possibile gestire livelli di interrupt multipli con priorità. Nei sistemi attuali esso si trova integrato nel south bridge, anche se in principio era un chip separato. E' possibile collegare più 8259 in cascata in modo da gestire un numero maggiore di interrupt. In una cascata di 8259 (fino ad un massimo di 64 livelli), un primo dispositivo funge da master e controlla gli altri mediante i segnali di CAS. Si possono gestire fino a 8 livelli di interrupt vettorizzato. Questo dispositivo ha in ingresso 8 linee di richiesta di interrupt, provenienti da altrettanti apparecchi e dialoga con la CPU mediante due segnali (INT e INTA).
All'8259 è collegato anche 8 bit del DBUS, che servono in fase di configurazione dei dispositivi ad esso collegati. Esistono inoltre i segnali di RD e RW ed il segnale Ao, che mi permette di selezionare quale dei registri dei dispositivi collegati selezionare. Il CS (Chip Select) permette di selezionare un dispositivo.
La procedura di interrupt è simile al caso precedente anche se è leggermente differente:
-un dispositivo periferico effettua una interrupt request sulla linea ad esso associata.
-Il bit dell'interrupt request register (IRR) viene settato e l'8259 manda una richiesta di interrupt (INT) alla CPU.
-la CPU conferma la richiesta, inviando un segnale di INTA.
-la richiesta a priorità più alta viene selezionata, settando il registro ISR e resettando IRR.
-la CPU invia un secondo INTA.
-l'8259 invia sul data bus il codice del dispositivo che ha effettuato la richiesta (1B).
-il ciclo di interrupt è concluso resettando il bit ISR. se l'8259 funziona in AEOI, questo accade in automatico oppure si attende che esso venga resettato manualmente mediante un end of interrupt esplicito (EOI)
Il chip 8259A deve essere programmato per operare nella modalità voluta. Esso necessita di 4 ICW per l'inizializzazione e 3 OCW per selezionare la modalità e le opzioni di funzionamento. Le ICW possono essere modificate solo in fase di inizializzazione, mentre le OCW possono essere modificate singolarmente in ogni momento:
-ICW1. L'inizializzazione avviene attraverso una sequenza di parole di comando, riconoscibile perchè il primo dato (ICW1) è caratterizzato dal segnale di indirizzo A0=0 e dato D4=1. Quando la CPU invia questa combinazione viene resettato il registro maschera IMR.
-ICW2, la CPU determina i tipi di interrupt corrispondenti agli 8 segnali di richiesta di interrupt:
--T3-T7 i 5 bit più significativi del vettore degli interrupt
-ICW3, ciscun bit specifica se il corrispondente segnale IR è un 8259 slave oppure un normale dispositivo.
-ICW4
-OCW1, permette di caricare il registro IMR. Ad ogni bit corrisponde un bit nel registro, consentendo quindi di mascherare i canali di interrupt
-OCW2, serve a gestire la rotazione delle priorità e dell'EOI. Alcuni bit specificano un particolare canale di interrupt
-OCW3, serve a settare o resettare lo special mask mode, la lettura di IRR e ISR, il Poll Command.
Le modalità di funzionamento sono le seguenti:
-fully nested mode, che è la modalità in cui il chip lavora di default. Le richieste di interrupt sono ordinate per priorità (da 0 a 7). Finchè il bit ISR è settato significa che è presente una richiesta a priorità massima e quindi tutte le altre richieste sono disabilitate. Nel momento in cui la CPU manda un messaggio EOI esplicito il bit ISR viene rimesso a 0, dopo il secondo INTA. In questa modalità può essere attivo l'automatic end of interrupt (AEOI), in tal caso l'8259 resetta automaticamente il registro ISR dopo il secondo fronte di salita di INTA. Se invece AEOI è settato a zero, allora per resettare ISR occorre un EOI esplicito. Per fare ciò è necessario inserire tale comando prima dell'istruzione IRET. In caso di cascata di 8259 occorre inviare il comando EOI due volte (uno per il master e uno per lo slave interessato). Esistono due tipi di EOI: il Non Specific EOI è valido in fully nested mode e corrisponde a inviare un EOI all'ultima richiesta di interrupt servita. Nel caso di Specific EOI (non si può usare in modalità fully nested), siccome non si ha più una priorità statica, corrisponde a inviare un EOI specificando il livello di interruzione di cui si vuole resettare il registro ISR, in quanto l'8259 non è più in grado di riconoscerlo autonomamente. Per settare un EOI specifico è necessario usare la parole OCW2.
-rotazione automatica di priorità, che viene utlizzato in presenza di dispositivi di I/O con uguale priorità. Ogni volta che viene soddisfatta una richiesta di interrupt la priorità del dispositivo associato viene messa al valore minimo. E' inoltre possibile cambiare i livelli di priorità con la OCW2. Settando correttamente i bit si possono ottenere diverse combinazioni come la rotazione di priorità con AEOI, con semplice EOI oppure disabilitare la rotazione. E' possibile modificare i livelli di priorità attraverso OCW2. In questo modo si ottiene una rotazione di priorità specifica. In modo EOI è possibile inviare un comando di EOI in modo speicfico e contemporaneamente ruotare le priorità.
-Special mask mode. In questa modalità i bit di IMR settati disabilitano i livelli corrispondenti, abilitando tutti gli altri. Questo è utile quando in modo EOI una richiesta è stata abilitata ed un comando di EOI non ha ancora disabilitato il bit IS. In questo caso le richieste a priorità più basse sono disabilitate. Ogni livello di richiesta può essere mascherato attraverso la parola OCW1 e la modalità può essere attivata/disattivata attraverso OCW3.
-Poll Command, serve a utilizzare l'8259 in polling. L'8259 legge la successiva istruzione di lettura come l'ACK di interrupt. In questo caso la CPU non esegue la solita sequenza di segnali di INTA.
-Special fully nested mode, utilizzata quando sono presenti più 8259A in cascata e si vuole conservare la priorità di ciascuno slave. Nel momento in cui uno slave esegue un'operazione, solo uno slave a priorità maggiore può costringere il master a far eseguire il proprio servizio. Nel caso in cui l'ISR dello slave sia a 0 è possibile inviare una EOI non specifica al master.
E' possibile leggere lo stato dell'8259 mediante la consultazione dei suoi registri interni. Infatti i registri IRR, ISR e IMR possono essere lette le condizioni relative al primo ciclo di lettura successivo al'ultima OCW3.
E' inoltre possibile rendere il dispositivo sensibile ai fronti o ai livelli mediante il bit LTIM. Se LTIM è a 0 le richieste saranno riconoscibili mediante una transazione da 0 a 1 su un ingresso di IR. Se LTIM è a 1 le richieste saranno riconosciute da un livello alto sull'ingresso IR.
Come già detto, è possibile gestire una cascata di 8259, fino a 64 livelli di interruzione, mediante l'uso di un master e 8 slave. Il master controlla gli slave mediante le linee di CAS, che funzionano da chip select codificato per gli slave durante la sequenza di INTA. Ogni 8259 deve essere programmato sulla modalità opportuna. I comandi di EOI per livelli interruzione provenienti da slave vanno ripetuti due volte, una per il master e una per lo slave a cui ci si sta riferendo. Quando uno slave ha una richiesta di interrupt su un suo livello, viene inviata una richiesta sul pin IR del master mediante il segnale di INT. Tale richiesta è inoltrata dal master alla CPU solo nel caso in cui tal elivello non sia mascherato e sia quello ad aver fatto richiesta con priorità maggiore. Quando la CPU invia il primo segnale, il master setta l'opportuno bit del registro ISR, pulisce il corrispondente bit IRR e verifica se tale richiesta proviene da uno slave oppure no, mediante la lettura del registro ICW3. Se la richiesta non proviene da uno slave, il master invia sul data bus il contenuto di ICW2 corrispondete all'indice della routine di servizio dell'interruzione.
Nei PC attuali le interruzioni mascherabili sono gestiti da una coppia di dispositivi: due 8259A (o compatibili) collegati in modalità master-slave. In questo modo un PC è in grado di gestire 15 tipi di interrupt diversi (7 sul master e 8 sullo slave). In più le interruzioni non mascherabili sono collegate direttamente alla logica di rilevamento degli errori di parità, presente nella memoria dinamica, oppure al timer-counter programmabile o infine ad un segnale del BUS ISA.
Nel momento in cui arriva una richiesta di interrupt, essa viene memorizzata all'interno dell'8259, nell'interrupt register. Se successivamente giunge un'altra richiesta, anche essa viene accodata. L'8259 manda INT e attende il segnale di INTA dalla CPU. Quando questo arriva, il priority resolver si occupa di selezionare l'interrupt a priorità maggiore all'interno della coda, settando un bit nel service register. A questo punto viene eseguita la normale procedura dell'8259.
Gestione della routine di interrupt
Le interruzioni nei pc moderni avvengono, come già detto in diversi modi a seconda della priorità dei dispositivi ad esse associati. Le interruzioni non mascherabili sono gestite direttamente dalla CPU mediante il piedino NMI, quelle mascherabili sono connesse alla coppia di 8259 mediante il piedino INT.
Quando la CPU riceve una richiesta di interrupt e il flag IF vale 1, essa inizia l'esecuzione della procedura di servizio dell'interruzione (Interrupt service routine, ISR). Ciascuna ISR è una normale procedura assembler che però soddisfa alcuni requisiti particolari in modo da garantire la convivenza con il programma in esecuzione. Prima di tutto deve inizializzare l'8259 e inizializzare il vettore interruzione (fase di boot). In più gli interrupt sono disabilitati di default, quindi, se si ha necessità di riabilitarli bisogna operare su STI (per abilitarli tutti), Mask Register (per abilitarne alcuni), EOIn (per abilitarne uno in particolare).
Ciascuna ISR viene attivata all'insaputa del programma in esecuzione quindi con DS, ES, SS, stack e registri del programma interrotto.
E' necessario che al termine dell'esecuzione di una ISR il sistema sia configurato nella stessa condizione precedente alla chiamata. Per tornare al programma iniziale è necessario chiamare IRET.
Se si vuole chiamare altre procedure bisogna assicurarsi che la chiamata sia di tipo FAR, altrimenti il CS potrebbe essere modificato. Per evitare problemi è meglio salvare nello stack tutti i registri a meno del CS e IP che vengono automaticamente ripristinati con la chiamata della IRET.
Siccome lo stack è già usato dal programma in esecuzione è meglio non abusarne (4/6 chiamate).
Non è possibile attivare chiamate a funzione DOS o BIOS (INT 21h,…), in quanto non è codice rientrante.
Se la procedura non è di alta priorità è bene fare in modo che altri interrupt abbiano maggiore precedenza: si ottiene questo risultato chiamando l'istruzione STI.
Prima di chiudere la ISR è bene riabilitare le future interruzioni con il comando EOI all'8259.
Per comunicare con il programma principale è bene utilizzare variabili globali, che verranno controllate periodicamente dal programma principale. Nell'accedere a variabili globali bisogna inserire il valore corretto nel registro DS.
In più bisogna aggiornare i dati dei registri, memorie,… dei periferici che hanno invocato la chiamata di interrupt.
Per attivare una ISR è necessario scrivere il suo indirizzo nella Interrupt Vector Table, abilitare l'8259 e gli eventuali latch che in alcuni PC bloccano alcune interruzioni.
Driver e periferiche
Quando si progetta un driver per una periferica, non bisogna solo gestire gli interrupt, che questa dovrà scatenare, ma bisognerà anche progettare i metodi con cui essa comunicherà con il SO. I driver accedono all'8259 in modo da abilitare/disabilitare un canale di interruzione, mandare comandi di INT, modificare le priorità.
Interrupt nei sistemi multiprocessore
Quando arriva un interrupt bisogna decidere a quale processore inviarlo e le reazioni che deve avere l'altro processore. La gestione di interrupt in sistemi a più processori è un problema abbastanza complesso. APIC è un sistema di gestione delle interruzioni avanzato, in grado di gestire in modo coerente gli interrupt in un sistema multiprocessore.
APIC decide a chi inviare gli interrupt in base al carico di ciascun processore. In più invia gli interrupt provenienti dalla stessa periferica allo stesso processore, in modo da evitare conflitti.
| < Prec. | Succ. > |
|---|





