Do spisu treści tematu 5

5.3.1 Opis przerwań sprzętowych (IRQ) w systemie Linux (i386)




Spis treści


Ponieważ Linux działa w trybie chronionym, więc cały poniższy opis dotyczy właśnie tego trybu.

Opis przerwań i wyjątków na procesorach x86

Przerwaniami i wyjątkami (ang. interrupts and exceptions) nazywamy takie zmiany przepływu sterowania w programie, które powodują wywołanie specjalnej, wspólnej dla wszystkich programów, procedury obsługi (ang. handler). Nie są to więc lokalne procedury, lecz globalne metody obsługi pewnych specjalnych sytuacji. Zasadniczo przerwania i wyjątki mogą mieć trzy przyczyny:

Obsługa przerwań i wyjątków polega na przerwaniu wykonywania programu i przekazaniu sterowania do procedury obsługi. Procedura obsługi wykonuje następnie powrót do przerwanego programu, odtwarzając jego stan (o ile nie nastąpiło w wyniku wykonania procedury przełączenie kontekstu).

Każde przerwanie lub wyjątek ma przypisaną jednobajtową nieujemną liczbę całkowitą, zwaną wektorem (ang. interrupt vector). Wektor służy do identyfikacji przerwania lub wyjątku.

Przerwania zewnętrzne

Stare procesory Intela (w tym niektóre modele Pentium) miały następujące przyporządkowanie źródeł przerwań zewnętrznych:

W nowszych procesorach Intela źródła przerwań są inne - istnieje specjalny wbudowany lokalny sterownik przerwań (ang. local Advanced Programmable Interrupt Controller), ale w normalnych warunkach ten sterownik symuluje zachowanie starszych wersji. Nie będę się tu zajmował tymi nowościami.

Przerwanie NMI nie może zostać zablokowane przez procesor (stąd nazwa). Związany jest z nim wektor 2. Wystąpienie przerwania NMI oznacza bardzo poważne kłopoty.

Przerwania sygnalizowane na INTR pochodzą ze sterownika przerwań zewnętrznych, tak zwanego PIC (Programmable Interrupt Controller). W komputerach typu PC AT używany jest układ 8259A, podłączony do INTR na procesorze. Do tego układu jest podłączony drugi, również 8259A. W komputerach PC XT znajduje się tylko jeden taki układ.

Przerwania pochodzące z INTR są maskowalne, tzn. procesor może odmówić przyjmowania tych przerwań (w szczególności jeśli flaga IF jest wyzerowana, to tak się dzieje). Jeżeli PIC chce przekazać procesorowi przerwanie, to wysyła mu również wektor tego przerwania. teoretycznie ten wektor może być dowolną liczbą od 0 do 255. W praktyce przerwań sprzętowych jest 16 i są im przypisane konkretne numery (opisuję to później).

Przerwania programowe

Przerwanie może zostać wywołane przez program, gdy wykona on instrukcję
INT n,
gdzie n jest dowolnym wektorem. Instrukcję tę można wykonać niezależnie od wartości flagi IF. W wypadku wywołania z wektorem przerwania NMI wołana jest procedura obsługi tego przerwania, ale nie są wykorzystywane żadne specjalne mechanizmy sprzętowe normalnie używane przy NMI.

Wyjątki

Wyjątki pochodzą zawsze z wewnątrz procesora. Zwykle ich przyczyną jest błąd w wykonaniu instrukcji - ale raczej nie błąd sprzętowy. Niektóre wyjątki są podnoszone jako reakcja na pewne specjalne instrukcje, np. BOUND - jest to jednak rzadko spotykane. Podczas podnoszenia niektórych wyjątków procesor umieszcza na stosie dodatkowo kod błędu, który ma wyjaśniać przyczynę podniesienia wyjątku. Ponieważ wyjątki mają przypisane wektory tak samo jak przerwania, więc można wywołać procedurę obsługi wyjątku za pomocą instrukcji INT n. Jednak spowoduje to jedynie wywołanie procedury obsługi, natomiast żaden kod błędu nie zostanie umieszczony na stosie. W związku z tym podczas powrotu z procedury obsługi zostanie zdjęty ze stosu kod, którego tam nie ma. Spowoduje to powrót w złe miejsce i nieprzewidywalne konsekwencje.

