Hát nem is tudom. Lehet, hogy nem egy jó ötlet, de azért megpróbálom, hátha kisül belőle valami értelmes.

Egy kis történeti áttekintés
A 286-osok megjelenésével jelent meg ez a mód is, mivel az INTEL nagyeszű mérnökeinek eszükbe jutott, hogy ez a 64kb-s lapozgatásos baromság lehet, hogy nem a legkezelhetőbb, ráadásul Billy Boy szövege sem vált be (640kb is enough...) mivel 640kb egy kicsit kevés, és valahogy kezelni is kellene azt a sok mega ramot. Ezért jelent meg ez a mód. A 286-oson csak fel lehetett lépni védett módba, le már nemigen. A 386-osok megjelenésével megoldódott ez a probléma is. Így már egybe lehet kezelni akár 4gb memóriát is, gond nélkül.
Előnyök
  • Ugye ott a 4gb memória kezelése.
  • Lehet multitaskot meg mindent csinálni.<- ez a lényeg
  • Vannak civilizált extenderek-debuggerek.
  • Stabilitás ???!!!
  • Nem kell lapozgatni, vége a 64kb-s szegmensek miatti mérgelődéseknek !
Hátrányok
  • A legkisebb extender is 150byte.
  • Egy használható 7kb
  • Debugger van, de azért nem túl sok
  • Egy kicsit bonyolult

Akit a nagyon részletes elmélet érdekel, annak javasolnám a DR. Kovács Magda féle 386,486 I/II-t,bár csak az elméleti rizsa található meg benne...

Akkor először itt vannak a leggyakrabban használt extenderek leirása, magánvélemény, majd a tényleges programozási dolgok következnek.

  Név:         Tran's PMODE 2.51   Alkotó:      Tran   Előnyei:     Kicsi, gyors   Hátrányai:   Nincs hozzá debugger, 16bites   Vélemény:    Tanulásra, esetleg kisebb intrók-hoz megfelelő   Név:         Tran's PMODE/W 1.33   Alkotó:      Tran   Előnyei:     10kb, gyors, lehet debuggolni a Watcom Debugger-rel...   Hátrányai:   van, akinek nem tetszik ... :)   Vélemény:    DoS4GW or PMODE/W, that is the question...   Név:         DOS4GW   Alkotó:      ???   Előnyei:     Ez biztos, hogy mindenkinek tetszik, sokat tud   Hátrányai:   Nagy, mint állat   Vélemény:    Aki e mellett dönt, az egy megbízható, jól működő                extendert kap   Név:         DOS32   Alkotó:      Adam Seychell   Előnyei:     Saját debugger, kicsi   Hátrányai:   a debugger még nem tökéletes   Vélemény:    ez is elég jó, most megjelent egy új verzió, csak                az meg akkora, mint egy ház...
Ebben a doksiban nem foglalkozok az extender megírásának módjával, erre .... [megfelelő magyar nyelvű könyv már rendelkezésre áll...]
Alapok
Védett módban a szegmensregiszterek nem szegmenscímeket, hanem szelektorokat tartalmaznak. A szelektor 16 bites, az alsó két bit a kívánt privilegizálási szintet tartalmazza a következő bit a globális vagy a lokális deszkriptortábla közül választ (ezekről kicsit később lesz szó), a többi 13 bit pedig a deszkriptort jelöli ki. A deszkriptor egy 8 byte-os adattípus, egy szegmenst határoz meg.
  Rajz:                      +------------------+                         +--> |    Deszkriptor   |   +---------------+     |    +------------------+   |   Szelektor   |  ---+   +---------------+
A globális deszkriptor tábla (GDT) alap szegmens deszkriptorokat tartalmaz, melyekben a memória bizonyos részeiről információ van letárolva (honnan kezdődik, mekkora, írható vagy olvasható ...) a lokális deszkriptor tábla (LDT) opcionális, általában a "futó programok" használják. Egy operációs rendszer - például - beállíthatja a GDT-t a saját rendszer deszkriptoraival, és minden egyes taszkhoz rendelhet egy LDT-t a "futó program" deszkriptorainak. Az interrupt deszkriptor tábla (IDT) is deszkriptorokat tartalmaz, melyek megmondják a processzornak, hogy hol található az adott interrupt handler. Ez is éppúgy egy bejegyzés per interrupt formájú, mint a védett módban, de a felépítése teljesen más.
Szegmens deszkriptor
  struc segment_descriptor   seg_length0_15        dw      ?   ; a szegmens hosszának alsó wordja   base_addr0_15         dw      ?   ; a báziscím alsó wordje   base_addr16_23        db      ?   ; a báziscím felső wordjének alsó bájtja   flags                 db      ?   ; segment type and misc. flags   access                db      ?   ; a szegmens hossz felső négy bitje                                     ; és az access flagok   base_addr24_31        db      ?   ; a báziscím felső wordjének felső bájtja   ends segment_descriptor
