Védett mód és az assembly

A védett mód alapjai

Egy alkalmazás szempontjából a védett mód nem sokban különbözik a valós módtól. De a valós módban a memória szegmentációja automatikusan kezelödik egy beépített mechanizmus által a szegmens regiszterekkel összhangban. A szegmens regiszterek alkotják a CPU által a címbuszra küldött fizikai cím egy részét. (ld. Fig. 1(a)) A fizikai cím a következöképp számolódik: megszorozzuk a szegmens regisztert 16-al, és hozzáadjuk a 16 bites offszet regisztert. 16 bites offszeteket használva a processzort akaratunkon kívül is 64 KByteos szegmensekre limitáljuk. Egyes programok túllépik ezt a 64 KByteos megkötést, a szegmens regiszter 16-al növelésével; ezen programok védett módban futtatása nem lehetséges, mert kivételt (exception) okoznának, mivel a szegmens regiszterek máshogy értelmezödnek. Védett módban a memória szegmentációját táblák definiálják (ezek neve leíró tábla, descriptor tábla), a szegmens regiszter csak mutatókat tartalmaz a tábla bejegyzéseire. Minden táblabejegyzés 8 byte széles; így a szegmens regiszter értékei a 8 többszörösei (08h, 10h, 18h, stb.). A szegmens regiszter alsó 3 bitje definiált, de az egyszerüség kedvéért tekintsük úgy, hogy bármely program, ami a szegmens regisztert nem 8 többszörösével tölti fel, védelmi hibát okozna. Két tábla van a memória szegmentáltságának definiálására: a Globális Leíró Tábla (Global Descriptor Table = GDT), és a Lokális Leíró Tábla (Local Descriptor Table = LDT). A GDT olyan szegmentációs információkat tartalmaz, amelyet minden program elérhet. Az LDT ezzel szemben egy specifikus taszk vagy program szegmentációs információit tartalmazza. Mint az már eddigre kiderült, a szegmens regiszterek nem alkotják részét védett módban a fizikai címnek, hanem mutatóként szolgálnak a GDT vagy az LDT bejegyzéseire (ld. Fig. 1(b)). Minden alkalommal, mikor feltöltjük a szegmens regisztert, a báziscím kiolvasódik egy táblabejegyzésböl, és eltárolódik egy a programozó számára nem látható regiszterben, a szegmens leíró cache-ben. A fizikai cím, ami megjelenik a címbuszon, a 16 vagy 32 bites offszetnek a leíró táblában lévö báziscímhez adásával keletkezik.
A valós módú alkalmazások védett módúvá átírásának következö problémája a megszakítások használata. Valós módban a 0-ás fizikai címtöl kezdödöen dupla word pointerek mutatnak a megszakítási rutinok fizikai címeire. A 4a kép mutatja a megszakító rutinok címzését valós módban. Mikor egy megszakítás generálódik, a CPU megkeresi a címét a megszakítás kezelö rutinnak (Interrupt Service Routine = ISR) ebben a megszakítás vektor táblában. A verembe PUSH-olt információk azonosak mind a szoftveres, hardveres vagy CPU generált megszakításoknál.

Védett módban a verembe PUSH-olt információ változhat, éppúgy, mint a megszakítási vektor báziscíme és a megszakítási tábla mérete. A megszakítási vektor visszakeresési mechanizmus szintén eltér a valós módútól. A 4b kép mutatja, hogy védett módban miként történik a megszakítások hívása. Mikor egy megszakítás generálódik, a CPU összehasonlítja a megszakítás számát (x8) az IDT méretével -- ami el van tárolva a megszakítás leíró cache regiszterben. Ha ez nem haladja meg az IDT méretét, a megszakítás hívhatónak minösül, és az IDT báziscím behívódik a leíró cacheböl; eztán az ISR védett módú címe betöltödik az IDT-böl. Az ISR címe nem egy fizikai cím, hanem egy védett módú, szegmentált cím. Az IDT-ben megadott segmens szelektor felhasználásával a CPUnak el kell végeznie mindazokat a korlát ellenörzéseket melyek a GDT-n is történnek, hogy kiszámítsa a fizikai címet. Mikor a fizikai cím kiszámolódik, a CPU PUSH-olja a FLAGS, SEGMENT, OFFSET -et és jó eséllyel egy HIBA KÓDOT (ERROR CODE) is a stackra, mielött elugrana az ISR-re. A szoftveres és hardveres megszakításoknak nem sokban kell különbözniük a valós módú párjaiktól, de a CPU által generált megszakításokat és hibákat lekezelö megszakítások lényegesen eltérnek.