Wyjątki dzieli się na trzy rodzaje, przy których angielskich nazwach pozostanę: faults,traps i aborts. Różnią się one zachowaniem procesora podczas ich wystąpienia. Wyjątki mają na stałe przyporządkowane numery, tak więc można zawsze powiedzieć, jakiego wyjątek o numerze n jest rodzaju. Oto różnice między rodzajami wyjątków:

faults
Są to wyjątki, po których obsłudze próbuje się ponownie wykonać instrukcję, która spowodowała błąd (zrestartować ją). Przykładem takiego wyjątku jest błąd braku strony (próbuje się ściągnąć stronę do pamięci i ponownie wykonać instrukcję dostępu do niej).
traps
Są to wyjątki, które następują po wykonaniu jednej instrukcji, a przed wykonaniem nastepnej. Procedura obsługi takich wyjątków wraca do tej niewykonanej instrukcji i ją wykonuje. Zatem w działaniu programu nie ma żadnych nieregularności - przepływ sterowania jest zwyczajny.
aborts
Są to wyjątki, z których nie ma powrotu do przerwanego programu. Najczęstszym jest opisany dalej błąd podwójny (ang. double fault).

Wyjątki i przerwania predefiniowane
WektorSkrótNazwaRodzajKod błęduŹródło
0#DEBłąd dzieleniaFault-DIV i IDIV
1#DBDebugFault/Trap-Różnie
2--NMIPrzerwanie-sygnał NMI
3#BPPułapkaTrap-INT 3
4#OFNadmiarTrap-INTO
5#BRIndeksowanie poza tablicęFault-BOUND
6#UDNiezdefiniowana instrukcjaFault-UD2 (Pentium) lub niedozwolona instrukcja
7#NMBrak koprocesoraFault-Instrukcja zmiennopozycyjna lub WAIT
8#DFBłąd podwójnyAbort+Różnie
9--???Fault-Instrukcja zmiennopozycyjna
10#TSBłąd w TSSFault+Zmiana zadania lub odwołanie do TSS
11#NPBrak segmentuFault+Ładowanie rejestrów segmentowych itp.
12#SSBłąd segmentu stosuFault+Operacje na stosie lub SS
13#GPBłąd ochronyFault+Nieuprawniony dostęp
14#PFBłąd stronicowaniaFault+Odwołanie do pamięci
15--zarezerwowane---
16#MFBłąd zmiennopozycyjnyFault-Instrukcja zmiennopozycyjna lub WAIT
17#AC???Alignment CheckFault+Odwołanie do pamięci
18#MC???Machine CheckAbort-Zależy od modelu
19-31--zarezerwowane
32-255--Przerwania niezarezerwowanePrzerwanieSterownik 8259A lub INT n

Maskowanie przerwań i wyjątków

Maskować (blokować) można jedynie przerwania otrzymywane przez procesor poprzez INTR. Jeżeli flaga IF jest wyzerowana, to przerwania pochodzące z INTR są ignorowane. Natomiast wyjątki generowane przez procesor oraz przerwanie NMI nie są blokowane. Również instrukcja INT n wykonuje się normalnie. Teoretycznie z INTR procesor może otrzymać wektor, który odpowiada wyjątkowi, a nie przerwaniu (np. 14). Takiej sytuacji nie nazywamy wyjątkiem, lecz przerwaniem - takie przerwanie jest maskowalne i nie wykonuje się jak wyjątek (tzn. kod błędu nie jest umieszczany na stosie).

Przerwanie NMI nie jest maskowalne, jednak procesor automatycznie blokuje dalsze przerwania NMI do wykonania najbliższej instrukcji IRET. Dlatego NMI należy obsługiwać z IF=0 - inaczej IRET od zwykłego przerwania ponowanie odblokuje NMI.

Istnieje jeszcze flaga RF (ang. Resume Flag), która maskuje wyjątek #DB, ale nie będę jej tu omawiał.

Tablica Deskryptorów Przerwań (IDT)

IDT, czyli Interrupt Descriptor Table jest tablicą systemową, w której każdemu z 256 wektorów odpowiada jeden deskryptor bramy. W rejestrze IDTR znajduje się adres IDT (tzn. 32 bity adresu bazowego i 16 bitów ograniczenia). Jeżeli procesor ma obsłużyć przerwanie lub wyjątek o wektorze x, to po wykonaniu czynności wstępnych (np. umieszczeniu kodu błędu na stosie), znajduje początek IDT patrząc na IDTR, potem dodaje do tego 8*x (8 jest rozmiarem deskryptora) i przechodzi przez bramę określoną przez ten deskryptor.

