Reload Original Page Print Page Email Page

Suojatun tilan ympäristö

Tämän oppaan kieliasu on korjattu perusteellisesti tammikuussa 2010.

Copyright (C) 2000, 2001 Prashant TR.
Kaikki oikeudet pidätetään.
Suomennos: Jouni Kähkönen, 2005, 2010

Sisällysluettelo

  • Sisältö
  • 1 Johdanto suojattuun tilaan
    • 1.1 Lyhyt johdanto suojattuun tilaan
    • 1.2 Suojatun tilan edut
  • 2 Osoittaminen reaalitilassa
  • 3 80386-suorittimen rekisterit
  • 4 Reaalitilan vektoritaulu
  • 5 Laitekeskeytykset
  • 6 Näppäimistö ja A20-linja
  • 7 Segmenttivalitsimet ja -deskriptorit
    • 7.1 Segmenttivalitsimet
    • 7.2 Suojatun tilan taulut
    • 7.3 Deskriptorit
  • 8 Suojatun tilan etuoikeudet
    • 8.1 Tietojen käyttö
  • 9 Kuinka moniajo toimii
  • 10 80386-suorittimen poikkeukset
  • 11 Muistinhallintayksikkö
  • 12 Suorittimen VM86-näennäistila
  • 13 Suojatun tilan keskeytysten käsittely
  • 14 Suojatun tilan käyttö
  • 15 Suojatun tilan ohjelmasarja
  • 16 Tietoja tästä oppaasta


Sisältö

DJGPP:n postituslistalla on kyselty usein tietoja suojatusta tilasta. Sen vuoksi tämä opas kirjoitettiin. Tämä opas sisältää yksityiskohtaisia tietoja suojatusta tilasta. Aloittelijat, jotka haluavat tietää vain perustiedot suojatusta tilasta, voivat keskittyä johdanto-osioon. Syvempää tietoa halavien on kuitenkin hyvä jatkaa pidemmälle.

Alkuperäiskielinen opas on myös saatavilla. Jos on jotain kysyttävää, sähköpostia voi lähettää englanniksi PMode-palstalle.


1 Johdanto suojattuun tilaan


1.1 Lyhyt johdanto suojattuun tilaan

Mikä on suojattu tila?

80386-suorittimien ja sitä uudempien suorittimien ominaisuudet paikkaavat 8086-suorittimen heikkouksia. 8086-suritinhan ei juuri tukenut muistin suojausta, näennäismuistia, moniajoa ja yli 640 kilotavun muistia. 80386-suoritin on edelleen yhteensopiva 8086-sarjan suorittimien kanssa. DJGPP pitää 386-suoritinta, 486-suoritinta ja sitä uudempia suorittimia samoina. 386-suorittimen periaatteet esiintyvät niin ikään sen seuraajissa.

8086 käyttää vain reaalitilaa. Intelin insinöörit halusivat 286-suoritinta suunnitellessaan lisätä tuen 8086-suorittimesta puuttuville ominaisuuksille. He halusivat kuitenkin säilyttää yhteensopivuuden 8086-suorittimen kanssa. Nämä vaatimukset täyttääkseen he loivat kahdessa eri tilassa toimivan 286-suorittimen. Nämä tilat ovat reaalitila ja suojattu tila. Reaalitilassa suoritin käyttäytyy muutamia parannuksia lukuun ottamatta aivan kuin 8086-suoritin. Suojattu tila eroaa reaalitilasta paljon. Lähes kaikki 8086-suorittimessa toimimaan suunnitellut ohjelmat eivät toimi suojatussa tilassa, ellei ohjelmaan tehdä suuria muutoksia. Dos on näitä ohjelmia.

386-suorittimessa on 8086- ja 286-suorittimesta tuttujen ominaisuuksien lisäksi paljon kehittyneitä ominaisuuksia. Suoritin toimii edeltäneiden suorittimien tavoin oletuksena reaalitilassa. 386 pystyy 286-suorittimen tavoin toimimaan suojatussa tilassa, mutta sisäisesti 386 on täysin erilainen; 386-suoritin tukee kehittyneempää suojausta ja suurempaa muistimäärää. Lisäksi 386 tukee kolmatta toimintatilaa, niin sanottua 8086-näennäistilaa eli V86-tilaa.

386-suoritin antaa V86-tilassa ajettavien ohjelmien käyttää simuloitua reaalitilan ympäristöä, vaikka suoritin onkin suojatussa tilassa. Sen vuoksi Dosin kaltaisia ohjelmia on mahdollista suorittaa suojatussa tilassa joutumatta vaihtamaan suojatusta tilasta reaalitilaan. V86-tilassa on useita etuja reaalitilaan verrattuna. Näistä eduista kerrotaan enemmän seuraavissa luvuissa.


1.2 Suojatun tilan edut

Kaikki 386-suorittimen erityispiirteet ovat käytettävissä, kun suoritin toimii suojatussa tilassa. Alla on mainittuna näitä ominaisuuksia.

Muistia voi käyttää neljä gigatavua – Tämä on merkittävin suojatun ja reaalitilan ero. Suojatun tilan ohjelmien data-, koodi- ja pinosegmentteihin voi käyttää muistia jopa neljä gigatavua. Tietyillä dokumentoimattomilla ominaisuuksilla 8086-suorittimessakin voi käyttää lisämuistia, tosin vain yhden megatavun verran ja sekin vain datasegmentille. Koodi- ja pinosegmenteille on epäkäytännöllistä käyttää dokumentoimattomia tekniikoita. Peruskäytössä muistia ei tarvittane neljää gigatavua, mutta neljän gigatavun tuki onkin tulevaisuutta varten.

Näennäismuisti – 386-suorittimen muistinhallintayksikön avulla on toteutettavissa niin sanottu näennäis- eli virtuaalimuisti. Näennäismuistin ollessa käytössä ohjelma kuvittelee käyttävänsä neljän gigatavun muistimäärää, vaikka todellisuudessa ohjelmalla on muistia vähemmän. 386-suoritin ja tietty käyttöjärjestelmän ohjelmisto jäljittelevät lisämuistia käyttäen apunaan massamuistia kuten kiintolevyä. Vapaata levytilaa tarvitaan tietenkin neljä gigatavua, mutta se on jo toinen asia.

Osoitteenmuunnos - Muistinhallintayksiköllä osoitteet saadaan ennen käyttöä niin ikään muunnettua eli kartoitettua. Esimerkiksi kaikki viittaukset B800H-segmentin neljän kilotavun lohkoon (eli CGA-tekstipuskuriin) voidaan ohjata ohjelmasi tietopuskuriin. Sittemmin ohjelmasi voisi kopioida puskurin sisällön ruudulle. Tästä on hyötyä kun suoraan ruudulle tulostavan ohjelman tuloste halutaan uudelleenohjata. Osoitteenmuunnoksella voi myös jäljitellä laajennettua muistia ilman muistinlaajennuskorttia. EMS-järjestelmän myöhemmissä versioissa on kuitenkin joitakin toimintoja, joita muistinhallintayksikkö ei voi emuloida. Näille toiminnoille tuskin lienee tarvetta edistyneissäkään ohjelmissa.