A CPU a megszakítások három kategóriáját generálhatja: csapdák (trap), hibák (fault), megszakítások (aborts). A stack képe kategóriáról kategóriára változó, minthogy egy hibakód pusholódik vagy sem a verembe. A csapdák sosem pusholnak hibakódot, hibák általában igen, míg a megszakítások (abort) mindíg.
A csapdák (trap) hasonlóak a szoftveres megszakításokhoz. A név elég beszédes, mivel a CPU "elkapja" a kiváltó eseményt. A CPU nem tudja, hogy az esemény bekövetkezett, egészen a bekövetkezés tényéig; tehát az eseményt a megszakítás hívása elött kell elkapnia. Így az ilyen ISR-ek visszatérési címe az esemény bekövetkezte utáni utasításra mutat. Csapda pl. az osztás 0-val, adat breakpointok, és a 3-as megszakítás (INT03).
Hibák (fault) olyankor jelentkeznek, ha valami rossz történt -- valami, amit ki kell javítani. A CPU azonnal tudja, hogy hiba történt és meghívja a megszakítás-generáló mechanizmust. Az ISRek ezen típusának az elsödleges célja, hogy kijavítsa a problémát, és pontosan onnan indítsa újra a programot, ahol abbamaradt. Épp ezért az ISR visszatérési címe a hibát kiváltó utasításra mutat -- így visszaállíthatóvá téve a hibát.
A megszakítások (abort) a leggyakoribb típusai az interruptoknak, és nem-újraindíthatónak tekinthetöek. Hibakód pusholódik a stackra, de ez mindíg 0 lesz. A CPU stack szegmense és állapotjelzöi lehet, hogy köztes állapotban vannak, és egy megszakítás (abort) folytatására tett kísérlet elöre megjósolhatatlan viselkedéshez vezethet. Az 1. táblázat kategorizálja a CPU védett módban generált megszakításainak listáját. Az esetek többségében a CPU valós módban ugyan olyan megszakítást generálna, mint védett módban, csak soha sem pushol hibakódot a verembe.

Érdekes kérdés, hogy a BIOS miért nem használható védett módban. Azt gondolhatnánk, egyszerü módfüggetlen kódot írni, csak ne használjunk távoli ugrásokat és távoli hívásokat ("FAR JUMP","FAR CALL"). De sajnos nem ilyen egyszerü, hogy követjük ezeket a megkötéseket. A felsoroltak kerülése mellett az ISRnek el kellene távolítania a verembe pusholt hibakódot is. Itt kezdödnek a problémák, mert ezek csak védett módban kerülnek oda; tehát detektálnunk kell, hogy védett módban vagyunk-e, mielött kivennénk a hibakódot... Ennek megállapításához hozzá kell férnünk a gép státusz wordhoz (machine status word = MSW), vagy a rendszer regiszterhet (system register, CR0). Az MSW elérése bármely privilégiumszinten történhet, de a CR0 elérése csak a legmagasabb privilégium szinten történhet -- 0. szint. Ha a felhasználói program alacsonyabb szinten fut a 0-nál, akkor nem érhetjük el a regisztert. Viszont megvalósítható, ha speciális "call gate"-t használunk, ami lehetövé teszi számunkra a szint megváltoztatását az ISR hívása elött. Ez persze nem szükséges, ha az SMSW (Store Machine Status Word) utasítást használjuk. De a probléma még ezzel sem megoldott, tegyük fel, hogy a program egy valós módú értéket hagyott a szegmens regiszterek bármelyikében. Ha az ISR PUSH-ol, majd ennek megfelelöen POP-ol bármely ilyen regisztert, a POP arra fogja késztetni a CPUt hogy szegmenst keressen ki vagy a GDTböl, vagy az LDTböl. Nagy valószínüséggel a valós módú érték védelmi hibát fog kiváltani (protection error). Tehát a BIOS használata védett módban szinte lehetetlen. Ha viszont lett volna definiálva egy szabályhalmaz, amit minden programozó és operációs rendszer követne, akkor megvalósítható volna.