Deskryptory bram dzielą się na trzy rodzaje:

Przez różne bramy przechodzi się w różny sposób. Przejście przez bramę zadania wiąże się ze zmianą kontekstu. Bramy przerwań i potrzasków są podobne do siebie - przejście przez nie polega na na dalekim skoku do wskazywanego przez deskryptor punktu bez zmiany kontekstu. Jeżeli jednak następuje przy tym zmiana poziomu uprzywilejowania, to następuje zmiana stosów. Podczas powrotu przez taką bramę wraca się również do swojego poprzedniego stosu. Bramy przerwań i potrzasków różnią się jedynie tym, że przejście przez bramę przerwania powoduje automatyczne wyzerowanie IF, natomiast przejście przez bramę potrzasku nie modyfikuje tej flagi.

Działania procesora po otrzymaniu przerwania lub wyjątku przy przechodzeniu przez bramy przerwań lub potrzasków

Procesor, chcąc wywołać przerwanie lub wyjątek x robi co następuje:

  1. Umieszcza na stosie flagi, CS i EIP (w tej kolejności)
  2. Jeżeli wyjątek posiada kod błędu, to jest on umieszczany na stosie
  3. Jeżeli procedura obsługi ma ten sam poziom uprzywilejowania, to nie zmienia się stosu
  4. W przeciwnym wypadku:
    1. Z segmentu TSS pobiera wskaźnik nowego stosu
    2. Umieszcza na nim SS i ESP starego stosu (te sprzed rozpoczęcia tego algorytmu)
    3. Umieszcza na nim flagi, CS, EIP i kod błędu
  5. Zeruje flagi TF, VM, RF i NT
  6. Wykonuje skok do procedury obsługi opisanej w bramie (ewentualnie zeruje IF)

Powrót z procedury obsługi następuje przez instrukcję IRET. Wykonuje ona zwykły powrót zdejmując jeszcze na koniec flagi ze stosu. Jeżeli jest to konieczne, to następuje ponowna zmiana stosów. Zdjęcie ze stosu kodu błędu nie następuje automatycznie - procedura obsługi musi go sama usunąć.

Błąd podwójny (Double Fault)

Błąd podwójny jest błędem typu Abort. Występuje on, gdy procesor wygeneruje jedno przerwanie lub wyjątek podczas obsługiwania drugiego. Zwykle taka sytuacja nie powoduje błędu, jednak na przykład podniesienie #PF (Page Fault podczas obsługiwania #PF generuje #DF. Po wygenerowaniu #DF w zasadzie nic się już nie da zrobić, można jedynie wyświetlić przykry komunikat.


Przerwania sprzętowe. Sterownik przerwań 8259A

W komputerach typu PC XT przerwania od urządzeń zewnętrznych były przekazywane do układu 8259, który następnie mógł je przekazać procesorowi. Układ ten, zwany PIC, był przyłączony do wejścia INTR procesora i przez to wejście sygnalizował żądanie obsługi przerwania. Do PIC można było przyłączyć 8 urządzeń, z których każde generowało inne przerwanie. Tych 8 wejść PIC, do których można przyłączyć urządzenia, nazywa się liniami IRQ (ang. Interrupt Request Lines). Tak więc na PC XT można było obsługiwać co najwyżej 8 różnych przerwań sprzętowych.

Rejestry układu 8259A

Do układu 8259A może być podłączonych 8 linii IRQ. Sygnały z tych linii przechodzą przez ESR (Edge Sense Register) do IRR (Interrupt Request Register). Niektóre z nich mogą być w danym momencie zamaskowane (jeżeli system operacyjne wysłał do PIC odpowiednia komendę). W rejestrze IMR (Interrupt Mask Register) znajduje się maska przerwań. Jeżeli bit x jest ustawiony, to linia IRQ o numerze x jest blokowana (tzn. przerwania z niej nie są przyjmowane). PIC posiada jeszcze jeden rejestr - bit x jest w nim ustawiony, jeśli PIC wysłał do na swoje wyjście (czyli zwykle do procesora) żądanie przerwania, a nie otrzymał jeszcze sygnału EOI, oznaczającego zakończenie obsługi przerwania. Ten rejestr nazywa się ISR (Interrupt Service Register).