Ohjelmat käyttävät loogisia osoitteita. 386-suoritin muuntaa nämä loogiset osoitteet 32-bittisiksi lineaarisiksi, segmentoimattomiksi osoitteiksi. Sen jälkeen muistinhallintayksikkö muuntaa lineaariset osoitteet fyysisiksi osoitteiksi. Jos muistinhallintayksikkö ei ole käytössä, lineaariset ja fyysiset osoitteet ovat yhtäläisiä. Kun osoitteiden terminologiaa sovelletaan reaalitilaan, on osoite B800:0010 looginen osoite. Sitä vastaava lineaarinen osoite on B8010H. Tässä fyysinen osoite on sama kuin lineaarinen osoite, koska reaalitilassa ei käytetä muistinhallintayksikköä.

Kehittynyt segmentointi - Reaalitilassa on vain kiinteitä, 64 kilotavun kokoisia segmenttejä. Suojatussa tilassa segmentti voi olla kooltaan aina yhdestä tavusta neljään gigatavuun. Funktio __djgpp_nearptr_enable() käyttää tätä ominaisuutta. Jos segmentin ulkopuolella olevaa segmenttiä yrittää käyttää, aiheutuu virhe. Jos segmentti on kooltaan neljä gigatavua ja ohjelma yrittää käyttää muistia neljän gigatavun rajan yli, osoite kiertää alkuun. Segmentit voivat alkaa mistä tahansa kohdasta. Lisäksi ohjelmoijan on päätettävä jokaisen segmentin käyttötarkoitus, sillä 386 vaatii näin. Eli jos ohjelma yrittää kirjoittaa tietoa ohjelmakoodille tarkoitettuun segmenttiin, 386 aiheuttaa virheen. On myös mahdollista määritellä koko neljän gigatavun osoitealueen kattava segmentti ja siten luopua tyystin segmenteistä. Tällöin muistiin viitataan aina 32-bittisin segmentoimattomin osoittimin. Tällaiset latteat osoittimet vastaavat välittömästi lineaarisia osoitteita.

Muistinsuojaus - 386-suorittimessa muisti voidaan suojata. Käyttäjän ohjelma ei esimerkiksi voi kirjoittaa käyttöjärjestelmän tietojen päälle. Muistinsuojaus segmenttitarkistuksineen suojaa virheellisiltä ohjelmilta, jotka voisivat muutoin jumittaa koko järjestelmän.

Prosessien suojaus - Muistin suojauksen tavoin ohjelmatkin voidaan suojata toisiltaan. Ohjelma ei voi käyttää toisen ohjelman tietoja, kun taas käyttöjärjestelmä pääsee minkä tahansa ohjelman tietoihin käsiksi. Käyttäjän ohjelmien on kyllä mahdollista käyttää käyttöjärjestelmän tietoja rajoitetusti. Tämä on itse asiassa toteutettavissa muistinhallintayksikön mahdollistamin sivunsuojausmekanismein.

32-bittiset rekisterit - Kaikki 386-suorittimen yleisrekisterit ovat 32-bittisiä. Nämä rekisterit ovat melkein saman nimisiä kuin 8086-suorittimen rekisterit; edessä on vain E-etuliite. Esimerkiksi AX-rekisterin sijasta on EAX-rekisteri. Käytettävissä on myös kaksi uutta segmenttirekisteriä, FS ja GS; niitä voi käyttää molemmista tiloista, mutta suojatun tilan ohjelmissa niistä on enemmän hyötyä. Reaalitilan ohjelmatkin voivat käyttää näitä 32-bittisiä rekistereitä, tosin eivät indeksointitarkoituksiin. Lisäksi 32-bittisten rekisterien käyttö suojatussa tilassa – siis 32-bittisessä – pudottaa koodin kokoa ylipäänsä.

Kehittyneet osoitustilat - Reaalitilan ohjelmat voivat muodostaa osoitteita vain vakioarvoilla eli BX- tai BP-rekistereillä ja SI- ja DI-rekistereillä. Suojatun tilan ohjelmissa millä tahansa rekisterillä voi muodostaa osoitteita. Indeksissä voi olla skaalatekijänä 1, 4 tai 8. Tämän ansiosta on mahdollista kirjoittaa muun muassa seuraava käsky: MOV EBX, [EDI][EAX*8]+2.

Tuki moniajolle - 386-suorittimessa on erityisominaisuuksia, joilla voi tallentaa suorittimen nykyisen tilan ja vaihtaa toiseen tehtävään. Tämän toiminnon nimi on kontekstin vaihto. Kontekstin voi vaihtaa hetkessä yhdellä ainoalla käskyllä. Tällä on tärkeä merkitys käyttöjärjestelmän ja reaaliaikaisen käsittelyn kannalta. 386 tukee myös sisäkkäisiä tehtäviä. Tehtävä voi palata alkuperäiseen tehtäväänsä back-linkillä.

Laitetason virheenkorjaus - 386-suorittimessa on erityinen laitteisto, jolla voi toteuttaa yksivaiheisen koodi- tai data-pysäytyskohdan. Reaalitilassa tämä laitteisto on käytettävissä erityistekniikoin.


2 Osoittaminen reaalitilassa

8086-tyypin suorittimissa muisti on järjestetty tavuiksi. Kun 8086 käsittelee kahdeksaa bittiä suurempia lukuja, se tallentaa alempaan osoitteeseen vähiten merkitsevän tavun. Tämä kuulostaa loogiselta, mutta on hyvin häiritsevää listauksia tai muistivedoksia luettaessa, sillä numerot esiintyvät takaperin. Tietokone tallettaa esimerkiksi sanan B800H kahtena tavuna: 00H ja B8H.

Intel-sarjan suorittimet käyttävät segmentointi-nimistä muistinosoitustekniikkaa. Segmentti on muistialue. Tietokone osaa käsitellä useita segmenttejä. Reaalitilassa (jota Dos-järjestelmäkin tavallisesti käyttää) voi olla 65 536 segmenttiä, joista kukin on kooltaan 64 kilotavua. Nämä segmentit ovat tosin osittain päällekkäin, sillä jokainen segmentti alkaa 16 tavun päästä edellisen segmentin alkua. Tämän vuoksi Dos voi käyttää muistia normaalisti vain yhden megatavun (65536 * 16 = 1048576 = 1 Mt). 8086- ja 8088-suorittimet joutuvat aina tyytymään yhteen megatavuun. 286- ja 386- ja sitä uudemmat suorittimet voivat käyttää muistia paljon enemmän. Lisämuistiakaan Dos ei voi käyttää suoraan.

Koska segmentit ovat 64 kilotavun kokoisia, määritämme haluamamme osoitteen käyttämällä arvoa nimeltään siirros. Täydellisessä 8086-tyypin osoitteessa on aina segmentti ja siirros.

Jos segmenttinä on 0040H ja siirroksena 0102H, merkitään 0040:0102.
Koska segmentit alkavat 16 tavun päästä (10H) edeltävän segmentin alusta laskien, osoite 0000:0010 on sama kuin osoite 0001:0000. Samoin osoite 0040:0000 on sama kuin osoite 0000:0400, joka taas on sama kuin 0020:0200. Kone tallentaa segmentoidut osoitteet aina takaperin. Esimerkiksi osoite 0040:1234 tallentuu muistiin näin:

34 12 40 00

Kaikki yllä mainitut osoitteet voi varmistaa keskenään yhtäläisiksi muuntamalla ne lineaarisiksi osoitteiksi. Segmentoidun osoitteen voi muuntaa lineaariseksi kertomalla segmentin arvo luvulla 16 (10H) ja lisäämällä siirros:

0040 * 10 + 0000 = 00400
0000 * 0 + 0400 = 00400
0020 * 10 + 0200 = 00400