4(a) kép -- Megszakítás kiszolgáló címzés Valós Módban

4(b) kép -- Megszakítás kiszolgáló címzés Védett Módban

1. táblázat -- Kivételek és Megszakítások
Description Int # Type Return Addr points to faulting instruction Error Code This interrupt first appeared in this CPU
Division by 0
Debug Exception
NMI
Breakpoint
Overflow
Bounds
Invalid OP Code
Device not available
Double Fault
Copr. segment overrun
Invalid TSS
Segment not present
Stack fault
General Protection
Page fault
Floating point error
Alignment check
Machine check
Software interrupts
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
16
17
18
0-255
Fault
*1
*2
Trap
Trap
Fault
Fault
Fault
Abort
Fault
Fault
Fault
Fault
Fault
Fault
Fault
Fault
Abort
Trap
Yes
*1
No
No
Yes
Yes
Yes
Yes
No
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
No
No
No
No
No
No
No
No
No
No
Yes
No
Yes
Yes
Yes
Yes
Yes
No
Yes
Yes
No
8086
8086
8086
8086
8086
80186
80186
80186
80286
80286 *3
80286
80286
80286
80286
80386
80386
80486
Pentium *4
All
*1 On the 386-class CPUs, debug exception can be either traps, or faults. A trap is caused by the Trap Flag (TF) being set | in the flags image, or using the debug registers to generate data breakpoints. In this case the return address is the instruction following the trap. Faults are generated by setting the debug registers for code execution breakpoints. As with all faults, the return address points to the faulting instruction.
*2 Non-maskable.
*3 Removed from the 80486, now generates exception 13 on all future processors.
*4 Model dependant. Behavior may be different or missing on future processors.

DESCRIPTOR CACHE REGISZTEREK

Mind valós, mind védett módban a CPU a szegmensek báziscímeit rejtett regiszterekben tárolja, ezeket descriptor cache regisztereknek nevezzük. Minden egyes alkalommal, amikor a CPU betölt egy szegmens regisztert, a szegmens báziscím, szegmens méret limit, és hozzáférési attribútumok (access rights) betöltödnek, vagy "cache"-elödnek ezekbe a rejtett regiszterekbe. A teljesítmény növelése érdekében a CPU a további memória hivatkozásokat ezen cache regiszterek segítségével végzi a fizikai cím számolása; vagy a báziscím leíró táblából kikeresése helyett. Ezeknek a rejtett regisztereknek a szerepének a megértése kulcsfontosságú a fejlett programozási technikák. és a nemdokumentált LOADALL utasítás kihasználásához. A 2(a) kép mutatja a descriptor cache kiosztását 80286, a 2(b) kép pedig 80386 és 80486 CPU esetén.
2(a) kép 80286 Descriptor Cache Register
[47..32] 31 [30..29] 28 [27..25] 24 [23..00]
16-bit Limit P DPL S Type A 24-bit base address


2(b) kép 80386/80486 Descriptor Cache Register
[31..24] 23 [22..21] 20 [19..17] 16 15 14 [13..00]
0 P DPL S Type A 0 D 0
[63..32]
32-bit Physical Address
[95..64]
32-bit Limit