Przerwania na PIC mają swoje priorytety - przerwania przyłączone do linii IRQ o niższych numerach mają wyższy priorytet. Linie IRQ numeruje się od zera do siedmiu (IRQ0-IRQ7).

Metoda działania PIC

Jako pierwszy przykład zobaczmy, co się dzieje, jeśli jesteśmy na PC XT, żadne przerwania nie są ani zamaskowane, ani obsługiwane, ani aktywne:

  1. Nasze założenie: ESR, ISR, IRR, IMR są wyzerowane
  2. Przez IRQ3 przechodzi sygnał od urządzenia
  3. Bit 3 rejestru ESR zostaje ustawiony
  4. Bit 3 rejestru IRR zostaje ustawiony
  5. Ponieważ bit 3 rejestru IMR jest wyzerowany (bo przerwanie IRQ3 nie było zamaskowane), więc wartość bitu 3 z IRR jest przekazywana dalej
  6. Ponieważ żadne przerwanie nie jest obsługiwane (ISR jest zero), więc IRQ3 jest przekazywane dalej
  7. Przez wyjście PIC puszczany jest sygnał
  8. Procesor otrzymuje sygnał z PIC na swoje wejście INTR
  9. Procesor odpowiada sygnałem INTA - PIC blokuje rejestr IRR i wybiera z niego przerwanie o najwyższym priorytecie (w tym wypadku IRQ3)
  10. PIC ustawia bit 3 rejestru ISR (przerwanie IR3 jest obsługiwane)
  11. Ustawienie bitu w ISR powoduje wyzerowanie bitu w ESR
  12. Procesor wysyła drugi sygnał INTA - PIC wysyła wektor związany z bitem o najniższym numerze w ISR (IRQ3) na szynę systemową. PIC odblokowuje rejestr IRR
  13. PIC zeruje bit 3 w IRR
  14. Procesor jakoś obsługuje przerwanie odpowiadające wektorowi umieszczonemu przez PIC na szynie. Po zakończeniu tej obsługi wysyła do PIC sygnał EOI (End of Interrupt), co powoduje wyzerowanie bitu w rejestrze ISR.
Powyższe zachowanie opisuje działanie w tzw. Edge-triggered mode. W tym trybie IRQ są sygnalizowane przez zmianę napięcia, a nie po prostu przez wysokie (lub niskie) napięcie na linii IRQ. Jeżeli IRQ3 pozostanie aktywna po powyższych krokach, nie powoduje to kolejnego przerwania. W tzw. Level mode przerwania są sygnalizowane odpowiednim napięciem na linii IRQ. Edge triggered mode pozwala na wspołdzielenie jednej linii IRQ przez wiele urządzeń (inaczej przerwania mogłyby ginąć). Z punktu widzenia systemu operacyjnego te tryby nie są tak bardzo istotne.

Komunikacja procesora z PIC

Procesor otrzymuje od PIC sygnały przez wejście INTR i reaguje na nie automatycznie. Jeżeli jednak chcemy wysłać do PIC sygnał EOI albo zamaskować jakieś przerwanie, to jest nam potrzebna jakaś droga komunikacji. Tą drogą są specjalne porty wejścia-wyjścia, przez które można kontrolować PIC. Dla PC XT są to 0x20 i 0x21. Służą one m.in. do inicjalizacji PIC, ale o tym nie będę pisał.

Chcąc zamaskować przerwanie IRQ o numerze x musimy mieć dostęp do rejestru IMR układu 8259A. Rejestr ten znajduje się pod portem wejścia-wyjścia o numerze 0x21. Jedynka w tej masce oznacza, że przerwanie jest zamaskowane. Jeżeli nie wiemy, jak wygląda teraz maska, a chcemy zamaskować przerwanie IRQ x, to musimy najpierw odczytać ten port, a następnie zapisać do tego portu (wartość odczytana OR 1<<x).

Z kolei komendy do PIC wysyłamy do portu 0x20, gdzie znajduje się tzw. Interrupt Command Register. Przykładowo tzw. komenda non-specific End of Interrupt ma numerz 0x20, zatem wysyłamy ją pisząc do portu 0x20 liczbę 0x20.