Kaikki nämä osoitteet osoittavat lopulta samaan muistikohtaan.


3 80386-suorittimen rekisterit

80386-suorittimessa on neljä yleisrekisteriä, yksi lippurekisteri, kuusi segmenttirekisteriä, kaksi indeksirekisteriä, yksi pinosegmenttirekisteri ja -osoitin, kantarekisteri sekä käskyyn osoittava rekisteri. Näiden lisäksi 386-suorittimessa on erikoisrekistereitä:

GDTR – Global Descriptor Table Register
IDTR – Interrupt Descriptor Table Register
LDTR – Local Descriptor Table Register
TR – Task Register
CR0-CR3 – Control Registers
DR0-DR7 – Debug Registers

Seuraavassa kuvassa on nähtävissä rekisterien nimet selityksineen. Kaaviosta huomaa, että 386-suorittimen mukana tulee useita erikoisrekistereitä. Niistä ei yleensä ole hyötyä Dosissa, mutta näemme joitakin niistä, kun käsittelemme Dosiin saatavia suojatun tilan laajennuksia.

fig2.gif


4 Reaalitilan vektoritaulu

8086-sarjan suorittimet voivat reagoida 256 eri keskeytykseen. Kohdasta 0000:0000 alkaen muistissa on taulu, joka sisältää keskeytysten osoitteet. Tämän keskeytysvektoritaulun jokainen tietue on kooltaan neljä tavua, mikä riittää juuri segmentin ja siirroksen tallentamiseen. Muistissa on siis 1024 tavun eli yhden kilotavun kokoinen varattu alue reaalitilan keskeytysvektoritaulua varten. Kun suoritin vastaanottaa esimerkiksi keskeytyksen 2 (INT 2), se tallentaa pinoon lippurekisterin sekä CS- ja IP-rekisterien sen hetkiset arvot. Sen jälkeen se hakee osoitteessa 0000:0008 tallennettuna olevan osoitteen, ja käynnistää saadussa osoitteessa olevan keskeytyspalvelurutiinin (ISR, interrupt service routine). Keskeytyspalvelurutiinissa oleva IRET-komento viestittää keskeytyksen olevan suoritettu1 ja saa suorittimen jatkamaan kohdasta, jota suoritettiin ennen keskeytyksen aloittamista.


5 Laitekeskeytykset

Laitekeskeytys on erityinen signaali I/O-laitteelta tietokoneelle. Tämä signaali informoi tietokoneelle, että I/O-laite tarvitsee huomion. Tavallisesti suoritin keskeyttää sen hetkisen tekemisensä, jotta se voi palvella keskeytystä. Kun keskeytys on suoritettu loppuun, suoritin jatkaa siitä mihin jäi.

Laitekeskeytyksiä tulee eri lähteistä. Esimerkiksi joka kerta, kun painat pohjaan tai vapautat näppäimen, aiheutat keskeytyksen. Muita keskeytyksiä tulee muiden muassa kellolta, tulostimelta, sarjaportista ja levyohjaimilta. Suoritinkin aiheuttaa joitakin keskeytyksiä. INT 0 esimerkiksi aiheutuu, kun ohjelma yrittää jakaa nollalla. Nämä kaikki ovat laitekeskeytyksiä. Laitekeskeytyksen käsittely lienee suojatun tilan tärkeimpiä tehtäviä. Laitekeskeytyksen käsittelijöillä voikin saada tuhoa aikaan.

Emolevyn 8259-keskeytysohjain eli PIC, programmable interrupt controller hoitaa kaikki laitekeskeytykset. Nämä ohjaimet vastaanottavat keskeytyssignaaleja eri laitteilta ja muuntavat ne sitten suorittimelle sopiviksi keskeytyksiksi.

Alla olevassa luettelossa on nähtävissä reaalitilan laitekeskeytykset PIC-keskeytyksenkutsusyötteineen eli tunnetummin IRQ-linjoineen. IRQ-numeroita ei tule sekoittaa keskeytysnumeroihin. Esimerkiksi näppäimistö kytkeytyy IRQ1-linjaan, joka lähettää INT 9 -keskeytyksen suorittimelle. PIC-piirejä voi myös ohjelmoida uudelleen siten, että ne luovat IRQ-linjoille eri keskeytysnumeroita. Tätä tekniikka käyttävät yleensä ruudunkaappausohjelmat sekä Dos-laajennukset kuten go32.

PIC-piirit ohjaavat myös keskeytysten prioriteetteja. Esimerkiksi kellolla (IRQ 0) on suurempi prioriteetti kuin näppäimistöllä (IRQ 0). Jos suoritin palvelee parhaillaan kellon keskeytystä, PIC ei voi aiheuttaa keskeytystä näppäimistölle, ennen kuin kellon keskeytyspalvelurutiini nollaa PIC-piirin. Toisaalta kello voi keskeyttää näppäimistön keskeytyspalvelurutiinin. PIC-piirit voi ohjelmoida käyttämään eri prioriteettiskeemoja, mutta sellaista tuskin käytetään PC-ohjelmoinnissa.

AT:n PIC-lisäpiiri kytkeytyy ensimmäisen PIC-piirin IRQ 2 -linjaan. Siten PIC-lisäpiirin IRQ-linjoilla (linjat 8 – 15) on sama prioriteetti kuin IRQ 2 -linjalla. IRQ 2 -linjan estämällä estyy kaikki PIC-lisäpiirin keskeytykset.

Keskeytys IRQ-numero Kuvaus
00H - Jako nollalla tai jaon ylivuoto
02H - NMI (Non-maskable Interrupt)
04H - (INTO:n aiheuttama) ylivuoto
08H 0 Järjestelmän ajastin
09H 1 Näppäimistö
0AH 2 PIC-lisäpiirin keskeytys
0BH 3 COM2
0CH 4 COM1
0DH 5 LPT2
0EH 6 Levykeasema
0FH 7 LPT1
70H 8 Reaaliaikainen kello
71H 9 Yleinen I/O
72H 10 Yleinen I/O
73H 11 Yleinen I/O
74H 12 Yleinen I/O
75H 13 Matematiikkasuoritin
76H 14 Kiintolevy
77H 15 Yleinen I/O

Voit estää keskeytyksiä häiritsemästä ohjelmakoodisi tärkeän osuuden suorittamista. CLI-käsky estää kaikki keskeytykset lukuun ottamatta NMI-keskeytystä, koska NMI-keskeytys ei kulje PIC-piirin kautta eikä sitä siten voida pysäyttää tällä keinoin2. Lisäksi PIC-piirit voidaan ohjelmoida kytkemään pois valittuja keskeytyksiä.


6 Näppäimistö ja A20-linja

Oletamme normaalisti, että 80386-suorittimessa reaalitilan osoitteet ovat kiertäviä. Tämän ennakoiden AT-emolevyn suunnittelijat reitittivät A20-linjan näppäimistön ohjaimen kautta. Tavallisesti ohjain estää A20-linjaa käyttämästä muistipiirejä. Lähettämällä tietyn komennon näppäimistön ohjaimelle A20-linjan pystyy ottamaan käyttöön. Vastaavasti toisella komennolla A20-linjan saa poistettua käytöstä. Tämän niin kutsutun A20-portin käyttö on keskeistä laajennetun muistin (extended memory) käytössä, olimme reaalitilassa tai suojatussa tilassa3.


7 Segmenttivalitsimet ja -deskriptorit