Bekapcsolásnál a descriptor cache regiszterek fix alapértékekkel lesznek feltöltve, a CPU valós módban van, és minden szegmens írható/olvasható adatszegmensnek van megjelölve, beleértve a kódszegmenst (CS) is. Az Intel szerint minden alkalommal, amikor a CPU betölt egy szegmens regisztert valós módban, a báziscím a szegmens érték 16-szorosa, míg a hozzáférési jogok és méretkorlát attribútumok fixen adottak, "valós mód kompatibilis" értékek. Ez így nem teljesen igaz. Valójában csak a CS descriptor cache hozzáférési jogok kerülnek betöltésre fix értékkel minden olyan alkalommal, mikor a szegmens regiszter betöltödik - és ez is csak akkor, ha far jump-ot hajtunk végre. Bármely más szegmens regiszterbe töltés valós módban NEM változtatja meg a hozzáférési jogokat vagy a szegmens méret korlát attribútumokat amik a descriptor cache regiszterekben tárolódtak. Ezekhez a szegmensekhez a hozzáférési jogok és a szegmens méret korlát attribútumok megörzödnek az elözö beállításból (ld. 3. kép). Így lehetséges hogy legyen egy 4 GByte-os adatszegmensünk valós módban egy 80386-oson, de az Intel nem támogatja ezt a módot...

A védett mód ebböl a szempontból különbözik a valóstól, mivel akármikor a CPU betölt egy szegmens regisztert, teljes mértékben betölti a descriptor cache regisztert közvetlenül a descriptor táblából, nem örzi meg a korábbi értékeket. A CPU ellenörzi a szegmens érvényességét a descriptor táblában talált hozzáférési jogok tesztelésével, az illegális értékek exceptiont generálnak. Bármilyen CS-be történö írható/olvasható adatszegmens betöltési kísérlete védelmi hibát okoz (protection error). Hasonlóan, kísérletek adatszegmens regiszterekbe kódszegmens töltésére exceptiont okoz. A CPU nagyon szigorúan érvényesíti ezeket a védelmi szabályokat, ha a descriptor tábla bejegyzés átmegy minden teszten; eztán a CPU betölti a descriptor cache regisztert.

3. kép -- Descriptor Cache Tartalom (Valós Mód)




Belépés védett módba

A célunk belépni védett módba, majd elhagyni a védett módot, és visszatérni pl. a DOS-hoz. A 286-osnak nincs beépített mechanizmusa a védett módból kilépésnek: ha már benn vagyunk védett módban, ott is kell maradnunk. Az IBM felismerte ezt, és implementált egy hardveres megoldást ami kihozza a 286-ost védett módból a CPU resetelésével. Mivel a 286-os bekapcsoláskori állapota valós mód, a CPU resetelés hatására valós módba kerül. De ez újabb problémával jár, mivel a CPU nem onnan fogja folytatni a végrehajtást, ahol abbahagyta. Resetnél a CPU a memória felsö részéröl kezdi a végrahajtást, a BIOSból. Olyan protokoll nélkül ami megmondja a BIOSnak, hogy védett módból kilépés miatt reseteltük a CPUt, a BIOS nem tudná visszaadni a vezérlést a felhasználói programnak. Az IBM egy egyszerü technikát dolgozott ki erre, a CMOS RAM-ba ír bele, amit a BIOS ellenörizhet és ez alapján dönthet, mi a teendö. Amint a BIOS elkezdi a futást a reset vektortól, ellenörzi ezt a kódot a CMOS területen, hogy eldöntse miért volt resetelve a CPU. A CMOS-beli kód alapján a BIOS képes visszaadni a vezérlést a felhasználói programnak.

A CPU resetelése nem jár veszteségek nélkül; minden CPU regiszter megsemmisül, és a megszakítási maszk a Programozható Megszakítás Vezérlöben (PIC) néha újraprogramozódik a BIOS által (a "shutdown típus" függvényében). Ezért a program felelössége elmenteni a PIC maszkot, a stack pointert és a visszatérési címet a protected módba lépés elött. A PIC maszk és a stack pointer a felhasználói adatszegmensen tárolandó, de a visszatérési címet egy fix címre kell tárolni a BIOS adatszegmensen -- 40:67h -ra.