Sygnał End of Interrupt jest bardzo ważny - jeżeli nie zostanie wysłany, to żadne przerwanie o priorytecie mniejszym równym od tego, na które nie odpowiedzielismy EOI, nie zostanie obsłużone. Wysłanie EOI powoduje ponowne odblokowanie tych przerwań.

Chcąc pisać do lub czytać z rejestrów PIC musimy wcześniej zablokować przerwania instrukcją cli. Ponieważ w momencie otrzymania przerwania, które jest obsługiwane przez bramę przerwań, procesor sam zeruje flagę IF, więc przy wejściu do procedury obsługi możemy od razu działać na portach PIC.

Sterowanie przerwaniami przez dwa układy 8259A

Ponieważ na PC XT było tylko 8 linii przerwań, więc szybko zaczęto odczuwać brak wolnych linii. W związku z tym połączono ze sobą dwa układy 8259A, które łącznie zapewniały obsługę 16 linii przerwań. Ponieważ wejście INTR na procesorze pozostało tylko jedno, więc połączono je w łańcuch - drugi PIC jest podłączony do pierwszego, które jest podłączony do INTR na procesorze. Pierwszy PIC jest nazywany Master PIC, drugi Slave PIC. Drugi PIC jest na komputerach AT podłączony do linii IRQ2 w pierwszym PIC. W związku z tym przerwanie IRQ2 nie może być już wykorzystane przez żadne inne urządzenie (czyli mamy naprawdę 15 wolnych linii przerwań).

Jak już wspominałem, priorytet mają przerwania o niższych numerach. Ze względu na podłączenie drugiego PIC do IRQ2, najwyższy priorytet mają przerwania IRQ0, IRQ1 (pierwszy PIC), dalej IRQ8-IRQ15 (drugi PIC), a na koniec IRQ3-IRQ7 (pierwszy PIC). Skutkiem użycia dwóch układów 8259A mamy też kolejne dwa porty wejścia-wyjścia do obsłużenia:

Ponieważ drugi PIC jest podłączony do IRQ2, więc otrzymując przerwanie z drugiego PIC musimy wysłać dwa sygnały EOI - najpierw do drugiego PIC, następnie do pierwszego.

Standardowe funkcje IRQ

Niektórym numerom IRQ przypisane są standardowe funkcje. Funkcje te opisane są w następującej tabeli:

Numer przerwaniaNumer sterownikaFunkcje
IRQ01Zegar systemowy - wyjście 0
IRQ11Klawiatura
IRQ21"Cascade" - połączenie z drugim PIC
IRQ31Port szeregowy, inne
IRQ41Port szeregowy, inne
IRQ51Audio, inne
IRQ61Stacja dyskietek
IRQ71Port równoległy
IRQ82Zegar czasu rzeczywistego
IRQ9-122Różnie
IRQ132Koprocesor matematyczny
IRQ142Twardy dysk
IRQ152Drugi twardy dysk

W dzisiejszych komputerach i procesorach architektura się poważnie zmieniła (nie ma już wejść INTR i NMI, na szynie PCI obsługa przerwań jest inna), ale zachowano kompatybilność z opisanym tu modelem - nowe, lepsze rozwiązania potrafią symulować stare - w systemie Linux nie korzysta się chyba z tych nowych możliwości.


Przerwania sprzętowe w systemie Linux

Obsługa przerwań sprzętowych w systemie Linux jest rozrzucona po paru plikach:

Osobiście opisałem pliki irq.c oraz irq.h. Plikami entry.S, softirq.c oraz interrupt.h zajął się chyba ktoś od procesów.

Kilka uwag o czytaniu kodu źródłowego

Kod źródłowy w języku C zawierający wstawki w GNU asemblerze jest ohydny z wyglądu. Dodatkowo jest całkowicie niekompatybilny ze zwykłym asemblerem intelowskim:

Wstęp do obsługi przerwań sprzętowych w Linuxie

Zasadniczo przerwania sprzętowe w systemie Linux są obsługiwane przez bramy przerwań. Przerwaniom IRQ0-IRQ15 odpowiadają wektory 0x20-0x2F - tak jest inicjalizowany układ 8259A. Nową niskopoziomową procedurę przerwania rejestruje się w IDT za pomocą makra set_intr_gate(n, addr), gdzie n oznacza wektor przerwania, a addr adres procedury obsługi. Makro to jest zdefiniowane w pliku system.h.

