Suojattu tila
Mureakuha
Suojattu tila. - Kääntänyt Jouni Kähkönen 3. - 10.6. 2005
HUOM: Uusin versio tästä dokumentista ja muista suomenkielisistä suojattuun tilaan liittyvistä asiakirjoista löytyy osoitteesta: http://seko.homelinux.net/dload/info/
Tämä dokumentaatio kirjoitettiin siksi, koska DJGPP:n postituslistalla yhä enenevässä määrin on kyselty, mikä se suojattu tila oikeastaan on. Tämä dokumentaatio sisältää yksityiskohtaisia tietoja suojatusta tilasta. Aloittelijat, jotka haluavat vain tietää perusseikat suojatusta tilasta, voivat lukea vain johdanto-osion. Kuitenkin niiden, jotka tarvitsevat syvempiä tietoja, on hyvä jatkaa pidemmälle.
Jos sinulla on jotain kysyttävää, voit lähettää sähköpostia englanniksi PMode-palstalle. Ohjeet palstalle kirjautumiseen löytyy tämän dokumentin lopusta.
Johdanto suojattuun tilaan
Lyhyt johdanto suojattuun tilaan
Mikä on suojattu tila
80386+ tuo mukanaan lukuisia uusia ominaisuuksia, jotka paikkaavat 8086:sen heikkoudet. 8086-prosessorissahan ei ollut juuri minkäänlaista tukea muistin suojaukselle, virtuaalimuistille, moniajolle ja muistille yli 640Kt:n. Suojattu tila säilyttää samalla yhteensopivuuden 8086-sarjan prosessoreiden kanssa. DJGPP:ssä 386, 486 ja sitä uudemmat prosessorit oletetaan olevan samoja. 386:n perusperiaatteet ovat samat myös sitä seuraavissa prosessoreissa.
8086 käyttää vain yhtä tilaa - reaalitilaa. Kun insinöörit Intelillä suunnittelivat 286-prosessoria, he halusivat tukea uusia lisäominaisuuksia, joita ei vielä 8086:ssa ollut. He halusivat kuitenkin säilyttää yhteensopivuuden 8086:seen. Täyttääkseen nämä vaatimukset he tekivät 286:sta prosessorin, joka osaa toimia kahdessa eri tilassa - reaalitilassa ja suojatussa tilassa. Reaalitilassa, joka on oletuksena, prosessori toimii juuri niin kuin 8086 - lukuunottamatta joitain pieniä parannuksia. Suojatussa tilassa on suuria eroja reaalitilaan nähden. Lähes kaikki ohjelmat, jotka on suunniteltu toimimaan 8086:ssa, eivät toimi suojatussa tilassa, ellei ohjelmaan tehdä tehdä suuria muutoksia. DOS on yksi tällaisista ohjelmista.
386:ssa on kaikki ne ominaisuudet, jotka on 8086:ssa ja 286:ssa, mutta lisäksi mukana on paljon kehittyneitä ominaisuuksia. Oletusarvona on reaalitila - niin kuin aikaisemmissakin prosessoreissa. 386 osaa toimia suojatussa tilassa, aivan kuten 286:kin. Kuitenkin sisäisesti 386 on täysin erilainen. 386:ssa suojattu tila tarjoaa ohjelmoijalle paremman suojauksen ja enemmän muistia kuin 286:ssa. 386 tukee lisäksi vielä kolmatta toimintatilaa, Virtuaalinen 8086 (V86) tila. V86-tilassa 386 toimii suojatussa tilassa, mutta sallii joidenkin ohjelmien käyttää simuloitua reaalitilan ympäristöä. Se tarkoittaa sitä, että sellaisia ohjelmia kuten esimerkiksi DOS voidaan suorittaa suojatussa tilassa ilman että täytyisi vaihtaa suojatun ja reaalitilan välillä. V86-tila sisältää monia etuja reaalitilaan nähden. Niistä kerron lisää seuraavien kappaleiden joukossa.
Suojatun tilan edut
Kaikki 386:sen erityiset ominaispiirtet ovat käytettävissä prosessorin toimiessa suojatussa tilassa. Tässä on mainittuna joitain niistä...
Voi käyttää 4 gigan verran muistia - Tämä on kaikkein selvin ero suojatun tilan ja reaalitilan välillä. Suojatun tilan ohjelmat voivat käyttää enimmillään jopa 4 gigatavua muistia data-, koodi- ja pinotiloille. Käyttämällä joitain dokumentoimattomia 8086-prosessorin ominaisuuksia voidaan kyllä reaalitilan ohjelmissakin käyttää lisää muistia, mutta enimmillän vain 1 megatavua, ja sekin vain data-segmentin tallentamiseen. Joka tapauksessa, näiden tekniikoiden käyttäminen koodi- ja pinotiloille on suorastaan epäkäytännöllistä. Et ilmeisesti tarvitse normaalissa käytössä koneessasi 4 gigatavua muistia, mutta se onkin tulevaisuutta varten.
Virtuaalimuisti - 386:sen muistinhallintayksikön (Memory Management Unit, MMU) avulla pystytään toteuttamaan ns. virtuaalimuisti, jonka avulla ohjelma luulee, että sillä on käytössään kokonaiset 4 gigatavua muistia, vaikka todellisuudessa sillä onkin vähemmän (periaatteessa todella paljon vähemmän). 386 ja erityinen käyttöjärjestelmäohjelmisto simuloivat lisämuistia käyttämällä massamuistia tukenaan (kuten kovalevyä). Tarvitaan tietysti noin 4 gigatavua vapaata levytallennustilaa, mutta se onkin jo toinen ongelma.
Osoitteenkäännös - MMU:n avulla voidaan kääntää eli kartoittaa osoitteita ennen niiden käyttöä (memory translation tai mapping). Saatat esimerkiksi haluta kääntää kaikki viittaukset 4Kt:n lohkoon segmentissä B800H (CGA:n tekstipuskuri) ohjelmasi omaan datapuskuriin. Sittemmin ohjelmasi voi kopioida puskurin esimerkiksi näytölle. Tämä on käytännöllistä etenkin silloin, kun halutaan uudelleen ohjata sellaisen ohjelman ulostulo, joka kirjoittaa suoraan näyttömuistiin. Muistinkäännös eli translaatio voi myös simuloida laajennettua muistia, vaikka muistia ei olisi enempää asennettunakaan. EMS:n myöhemmissä versioissa on kuitenkin tiettyjä toimintoja, joita MMU ei kykene emuloimaan. Tuskin tulet kuitenkaan tarvitsemaan kyseisiä toimintoja juuri koskaan - et edes kehittyneitä ohjelmia tehdessä.
Ohjelmat työskentelevät loogisten osoitteiden kanssa. 386-prosessori muuntaa nämä loogiset osoitteet 32-bittisiksi lineaarisiksi (segmentoimattomiksi osoitteiksi). MMU-yksikkö sitten muuntaa lineaariset osoitteet fyysisiksi osoitteiksi. Jos MMU ei ole päällä, lineaariset ja fyysiset osoitteet ovat samoja. Soveltaen tätä tekniikkaa reaalitilaan osoite B800:0010 on looginen osoite. Sitä vastaava lineaarinen osoite on B8010H. Koska reaalitila ei käytä MMU-yksikköä, fyysinen osoite on sama kuin lineaarinen osoite.
Kehittynyt segmentointi - Reaalitilassa kaikki segmentit ovat 64 Kt kokoisia ja ovat kiinteässä sijainnissa. Suojatussa tilassa segmentti voi olla vain yhden tavun kokoinen tai vastaavasti jopa 4 gigatavun kokoinen. Funktio __djgpp_nearptr_enable() käyttää tätä ominaisuutta. Yrittäminen käydä käsiksi muistiin, joka on segmentin ulkopuolella, aiheuttaa virheen. Jos segmentti on 4 gigatavun kokoinen ja ohjelma yrittää käsitellä muistia 4 gigatavun rajan ulkopuolelta, osoite kierretään muistin alkuun. Segmentit voivat alkaa mistä sijainnista tahansa. Ohjelmoija päättää itse segmenttien käyttötarkoituksen, sillä 386:n takia niin on pakko tehdä. Se tarkoittaa sitä, että jos ohjelma yrittää kirjoittaa dataa segmenttiin, joka onkin tarkoitettu ohjelmakoodille, 386 aiheuttaa virheen eikä anna ohjelman kirjoittaa kyseiselle alueelle. Voit myös määritellä segmentin, joka kattaa koko 4 gigatavun osoiterajan ja jaat segmentit tehokkaasti keskenään. Kaikki muistiinviittaukset kulkevat sitten 32-bittisen segmentoimattoman osoittimen kautta. Tällaiset "litteät" osoittimet vastaavat suoraan lineaarisia osoitteita.
Muistinsuojaus - 386:ssa muisti voidaan suojata. Käyttäjän ohjelma ei esimerkiksi pysty kirjoittamaan käyttöjärjestelmän datan päälle. Tämä, yhdessä segmenttien merkintöjen kanssa, suojaavat ohjelmia virheiltä, jotka saattaisivat kaataa koko tietokoneen.
Prosessien suojaus - Ohjelmat (tai ohjelman osat) voidaan suojata toisistaan. Ohjelma ei voi käyttää toisen ohjelman dataa, kun taas käyttöjärjestelmällä on pääsy kaikkien dataan. Käyttäjäohjelmilla on käyttöjärjestelmän dataan vain rajoitettu pääsy. Tämä toteutetaan itse asiassa MMU:ssa olevalla sivunsuojausmekanismilla.
32-bittisten rekisterien käyttö- Kaikki yleiskäyttöiset rekisterit 386:ssa ovat 32-bittiä leveitä. Näillä rekistereillä on muuten sama nimi kuin 8086:n rekistereillä paitsi että niiden edessä on E-etuliite (esim. EAX, eikä AX). Mukana on myös kaksi uutta segmenttirekisteriä (FS ja GS); niitä voi käyttää molemmista tiloista, mutta ovat hyödykkäimpiä suojatun tilan ohjelmissa. Reaalitilan ohjelmat voivat myös käyttää näitä 32-bittisiä rekistereitä, mutta ne eivät voi käyttää niitä indeksointitarkoituksiin. Ja 32-bittisten rekistereiden käyttö suojatussa tilassa (32-bittisessä suojatussa tilassa) pudottaa koodin kokoa ylipäänsä.
Kehittyneet osoitustilat- Reaalitilassa ohjelmat voivat muodostaa osoitteita vain vakioarvoilla, eli BX- tai BP-rekistereillä, ja SI- ja DI-rekistereillä. Suojatun tilan ohjelmissa mikä tahansa rekisteri voi muodostaa osoitteita. Indeksi voi sisältää skaalatekijän yhdestä, neljästä tai kahdeksasta. Tämän avulla voit kirjoittaa sellaisia käskyjä kuin MOV EBX, [EDI][EAX*8]+2.
Voi käyttää moniajoa - 386:ssa on erityisiä ominaisuuksia prosessorin nykyisen tilan tallentamiseen ja uuteen työtehtävään vaihtamiseen (nimeltään kontekstin vaihto). Kontekstin voi vaihtaa hetkessä käyttäen yhtä ainutta käskyä. Tällä on tärkeä merkitys käyttöjärjestelmän ja reaaliaikaisen prosessoinin kannalta. 386 tukee myös "sisäkkäitä" työtehtäviä (nested tasks). Työtehtävä voi palata alkuperäiseen työtehtäväänsä käyttämällä back-linkkiä.
Laitteiston debuggaus - 386:ssa on erityinen laitteisto yksivaiheisen koodi- ja data-breakpointtien toteuttamiselle. Tämä laitteisto on käytettävissä reaalitilassa pienten lisätekniikoiden avulla.
Osoittaminen reaalitilassa
8086-tyyppisissä prosessoreissa muisti on järjestetty tavuiksi (8 bittiä=1 tavu). Kahdeksaa bittiä suurempia määriä käsitellessä 8086 tallettaa vähiten merkitsevän tavun alimpaan osoitteeseen. Tämä kuulostaa loogiselta, mutta on hyvin häiritsevää esim. luettaessa listauksia tai muistin vedoksia, koska numerot näyttävät olevan takaperoisessa järjestyksessä. Esimerkiksi tietokone tallettaa sanan B800H kahtena tavuna: 00H, jonka jäljessä on B8H.
Intel-sarjan prosessorit käyttävät muistinosoitustekniikkaa nimeltä segmentointi. Segmentti on muistialue muistissa. Tietokone osaa käsitellä useita segmenttejä. Reaalitilassa (eli tilassa, jota DOS:kin tavallisesti käyttää) segmentit ovat 64 Kt:n kokoisia ja saatavilla on 65536 segmenttiä. Nämä segmentit kuitenkin menevät jonkin verran päällekkäin siten, että kukin niistä alkaa 16 tavua ennen edellisen segmentin loppumista. Tämän takia DOS ei voi tavallisesti osoittaa enempää kuin 1 Mt:n muistia (65536 * 16 = 1048576 = 1 Mt). 8086- ja 8088-prosessorit voivat joka tapauksessa osoittaa vain 1 Mt:a muistia, mutta 286 ja 386+ voivat jo käyttää paljon enemmän. Kuitenkaan DOS ei sitäkään voi käyttää suoraan.
Segmentit on numeroitu alkaen 0000H:sta aina FFFFH:hon. Koska segmentit ovat kooltaan 64 Kt, meidän täytyy käyttää erityistä arvoa nimeltään siirros (eng. offset) määrittelemään haluamamme tarkan tavun, johon haluamme osoittaa. Täydellinen 8086-tyyppinen osoite sisältää aina segmentin sekä siirroksen.
Jos segmentti on 0040H ja siirros on 0102H, kirjoitamme 0040:0102. Koska segmentit limittyvät joka 16:nes (10H) tavu, osoite 0000:0010 on yhtäläinen osoitteeseen 0001:0000 verrattuna. Samaten 0040:0000 on sama osoite kuin 0000:0400, joka on taasen sama kuin 0020:0200. Kone tallentaa segmentoidut osoitteet aina "nurinkurin". Esim. 0040:1234 näkyy koneen muistissa tähän tapaan (heksana): 34 12 40 00 Varmistaaksesi kaikkien yllä mainittujen osoitteiden olevan yhtäpitäviä muunna ne lineaarisiksi osoitteiksi. Segmentoidun osoitteen voi muuttaa lineaariseksi osoitteeksi kertomalla segmentin arvon kuudellatoistalla (16 eli 10H) ja lisäämällä siihen siirroksen arvon. Eli siis näin (kaikki heksoina): 0040 * 10 + 0000 = 00400 0000 * 0 + 0400 = 00400 0020 * 10 + 0200 = 00400 Näistä kaikki osoittaa lopulta samaan muistin alueeseen.
Rekisterit 80386:ssa
80386:ssa on neljä yleiskäyttöön käypää rekisteriä, yksi lippurekisteri, kuusi segmenttirekisteriä, kaksi indeksirekisteriä, yksi pinosegmenttirekisteri ja -osoitin, kantarekisteri sekä käskyyn osoittava rekisteri. Näiden lisäksi 386:ssa on vielä muita 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)
Seuraavasta kaaviosta näkee useimmat näiden rekistereiden nimistä ja merkityksistä. Kuten huomaat 386+ tuo mukanaan moninaisia erikoisrekistereitä. Ne eivät ole yleensä hyödyllisiä DOS:issa, mutta tulemme näkemään joitain niistä käydessämme läpi Dosiin saatavia suojatun tilan laajennuksia.
Reaalitilan vektoritaulukko
8086-sarjan prosessorit voivat reagoida 256 eri keskeytykseen. Kohdasta 0000:0000 alkaen muistissa on taulukko, joka sisältää osoitteet kuhunkin keskeytykseen. Kukin tässä keskeytysvektoritaulukossa oleva kohtio on aina neljän tavun mittainen, joka riittää juuri segmentin ja siirroksen tallettamiseen. Muistissa on siis 1024 tavun eli 1 kilotavun kokoinen varattu alue reaalitilan keskeytysvektoritaulukkoa varten. Kun prosessori vastaanottaa sanotaan vaikka keskeytyksen 2 (INT 2), se tallentaa lippurekisterin sekä CS- ja IP-rekistereiden sen hetkiset arvot pinoon. Sitten se hakee osoitteen, joka on talletettuna muistin kohdassa 0000:0008 ja käynnistää saadusta osoitteesta löytyvän keskeytyspalvelurutiinin (ISR, Interrupt Service Routine). IRET-komento ISR:ssä ilmaisee keskeytyksen suorittamisen loppuneen1 ja aiheuttaa sen, että prosessori palaa takaisin siihen, mitä oli ennen keskeytyksen täytäntöönpanemista tekemässä.
Laitteistokeskeytykset
Laitteistokeskeytys on erityinen signaali I/O-laitteelta tietokoneelle. Tämä signaali informoi tietokoneelle, että I/O-laite tarvitsee huomiota. Tavallisesti prosessori keskeyttää sen hetkisen tekemisensä, jotta se voisi palvella keskeytystä. Kun keskeytys on suoritettu loppuun, prosessori jatkaa siitä, mihin se jäikin.
Laitteistokeskeytyksiä tulee eri lähteistä. Esim. joka kerta kun painat pohjaan tai vapautat näppäimen, aiheutat keskeytyksen. Muita keskeytyksiä tulee esim. kellolta, tulostimelta, sarjaportista, levyohjaimilta ja niin pois päin. Prosessorikin aiheuttaa joitain keskeytyksiä. INT 0 esimerkiksi aiheutuu, kun ohjelma yrittää jakaa nollalla. Nämä kaikki ovat laitteistokeskeytyksiä. Laitteistokeskeytyksen käsittely on ehkä yksi tärkeimmistä tehtävistä suojatussa tilassa. Huonosti sanottuna laitteistokeskeytyksen käsittelijät saattavat aiheuttaa suuronnettomuuksia.
Emolevyllä sijaitseva 8259 ohjelmoitava keskeytyksenohjain (PIC, Programmable Interrupt Controller) hoitaa kaikki laitteistokeskeytykset. Nämä ohjaimet vastaanottavat keskeytyssignaaleja eri laitteilta ja muuntavat ne sitten sopiviksi keskeytyksiksi prosessorille.
Alla olevasta taulukossa näkee reaalitilan laitteistokeskeytykset niitä vastaavien PIC-keskeytyksenkutsusyötteiden kanssa (tunnetaan nimellä IRQ-linjat). Älä sekoita IRQ-numeroita keskeytysnumeroihin. Esimerkiksi näppäimistö kytkeytyy IRQ1-linjaan, joka lähettää INT 9 -keskeytyksen CPU:lle. PIC-piirejä voi myös uudelleen ohjelmoida siten, että ne luo IRQ-linjoille eri keskeytysnumeroita. Tätä tekniikka käyttävät yleensä näytönkaappausohjelmat sekä DOS-laajentajat kuten go32.
PIC-piirit ohjelmoivat myös keskeytysprioriteettejä. Esim. kellolla (linjalla IRQ 0) on suurempi prioriteetti kuin näppäimistöllä (IRQ 0). Jos prosessori on parhaillaan palvelemassa kello-keskeytystä, PIC ei voi aiheuttaa keskeytystä näppäimistölle ennen kuin kellon ISR resetoi PIC:in. Toisaalta kello voi keskeyttää näppäimistön ISR:n. PIC-piirejä voi ohjelmoida siten, että ne käyttävät erilaisia prioriteettiskeemoja, mutta tämä on epätavallista, tuskin koskaan PS-ohjelmoinin parissa käytettyä.
AT:n lisä-PIC kytkeytyy ensimmäisen PIC:in IRQ 2:seen. Siten lisä-PIC:in IRQ-linjoilla (8:sta 15:aan) on sama prioriteetti kuin IRQ 2:sella. IRQ 2:sen estäminen estää kaikki keskeytykset toisesta PIC-piiristä.
Keskeytys IRQ-numero Kuvaus
00H - Jako nollalla tai jakaessa ylivuoto
02H - NMI (Non-maskable Interrupt)
04H - Ylivuoto (INTO:n aiheuttama)
08H 0 Järjestelmän ajastin
09H 1 Näppäimistö
0AH 2 Keskeytys toiselta PIC-piiriltä
0BH 3 COM2
0CH 4 COM1
0DH 5 LPT2
0EH 6 Levykeasema
0FH 7 LPT1
70H 8 Reaalitilan kello
71H 9 Yleinen I/O
72H 10 Yleinen I/O
73H 11 Yleinen I/O
74H 12 Yleinen I/O
75H 13 Matematiikkaprosessori
76H 14 Kovalevy
77H 15 Yleinen I/O
Voit estää keskeytyksiä häiritsemästä ohjelmakoodisi tärkeän osuuden suorittamista. CLI-käsky estää kaikki keskeytykset paitsi nonmaskable-keskeytyksen (NMI), koska NMI:tä, joka ei kulje PIC-piirin kautta, ei voida pysäyttää tällä keinolla2. Lisäksi PIC-piirit voidaan uudelleen ohjelmoida niin, että ne kytkevät pois tietyt keskeytykset.
Näppäimistö ja A20-linja
Tavallisesti oletamme, että 80386 wrappaisi reaalitilan osoitteita. Tämän aavistaen AT-emolevyn suunnittelijat reitittivät A20-linjan näppäimistön ohjaimen kautta. Tavallisesti ohjain estää A20-linjaa tavoittamasta muistipiirejä. Erityinen näppäimistön ohjaimelle annettu komento pystyy ottamaan A20-linjan käyttöön, ja toinen komento voi taas poistaa sen käytöstä sitten myöhemmin. Tämä niin kutsuttu A20-portti on keskeinen osa laajennetun muistin käytössä, olimme sitten reaalitilassa tai suojatussa tilassa3.
Segmentin selektorit ja deskriptorit
Segmentin selektorit (valitsijat)
Segmenttien käsittäminen on avainasia suojatun tilan ymmärtämisessä. Suojatun tilan segmenteillä on vähän yhteistä reaalitilan segmenttien kanssa. Suojatun tilan segmenttiin menee 16-bittinen segmenttiselektori (katso kuvaa alla). Vastoin kuin reaalitilassa, suojatussa tilassa selektorilla ei ole mitään tekemistä sillä, missä segmentti sijaitsee muistissa. Sen sijaan, rekisterissä sijaitseva arvo on indeksi segmenttideskriptoreista koostuvan taulukon sijaintiin. Kukin deskriptori määrittelee yhden segmentin ja määrittää, missä segmentti sijaitsee, minkätyyppinen segmentti on ja muita tärkeitä parametrejä, kuten käyttöoikeudet.
Selektori sisältää kolme kenttää. Alimmat kaksi bittiä (RPL) viittaa 386:sen suojausmekanismiin, josta kerrotaan lyhyesti myöhemmin. Seuraava bitti, TI, määrittää, mikä taulukko deskriptoreista määrittelee segmentin.
Segmenttideskriptoritaulukkoja on kolmea tyyppiä:
- Global Descriptor Table (GDT)
- Interrupt Descriptor Table (IDT)
- Local Descriptor Table (LDT)
Segmenttiselektorit eivät koskaan viittaa IDT-taulukkoon. Jos TI on nolla, segmentin määrittelyt ovat GDT:ssä. Jos se on yksi, LDT sisältää kyseisen informaation.
Suojatussa tilassa tarvittavat taulukot
Jokainen deskriptoritaulukko pystyy sisältämään maksimissaan 8192 deksriptoria. Selektorissa sijaitsevat INDEX-bitit (bitit 15:sta 3:seen) päättävät, mitä deskriptoria käytetään.
GDTR- ja IDTR-rekisterit päättävät GDT- ja IDT-taulukoiden sijainnit vastaavasti. Kumpikin sisältää 32-bittisen osoitteen ja 16-bittisen rajan. Raja on yhden (1) tavun pienempi kuin taulukon leveys. GDTR ja IDTR ovat 48-bittisiä rekistereitä. Osoite on lineaarinen eikä segmentti-siirros -pari. Taulukko voi sisältää maksimissaan 64 Kt eli 8192 deskriptoria.
GDT-taulukko, kuten nimikin kertoo, on globaali; jopa silloin, kun järjestelmä pyörii moniajolla, kaikki työtehtävät jakavat saman GDT:n. Tämä pitää paikkansa myös IDT:lle - kukin työtehtävä käyttää yhtä ja samaa taulukkoa. Jos joku työtehtävä muuttaa GDT:ta tai IDT:tä, se vaikuttaa kaikkiin työtehtäviin.
LDTR määrittää LDT:n sijainnin. Vastoin kuin GDT:ssä, kullakin työtehtävällä on yleensä oma LDT-taulukkonsa. Vastoin kuin GDTR:ssä, LDTR ei sisällä 48-bittistä osoitetta&arvoa. Sen sijaan se pitää sisällään segmenttiselektoria, jonka on osoitettava tiettyyn kohtioon GDT-taulukossa. Tämä GDT-kohtio osoittaa LDT:hen. GDT-taulukko voi sisältää osoittimia useisiin LDT-taulukoihin.
IDT vastaa reaalitilan keskeytysvektoritaulukkoa. Kukin deskriptori määrittelee reaktion yhteen 256:stä mahdollisesta keskeytyksestä. Vaikka IDT voi sisältää jopa 8192 deskriptoria, yhtään yli 256:n on vaan tuhlausta.
Alla olevasta kuviosta näet deskriptoritaulukon kohtion perusformaatin. Mukana on myös muita erityistyyppisiä deskriptoreita.
Kuva:Index tiedostot/fig4.jpg Kuva:Index tiedostot/fig5.jpg
Deskriptorit
Kaksi kenttää segmenttideskriptorissa ovat erityisen kiinnostavia. P-bitti (bitti 47) määrittelee sen, onko segmentti käytössä. Käyttöjärjestelmä voi nollata tämän bitin luodakeen virtuaalisegmentin Kun ohjelma yrittää käyttää virtuaalisegmenttiä, 386 generoi virheen. Käyttöjärjestelmä voi siten ladata segmentin levyltä ja yrittää uudestaan. Kun P on nollattuna, bitit 0:sta 39:ään ja 48:sta 63:een voivat sisältää mitä tahansa arvoja. Käyttöjärjestelmä voisi tallentaa tähän tilaan vaikka levyn osoitteen. Tämä ei kuitenkaan kelpaa, jos segmentin koko on suuri. Onneksi 386 tarjoaa paremman tavan käyttää virtuaalimuistia.
Toinen kiinnostava kenttä on A-bitti (bitti 40). 386 asettaa tämän bitin päälle, jos jokin ohjelma kirjoittaa segmenttiin. Meidän "raaka" virtuaalimuistimme voisi käyttää tätä bittiä päättämään, onko sen kirjoitettava segmentti levylle ennen sen tekemistä poissaolevaksi ja sen tilan uudelleen käyttämistä ennen.
Toinen kysymys on se, että miten deskriptori pystyy määrittelemään segmentin yhdestä tavusta 4 gigatavun pituiseksi. Annettu raja-aluehan on vain 20 bittiä. Tähän tulee G-bitti (bitti 55) apuun. Jos G on nolla, raja-alue vastaa segmentin maksimaalista sallittua siirrosta (eli yhden vähemmän kuin segmentin leveys). Jos G on yksi, 386 siirtää raja-alueen bittejä 12 kohtaa vasemmalle luodaksensa 32-bittisen rajan. 386 täyttää loput 12-bittiä ykkösilä.
Esimerkki: Jos deskriptorin raja-alue on yksi, ja G on yksi, oikea raja on 1FFFH. Kun G on yksi, ja raja on nolla, raja on FFFFH.
Tämän menetelmän avulla voimme määritellä segmentin, jonka leveys on alle 1 megatavun tai 4 kilotavun kerrannaisina. Kun G on nolla, segmentti voi ulottua yhdestä tavusta 1 megatavun mittaiseksi. Kun G on yksi, segmentti ulottuu 4 kilotavusta 4 gigatavuun leveydessä (4 kilotavun askelin). On mahdollista luoda kaksi tai usempia deskriptoreita, jotka osoittavat samaan muistialueeseen. Käyttöjärjestelmä voi esim. ladata tiedoston datasegmenttiin ja hypätä sitten koodisegmenttiin, joka alkaa samasta paikasta. Tämä toimenpide tunnetaan nimellä aliasing. Käyttöjärjestelmällä on oltava jonkinlainen keino ladata GDT ja muut taulukot. Siksi sillä on yleensä GDT-taulukkoon datasegmentti-alias. Jotkut järjestelmät asettavat pystyyn datasegmentin, joka kattaa koko 4 gigatavun muistialueen. Siten taulukot voidaan kirjoittaa suoraan tuohon datasegmenttiin. Harva käyttöjärjestelmä sallii käyttäjäohjelmien päästä suoraan käsiksi GDT-, IDT- ja muihin järjestelmätaulukoihin.
Prosessori varaa ensimmäisen lohkon GDT:stä. Tämän lohkon selektori on ns. nollaselektori (null selector), ja sen käyttäminen aiheuttaa aina virheen. Nollaselektorin deskriptoreiden kuuluisi aina olla nollia. Nollasta poikkeavat arvotkin toimivat, mutta eihän sitä koskaan tiedä ;-).
Suojatun tilan etuoikeudet
Suojattu tila on saanut nimensä 386:sen etuoikeus-suojauksesta. Jokaisella ohjelmalla on oma etuoikeustaso eli privilege level, PL, väliltä nolla ja kolme. PL0-tason ohjelmat voivat suorittaa mitä tahansa käskyjä ja päästä käsiksi mihin tahansa dataan. PL3-tason ohjelmat eivät voi suorittaa tiettyjä käskyjä; ne eivät myöskään voi käsitellä dataa, joka kuuluu suuremman etuoikeustason ohjelmille. Kullakin segmenttideskriptorilla on Descriptor Privilege Level (DPL), jota 386 käyttää suojauksessa. 386 määrää myös, mitkä ohjelmat saavat suorittaa I/0-käskyjä.
Etuoikeus-hierarkia on tärkeää nykyaikaisten käyttöjärjestelmien tukemisessa. Tyypillisessa käyttöjärjestelmässä pääkerneli toimii PL0-tasossa. Muut käyttöjärjestelmän osat saattavat pyöriä PL1-tasossa. Laiteajurit voisivat pyöriä PL2-tasossa; niidenhän on käsiteltävä I/O-laitteita suoraa. Käyttäjäohjelmat tässä järjestelmässä voisivat pyöriä PL3-tasossa. Tällä ehdotelmalla on monia etuja. Etenkin ilkeämieliset ohjelmat eivät näin pysty vahingoittamaan käyttöjärjestelmää tai muita käyttäjäohjelmia.
Vain PL0-ohjelmat voivat suorittaa seuraavia käskyjä: •HLT •CLTS •LGDT •LIDT •LLDT •LTR •LMSW •MOV (ohjaus/debuggaus/testi-rekistereistä tai -rekistereille) 486-järjestelmässä: •INVD •WBINVD •INVLPG Pentium- ja sitä uudemmilla koneilla: •RDMSR •WRMSR •RDTSC
EFLAGS-rekisterissä olevan IOPL-kentän avulla käyttöjärjestelmä voi ohjata, mitkä voivat käsitellä I/O:ta. Nämä kaksi bittiä määrittelevät pienimmän etuoikeustason, joka ohjelmalla on oltava, että se voisi suorittaa I/O-käskyjä (CLI, STI, IN, INS, OUT ja OUTS). Jos IOPL on nolla, vain PL0-ohjelmat voivat käyttää I/O:ta. Jos IOPL on 3, kaikki ohjelmat voivat suorittaa I/O-käskyjä. Vain PL0-ohjelmat voivat modifioida IPL-lippuja. Jos muut ohjelmat yrittävän muuttaa näitä lippuja, niin IOPL ei muutu! Kun jättää IOPL:n arvoksi 3, elämä on helpompaa DOS-laajentajilla, mutta se saattaa aiheuttaa vielä suurempia ongelmia, sillä reaalitilan ohjelmat käyttävät pääpiirteissään suoraa I/O:ta.
Ohjelman etuoikeustaso on sama kuin CS-rekisterissä oleva selektorin RPL-kenttä. Tämä on voimassa oleva etuoikeustaso eli CPL. Et voi suoraan muuttaa CS-rekisteriä niin, että sillä olisi eri RPL-arvo. Sama juttu pitää paikkansa SS-rekisterillä.
Datan käyttö
Ohjelmat eivät voi ladata segmenttirekisteriin mitä tahansa selektoria. Kun datasegmenttirekisteri (DS, ES, FS tai GS) ladataan, 386 tarkistaa DPL:n ohjelman CPL:ään ja selektorin RPL:n verrattuna. 386 vertailee ensin CPL:ää RPL:ään. Suurempi niistä tulee voimassa olevaksi etuoikeustasoksi (effective privilege level, EPL). Jos DPL on suurempi tai yhtä suuri kuin EPL, 386 lataa segmenttirekisterin; muulloin tapahtuu virhe.
SS-rekisteri on ladattava segmentillä, jonka DPL ja CPL ovat yhtä suuret. 386 tarkistaa aina, että pinosegmentti on luettava, kirjoitettava ja käytössä oleva.
386 tarjoaa erityisen pinosegmenttityypin. Voit käyttää pinona myös tavallista datasegmenttiä, jos haluat. Pinosegmentin raja-alue ilmaisee segmentin alimman mahdollisen siirroksen.
Segmenttirekisteriin voi aina ladata nollaselektorin (0:sta 3:een). Kuitenkin yritys päästä käsiksi muistiin selektorin kautta aiheuttaa odotetusti virheen.
Kuinka moniajo toimii
386:ssa on, niin kuin aikaisemmin jo mainittiin, tuki moniajolle eli useiden prosessien suorittamiselle yhtäaikaisesti. Todellisuudessa ne eivät kuitenkaan toimi samanaikaisesti. Se vain näyttää käyttäjälle niin.
386 käyttää moniajoon Task State -segmenttejä (TSS:ä). TSS-deskriptori osoittaa puskuriin, jonka on oltava vähintään 104 tavua pitkä. Moniajon lisäksi TSS-deskriptoreita voidaan käyttää laitteistokeskeytysten käsittelyyn (käyttäen task- eli työtehtävä-portteja IDT:ssä). TSS-selektori on joko luettava tai kirjoitettava. Useimmiten luodaan TSS-alias, mikä on yksinkertaisuudessaan vain TSS-puskuriin osoittava "data-tyyppi". TSS-selektoreita voi olla vain GDT:ssä, ei koskaan LDT:ssä tai IDT:ssä. Kuten vähän aikaa sitten mainittiin, kuitenkin task-portteja voi olla myös IDT:ssä. Prosessori käyttää TSS-selektoria sisäisesti.
Koska moniajossa vaihdos vaatii sen, että prosessorin tila tallennetaan, puskuri sisältää yleensä laitteistorekistereiden sisällön. Kun työtehtävän vaihdos tapahtuu, prosessori tallentaa monenlaisia tietoja TSS-puskuriin automaattisesti. Tämä toimenpide on hyvin nopea ja siten uuteen työtehtävään vaihtamiseen ei tuhlaannu monta CPU-kierrosta. Ennen kuin työtehtävä on alkujaan käynnistetty, käyttöjärjestelmän on täydennettävä tiettyjä kohtia TSS-puskurista.
Huomioi lohkot TSS:n ylätuntumassa olevien PL0-, PL1- ja PL2-tasojen pinosegmenteille ja -osoittimille. Ohjelman on ylläpidettävä erillisiä työtehtäviä kullekin käyttämälleen etuoikeus-kehälle. Etenkin PL0:n pinosegmenttien ja osoittimien on pakko olla olemassa. Muuten prosessori saattaa sammua johtuen tupla-häiriöstä (double fault) esim. keskeytyksen tapauksessa.
Työtehtävän vaihdos tapahtuu "far-jumpin" tai "far-callin" aikana. "Jumpin" tai "callin" siirros-osuus jätetään yksinkertaisesti huomioimatta. TSS:ssä olevat arvot ladataan rekistereihin ja uusi työtehtävä aloittaa suorituksen. Jumpin tai callin viittaaman selektorin on oltava TSS-selektori tai task-portti. Task-portti sisältää TSS-selektorin. Mutta vastoin kuin TSS-selektori, task-portti voi esiintyä TSS:ssä, IDT:ssä tai LDT:ssä. EPL:n täytyy aina olla vähemmän tai yhtä suuri kuin TSS:n DPL, niin kuin tavallisten segmenttiselektoreidenkin tapauksessa.
386 tukee myös sisäkkäitä työtehtäviä (nested tasks). Se käsittelee sisäkkäitä työtehtäviä käyttäen NT-bittiä EFLAGS-rekisterissä. Kun työtehtävä "kutsuu" toista työtehtävää, 386 tallentaa vanhan työtehtävän TSS-selektorin uuden TSS:n "back-linkki" -kenttään. Samalla asetetaan myös EFLAGS-rekisterissä oleva NT-bitti päälle. Kun uusi työtehtävä haluaa palata vanhaan työtehtävään takaisin, se panee täytäntöön IRET-käskyn4.
TSS ei ole uudelleen-astuttava (eng. reentrant). Kun työtehtävä on käynnissä, 386 asettaa TSS-selektorissa olevan BUSY-bitin päälle ilmoittaakseen tästä. Tämä tehdään estämään työtehtävän toistuvaa kutsumista.
Kuten aikaisemmin mainitsin TSS:n täytyy olla vähintäin 104 tavun pituinen. TSS:n kokoa voi laajentaa mihin tahansa kokoon asti. 386 sisältää viimeisessä kentässä osoittimen I/O-bittikarttaan. Tämän bittikartan koko on yleensä 8K, mutta saa olla vähemmänkin. I/O-bittikartta on valinnainen. Jos I/O-bittikartan koko on vähemmän, bittikartan jälkeiset kohdat oletetaan ykkösiksi (1). Kukin bitti I/O-bittikartassa vastaa aina yhtä I/O-porttia. Jos työtehtävä yrittää suorittaa I/O:ta, 386 varmistaa työtehtävän oman CPL:n IOPL:ää vasten. Jos CPL on vähemmän tai yhtä suuri kuin IPL, pääsy myönnetään, muulloin 386 tarkistaa I/O-bittikartan. Jos käytettävää I/O-porttia vastaava bitti on nolla, 386 sallii pääsyn, muulloin se estää pääsyn. Bittikartan pitäisi aina päättyä numeroon 0FFh.
80386-prosessorin poikkeukset
386:ssa on tuki 256:lle keskeytykselle (tai poikkeukselle) juuri niin kuin 8086:sessakin. Interrupt Descriptor- eli keskeytysdeskriptoritaulukko (IDT) sisältää määritelmän jokaiselle näistä keskeytyksistä. IDT:ssä voi olla 8192 kohtaa. Jos näistä kohdista on käytössä enemmän kuin 256, ne jäävät yksinkertaisesti käyttämättömiksi. IDT voi sisältää ohjelmallisia keskeytysportteja (trap gates), keskeytysportteja tai task-portteja. Ohjelmallinen keskeytysportti on sellainen, joka ei pyyhi keskeytyksiä ennen kuin se astuu poikkeuksen käsittelijään. Kuitenkin keskeytysportti estää kaikki keskeytyksen ennen käsittelijään astumista. Tarkempia tietoja task-porteista annetaan toisessa kohtaa tätä dokumenttia. Katso Kuinka moniajo toimii.
Keskeytyksiä voi tapahtua ulkoisen laitteen (joka kulkee PIC:in kautta) johdosta. Katso Laitteistokeskeytykset.), saattaa olla prosessorin itsensä aiheuttama, tai sitten jonkin ohjelmistokeskeytyksen. Prosessorin aiheuttamien laitteistokeskeytyksen huolellinen käsitteleminen on yksi tärkeimmistä tehtävistä käyttöjärjestelmässä. Vähäisetkin virheet näissä keskeytyksen käsittelijöissä johtavat "onnettomuuksiin"... joskus tuloksena voi olla myös sininen ruutu.
Prosessorin aiheuttamat 386 poikkeukset voidaan luokitella vioiksi (faults), ohjelmallisiksi keskeytyksiksi (traps) tai peruutuksiksi (aborts).
Fault on oikaistavava virhe. Virheelliset operaatiot johtavat faulteihin. Kun fault tapahtuu, CS:EIP osoittaa käskyyn, joka aiheutta faultin. Faulttien katsotaan olevan vähiten vakavia poikkeuksia. Yleisin näistä faulteista on "General Protection Fault (GPF)".
Trap ilmenee, kun ohjelmistokeskeytys tapahtuu. Ohjelmistokeskeytykset johtuvat INT- ja INTO-käskyjen suorittamisesta. Kun trap tapahtuu, CS:EIP osoittaa sitä seuraavaan käskyyn, joka aiheutti trapin.5 The system cannot restart traps.
Peruutukset (aborts) ovat vakavia virheitä, jotka kertovat, että itse käyttöjärjestelmässä on ehkä vakavia ongelmia. Double Fault ja FPU Overrun ovat esimerkkejä peruutuksista.
Seuraavassa taulukossa näkyy eri poikkeuksia niiden luokituksen kanssa:
Poikkeus (#num) Tyyppi Divide Error (0) Fault Debug (1) F/Trap Breakpoint (3) Trap Overflow (4) Trap Bounds Check (5) Fault Bad Opcode (6) Fault No Coprocessor (7) Fault Double Fault (8) Abort Coprocessor Overrun (9) Abort Invalid TSS Segment (0A) Fault Segment not Present (0B) Fault Stack Fault (0C) Fault General Protection Fault (0D) Fault Page Fault (0E) Fault Coprocessor Error (10) Fault
Muistinhallintayksikkö (MMU)
386:ssa on ainakin kaksi tapaa tukemaan muistinhallintaa. Ne ovat:
- Segmentointi
- Sivutus
Näistä kahdesta tavasta segmentointimekanismi on pakollinen kun taas sivutus on käyttäjälle valinnainen. Sivutus tarjoaa mekanismin virtuaalimuistin toteuttamiseen, jota lähes kaikki tämän päivän käyttöjärjestelmät käyttävät. Sivutusmekanismin käytön etu on, että voit rajoittaa pääsyä tiettyihin muistin alueisiin, mutta sen toteuttaminen segmentointi-tapaa käyttäen on vaikeaa. Segmenttejä käytetään pitämään tietyn ohjelman käyttämää dataa, koodia ja pinoa muistissa. Käyttöjärjestelmä voi kuitenkin käyttää yhtä ainutta selektoria, joka kattaa koko 4 gigatavun osoiteavaruuden, jota tässä dokumentissa jo aikaisemmin käsiteltiin. Katso [#Suojatun tilan edut Suojatun tilan edut].
Kuten lähes kaikkea muutakin toimintaa - vain PL0-ohjelmat voivat aktivoida MMU:n. Käyttäjäohjelmat eivät edes tiedä, että MMU on olemassa! Sivut luokitellaan luokkaan User tai System. PL0-ohjelmat pääsevät käsiksi mihin tahansa sivuun. PL3-ohjelmat pääsevät vain "User"-sivuihin, ei järjestelmän System-sivuihin. Koska tavallisessa järjestelmässä ei yleensä ole 4 gigatavun verran muistia käytössä, näille ei tietenkään aseteta sivutaulukoita. Vastaavat kohdat PDE:eissä merkitään "ei-käytössä" oleviksi (not-present).
MMU käyttää kahden tyyppisiä taulukoita osoitteiden kääntämisessä - Page Directory Entry ja Page Table Entries (eli sivutushakemistokohtio ja sivutustaulukon kohtiot). Kukin PDE vastaa neljää (4) megatavua jatkuvaa muistia. PDE sisältää osoittimen niitä vastaavien sivutustaulukoiden aloituskohtaan. Näitä PTE-kohtioita voidaan käyttää asettamaan käyttöoikeudet 4 kilotavun lohkoille PDE:n 4 megatavun alueen sisällä. PTE:t sisältävät myös varsinaisen fyysisen osoitteen. Huomaa, että PDE sisältää sivutustaulukoiden fyysisen osoitteen. Kääntääkseen lineaarisen osoitteen fyysiseksi osoitteeksi MMU katsoo lineaarisen osoitteen bittejä 31-22. Tätä käytetään valitsemaan PDE-kohtiot yhteistyössä. Bittejä 21-12 käytetään valitsemaan yhden 1024 PTE:stä valitussa sivutustaulukossa. Alimmat 12 bittiä muodostavat fyysisen osoitteen alimmat 12-bittiä.
Kysymys kuuluu nyt, että miten MMU tietää, missä Page Directory:t sijaitsevat. CR3-rekisteri pitää sisällään kantaosoitetta PDE-kohtioille. Siten se tunnetaan myös nimellä PDBR (Page Directory Base Register)6
Virtuaalinen 8086 (V86/VM86) tila
Kuten tässä dokumentissa on jo aikaisemmin mainittu 80386:ssa on myös kolmas tila nimeltään V86-tila. Tässä tilassa 80386 käyttäytyy aivan kuten 8086 muutamilla pikku eroavaisuuksilla. V86-tilassa CPU ei välitä mitään etuoikeutetuista käskyistä kuten LGDT, LIDT, LLDT, SLDT, ARPL, LAR, LSL, LTR, VERR, VERW, INVD, WBINVD, WRMSR, RDMSR ja niin edelleen. Kuitenkin vastoin kuin reaalitilassa, V86-tilassa MMU on käytössä. Sen takia käyttöjärjestelmällä on ohjakset käsissä V86-työtehtävän suhteen, vaikka sellainen työtehtävä pyörii juuri niin kuin reaalitilassa. Koska etuoikeutettuja käskyjä ei voida suorittaa, käyttöjärjestelmä voi välttää järjestelmän kaatumisia sekä estää ilkeämielisiä ohjelmia tuhoamasta dataa.
Työtehtävästä sanotaan, että se on V86-työtehtävä, kun EFLAGS-rekisterin VM-bitti on kytkettynä päälle. Vain PL0-ohjelma voi muuttaa tätä bittiä. Bitti voidaan asettaa myös TSS:ssä ennen työtehtävän suorittamista. V86-työtehtävän käyttämisen etu reaalitilan työtehtävän käyttämisen sijaan on ilmiselvä - kyseessähän on turvallisuussyyt. Toinen syy on se, että aika, joka CPU:ltä menee vaihtamaan suojatun tilan ja reaalitilan välillä on huomattava ja hidastaa ohjelmaa suuresti. Ohjelman ajaminen V86-tilassa on siis pohjimmiltaan nopeampaa.
V86-työtehtävä, niin kuin reaalitilan ohjelmakin, käyttää segmenttejä ja siirroksia selektori:siirros-parin asemesta. Se voi käyttää 1 megatavun verran muistia. V86-työtehtävä pyörii aina PL3:lla. Ne voivat käyttää I/O:ta vain, jos IOPL on 3 tai jos TSS-bittikartta sallii niiden käyttää sitä. Jos IOPL on vähemmän kuin 3, CPU luo General Protection Faultin, jos V86-työtehtävä yrittää suorittaa joitain seuraavista käskyistä - CLI, STI, INT, IRET, LOCK, PUSHF tai POPF.
Keskeytyksen käsittely suojatussa tilassa
Keskeytysten käsittely on tärkeimpiä työtehtäviä missä tahansa käyttöjärjestelmässä. Erityisesti, jos jättää laitteistokeskeytykset käsittelemättä kunnolla, mitään ei tapahdu. Järjestelmä saattaa kaatua tai aiheuttaa epätavallisia ongelmia. Tämä kappale antaa yleiskatsauksen keskeytyksenkäsittelystä suojatun tilan ja V86-tilan ympäristöissä.
Suojatun tilan keskeytyksen käsittely on mainittu tässä dokumentissa aikaisemminkin. Katso 386-prosessorin poikkeukset.
Keskeytyksenkäsittely V86-tilassa on hivenen verran monimutkaisempaa. Vaikka prosessori on V86-tilassa, itse keskeytyksenkäsittely tapahtuu suojatussa tilassa. Koska segmenttirekisterit sisältävät todennäköisimmin mitä tahansa arvoja, 386 nollaa kaikki segmenttirekisterit ennen asianmukaisen keskeytyksenkäsittelijän kutsumista. Pidä mielessä, että puhumme tässä laitteistokeskeytyksistä, emme niistä INT-käskyn keskeytyksistä. SS siis sisältää selektorin PL0-pinoon Task State segmentissä. VM86-pinokehyksen (VM86 stack frame) rakenne, joka tallennetaan PL0-pinoon, on alla olevan kuvan kaltainen.
Kun General Protection Fault tapahtuu, se voi joko johtua siitä, että VM86-työtehtävä keskeytyi tai sitten keskeytyksestä varsinaisessa suojatun tilan ohjelmassa. Havaitakseen kumpi se näistä kahdesta oli käsittelijä voi katsoa EFLAGS-rekisteriin tarkistaakseen josko V86-työtehtävä oli käynnissä. Jos V86-työtehtävä aiheutti keskeytyksen, keskeytyksenkäsittelijä voi katsoa "loukanneeseen" käskyyn. Kun keskeytyksen syy on selvillä, käyttöjärjestelmä voi valita joko sen, että se emuloi kyseistä käskyä (eli sellaisia käskyjä kuten CLI, STI, ...) tai yksinkertaisesti päättää ohjelman tai suorittaa minkä tahansa muun toiminnon.
Toimiminen suojatussa tilassa
Suojatussa tilassa toimiminen vaatii, että ensin siirryt suojattuun tilaan. Siirtyäksesi suojattuun tilaan ja tehdäksesi jotain todellista työtä sinun täytyy noudattaa seuraavia vaiheita:
- Luo Global Descriptor Table (GDT)
- Luo Interrupt Descriptor Table (IDT)
- Uudelleen ohjelmoi PIC-piirit siten, että ne generoivat erilaisia keskeytyksiä
- Aseta TSS
- Luo sivutustaulukot ja CR3 (ehkä et saata tarvita tätä)
- Aseta bitti 0 CR0:ssa
- Lataa Task Register (TR)
- Hyppää TSS-selektoriin
GDT- ja IDT-taulukoiden luomisen pitäisi olla helppoa. Luo deskriptorit ja lataa GDTR:ään kyseisen taulukon osoite ja koko. Alexei A Frounze'n tekemät ohjelmat selostavat kaiken tämän.
TSS:n asettaminen voi olla myös helppoakin, jos noudatat selkeää työjärjestystä. Lopuksi suorita far-hyppy TSS:ään ja sillä selvä.
Suojatun tilan tutoriaali
Alexei A Founze on kirjoittanut upean suojattua tilaa käsittelevän ohjelmasarjan, joka on ladattavissa osoitteesta http://members.tripod.com/protected_mode/alexfru/pmtuts.html.
Näiden ohjelmien ajamiseen tarvitset järjestelmän seuraavalla kokoonpanolla:
- 80386 tai sitä uudempi prosessori
- DOS 5.0 + tai Windows 9x MS-DOS-tilassa (Ei MS-DOS-ikkunasta)
- Sellaisten ajurien kuten EMM386 (tai HIMEM.SYS) poistaminen käytöstä
- Noin 2 Mt RAM-muistia
- VGA- tai SVGA-kortti
Tässä lyhyt kuvaus kustakin ohjelmasta:
- Vaihtaa suojattuun tilaan ja sitten takaisin reaalitilaan käyttäen CR0-rekisteriä
- Valmistelee GDT:n, siirtyy suojattuun tilaan, tulostaa "Hello from PMode!" ja palaa takaisin.
- IDT-taulukko asetetaan ohjelmisto-ISR:ää varten (Int 20h) sekä jako nollalla -poikkeus (Int 0). Tämä ohjelma esittelee käsittelijöiden toimintaa.
- Sama GDT kuin ennenkin, IDT asetetaan kaikille poikkeuksille, nyt näet myös poikkeuksen osoitteen ja tyypin.
- Sama GDT kuin ennenkin, osapuilleen sama IDT kuin TUT04:ssa. Kaksi IDT-kohtiota ja IRQ-käsittelijää lisätty - IRQ0 (ajastin) ja IRQ1 (näppäimistö). Se uudelleen ohjelmoi PIC:in, jotta IRQ:ita voi käsitellä suojatussa tilassa.
- Lähes sama kuin 5. Työtehtävien vaihtaminen lisätty.
- Esimerkki moniajosta.
- Demonstraatio sivunkäännöksestä (page translation)
- Tämä tutoriaali on vähäsen erilainen seitsemänteen verrattuna. Tämä ei käytä TSS:ää työtehtävän vaihdokseen, vaan käyttää sen sijaan pinoon perustuvaa vaihdosta.
- Tämä tutoriaali näyttää Big/Unreal-tilat - kuinka käyttää 4 megatavua muistia siirtymättä suojattuun tilaan.
- Tämä on lähes sama kuin 7. Ainoa ero on, että työtehtävät ovat 32-bittisiä.
- Sama kuin 11, paitsi että kaksi LDT:tä lisätty kullekin PL3-tason työtehtävälle.
- Moniajo. Täällä pyöritämme ensimmäistä kertaa virtuaalista 8086 -konetta.
- Syventävää V86-kamaa. Nyt on tuki ohjelmistokeskeytykselle Int nn V86-työtehtävissä.
- Toimiva V86-monitori - DOS-ikkunaa vastaava.
- Sama V86-monitori. Melko pieniä muutoksia (Int 1 - yksivaiheinen trap on nyt lisätty V86-työtehtävälle).
Tietoja tästä dokumentista
Tämän dokumentin on kirjoittanut ja ylläpitänyt Prashant TR. Jos sinulla on kommetteja, kysymyksiä tai muita ehdotuksia, lähetä sähköpostia Prashant TR:lle tai PMode-palstalle. Varmista, että viittaat uusimpaan versioon tästä dokumentista, joka on osoitteessa http://members.tripod.com/protected_mode/. Jos sinulla on ongelmia tämän manuaalin ymmärtämisessä tai haluat ottaa esille jonkin kysymyksen, harkitse postaamista/liittymistä PMode list. Ohjeet palstalle liittymiseen löytyy osoitteesta http://www.midpec.com/. Voit lähettää palstalle vapaasti kommenttejasi.
Jos sinulla on jotain kysyttävää tästä suomennetusta versiosta, ota yhteys sen kääntäjään osoitteessa jouni_kahkonen osoitteessa hotmail piste com tai kajouni osoitteessa mbnet piste fi.
Seuraavat ihmiset ovat antaneet arvokkaita kommentteja ja tietoja sekä tehneet tästä dokumentista onnistuneemman:
- Alexei A Frounze - Alexei A Frounze on työskennellyt käyttöjärjestelmäkehityksen parissa jo kauan. Hän on myös fysiikan opettaja.
- Eli Zaretskii - Eli Zaretskii on työskennellyt DJGPP:n parissa useita vuosia. Hän on DJGPP FAQ:in kirjoittaja ja ylläpitäjä ja hän on muuntanut monia Unix-paketteja DJGPP:lle. (Katso luettelo eri pakettien avustajista).
Viitteet
- Todellisuudessa tätä tapahtuu hyvin harvoin. Useimmat BIOSit ja jopa DOS käyttävät joskus sen tyyppisiä käskyjä kuten
RETF 2tehden tämän INT-IRET-sekvenssin tarpeeksi epävarmaksi käskyjen simuloimista varten V86-tilassa. Tehtävänä on käyttä erityistä VM86 pinokehystä, joka huolehtii kaikesta tästä. - Määritelmän mukaan 8086 ei voi maskata NMI:tä. PC:n emolevyllä ei ole kuitenkaan virtapiiriä, joka voisi estää NMI:n tapahtumasta. Sinun on kuitenkin harvoin tarve ottaa NMI pois käytöstä. AT:n emolevyissä sitä voidaan kuitenkin ohjata portin 70H avulla. Tämän portin bitin 7 nollaaminen ottaa NMI:n pois käytöstä.
- Monet ohjelmat pääsevät käsiksi 1 megatavun muistirajoituksen yli yksinkertaisesti ottamalla käyttöön A20-linjan. Kun A20 on päällä, osoitteet eivät kierrä ympäri, joten ne voivat käydä käsiksi 64 kilotavuun muistia yhden megatavun yläpuolelta ilman menemistä reaalitilaan. Tämä voi kuitenkin aiheuttaa monia ongelmia muistimanagereiden kanssa, joten se täytyy suorittaa varoivaisesti.
- IRET-käskyllä on 386:sen suojatussa tilassa täysin eri merkitys, kuin sillä oli reaalitilassa. Suojatussa tilassa keskeytyksenkäsittelijästä palaamiseen käytetään IRETD-käskyä.
- Trapeilla ei ole mitään tekemistä trap-porttien kanssa. Trappia voidaan käsitellä käyttämällä joko keskeytysporttia tai trap-porttia.
- Huomaa, että PDE:n ja kaikkien PTE:iden on sijaittava 4 kilotavun lohkon alussa.