Interrupt deszkriptor
  struc interrupt_descriptor   offset0_15    dw      ?           ; a kezelő offsetjének alsó wordja   selector0_15  dw      ?           ; szegmens szelektor   zero_byte     db      0           ;   flags         db      ?           ; flag-byte   offset16_31   dw      ?           ; a kezelő offsetjének felső wordja   ends interrupt_descriptor
A szegmens szelektor felépítése:
  0. byte: A szegmens határának 0..7 bitjei   1. byte: A szegmens határának 8..15 bitjei   2. byte: A báziscím 0..7 bitjei   3. byte: A báziscím 8..15 bitjei   4. byte: A báziscím 16..23 bitjei   5. byte: Információs bitek, a legalacsonyabb helyiértékűtől kezdve:   ---------   0. bit (A=Accessed): Akkor 1, ha a deszkriptort valamelyik                        szegmensregiszterbe töltött szelektor kiválasztja.   1. bit  (W/R=Write/Read):  Ha 0, akkor a szegmens csak olvasható,                              ha 1, akkor írható is.   2. bit (C/E): Ha 0, akkor a szegmens a báziscímtől felfelé bővül,                 ha 1, akkor a határtól lefelé.   3. bit  (EX=Executable): 1,  ha a szegmens futtatható kódot tartalmaz,                            0, ha nem.   4. bit  (S=Segment):  1  érték esetén a deszkriptor memóriaszegmenst ír le,                         0 érték esetén valami mást (pl. kaput).   5-6. bit (DPL=Descriptor Privilege Level): A privilegizálási szint,                                              esetünkben 0 lesz.   7.  bit (P=Present): Ha 1, akkor a szegmens fizikailag jelen van a                        memóriában, ha 0, akkor nincs (ez a bit a virtuális                        memória kezelésénél hasznos).   6. byte:   ---------   0-3 bit: A szegmens határának 16..19 bitjei.   4.  bit  (AVL=Available): 1-be állítva megtilthatjuk a báziscím                             változtatását.   5. bit: Fenntartott, állítsuk 0-ra.   6. bit (B=Big): 1, ha az adatszegmens mérete nagyobb 64K-nál.   7. bit (G=Granularity): Azt adja meg, hogy a szegmensméret byte-ban                           (G=0) vagy lapban (G=1) értendő.   7. byte: A báziscím 24..31 bitjei
A bázis és a méret bitjeinek kissé furcsa elrendezését az indokolja, hogy 80286-on csak az első 6 byte-ot használták, és a kompatibilitás érdekében nem ártott megtartani az eredeti formát az első 6 byte-on.

Magyarázatot igényel még a lap: ez egy 4096 byte-os egység. Erre épül egy másik virtuális memóriaszervezési módszer, a lapozás, ezzel most nem foglalkozunk. Azért érdekes a Granularity bit, mert a szegmenshatár 0 és 1048575 között állítható, ez byte-os felbontásban csak 1 MByte méretű szegmenseket jelentene. Ha lapban adjuk meg a méretet, akkor a maximális szegmensméret 4 GByte, ami a 80386 és 80486 címzésének felső határa, ugyanis 32 címbitje van a processzornak (ez még a Pentiumra is igaz).

Ezek voltak tehát az alapok. Most akkor jöjjön a gyakorlati felhasználás.

Gyakorlati felhasználás
Ez eddig mind nagyon szép és jó, de hogyan kérek memóriát, meg hogyan hivogatok interruptokat...

Ha nincsen egy védett módú extendered, akkor sehogy. Ilyenek például a : DOS4GW, PMODE/W, Dos32, ...
A memória kezelése 3 féle képpen mehet:

  • Ha nem fut semmi, akkor simán irogat a memóriába
  • Ha egy VCPI valami fut (pl. emm386), akkor VCPI hívásokon keresztül
  • Ha egy DPMI szerver fut (ilyen pl. a windoz is:)), akkor DPMI hívásokat használ
Az interruptokról meg annyit, hogy ha DOS-os interruptokat kell hívnunk, akkor azt sajnos már nem lehet a sima int xx -szel megcsinálni, mert mi van akkor, ha egy interruptnak szegmenscím kell, mi meg szelektort adunk neki...

Szerencsére a jobb extenderek (Dos32,EOS,Pmode/w,Dos4Gw) már megoldották ezt a problémát.
Akkor lássuk a tényleges gyakorlati megvalósítást.Ha ügyesek vagyunk, akkor már van egy alap fileunk, ami kb. így néz ki:

  -------------------------[ PMODE SOURCE ]-----------------------   segment code use32                         ; Ezután jönnek az utasítások ..start:   jmp          cmain                ; Csak ha pmode/w-t linkelünk            db           'WATCOM'             ; elé, hogy lehessen debuggolni cmain:     sti            cld            mov          ah,9            mov          edx,szoveg            int          21h            mov          ax,4c00h            int          21h   segment data  use32   szoveg  db    'Hello world from Protected Mode !$'   segment stack stack use32   resb 64   stacktop:   -------------------------[ END OF PMODE ]-----------------------