Przerwanie IRQx może być obsługiwane przez trzy rodzaje niskopoziomowych procedur: IRQx_interrupt, fast_IRQx_interrupt oraz bad_IRQx_interrupt. Pierwsza z nich jest używana dla przerwań obsługiwanych bez flagi SA_INTERRUPT, druga dla tych z flagą SA_INTERRUPT, trzecia dla przerwań w ogóle nie zarejestrowanych. Procedury te są faktycznie zdefiniowane w irq.c za pomocą makr z irq.h. W pierwszym z tych plików są też zadeklarowane trzy statyczne tablice, w których znajdują się adresy tych procedur.

Podczas obsługi przerwań używa się wielokrotnie makr zachowujących rejestry:

Ogólne metody obsługi przerwań sprzętowych

W Linuxie cały czas mamy pod ręką informację, które przerwania są zamaskowane: wartości rejestrów IMR obu sterowników znajdują się w zmiennych cache_21, cache_A1. Dzięki temu nie musimy odczytywać portów 0x21 i 0xA1.

Ogólny algorytm obsługi przerwań jest następujący (x - numer przerwania):

  1. Zachowaj rejestry
  2. Zamaskuj przerwanie x (zmiana jest też zapisywana w cache_21/A1)
  3. Wyślij EOI do sterownika(ów)
  4. Zwiększ intr_count
  5. Obsłuż przerwanie x (procedurą wyższego poziomu)
  6. Odmaskuj przerwanie x (zmiana jest też zapisywana w cache_21/A1)
  7. Zmniejsz intr_count

Różnice między procedurami obsługi dotyczą spraw następujących:

Jeżeli nikt nie zarejestrował własnej procedury obsługi IRQx, to jest ona obsługiwana przez bad_IRQx_interrupt. Ta procedura robi następujące rzeczy:

  1. Wykonuje SAVE_MOST
  2. Zamaskowuje wywołane przerwanie
  3. Wykonuje RESTORE_MOST
Jak widać jedynym skutkiem wywołania przerwania bez procedury obsługi jest jego zamaskowanie.

Procedury obsługi przerwań sprzętowych (wyższego poziomu)

Każde przerwanie ma związaną ze sobą listę struktur irqaction. Tablica tych lista nazywa się irq_action. Struktura tak zawiera w sobie pewne informacje o rodzaju przerwania, dowiązanie do następnego elementu listy oraz adres procedury obsługi zarejestrowanej np. przez podprogram obsługi jakiegoś urządzenia. Jeżeli jakieś przerwanie zostanie wywołane, to wykonają sie po kolei wszystkie procedury obsługi znajdujące się na liście.

Do rejestrowania nowych procedur obsługi służy funkcja request_irq, do odrejestrowywania funkcja free_irq. Funkcje te dodają po prostu nową strukturę do listy lub usuwają tę strukturę z listy. Jeżeli jednak przerwanie było dotychczas nie obsługiwane, to trzeba jeszcze wywołać set_intr_gate, by przerwanie było obsługiwane przez (fast_)IRQx_interrupt, a nie bad_IRQx_interrupt. Odwrotne działanie następuje w momencie odrejestrowywania ostatniej procedury obsługi dla danej linii IRQ.

Inicjalizacja przerwań sprzętowych polega na wywołaniu set_interrupt_gate dla każdego przerwania z procedurą obsługi bad_IRQx_interrupt. Dodatkowo jeszcze inicjalizuje się zegar i ustanawia standardowe procedury obsługi przerwań IRQ2 ("cascade") i IRQ13("math error").

Obsługa przerwań "szybkich"

Procedury obsługi przerwań dzielą się na "szybkie" i "wolne". Procedury "szybkie" są obsługiwane przez fast_IRQx_interrupt, a "wolne" przez IRQx_interrupt. Opiszę najpierw działanie procedur "szybkich" (są prostsze).