Következö lépésként beállítjuk a kódot a CMOSban ami megmondja a BIOSnak hogy el akarjuk hagyni a védett módot és visszatérni a felhasználói programhoz. Ez egyszerüen a két CMOS I/O portra írt adattal történik. Mikor a CPU resetelödik, a BIOS ellenörzi a CMOS kódot, törli is azt, hogy további resetek ne okozzanak váratlan eredményeket. A CMOS kód beállítása után a programnak fel kell építenie a GDT-t. A limit és hozzáférési jogok kitöltethetöek a fordítóprogrammal is, mivel statikus adatok. De az egyes szegmensek báziscímei csak futásidöben számolhatóak; így ezt a program kell hogy beírja a GDTbe. A programunk felépít egy GDT-t ami tartalmaz kód, adat és stack szegmenst. Egy bejegyzés fog még mutatni 1 MByte-hoz a GDT-ben illusztrációs célokra.

Hozzáférés a memóriához 1 MByte-nál nem olyan egyszerü, hogy létrehozzuk hozzá a bejegyzést a GDTben. A 8086-os képes volna megcímezni az 1 MByte-os terület elsö 64 KByte-ját (-16 byte) is -- ami kellene az csak egy 21. címzö vonal. A 8086-os csak 20 címvonalat tartalmazott (A00..A19), és minden kísérlet az 1 MByte feletti címzésre "körbefordult" 0-hoz, az A20 hiánya miatt. A 286-os 24 címvonallal rendelkezett (A00..A23) és ennek hatására nem viselkedik úgy, mint a 8086. Az 1M feletti címzés (FFFF:0010 - FFFF:FFFF) minden gond nélkül használni fogja az A20-at, így nem "fordul vissza" 0-hoz. Bármely program, ami kihasználta ezt a "körbefordulást" a 8086-oson, hibásan futna. Erre a problémára az IBM kitalálta, hogy ÉS-eljük meg az A20 vonalát a processzornak egy programozható kimenö jellel valamely chipröl. Az ÉS kapu kimenete rá van kötve a címbuszra, így engedélyezve / tiltva az A20-at. Erre a feladatra a billentyüzetvezérlöt választották mert volt pár szabad kimenete aminek az állapotát tetszölegesen magasra és alacsonyra lehetett állítani programmal vezérelve. Ha ez a láb alacsonyra van állítva, akkor az ÉS kapu miatt a processzor bármilyen címet adjon is ki a buszra, a 8086-os viselkedését kapjuk.

Vegyük észre, hogy csak az A20 van kapuzva a címbuszra, így az A20 kapu engedélyezése nélkül a CPU minden páros Megabytehoz hozzáfér: 0-1M, 2-3M, 4-5M, stb. Történetesen ezek a memória blokkok duplikálódnak az 1-2M, 3-4M, 5-6M címeken, ha az A20-at alacsonyan tartjuk a címbuszon. A teljes 24 bites címezhetöség elérésére paracsot kell küldenünk a billentyüzet vezérlönek (keyboard controller = KBC). A KBC magasra fogja állítani a megfelelö kimenetét, ami az A20 kapuhoz megy. Ha ez megtörtént, a memória nem fog "fordulni", így elérhetövé válik a teljes címezhetö 16 MByte a 286-oson, illetve a teljes 4 GByte a 80386-osztályú gépeken. Ami hátravan a védett módba lépéshez, az a CPU állapotának védett módúra állítása, és egy ugrás, amivel töröljük a prefetch queue tartalmát (Pentium gépeken utóbbi nem feltétlenül szükséges).