7.1 Segmenttivalitsimet

Jotta ymmärtää suojatun tilan toimintaa, on ymmärrettävä segmenttien toiminta. Suojatun tilan segmenteillä on jotain yhteistä reaalitilan segmenttien kanssa. Suojatun tilan segmentti sisältää 16-bittisen segmenttivalitsimen (katso kuva alla). Reaalitilasta poiketen valitsimella ei ole mitään tekemistä segmentin sijainnilla muistissa, vaan rekisterissä oleva arvo on indeksi segmenttideskriptoreita sisältävään tauluun. Kukin deskriptori eli kuvaustietue määrittää yhden segmentin ja määrää segmentin sijainnin, tyypin ja muita oleellisia parametreja kuten käyttöoikeudet.

fig3.gif

Valitsimessa on kolme kenttää. Kaksi alinta bittiä (RPL) viittaa 386-suorittimen suojausmekanismiin, josta kerrotaan lyhyesti myöhemmin. Seuraava bitti, TI, valitsee, mikä deskriptoritaulu määrittää segmentin. Segmenttideskriptoritauluja on kolmea tyyppiä:

  1. globaali deskriptoritaulu, GDT
  2. keskeytysdeskriptoritaulu, Interrupt Descriptor Table, IDT
  3. lokaali deskriptoritaulu, LDT

Segmenttivalitsimet eivät koskaan viittaa IDT-tauluun. Jos TI on nolla, segmentin määrittelyt sijaitsevat GDT-taulussa. Jos TI on yksi, segmentin määrittelyt sijaitsevat LDT-taulussa.


7.2 Suojatun tilan taulut

Jokaisessa deskriptoritaulussa voi olla enintään 8192 deskriptoria. Valitsimen INDEX-bitit eli bitit 15 – 3 valitsevat käytettävän deskriptorin.

GDTR- ja IDTR-rekisterit taas määräävät GDT- ja IDT-taulujen sijainnit. Molemmat sisältävät 32-bittisen osoitteen ja 16-bittisen raja-arvon. Raja-arvo on todellista taulun pituutta yhden (1) tavun pienempi. GDTR ja IDTR ovat 48-bittisiä rekistereitä. Osoite on lineaarinen, ei segmentti-siirros–pari. Taulu voi sisältää enintään 64 kilotavua tietoa eli yhteensä 8192 deskriptoria.

GDT-taulu on nimensä mukaisesti globaali; Kaikki tehtävät käyttävät samaa GDT-taulua; silloinkin kun järjestelmä toimii moniajolla. Tämä pätee myös IDT-taululle – kaikki tehtävät käyttävät samaa taulua. Jos jokin tehtävä muuttaa GDT- tai IDT-taulua, se vaikuttaa kaikkiin työtehtäviin.

LDTR-rekisteri määrittää LDT-taulun sijainnin. GDT-taulusta poiketen on jokaisella tehtävällä oma LDT-taulunsa. LDTR-rekisteri ei sisällä GDTR-rekisteristä tuttua 32-bittistä osoitetta ja 16-bittistä raja-arvoa. LDTR-rekisteri sisältää segmenttivalitsimen, jonka on osoitettava erityiseen GDT-taulun tietueeseen; tämä GDT-taulun tietue osoittaa LDT-tauluun. GDT-taulussa voi olla osoittimia useisiin LDT-tauluihin.

IDT-taulu vastaa reaalitilan keskeytysvektoritaulua. Kukin deskriptori määrittelee reaktion yhteen 256:sta mahdollisesta keskeytyksestä. Vaikka IDT-taulu voi sisältää jopa 8192 deskriptoria, yli 256:n deskriptorin käyttö olisi tuhlausta.

Alla olevasta kuvasta näkee deskriptoritietueen formaatin. Myös erityistyyppiset deskriptorit ovat nähtävissä.

fig4.gif


fig5.gif


fig6.gif


7.3 Deskriptorit

Kaksi segmenttideskriptorin kenttää ovat erityisen mielenkiintoisia. P-bitti (bitti 47) määrää, onko segmentti käytössä. Käyttöjärjestelmä voi asettaa tämän bitin nollaksi luodakseen näennäissegmentin. Kun ohjelma yrittää käyttää näennäissegmenttiä, 386 aiheuttaa virheen. Käyttöjärjestelmä voi sitten ladata segmentin levyltä ja yrittää uudestaan. Kun P-bitti on nollattuna, bitit 0 – 39 ja 48 – 63 saavat sisältää mitä tahansa arvoja. Tuohon tilaan käyttöjärjestelmä voisi tallentaa vaikka levyosoitteen. Tämä ei kuitenkaan onnistu, mikäli segmentin koko on kovin suuri. Onneksi 386 tarjoaa paremman tavan näennäismuistin toteuttamiseen.

Toinen mielenkiintoinen kenttä on A-bitti (bitti 40). 386 asettaa tämän bitin päälle, jos jokin ohjelma kirjoittaa segmenttiin. Tämä meidän näennäismuistiviritelmämme voisi käyttää tätä bittiä päättämään, onko sen kirjoitettava segmentti levylle ennen kuin segmentti merkitään poissa olevaksi ja segmentin tila käytetään uudelleen.

Toinen ihmetystä herättävä asia on se, miten deskriptori pystyy määrittämään segmentin pituuden yhden tavun ja neljän gigatavun väliltä. Käytettävissä oleva raja-aluehan on vain 20 bittiä. Tässä tulee G-bitti (bitti 55) apuun. Jos G-bitin arvo on nolla, raja-arvokentän arvo on sama kuin segmentin suurin mahdollinen siirros (eli segmentin pituutta yhden tavun pienempi). Jos G-bitti on yksi, 386 siirtää raja-arvokentän arvoa 12 bittiä vasemmalle luoden 32-bittisen raja-arvon. Alimmat 12 bittiä 386 täyttää ykkösin.

Esimerkki:

Jos deskriptorin raja-arvo on yksi ja G-bitti on yksi, todelliseksi raja-arvoksi saadaan 1FFFH.
Jos G-bitti on yksi ja raja-arvo nolla, raja-arvoksi saadaan FFFFH.

Tällä menetelmällä voidaan määritellä segmentti, jonka pituus on joko alle megatavun tai jonka pituus ilmaistaan neljän kilotavun kerrannaisina. Kun G-bitti on nolla, segmentin pituus voi ulottua yhdestä tavusta megatavuun. Kun G-bitti on yksi, segmentin pituus ulottuu neljästä kilotavusta neljään gigatavuun (tosin neljän kilotavun askelin).

On mahdollista luoda useampia deskriptoreja, jotka kaikki osoittavat samaan muistialueeseen. Käyttöjärjestelmä voi esimerkiksi ladata tiedoston sisällön datasegmenttiin ja hypätä sen jälkeen samasta kohdasta alkavaan koodisegmenttiin. Tämä toimenpide tunnetaan nimellä aliasten muodostaminen eli aliasing. Käyttöjärjestelmän on jotenkin voitava ladata muistiin GDT- ja muut taulut. Siksi se käyttää yleensä GDT-tauluun osoittavaa datasegmentti-aliasta. Jotkin järjestelmät luovat koko neljän gigatavun muistialueen kattavan datasegmentin. Silloin taulut voidaan kirjoittaa muistiin suoraan tämän datasegmentin kautta. Harvat käyttöjärjestelmät antavat tavallisten käyttäjäohjelmien päästä suoraan käsiksi GDT-, IDT- ja muihin järjestelmätauluihin.