Algotytm obsługi procedury szybkiej (niskopoziomowy) jest następujący:
  1. SAVE_MOST
  2. Zamaskuj przerwanie
  3. Wyślij EOI
  4. Zwiększ intr_count
  5. Wywołaj do_fast_IRQ z numerem przerwania jako parametrem
  6. CLI (na wszelki wypadek; IF powinno i tak być 0)
  7. Odmaskuj przerwanie
  8. Zmniejsz intr_count
  9. RESTORE_MOST
Funkcja do_fast_IRQ po prostu wykonuje wszystkie zarejestrowane dla tego przerwania procedury obsługi.

Obsługa przerwań "wolnych"

Przerwania "wolne" (czyli zwykłe) obsługuje się bardzo podobnie do "szybkich":

  1. Umieść numer przerwania-2 na stosie (konieczne ze względu na budowę RESTORE_ALL w pliku entry.S)
  2. SAVE_ALL
  3. Zamaskuj przerwanie
  4. Wyślij EOI
  5. Zwiększ intr_count
  6. STI
  7. Wywołaj do_IRQ z numerem przerwania jako parametrem oraz wskaźnikiem do zapamiętanych rejestrów jako parametrami
  8. CLI (na wszelki wypadek; IF powinno być 0)
  9. Odmaskuj przerwanie
  10. Zmniejsz intr_count
  11. Skocz do ret_from_sys_call
Funkcja do_IRQ praktycznie niczym się nie różni do do_fast_IRQ. Jest jednak wykonywana przy zablokowanych przerwaniach.

W wypadku przerwań zachowanie przy wywołaniu funkcji ret_from_sys_call zależy od wartości zmiennej intr_count. Jeżeli zmienna ta ma wartość większą od zera, to znaczy, że wracamy z obsługi przerwania, które nastąpiło podczas obsługi innego przerwania. W takiej sytuacji wykonuje się jedynie makro RESTORE_ALL. Jeżeli jednak intr_count jest zero, to wykonuje się pełny powrót z funkcji systemowej: obsługuje się tzw. dolne połowy, sygnały i wykonuje ewentualnie reschedule.

Przerwanie zegarowe jest obsługiwane tak, jak inne, z małym wyjątkiem: przerwania są podczas jego obsługi zawsze zablokowane. Wynika to stąd, że zmienna jiffies jest używana przez niektóre przerwania do obliczania opóźnień itp. Gdyby jakieś przerwanie było wywołane podczas obsługi przerwania zegarowego, to zmienna jiffies by się nie zmieniła - przerwanie zegara byłoby bowiem zamaskowane (jako jedyne).

Poszukiwanie IRQ odpowiadających jakiemuś urządzeniu itp.

Jeżeli chcemy znaleźć IRQ, na którym siedzi nasze urządzenie, to według rad z pliku interrupt.h powinniśmy zrobić co następuje:

  1. Wyzeruj wewnętrzne przerwania urządzenia
  2. sti();
  3. irqs = probe_irq_on(); irqs to teraz maska tych przerwań, które nie mają procedur obsługi i nie są aktywne. Zatem nasze urządzenie siedzi na jednym z tych przerwań. Jest istotne, że przerwania, które występują, choć nie powinny (tzn. nie są obsługiwane, ale w rzeczywistości zachodzą), nie są zwracane w tej masce.
  4. Spowoduj, by urządzenie wywołało przerwanie
  5. Czekaj, aż urządzenie wywoła przerwanie (np. za pomocą opóźnienia)
  6. irq = probe_irq_off(irqs); irq to numer przerwania spośród tych w irqs, które istotnie zaszło. Jeśli żadne nie zaszło, to zwracamy 0, jeśli zaszło wiele to zwracamy -numer_największego_przerwania.
  7. Obsłuż jakoś przerwanie od urządzenie (żeby się nie złościło)

Przerwania a generator liczb losowych

Funkcje do_IRQ oraz do_fast_IRQ wykonują jeszcze jedną, dotychczas przeze mnie nie opisaną funkcję. Otóż jeżeli którakolwiek spośród procedur obsługi znajdujących się na liście odpowiadającej przerwaniu IRQx ma ustawioną flagę SA_SAMPLE_RANDOM, to funkcje te wywołują add_interrupt_randomness. To wywołanie powoduje zwiększenie "entropii" generatora i , w konsekwencji, prowadzi do uzyskiwania liczb losowych, a nie jedynie pseudolosowych.


Bibliografia


Autor: Piotr Hoffman