Az alábbi lista összegzi a védett módba lépés feladatait (feltételezve, hogy vissza is akarunk térni) a 286-oson:
  1. Mentsük el a 8259 PIC maszkot a program adatszegmensén
  2. Mentsük el az SS:SP -t a program adatszegmensén
  3. Mentsük el a védett módbóli visszatérés címét a 40:67 -re
  4. Állítsuk be a leállási kódot a CMOSban, ami közli a BIOS-al resetnél, hogy vissza akarunk térni a programunkhoz
  5. Építsük fel a GDT-t
  6. Engedélyezzük az A20-at a címbuszon
  7. Engedélyezzük a védett módot a CPU gép állapot jelzö word-jában (MSW)
  8. JUMP -oljunk, hogy töröljük a prefetch queue-t
Az 1-6 lépések tetszöleges sorrendben végrehajthatóak.

A minimálisan szükséges lépések védett módba lépéshez 386-os vagy 486-os gépen lényegesen kevesebbek, mivel a 386-os képes kilépni védett módból a CPU resetelése nélkül is. Kompatibilitási okokból minden 386-os BIOS felismeri a CPU leállítási kódot amit a 286-os gépeken definiáltak, de ennek követése nem kötelezö. A védett módból kilépés a 386-oson egyszerüen egy bit törlése a CPU vezérlö regiszterében. Nem szükséges elmenteni a PIC maszkot, SS:SP -t, a visszatérési címet, vagy beállítani a CMOS kódot. A szükséges lépések a védett módba lépéshez 386-oson egyszerüen:
  1. GDT felépítése
  2. A20 engedélyezése az adatbuszon
  3. A védett mód engedélyezése a CPU vezérlö regiszterében (CR0, vagy MSW)
  4. JUMP a prefetch queue kiürítéséhez
Ezekben a lépésekben pusztán a GDT felépítése az egyetlen, ami eltér. A 386-oson a báziscím ki van egészítve 32 bitesre, a limit 20 bitesre, és van két további vezérö attribútum. Az 1. program tartalmaz minden olyan szubrutint ami a védett módba lépéshez kell.



Kilépés védett módból

Mint a védett módba lépés, a kilépés is különbözik a 286-os és 80386-osztályú gépeken. A 386 egyszerüen töröl egy bitet a CPU CR0 vezérlö regiszterében, míg a 286-osnál resetelni kell a CPUt. A CPU resetelése nem költségtelen, mivel több száz -- ha nem több ezer -- órajelciklus telik el míg a CPU resetel és visszakerül a vezérlés a felhasználói programhoz. Az eredeti megoldás melyet az IBM alkalmazott, a billentyüzet vezérlö egy másik lábát kötötte a CPU RESET vonalára. A megfelelö parancs kiadásával a KBC átállítja a CPU RESET vonalát. Ez a módszer müködik, de igen lassú. Sok újabb generációs 286-os chip rendelkezik egy "FAST RESET" lehetöséggel. Ez egyszerüen állítja a RESET lábat egy I/O portra írással. Ha elérhetö, a FAST RESET módszer a preferált. Viszont létezik egy harmadik, kevésbé ismert, de hatékony módja a CPU resetelésének a KBC vagy a FAST RESET használata nélkül. Ez a módszer elegáns, gyorsabb mint a KBC használata, és müködik a 386-oson is, ráadásul a CPU resetelése NÉLKÜL! Tehát ez a módszer müködik mind a 286-os, mind a 386-os gépeken -- mindkét processzoron a lehetö leghatékonyabban. A 2. program bemutatja a KBC és ezen elegáns kód használatát.