Akkor kérjünk egy selectort
               mov     eax,0                mov     cx,1                int     31h                mov     [selector],ax
Állítsuk be a kezdőcímét:
               mov     edx,0a0000h                shld    ecx,edx,16                mov     bx,[selector]                mov     ax,7                int     31h
Írjunk ki a memóriába egy pontot
               mov     ax,[selector]                mov     es,ax                xor     edi,edi                mov     al,[color]                mov     es:[edi],al
Szabadítsuk fel a szelektort
               mov     ax,1                mov     bx,[selector]                int     31h
Miután minden normális extendernél 0-ra van állítva a szegmensek kezdőcíme, ezért ezt az egész mókát el is hagyhatjuk:
               mov     edi,0a0000h                mov     al,[color]                mov     [edi],al         ; :)
Miután a civilizáltabb extenderek az int 21h-t is átírják, így nincs gond a fileból olvasásra. Pl. kérünk 10mb memóriát, beolvassuk a filet, kiírjuk a filet, és mindezt a lehető legkényelmesebben.

Régi interruptokat úgy tudsz meghívni, hogy

  AX = 300h   BL = interrupt száma   BH = 0   ES:EDI pedig egy táblára mutat, melyben a virtuális regiszterek   vannak eltárolva.   v86r_edi     dd      ?   v86r_esi     dd      ?   ...   [lásd NG]
mondjuk lépjünk fel 320x200x256-ba, BIOS-on keresztül...
               mov     ax,300h                mov     bl,10h                xor     bh,bh                mov     [v86r_eax],13h                mov     edi,v86_table                int     31h
Ezt lehet akár procosítani vagy makrósítani is...

Még arra kell vigyázni, ha 32bites szegmensben vagyunk, akkor 66h,67h a nem 32bites utasítások előtt lesz: xor al,al...

Egy kicsit a hatékony programozáshoz még néhány ötletet szeretnék adni: mindenképpen csináljunk különböző könyvtárakat (objecteket), amikben a filekezelés, memóriakezelés, videomem kezelés, stb. vannak, így sokkal egyszerűbb a debuggolás, mert csak az új kóddal kell vacakolni, a már működőkkel nincs semmi gond...

Adós vagyok még egy exception táblával is. Exception akkor keletkezik, ha pl. olyan utasítás lenne, amit a processzorunk nem ismer, vagy ha csak olvasható szegmensbe akarunk írni. (mov cs:[akarmi],eax - nál például)

+------+------------------+---------------------------------- |   0  |  Division by     |  Nullával osztottál |      |  Zero            | |      |                  | |   1  |  Single Step     |  Ha a trap flag be van állítva, |      |                  | akkor minden egyes utasításnál |      |                  | meghívódik... |      |                  | |   2  |  Non Maskable    | Hardware hibánál |      |  Interrupt (NMI) | |      |                  | |   3  |  Breakpoint      | Debuggolásra használják |      |                  | |   4  |  Overflow        | Ha egy "into" volt, és |      |                  | az overflow bit = 1 |      |                  | |   5  |  Bound Range     | BOUND failed |      |  Exceeded        | |      |                  | |   6  |  Invalid Opcode  | A proci számára ismeretlen |      |                  | utasítás |      |                  | |   7  |  Coprocessor     | Ha nincs koprocesszor, és |      |  Not Available   | koprocis utasítás ment volna. |      |                  | |   8  |  Double Fault    | Egy exceprion érkezett,amikor |      |                  | egy másik exception kezelő is |      |                  | aktív volt |      |                  | |   9  |  Coprocessor     | Ismeretlen |      |  Segment Overrun | |      |                  | |  10  |  Invalid TSS     | ??? |      |                  | |  11  |  Segment not     | Olyan szegmens probált elérni, |      |  Present         | melynek a present bitje 1 volt |      |                  | |  12  |  Stack Exception | Ha betelt a verem, vagy az SS |      |  Fault           | selectorja hibás |      |                  | |  13  |  General         | Megpróbáltál egy nemlétező/védett |      |  Protection      | vagy nem-present memóriacímet |      |  Fault           | elérni. |      |                  | |  14  |  Page Fault      | Ha a lapozás be volt kapcsolva, és az |      |                  | elérés egy nemlétező/védett vagy nem- |      |                  | present lapra ért |      |                  | |  16  |  Coprocessor     | Azt mondja a koprocesszor, hogy |      |  Error           | valamit elrontott |      |                  | |  17  |  Arrangement     | ??? |      |  Error           | |      |                  | |0..255|  Software        | Ha egy interruptot hívsz (int xx) |      |  Interrupts      | +------+------------------+----------------------------------
A itt megtalálhatod a pmode/w leirását is, NG (Norton Guide) formában.