Suoritin varaa itselleen GDT-taulun ensimmäisen lohkon. Tämän lohkon valitsin on niin sanottu nollavalitsin (null selector). Sen käyttäminen aiheuttaa aina virheen. Nollavalitsimen deskriptorien tulisi kaikkien olla nollia. Nollasta poikkeavat arvotkin toimivat, mutta eihän sitä koskaan tiedä.


8 Suojatun tilan etuoikeudet

Suojattu tila on saanut nimensä 386-suorittimen etuoikeustasoihin perustuvasta suojauksesta. Jokaisella ohjelmalla on oma etuoikeustasonsa eli privilege level (PL). Sen arvo on nolla, yksi, kaksi tai kolme. PL0-tason ohjelmat voivat suorittaa mitä tahansa käskyjä ja päästä käsiksi mihin tahansa tietoon. PL3-tason ohjelmat eivät voi suorittaa tiettyjä käskyjä; ne eivät voi myöskään käsitellä tietoja, jotka kuuluvat suuremman etuoikeustason ohjelmalle. Kullakin segmenttideskriptorilla on deskriptorin etuoikeustaso eli Descriptor Privilege Level (DPL). 386-suoritin käyttää sitä suojauksen toteuttamisessa. 386 määrää myös mitkä ohjelmat saavat suorittaa I/O-käskyjä.

Etuoikeushierarkia on tärkeä nykyaikaisten käyttöjärjestelmien tukemisessa. Tyypillisessä käyttöjärjestelmässä pääydin toimii PL0-tasossa. Muut käyttöjärjestelmän osat saattavat toimia PL1-tasossa. Laiteajurit voisivat pyöriä PL2-tasossa; niidenhän on voitava käsitellä I/O-laitteita suoraan. Käyttäjän ohjelmat voisivat tällaisessa järjestelmässä toimia PL3-tasossa. Tällaisesta järjestelystä on paljon etua; erityisesti haittaohjelmat eivät pysty vahingoittamaan käyttöjärjestelmää tai muita käyttäjäohjelmia.

Seuraavia käskyjä voivat suorittaa vain PL0-ohjelmat:

•HLT
•CLTS
•LGDT
•LIDT
•LLDT
•LTR
•LMSW
•MOV (ohjaus-, virheenkorjaus- ja testausrekistereistä ja -rekistereihin)

486-järjestelmässä lisäksi:

•INVD
•WBINVD
•INVLPG

Pentium- ja uudemmissa järjestelmissä:

•RDMSR
•WRMSR
•RDTSC

Käyttöjärjestelmä voi määrätä EFLAGS-rekisterin IOPL-kentän avulla, mitkä ohjelmat voivat käyttää I/O-siirräntää. Nämä kaksi bittiä määrittelevät alimman etuoikeustason, joka ohjelmalla on oltava voidakseen suorittaa I/O-käskyjä eli käskyjä CLI, STI, IN, INS, OUT ja OUTS. Jos IOPL on nolla, vain PL0-ohjelmat voivat käyttää I/O-siirräntää. Jos IOPL on 3, kaikki ohjelmat voivat suorittaa I/O-käskyjä. Vain PL0-ohjelmat voivat muokata IOPL-lippuja. Jos muut ohjelmat yrittävät muuttaa näitä lippuja, IOPL ei vain muutu! Jättämällä IOPL-kentän arvoksi 3 on Dos-laajennusten elämä helpompaa. Tämä saattaa kuitenkin aiheuttaa vielä suurempia ongelmia, sillä reaalitilan ohjelmat käyttävät usein suoraa I/O-siirräntää.

Ohjelman etuoikeustaso on yhtä suuri kuin CS-rekisterissä olevan valitsimen RPL-kenttä. Tämä on nykyinen etuoikeustaso eli current privilege level eli CPL. CS-rekisteriä ei voi muuttaa suoraan, jotta sillä olisi eri RPL-arvo. Sama pätee SS-rekisteriin.

8.1 Tietojen käyttö

Ohjelmat eivät voi ladata segmenttirekisteriin mitä tahansa valitsinta. Kun datasegmenttirekisteriin (DS, ES, FS tai GS) ladataan arvo, 386 vertaa DPL-arvoa, ohjelman CPL-arvoa ja valitsimen RPL-arvoa toisiinsa. Ensin 386 vertaa CPL- ja RPL-arvoja keskenään. Niistä suurempi tulee voimassa olevaksi etuoikeustasoksi (effective privilege level, EPL). Jos DPL on suurempi tai yhtä suuri kuin EPL, 386 lataa segmenttirekisterin; muutoin aiheutuu virhe.

SS-rekisteriin on ladattava segmentti, jonka DPL ja CPL ovat yhtä suuret. 386 tarkistaa myös onko pinosegmentti luettavissa, kirjoitettavissa ja käytössä.

386-suorittimessa on mahdollista käyttää myös varsinaista pinosegmenttiä. Haluttaessa pinona voi käyttää tavallistakin datasegmenttiä. Pinosegmentin raja-arvokenttä ilmaisee segmentin alimman mahdollisen siirroksen.

Nollavalitsimen (0 – 3) lataaminen segmenttirekisteriin on aina laillista. Jos tämän valitsimen kautta yrittää käyttää muistia, aiheutuu kuitenkin odotetusti virhe.


9 Kuinka moniajo toimii

386-suoritin tukee moniajoa. Moniajon avulla useita prosesseja voi suorittaa samanaikaisesti. Todellisuudessa prosesseja ei kuitenkaan suoriteta yhtäaikaisesti, vaan se vain tuntuu käyttäjästä siltä.

386-suoritin käyttää moniajossa niin sanottuja tehtävätilasegmenttejä (task state segment, TSS). TSS-deskriptori osoittaa puskuriin, jonka on oltava kooltaan vähintään 104 tavua. Moniajon lisäksi TSS-deskriptoreita voi käyttää laitekeskeytysten käsittelyyn (käyttäen IDT-taulussa tehtäväportteja). TSS-valitsin ei ole luettava eikä kirjoitettava. Yleensä luodaan TSS-alias, joka on vain TSS-puskuriin osoittava datasegmentti. TSS-valitsimia voi olla vain GDT-taulussa, ei koskaan LDT- tai IDT-taulussa. IDT-taulussa voi kyllä olla tehtäväportteja, kuten aiemmin mainittiin. Suoritin käyttää TSS-valitsinta sisäisesti.

Moniajossa tehtävän vaihto edellyttää, että suorittimen tila tallennetaan muistiin, joten puskuriin tallennetaan muun muassa laiterekisterien arvot. Tehtävää vaihdettaessa suoritin tallentaa automaattisesti TSS-puskuriin eri tietoja. Tämä toimenpide on hyvin nopea, joten tehtävän vaihtamiseen ei mene montakaan suoritinjaksoa. Ennen kuin tehtävä alun perin käynnistetään, käyttöjärjestelmän on täytettävä tietyt tietueet TSS-puskuriin.

Huomaa TSS-segmentin yläosassa olevat pinosegmenttien kentät ja PL0-, PL1- ja PL2-tasojen osoittimet. Ohjelman on ylläpidettävä erillisiä tehtäviä jokaista käyttämäänsä etuoikeustasoa varten. Etenkin PL0-tason pinosegmenttien ja osoittimien on oltava olemassa. Muuten suoritin saattaa sammua kaksoisvirheen vuoksi keskeytyksen tapahtuessa.