A KBC használata a CPU resetelésére egy magától értetödö módszer, de az elegáns módszer megértése némi magyarázatot igényel. Emlékezzünk, hogy a megszakítások tárgyalásánál említettük, hogy a CPU ellenörzi a megszakítás számot (x8) a limit mezöhöz képest a megszakítás leíró cache regiszterben (interrupt descriptor cache register = IDTR). Ha ez a teszt sikeres, a megszakítás feldolgozás következö fázisa indul. De ha a teszt elbukik, a CPU DOUBLE FAULT (INT08) -ot generál. Például legyen a limit mezö az IDTR-ben 80h: az IDT-nk 16 megszakítást szolgál ki, 00-15. Ha 16-os vagy e feletti megszakítás generálódik, a CPU DOUBLE FAULT-ot genreál a megszakítás hívási szekvenciában. Most gondoljuk meg, hogy az IDTR=0, vagyis egy megszakítást sem szolgálunk ki. Így bármilyen megszakítás DOUBLE FAULT-ot okoz. De a DOUBLE FAULT maga is hibát okoz (fault), mivel a limit kisebb, mint 40h. Ez egy TRIPLE FAULT-ot okozna, és a CPU shutdown ciklusba kezd. A shutdown ciklus nem reseteli a CPUt, mivel a shutdown ciklus BUS ciklusnak minösül. A CPUhoz külsö hardver csatlakozik, ami felismeri a shutdown ciklust. Mikor shutdown ciklus érzékelödik, a külsö hardver aktiválja a CPU reset lábát. Így amit tennünk kell egy RESEThez: beállítani az IDTR LIMITet 0-ra, majd generálni egy megszakítást. Hogy még elegánsabbak legyünk, nem csak egy INT-et hajtatunk végre a CPUval, hanem generálunk egy érvénytelen opkódot. Az opkódunk gondosan választott, ami nem létezik a 286-oson, de a 386-oson igen. Az algoritmus azért elegáns, mert gondosan választott opkódot használunk a célhoz: MOV CR0,EAX. Ez a kívánt opkód kivételt eredményezi a 286-oson, de ez az elsö utasítása egy sorozatnak, ami kilép a védett módból a 386-oson. Így a 286-os RESETelve lesz, míg a 386 átesik a kódon és kilép a védett módból.

Kilépés védett módból a 286-oson és 386-oson majdnem a belépés fordítottja. A 286-oson a következök kellenek:
  1. A CPU resetelése a valós módhoz visszatéréshez
  2. A szegmens regiszter valós móddal kompatibilis értékekkel feltöltése
  3. SS:SP visszaállítása
  4. A20 levétele a címbuszról (A20 gate ki)
  5. A PIC maszk visszaállítása
És a 386-oson, a lépések egyszerüen:
  1. A szegmens regiszterek feltöltése valós mód kompatibilis értékekkel
  2. A Protection Enable (PE) bit resetelése a CR0-ban
  3. A szegmens regiszterek feltöltése valós módú értékkel
  4. A20 levétele a címbuszról (A20 gate ki)
(A 3. program tartalmazza mindazokat a szubrutinokat, amely visszaállítja a gép állapotát védett módból kilépés után)

Vegyük észre, hogy védett módból kilépésnél a 386-osnál a szegmens regiszter feltöltése kétszer is szerepel. A szegmens regiszter elsö feltöltésénél biztosítjuk, hogy a rejtett descriptor cache regiszterben a valós móddal kompatibilis érték kerül -- mivel a descriptor cache regiszter megtartja a régebbi hozzáférési attribútumokat és szegmens méret limitet a védett módból, még valós módban is! A szegmens regiszterek második alkalommali feltöltése definiálja öket valós módú szegmens értékekkel.

Most, hogy minden tudásunk megvan a védett módba lépéshez és kilépéshez, alkalmazhatjuk ezt a tudást egy olyan program írásánál, amely belép védett módba, a kiterjesztett memóriából mozgat egy adatblokkot, majd kilép védett módból -- visszatérve a DOShoz. A 4. program mutatja be ezt, és 1K blokk adatot mozgat az 1M feletti területröl a programunk adatszegmensére.

program
1. programrészlet
2. programrészlet
3. programrészlet
4. programrészlet


Kiegészítés:

Az elöbbiekben nem sok szó esett a processzor regisztereiröl:
Védett módban elérhetö 8 32 bites általános célú regiszter: Ezen felül vannak nem-alkalmazás regiszterek, melyek a processzor állapotát változtatják: Az MSW a CR0 része...