Keskeytykset ja poikkeukset
Tekijä: Yariv Kaplan
Suomentanut Jouni Kähkönen 21.4.2005, 21.9.2005, 24.3.2007, 30.4.2007
Tietokoneen toimintaa ohjataan suorittimen lisäksi monin eri laittein. Esimerkiksi sarjaportin tietoliikennettä ohjaa emolevyn (täsmällisemmin ASIC-yksikön) Intel 8251A -piiri (tai uusissa koneissa 16550AF-piiri), ja näppäimistöä ohjaa 8042A-mikrosuoritin.
Koska laitteet toimivat kaikki omilla nopeuksillaan, tarvitaan jokin menetelmä suorittimen toiminnan ja muiden laitteiden synkronoimiseen. Eräs ratkaisu on, että suoritin kiertää nopeasti silmukkaa kysyen koko ajan laitteilta niiden senhetkistä tilaa (menetelmää kutsutaan kiertokyselyksi, engl. polling). Kun tiedot on noudettavissa laitteelta, suoritin voi lukea ja käsitellä saapuvat tavut. Toimiihan tämäkin menetelmä, mutta se on monin tavoin ongelmallinen. Ensinnäkin se on todella tuhlaava käsittelyn tehokkuuden suhteen, sillä suoritin joutuu olemaan koko ajan varattuna lukiessaan oheislaitteiden tiloja, vaikka se voisi sen ajan suorittaa jotain hyödyllistä koodia. Toisekseen datan siirtotahdin ollessa hyvin suuri suoritin saattaa hävittää laitteilta saapuvaa dataa.
Täten keksittiin toisenlainen toimintamalli. Laitteilta ei pyydetä koko ajan vastausta, vaan ne ovat itse vastuussa tilansa ilmoittamisesta suorittimelle. Tarvitessaan huomiota suorittimelta laite vain lähettää sähkösignaalin (ns. laitteistokeskeytyksen, engl. hardware interrupt) emolevyllä sijaitsevan keskeytysohjainpiirin tiettyyn pinniin.
Keskeytysohjain toimii välikappaleena suorittimen ja laitteiden välillä. Sen vastuulla on ilmoittaa suorittimelle siitä, että jokin laite tarvitsee siltä välitöntä huomiota. Tällaisessa tapauksessa suoritin keskeyttää senhetkisen toimintansa ja siirtyy suorittamaan toimintoa (eli keskeytyksenkäsittelijää, engl. interrupt handler), joka on aikaisemmin yhdistetty kutsuvaan laitteeseen (tai tarkalleen sanottuna laitteen keskeytysvektoriin yhdistettyyn laitteeseen).
Ohjelmistokeskeytyksillä on laitteistokeskeytysten tavoin tärkeä asema PC:n perustoiminnassa. Nämä keskeytykset ovat pikemminkin synkronisia kuin asynkronisia, sillä ne ovat itsensä suorittimen aikaansaamia (suorittimen tavatessa koodivuossa INT-käskyn). Käyttöjärjestelmät julkaisevat sisäiset funktionsa ohjelmistokeskeytyksillä, jotta sovellukset voivat käyttää järjestelmän palveluita hyödyksi.
Poikkeukset (engl. exceptions) ovat erityisen kaltaisia ohjelmistokeskeytyksiä. Suoritin aiheuttaa poikkeuksen, kun jokin odottamaton ja kriittinen tapahtuma ilmenee. Esimerkiksi sivutushäiriöpoikkeus (keskeytys 14, engl. page fault exception) laukaistaan suorittimen yrittäessä käyttää käyttämättömäksi merkittyä sivua. Poikkeuksenkäsittelijä voi sitten ladata sivun levyltä eli näennäismuistista takaisin muistiin ja suorittaa poikkeuksen aiheuttaneen käskyn uudestaan.
Suoritin osaa aiheuttaa kolmenlaisia poikkeuksia: vikoja (fault), ohjelmallisia keskeytyksiä (trap) ja virhelopetuksia (abort). Vikapoikkeuksen sattuessa pinoon viedyt CS- ja (E)IP-rekisterit osoittavat poikkeuksen aiheuttaneen käskyn osoitteeseen. Tämä antaa poikkeuksenkäsittelijälle mahdollisuuden korjata poikkeuksen aiheuttaneen ehdon, ennen kuin vian aiheuttanut käsky suoritetaan uudelleen. Ohjelmalliset keskeytykset ovat hieman samankaltaisia kuin keskeytykset. Ohjelmalliset keskeytykset nimittäin panevat suorittimen tallentamaan pinoon seuraavan käskyn osoitteen. Ne myös keskeyttävät häiriköineen sovelluksen ja määrittelevät häiriön tehneen käskyn sijainnin, jotta ne voitaisiin näyttää käyttäjälle peruuttamattomien vakavien virheiden ilmetessä (kuten laitteistovirheet ja laittomat järjestelmätaulut).
ReaalitilaJos olet joskus ohjelmoinut DOS-järjestelmällä, tietänet INT 21h -liittymällä olleen tärkeä merkitys sovellusten yhdistämisessä käyttöjärjestelmäpalveluihin. Esimerkiksi käyttöjärjestelmän tiedostonavauskomennon käyttö vaatii INT 21h -keskeytyksen kutsumista sopivin rekisteriparametrein.
BIOS eli Basic Input Output System käyttää samankaltaista ohjelmistokommunikointijärjestelmää. INT 10h, 13h ja 16h ovat näyttöä, levyohjainta ja näppäimistöä ohjaavia BIOS-järjestelmän sisäisiä toimintoja. Laitteiston välittömän käytön sijasta DOS ohjaa järjestelmän toimintaa BIOS-palveluilla. Windows NT ja muut uudenaikaiset käyttöjärjestelmät eivät ole BIOS-järjestelmästä riippuvaisia, jotta PC-laitteita voitaisiin käyttää nopeammin keinoin eli laitteistoajurein.
Hypätessään INT-käskyyn suoritin heittää pinoon seuraavaksi suoritettavan käskyn osoitteen (eli CS- ja IP-rekisterit) sekä lippurekisterin sisällön ja siirtyy sitten suorittamaan keskeytyksenkäsittelijän koodia. Näin varmistetaan, että suoritin voi käsittelijän koodin suoritettuaan palata automaattisesti alkuperäiseen koodivuohon (eli koodiin, jota oltiin suorittamassa ennen keskeytyksen aloittamista).
Tässä yksityiskohtainen luettelo suorittimen eri vaiheista INT-käskyn aikana:
Monet sovellukset (erityisesti TSR- eli Terminate and Stay Resident -ohjelmat) jättävät muistiin ohjelmistokeskeytyksiä tarjotakseen lisäpalveluja Dos- ja BIOS-järjestelmien palvelujen lisäksi. Eräs hyvä esimerkki on Netware 3.1, joka lisää keskeytyksiä INT 21h -keskeytykseen verkon tiedostotoimintojen tukemiseen (kuten etäkoneella olevan tiedoston lukemiseen). Muut koodinpätkät, etenkin laiteajurit, luovat laitteistokeskeytyksiä valvoakseen eri laitteita ja varmistaakseen niiden virheettömän toiminnan.
Luodakseen keskeytyksen ohjelman tarvitsee vain panna keskeytystaulussa sijaitsevaan tietueeseen oman keskeytyksenkäsittelijänsä osoite. Kun tätä keskeytystä joskus kutsutaan, suoritin suorittaa keskeytyksenkäsittelijän itsestään. Hyvä ohjelmointikäytäntö on panna keskeytyksenkäsittelijäfunktion sisään kutsu edelliseen käsittelijään. Näin varmistutaan siitä, että kaikki aikaisemmin luodut keskeytykset saavat tilaisuuden käsitellä tulevia keskeytyksiä.
Huomaa, että ladattaessa sovellusta, joka kutsuu käyttöjärjestelmän palveluja ohjelmistokeskeytyksin, sovelluskoodin muistiosoitteita ei tarvitse muuttaa vastaamaan käyttöjärjestelmäpalvelujen todellisia muistiosoitteita. Siten käyttöjärjestelmä voi vapaasti siirtää palvelunsa uuteen paikkaan muistissa yksinkertaisesti päivittämällä vastaavat keskeytystaulun tietueet uusilla osoitteilla.
LaitteistokeskeytyksetLaitteistokeskeytykset (engl. hardware interrupts) eivät poikkea käyttäytymiseltään muista keskeytyksistä suuresti. Kuitenkin tarkastellessamme laitteistokeskeytyksen kulkemaa reittiä voimme todeta laitteistokeskeytysten poistuneen laitteesta ennen saapumistaan suorittimelle. On siis huomioitava toimet, jotka keskeytyksenkäsittelijä (tai 8259A, jos se kuulostaa paremmalta) saattaa tehdä.
Suorittaessaan INT-käskyn suoritin noutaa keskeytyskoodin juurikin opkoodilta. Suoritin osoittaa tällä arvolla myöhemmin IVT-tauluun (engl. interrupt vector table) ja etsii keskeytyksenkäsittelijän osoitteen. Toisin sanoen havaitessaan laitteistokeskeytyksen keskeytysohjain lähettää keskeytyskoodin suorittimelle väyliä pitkin. Vastaanotettuaan koodin (joko INT-opkoodilta tai keskeytysohjaimelta) suorittimen suorittamat vaiheet ovat edellä mainitun kaltaisia.
Taulukko 1 kuvaa keskeytyksenohjauspiirien käyttämiä keskeytysvektoreita eri käyttöjärjestelmillä:
Käyttöjärjestelmä | 8259A-piirin käyttämät vektorit | 8259A-alipiirin käyttämät piirit |
---|---|---|
|
|
|
|
|
|
|
|
|
Reaalitila tukee seuraavia poikkeuksia:
Poikkeus | Vektori | Ehto |
---|---|---|
|
|
Yritys suorittaa DIV- tai IDIV-käsky jakajan ollen nolla. |
|
|
Yhdessä virheenkorjausrekisterien kanssa kertoo keskeytyskohdan kohtaamisesta. Suoritin myös suorittaa tämän keskeytyksen aina jokaisen käskyn suorittamisen jälkeen, mikäli TRAP-lippu on päällä. |
|
|
INT 3 -käsky aiheuttaa tämän poikkeuksen. Koska tämän käskyn opkoodi on vain yhden tavun kokoinen, virheenkorjaussovellukset käyttävät käskyä usein asettaakseen keskeytyskohdan sovelluksen koodiin. Virheenkorjaussovelluksen on vain vaihdettava käskyn ensimmäinen tavu INT 3 -keskeytyksen opkoodiin (11001100b) ja odotettava keskeytyskohtapoikkeuksen ilmenemistä. Jatkaessaan suoritusta poikkeuksenkäsittelijä ei vielä palaa sovellukseen, jonka virheitä jäljitetään, vaan sitä ennen virheenkorjaussovellus muuttaa INT 3 -käskyn opkoodiksi aikaisemmin ylikirjoitetun tavun ja suorittaa IRET-käskyn (engl. interrupt return). |
|
|
Suorittaessaan aritmeettisia käskyjä, joilla on etumerkillisiä operandeja, suoritin panee OF-lipun päälle ilmoittaakseen ylivuodon tapahtuneen. INTO-käsky tarkistaa tämän lipun arvon. Jos lippu on päällä, aiheutetaan poikkeus. |
|
|
BOUND-käskyllä määritetään taulukon (engl. array) indeksin raja-arvo, jota ei saa ylittää. Jos raja-arvo ylitetään, suoritin aiheuttaa poikkeuksen. |
|
|
Tapahtuu suorittimen käyttäessä varattua opkoodia tai käsitellessä LOCK-etuliitettä väärin. Voi myös ilmaista opkoodin jälkeen ilmenevän virheellisen operandin. |
|
|
Yritys suorittaa liukulukukäskyä, kun matematiikkasuoritinta ei ole asennettu. Nollaa CR0-rekisterin EM-bitti, mikäli haluat poistaa tämän poikkeuksen käytöstä. |
|
|
Tapahtuu suorittaessa keskeytystä, jolla ei ole tietuetta IVT-taulussa tai aiheutettaessa poikkeus suorittimen suorittaessa vielä aikaisemmin käynnistettyä poikkeuksenkäsittelijää. |
|
|
Tapahtuu, kun pinoon liittyvä toiminto ylittää siirroksen FFFFh, tai kun SS-rekisteriin ladataan käyttämättömäksi merkitty segmentti. |
|
|
Word-tyyppisen siirroksen käyttö siirroksen arvon ollessa FFFFh tai yritys suorittaa koodia koodisegmentin raja-arvon ulkopuolella. |
|
|
Virhe matematiikkasuorittimen yhteydessä (jako nollalla, alivuoto, ylivuoto yms). |
Muut poikkeukset ovat olemassa vain 8086-suorittimen näennäis- eli virtuaalitilassa:
Poikkeus | Vektori | Ehto |
---|---|---|
Task State -segmentti |
|
Kertoo, että jokin tehtävän vaihdon aikana tehdyistä tarkastuksista epäonnistui. |
|
|
Minkä tahansa segmenttirekisterin lataaminen selektorilla, joka osoittaa käyttämättömäksi merkittyyn segmenttiin. |
|
|
Järjestelmävalvojatason sivun käyttö käyttäjätason koodista käsin tai käyttämättömäksi merkityn sivun käyttö. |
(engl. Alignment Check) |
|
Ryhmittelemättömän muistisijainnin käyttö (voi ilmetä vain ring 3 -tason koodia suoritettaessa) |
Keskeytystenkäsittely suojatussa tilassa vaatii erinäisen taulun asettamista muistiin. Tämä taulu on nimeltään IDT (Interrupt Descriptor Table). IDT poikkeaa hieman reaalitilan keskeytysvektoritaulusta. Suojatussa tilassa IDT-taulu ei ole paikallaan fyysisessä osoitteessa 0, vaan se voi siirtyä lineaarisen osoiteavaruuden sisällä täysin vapaasti. Reaalitilassakin IVT-taulun sijaintia voi vaihtaa, mutta se ei ole kuitenkaan yhteensopiva 8086-suorittimen arkkitehtuurin kanssa. IDT-taulun lineaarisen osoitteen määrää IDTR-rekisteriin LIDT-käskyllä asetettu arvo. IDT-taulun jokainen tietue on 8 tavun kokoinen (IVT-taulussa vastaava tietueen koko on 4 tavua). Nämä tietueet voivat sisältää jonkin näistä kolmesta porttideskriptorista:
Seuraava kuvio kuvaa ohjelmallisen keskeytysportin tietueen sisäisen rakenteen:
Kuvio 1 - Ohjelmallisen keskeytysportin tietueen rakenne
Keskeytysporteilla eli keskeytyksillä ja ohjelmallisilla keskeytyksillä on paljon yhteistä. Niillä molemmilla suoritetaan ohjauksensiirtoja (engl. control transfer) eri etuoikeustasojen välillä. Näissä porttideskriptoreissa määriteltyjä selektori- ja siirroskenttiä käytetään keskeytyksenkäsittelijän koodin paikantamiseen ja suorittamiseen. Ohjauksensiirto sallitaan vain koodille, joka sijaitsee samalla tai ylemmällä etuoikeustasolla.
OhjelmistokeskeytyksetMonet suojatun tilan käyttöjärjestelmät käyttävät yhä ohjelmistokeskeytyksiä sisäisten palvelujensa julkaisemiseen. Useimmat näistä rajapinnoista ovat kuitenkin funktioiden takana eikä niitä voida käyttää suoraan (se on tosin mahdollista muttei suositeltavaa). Esimerkiksi Windows NT mahdollistaa käyttäjätilan ja ydintilan osien välisen ohjauksensiirron käyttämällä dokumentoimatonta keskeytystä 2Eh. Kun oikeuttamaton Windows-sovellus kutsuu API-funktiota, järjestelmä reitittää kutsun, ellei se kohtaa INT 2Eh -käskyä. Tätä keskeytystä vastaava IDT-portti osoittaa ntoskrnl-ytimen sisällä olevaan käsittelijään, joka suorittaa vaaditut, etuoikeutetut toimenpiteet ohjelman puolesta. Windows 95 ja 98 käyttävät vastaavanlaista tekniikkaa käyttäjä- ja ydintilojen välillä vaihteluun. Tosin Windows 95 ja 98 tukeutuvat INT 2Eh -keskeytyksen sijasta INT 30h -keskeytykseen.
LaitteistokeskeytyksetLaitteistokeskeytykset käyttäytyvät suojatussa tilassa reaalitilan kappaleessa kuvatulla tavalla. Ainoa merkittävä ero on se, että suojatussa tilassa suoritin käyttää avuksi omaa IDT-tauluaan eikä etsiskele keskeytyksenkäsittelijän osoitetta reaalitilan IVT-taulusta.
PoikkeuksetSuurin osa edellisten kappaleiden tiedoista koskee suojatussakin tilaa. Poikkeuksella 13 (General Protection Fault -poikkeus) on kuitenkin suojatussa tilassa laajempi merkitys; sillä ilmaistaan muutakin kuin reaalitilassa määriteltyjä asioita.
Se on siinä! Lisää tietoa suojatun tilan keskeytyksistä ja poikkeuksista saat Intelin "Pentium-suorittimen ohjekirjasta".
Voit halutessasi tutustua myös Intelin ohjekirjoihin.
Copyright © 1997, 1998 Yariv Kaplan
yariv(at)internals(dot)com
Suomennos: Jouni Kähkönen,