Tehtävän voi vaihtaa far-hypyn tai far-kutsun aikana. Huomioimatta jätetään hypyn tai kutsun siirros. TSS-segmentin arvot ladataan rekistereihin, ja uusi tehtävä aloittaa suorituksen. Valitsimen, jota hyppy tai kutsu koskee, on oltava TSS-valitsin tai tehtäväportti. Tehtäväportti sisältää TSS-valitsimen. Tehtäväportti voi olla GDT-, IDT- tai LDT-taulussa, toisin kuin TSS-valitsin. EPL-tason on oltava aina vähemmän tai yhtä suuri kuin TSS-segmentin DPL-taso, samoin kuin normaalien segmenttivalitsimien tapauksessa.

386-suoritin tukee myös sisäkkäisiä tehtäviä. Se käsittelee sisäkkäisiä tehtäviä EFLAGS-rekisterin NT-bitin avulla (NT, nested tasks). Kun tehtävä "kutsuu" toista tehtävää, 386 tallentaa vanhan tehtävän TSS-valitsimen uuden TSS-segmentin paluulinkki-kenttään (back link). Samalla asetetaan EFLAGS-rekisterin NT-bitti päälle. Kun uusi tehtävä haluaa palata vanhaan tehtävään, uusi tehtävä suorittaa IRET-käskyn4.

TSS ei ole vapaakäyntinen (eng. reentrant). 386 kertoo tehtävän olevan käynnissä asettamalla TSS-valitsimen BUSY-bitin päälle. Suoritin tekee näin, jotta tehtävää ei toi toistuvasti kutsua.

Aiemmin mainittiin, että TSS-segmentin on oltava kooltaan vähintään 104 tavua. TSS-segmentin koon on mahdollista laajeta vapaasti. 386 sisältää osoittimen I/O-bittikarttaan viimeisessä kentässä. Tämän bittikartan koko on yleensä 8 kilotavua mutta saattaa olla vähemmänkin. I/O-bittikartta on valinnainen. Jos I/O-bittikartan koko on vähemmän, bittikartan jäljessä olevat kohdat oletetaan ykkösiksi (1). Kukin I/O-bittikartan bitti vastaa aina yhtä I/O-porttia. Jos tehtävä yrittää käyttää I/O-siirräntää, 386 vertaa tehtävän CPL-arvoa IOPL-arvoon. Jos CPL on vähemmän tai yhtä suuri kuin IOPL, pääsy sallitaan, muussa tapauksessa 386 tarkistaa I/O-bittikartan. Jos käytettävää I/O-porttia vastaava bitti on nolla, 386 sallii pääsyn, muussa tapauksessa 386 estää pääsyn. Bittikartan on aina päätyttävä arvoon 0FFh.

fig7.gif


10. 80386-suorittimen poikkeukset

386-suoritin tukee 8086-suorittimen tapaan 256 keskeytystä (tai poikkeusta). Keskeytysdeskriptoritaulussa (interrupt descriptor table, IDT) on määritelmä jokaiselle keskeytykselle. IDT-taulu voi sisältää 8192 tietuetta, mutta käytettävissä on vain ensimmäiset 256 tietuetta. IDT-taulussa voi olla myös ohjelmistokeskeytysten portteja (trap gates), keskeytysportteja ja tehtäväportteja. Ohjelmistokeskeytyksen portti ei tyhjennä keskeytyksiä ennen poikkeuksen käsittelijään siirtymistä. Keskeytysportit taas estävät kaikki keskeytykset ennen käsittelijään siirtymistä. Tehtäväporteista kerrotaan enemmän toisessa kohdassa. Katso yhdeksäs luku, "Kuinka moniajo toimii".

Suorittimen ja ulkoisten laitteiden aiheuttamien keskeytysten lisäksi on olemassa ohjelmistokeskeytyksiä. Laitekeskeytykset kulkevat PIC-piirin kautta (ks. laitekeskeytykset). Suorittimen aiheuttamien laitekeskeytysten huolellinen käsittely on käyttöjärjestelmän tärkeimpiä tehtäviä. Näiden keskeytysten käsittelijöissä tehdyt pienetkin virheet johtavat tuhoon, esimerkiksi ruudulle ilmestyvän sinisen ruudun muodossa.

386-suorittimen aiheuttamat poikkeukset ovat luokiteltavissa vioiksi (faults), ohjelmistokeskeytyksiksi (traps) ja virhelopetuksiksi (aborts).

Vika on korjattavissa oleva virhe. Virheelliset toimet johtavat yleensä vikoihin. Kun vika ilmenee, osoite CS:EIP osoittaa vian aiheuttamaan käskyyn. Vikoja pidetään vähiten vakavina poikkeuksina. Näistä vioista tavanomaisin on yleinen suojausvirhe eli general protection fault, GPF.

Ohjelmistokeskeytys ilmenee, kun INT- tai INTO-käsky suoritetaan. Ohjelmistokeskeytyksen ilmetessä osoite CS:EIP osoittaa keskeytyksen aiheuttaneen käskyn jäljessä olevaan käskyyn.5 Järjestelmä ei voi käynnistää ohjelmistokeskeytyksiä alusta.

Virhelopetukset ovat vakavia virheitä. Ne viittaavat usein käyttöjärjestelmässä ilmeneviin vakaviin ongelmiin. Näitä ovat muiden muassa kaksoisvirhe ja liukulukuyksikön yliajo eli double fault ja FPU overrun.

Alla olevassa taulussa on esillä poikkeukset luokituksineen:

Divide Error (0) Vika
Debug (1) Vika/ohjelmistokeskeytys
Breakpoint (3) Ohjelmistokeskeytys
Overflow (4) Ohjelmistokeskeytys
Bounds Check (5) Vika
Bad Opcode (6) Vika
No Coprocessor (7) Vika
Double Fault (8) Virhelopetus
Coprocessor Overrun (9) Virhelopetus
Invalid TSS Segment (0A) Vika
Segment not Present (0B) Vika
Stack Fault (0C) Vika
General Protection Fault (0D) Vika
Page Fault (0E) Vika
Coprocessor Error (10) Vika


11 Muistinhallintayksikkö

386-suorittimessa muistinhallinnan voi toteuttaa ainakin kahdella eri tavalla:

  1. Segmentointi
  2. Sivutus

Näistä kahdesta segmentoinnin käyttö on välttämätöntä, kun taas sivutus on käyttäjälle valinnainen. Sivutus suo mahdollisuudet näennäismuistin toteuttamiseen. Näennäismuistia käyttävät nykyisin lähes kaikki käyttöjärjestelmät. Muistinhallinta on järkevää toteuttaa sivutusta käyttäen, sillä sen avulla muistin käytön voi rajata tiettyyn muistialueeseen. Segmentointitavalla rajoittamisen toteutus olisi vaikeampaa. Sivutus on otettavissa käyttöön CR0-rekisterillä. Segmenteillä voi pitää kirjaa kunkin ohjelman käyttämistä data-, koodi- ja pino-osista, mutta yhtä hyvin käyttöjärjestelmä voi käyttää koko neljän gigatavun osoitealueen kattavaa valitsinta. Tästä on kerrottu jo aiemmin. Katso Suojatun tilan edut.

Sivutusta ei voi käynnistää muuttaen vain CR0-rekisterin bittiä 31. On lisäksi luotava PDE- ja PTE-tietueet. PDE on page directory entry eli sivuhakemistotietue. PTE on page table entry eli sivutaulutietue. PDE- ja PTE-taulujen avulla loogiset osoitteet muutetaan fyysisiksi osoitteiksi. Katso Suojatun tilan edut.

Muistinhallintayksikön voivat käynnistää vain PL0-tason ohjelmat. Käyttäjätason ohjelmat eivät edes ole tietoisia muistinhallintayksikön olemassaolosta. Sivut jaetaan käyttäjä- ja järjestelmätasoihin. PL0-tason ohjelmat voivat käyttää mitä tahansa sivua. PL3-tason ohjelmat voivat käyttää vain käyttäjätason sivuja eli niillä ei ole pääsyä järjestelmätason sivuihin. Jos järjestelmässä ei ole neljää gigatavua muistia, olemattomalle muistille ei yleensä luoda sivutauluja. Nämä PDE-taulun kohdat merkitäänkin käyttämättömiksi.

Muistinhallintayksikkö muuntaa osoitteet PDE- ja PTE-tietueiden avulla. Kukin PDE-tietue kuvaa neljää megatavua yhtäjaksoista muistia. PDE-tietueessa on osoitin sitä vastaavien sivutaulujen alkukohtaan. PTE-tietueilla voidaan asettaa neljän kilotavun kokoisten lohkojen käyttöoikeudet. Nämä lohkot sijaitsevat PDE-tietueen neljän megatavun kokoisella muistialueella. PTE-tietueissa on merkittynä myös todellinen fyysinen osoite. On otettava huomioon, että PDE-tietue sisältää sivutaulujen fyysisen osoitteen. Muistinhallintayksikkö muuntaa lineaarisen osoitteen fyysiseksi osoitteeksi käyttäen lineaarisen osoitteen bittejä 31 – 22. Sillä valitaan kyseessä oleva PDE-tietue. Bittien 21 – 12 avulla valitaan yksi PTE-tietue 1024 sivutaulutietueen joukosta. Alimmat 12 bittiä muodostavat fyysisen osoitteen 12 alinta bittiä.

Nyt saattaa mietityttää kuinka muistinhallintayksikkö tietää missä PDE-sivuhakemistot sijaitsevat. PDE-tietueiden löytyminen ei ole ongelma, sillä CR3-rekisterissä on tallella PDE-tietueiden kantaosoite. Näin se tunnetaan myös nimellä PDBR eli page directory base register.6

fig8.gif


12 Suorittimen VM86-näennäistila

80386-suorittimella on kahden muun tilan lisäksi myös V86-tila. Siinä suoritin toimii 8086-suorittimen tavoin, muutamin erotuksin: Suoritin ei V86-tilassa salli etuoikeutettujen käskyjen kuten LGDT, LIDT, LLDT, SLDT, ARPL, LAR, LSL, LTR, VERR, VERW, INVD, WBINVD, WRMSR ja RDMSR suorittamista. Tavallisesta reaalitilasta poiketen muistinhallintayksikkö on V86-tilassakin toiminnassa, joten V86-tilaa käyttävä ohjelma on täysin käyttöjärjestelmän hallittavissa; etuoikeutettuja käskyjä ei voi suorittaa, joten haittaohjelmat eivät voi vahingoittaa tietoja ja koko järjestelmän jumiutumiselta vältytään.

Tehtävän sanotaan olevan V86-tehtävä, kun EFLAGS-rekisterin VM-bitti on päällä. Tätä bittiä voi muuttaa vain PL0-ohjelma. Tämän bitin voi niin ikään muuttaa TSS:ssä ennen tehtävän suorittamista. Reaalitilassa ajettavan tehtävän sijasta on kaikin puolin hyödyllisempää käyttää V86-tehtävää, koska se on turvallisempaa. Lisäksi ohjelman suorittaminen hidastuisi, jos suorittimen olisi vaihdettava suojatun ja reaalitilan välillä. Ohjelmaa on siis itse asiassa nopeampaa ajaa V86-tilassa kuin reaalitilassa.

V86-tehtävä käyttää reaalitilan ohjelman tavoin segmenttejä ja siirroksia, ei valitsin:siirros-paria. Se voi käyttää muistia yhden megatavun verran. V86-tehtävä suoritetaan aina PL3-tasolla. V86-tehtävä voi käyttää I/O-siirräntää vain, kun sen IOPL-taso on kolme (3) tai kun siirrännän käyttö on sallittu TSS-bittikartassa. Jos V86-tehtävä, jonka IOPL-taso on alle kolmen, yrittää suorittaa käskyn CLI, STI, INT, IRET, LOCK, PUSHF tai POPF, suoritin aiheuttaa yleisen suojausvirheen.


13 Suojatun tilan keskeytysten käsittely

Keskeytysten käsittely on käyttöjärjestelmän tärkeimpiä tehtäviä. Etenkin laitekeskeytysten virheellisestä käsittelystä voi koitua mitä vain; järjestelmä voi jumiutua tai aiheuttaa omituisia ongelmia. Tässä kappalessa valaistaan suojatun tilan ja V86-tilan keskeytysten käsittelyä.

Suojatun tilan keskeytysten käsittelyä on käsitelty aiemminkin. Katso 386-suorittimen poikkeukset.

V86-tilan keskeytysten käsittely onkin jonkin verran mutkikkaampaa; vaikka suoritin on V86-tilassa, keskeytykset on käsiteltävä suojatussa tilassa. 386 nollaa kaikki segmenttirekisterit ennen kyseessä olevan keskeytyskäsittelijän kutsumista, koska segmenttirekisterit sisältävät todennäköisimmin satunnaisarvoja. On pidettävä mielessä, että tässä puhutaan laitekeskeytyksistä, ei niistä INT-käskyjen aiheuttamista keskeytyksistä. SS-rekisteri sisältää valitsimen TSS-tietueen PL0-pinoa varten. PL0-pinoon lisättävän VM86-pinokehyksen rakenne on kuvattuna alla olevassa kuvassa.

fig9.gif

Yleinen suojausvirhe voi johtua joko VM86-tehtävän tai varsinaisen suojatun tilan ohjelman keskeytyksestä. Keskeytyksen käsittelijä voi tarkistaa kumpi suojausvirheen aiheutti tarkistamalla EFLAGS-rekisteristä onko V86-tehtävä käynnissä. Jos keskeytyksen aiheutti V86-tehtävä, keskeytyksen käsittelijä voi tarkastella virheen tuottanutta käskyä. Keskeytyksen syyn selvittyä käyttöjärjestelmä voi päättää emuloida kyseisen käskyn (kuten CLI- tai STI-käskyn), lopettaa ohjelman välittömästi tai ryhtyä muihin toimiin.


14 Suojatun tilan käyttö

Suojatun tilan käyttö edellyttää suojattuun tilaan siirtymistä. Jotain todellista työtä pääsee tekemään, kun siirtyy suojattuun tilaan noudattamalla seuraavia vaiheita:

  1. Luo globaali deskriptoritaulu, global descriptor table, GDT.
  2. Luo keskeytysdeskriptoritaulu, interrupt descriptor table, IDT.
  3. Ohjelmoi PIC-piiri luomaan eri keskeytyksiä.
  4. Luo TSS-tietue.
  5. Luo sivutaulut ja aseta CR3-rekisterin arvo (tämä ei ole pakollista).
  6. Pane CR0-rekisterin bitti 0 päälle.
  7. Lataa tehtävärekisteri, task register, TR.
  8. Hyppää TSS-valitsimeen.

GDT- ja IDT-taulujen luomisen pitäisi olla helppoa. Luo deskriptorit ja lataa GDTR-rekisteriin kyseisen taulun osoite ja koko. Alexei A Frounze'n tekemät ohjelmat kuvaavat nämä hyvin.

TSS-segmentinkin luominen voi olla helppoa, kunhan noudattaa huolellista käsittelyjärjestystä. Asian pitäisi olla kunnossa, kun siirtyy lopuksi TSS:ään far-hypyllä.


15 Suojatun tilan ohjelmasarja

Alexei A Frounze on kirjoittanut upean suojattua tilaa käsittelevän ohjelmasarjan. Ohjelmasarja on ladattavissa osoitteesta http://members.tripod.com/protected_mode/alexfru/pmtuts.html.

Ohjelmien ajamiseen tarvitsee järjestelmän, jossa on seuraava kokoonpano:

  • 80386 tai sitä uudempi suoritin
  • DOS 5.0 tai uudempi, tai Windows 9x MS-DOS-tilassa (Ei siis MS-DOS-ikkunasta.)
  • EMM386- ja HIMEM.SYS-tyyppisten ajurien poistaminen käytöstä
  • Vähintään kaksi megatavua työmuistia
  • VGA- tai SVGA-yhteensopiva näytönohjain

Ohjelmat on lyhyelti kuvattuna tässä:

  1. Siirtyy suojattuun tilaan ja palaa reaalitilaan käyttäen CR0-rekisteriä.
  2. Luo GDT-taulun, siirtyy suojattuun tilaan, tulostaa tervehdyksen ja palaa reaalitilaan.
  3. Luo IDT-tauluun tiedot keskeytyspalvelurutiineja varten (Int 20h) sekä nollallajakopoikkeusta varten (Int 0). Tämä ohjelma kuvaa, kuinka nämä käsittelijät toimivat.
  4. GDT-taulu sama kuin ennenkin, IDT-taulu asetetaan kaikille poikkeuksille, poikkeuksen tyyppi ja osoite on nyt nähtävissä.
  5. GDT-taulu sama kuin ennenkin, IDT-taulu lähes sama kuin neljännessä ohjelmassa. Lisätty kaksi IDT-tietuetta ja IRQ-käsittelijää: IRQ0 ajastinta varten ja IRQ1 näppäimistöä varten. Tämä ohjelmoi PIC-piirin uudelleen, jotta PIC-piiri osaa käsitellä IRQ-linjoja suojatussa tilassa.
  6. Lähes sama kuin viides ohjelma. Lisätty tehtävävaihto.
  7. Moniajoesimerkki.
  8. Havainnollistaa sivun muuntamisen, page translation.
  9. Tämä ohjelma poikkeaa hieman seitsemännestä ohjelmasta, sillä tämä ei vaihda tehtäviä TSS:n avulla, vaan käyttää pinoon perustuvaa tehtävän vaihtoa.
  10. Tämä ohjelma esittelee Big/Unreal-tilat eli kuvaa kuinka muistia voi käyttää neljä gigatavua ilman suojattuun tilaan siirtymistä.
  11. Tämä on lähes sama kuin seitsemäs ohjelma. Ainoa ero on, että tehtävät ovat 32-bittisiä.
  12. Tämä on lähes sama kuin 11. ohjelma, mutta nyt jokaiselle PL3-tason tehtävälle on lisätty kaksi LDT-tietuetta.
  13. Moniajo. Tässä ajamme ensimmäisen kerran näennäistä 8086-suoritinta.
  14. Kehittyneempiä V86-asioita. V86-tehtävissä voi nyt käyttää ohjelmistokeskeytyksiä (Int nn).
  15. Toimiva V86-seurantaohjelma, DOS-ikkunan kaltainen.
  16. Sama V86-seurantaohjelma. Pienehköjä muutoksia: V86-tehtävät voivat käyttää yksivaiheista ohjelmistokeskeytystä Int 1.


16 Tietoja tästä oppaasta

Tämä on henkilön Prashant TR kirjoittama ja ylläpitämä opas. Voit lähettää kommentit, kysymykset ja muut ehdotukset henkilön Prashant TR sähköpostiosoitteeseen tai PMode-palstalle. Varmista, että viittaat tämän oppaan tuoreimpaan versioon. Tuorein versio on osoitteessa http://members.tripod.com/protected_mode/. Mikäli tämän oppaan ymmärtämisessä on ongelmia tai haluat esittää kysymyksen, harkitse liittymistä PMode-palstalle. Ohjeet palstalle liittymiseen on osoitteessa http://www.midpec.com/. Palstalle voi vapain mielin lähettää kommentteja.

Jos sinulla on jotain kysyttävää tästä suomennetusta versiosta, ota yhteys sen kääntäjään Jouni Kähköseen (jouni at kajouni net).

Seuraavat henkilöt ovat lähettäneet arvokkaita kommentteja ja tietoja ja tehneet tästä oppaasta menestyksen:

  1. Alexei A Frounze - Alexei A Frounze on työskennellyt käyttöjärjestelmäkehityksen parissa jo kauan. Hän on myös fysiikan opettaja.
  2. Eli Zaretskii - Eli Zaretskii on työskennellyt DJGPP-projektin parissa useita vuosia. Hän on DJGPP:n usein kysyttyjen kysymysten kirjoittaja ja ylläpitäjä ja hän on muuntanut DJGPP-kääntäjälle useita Unix-paketteja. (Katso luettelo eri pakettien avustajista).

Viitteet

  1. Todellisuudessa näin tuskin käy. Useimmat BIOS-järjestelmät ja jopa DOS käyttävät joskus RETF 2 -tyyppisiä käskyjä, jolloin tästä INT-IRET-sekvenssistä tulee niin epävakaa V86-tilan keskeytysten simuloimiseksi. Kiertotie on käyttää erityistä VM86-pinokehystä, joka hoitaa kaiken tämän.

  2. Määritelmän mukaan 8086 ei voi maskata NMI:tä. PC:n emolevyllä ei ole piiriä, joka voisi estää NMI:n ilmenemistä. NMI:tä on kuitenkin harvoin tarve estää. AT-emolevyissä sitä voidaan kuitenkin ohjata portin 70H avulla. Tämän portin bitin 7 nollaaminen poistaa NMI:n käytöstä.

  3. Useat ohjelmat pääsevät yhden megatavun muistirajoituksen yli ottamalla vain A20-linjan käyttöön. Kun A20-linja on käytössä, osoitteet eivät ole kiertäviä, jolloin muistia voi käyttää reaalitilaan siirtymättä yhden megatavun rajoituksen lisäksi 64 kilotavua. Tästä voi kuitenkin koitua ongelmia muistinhallinnassa, joten se on tehtävä varoen.

  4. 386-suorittimen suojatun tilan IRET-käskyllä on eri merkitys kuin sillä on reaalitilassa. Suojatussa tilassa keskeytyksen käsittelijästä palataan IRETD-käskyllä.

  5. Ohjelmakeskeytyksillä (trap) ei ole mitään tekemistä trap-porttien kanssa. Ohjelmistokeskeytyksiä voidaan käsitellä käyttämällä joko keskeytysporttia tai trap-porttia.

  6. Huomaa, että PDE-tietueen ja kaikkien PTE-tietueiden on sijaittava neljän kilotavun lohkon alkupäässä.