pamiec operacyjna worddoc(1)


PRACA DYPLOMOWA:

PAMIĘĆ OPERACYJNA KOMPUTERÓW PC

0x08 graphic

autor:

Łukasz Sterkowicz

rok 1998

Bibliografia

Intel 80386 Programmer's Reference Manual. Intel Corporation, 1986.

eXtended Memory Specification (XMS), ver 3.0. Microsoft Corporation, Lotus Development Corporation, Intel Corporation, AST Research, Inc., 1988.

Virtual Control Program Interface (VCPI) specification, ver 1.0. Phar Lap Software, Inc., Quarterdeck Office Systems, 1989.

Dos Protected Mode Interface (DPMI) specification, ver 0.9. 1990.

Mapa pamięci IBM/PC. Arkadiusz Andrusz, Maciej Sokołowski. Lynx-SFT, Warszawa, 1995.

Encyklopedia informatyki. Stanisław Kruk. Pracownia Komputerowa Jacka Skalmierskiego, Gliwice, 1996.

Anatomia PC. Piotr Metzger. Helion, 1996.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

li {font-family: Times New Roman}

Spis treści

1. Wstęp ........................................................................................................ 5

1.1 Przyjęta konwencja ................................................................................... 6

2. Okiem technika ......................................................................................................... 7

2.1 Zasada działania pamięci .......................................................................... 8

2.2 Typy pamięci ............................................................................................ 9

2.3 Moduły pamięci ........................................................................................ 10

2.4 Układ DMA .............................................................................................. 11

3. Procesor a pamięć .................................................................................... 14

3.1 Pojęcie adresu ........................................................................................... 15

3.2 Rejestry procesora ..................................................................................... 15

3.3 Stronicowanie pamięci .............................................................................. 19

3.3.1 Pamięć wirtualna ....................................................................... 21

3.3.2 TLB ............................................................................................ 21

3.4 Tryb rzeczywisty ....................................................................................... 21

3.5 Tryb chroniony .......................................................................................... 23

3.5.1 Organizacja pamięci .................................................................. 23

3.5.2 Ochrona pamięci ........................................................................ 25

3.5.3 Wielozadaniowość ..................................................................... 27

3.5.4 Przerwania i wyjątki .................................................................. 29

3.6 Tryb V86 ................................................................................................... 31

4. Pamięć bazowa ......................................................................................... 32

4.1 Pamięć konwencjonalna ............................................................................ 33

4.1.1 Tablica wektorów przerwań ....................................................... 34

4.1.2 Zmienne BIOSu ......................................................................... 37

4.2 Pamięć górna ............................................................................................. 39

4.2.1 Pamięć wideo ............................................................................. 40

4.2.2 Obszary BIOSu .......................................................................... 41

4.2.3 Shadow RAM ............................................................................ 41

4.2.4 Bloki pamięci górnej .................................................................. 41

4.3 Struktury DOSu ........................................................................................ 42

4.3.1 Lista list ..................................................................................... 42

4.3.2 Bloki kontroli pamięci ............................................................... 43

4.3.3 Blok danych systemowych ........................................................ 44

4.3.4 Blok wstępny programu ............................................................. 44

4.4 Struktury DOSu ........................................................................................ 45

5. Pamięć rozszerzona ................................................................................. 46

5.1 Linia adresowa A20 .................................................................................. 47

5.2 Pamięć wysoka ......................................................................................... 50

5.3 Pamięć EMS ............................................................................................. 50

5.4 Schematy alokacji pamięci rozszerzonej .................................................. 59

5.4.1 BOTTOM-UP ............................................................................ 60

5.4.2 TOP-DOWN .............................................................................. 61

5.4.3 XMS .......................................................................................... 62

5.4.4 VCPI .......................................................................................... 67

5.4.5 DPMI ......................................................................................... 71

5.4.6 Alternatywny sposób alokacji .................................................... 85

5.5 DOS extendery ......................................................................................... 86

5.6 Funkcje BIOSu ......................................................................................... 87

5.7 Instalacja sterowników ............................................................................. 88

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

1. Wstęp

        Niniejsze opracowanie zostało stworzone w taki sposób, aby docierało do szerokiej rzeszy odbiorców. Rozdział "Okiem technika" skierowany jest do osób chcących zapoznać się z pamięcią, o której wiedzą jedynie tyle że jest. Swoje trzy grosze znajdą też tam programiści wykorzystujący układ DMA. Kolejny rozdział "Procesor a pamięć" powinni przeczytać wszyscy chcący zagłębić się w dalsze części opracowania. Są tam zdefiniowane podstawowe pojęcia, i wiedza niezbędna do zrozumienia niektórych zagadnień. Temat poświęcony trybie chronionemu mogą pominąć początkujący programiści, gdyż jest on napisany z myślą o twórcach systemów i oprogramowania pracującego w tym trybie. Rozdział "Pamięć bazowa" poświęcony jest pamięci zarządzanej przez stary, lecz wciąż obecny system DOS. Ostatni z rozdziałów "Pamięć rozszerzona" dotyczy w dużej mierze sposobów udostępniania tej pamięci dla programów pracujących pod systemem DOS, lecz nie tylko. Skierowany jest on głównie do twórców DOS-extenderów, emulatorów DOS-u, lecz pożyteczne informacje znajdzie też zwykły użytkownik mający problemy ze skonfigurowaniem pamięci rozszerzonej.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

--></><basefont face="Times New Roman" size=3>

1.1. Przyjęta konwencja

        Aby rozwiać wszelkie wątpliwości, poniżej przedstawiony jest sposób w jaki należy interpretować poszczególne elementy opracowania.

Nazewnictwo

        Przyjęte nazewnictwo jest z godne z tym, które obowiązuje w ogólnodostępnej literaturze. Wyjątek dotyczy dwóch przypadków. Po pierwsze niektóre zwroty z języka angielskiego przetłumaczone zostały zgodnie z inwencją autora. Po drugie określenie "pamięć bazowa" jest w literaturze równoważne "pamięci konwencjonalnej", jednak autor postanowił je odnieść do obszaru pierwszego megabajta pamięci, gdyż nie ma funkcjonalnego określenia tego obszaru.

Funkcje API

        W przedstawionych funkcjach API (Application Program Interface) przeważnie występują dwa przypadki zakończenia takiej funkcji. Chociaż nie jest to jawnie powiedziane, pierwszy z przypadków dotyczy poprawnego zakończenia, natomiast drugi błędnego.

Przykłady

        Przedstawione przykłady w języku assemblera są zgodne ze składnią Turbo Assemblera (TASM) firmy Borland. Należy pamiętać iż nie są to w pełni działające programy, a jedynie ich fragmenty mające uzmysłowić działanie niektórych mechanizmów. Użyte dyrektywy ".CODE" i ".DATA" mają jedynie za zadanie wizualne oddzielenie fragmentów kodu od danych.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

--></><basefont face="Times New Roman" size=3>

2. Okiem technika

        Nie sposób rozpocząć pracy poświęconej pamięci bez krótkiego rzutu okiem na nią od strony technicznej. Dlatego też treścią tego rozdziału jest budowa pamięci, typy w jakich ona występuje, oraz układy bezpośrednio z nią współpracujące.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

--></><basefont face="Times New Roman" size=3>

2.1. Zasada działania pamięci

        Pamięć RAM fizycznie występuje w postaci układów scalonych (chipów). Każdy taki chip składa się z układów zwanych przerzutnikami, zazwyczaj są to przerzutniki bistabilne (flip-flop) typu D. Charakteryzują się one tym iż posiadają dwa stany równowagi trwałej, a więc mogą przechowywać jeden bit informacji (przyjmujący wartości 0 lub 1). Przerzutniki układane są w matrycę, dzięki czemu zapewniony jest swobodny dostęp do pamięci:

0x08 graphic

        Specjalny układ zwany dekoderem adresu przekształca napływające adresy tak aby móc dokonać odczytu z matrycy. Sama matryca działa w ten sposób iż na żądaną linię słowa podajemy napięcie, po czym możemy pobrać/zapisać wartości na linii bitów.

        Pamiętać należy iż architektura komputerów PC uniemożliwia nam programowy odczyt pojedynczego bitu. Najmniejszą jednostką którą możemy odczytać jest bajt (8 bitów).

        Ze względu na różne elementy konstrukcyjne dzielimy pamięci na statyczną i dynamiczną.

Pamięć statyczna

0x08 graphic
        Oto układ komórki statycznej przechowujący bit informacji:

        Pamięć oparta o te układy charakteryzuje się tym iż jest nieulotna i nie wymaga odświeżania.

        W zależności od tego jaką wartość reprezentuje komórka, jeden z tranzystorów przewodzi, a drugi jest w stanie odcięcia. Gdy komórka nie jest wybrana na linii słowa występuje napięcie 0,3 V dzięki czemu prąd płynący przez przewodzący tranzystor płynie do linii słowa (złącze połączone z linią bitów jest spolaryzowane zaporowo). Gdy chcemy odczytać stan, na linii słowa podajemy napięcie 3 V przez co spolaryzowane zaporowo staje się złącze z linią słowa, natomiast przewodzić zaczyna złącze z linią bitów. Spadek napięcia na odpowiednim rezystorze powoduje różnicę potencjałów która odczytywana jest przez wzmacniacz różnicowy jako 0 lub 1 (w zależności czy linia D czy D zaprzeczone ma wyższy potencjał). Podczas zapisu komórki na linii słowa również wystawiamy napięcie 3 V a na linie bitów żądane wartości, co spowoduje odpowiednie ustawienie tranzystorów.

Pamięć dynamiczna

        Oto układ komórki dynamicznej przechowujący bit informacji:

0x08 graphic

        Pamięć dynamiczna cechuje się ulotnością ze względu na użycie pojemności C. Wymaga to niestety odświeżania poprzez podanie odczytywanej wartości na sprzężenie zwrotne. Konieczny jest wtedy okresowy odczyt komórki, realizowany sprzętowo, lub programowo.

        W przypadku wartości 1 kondensator jest załadowany, w przypadku 0 rozładowany. Zapisywanie wartości polega na podaniu stanu logicznego na linię bitów i napięcia na bramkę tranzystora T2 co powoduje ładowanie/rozładowanie kondensatora. Odczyt działa analogicznie, z tym że napięcie podajemy na bramkę T3. Wtedy prąd płynie przez tranzystory T1 i T3 do linii bitów.

0x08 graphic

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

--></><basefont face="Times New Roman" size=3>

2.2. Typy pamięci

        Pamięć operacyjna naszego komputera zwana jest pamięcią RAM (Random Access Memory), czyli pamięcią o dostępie swobodnym. Ze względu na różną budowę i dostęp, wśród pamięci RAM wyróżniamy poszczególne typy.

Podział ze względu na budowę

SRAM - (Static RAM), pamięć statyczna wykonana w oparciu o tranzystory bipolarne. Cechuje ją bardzo krótki czas dostępu do poszczególnej komórki i nieulotność. Niestety, pamięci SRAM są drogie, dlatego też wykorzystuje się je głównie jako pamięci cache.

DRAM - (Dynamic RAM) pamięć dynamiczna wykonana w oparciu o tranzystory MOS. Pamięć ta jest wolniejsza niż pamięć SRAM a w dodatku jest ona ulotna. Aby pamięć ta nie utraciła danych trzba ją odświeżać z częstotliwością co najmniej kilkaset Hz. Odświeżanie polega na zwykłym odczycie zawartości komórki.

SDRAM - (Synchronous Dynamic RAM) pamięć dynamiczna, synchroniczna. Pamięć ta jest podobna do pamięci DRAM, z tym że dostęp do komórek pamięci jest zsynchronizowany z zewnętrznym zegarem taktującym procesor.

Podział ze względu na dostęp

FPM RAM - (Fast Page Mode RAM), pamięć ta zorganizowana jest w strony, przy czym najszybciej realizowany jest dostęp do kolejnych komórek w obrębie strony.

EDO RAM - (Extended Data Output RAM), jest to pamięć w przypadku której w czasie odczytu danej komórki, może zostać pobrany adres następnej.

BEDO RAM - (Burst EDO RAM), w przypadku tej pamięci zamiast jednego adresu pobierane są cztery, przy czym na magistralę wystawiany jest tylko pierwszy co znacznie zwiększa szybkość dostępu.

0x08 graphic

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

--></><basefont face="Times New Roman" size=3>

2.3. Moduły pamięci

        Pamięć fizycznie występuje w postaci kości (układów scalonych), które mogą być całkowicie od siebie różne. Dlatego też powstały standardy konstrukcyjne, wymuszające łączenie kości w funkcjonalne moduły, które są zwyczajnymi płytkami drukowanymi z wlutowanymi chipami pamięci. Wraz z rozwojem komputerów i poszerzaniem szyny adresowej powstały różne typy modułów.

SIMM - (Single Inline Memory Module), moduł 32-stykowy, w którym szerokość szyny adresowej wynosi 8 bitów. Moduły te obecnie wykorzystywane są jedynie w niektórych kartach rozszerzających, gdyż płyty główne już dawno przestały je obsługiwać.

PS/2 - moduł 72-stykowy z 32-bitową szyną adresową. Jego nazwa powstała od rodziny komputerów PS/2, w których pierwotnie zainstalowano te moduły.

DIMM - (Dual Inline Memory Module) moduł 128-stykowy w którym szyna adresowa ma 64 bity. Jest to najnowszy standard konstrukcyjny wykorzystywanych w płytach z procesorem Pentium.

0x08 graphic

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

--></><basefont face="Times New Roman" size=3>

2.4. Układ DMA

        Układ DMA (Direct Memory Access) służy do bezpośredniej komunikacji z pamięcią bez użycia procesora. Najczęściej wymiana danych przebiega na linii pamięć - urządzenia zewnętrzne, lecz możliwa jest też wymiana pamięć - pamięć (obecnie bezużyteczna ze względu na powolność układów DMA oraz blokadę magistrali dla procesora).

Fizycznie DMA jest umieszczone w dwóch kościach 8237A, pełniących role układów master i slave, z których każdy obsługuje cztery kanały (slave: 0-3, master: 4-7). Kanał 4 jest używany do realizacji połączenia kaskadowego układu master z układem slave. Kanał 2 jest standardowo wykorzystywany przez kontroler stacji dyskietek. Należy dodać że kanały slave są 8-bitowe, natomiast kanały master w zależności od modelu komputera 16 lub 32-bitowe.

        Wyróżniamy pięć trybów pracy każdego z kanałów DMA:

Tryb S - (Single), tryb w którym dokonywane jest pojedyncze przesłanie. Licznik transmisji jest zmniejszany a rejestr adresowy (w zależności od zaprogramowania) zmniejszany lub zwiększany. Kolejne przesłanie wymaga żądania przez urządzenie z którym następuje komunikacja (sygnał DREQ).

Tryb B - (Block), w tym trybie transmisja trwa nieprzerwanie do wystąpienia sygnału jej zakończenia (EOP), lub do osiągnięcia żądanej liczby przesłań.

Tryb D - (Demand), podobny do trybu B, z tym że transmisja może być chwilowo wstrzymana przez wystąpienie żądania o wyższym priorytecie, lub przez zanik sygnału na linii żądania (DREQ).

Tryb C - (Cascade), w rybie tym układ master jedynie przekazuje sygnały do układu slave. Dzięki niemu można zrealizować kaskadowe połączenie układów 8237A.

Tryb V - (Verify), tryb służący wewnętrznej weryfikacji układu. Układ wytwarza adresy i reaguje na sygnały, lecz nie generuje sygnałów dostępu do pamięci i urządzeń we/wy.

        Programowanie układu DMA polega na zapisie odpowiednich portów. Najpierw maskujemy żądany kanał poprzez rejestr maski. Następnie wybieramy tryb za pomocą rejestru trybu oraz zapisujemy wartości rejestrów strony, adresu i licznika. Rejestry adresu są 16-bitowe (ustawiamy przerzutnik w stan początkowy, następnie zapisujemy młodszy bajt a potem starszy), natomiast rejestry stron 8-bitowe i uzupełniają one starszą część 24-bitowego adresu.

        Poniższa tabela zawiera wszystkie adresy portów sterujących pracą układu DMA:

adres

opis portu

Porty układu slave

000H

Rejestr adresu kanału 0

001H

Rejestr licznika kanału 0

002H

Rejestr adresu kanału 1

003H

Rejestr licznika kanału 1

004H

Rejestr adresu kanału 2

005H

Rejestr licznika kanału 2

006H

Rejestr adresu kanału 3

007H

Rejestr licznika kanału 3

008H

Rejestr stanu (odczyt)

008H

Rejestr rozkazowy (zapis)

009H

Rejestr żądań

00AH

Rejestr maski kanału

00BH

Rejestr trybu

00FH

Rejestr maskujący

081H

Rejestr strony kanału 2

082H

Rejestr strony kanału 3

083H

Rejestr strony kanału 1

087H

Rejestr strony kanału 0

Porty układu master

089H

Rejestr strony kanału 6

08AH

Rejestr strony kanału 7

08BH

Rejestr strony kanału 5

08DH

Rejestr strony kanału 4

0C0H

Rejestr adresu kanału 4

0C1H

Rejestr licznika kanału 4

0C2H

Rejestr adresu kanału 5

0C3H

Rejestr licznika kanału 5

0C4H

Rejestr adresu kanału 6

0C5H

Rejestr licznika kanału 6

0C6H

Rejestr adresu kanału 7

0C7H

Rejestr licznika kanału 7

0D0H

Rejestr stanu (odczyt)

0D0H

Rejestr rozkazowy (zapis)

0D2H

Rejestr żądań

0D4H

Rejestr maski kanału

0D6H

Rejestr trybu

0DEH

Rejestr maskujący

Port 009H i 0D2H, Rejestr żądań
bity 3-7 - równe zero
bit 2 - jedynka oznacza uruchomienie transmisji
bity 0-1 - numer kanału, którego dotyczy żądanie

Port 008H i 0D0H, Rejestr stanu (tylko do odczytu)
bity 4-7 - jedynka oznacza wystąpienie zgłoszenia dla kanału
bity 0-3 - jedynka oznacza osiągnięcie liczby przesłań dla kanału

Port 008H i 0D0H, Rejestr rozkazowy (tylko do zapisu)
Rejestr ten służy do programowej kontroli pracy układu

Port 00AH i 0D4H, Rejestr maski kanału
bity 3-7 - równe zero
bit 2 - jedynka oznacza zamaskowanie kanału
bity 0-1 - numer kanału, którego dotyczy żądanie

Port 00FH i 0DEH, Rejestr maskujący
bity 4-7 - równe zero
bity 0-3 - jedynka oznacza zamaskowanie kanału

Port 00BH i 0D6H, Rejestr trybu
bity 6-7 - tryb pracy (00 - D, 01 - S, 10 - B, 11 - C)
bit 5 - 0 oznacza inkrementację adresu, 1 dekrementację
bit 4 - jedynka powoduje samooprogramowanie się układu
bity 2-3 - 00 - tryb V, 01 - zapis, 10 - odczyt
bity 0-1 - numer kanału, którego dotyczy żądanie

        Dodatkowo występują także "sztuczne" porty, których specyfika polega na tym iż istotny jest tylko fakt zapisu do portu (argument przesyłany jest ignorowany). Porty te przedstawia tabela:

adres

działanie portu

Porty układu slave

00CH

Ustawienie przerzutnika w stan początkowy (używany przy przesyłaniu danych 16-bitowych, zapobiega pomyleniu młodszego bajtu ze starszym)

00DH

Programowa inicjalizacja układu

00EH

Wyzerowanie rejestru maski (uaktywnienie wszystkich kanałów)

Porty układu master

0D8H

Ustawienie przerzutnika w stan początkowy

0DAH

Programowa inicjalizacja układu

0DCH

Wyzerowanie rejestru maski

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

3. Procesor a pamięć

        Pamięć jest niewątpliwie elementem architektury komputera, który najintensywniej współpracuje z procesorem. Do dyspozycji programisty istnieje wiele rejestrów i poleceń procesora, ułatwiających dostęp do pamięci, a także tryby pracy dla których zdefiniowane są różne jej modele. Dlatego mówiąc o pamięci nie można pominąć tak istotnego zagadnienia jak współpraca z procesorem. Niniejszy rozdział zawiera szczegółowy opis architektury procesora i jego mechanizmów. Znajduje się tutaj między innymi opis rejestrów i trybów pracy procesora 80386 i wyższych. Procesor ten, jako pierwszy 32-bitowy procesor Intela wprowadził standard dostępu do czterogigowej pamięci, jej ochrony i stronicowania, który praktycznie bez zmian zaimplementowany jest w najnowszych procesorach Pentium.

3.1. Pojęcie adresu

        Adresem nazywamy pewną specyficzną liczbę, która opisuje komórkę pamięci. Za pomocą adresu informujemy procesor gdzie ma zostać zapisana, lub odczytana dana. Niestety, ze względu na różne sposoby dostępu procesora do pamięci samo pojęcie adresu niewiele już znaczy. Poniżej zdefiniowane są najistotniejsze pojęcia adresów, które należy poznać aby bez problemu orientować się podczas czytania specjalistycznej literatury:

adres fizyczny - (physical address) jest adresem najniższego poziomu. Podczas komunikacji procesora z układem obsługującym pamięć, na jego liniach adresowych wystawiany jest właśnie adres fizyczny. Wykorzystujemy go przy tworzeniu tablic implementujących stronicowanie, lub podczas komunikowania się z dowolnymi urządzeniami. Należy zauważyć, że podczas gdy mechanizm stronicowania pamięci jest wyłączony, adres fizyczny jest równy adresowi liniowemu,

adres liniowy - (linear address) jest formą przejściową między adresem fizycznym. Dzięki istnieniu adresu liniowego można uzyskać ciągłość pamięci nawet, jeżeli fizycznie jest ona porozrzucana. Adres liniowy jest zamieniany przez mechanizm stronicowania na adres fizyczny za pomocą tablic stron. W systemach wielozadaniowych niemożliwa jest wymiana adresów liniowych pomiędzy zadaniami, gdyż każde z nich może mieć oddzielne tablice stron. Adresy liniowe wykorzystujemy głównie przy tworzeniu deskryptorów,

adres logiczny - (logical address) jest adresem złożonym z dwóch członów: identyfikatora segmentu i przemieszczenia w tym segmencie. Dla trybu rzeczywistego i V86 identyfikatorem segmentu będzie jego adres liniowy podzielony przez 16, dla trybu chronionego będzie to selektor segmentu. Adres taki zapisujemy w postaci SEGMENT:OFFSET lub SELEKTOR:OFFSET. Adres logiczny powinien być wykorzystywany do zapisywania lub odczytywania danych, procesor automatycznie zamienia go na adres logiczny a następnie na adres fizyczny,

adres segmentowy - (segment) jest pierwszą częścią adresu logicznego. Jeżeli został podany bez przemieszczenia oznacza to, że wskazuje nie konkretną komórkę pamięci a cały blok. Domyślnie przyjmujemy przemieszczenie 0. Adres segmentowy zwracany jest przez niektóre funkcje interfejsów API (Application Program Interface),

adres relatywny - (offset) jest przemieszczeniem względem segmentu, lub jakiegoś bloku danych. Adres takiego segmentu musi być znany.

0x08 graphic

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

3.2. Rejestry procesora

        Pierwszym etapem poznawania architektury procesora są jego rejestry. W zależności od ich typów przechowują one dane, adresy pamięci lub flagi. Poniżej przedstawione są wszystkie rejestry procesorów 386 wzwyż, wraz ze szczegółowym opisem:

Rejestry podstawowe

        Do tej grupy rejestrów należą 32-bitowe rejestry EAX, EBX, ECX, EDX, ESI, EDI, ESP i EBP. Każdy z nich ma możliwość odwołania się do mniej znaczącego słowa, a niektóre także do bajtów w tym słowie. W trybie rzeczywistym często znaczenie ma jedynie mniej znaczące słowo każdego z nich. Budowę rejestrów podstawowych przedstawia rysunek:

0x08 graphic

EAX - akumulator, jest używany w niektórych operacjach jak mnożenie, czy dzielenie,
EBX - rejestr bazowy, zawiera przemieszczenie względem segmentu danych,
ECX - rejestr licznikowy, określa liczbę wykonań pętli,
EDX - używany jako rozszerzenie akumulatora w operacjach 64-bitowych,
ESI - rejestr indeksowy, zawiera adres źródła w operacjach łańcuchowych,
EDI - rejestr indeksowy, zawiera adres przeznaczenia w operacjach łańcuchowych,
ESP - wskaźnik stosu,
EBP - rejestr bazowy, zawiera przemieszczenie względem segmentu stosu.

Rejestry segmentowe

        W skład tej grupy wchodzą rejestry 16-bitowe CS, DS, SS, ES, FS i GS. Każdy z nich zawiera identyfikator segmentu. W trybie rzeczywistym jest to adres liniowy segmentu podzielony przez 16, a w trybie chronionym selektor.

CS - segment kodu,
DS - segment danych,
SS - segment stosu,
ES - dodatkowy segment danych,
FS - dodatkowy segment,
GS - dodatkowy segment.

Wskaźnik instrukcji

        Rejestr EIP jest wskaźnikiem aktualnie wykonywanej instrukcji. Nie można się do niego odwołać bezpośrednio. W zależności czy segment jest typu USE32, czy USE16, używany jest rejestr 32-bitowy (EIP), lub rejestr 16-bitowy (IP).

Rejestr flag

0x08 graphic
        Rejestr rozszerzonych flag EFLAGS, zawiera ogólne informacje o stanie procesora w danej chwili. Stan tych flag zmieniany jest w zależności od wyniku niektórych operacji. Rozmieszczenie flag w rejestrze przedstawia rysunek:

CF - (Carry Flag) znacznik przeniesienia,
PF - (Partity Flag) znacznik parzystości,
AF - (Auxiliary Flag) znacznik przeniesienia pomocniczego,
ZF - (Zero Flag) znacznik zera,
SF - (Sign Flag) znacznik znaku,
TF - (Trap Flag) znacznik pułapki,
IF - (Interrupt Enable) znacznik zezwolenia na przerwanie,
DF - (Direction Flag) znacznik kierunku operacji łańcuchowych,
OF - (Overflow) przepełnienie,
IOPL - (I/O Privillege Level) 2-bitowy poziom uprzywilejowania operacji wejścia wyjścia,
NT - (Nested Task) znacznik zagnieżdżonego zadania,
RF - (Resume Flag) znacznik wznowienia,
VM - (Virtual 8086 Mode) znacznik trybu V86.

Rejestry kontrolne

        Rejestry kontrolne sterują pracą procesora. Wyróżniamy trzy rejestry CR0, CR2 i CR3, dwa ostatnie uwzględniane są tylko w przypadku włączonego mechanizmu stronicowania pamięci.

CR3 - bity 12-31 zawieraja numer (adres fizyczny podzielony przez 4k) strony zawierającej katalog stron, reszta bitów zarezerwowana,

CR2 - zawiera 32-bitowy adres liniowy komórki pamięci, do której odwołanie spowodowało wyjątek 0EH (Page Fault),

CR0 - rejestr flag kontrolujących pracę procesora, przedstawiony na rysunku:

0x08 graphic

PE - (Protection Enable) bit trybu chronionego,
MP - (Math Present) znacznik kontroli koprocesora,
EM - (Emulation) znacznik emulacji koprocesora,
TS - (Task Switched) znacznik przełączenia zadania,
ET - (Extension Type) znacznik typu koprocesora,
PG - (Paging) znacznik mechanizmu stronicowania.

Rejestry testowe

        Rejestry TR6 i TR7 służą do testowania pamięci cache TLB (Translation Lookaside Buffer) używanej przy przekształcaniu przez procesor adresu liniowego na adres fizyczny. Są one specyficzne dla maszyn 80386 i w wyższych procesorach powinny być używane zgodnie z ich specyfikacją. Testowanie pamięci TLB powinno się odbywać na poziomie BIOSu, dlatego rejestry te nie zostaną dokładnie omówione.

Rejestry uruchomieniowe

        Rejestry uruchomieniowe zwiększają możliwości kontroli kodu i danych. Za ich pomocą można ustawić cztery pułapki i kontrolować ich stan. Istnieje sześć rejestrów uruchomieniowych DR0, DR1, DR2, DR3, DR6 i DR7. Rejestry DR0-DR3, zawierają adresy liniowe pułapek, pozostałe dwa służą do konfiguracji i sprawdzania pułapek.

0x08 graphic
DR7 - rejestr flag kontrolujących pułapki, przedstawiony na rysunku:

L0-L3 - uaktywnienie pułapki 0-3, zerowane po wystąpieniu przełączenia zadania,

G0-G3 - uaktywnienie pułapki 0-3, nie zerowane po wystąpieniu przełączenia zadania,

LE - zwolnienie pracy procesora po wystąpieniu pułapki, zerowane po wystąpieniu przełączenia zadania,

GE - zwolnienie pracy procesora po wystąpieniu pułapki, nie zerowane po wystąpieniu przełączenia zadania,

R/W0-R/W3 - 2-bitowa wartość określająca warunek jaki wymusza przerwanie działania programu po wystąpieniu pułapki 0-3:

00 - wykonanie instrukcji,

01 - zapisanie,

11 - odczytanie lub zapisanie,

LEN0-LEN3 - 2-bitowa wartość określająca rozmiar pułapki 0-3:

00 - bajt (lub wykonanie instrukcji),

01 - słowo,

11 - podwójne słowo,

DR6 - rejestr flag kontrolujących stan pułapek, przedstawiony na rysunku. Bity tego rejestru mogą być jedynie ustawiane przez procesor, dlatego procedura obsługi wyjątku 01H (Debugger exceptions) powinna je wyzerować.

0x08 graphic

B0-B3 - natrafienie na pułapkę 0-3,
BD - znacznik kolizji w dostępie do rejestrów uruchomieniowych,
BS - znacznik związany z flagą TF rejestru EFLAGS,
BT - znacznik związany z bitem T rejestru TSS,

Rejestry zarządzania pamięcią

        Istnieją jeszcze dodatkowe rejestry przechowujące adresy tablic systemowych GDTR, LDTR, IDTR, i TR:

GDTR - rejestr ten składa się z 6 bajtów w których przechowuje adres liniowy i rozmiar (pomniejszony o 1) globalnej tablicy deskryptorów GDT. Rejestr GDTR przedstawia poniższy rysunek:

0x08 graphic

LDTR - rejestr analogiczny do GDTR, zawiera informacje o lokalnej tablicy deskryptorów LDT,

IDTR - 16-bitowy rejestr przechowujący selektor tablicy deskryptorów przerwań IDT,

TR - 16-bitowy rejestr przechowujący selektor segmentu stanu zadania TSS.

0x08 graphic

3.3. Stronicowanie pamięci

        Mechanizm stronicowania pamięci zaimplementowany został dopiero w procesorach 80386 i stanowił przełom w komputerach typu PC. Umożliwił on stworzenie trybu V86, sklejanie fizycznie rozproszonych obszarów pamięci w ciągłe bloki, oraz implementację pamięci wirtualnej. Mechanizm ten dzieli cały dostępny 4G obszar na strony wielkości 4kb, które za pomocą tablic stron zmieniają swoje położenie w przestrzeni adresowej widzianej przez programy.

        Z mechanizmem stronicowania procesor związany jest przez flagę PG w rejestrze CR0 (włączającą/wyłączającą stronicowanie) oraz przez rejestry CR3 (zawierający fizyczny adres katalogu tablic) i CR2 (zawierający liniowy adres komórki pamięci do której dostęp wygenerował wyjątek). Przed ustawieniem flagi PG należy zainicjować katalog tablic i związane z nim tablice stron. Katalog tablic jest to struktura opisująca wszystkie tablice stron, które z kolei opisują strony fizyczne. Katalog i tablice mają rozmiar jednej strony (4kb), a każdy ich wpis zajmuje 4 bajty i opisuje jedną stronę. Łatwo więc policzyć że ilość tablic stron jest równa 1024, z których każda opisuje 1024 strony fizyczne. Tak więc mechanizm stronicowania potrafi opisać 1024 * 1024 * 4096 = 4G (ILOŚĆ_TABLIC * ILOŚĆ_STRON_OPISYWANYCH_PRZEZ_TABLICĘ * WIELKOŚĆ_STRONY), czyli cały obszar przestrzeni adresowej. O to jak wygląda pojedynczy wpis w katalogu i tablicach 0x08 graphic
stron:

P - (Present) bit obecności strony w pamięci (jeżeli wyzerowany reszta bitów do dyspozycji programisty),
R/W - (Read/Write) znacznik praw modyfikacji,

U/S - (User/Supervisor) znacznik praw dostępu,

A - (Accessed) ustawiany gdy wystąpił zapis lub odczyt ze strony,

D - (Dirty) ustawiany gdy wystąpił zapis do strony (nie dotyczy tablic stron),

AVAIL - (Available) trzy bity przeznaczone dla programisty,

        Numer strony jest jej adresem fizycznym podzielonym przez 4k (4096).

        Pozostaje tylko pytanie w jaki sposób powstaje adres liniowy do którego można się odwoływać. Na adres liniowy opisujący bajt pamięci składają się trzy człony:

Translację adresu logicznego na adres fizyczny przedstawia rysunek:

0x08 graphic

3.3.1. Pamięć wirtualna

        Dzięki mechanizmowi stronicowania pamięci możliwe jest stworzenie pamięci wirtualnej (virtual memory). Polega to na powiększeniu dostępnej przestrzeni o nieistniejące obszary pamięci. W chwili gdy wystąpi żądanie przydziału pamięci, a wykorzystany jest cały obszar fizyczny, system operacyjny zapisuje fragmenty pamięci fizycznej na dysk po czym przepina (za pomocą mechanizmu stronicowania) tą pamięć udostępniając ją żądającemu zadaniu. Jeżeli pamięć zapisana na dysk jest potrzebna, system zapisuje inny obszar i tak w kółko. Zapis dokonywany jest do specjalnego pliku wymiany (swap file), lub partycji wymiany (swap partition). Jeżeli jest to plik, musi on zajmować kolejne sektory i nie może być przenoszony w inne miejsce dysku. Rozmiar pamięci wirtualnej jest ograniczony przez rozmiar pliku lub partycji.

Pamiętać należy, że niektóre obszary pamięci powinny być zablokowane przed wymianą na dysk (dotyczy to głównie procedur obsługi przerwań, oraz procedur, które nie mogą czekać na stosunkowo długi czas odczytu z dysku).

        Aby zrealizować czynność wymiany musimy mieć kontrolę nad wyjątkiem 0DH (Page fault), oraz nad tablicami stron. Należy zdefiniować jeden z bitów wpisu w tablicach, który będzie oznaczał czy strona może być wymieniona na dysk, czy nie. Ponieważ podczas, gdy bit P wpisu jest wyzerowany reszta bitów jest dostępna, należy je wykorzystać na numer sektora w pliku/partycji wymiany.

Procedura obsługi wyjątku 0DH musi w pierwszej kolejności odczytać adres liniowy komórki do której dostęp spowodował wyjątek (rejestr CR2). Na podstawie tego adresu znaleźć odpowiedni wpis w tablicach. Następnie trzeba odszukać stronę którą zapiszemy na dysk. Strona ta musi być obecna w pamięci (P=1) i musi mieć prawo do wymiany (zdefiniowany przez nas bit). Zapisujemy stronę na dysk, zerujemy bit P i uzupełnianiu jej wpis o sektor w pliku/partycji wymiany. Następnie wolną już stronę fizyczną podpinamy pod tą która wygenerowała wyjątek i na koniec i odczytujemy dane z dysku.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

3.3.2. TLB

        TLB (Translation Lookaside Buffer), jest blokiem pamięci wewnętrznej procesora, który służy przyspieszeniu mechanizmu stronicowania. Zawiera on dane na temat najczęściej używanych tablic stron. Bufor ten powinien być czyszczony po każdej zmianie zawartości katalogu, lub tablic stron, poprzez załadowanie rejestru CR3. Można go także testować za pomocą rejestrów TR6 i TR7.

0x08 graphic

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

pre {font-family: Courier}

3.4. Tryb rzeczywisty

        Tryb rzeczywisty jest już bardzo przestarzały i istnieje jedynie ze względu na zgodność z dużą ilością oprogramowania przeznaczonego wyłącznie dla niego. Tryb ten może zaadresować wyłącznie 1Mb pamięci operacyjnej. 20-bitowy adres fizyczny jest dostępny poprzez dwa rejestry: segmentowy i indeksowy. Rejestr segmentowy zawiera adres pamięci wyrażony w paragrafach (paragraf=16 bajtów), natomiast rejestr indeksowy zawiera przemieszczenie od adresu wskazywanego przez rejestr segmentowy, wyrażone w bajtach. Adres taki ma postać SEGMENT:OFFSET (offset czyli przemieszczenie) i nazywany jest adresem logicznym. Adres fizyczny otrzymuje się z adresu logicznego według wzoru: ADRES_FIZYCZNY = SEGMENT * 16 + OFFSET. Ponieważ obydwa rejestry segmentowy i indeksowy są 16-bitowe widać że w ten sposób można zaadresować ponad 1Mb pamięci (0FFFFH * 16 + 0FFFFH = 10FFEFH czyli 1,114,096 bajtów). Dowolna komórka pamięci może być adresowana na wiele sposobów np. komórka o adresie fizycznym 012CH może być wyrażona za pomocą nast. adresów logicznych: 0012H:000CH, 0010H:002CH, 0011H:001CH lub 0000H:012CH. Widać więc że segment nie jest jakąś sztywną formą podziału pamięci, a jego rozmiar 64kb jest ograniczony przez wielkość rejestru indeksowego.
Uwaga! Pomimo iż procesory od 386 wzwyż posiadają 32-bitowe rejestry indeksowe w trybie rzeczywistym mechanizm segmentacji używa tylko ich mniej znaczącego słowa.

        W trybie rzeczywistym mechanizm stronicowania jest wyłączony dlatego adres logiczny jest zamieniany wprost na adres fizyczny (bez pośredniej zamiany na adres liniowy).

        Komputery PC posiadają następujące rejestry segmentowe: CS, DS, ES, SS (procesory od 386 wzwyż dodatkowo FS i GS), oraz indeksowe: IP, SI, DI, SP, BP. Oznaczenia rejestrów segmentowych nazywamy prefiksami. Rejestry segmentowe i indeksowe tworzą domyślne pary (przy odwołaniu do danego rejestru indeksowego nie trzeba podawać ich domyślnego prefiksu): DS:SI, ES:DI, SS:BP. Do rejestrów IP i SP nie odwołujemy się jawnie, poza tym rejestr IP jest wskaźnikiem wykonywanej instrukcji i nie możemy go modyfikować poleceniem MOV.

        Ze względu na niewielki w dzisiejszych czasach rozmiar segmentu stosuje się różne techniki odczytu danych. Poniższy kod przedstawia najprostszy sposób odczytu następujących po sobie segmentów których liczba znajduje się w rejestrze CX.

;w CX ilość segmentów do odczytu

;początek bufora ma adres DS:0000H

XOR SI,SI

CLD

PETLA:

LODSB

;tutaj obróbka danej znajdującej się w AL

OR SI,SI

JNE SHORT PETLA

MOV DX,DS

ADD DH,10h

MOV DS,DX

LOOP PETLA

;tutaj zakończenie odczytu z bufora

0x08 graphic

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

3.5. Tryb chroniony

        Tryb chroniony istnieje począwszy od procesorów 80286 gdzie pozwalał zaadresować 16Mb pamięci, jednak pełne skrzydła rozwinął dopiero w procesorze 80386 i obecnie udostępnia nam przestrzeń adresową wielkości 4Gb. Tryb chroniony maszyn 80286 jest zubożoną wersją w stosunku do 80386, więc nie będziemy się nim dokładnie zajmować.

        Dzięki wprowadzeniu trybu chronionego możliwe się stało stworzenie profesjonalnych, wielozadaniowych systemów operacyjnych, zorientowanych sieciowo. Mechanizmy ochrony zapewniają łatwe wykrywanie błędów i bezpieczeństwo danych systemowych (system może mieć architekturę całkowicie zamkniętą i udostępniać programom zasoby komputera według własnych praw). Wielozadaniowość pozwala na jednoczesne wykonywanie się niezależnie wielu zadań, którymi zarządza system operacyjny. W połączeniu ze stronicowaniem pamięci tryb chroniony czyni maszyny klasy PC najpoważniejszymi komputerami osobistymi.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

3.5.1. Organizacja pamięci

        W trybie chronionym pamięć podzielona jest na segmenty, z których każdy może mieć dowolny rozmiar i mogą one na siebie nachodzić. Segmenty te nie mają jednak nic wspólnego z segmentami trybu rzeczywistego, dlatego też oprogramowanie jest specyficzne dla danego trybu i nie może być uruchamiane w innym. Segmenty opisywane są za pomocą deskryptorów, umieszczanych w tablicach deskryptorów. Istnieją trzy rodzaje takich tablic:

- globalna tablica deskryptorów GDT (Global Descriptor Table), jest tablicą przeznaczoną dla systemu operacyjnego. Dane na jej temat zawiera rejestr GDTR,

- lokalna tablica deskryptorów LDT (Local Descriptor Table), jest tablicą specyficzną dla danego zadania, przy przełączaniu zadań następuje też przełączenie lokalnych tablic. Jej selektor zawiera rejestr LDTR,

- tablica deskryptorów przerwań IDT (Interrupt Descriptor Table), jest tablicą opisującą procedury obsługi przerwań i wyjątków, przy wystąpieniu przerwania procesor odczytuje dane z tej tablicy. Dane na jej temat zawiera rejestr IDTR.

        Deskryptory dzielimy na deskryptory segmentów i deskryptory bramek. Pierwsze opisują segmenty pamięci, drugie punkty wejścia do segmentów (deskryptory bramek opisane są szerzej w kolejnych tematach). Wyróżniamy trzy rodzaje deskryptorów segmentów.

0x08 graphic
deskryptor segmentu danych - opisuje obszary w których mogą być zapisywane i czytane dane (również stos):

0x08 graphic
deskryptor segmentu kodu - opisuje obszary gdzie znajduje się wykonywalny kod programów, mogą być z nich również czytane dane:

0x08 graphic
deskryptor segmentu systemowego - opisuje takie struktury jak lokalna tablica deskryptorów i segment stanu zadania:

        Oto opis pól wszystkich deskryptorów segmentów:

A - (Accessed) ustawiany gdy selektor segmentu jest ładowany do rejestru segmentowego,

W - (Writable) określa, czy może wystąpić operacja zapisu do segmentu danych,

R - (Readable) określa, czy może wystąpić operacja odczytu z segmentu kodu,

E - (Expand-down) określa kierunek ekspansji segmentu danych (używany do tworzenia segmentów stosu),

C - (Confirming) określa czy segment kodu jest dostępny na wszystkich poziomach uprzywilejowania,

P - (Segment Present) określa, czy segment jest obecny w pamięci,

AVL - (Available) bit dostępny dla programisty,

B - (Big) określa rozmiar segmentu (zwykle ustawiony, gdy bit G=1),

D - (Default) określa domyślny rozmiar adresów w obrębie segmentu (0 - adresy 16-bitowe, 1 - adresy 32-bitowe),

G - (Granularity) określa, czy limit segmentu jest wyrażony w bajtach (G=0), czy w 4k stronach (G=1),

DPL - (Descriptor Privillege Level) 2-bitowa wartość określająca poziom uprzywilejowania deskryptora.
        Adres bazowy jest 32-bitowym adresem liniowym wskazującym początek segmentu.
        Limit jest rozmiarem segmentu pomniejszonym o 1 (jeżeli bit G=1 rozmiar jest pomniejszony o 4kb). Jeżeli bit E jest wyzerowany poprawne adresy w obrębie segmentu są z zakresu 0 do LIMIT + 1, jeżeli jest ustawiony z zakresu MAKSYMALNY_ROZMIAR - (LIMIT + 1) do MAKSYMALNY_ROZMIAR (przydatne jest to w segmentach stosu, gdyż nie trzeba zmieniać wartości szczytu stosu przy każdej zmianie jego wielkości). MAKSYMALNY_ROZMIAR zależy od bitu G i może być równy 64k lub 4G.

        Typy segmentów systemowych przedstawiają poniższe wartości:

01H - wolny segment stanu TSS (dla procesora 286),

02H - lokalna tablica deskryptorów LDT,

03H - zajęty segment stanu TSS (dla procesora 286),

09H - wolny segment stanu TSS (dla procesora 386),

0BH - zajęty segment stanu TSS (dla procesora 386),

pozostałe wartości są zarezerwowane, lub wykorzystywane przez bramki.

        Dostęp do obszarów zdefiniowanych przez deskryptory jest realizowany poprzez selektory. Selektor wskazuje na konkretny deskryptor w tabeli GDT lub LDT, a jego wartość jest umieszczana w jednym z rejestrów segmentowych. Selektor ma następującą postać:

0x08 graphic

TI - (Table Indicator) oznacza rodzaj tabeli (0 -GDT, 1 - LDT),

RPL - (Requestor Privillege Level) określa poziom uprzywilejowania kodu który żąda dostępu.

        Numer deskryptora jest przemieszczeniem w tablicy podzielonym przez 8.

Model "flat"

        Niektóre środowiska systemowe nie współpracują z segmentową organizacją pamięci, a wszelkie wykorzystywane adresy są liniowe. Taki model pamięci nazywamy modelem "flat". Jest on dosyć prosty do zaimplementowania w trybie chronionym. Należy po prostu podczas inicjacji systemu zdefiniować segmenty o adresie bazowym 0 i limicie 4Gb (osobno segment kodu i osobno danych) po czym załadować rejestry segmentowe odpowiednimi selektorami. Model "flat" pozbawia nas jednak funkcjonalności mechanizmów ochrony pamięci.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

3.5.2. Ochrona pamięci

        Jednym z założeń trybu chronionego jest ochrona pamięci przed niepożądanym zapisem, odczytem i wykonywaniem kodu. Istnieją dwa poziomy ochrony pamięci: ochrona na poziomie segmentacji i ochrona na poziomie stronicowania. Drugi poziom występuje wyłącznie w przypadku włączonego mechanizmu stronicowania, inaczej jest ignorowany.

Ochrona na poziomie segmentacji

        Ochrona na tym poziomie obejmuje:
- sprawdzanie typów segmentów,
- sprawdzanie limitu,
- ograniczenie dostępu do segmentów,
- ograniczenie dostępu przestrzeni,
- ograniczenie wykonywania instrukcji.

        Sprawdzanie typów segmentów dotyczy praw zapisu/odczytu/uruchamiania. Ma ono znaczenie gdy na przykład selektor segmentu kodu jest ładowany do rejestru segmentowego CS. Niektóre rejestry segmentowe mogą przechowywać selektory tylko niektórych segmentów. Wyjątek 0Dh (General Protection Fault) jest generowany podczas wykonania złej operacji na danym segmencie.

        Sprawdzanie limitu występuje podczas realizowania dostępu do komórki pamięci. Jeżeli podane przemieszczenie wykracza ponad limit segmentu generowany jest wyjątek 0DH.

        Ograniczenie dostępu do segmentów jest realizowane poprzez poziomy uprzywilejowania. Poziom uprzywilejowania to dwubitowa wartość, przy czym najwyższy poziom to 0, a najniższy 3. Są one przechowywane w polach CPL (Current Privillege Level), RPL (Requestor Privillege Level) i DPL (Descriptor Privillege Level). CPL jest aktualnym poziomem uprzywilejowania znajdującym się w selektorze wykonywanego kodu, RPL znajduje się w selektorze odwołującym się do danego segmentu a DPL w dekryptorze tego segmentu. Procesor bierze pod uwagę wszystkie te pola i jeżeli stwierdzi że dany kod nie ma dostępu do segmentu, generuje wyjątek 0DH. Dany kod ma dostęp do segmentów danych na tym samym lub niższym poziomie, lecz może wykonywać skoki tylko do segmentów kodu na tym samym poziomie. Nie dotyczy to zgodnych segmentów kodu (bit C w deskryptorze segmentu kodu). Aby umożliwić wykonywanie kodu na innym poziomie stworzone zostały bramki. Bramki definiują punkt wejścia do segmentów kodu. Na ich potrzeby stworzone zostały specjalne deskryptory bramek. Wyróżniamy cztery typy bramek:

- bramki wywołania,

- bramki pułapek,

- bramki przerwań,

- bramki zadań.

Bramki zadań omówione są przy zagadnieniu wielozadaniowości, a bramki pułapek i przerwań przy przerwaniach i wyjątkach.

0x08 graphic
Deskryptory bramek wywołania mogą być umieszczone w tablicach GDT i LDT. Program na poziomie uprzywilejowania większym lub równym poziomowi bramki może za pomocą instrukcji CALL przenieść wykonywanie programu do segmentu innego poziomu (wykorzystywany jest do tego tylko selektor bramki, przemieszczenie jest pomijane). Poniżej ukazany jest deskryptor bramki wywołania:

P - (Present) bit obecności segmentu do którego odwołuje się bramka,

DPL - (Descriptor Privillege Level) określa, najniższy poziom uprzywilejowania jaki musi mieć kod aby wykonać skok przez bramkę.

        Selektor musi wskazywać segment do którego ma nastąpić skok, a przemieszczenie jest adresem relatywnym w obrębie tego segmentu. Deskryptor zawiera też liczbę słów jaka ma być skopiowana ze stosu (każdy poziom uprzywilejowania ma oddzielny stos).

        Ograniczenie dostępu do przestrzeni wejścia/wyjścia jest realizowane przez wartość IOPL (Input/Output Privillege Level) w rejestrze flag oraz przez mapy portów w segmentach stanu zadań. Pole IOPL to określa jaki najniższy poziom uprzywilejowania może mieć kod, aby wykonać operację wejścia/wyjścia. Mapy bitów w segmentach TSS określają dokładnie które z portów może używać zadanie (jedynka zabrania użycia portu). Mapy te sprawdzane są tylko w przypadku, gdy zadanie ma niższy priorytet niż określa IOPL. W wypadku wystąpienia niepożądanego dostępu do przestrzeni we/wy procesor generuje wyjątek 0DH.

        Ograniczenie wykonywania instrukcji dotyczy tylko instrukcji uprzywilejowanych. W wypadku użycia ich na poziomie niższym niż 0 generowany jest wyjątek 0DH. Do instrukcji uprzywilejowanych zaliczamy:

- CLTS - wyzerowanie bitu przełączenia zadania TS w rejestrze EFLAGS,

- HLT - zatrzymanie pracy procesora do momentu wystąpienia przerwania,

- LGDT, LIDT, LLDT - załadowanie rejestrów tablic systemowych,

- LMSW - załadowanie słowa stanu procesora,

- LTR - załadowanie rejestru zadania,

- MOV do/z CRn, DRn, TRn - załadowanie, lub odczytanie rejestrów kontrolnych, uruchomieniowych i testowych.

Ochrona na poziomie stronicowania

        Ochrona na tym poziomie obejmuje:
- ograniczenie dostępu do stron,
- sprawdzanie typów stron.

 

       Ograniczenie dostępu do stron jest związane z bitem U/S wpisu w tablicy stron. Określa on dwa poziomy dostępu do stron: supervisor (poziom uprzywilejowania 0-2) i user (poziom uprzywilejowania 3). Jeżeli kod żądający dostępu do strony jest na prawach suprvisor, może on dowolnie odczytywać, lub zapisywać stronę (pomijany jest bit R/W).

        Sprawdzanie typów stron dotyczy praw zapisu/odczytu (bit R/W wpisu w tablicy stron). Jeżeli nieodpowiednia operacja jest wykonana na stronie, generowany jest wyjątek.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

3.5.3. Wielozadaniowość

        Tryb chroniony umożliwia nam zaimplementowanie mechanizmu wielozadaniowości poprzez wprowadzenie specjalnych segmentów stanu zadania TSS (Task State Segment). Selektor aktualnie wykonywanego zadania jest umieszczony w rejestrze zadania TR (Task Register). System operacyjny dokonuje przełączania zadań gdy wystąpi przerwanie zegarowe, lub gdy otrzyma od zadania sygnał bezczynności (IDLE). Mechanizm wielozadaniowości jest ściśle powiązany z bitem NT rejestru EFLAGS i bitem TS rejestru CR0. Pierwszy z nich oznacza zagnieżdżone zadanie tzn. ustawinay jest gdy jedno zadanie zostało przerwane przez drugie (zapobiega to zapętleniu się zadań). Drugi z bitów ustawiany jest gdy wystąpiła operacja przełączania zadań.

        Rejestr TSS przechowuje wszelkie dane dotyczące zadania, włączając adres katalogu stron (każde zadanie może mieć inne odwzorowanie adresów liniowych w fizyczne), selektor tablicy LDT oraz mapę dostępnych portów. Rozmiar segmentu TSS wynosi minimum 104 bajty, lecz może być większy w zależności od wielkości mapy portów i danych przechowywanych przez system. Postać segmentu TSS przedstawia rysunek:

0x08 graphic

T - (Trap) oznacza, czy ma być wygenerowany wyjątek 01H (Debug exceptions) przy przełączaniu do danego zadania.

        Oprócz rejestrów segment TSS zawiera selektor poprzedniego segmentu stanu (uzupełniany przez procesor w wypadku przerwania działania poprzedniego zadania), oraz przemieszczenie wskazujące na mapę portów. Mapa ta jest strukturą w której jeden bit oznacza jeden z 65536 portów (jedynka oznacza blokadę). Mapa portów nie musi uwzględniać ich wszystkich, tylko pewną ilość numerowaną kolejno od 0 do n.

        Segment TSS ma swój specjalny deskryptor, które może występować jedynie w tablicy GDT. Nie może on służyć do modyfikowania zawartości segmentu (w tym celu należy stworzyć tożsamy segment danych). W procesorach 80386 ma on następującą postać:

0x08 graphic

B - (Busy) oznacza, czy zadanie jest aktualnie wykonywane (ustawiany i zerowany przez procesor).
        Pozostałe bity mają takie samo znaczenie jak w innych deskryptorach.

        Na potrzeby wielozadaniowości stworzona została też specjalna bramka zwana bramką zadania. Można ją umieszczać we wszystkich tablicach systemowych. Pozwala ona programom nie mającym dostępu do rejestru TR na zmianę zadania. Deskryptor bramki zadania wygląda następująco:

0x08 graphic

        Selektor wskazuje na segment stanu zadania. Pozostałe bity jak w przypadku bramki wywołania.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

3.5.4. Przerwania i wyjątki

        W trybie chronionym istnieje tablica IDT (Interrupt Descriptor Table) opisująca wszystkie 256 przerwań procesora. Deskryptorami tej tablicy mogą być bramki zadań, bramki pułapek i bramki przerwań. Deskryptor bramki przerwania wygląda następująco:

0x08 graphic

        A oto jak wygląda deskryptor bramki pułapki:

0x08 graphic

        Wszystkie bity mają takie samo znaczenie jak w przypadku bramki wywołania.

        Bramki przerwań i pułapek mają bardzo podobne znaczenie. Wykonują one skok pod zadany adres (wykonywane są w kontekście zadania w którym wystąpiły), zapisują na stosie rejestr EFLAGS i zerują bit TF (aby uniemożliwić krokowe śledzenie procedury obsługi). Różnica pomiędzy nimi polega na tym, że bramka przerwania zeruje dodatkowo bit IF (wyłącza przerwania). Powrót w obydwu przypadkach powinien być realizowany instrukcją IRET.

Wyjątki

        Wyjątki są zestawem przerwań numerowanych od 00H do 1FH. Zarezerwowane są one dla procesora i generowane są w przypadku szczególnych zdarzeń związanych z jego pracą. Wyjątki w odróżnieniu od pozostałych przerwań nie mogą być maskowane instrukcją CLI. Dzielą się one na:

- niepowodzenia, generowane przed wykonaniem instrukcji, umożliwiają powrót i ponowne jej wykonanie,

- pułapki, generowane po wykonaniu oczekiwanej instrukcji,

- załamania, generowane np. po wykryciu błędu w tablicach systemowych, umożliwiają lokalizację instrukcji jak również ponowne załadowanie programu którego działanie spowodowało wyjątek.

        Oto lista wyjątków procesora 80386 wraz z krótkim opisem:

numer

nazwa

opis wyjątku

00H

Divide error

Dzielenie przez zero

01H

Debug exceptions

Wyjątek generowany przez pułapki

02H

Nonmaskable interrupt

Przerwanie niemaskowalne (NMI)

03H

Breakpoint

Pułapka (INT 3)

04H

Overflow

Nadmiar (INTO)

05H

Bounds check

Sprawdzenie limitu (BOUND)

06H

Invalid opcode

Nieprawidłowa instrukcja

07H

Coprocessor not availabe

Koprocesor nieobecny

08H

Double fault

Niepowodzenie wykonania procedury wyjątku

09H

(reserved)

Zarezerwowane

0AH

Invalid TSS

Błędny segment stanu zadania

0BH

Segment not present

Nieobecność segmentu w pamięci

0CH

Stack exception

Przekroczenie limitu stosu

0DH

General protection fault

Błąd naruszający mechanizm ochrony

0DH

Page fault

Wyjątek generowany przez mechanizm stronicowania

0FH

(reserved)

Zarezerwowane

10H

Coprocessor error

Błąd koprocesora

11H-1FH

(reserved)

Zarezerwowane

        Ze względu na to iż podstawowy układ przerwań sprzętowych PIC (Programable Interrupt Controler) ma standardowe wektory w obszarze przerwań 08H-0FH (zarezerwowanych dla wyjątków procesora), należy go przeprogramować przed przełączeniem do trybu chronionego, w celu uniknięcia konfliktów.

0x08 graphic

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

3.6. Tryb V86

        Tryb V86 (Virtual 8086 machine) jest możliwy do zrealizowania przez połączenie trybu rzeczywistego, trybu chronionego i stronicowania pamięci. Specjalizowany program (może być to system operacyjny) pracuje w trybie chronionym z którego rozporządza zadaniami wykonującymi się w trybie rzeczywistym. Dzięki stronicowaniu, może on udostępniać programom trybu rzeczywistego pamięć rozszerzoną przez podczepianie jej w obszar 1Mb. Należy zatem pamiętać, i uwzględniać w przekazywaniu adresów do urządzeń, że w przypadku trybu V86 adresy logiczne zamieniane są na adresy liniowe, a te dopiero przez mechanizm stronicowania na adresy fizyczne. Program może sprawdzać czy pracuje w trybie rzeczywistym czy V86, przez kontrolę bitu VM w rejestrze EFLAGS.

        Zalety trybu V86 wykorzystują wszelkie sterowniki pamięci EMS, jak również wielozadaniowe systemy operacyjne (np. Windows), które emulują środowisko systemu DOS.

4. Pamięć bazowa

        Korzenie komputerów klasy PC sięgają czasów, kiedy 640kb pamięci operacyjnej wydawało się być w zupełności wystarczające i to na długie lata. Stąd też wynika architektura ówczesnych maszyn (komputery klasy XT), których rejestry pozwalały zaadresować maksymalnie do 1Mb pamięci. Aby załatać tę lukę w rozwoju komputerów, wprowadzono tryb chroniony pozwalający w modelach AT zaadresować do 16Mb, a w 386 i wyższych do 4Gb pamięci. System DOS pracujący w trybie rzeczywistym nie potrafi obsłużyć dodatkowej pamięci, dlatego też powstały liczne rozszerzenia udostępniające pamięć rozszerzoną (ponad 1 Mb) dla programów dosowych. Stąd też w przypadku DOSu pamięć dzielimy na bazową (base memory) i rozszerzoną (extended memory). Niniejszy rozdział traktuje o pierwszej z nich.

4.1. Pamięć konwencjonalna

        Pamięć konwencjonalna (conventional memory) jest to pamięć o wielkości 640kb. Powstała ona przy tworzeniu pierwszych modeli komputera PC jako cała dostępna adresowalna pamięć, stąd wynika jej odrębność od pozostałych obszarów. Istotnymi elementami pamięci konwencjonalnej jest tablica wektorów przerwań oraz obszar zmiennych BIOS-u. Poza nimi znajdują się w niej procedury systemowe, programy rezydentne, oraz aktualnie wykonywany program. Obecnie, ze względu na niewielki obszar tej pamięci dąży się do jak największego udostępnienia jej programom poprzez ładowanie rezydentów i procedur systemowych do pamięci górnej i podwyższonej.

        Do zarządzania pamięcią konwencjonalną służą nam funkcje 48H-4AH i 58H przerwania 21H. W szczególnych przypadkach funkcje te mogą obsługiwać również bloki pamięci górnej.

INT 21H, AH=48H, Przydzielenie bloku pamięci
Wejście:
    BX = rozmiar bloku w paragrafach
Wyjście jeżeli CF=0:
    AX:0000 = adres przydzielonego bloku
Wyjście jeżeli CF=1:
    AX = kod błędu
    BX = rozmiar największego wolnego bloku

INT 21H, AH=49H, Zwolnienie bloku pamięci
Wejście:
    ES = segment przydzielonego bloku
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    AX = kod błędu

INT 21H, AH=49H, Zmiana rozmiaru bloku pamięci
Wejście:
    ES = segment przydzielonego bloku
    BX = nowy rozmiar bloku w paragrafach
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    AX = kod błędu
    BX = największy możliwy rozmiar bloku

INT 21H, AX=5800H, Pobranie strategii alokacji pamięci
Wejście:
    Nie ma
Wyjście:
    CF = 0
    AX = kod strategii alokacji pamięci

INT 21H, AX=5801H, Ustalenie strategii alokacji pamięci
Wejście:
    BX = kod strategii alokacji pamięci
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    AX = kod błędu

        A oto jak wygląda kod strategii alokacji pamięci:

Bity 0-1:
    00 = alokacja w obszarze najniższym
    01 = alokacja w obszarze najlepiej pasującym
    10 = alokacja w obszarze najwyższym
Bity 6-7:
    00 = alokacja wyłącznie pamięci konwencjonalnej
    01 = alokacja wyłącznie pamięci górnej
    10 = alokacja pamięci górnej i konwencjonalnej
Reszta bitów równa 0

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

pre {font-family: Courier}

4.1.1. Tablica wektorów przerwań

        Tablica wektorów wszystkich 256 przerwań znajduje się pod adresem zerowym i zajmuje obszar 1kb, gdyż każdy wektor mieści się w 4 bajtach (2 na segment i 2 na przemieszczenie). Podczas każdego wywołania przerwania procesor odkłada na stos rejestr flagowy, oraz rejestry CS i IP (aktualną pozycję wykonywanego programu). Następnie oblicza pozycję w tablicy wektorów (numer przerwania * 4) i wykonuje daleki skok pod otrzymany adres. W trybie chronionym tablica wektorów przerwań zastąpiona została przez tablicę deskryptorów przerwań, która może znajdować się gdziekolwiek w pamięci. Jej adres umieszczony jest w rejestrze IDTR (Interrupt Descriptor Table Register).

        Podmianę wektora możemy zrealizować poprzez funkcje DOSu, lub też ręcznie przez bezpośredni dostęp do tablicy wektorów (przy drugim sposobie należy koniecznie pamiętać o wyłączeniu przerwań na czas podmiany). Oto funkcje 35H i 25H przerwania 21H, które zajmują się obsługą wektorów:

INT 21H, AH=35H, Pobranie wektora przerwania
Wejście:
    AL = numer wektora przerwań
Wyjście:
    ES:BX = adres procedury obsługi przerwania

INT 21H, AH=25H, Ustawienie wektora przerwania
Wejście:
    AL = numer wektora przerwań
    DS:DX = adres procedury obsługi przerwania
Wyjście:
    Nie ma

        Poniższy fragment kodu obrazuje jak podmienić wektor bez informowania systemu, a następnie przywrócić poprzedni:

;nowy wektor znajduje się w rejestrach AX:DX

;w BX znajduje się numer przerwania

.CODE

;podmiana wektora

SHL BX,2

MOV ES,0

CLI

XCHG DX,[ES:BX]

XCHG AX,[ES:BX+2]

STI

MOV [STARY],DX

MOV [STARY+2],AX

;przywrócenie wektora

MOV DX,[STARY]

MOV AX,[STARY+2]

CLI

MOV [ES:BX],DX

MOV [ES:BX+2],AX

STI

.DATA

;miejsce na stary wektor

STARY DW ?,?

        Oto lista wszystkich przerwań wraz z przemieszczeniem w tablicy wektorów.

numer

offset

opis przerwania

Przerwania BIOSu

0H

0000H

Dzielenie przez zero

1H

0004H

Praca krokowa

2H

0008H

Przerwanie niemaskowalne (NMI)

3H

000CH

Pułapka

4H

0010H

Nadmiar

5H

0014H

Drukowanie ekranu

6H-7H

0018H

Zarezerwowane

8H

0020H

IRQ 0 - Przerwanie zegarowe

9H

0024H

IRQ 1 - Przerwanie klawiatury

0AH

0028H

IRQ 2 - Zarezerwowane

0BH

002CH

IRQ 3 - Przerwanie łącza szeregowego (COM2)

0CH

0030H

IRQ 4 - Przerwanie łącza szeregowego (COM1)

0DH

0034H

IRQ 5 - Przerwanie drukarki (LPT2)

0EH

0038H

IRQ 6 - Przerwanie sterownika dyskietek

0FH

003CH

IRQ 7 - Przerwanie drukarki (LPT1)

10H

0040H

Obsługa karty graficznej

11H

0044H

Odczyt konfiguracji systemu

12H

0048H

Odczyt wielkości pamięci konwencjonalnej

13H

004CH

Obsługa dysków

14H

0050H

Obsługa portu szeregowego

15H

0054H

Różnorodne funkcje

16H

0058H

Obsługa klawiatury

17H

005CH

Obsługa drukarki

18H

0060H

Wywołanie programu konfiguracyjnego BIOSu.

19H

0064H

Uruchomienie bootstrap

1AH

0068H

Obsługa zegara

1BH

006CH

Obsługa klawisza CTRL-BREAK

1CH

0070H

Obsługa przerwania zegara czasu rzeczywistego

1DH

0074H

Parametry sterownika graficznego ekranu 6845

1EH

0078H

Parametry napędu dyskietek

1FH

007CH

Wskaźnik do rozszerzonych znaków ASCII

Przerwania DOSu

20H

0080H

Zakończenie programu

21H

0084H

Uniwersalne funkcje systemowe

22H

0088H

Adres zakończenia programu (procesu)

23H

008CH

Obsługa przerwania wykonywania programu

24H

0090H

Obsługa błędów krytycznych

25H

0094H

Odczyt sektorów logicznych dysku

26H

0098H

Zapis sektorów logicznych dysku

27H

009CH

Zakończenie programu z pozostawieniem w pamięci

28H

00A0H

Praca w tle

29H

00A4H

Szybkie wysłanie pojedynczego znaku

2AH

00A8H

Nieudokumentowane

2BH-2DH

00ACH

Zarezerwowane

2EH

00B8H

Nieudokumentowane

2FH

00BCH

Funkcje XMS i inne

30H

00C0H

CP/M JMP Command

31H

00C4H

Funkcje DPMI

32H

00C8H

Zarezerwowane

33H

00CCH

Obsługa myszy

34H-3FH

00D0H

Zarezerwowane

40H

0100H

Opis dyskietki

41H

0104H

Opis dysku twardego nr 1

42H

0108H

Przerwanie karty EGA/VGA

43H

010CH

Wskaźniki parametrów inicjujących

44H

0110H

Zarezerwowane dla Novell NetWare

45H

0114H

Zarezerwowane

46H

0118H

Opis dysku twardego nr 2

47H-5FH

011CH

Zarezerwowane

60H-63H

0180H

Zarezerwowane dla użytkownika

64H

0190H

Zarezerwowane dla Novell NetWare

65H-66H

0194H

Zarezerwowane dla użytkownika

67H

019CH

Funkcje VCPI

68H-6CH

01A0H

Zarezerwowane

6DH

01B4H

Zarezerwowane dla karty VGA

6EH-6FH

01B8H

Zarezerwowane

70H

01C0H

IRQ 8 - Przerwanie zegara czasu rzeczywistego

71H-74H

01C4H

IRQ 9 - IRQ 12 - Zarezerwowane dla dodatkowych urządzeń

75H

01D4H

IRQ 13 - Przerwanie koprocesora

76H

01D8H

IRQ 14 - Przerwanie sterownika dysków twardych

77H

01DCH

IRQ 15 - Zarezerwowane dla dodatkowych urządzeń

78H-7FH

01E0H

Zarezerwowane

80H-85H

0200H

Zarezerwowane dla BASICa

86H-F0H

0218H

Przerwania używane przez BASIC

F1H-FDH

0384H

Zarezerwowane dla użytkownika

FEH-FFH

03F8H

Zarezerwowane

4.1.2. Zmienne BIOSu

        Zmienne BIOSu są obszarem pamięci o wielkości 256 bajtów i zaczynają się od adresu fizycznego 0400H (adres logiczny 0040H:0000H). Zmienne te można odczytywać i modyfikować, należy jednak zauważyć że niektóre z nich zmieniane są przez przerwania obsługiwane przez BIOS.

        Poniżej znajduje się lista wszystkich zmiennych BIOSu wraz z przemieszczeniem od adresu 0400H.

offset

opis zmiennej

0000H

Adresy we/wy COM1-COM4

0008H

Adresy we/wy LPT1-LPT4

0010H

Słowo konfiguracji systemu

0012H

Bajt zarezerwowany dla inicjacji komputera

0013H

Słowo określające wielkość pamięci RAM w kb

0015H

Bajt zarezerwowany przy testowaniu komputera

0016H

Bajt kodów błędów wykrytych podczas inicjacji komputera

0017H

Słowo stanu klawiatury

0019H

Zmienna używana przy wpisywaniu kodu z klawiatury numerycznej i klawisza ALT

001AH

Początek bufora klawiatury

001CH

Koniec bufora klawiatury

001EH

32 bajtowy bufor klawiatury

003EH

Bajt rekalibracji dysku miękkiego

003FH

Bajt stanu silników napędów dyskowych

0040H

Licznik czasu włączenia silnika

0041H

Bajt stanu dyskietki

0042H

Siedem bajtów sterownika dyskietki

0049H

Bieżący tryb pracy sterownika ekranu

004AH

Liczba kolumn na ekranie

004CH

Wielkość pamięci obrazu w bajtach

004EH

Adres początku obrazu w pamięci obrazu

0050H

Położenie kursora na każdej stronie (od 1-8)

0060H

Typ kursora

0062H

Bieżący numer wyświetlanej strony

0063H

Adres portu (rejestru indeksowego) układu 6845 sterownika wideo

0065H

Bieżący tryb pracy sterownika wideo

0066H

Numer wybranej palety (CGA)

0067H

Słowo zawierające adres ponownego wejścia w tryb rzeczywisty

006BH

Ostatnie nieoczekiwane przerwanie

006CH

Cztery bajty licznika zegara

0070H

Przepełnienie zegara (upłynęło 24 godz. od ostatniego odczytu zegara)

0071H

Flaga naciśnięcia klawiszy zatrzymania (bit 7)

0072H

Słowo wpisywane po resecie poprzez naciśnięcie CTRL-ALT-DEL

0074H

Stan sterownika dysku twardego

0075H

Liczba dysków twardych

0076H

Słowo zarezerwowane

0078H

Cztery bajty przeterminowania łączy szeregowych (LPT1-LPT4)

007CH

Cztery bajty przeterminowania łączy równoległych (COM1-COM4)

0080H

Wartość początku przemieszczenia bufora klawiatury

0082H

Wartość końca przemieszczenia klawiatury

0084H

Liczba wierszy (EGA)

0085H

Wartość znaku (EGA)

0087H

Bajt kontrolny (EGA)

0088H

Stan przełączników (EGA)

0089H

Bajt trybu kontrolnego (VGA)

008AH

Indeks tablicy kodu wyświetlania (VGA)

008BH

Identyfikator nośnika dysków miękkich

008CH

Stan kontrolera dysku twardego

008DH

Status błędu dysku twardego

008EH

Przerwanie kontrolne dysku twardego

008FH

Bajt informacyjny kontrolera dysków miękkich

0090H

Stan (nośnika) - dyskietki nr 0

0091H

Stan (nośnika) - dyskietki nr 1

0092H

Znacznik rozpoczęcia operacji na dyskietce 0

0093H

Znacznik rozpoczęcia operacji na dyskietce 1

0094H

Bieżący numer ścieżki dyskietki nr 0

0095H

Bieżący numer ścieżki dyskietki nr 0

0096H

Znacznik typu klawiatury

0097H

Znacznik diod LED na klawiaturze

0098H

Wskaźniki dotyczące zegara

00A1H

7 bajtów zarezerwowanych

00A8H

Wskaźnik do tablicy parametrów (EGA, VGA)

00ACH

34 bajty zarezerwowane

00CEH

Znacznik związany z bootowaniem systemu

00D0H

32 bajty zarezerwowane

00F0H

16 bajtów zarezerwowanych dla użytkownika

0100H

Status drukowania ekranu

0101H

13 bajtów zarezerwowanych

010EH

18 bajtów zarezerwowanych dla BASICa

0x08 graphic

4.2. Pamięć górna

        Pamięć górna UMA (Upper Memory Area) obejmuje obszar od adresu A0000h do FFFFFh, czyli uzupełnienie pamięci konwencjonalnej do 1Mb. W przestrzeni tej znajduje się pamięć wideo, obszary BIOSu, oraz bloki pamięci górnej. Zazwyczaj znajduje się tam także ramka pamięci EMS.

        Alokację pamięci górnej możemy zrealizować na dwa sposoby, za pomocą funkcji XMS lub DOSu. W drugim przypadku alokacja wygląda identycznie jak w przypadku pamięci konwencjonalnej (funkcje 48H-4AH i 58H). Przydatne też mogą być dwie niżej opisane podfunkcje funkcji 58H. Pierwsza z nich określa czy pamięć górna wchodzi w skład obszarów przeznaczonych do alokacji. Nie oznacza to jednak, czy pamięć górna jest dostępna dla DOSu czy nie. Możemy się tego dowiedzieć przy pomocy drugiej funkcji. W tym celu trzeba nakazać podłączenie pamięci górnej i jeżeli wystąpi błąd o numerze 01 oznacza to że pamięć ta nie jest dostępna dla DOSu.

INT 21H, AX=5802H, Pobranie podłączenia pamięci górnej
Wejście:
    Nie ma
Wyjście:
    CF = 0
    AL = 0 - pamięć górna nie podłączona
    AL = 1 - pamięć górna podłączona

INT 21H, AX=5803H, Ustalenie podłączenia pamięci górnej
Wejście:
    BX = 0 - odłączenie
    BX = 1 - podłączenie
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    AX = kod błędu

        W przypadku gdy pamięcią górną zarządzamy przez interfejs XMS, wykorzystujemy funkcje 10H i 11H. Więcej informacji o wywoływaniu funkcji XMS w kolejnym rozdziale.

AH=10H, Przydzielenie bloku pamięci górnej
Wejście:
    DX = rozmiar bloku w paragrafach
Wyjście jeżeli AX=1:
    BX = adres segmentowy bloku
    DX = rozmiar bloku w paragrafach
Wyjście jeżeli AX=0:
    BL = kod błędu

AH=11H, Zwolnienie bloku pamięci górnej
Wejście:
    DX = adres segmentowy bloku
Wyjście jeżeli AX=1:
    Nie ma
Wyjście jeżeli AX=0:
    BL = kod błędu

4.2.1. Pamięć wideo

        Pamięć wideo (video RAM), lub inaczej pamięć obrazu jest to obszar o wielkości dwóch segmentów począwszy od adresu A0000h który podpięty jest bezpośrednio do pamięci wewnętrznej karty. Rozwiązanie to jest bardzo korzystne, gdyż umożliwia swobodny zapis wprost do karty, szczególnie w trybach 256 kolorowych, gdzie organizacja pamięci jest spakowana i każdy bajt reprezentuje jeden piksel obrazu. Sytuacja komplikuje się w trybach o organizacji płatowej, gdyż konieczne jest dodatkowe programowanie karty przez porty.

        Różne karty w różny sposób podpinają się pod dostępny obszar i tak karta CGA wykorzystuje przestrzeń począwszy od adresu B8000h, karty MDA i Hercules od B0000h, a karty EGA i VGA od A0000h. Nowoczesne karty SVGA, które posiadają dużą pamięć wewnętrzną, wykorzystują obszar video RAM jako ramkę która w danej chwili odzwierciedla tylko pewien fragment pamięci wewnętrznej. Programy pracujące w trybie chronionym mogą zamiennie wykorzystać linear framebuffer czyli ramkę umieszczoną gdziekolwiek w czterogigowej przestrzeni adresowej. Ramka ta jest ciągłym blokiem obrazującym całą pamięć wewnętrzną karty.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

4.2.2. Obszary BIOSu

        Ponieważ pierwsze modele XT wyposażone były co najwyżej w 640kb pamięci, a procesor mógł zaadresować 1Mb, niewykorzystany obszar przestrzeni adresowej przeznaczono na BIOS różnych urządzeń. Znajduje się on w kościach pamięci ROM, która podpinana jest w przestrzeń adresową procesora. BIOS (Basic Input/Output System) jest podstawowym ustandaryzowanym systemem komunikacji z urządzeniami zewnętrznymi. W każdym komputerze istnieją przynajmniej dwa BIOSy: płyty głównej (umieszczony pod adresem 0F0000H, o rozmiarze 64kb), oraz karty graficznej (umieszczony pod adresem 0C0000H, o rozmiarze 32kb). Pozostałe BIOSy mogą istnieć w przypadku zainstalowanego sprzętu, który takowe posiada.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

--></><basefont face="Times New Roman" size=3>

4.2.3. Shadow RAM

        Obszary BIOSu różnych urządzeń standardowo zapisane są w pamięci stałej ROM. Pamięć ta podpinana jest w odpowiednie miejsca przestrzeni adresowej, tak aby były one adresowalne z trybu rzeczywistego. Ponieważ obecnie w komputerach nie instaluje się pamięci poniżej 1Mb, korzystne stało się skopiowanie BIOSu urządzeń z pamięci ROM do RAM. Pamięć RAM jest o wiele szybsza, przez co zyskujemy szybszy dostęp do procedur BIOSu. Obszary, które mają być skopiowane ustalamy z poziomu konfiguracji BIOSu (przy starcie komputera). Pamięć RAM pełni więc jakby funkcję cienia pamięci ROM, stąd pochodzi nazwa - shadow RAM.

4.2.4. Bloki pamięci górnej

        W pamięci górnej poza pamięcią wideo i obszarami BIOSu pozostają dziury, które nazwano blokami pamięci górnej, UMB (Upper Memory Block). Ponieważ bloków tych nie można posklejać, dlatego najlepiej nadają się one do przechowywania małych programów rezydentnych. Aby uzyskać dostęp do bloków UMB, w systemie musi być zainstalowany sterownik pamięci expanded (np. EMM386). Blokami pamięci górnej zarządzamy na dwa sposoby: wykorzystując interfejs XMS, lub poprzez standardowe funkcje DOSu. W drugim przypadku plik CONFIG.SYS musi zawierać linię DOS=UMB. Pozwala to nam także na ładowanie programów rezydentnych do pamięci górnej za pomocą poleceń LOADHIGH, INSTALLHIGH lub DEVICEHIGH.

0x08 graphic

4.3. Struktury DOSu

        Aby system mógł sprawnie rozporządzać zasobami, stworzone zostały pewne struktury danych. Do istotnych dla nas zaliczamy listę list (jako strukturę nadrzędną zawierającą zmienne systemowe i wskaźniki do innych struktur), bloki kontroli pamięci MCB oraz blok wstępny programu PSP.

4.3.1. Lista list

        Struktura listy list LL (List of List) zawiera część zmiennych systemowych oraz adresy innych istotnych struktur w DOSie. Wskaźnik do niej otrzymamy po wywołaniu funkcji 52H przerwania 21H. Struktura ta nie została nigdy do końca udokumentowana, a jej obecny wygląd ustalił się w wersji 4.0 systemu.

INT 21H, AH=52H, Pobranie adresu listy list
Wejście:
    Nie ma
Wyjście:
    ES:BX = adres listy list

        Poniższa tabela zawiera opis pól listy list wraz z przemieszczeniem od adresu zwracanego przez funkcję 52H:

offset

zawartość

-000CH

Licznik powtórzeń dzielonego dostępu

-000AH

Opóźnienie w dzielonym dostępie do plików

-0008H

Daleki wskaźnik do bieżącego bufora dyskowego

-0004H

Wskaźnik do bufora zawierającego nie odczytane znaki z konsoli

-0002H

Segment adresu nagłówka pierwszego bloku MCB

0000H

Daleki wskaźnik do pierwszego bloku parametrów dysku (DPB)

0004H

Daleki wskaźnik do systemowej tablicy plików (SFT)

0008H

Daleki wskaźnik do programu obsługi CLOCK$

000CH

Daleki wskaźnik do programu obsługi CON

0010H

Maksymalna długość bloku (w bajtach) dla urządzeń blokowych

0012H

Daleki wskaźnik do informacji o buforach dyskowych

0016H

Daleki wskaźnik do tablicy katalogów roboczych

001AH

Daleki wskaźnik do systemowych tablic opisów plików

001EH

Liczba bloków FCB chronionych przed usunięciem

0020H

Liczba urządzeń blokowych

0021H

Wartość LASTDRIVE

0022H

Nagłówek programu obsługi urządzenia NULL

0034H

Liczba dysków dołączonych poleceniem JOIN

0035H

Wskaźnik w segmencie kodu systemu do listy specjalnych nazw programów

0037H

Daleki wskaźnik do procedury z usługami pomocniczymi

003BH

Daleki wskaźnik do łańcucha programów obsługi instalowanych systemów plików (IFS)

003FH

Wartość pierwszego parametru w poleceniu BUFFERS

0041H

Wartość drugiego parametru w poleceniu BUFFERS

0043H

Dysk z którego załadowano system

0044H

Zarezerwowane

0046H

Rozmiar pamięci rozszerzonej w kb

4.3.2. Bloki kontroli pamięci

        Bloki kontroli pamięci MCB (Memory Control Block) opisują obszary pamięci bazowej tak, aby ułatwić rozporządzanie nimi. Każdorazowo po wystąpieniu żądania przydziału, zwolnienia lub zmiany bloku pamięci system zmienia MCB tzn. wyodrębnia bloki o pożądanej wielkości z większego bloku, łączy sąsiednie nieużywane bloki lub modyfikuje ich zawartość. Segment pierwszego bloku uzyskamy odczytując pole -02H listy list. Segmenty kolejnych bloków uzyskujemy wg wzoru: SEGMENT_KOLEJNEGO_MCB = SEGMENT_BIEŻĄCEGO_MCB + ROZMIAR_BIEŻĄCEGO_MCB + 10H.

        Blok MCB ma postać:

offset

Opis

0000H

typ bloku:
4DH ('M') - nie ostatni blok
5AH ('Z') - ostatni blok

0001H

Wskaźnik na PSP procesu zarządzającego danym blokiem (0 - blok bez właściciela)

0003H

Długość bloku w paragrafach

0005H

Zarezerwowane

0008H

Nazwa procesu który jest właścicielem bloku
'SC' - blok kodu systemu
'SD' - blok danych systemowych
0 - brak właściciela

0010H

Początek bloku pamięci

4.3.3. Blok danych systemowych

        Blok danych systemowych SD (System Data) jest pierwszym blokiem MCB (jego segment umieszczony jest w polu -02H listy list). Składa się on z podbloków tworzonych podczas interpretacji pliku CONFIG.SYS. Pojedynczy podblok wygląda następująco:

offset

opis

0000H

typ podbloku:
44H ('D') - DEVICE
46H ('F') - FILES
58H ('X') - FCBS
42H ('B') - BUFFERS
4CH ('L') - LASTDRIVE
53H ('S') - STACK

0001H

Segment bloku opisywanego przez nagłówek

0003H

Długość podbloku w paragrafach

0005H

Zarezerwowane

0008H

Dla typu 'D' nazwa programu obsługi urządzenia

4.3.4. Blok wstępny programu

        Od momentu uruchomienia programu, system wykonuje kilka ważnych czynności. Przydziela programowi największy wolny blok pamięci, umieszcza na jego początku blok wstępny programu PSP (Program Segment Prefix) i ładuje program do pamięci. Rejestr segmentowy ES zawiera wartość równą początkowi bloku pamięci. Tak więc blok MCB znajduje się pod adresem ES:-0010H, blok PSP pod adresem ES:0000H natomiast sam program pod adresem ES:0100 (CS:0000H). Rola PSP polega na przekazaniu programowi w najprostszy sposób szeregu przydatnych informacji. Szczególne walory bloku wstępnego dostrzec można gdy dany program uruchamia podprogramy (może on wtedy dowolnie kreować PSP).

        Adres bloku PSP możemy odczytywać i zapisywać za pomocą funkcji 50H, 51H i 62H przerwania 21H:

INT 21H, AH=50H, Ustawienie adresu bloku PSP
Wejście:
    BX = adres segmentowy nowego bloku PSP
Wyjście:
    CF = 0 - operacja powiodła się
    CF = 1 - operacja nie powiodła się

INT 21H, AH=51H lub 62H, Pobranie adresu bloku PSP
Wejście:
    Nie ma
Wyjście:
    BX = adres segmentowy bieżącego bloku PSP

        Poniższa tabela przedstawia zawartość bloku wstępnego programu:

offset

zawartość

0000H

Kod rozkazu INT 20H (zakończenie programu)

0002H

Segment końca pamięci dostępnej dla programu

0004H

Zarezerwowane

0005H

Dalekie wywołanie do systemu DOS

000AH

Adres zakończenia programu

000EH

Adres obsługi CTRL-BREAK

0012H

Adres programu obsługi błędów krytycznych

0016H

Adres segmentowy bloku PSP procesu nadrzędnego

0018H

Tablica plików procesów (JFT)

002CH

Adres segmentowy otoczenia programu

002EH

Rejestr SS przechowywany podczas wywołania funkcji systemowych

0030H

Rejestr SP przechowywany podczas wywołania funkcji systemowych

0032H

Ilość elementów tablicy plików procesu (JFT)

0034H

Adres tablicy plików procesu (JFT)

0038H

Zarezerwowane

0050H

Kody rozkazów odwołania do funkcji INT 21H

0053H

Zarezerwowane

005CH

Standardowy blok opisu pliku (FCB) #1

006CH

Standardowy blok opisu pliku (FCB) #2

0080H

Bufor transmisji dyskowych (DTA)

0x08 graphic

4.4. Ramka EMS

        Ramka EMS jest blokiem o rozmiarze jednego segmentu (64kb) i jest wykorzystywana gdy w systemie występuje pamięć expanded. Pamięć ta podzielona jest na 16-kilobajtowe strony logiczne umieszczone w pamięci rozszerzonej. Dostęp do nich w trybie rzeczywistym jest realizowany właśnie przez ramkę, zawierającą cztery strony fizyczne do których możemy podczepić dowolne strony logiczne. Ramka może znajdować się gdziekolwiek w pamięci bazowej, w zależności od konfiguracji sterownika EMS. Więcej informacji o pamięci EMS w kolejnym rozdziale.

5. Pamięć rozszerzona

        Pamięć rozszerzona już na tyle zadomowiła się w naszych komputerach, że prawdopodobnie nikt z nas nie ma do czynienia z maszyną w której by jej nie było. Dlatego większość obecnych systemów operacyjnych, pracujących w trybie chronionym nie ma problemów z zarządzaniem tą pamięcią, jednak taki system jak DOS, stworzony wyłącznie dla trybu rzeczywistego, nie "widzi" pamięci powyżej 1Mb. Dlatego też powstały liczne techniki alokacji i rozszerzenia udostępniające pamięć rozszerzoną. Programista staje więc przed wyborem schematu alokacji który mu najbardziej odpowiada, jednak nowoczesne programy powinny pracować w różnych konfiguracjach, dlatego dobrze by było gdyby dany program obsługiwał wszystkie dostępne schematy. Niniejszy rozdział ma za zadanie przybliżyć tą tematykę.

<><!--

body {font-family: Times New Roman}

p {font-family: Times New Roman}

td {font-family: Times New Roman}

pre {font-family: Courier}

--></><basefont face="Times New Roman" size=3>5.1. Linia adresowa A20

        Tryb rzeczywisty stworzony na pierwsze komputery PC zakładał, że użytkownik ma do dyspozycji jedynie 1 Mb pamięci operacyjnej. Do obsłużenia takiej ilości pamięci wystarczało 20 lini adresowych procesora (numerowanych od A0 do A19). Gdy w komputerach zaczęto instalować więcej pamięci powstał problem niekompatybilności, gdyż standardowo po wywołaniu adresu odwołującego się do pamięci powyżej 1 Mb starsze procesory "zawijały" adres, który wskazywał na zupełnie inny obszar pamięci. Dla przykładu adres FFFF:0010 konwertowany był w rzeczywistości do adresu zerowego. Wynikało to z tego iż adres taki zajmował 21 bitów, z których najstarszy był wystawiany na nieistniejącą linię adresową. Dlatego w komputerach, których procesory posiadają już więcej nóżek adresowych linia A20 jest standardowo wyłączana, aby adres był "zawijany" tak jak w starszych modelach. Programy korzystające z pamięci rozszerzonej mogą ją włączać i wyłączać poprzez port sterujący klawiatury lub za pomocą interfejsu XMS. Drugi ze sposobów jest wyjątkowo prosty i polega na wywołaniu, w zależności od potrzeb, jednej z funkcji od 03h do 07h, pierwszy natomiast, wymaga programowania portu 064h. Programy korzystające z A20 powinny w pierwszej kolejności upewnić się czy zainstalowany jest sterownik XMS i jeżeli tak to włączać i wyłączać linię A20 przez jego funkcje.

        Oto funkcje XMS sterujące stanem lini A20. Pamiętać zawsze należy aby po uprzednim odblokowaniu A20, przed zakończeniem programu ponownie ją zablokować. Istotny jest fakt, że sterownik XMS zlicza ilość odblokowań i zablokowań lini, tak więc jeżeli odblokujemy linię A20 np. dwukrotnie, a zablokujemy tylko raz, to w efekcie fizycznie pozostanie ona odblokowana. Funkcje 03H, 04H (przeznaczone dla programów obsługujących wyłącznie HMA) i 05H, 06H (dla programów mających dostęp do pamięci rozszerzonej) tworzą pary różniące się znacznie, dlatego np. przy odblokowaniu lini A20 funkcją 03H należy ją zablokować funkcją 04H.

AH=03H, Globalne odblokowanie lini A20
Wejście:
    Nie ma
Wyjście jeżeli AX=1:
    Nie ma
Wyjście jeżeli AX=0:
    BL = kod błędu

AH=04H, Globalne zablokowanie lini A20
Wejście:
    Nie ma
Wyjście jeżeli AX=1:
    Nie ma
Wyjście jeżeli AX=0:
    BL = kod błędu

AH=05H, Lokalne odblokowanie lini A20
Wejście:
    Nie ma
Wyjście jeżeli AX=1:
    Nie ma
Wyjście jeżeli AX=0:
    BL = kod błędu

AH=06H, Lokalne zablokowanie lini A20
Wejście:
    Nie ma
Wyjście jeżeli AX=1:
    Nie ma
Wyjście jeżeli AX=0:
    BL = kod błędu

AH=07H, Informacja o stanie fizycznym lini A20
Wejście:
    Nie ma
Wyjście jeżeli BL=0:
    AX = 1 - linia A20 odblokowana
    AX = 0 - linia A20 zablokowana
Wyjście jeżeli BL<>0:
    BL = kod błędu

        Oto jak należy sterować stanem lini A20, gdy w systemie nie ma sterownika XMS:

.CODE

;odblokowanie lini A20

MOV AL,0D1H

OUT 64H,AL

CALL KLAW_GOT

MOV AL,0DFH

OUT 60H,AL

CALL KLAW_GOT

MOV CX,800H

PETLA:

CALL SPR_A20

JE SHORT OK

CALL DELAY

LOOP PETLA

;nie można odblokować A20

;w tym miejscu obsługa błędu

OK:

;linia A20 odblokowana

;zablokowanie lini A20

MOV AL,0D1H

MOV 64H,AL

CALL KLAW_GOT

MOV AL,0DDH

OUT 60h,AL

CALL KLAW_GOT

;linia A20 zablokowana

;procedura opóźniająca wykorzystująca

;zegar czasu rzeczywistego

PROC DELAY NEAR

CALL READ_ZEG

MOV AH,AL

PETLA1:

CALL READ_ZEG

CMP AL,AH

JE SHORT PETLA1

RET

ENDP DELAY

;sprawdzenie stanu zegara

PROC READ_ZEG NEAR

IN AL,40H

JMP SHORT $+2

JMP SHORT $+2

JMP SHORT $+2

IN AL,40H

RET

ENDP READ_ZEG

;sprawdzenie zawijania adresu powyżej 1Mb

PROC SPR_A20 NEAR

XOR AX,AX

MOV FS,AX

DEC AX

MOV GS,AX

CLI

MOV AL,[FS:0]

MOV AH,AL

NOT AL

XCHG [GS:10H],AL

CMP AH,[FS:0]

MOV [GS:10h],AL

STI

RET

ENDP SPR_A20

;sprawdzenie czy port danych klawiatury gotowy

PROC KLAW_GOT NEAR

MOV CX,800H

PETLA2:

CALL DELAY

IN AL,64H

TEST AL,2

LOOPNE PETLA2

RET

ENDP KLAW_GOT

0x08 graphic

--></><basefont face="Times New Roman" size=3>5.2. Pamięć wysoka

        Pamięć wysoka HMA (High Memory Area) jest specyficznym obszarem, ponieważ należy on do pamięci rozszerzonej, lecz może być adresowany z trybu rzeczywistego. Wynika to z architektury samego procesora. Zauważmy że największy możliwy adres logiczny 0FFFFH:0FFFFH zapiszemy jako adres fizyczny 10FFEFH czyli leżący poza 1Mb. Tak więc w trybie rzeczywistym mamy dodatkowy blok pamięci o rozmiarze 65520 bajtów począwszy od adresu fizycznego 100000H. Blok ten obsługiwany jest przez interfejs XMS za pomocą funkcji 01H i 02H. W przypadku braku sterownika XMS, możemy sami pokusić się o zagospodarowanie HMA wykorzystując schemat alokacji BOTTOM-UP. Należy pamiętać że przy dostępie do HMA linia A20 musi być odblokowana. W przeciwnym wypadku zamazana zostanie tablica wektorów przerwań leżąca na początku pamięci bazowej, co nieuchronnie doprowadzi do zawieszenia komputera.

        Korzystanie z pamięci wysokiej niesie ze sobą kilka ograniczeń. Adresy z jej obszaru nie powinny być wektorami przerwań. Nie powinny być również przekazywane do żadnej z funkcji DOSu. Program korzystający z obszaru HMA, powinien wykorzystać go maksymalnie, gdyż sterownik XMS udostępnia go tylko jednemu programowi. Stosuje on selekcję i nie przydziela HMA programowi który zażąda bloku o rozmiarze mniejszym niż jest określony parametrem HMAMIN.

        Należy zauważyć że system DOS pomimo braku obsługi pamięci wysokiej może ją wykorzystać, zwalniając przy tym część pamięci bazowej. Obsługę HMA przez DOS realizujemy wpisując linię DOS=HIGH w pliku CONFIG.SYS.

        Poniższe funkcje XMS sterują przydziałem pamięci HMA:

AH=01H, Alokacja obszaru HMA
Wejście:
    DX = rozmiar wymaganego obszaru HMA
Wyjście jeżeli AX=1:
    Nie ma
Wyjście jeżeli AX=0:
    BL = kod błędu

AH=02H, Dealokacja obszaru HMA
Wejście:
    Nie ma
Wyjście jeżeli AX=1:
    Nie ma
Wyjście jeżeli AX=0:
    BL = kod błędu

0x08 graphic

--></><basefont face="Times New Roman" size=3>

5.3. Pamięć EMS

        Pamięć EMS (Expanded Memory Specification) zwana krótko pamięcią expanded, jest zagadnieniem z pogranicza pamięci bazowej i rozszerzonej. Polega ona na umieszczeniu stron logicznych (wielkości 16kb) w pamięci rozszerzonej, do których dostęp realizowany jest przez strony fizyczne tworzące ramkę EMS i znajdujące się w pamięci bazowej. Gdy zachodzi potrzeba, odpowiednie strony logiczne podczepiane są do stron fizycznych. Mechanizm ten implementowany jest na kilka sposobów: sprzętowo (poprzez kartę rozszerzającą lub sterownik na płycie) albo programowo (przez kopiowanie stron, lub wykorzystanie mechanizmu stronicowania pamięci). Do dziś przetrwała jedynie metoda wykorzystująca stronicowanie. Implementowana jest ona przez sterownik QEMM386, lub najpopularniejszy EMM386.

        Obecnie przyjętym standardem dotyczącym pamięci expanded jest LIM EMS 4.0. Istotnymi zmianami w stosunku do starszych wersji jest wprowadzenie większej ilości stron fizycznych (umieszczonych poza ramką EMS), oraz zaimplementowanie interfejsu VCPI.

        Funkcje sterownika EMS instalowane są pod przerwaniem 67H, nim jednak wywołamy jakąkolwiek z nich należy sprawdzić obecność sterownika w pamięci. Najprostsza metoda polega na sprawdzeniu czy wektor przerwania 67H wskazuje na jakąś procedurę obsługi (wektor pusty jest wypełniony zerami).

.CODE

;detekcja sterownika EMS przez kontrolę

;wektora INT 67H

XOR AX,AX

MOV ES,AX

MOV AX,[ES:67H*4]

MOV BX,[ES:67H*4+2]

OR AX,BX

JE SHORT NIE_MA

;sterownik EMS jest zainstalowany

NIE_MA:

;sterownik EMS nie jest zainstalowany

        Metoda ta może jednak być zawodna, jeżeli np. jakiś nierozsądny program TSR podczepi się pod przerwanie 67H. Dlatego raczej należy używać metody sprawdzenia nazwy sterownika obsługującego to przerwanie. Nazwa sterownika EMS 'EMMXXXX0' umieszczona jest pod przemieszczeniem 0AH względem segmentu wektora INT 67H. Poniższy fragment kodu przedstawiający tą technikę dla ułatwienia wykorzystuje możliwości 32-bitowego adresowania procesorów 386.

.CODE

;detekcja sterownika EMS przez sprawdzenie nazwy

XOR AX,AX

MOV ES,AX

MOV ES,[ES:67H*4+2]

CMP [DWORD PTR ES:0AH],'XMME'

JNE SHORT NIE_MA

CMP [DWORD PTR ES:0AH+4],'0XXX'

JNE SHORT NIE_MA

;sterownik EMS jest zainstalowany

NIE_MA:

;sterownik EMS nie jest zainstalowany

        Poniżej znajdują się najistotniejsze funkcje EMS których wywołanie realizuje się przez przerwanie 67H. Funkcje 41H-4EH obejmuje standard LIM EMS 3.x, natomiast funkcje 4FH-58H standard LIM EMS 4.0.

INT 67H, AH=40H, Pobranie statusu
Wejście:
    Nie ma
Wyjście:
    AH = 0 - mechanizmy EMS działają poprawnie
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=41H, Pobranie adresu ramki EMS
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    BX - adres segmentowy ramki EMS
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=42H, Pobranie liczby stron logicznych
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    BX - liczba niezaalokowanych stron logicznych
    DX - liczba wszystkich stron logicznych
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=43H, Alokacja stron
Wejście:
    BX - liczba stron do zaalokowania
Wyjście jeżeli AH=0:
    DX - uchwyt zaalokowanych stron
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=44H, Podpięcie stron
Wejście:
    AL - numer strony fizycznej w którą zostanie wpięta logiczna
    BX - numer wpinanej strony logicznej
    DX - uchwyt zaalokowanych stron
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=45H, Dealokacja stron
Wejście:
    DX - uchwyt stron
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=46H, Pobranie wersji LIM EMS
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    AL - numer wersji standardu LIM EMS
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=47H, Zapamiętanie stanu odwzorowania stron
Wejście:
    DX - uchwyt stron zaalokowanych przez program
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=48H, Odtworzenie stanu odwzorowania stron
Wejście:
    DX - uchwyt stron zaalokowanych przez program
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=4BH, Pobranie liczby uchwytów
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    DX - liczba wszystkich otwartych uchwytów
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=4CH, Pobranie liczby stron związanych z uchwytem
Wejście:
    DX - uchwyt stron
Wyjście jeżeli AH=0:
    BX - liczba stron
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=4DH, Pobranie liczby stron związanych z wszystkimi uchwytami
Wejście:
    ES:DI - wskaźnik do obszaru danych
Wyjście jeżeli AH=0:
    BX - liczba otwartych uchwytów
Wyjście jeżeli AH<>0:
    AH = kod błędu


Uwaga! Wskaźnik w ES:DI powinien wskazywać obszar o wielkości wyznaczonej przez liczbę otwartych uchwytów (funkcja 4BH) pomnożoną przez cztery. Zapisana w nim informacja ma postać poniższych struktur:

STRUC UCHW_INFO

;wartość uchwytu

UCHW DW ?

;liczba stron związanych z uchwytem

PAGES DW ?

ENDS UCHW_INFO

INT 67H, AX=4E00H, Pobranie stanu odwzorowania stron
Wejście:
    ES:DI - wskaźnik obszaru do zapisania stanu
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=4E01H, Ustalenie stanu odwzorowania stron
Wejście:
    DS:SI - wskaźnik obszaru do pobrania stanu
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=4E02H, Pobranie i ustalenie stanu odwzorowania stron
Wejście:
    ES:DI - wskaźnik obszaru do zapisania stanu
    DS:SI - wskaźnik obszaru do pobrania stanu
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=4E03H, Pobranie rozmiaru obszaru do zapisu danych o stanie odwzorowania stron
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    AL = rozmiar obszaru w bajtach
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! W podfunkcjach 00H-02H funkcji 4EH wskaźnik w ES:DI powinien wskazywać obszar w którym zapisane zostaną dane dotyczące odwzorowania, natomiast wskaźnik w DS:SI obszar z którego zostaną pobrane dane. Wielkość obszaru pobieramy podfunkcją 03H

INT 67H, AX=4F00H, Pobranie częściowego stanu odwzorowania stron
Wejście:
    DS:SI - wskaźnik obszaru danych o wybranych stronach
    ES:DI - wskaźnik obszaru do zapisania stanu
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=4F01H, Ustalenie częściowego stanu odwzorowania stron
Wejście:
    DS:SI - wskaźnik obszaru do pobrania stanu
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=4F02H, Pobranie rozmiaru obszaru do zapisu danych o częściowym stanie odwzorowania stron
Wejście:
    BX = liczba wybranych stron
Wyjście jeżeli AH=0:
    AL = rozmiar obszaru w bajtach
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Funkcja 4FH działa analogicznie do funkcji 4EH, jednak informacja dotyczy tylko wybranych stron. W podfunkcji 00H wskaźnik w DS:SI wskazuje obszar w którym zapisana jest informacja których stron fizycznych dotyczy zapisanie stanu.

INT 67H, AH=50H, Podpięcie wielu stron
Wejście:
    AL = 0 - funkcja bazuje na numerach stron fizycznych
    AL = 1 - funkcja bazuje na segmentach stron fizycznych
    DX - uchwyt stron
    CX - ilość elementów w obszarze danych
    DS:SI - wskaźnik obszaru do pobrania stanu
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Elementy w tablicy wskazywanej przez ES:DI mają postać poniższych struktur:

STRUC PODP_STRON

;numer strony logicznej

LOG DW ?

;numer strony fizycznej (dla AL=0)

;lub jej adres segmentowy (dla AL=1)

FIZ DW ?

ENDS PODP_STRON

INT 67H, AH=51H, Realokacja stron
Wejście:
    DX - uchwyt stron
    BX - wymagana liczba stron
Wyjście jeżeli AH=0:
    BX - wynikowa liczba zaalokowanych stron
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=5200H, Pobranie atrybutu uchwytu
Wejście:
    DX - uchwyt
Wyjście jeżeli AH=0:
    AL = 0 - uchwyt ulotny
    AL = 1 - uchwyt nieulotny
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=5201H, Ustalenie atrybutu uchwytu
Wejście:
    DX - uchwyt
    BL = 0 - uchwyt ulotny
    BL = 1 - uchwyt nieulotny
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=5202H, Określenie ulotności pamięci
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    AL = 0 - pamięć ulotna
    AL = 1 - pamięć nieulotna
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Funkcja 52H ma znaczenie wyłącznie w sprzętowych implementacjach pamięci EMS. Atrybut uchwytu decyduje wówczas, czy pamięć zostanie wymazana czy nie po restarcie systemu kombinacją CTRL-ALT-DEL.

INT 67H, AX=5300H, Pobranie nazwy uchwytu
Wejście:
    DX - uchwyt
    ES:DI - wskaźnik obszaru do zapisania nazwy
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=5301H, Ustalenie nazwy uchwytu
Wejście:
    DX - uchwyt
    DS:SI - wskaźnik obszaru z zapisaną nazwą
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Nazwa uchwytu złożona jest z maksymalnie 8 znaków. Puste pola wypełniane są wartością 00H.

INT 67H, AX=5400H, Pobranie nazw wszystkich uchwytu
Wejście:
    ES:DI - wskaźnik obszaru do zapisania nazw
Wyjście jeżeli AH=0:
    AL = liczba otwartych uchwytów
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Elementy w tablicy wskazywanej przez ES:DI mają postać poniższych struktur:

STRUC NAZW_STRON

;wartość uchwytu

UCHW DW ?

;nazwa uchwytu

NAZWA DB 8 DUP(?)

ENDS NAZW_STRON

INT 67H, AX=5401H, Wyszukanie uchwytu przez nazwę
Wejście:
    DS:SI - wskaźnik obszaru z zapisaną nazwą
Wyjście jeżeli AH=0:
    DX - uchwyt
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=5402H, Pobranie maksymalnej liczby uchwytów
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    BX - liczba dostępnych uchwytów
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AH=57H, Skopiowanie lub wymiana obszaru pamięci
Wejście:
    AL = 0 - skopiowanie obszaru
    AL = 1 - wymiana obszaru
    DS:SI - wskaźnik struktury opisującej obszary
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Gdy AL=0 dane są kopiowane z obszaru źródłowego do docelowego, natomiast gdy AL=1 dane są wymieniane pomiędzy tymi obszarami. Struktura opisująca ma postać:

STRUC KOP_WYM

;liczba bajtów do skopiowania

WIELK DD ?

;rodzaj obszaru źródłowego

;0 - dla pamięci bazowej

;1 - dla stron EMS

ZR_RODZ DB ?

;uchwyt stron EMS obszaru źródłowego

;(dla pamięci bazowej = 0)

ZR_UCHW DW ?

;przemieszczenie względem segmentu

;lub strony EMS obszaru źródłowego

ZR_OFFS DW ?

;segment pamięci bazowej

;lub numer strony EMS obszaru źródłowego

ZR_SEG DW ?

;poniższe parametry obszaru docelowego są

;analogiczne do obszaru źródłowego

DC_RODZ DB ?

DC_UCHW DW ?

DC_OFFS DW ?

DC_SEG DW ?

ENDS KOP_WYM

INT 67H, AX=5800H, Pobranie adresów segmentowych stron fizycznych
Wejście:
    ES:DI - wskaźnik obszaru do zapisania danych
Wyjście jeżeli AH=0:
    CX - liczba stron fizycznych
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=5801H, Pobranie liczby stron fizycznych
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    CX - liczba stron fizycznych
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Wskaźnik w ES:DI podfunkcji 00H powinien wskazywać obszar o wielkości wyznaczonej przez liczbę stron fizycznych pomnożoną przez cztery. Zapisana w nim informacja ma postać poniższych struktur:

STRUC SEG_FIZ

;segment strony fizycznej

SEG DW ?

;numer strony fizycznej

NUM DW ?

ENDS SEG_FIZ

0x08 graphic

--></><basefont face="Times New Roman" size=3>

5.4. Schematy alokacji pamięci rozszerzonej

        Od czasu powstania pamięci rozszerzonej powstało wiele standardów według których programy mogły zarządzać dodatkową pamięcią. Niektóre z nich stanowią rozbudowane programy nie tylko ułatwiające dostęp do pamięci, ale także zawierające interfejsy realizujące podstawowe czynności związane z przełączaniem do trybu chronionego. Niestety każdy ze sposobów alokacji pamięci wiąże się z odmienną konfiguracją systemu co staje się ciężarem dla użytkownika, który musi za każdym razem restartować komputer modyfikując przy tym plik CONFIG.SYS. Dlatego programista powinien zadbać o to, aby jego program uruchamiał się z dowolnej konfiguracji. Może do tego wykorzystać jeden z dostępnych DOS extenderów, lub stworzyć własny algorytm do zarządzania pamięcią.

        Złożone sterowniki pamięci zazwyczaj wykorzystują inne, prymitywniejsze sterowniki i schematy: XMS wykorzystuje schemat TOP-DOWN, VCPI(EMS) wykorzystuje XMS, natomiast DPMI wszystkie podrzędne. Dlatego program obsługujący pamięć powinien w pierwszej kolejności wykorzystywać schematy najbardziej rozbudowane. Poniżej przedstawiony jest sposób postępowania po wykryciu istnienia danego schematu:

DPMI - po jego wykryciu program powinien przełączyć się w tryb chroniony za pomocą jego interfejsu, bez dodatkowego sprawdzania innych schematów,

VCPI - program może sprawdzić istnienie pamięci TOP-DOWN i BOTTOM-UP i dołączyć ją do puli zarządzanych obszarów, następnie zaalokować pamięć XMS i na końcu VCPI. Ten sposób postępowania znacznie przyspiesza sam proces alokacji gdyż VCPI przydziela po jednej stronie 4kb, natomiast XMS dowolnie duży obszar. Przełączenie do trybu chronionego musi być wykonane przez interfejs VCPI,

XMS - jeżeli nie wykryty został sterownik VCPI program alokuje pamięć za pomocą interfejsu XMS, opcjonalnie alokując także pamięć TOP-DOWN i BOTTOM-UP. Przełączenie do trybu chronionego następuje przez samodzielnie stworzony do tego mechanizm,

TOP-DOWN - program alokuje pamięć według tego schematu licząc się jednocześnie ze schematem BOTTOM-UP. Przełączenie do trybu chronionego następuje przez samodzielnie stworzony do tego mechanizm,

BOTTOM-UP - zalecane jest wykorzystanie zamiennie schematu TOP-DOWN który oferuje te same możliwości i jest bardziej elegancki.

--></><basefont face="Times New Roman" size=3>

5.4.1. BOTTOM-UP

        Schemat BOTTOM-UP zwany także schematem VDISK, jest dosyć przestarzałym sposobem na alokację pamięci i raczej nie należy go używać. Zamiast niego programy mogą zastosować schemat TOP-DOWN. Różnica polega na tym że BOTTOM-UP alokuje pamięć rozszerzoną poczynając od adresu 100000H (1Mb) w górę, natomiast TOP-DOWN od górnej granicy w dół. Niezbędne jest jednak poznanie mechanizmu BOTTOM-UP, gdyż jeżeli jest obecny wyznacza on dolną granicę dla TOP-DOWN.

        W praktyce uzyskanie górnej granicy BOTTOM-UP polega na odczytaniu wartości w dwóch miejscach pamięci, porównaniu ich i wybraniu wyższej. Wynika to z różnych implementacji tego schematu. Pierwsze z miejsc wskazywane jest przez wektor przerwania 19H. Pod przemieszczeniem 12H względem segmentu tego wektora znajduje się sygnatura 'VDISK V', pod przemieszczeniem 2CH mniej znaczące słowo a pod 2EH bardziej znaczący bajt górnej granicy. Drugie miejsce znajduje się w bootblocku umieszczonym na początku pamięci rozszerzonej (wymaga to odblokowania lini A20). Przemieszczenie 03H względem 1Mb wskazuje sygnaturę 'VDISK', natomiast przemieszczenie 1EH słowo górnej granicy wyrażone w kilobajtach. Poniższy kod pokazuje w jaki sposób otrzymać górną granicę schematu BOTTOM-UP:

.CODE

;odczytanie górnej granicy BOTTOM-UP

XOR AX,AX

MOV FS,AX

DEC AX

MOV GS,AX

MOV EDX,0100000H

MOV EBX,EDX

;sprawdzenie pierwszej lokacji

MOV ES,[FS:19H*4+2]

CMP [DWORD PTR ES:12H],'SIDV'

JNE SHORT NAST

MOV DL,[ES:2EH]

SHL EDX,16

MOV DX,[ES:2CH]

;sprawdzenie drugiej lokacji

NAST: CMP [DWORD PTR GS:13H],'SIDV'

JNE SHORT POROWN

XOR EBX,EBX

MOV BX,[GS:2EH]

SHL EBX,10

;porównanie wyników

POROWN: CMP EDX,EBX

JB SHORT KONIEC

MOV EBX,EDX

KONIEC:

;w EBX zwracana jest górna granica BOTTOM-UP

;w przypadku nie istnienia tego schematu

;wartość EBX wynosi 100000H (1Mb)

--></><basefont face="Times New Roman" size=3>

5.4.2. TOP-DOWN

        Schemat TOP-DOWN (zwany także schematem INT 15) jest stosunkowo prosty i zalecane jest jego używanie zamiast schematu BOTTOM-UP. Bazuje on na funkcji 88H przerwania 15H. Funkcja ta zwraca rozmiar pamięci rozszerzonej wyrażonej w kilobajtach:

INT 15H, AH=88H, Odczytanie rozmiaru pamięci rozszerzonej
Wejście:
    Nie ma
Wyjście jeżeli CF=0:
    AX - rozmiar pamięci w kilobajtach
Wyjście jeżeli CF=1:
    Nie ma

        Sposób alokacji pamięci polega na stworzeniu procedury obsługi przerwania 15H która w przypadku wystąpienia funkcji 88H zwraca wielkość pamięci rozszerzonej pomniejszonej o obszar zaalokowany przez siebie. Przy alokowaniu pamięci tą metodą programy muszą liczyć się ze schematem BOTTOM-UP, który wyznacza dolną granicę pamięci (w przypadku jego braku granica ta wynosi 1Mb).

.CODE

;wielkość pamięci do zaalokowania (w kb)

;w naszym przypadku 3Mb

ILE_KB EQU 3072

;na wejściu rejestr BX powinien zawierać

;dolną granicę pamięci

XOR EAX,EAX

MOV AH,88H

INT 15H

SHL EAX,10

ADD EAX,100000H

XOR ECX,ECX

MOV CX,ILE_KB

SHL ECX,10

SUB EAX,ECX

CMP EAX,EBX

JAE SHORT OK

;błąd - za mało pamięci

OK:

;instalacja obsługi INT 15H

XOR SI,SI

MOV ES,SI

MOV SI,CS

MOV DI,OFFSET INT_15H

CLI

XCHG [ES:15H*4],DI

XCHG [ES:15H*4+2],SI

MOV [CS:ADRES],DI

MOV [CS:ADRES+2],SI

STI

;procedura alokacji zakończona

;EAX - początek zaalokowanej pamięci

;ECX - rozmiar zaalokowanej pamięci

;procedura obsługi przerwania

PROC INT_15H FAR

MOV [CS:AH_REJ],AH

PUSHF

CALL [DWORD PTR CS:ADRES]

CMP [BYTE PTR CS:AH_REJ],88H

JNE SHORT EX_INT

SUB AX,ILE_KB

EX_INT: IRET

ENDP INT_15H

;zmienna przechowująca rejestr AH

AH_REJ DB ?

;adres starej procedury obsługi INT 15H

ADRES DW ?,?

5.4.3. XMS

        XMS (eXtended Memory Specification) jest interfejsem udostępnianym przez program XMM (eXtended Memory Manager). Przekazuje on programom do dyspozycji funkcje związane z kontrolą lini A20, alokacją pamięci górnej, wysokiej i rozszerzonej. Prostota i wygoda obsługi XMS sprawiła że jest to najpopularniejszy standard dotyczący zarządzania pamięcią komputerów PC. Nawet system Windows95 do pracy wymaga zainstalowanego sterownika XMS. Najbardziej znanym jest program HIMEM dołączany do systemów DOS i Windows95.

        Pamięć XMS jest ciągłym blokiem w którym wyodrębnia się bloki EMB (Extended Memory Block). Należy jednak pamiętać że XMS nie korzysta z mechanizmu stronicowania i nie potrafi sklejać wolnych bloków. Oznacza to że jeżeli program A zaalokuje obszar o rozmiarze AA, następnie program B obszar BB wtedy największy wolny blok jest równy WIELKOŚĆ_PAMIĘCI - AA - BB. Jeżeli z kolei program A zwolni swój blok, to największy wolny EMB dalej będziemy wyznaczać tym wzorem, aż do zwolnienia pamięci przez program B. Dlatego jeżeli dany program wymaga maksimum pamięci, a jest ona podzielona, powinien on wykorzystać stronicowanie pamięci w celu zachowania jej ciągłości.

        Przed wywołaniem funkcji XMS należy sprawdzić jego obecność i pobrać adres wejścia. Zajmują się tym funkcje przerwania 2FH przedstawione poniżej. Przy każdym wywołaniu funkcji XMS należy w AH umieścić jej numer a następnie wykonać daleki skok pod adres zwrócony w parze ES:BX.

INT 2FH, AX=4300H, Detekcja XMS
Wejście:
    Nie ma
Wyjście:
    AL = 80H - sterownik XMS zainstalowany

INT 2FH, AX=4310H, Pobranie adresu wejścia do procedur XMS
Wejście:
    Nie ma
Wyjście:
    ES:BX = adres wejścia do procedur XMS

        Poniższy kod pokazuje sposób detekcji XMS i przykładowe wywołanie funkcji 00H.

.DATA

;pobrany adres wejścia do procedur XMS

ADR_XMS DW ?,?

.CODE

;detekcja sterownika XMS

MOV AX,4300H

INT 2FH

CMP AL,80H

JE SHORT OK

;błąd - sterownik XMS nie zainstalowany

OK:

;pobranie adresu wejścia

MOV AX,4310H

INT 2FH

MOV [ADR_XMS],BX

MOV [ADR_XMS+2],ES

;wywołanie funkcji 00H

MOV AH,00H

CALL [DWORD PTR ADR_XMS]

        Większość funkcji XMS została przedstawiona w rozdziałach związanych tematycznie. Tutaj zajmiemy się głównie funkcjami dotyczącymi pamięci rozszerzonej. Funkcje 88H-8FH wykorzystują możliwości 32-bitowego adresowania procesorów 386 i wyższych.

AH=00H, Pobranie numeru wersji
Wejście:
    Nie ma
Wyjście:
    AX = numer wersji XMS
    BX = wewnętrzny numer programu XMM
    DX = 1 - istnieje pamięć wysoka
    DX = 0 - nie istnieje pamięć wysoka

AH=08H, Informacja o wolnej pamięci rozszerzonej
Wejście:
    Nie ma
Wyjście jeżeli BL=0:
    AX = rozmiar największego wolnego bloku (w kb)
    DX = sumaryczny rozmiar wszystkich bloków (w kb)
Wyjście jeżeli BL<>0:
    BL = kod błędu

AH=09H, Przydzielenie bloku pamięci
Wejście:
    DX = żądany rozmiar bloku (w kb)
Wyjście jeżeli AL=1:
    DX = uchwyt przydzielonego bloku
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=0AH, Zwolnienie bloku pamięci
Wejście:
    DX = uchwyt bloku
Wyjście jeżeli AL=1:
    Nie ma
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=0BH, Skopiowanie bloku danych
Wejście:
    DS:SI = adres obszaru z informacją
Wyjście jeżeli AL=1:
    Nie ma
Wyjście jeżeli AL=0:
    BL = kod błędu

Uwaga! Wskaźnik w DS:SI powinien wskazywać obszar w którym zapisana jest informacja o bloku źródłowym i docelowym. Struktura ta ma postać:

STRUC KOP_INFO

;rozmiar kopiowanego bloku w bajtach

ROZM DD ?

;uchwyt bloku źródłowego lub 00H jeżeli

;obszar znajduje się w pamięci bazowej

SR_UCHW DW ?

;przemieszczenie w bloku źródłowym, lub

;adres logiczny (segment:offset) dla

;pamięci bazowej

SR_OFFS DD ?

;parametry analogiczne dla bloku docelowego

DC_UCHW DW ?

DC_OFFS DD ?

ENDS KOP_INFO

AH=0CH, Zablokowanie bloku pamięci
Wejście:
    DX = uchwyt bloku
Wyjście jeżeli AL=1:
    DX:BX = 32-bitowy adres liniowy zablokowanego bloku
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=0DH, Odblokowanie bloku pamięci
Wejście:
    DX = uchwyt bloku
Wyjście jeżeli AL=1:
    Nie ma
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=0EH, Pobranie informacji o bloku pamięci
Wejście:
    DX = uchwyt bloku
Wyjście jeżeli AL=1:
    BH = ilość zablokowań danego bloku
    BL = ilość wolnych uchwytów pamięci
    DX = rozmiar bloku (w kb)
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=0FH, Zmiana rozmiaru bloku pamięci
Wejście:
    DX = uchwyt bloku
    BX = nowy rozmiar bloku (w kb)
Wyjście jeżeli AL=1:
    Nie ma
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=88H, Informacja o wolnej pamięci rozszerzonej
Wejście:
    Nie ma
Wyjście jeżeli BL=0:
    EAX = rozmiar największego wolnego bloku (w kb)
    EDX = sumaryczny rozmiar wszystkich bloków (w kb)
    ECX = najwyższy fizyczny adres pamięci
Wyjście jeżeli BL<>0:
    BL = kod błędu

AH=89H, Przydzielenie bloku pamięci
Wejście:
    EDX = żądany rozmiar bloku (w kb)
Wyjście jeżeli AL=1:
    DX = uchwyt przydzielonego bloku
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=8EH, Pobranie informacji o bloku pamięci
Wejście:
    DX = uchwyt bloku
Wyjście jeżeli AL=1:
    BH = ilość zablokowań danego bloku
    CX = ilość wolnych uchwytów pamięci
    EDX = rozmiar bloku (w kb)
Wyjście jeżeli AL=0:
    BL = kod błędu

AH=8FH, Zmiana rozmiaru bloku pamięci
Wejście:
    DX = uchwyt bloku
    EBX = nowy rozmiar bloku (w kb)
Wyjście jeżeli AL=1:
    Nie ma
Wyjście jeżeli AL=0:
    BL = kod błędu

5.4.4. VCPI

        Interfejs VCPI (Virtual Control Program Interface) powstał jako rozszerzenie standardu EMS począwszy od wersji LIM EMS 4.0. Udostępnia on możliwość alokacji pamięci rozszerzonej i mechanizmy przełączania do trybu chronionego dla programów pracujących w tym trybie. Ponieważ w przypadku zainstalowanego sterownika EMS system pracuje w trybie V86 (Virtual 8086 machine) na najniższym poziomie uprzywilejowania, program jest zmuszony do wykorzystania VCPI do przełączenia do trybu chronionego, gdyż inaczej spowoduje on powstanie wyjątku np. przy dostępie do rejestrów sterujących.

        VCPI ma dosyć ograniczone możliwości alokowania pamięci. Każdym wywołaniem funkcji alokującej przydzielana jest nam tylko jedna strona o wielkości 4kb. Dlatego programy wymagające dużego obszaru pamięci powinny ze względu na szybkość alokować bloki za pomocą XMS, zablokowywać je i na podstawie otrzymanego adresu dokonywać podziału na 4kb strony. Pamiętać należy że adres każdej strony powinien być podzielny przez 4kb, zgodnie z mechanizmem stronicowania.

        Aby sprawdzić obecność VCPI należy najpierw zdetektować EMS, następnie zaalokować jedną jego stronę (aby upewnić się że mechanizm VCPI jest włączony) a następnie wywołać funkcję DEH przerwania 67H. Ze względu na fakt iż mechanizm VCPI występuje tylko na maszynach 386 i wyższych można przed całą procedurą dokonać sprawdzenia typu procesora. Oto funkcja DEH:

INT 67H, AX=DE00H, Detekcja VCPI
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    BX = numer wersji VCPI
Wyjście jeżeli AH<>0:
    AH = kod błędu

        Funkcje VCPI dostępne są pod przerwaniem 67H. Pełne ich zrozumienie wymaga znajomości architektury procesorów 386 w górę a w szczególności trybu chronionego i mechanizmu stronicowania pamięci. Dzielą się one na funkcje dostępne z poziomu trybu V86 i trybu chronionego. Oto pierwsza grupa:

INT 67H, AX=DE01H, Pobranie interfejsu trybu chronionego
Wejście:
    ES:DI = wskaźnik do tablicy stron
    DS:SI = wskaźnik do trzech deskryptorów
Wyjście jeżeli AH=0:
    DI = przemieszczenie w tablicy stron
    EBX = przemieszczenie w segmencie kodu
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Wskaźnik w ES:DI powinien wskazywać na pierwszą tablicę stron (opisującą pierwsze 4Mb pamięci) która zostanie wypełniona przez VCPI. W rejestrze DI zwracane jest przemieszczenie w tej tablicy wskazujące pierwszy nie używany element (od tego miejsca tablica może być wypełniana przez nasz program). Wskaźnik w DS:SI wskazuje na pole w którym umieszczone zostaną trzy deskryptory należące do VCPI. Pierwszy z nich opisuje segment kodu VCPI i wraz z przemieszczeniem zwracanym w EBX powinien być używany jako adres wejścia do procedur VCPI dla trybu chronionego.

INT 67H, AX=DE02H, Pobranie adresu najwyższej strony
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    EDX = fizyczny adres strony
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=DE03H, Pobranie ilości wolnych stron
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    EDX = ilość wolnych stron
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=DE04H, Alokacja strony
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    EDX = fizyczny adres strony
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=DE05H, Dealokacja strony
Wejście:
    EDX = fizyczny adres strony
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=DE06H, Pobierz adres fizyczny strony umieszczonej w pamięci bazowej
Wejście:
    CX = numer strony
Wyjście jeżeli AH=0:
    EDX = fizyczny adres strony
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Numer strony (rejestr CX) jest adresem liniowym podzielonym przez 4kb.

INT 67H, AX=DE07H, Odczytanie CR0
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    EBX = wartość rejestru CR0
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=DE08H, Odczytanie rejestrów uruchomieniowych
Wejście:
    ES:DI = wskaźnik do zapisu rejestrów
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! W obszarze ES:DI zapisane zostaną 32-bitowe rejestry uruchomieniowe (DR0-DR7). Pomimo braku rejestrów DR4 i DR5 dla nich również zostanie przydzielone miejsce.

INT 67H, AX=DE09H, Zapisanie rejestrów uruchomieniowych
Wejście:
    ES:DI = wskaźnik z zapisanymi rejestrami
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Z obszaru ES:DI odczytane zostaną 32-bitowe wartości i wpisane do rejestrów uruchomieniowych (DR0-DR7). Pola dotyczące rejestrów DR4 i DR5 będą ignorowane.

INT 67H, AX=DE0AH, Odczytanie wektorów przerwań sprzętowych
Wejście:
    Nie ma
Wyjście jeżeli AH=0:
    BX = wektor układu PIC master (IRQ0-IRQ7)
    CX = wektor układu PIC slave (IRQ8-IRQ15)
Wyjście jeżeli AH<>0:
    AH = kod błędu

INT 67H, AX=DE0BH, Ustawienie wektorów przerwań sprzętowych
Wejście:
    BX = wektor układu master (IRQ0-IRQ7)
    CX = wektor układu slave (IRQ8-IRQ15)
Wyjście jeżeli AH=0:
    Nie ma
Wyjście jeżeli AH<>0:
    AH = kod błędu

Uwaga! Wektor oznacza numer przerwania programowego dla pierwszego przerwania sprzętowego danego układu. Ustawienie wektorów oznacza jedynie poinformowanie VCPI o ich zmianie. Program sam musi dokonać zmiany programując układ 8259A. Podczas tej operacji oraz podczas przekazywania wektorów do VCPI przerwania muszą być wyłączone. Program powinien odtworzyć poprzednie ustawienia wektorów przed zakończeniem działania.

INT 67H, AX=DE0CH, Przełączenie do trybu chronionego
Wejście:
    ESI = adres struktury w pierwszym megabajcie
Wyjście:
    Nie ma

Uwaga! Rejestr ESI powinien zawierać liniowy adres struktury w pierwszym megabajcie pamięci zawierającej wartości wpisywane do rejestrów procesora. Przerwania podczas całej operacji przełączenia powinny być wyłączone. Funkcja ładuje rejestry CR3, GDTR, IDTR, LDTR i TR po czym wykonuje skok pod zadany adres. Po otrzymaniu kontroli program powinien wypełnić własnymi wartościami rejestry stosu (SS:ESP) i włączyć przerwania. Oto postać struktury:

STRUC WART_REJ

;wartość rejestru CR3

CR3_REG DD ?

;liniowy adres w pierwszym megabajcie zawierający

;6-bajtową wartość ładowaną do GDTR

GDTR_AD DD ?

;liniowy adres w pierwszym megabajcie zawierający

;6-bajtową wartość ładowaną do IDTR

IDTR_AD DD ?

;selektor ładowany do LDTR

LDTR_SL DW ?

;selektor ładowany do TR

TR_SL DW ?

;adres pod który wykonany zostanie skok

;po przełączeniu, wielkość ta zależy od

;typu segmentu:

;USE16 - 4 bajty (DWORD)

;USE32 - 6 bajtów (FWORD)

ADRES DF ?

ENDS WART_REJ

        Druga grupa funkcji VCPI dostępna jest z poziomu trybu chronionego. Wywołanie każdej funkcji polega na wykonaniu dalekiego skoku pod adres wejścia VCPI. Selektor umieszczany w rejestrze segmentowym wyznaczamy sami. Jest to selektor pierwszego deskryptora VCPI (adres trzech deskryptorów przekazujemy funkcją DE01H). Przemieszczenie natomiast zwracane jest w rejestrze EBX po wykonaniu funkcji DE01H. Pierwsze trzy funkcje trybu chronionego są analogiczne dla trybu V86, omówienia wymaga jedynie funkcja DE0CH.

AX=DE03H, Pobranie ilości wolnych stron

AX=DE04H, Alokacja strony

AX=DE05H, Dealokacja strony

AX=DE0CH, Przełączenie do trybu V86
Wejście:
    SS:ESP = szczyt stosu z odłożonymi wartościami
    DS = selektor segmentu pierwszego megabajtu
Wyjście:
    Nie ma

Uwaga! Rejestr DS powinien zawierać selektor segmentu obejmującego początkowy obszar pamięci, którego adres bazowy wynosi zero a limit jest określony przy wywołaniu funkcji DE01H (rejestr DI). Na szczyt stosu (znajdującego się w pierwszym megabajcie) odłożone być powinny kolejno następujące wartości charakterystyczne dla trybu V86 (wszystkie wartości są 32-bitowe mimo iż uwzględniane jest tylko ich mniej znaczące słowo):

(DWORD) wartość rejestru GS

(DWORD) wartość rejestru FS

(DWORD) wartość rejestru DS

(DWORD) wartość rejestru ES

(DWORD) wartość rejestru SS

(DWORD) wartość rejestru SP

(DWORD) zarezerwowane dla EFLAGS (ignorowane)

(DWORD) wartość rejestru CS

(DWORD) wartość rejestru IP

Podczas przełączenia do trybu V86 przerwania powinny być wyłączone. Przed wykonaniem procedury program powinien także wyzerować bit TS w rejestrze CR0. W przeciwnym wypadku operacje na liczbach zmiennoprzecinkowych spowodują wyjątek 07H.

5.4.5. DPMI

        Interfejs DPMI udostępnia zintegrowane środowisko trybu chronionego programom pracującym pod kontrolą DOSu. Może on zaistnieć w postaci zwykłego dosowego sterownika pamięci, lub jako wirtualne środowisko DOSu zaimplementowane w zupełnie odrębnym systemie operacyjnym. Między innymi właśnie dzięki DPMI programy wykorzystujące ten interfejs mogą działać praktycznie bezbłędnie pod systemem Windows95.

        DPMI udostępnia funkcje zarządzania pamięcią bazową i rozszerzoną, deskryptorami oraz przerwaniami i wyjątkami. W prosty sposób umożliwia on także uruchamianie kodu trybu rzeczywistego i standardowych przerwań BIOSu i DOSu. Program pracujący w środowisku DPMI nie może liczyć na to, że będzie uruchomiony na najwyższym poziomie uprzywilejowania, dlatego też zmuszony jest do używania funkcji tego interfejsu (jako jedynego sposobu na modyfikację rejestrów, których zmiana na niższym poziomie uprzywilejowania generuje wyjątek).

        Prawie wszystkie funkcje DPMI dostępne są pod przerwaniem 31H . Wywołanie ich może nastąpić jedynie z poziomu trybu chronionego. Dlatego w trybie rzeczywistym, po wykryciu DPMI program musi przełączyć się do trybu chronionego (za pomocą jego interfejsu) i dopiero wtedy wykonywać wszelkie operacje związane z alokacją pamięci itd. Obecność DPMI ustalamy za pomocą funkcji 1687H przerwania 2FH. Zwraca ona szereg danych charakteryzujących środowisko, m.in. numer wersji, implementację 16-bitową lub 32-bitową, oraz adres procedury przełączającej do trybu chronionego.

INT 2FH, AX=1687H, Pobranie adresu procedury przełączającej do trybu chronionego
Wejście:
    Nie ma
Wyjście jeżeli AX=0:
    BX = flagi
    CL = typ procesora
    CL = 02H - 80286
    CL = 03H - 80386
    CL = 04H - 80486
    DX = numer wersji DPMI
    SI = wielkość obszaru dla DPMI (w paragrafach)
    ES:DI = adres procedury przełączającej
Wyjście jeżeli AX<>0:
    Nie ma

Uwaga! Rejestr BX zawiera tylko jedną flagę (bit 0). Jeżeli jest ona ustawiona oznacza to 32-bitową implementację DPMI, w przeciwnym wypadku 16-bitową. Rejestr SI zawiera rozmiar pamięci bazowej przeznaczonej dla DPMI, która zaalokowana musi być przez klienta.

        Po wywołaniu powyższej funkcji program powinien przełączyć się do trybu chronionego, wykonując daleki skok pod adres zwracany przez parę ES:DI. Oto funkcja realizująca przełączenie:

Przełączenie do trybu chronionego
Wejście:
    AX = flagi
    ES = adres obszaru dla DPMI
Wyjście jeżeli CF=0:
    CS = selektor kodu trybu rzeczywistego
    SS = selektor stosu trybu rzeczywistego
    DS = selektor danych trybu rzeczywistego
    ES = selektor PSP klienta
    FS, GS = 0
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Rejestr AX powinien zawierać tylko jedną flagę (bit 0). Jeżeli jest ona ustawiona oznacza to program 32-bitowy. Rejestr ES jest segmentem obszaru pamięci bazowej przeznaczonej dla DPMI, którego rozmiar podaje funkcja 1687H. Wszystkie zwracane selektory wskazują segmenty 16-bitowe. Ich adres bazowy wyznaczany jest na podstawie zawartości rejestrów segmentowych przed wywołaniem funkcji, natomiast limit wynosi 0FFFFH (z wyjątkiem segmentu PSP - 100H). Po prawidłowym wykonaniu funkcji program wykonywany jest w trybie chronionym.

        Programy pracujące na przemian w dwóch trybach, chronionym i rzeczywistym (lub V86) mają do dyspozycji funkcję 1686H, która podaje aktualny tryb pracy procesora. Dużo szybszym sposobem jest jednak użycie instrukcji SMSW i sprawdzenie bitu 0 słowa stanu procesora (instrukcja SMSW nie powoduje wyjątku na niższym poziomie uprzywilejowania).

INT 2FH, AX=1686H, Pobranie trybu pracy procesora
Wejście:
    Nie ma
Wyjście:
    AX = 0 - praca w t
rybie chronionym
    AX <> 0 - praca w trybie rzeczywistym (lub V86)

        A oto funkcje DPMI (zgodne ze standardem DPMI 0.9) dostępne wyłącznie z poziomu trybu chronionego:

INT 21H, AX=4CH, Zakończenie działania programu
Wejście:
    AL = kod wyjścia
Wyjście:
    Nie ma

Uwaga! Pomimo że funkcja ta przypomina standardową funkcję DOSu, powinna być wywołana z trybu chronionego przez program pracujący w tym trybie. Wywołanie tej funkcji z trybu rzeczywistego może spowodować w konsekwencji zawieszenie systemu.

INT 31H, AX=0000H, Zaalokowanie deskryptorów w tablicy LDT
Wejście:
    CX = ilość deskryptorów do zaalokowania
Wyjście jeżeli CF=0:
    AX = podstawowy selektor
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Zwracany selektor jest pierwszym z szeregu. Aby uzyskać kolejne selektory należy dodać wartość zwracaną przez funkcję 0003H.

INT 31H, AX=0001H, Zwolnienie deskryptora tablicy LDT
Wejście:
    BX = selektor deskryptora
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0002H, Konwersja segmentu trybu rzeczywistego do deskryptora
Wejście:
    BX = segment trybu rzeczywistego
Wyjście jeżeli CF=0:
    AX = selektor deskryptora
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Powstały deskryptor nie może być modyfikowany ani zwalniany. Limit każdego deskryptora wynosi 0FFFFH.

INT 31H, AX=0003H, Pobranie wartości wyznaczającej kolejne selektory
Wejście:
    Nie ma
Wyjście jeżeli CF=0:
    AX = wartość dodawana do selektora
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0006H, Pobranie adresu bazowego deskryptora
Wejście:
    BX = selektor deskryptora
Wyjście jeżeli CF=0:
    CX:DX = 32-bitowy adres liniowy
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0007H, Ustawienie adresu bazowego deskryptora
Wejście:
    BX = selektor deskryptora
    CX:DX = 32-bitowy adres liniowy
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0008H, Ustawienie limitu deskryptora
Wejście:
    BX = selektor deskryptora
    CX:DX = 32-bitowy limit (rozmiar)
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0009H, Ustawienie praw dostępu deskryptora
Wejście:
    BX = selektor deskryptora
    CL = podstawowy bajt flag deskryptora
    CH = rozszerzony bajt flag (tylko 386)
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=000AH, Stworzenie analogicznego segmentu kodu
Wejście:
    BX = selektor segmentu kodu
Wyjście jeżeli CF=0:
    AX = selektor segmentu danych
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Funkcja tworzy segment danych na podstawie podanego segmentu kodu. Ponieważ segment kodu może być tylko wykonywany lub odczytywany, umożliwia to ingerencję w kod programu.

INT 31H, AX=000BH, Pobranie deskryptora
Wejście:
    BX = selektor deskryptora
    ES:EDI = wskaźnik obszaru do zapisu deskryptora
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Wskaźnik w ES:EDI powinien wskazywać obszar o wielkości 8 bajtów, gdzie skopiowany zostanie deskryptor.

INT 31H, AX=000CH, Ustawienie deskryptora
Wejście:
    BX = selektor deskryptora
    ES:EDI = wskaźnik obszaru z deskryptorem
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Wskaźnik w ES:EDI powinien wskazywać obszar o wielkości 8 bajtów, gdzie zapisany jest deskryptor.

INT 31H, AX=000DH, Alokacja specyficznego deskryptora
Wejście:
    BX = selektor deskryptora
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Specyficznymi deskryptorami nazywamy pierwsze 16 deskryptorów tablicy LDT. DPMI rezerwuje je specjalnie na potrzeby tej funkcji. Mogą one być niedostępne w przypadku gdy inny program dokonał ich alokacji. Specyficzne deskryptory zwalniamy funkcją 0001H.

INT 31H, AX=0100H, Alokacja bloku pamięci bazowej
Wejście:
    BX = rozmiar bloku (w paragrafach)
Wyjście jeżeli CF=0:
    AX = segment bloku trybu rzeczywistego
    DX = selektor bloku
Wyjście jeżeli CF=1:
    AX = kod błędu (zwracany przez DOS)
    BX = rozmiar największego wolnego bloku

Uwaga! Jeżeli żądany rozmiar jest większy niż 64kb zaalokowane zostanie więcej deskryptorów, które wyznaczamy za pomocą funkcji 0003H. W 32-bitowych implementacjach limit pierwszego deskryptora będzie równy rozmiarowi bloku, limity pozostałych deskryptorów będą równe 0FFFFH, oprócz ostatniego, którego limit będzie resztą z dzielenia rozmiaru bloku przez 64kb. W 16-bitowych implementacjach limit pierwszego deskryptora będzie także równy 0FFFFH. Program nie powinien zwalniać lub modyfikować otrzymanych deskryptorów.

INT 31H, AX=0101H, Zwolnienie bloku pamięci bazowej
Wejście:
    DX = selektor bloku
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    AX = kod błędu (zwracany przez DOS)

Uwaga! Wraz z blokiem pamięci zwalniane są przydzielone mu deskryptory.

INT 31H, AX=0102H, Zmiana rozmiaru bloku pamięci bazowej
Wejście:
    BX = nowy rozmiar bloku (w paragrafach)
    DX = selektor bloku
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    AX = kod błędu (zwracany przez DOS)
    BX = rozmiar największego wolnego bloku

Uwaga! Zmiana rozmiaru bloku dodaje, zwalnia, lub modyfikuje deskryptory. Jeżeli wymagana jest alokacja deskryptora, a kolejny deskryptor w LDT jest zajęty funkcja zwróci błąd.

INT 31H, AX=0200H, Pobranie wektora przerwania trybu rzeczywistego
Wejście:
    BL = numer przerwania
Wyjście:
    CF = 0
    CX:DX = wektor przerwania (SEGMENT:OFFSET)

INT 31H, AX=0201H, Ustawienie wektora przerwania trybu rzeczywistego
Wejście:
    BL = numer przerwania
    CX:DX = wektor przerwania (SEGMENT:OFFSET)
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0202H, Pobranie wektora wyjątku
Wejście:
    BL = numer wyjątku (00H-1FH)
Wyjście jeżeli CF=0:
    CX:EDX = wektor wyjątku (SELEKTOR:OFFSET)
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0203H, Ustawienie wektora wyjątku
Wejście:
    BL = numer wyjątku (00H-1FH)
    CX:EDX = wektor wyjątku (SELEKTOR:OFFSET)
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Nie wszystkie wyjątki są udostępniane przez DPMI. Procedura obsługi wyjątku powinna zakończyć działanie wykonując instrukcję dalekiego powrotu lub skok do następnej procedury obsługi. Przerwania są wyłączone podczas trwania wyjątku.

INT 31H, AX=0204H, Pobranie wektora przerwania
Wejście:
    BL = numer przerwania
Wyjście:
    CF = 0
    CX:EDX = wektor przerwania (
SELEKTOR:OFFSET)

INT 31H, AX=0205H, Ustawienie wektora przerwania
Wejście:
    BL = numer przerwania
    CX:EDX = wektor przerwania (SELEKTOR:OFFSET)
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0300H, Symulacja przerwania trybu rzeczywistego
Wejście:
    BL = numer przerwania
    BH = flagi
    CX = ilość słów na stosie
    ES:EDI = struktura zawierająca rejestry
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0301H, Wywołanie procedury trybu rzeczywistego zakończonej dalekim powrotem
Wejście:
    BH = flagi
    CX = ilość słów na stosie
    ES:EDI = struktura zawierająca rejestry
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0302H, Wywołanie procedury trybu rzeczywistego zakończonej IRET
Wejście:
    BH = flagi
    CX = ilość słów na stosie
    ES:EDI = struktura zawierająca rejestry
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Funkcje 0300H-0302H służą do wykonywania kodu trybu rzeczywistego. Rejestr BH zawiera flagę (bit 0) która ustawiona oznacza przywrócenie standardowych ustawień kontrolera przerwań dla tego trybu (ignorowane w trybie V86). Rejestr CX zawiera liczbę słów do skopiowania ze stosu trybu chronionego do stosu trybu rzeczywistego. Adres w ES:EDI wskazuje na strukturę zawierającą wartości rejestrów przekazywane do trybu rzeczywistego. Po powrocie z funkcji struktura ta zawiera zmodyfikowane przez nią wartości.

STRUC WART_REJ

;rejestr EDI

EDI_REG DD ?

;rejestr ESI

ESI_REG DD ?

;rejestr EBP

EBP_REG DD ?

;zarezerwowane

ZAREZ DD ?

;rejestr EBX

EBX_REG DD ?

;rejestr EDX

EDX_REG DD ?

;rejestr ECX

ECX_REG DD ?

;rejestr EAX

EAX_REG DD ?

;rejestr FLAGS

FLAGS DD ?

;rejestr ES

ES_REG DW ?

;rejestr DS

DS_REG DW ?

;rejestr FS

FS_REG DW ?

;rejestr GS

GS_REG DW ?

;rejestr IP

IP_REG DW ?

;rejestr CS

CS_REG DW ?

;rejestr SP

SP_REG DW ?

;rejestr SS

SS_REG DW ?

ENDS WART_REJ

INT 31H, AX=0303H, Alokacja adresu call-back
Wejście:
    DS:ESI = adres procedury trybu chronionego
    ES:EDI = struktura zawierająca rejestry
Wyjście jeżeli CF=0:
    CX:DX = adres trybu rzeczywistego
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Adresy call-back służą do przekazywania kontroli procedurom trybu chronionego z poziomu trybu rzeczywistego. Rejestry DS:ESI zawierają adres procedury która zostanie wywołana. ES:EDI jest wskaźnikiem do struktury w której przekazane zostaną rejestry. Para CX:DX zwraca adres trybu rzeczywistego który może być np. wektorem przerwania 21H. Wtedy po każdym wystąpieniu tego przerwania kontrol zostanie przekazana do procedury trybu chronionego.

INT 31H, AX=0304H, Zwolnienie adresu call-back
Wejście:
    CX:DX = adres trybu rzeczywistego
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0305H, Pobranie adresów zapisu/odczytu stanu
Wejście:
    Nie ma
Wyjście jeżeli CF=0:
    AX = rozmiar bufora zapisu stanu
    BX:CX = adres dla trybu rzeczywistego
    SI:EDI = adres dla trybu chronionego
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Funkcja zwraca adresy procedur dla trybu rzeczywistego i chronionego które służą do zapisania stanu rejestrów w odrębnym trybie (np. funkcja wywołana w trybie rzeczywistym zapisuje stan dla trybu chronionego) zanim przełączenie między trybami spowoduje ich zmianę. Nie jest wymagane zapisanie stanu przy użyciu funkcji 0300H-0302H, może być jednak użyteczne przy "surowym" przełączeniu.

Zapisanie/odczytanie stanu
Wejście:
    ES:EDI = bufor zapisu stanu
    AL = 0 zapis
anie stanu
    AL = 1 odczytanie stanu

INT 31H, AX=0306H, Pobranie adresów "surowego" przełączania między trybami
Wejście:
    Nie ma
Wyjście jeżeli CF=0:
    BX:CX = adres dla trybu rzeczywistego
    SI:EDI = adres dla trybu chronionego
Wyjście jeże
li CF=1:
    Nie ma

Uwaga! Funkcja pobiera adresy procedur przełączających między trybami. Przełączenie w ten sposób nie zapewnia zapisania stanu i żadnych dodatkowych operacji, lecz jest proporcjonalnie szybkie.

"Surowe" przełączenie między trybami
Wejście:
    AX = nowy DS
    CX = nowy ES
    DX = nowy SS
    EBX = nowy ESP
    SI = nowy CS
    EDI = nowy EIP

INT 31H, AX=0400H, Pobranie wersji DPMI
Wejście:
    Nie ma
Wyjście:
    CF = 0
    AX = wersja DPMI
    BX = flagi
    CL = typ procesora
    CL = 02H - 80286
    CL = 03H - 80386
    CL = 04H - 80486
    DH = wektor układu master kontrolera przerwań sprzętowych
    DL = wektor układu slave kontrolera przerwań sprzętowych

Uwaga! Rejestr BX zawiera następujące flagi:
bit 0 - ustawiony dla 32-bitowych implementacji
bit 1 - ustawiony dla wirtualnego środowiska DOSu
bit 2 - ustawiony jeżeli zaimplementowana jest pamięć wirtualna
bit 3 - zarezerwowany
Reszta bitów jest wyzerowana i zarezerwowana dla późniejszych implementacji.

INT 31H, AX=0500H, Pobranie informacji o wolnej pamięci
Wejście:
    ES:EDI = wskaźnik do zapisu informacji
Wyjście:
    CF = 0

Uwaga! Wskaźnik w ES:EDI powinien wskazywać 48-bajtowy obszar w której zapisana zostanie struktura przedstawiona poniżej. Jeżeli pamięć wirtualna nie jest zaimplementowana istotna jest tylko pierwsza wartość, reszta równa jest -1 (0FFFFFFFFH).

STRUC WOLNA_PAM

;długość największego wolnego bloku

NAJ_BLO DD ?

;maksymalna liczba możliwych stron

;do zaalokowania

MAX_NZB DD ?

;maksymalna liczba możliwych stron

;do zaalokowania i zablokowania

MAX_ZB DD ?

;liniowa przestrzeń w stronach

LIN_STR DD ?

;liczba niezablokowanych stron

NZB_STR DD ?

;liczba wolnych stron

WOL_STR DD ?

;liczba wszystkich stron

WSZ_STR DD ?

;wolna liniowa przestrzeń w stronach

WL_STR DD ?

;rozmiar pliku lub partycji wymiany stron

WYMIAN DD ?

;zarezerwowane

ZAREZ DD 3 DUP(?)

ENDS WOLNA_PAM

INT 31H, AX=0501H, Alokacja bloku pamięci
Wejście:
    BX:CX = rozmiar bloku w bajtach
Wyjście jeżeli CF=0:
    BX:CX = liniowy adres bloku
    SI:DI = uchwyt bloku
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0502H, Zwolnienie bloku pamięci
Wejście:
    SI:DI = uchwyt bloku
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0503H, Zmiana rozmiaru bloku pamięci
Wejście:
    BX:CX = nowy rozmiar bloku w bajtach
    SI:DI = uchwyt bloku
Wyjście jeżeli CF=0:
    BX:CX = nowy liniowy adres bloku
    SI:DI = nowy uchwyt bloku
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0600H, Zablokowanie obszaru pamięci
Wejście:
    BX:CX = początkowy adres liniowy obszaru
    SI:DI = rozmiar obszaru
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Zablokowanie obszaru powoduje że nie może on być zapisany na dysk. W szczególności blokowane powinny być obszary zawierające procedury obsługi wyjątków, przerwań i ich stosów. DPMI przechowuje licznik blokowań obszaru, więc aby go odblokować trzeba to zrobić tyle razy ile nastąpiło zablokowanie. Funkcje dotyczące blokowania/odblokowania obszaru są istotne tylko w wypadku, gdy zaimplementowana jest pamięć wirtualna.

INT 31H, AX=0601H, Odblokowanie obszaru pamięci
Wejście:
    BX:CX = początkowy adres liniowy obszaru
    SI:DI = rozmiar obszaru
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0602H, Zaznaczenie obszaru pamięci bazowej jako podlegającego wymianie
Wejście:
    BX:CX = początkowy adres liniowy obszaru
    SI:DI = rozmiar obszaru
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Funkcja wyznacza, które obszary pamięci bazowej mogą podlegać wymianie (standardowo cała pamięć bazowa jest zablokowana).

INT 31H, AX=0603H, Zaznaczenie obszaru pamięci bazowej jako nie podlegającego wymianie
Wejście:
    BX:CX = początkowy adres liniowy obszaru
    SI:DI = rozmiar obszaru
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0604H, Pobranie rozmiaru strony fizycznej
Wejście:
    Nie ma
Wyjście jeżeli CF=0:
    BX:CX = rozmiar strony
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0702H, Ustawienie stron do wymiany w pierwszej kolejności
Wejście:
    BX:CX = początkowy adres liniowy stron
    SI:DI = ilość bajtów do zaznaczenia
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0703H, Usunięcie zawartości stron
Wejście:
    BX:CX = początkowy adres liniowy stron
    SI:DI = ilość bajtów do usunięcia
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0800H, Odwzorowanie adresu fizycznego
Wejście:
    BX:CX = adres fizyczny obszaru pamięci
    SI:DI = wielkość obszaru
Wyjście jeżeli CF=0:
    BX:CX = adres logiczny obszaru pamięci
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Funkcja powinna być używana tylko w przypadku konieczności odwzorowania adresu fizycznego zwracanego np. przez jakieś urządzenie (kartę graficzną, sieciową) na adres liniowy. Jeżeli pamięć wirtualna nie jest zaimplementowana adres fizyczny jest równoznaczny z adresem liniowym.

INT 31H, AX=0900H, Pobranie statusu i zablokowanie przerwań wirtualnych
Wejście:
    Nie ma
Wyjście:
    CF = 0
    AL = 0 jeżeli przerwania były zablokowane
    AL = 1 jeżeli przerwania były odblokowane

INT 31H, AX=0901H, Pobranie statusu i odblokowanie przerwań wirtualnych
Wejście:
    Nie ma
Wyjście:
    CF = 0
    AL = 0 jeżeli przerwania były zablokowane
    AL = 1 jeżeli przerwania były odblokowane

INT 31H, AX=0902H, Pobranie statusu przerwań wirtualnych
Wejście:
    Nie ma
Wyjście:
    CF = 0
    AL = 0 jeżeli przerwania były zablokowane
    AL = 1 jeżeli przerwania były odblokowane

Uwaga! Niektóre implementacje DPMI nie zezwalają na zablokowanie przerwań, w zamian przechowując status przerwań wirtualnych który pobieramy i zmieniamy funkcjami 0900H-0902H. Program może wykorzystać też instrukcje CLI i STI do zmiany statusu, lecz nie może go wyznaczać na podstawie rejestru FLAGS.

INT 31H, AX=0A00H, Pobranie adresu specyficznych funkcji
Wejście:
    DS:ESI = wskaźnik sygnatury
Wyjście jeżeli CF=0:
    ES:EDI = adres specyficznych funkcji
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Funkcja pobiera adres funkcji specyficznych dla danej implementacji DPMI. Funkcje te muszą być udokumentowane przez interfejs udostępniający je. Sygnatura służy rozpoznaniu konkretnego interfejsu. Składa się ona z znaków ASCII zakończonych znakiem NULL (00H). Funkcja ta w szczególnych przypadkach może modyfikować wszystkie podstawowe rejestry.

INT 31H, AX=0B00H, Ustawienie pułapki
Wejście:
    BX:CX = adres liniowy pułapki
    DL = rozmiar pułapki (1, 2 lub 4)
    DH = typ pułapki
    DH = 0 - wykonanie
    DH = 1 - zapisanie
    DH = 2 - odczytanie/zapisanie
Wyjście jeżeli CF=0:
    BX = uchwyt pułapki
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Funkcja wykorzystuje możliwości procesorów 386 i wyższych kontrolowania kodu i danych programu (rejestry uruchomieniowe DR0-DR7). Jeżeli pułapka jest typu "wykonywanie" jej rozmiar powinien wynosić 1.

INT 31H, AX=0B01H, Zwolnienie pułapki
Wejście:
    BX = uchwyt pułapki
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

INT 31H, AX=0B02H, Pobranie statusu pułapki
Wejście:
    BX = uchwyt pułapki
Wyjście jeżeli CF=0:
    AX = flagi
Wyjście jeżeli CF=1:
    Nie ma

Uwaga! Rejestr AX zawiera jedną flagę (bit 0). Jeżeli jest ona ustawiona oznacza to że pułapka została osiągnięta.

INT 31H, AX=0B03H, Wyzerowanie statusu pułapki
Wejście:
    BX = uchwyt pułapki
Wyjście jeżeli CF=0:
    Nie ma
Wyjście jeżeli CF=1:
    Nie ma

5.4.6. Alternatywny sposób alokacji

        Większość sterowników pamięci rozszerzonej udostępnia nam cały dostępny obszar, ograniczony jedynie rozmiarem fizycznie zainstalowanej pamięci. Co jednak zrobić, gdy jesteśmy autorami systemu operacyjnego, który jest w pełni niezależną od DOSu i jego sterowników platformą? Jak wiadomo BIOS zwraca nam rozmiar pamięci rozszerzonej, jednak maksymalna wartość jaką może nam przekazać to 64Mb, a obecnie "mocne" komputery (np. serwery) wyposażone są w dużo większą pamięć operacyjną. W takim przypadku należy stworzyć własną procedurę sprawdzającą rozmiar zainstalowanej pamięci.

        Aby dokonać sprawdzenia pamięci trzeba przełączyć procesor w tryb chroniony i stworzyć segment obejmujący całą dostępną czterogigową przestrzeń adresową (adres bazowy równy zero, limit równy 4Gb). Pamiętać należy o następujących warunkach które muszą być spełnione:

- mechanizm stronicowania pamięci musi być wyłączony,

- przerwania muszą być zablokowane,

- linia A20 musi być odblokowana,

- procedura testująca musi znajdować się w pierwszym megabajcie (ten obszar nie poddajemy testowi ze względu na obecność BIOSu),

- wyłączone muszą być mechanizmy urządzeń które podczepiają pamięć wewnętrzną (np liniowa ramka pamięci wideo).

Samo działanie procedury sprowadza się do przetestowania obecności jednego bajta z każdej kolejnej strony pamięci (o wielkości 4kb) poczynając od adresu 100000H (ominięcie pierwszego megabajta). Jeżeli wystąpi błąd, oznacza to że adres nie jest dostępny. Funkcję należy zakończyć po wykryciu pierwszego błędu. Oto prosty i skuteczny algorytm testowania pamięci:

.CODE

;przyjmujemy że rejestr DS wskazuje segment

;obejmujący całą przestrzeń 4Gb

MOV ESI,100000H-1000H

CLI

NAST:

ADD ESI,1000H

OR ESI,ESI

JE SHORT KONIEC

MOV AL,[ESI]

XOR AL,0FFH

MOV AH,AL

MOV [ESI],AL

MOV AL,[ESI]

XOR [BYTE PTR ESI],0FFH

CMP AL,AH

;jeżeli komórka w porządku skok

JE SHORT NAST

;komórka nie istnieje

;wyznaczenie górnego adresu

KONIEC:

STI

DEC ESI

;ESI = adres fizyczny najwyższej komórki

0x08 graphic

5.5. DOS extendery

        Określeniem DOS extender nazywamy program, który spełnia trzy podstawowe funkcje:
- ładuje klienta i wykonuje podstawowe czynności inicjalizacyjne,

- udostępnia klientowi środowisko trybu chronionego,

- udostępnia klientowi pamięć rozszerzoną.

        Zazwyczaj klientem extendera jest jeden program, na którego potrzeby ustawiane są rejestry i tablice systemowe. Extender nie jest częścią systemu DOS, dlatego każdy program powinien zapewniać obecność extendera, którego jest klientem. Dobrą metodą jest doklejanie kodu klienta do pliku extendera, lecz istnieją też extendery które nie udostępniają takiej możliwości. Do najpopularniejszych extenderów zaliczają się: DOS4GW, PMODE/W, WDOSX, czy DOS32.

        Interfejs jaki oferuje DOS extender zależy od jego twórców. Może to być zestaw dowolnych funkcji, najczęściej jednak funkcje te zgodne są ze standardem DPMI. Płynie z tego wiele korzyści. Po pierwsze DPMI posiada duży wachlarz funkcji, w zupełności wystarczający na potrzeby extendera. Po drugie nie trzeba tworzyć mechanizmów tłumaczenia funkcji extendera na funkcje DMPI i po trzecie nie trzeba pisać dokładnej dokumentacji, gdyż DPMI taką już posiada. Każdy extender, który oferuje dodatkowe funkcje może skorzystać z mechanizmu jaki oferuje funkcja 0A00H przerwania 31H.

        Pamiętać należy, że aby extender był dobry, powinien pracować w każdej konfiguracji systemu, dlatego też dobrze jest jeżeli obsługuje on wszystkie udokumentowane schematy alokacji pamięci rozszerzonej.

0x08 graphic

5.6. Funkcje BIOSu

        System BIOS oferuje trzy dosyć prymitywne funkcje związane z pamięcią rozszerzoną. Ich użyteczność (poza funkcją 88H używaną w schemacie TOP-DOWN) jest raczej wątpliwa.

INT 15H, AH=87H, Skopiowanie bloku pamięci rozszerzonej
Wejście:
    CX = ilość słów do skopiowania (maksymalnie 8000H)
    ES:SI = adres tablicy GDT
Wyjście jeżeli CF=0:
    AH = 0
Wyjście jeżeli CF=1:
    AH = kod błędu

Uwaga! Podczas działania funkcji przerwania są wyłączone. Globalna tablica deskryptorów powinna wyglądać jak poniżej. Bajt praw dostępu deskryptorów powinien być równy 93H.

00H - deskryptor zarezerwowany
08H - deskryptor zarezerwowany
10H - deskryptor obszaru źródłowego
18H - deskryptor obszaru docelowego
20H - deskryptor zarezerwowany
28H - deskryptor zarezerwowany

INT 15H, AH=88H, Odczytanie rozmiaru pamięci rozszerzonej
Wejście:
    Nie ma
Wyjście jeżeli CF=0:
    AX - rozmiar pamięci w kilobajtach
Wyjście jeżeli CF=1:
    Nie ma

INT 15H, AH=89H, Przełączenie do trybu chronionego
Wejście:
    BH = wektor układu PIC master (IRQ0-IRQ7)
    BL = wektor układu PIC slave (IRQ8-IRQ15)
    ES:SI = adres tablicy GDT
Wyjście jeżeli CF=0:
    AH = 0
Wyjście jeżeli CF=1:
    AH = 0FFH

Uwaga! Rejestr BX zawiera wektory kontrolera przerwań sprzętowych. Globalna tablica deskryptorów powinna zawierać przynajmniej 8 deskryptorów w kolejności przedstawionej poniżej (ostatni deskryptor jest inicjowany przez BIOS):

00H - deskryptor pusty
08H - deskryptor GDT
10H - deskryptor IDT
18H - deskryptor segmentu danych (DS)
20H - deskryptor segmentu danych (ES)
28H - deskryptor segmentu stosu (SS)
30H - deskryptor segmentu kodu (CS)
38H - deskryptor BIOSu

0x08 graphic

5.7. Instalacja sterowników

        Poniżej znajduje się krótki opis instalacji sterownika XMM (eXtended Memory Manager) implementującego pamięć XMS oraz EMM (Expanded Memory Manager) implementującego pamięć EMS. Opis dotyczy standardowych sterowników rozpowszechnianych wraz z systemem DOS.

XMM

Sterownik XMM znajduje się w pliku HIMEM.SYS. Aby go zainstalować, należy umieścić stosowną linię w pliku CONFIG.SYS. Jej postać ukazana jest poniżej (w nawiasach kwadratowych podane są opcjonalne parametry):

DEVICE=[dysk:][ścieżka]HIMEM.SYS [/HMAMIN=n] [/NUMHANDLES=n] [/INT15=n] [/MACHINE=n] [/A20CONTROL:ON|OFF] [/EISA] [/SHADOWRAM:ON|OFF] [/VERBOSE]

        Poniżej znajduje się opis wszystkich parametrów sterownika XMM:

/HMAMIN=n - parametr n (podawany w kilobajtach) określa minimalny rozmiar pamięci wysokiej. Program który żąda przydziału tej pamięci musi podać rozmiar wykorzystywanego przez siebie obszaru. W przypadku gdy rozmiar ten będzie mniejszy niż wartość parametru HMAMIN pamięć HMA nie zostanie przydzielona. Domyślą wartością jest 0, co oznacza że pamięć przydzielona zostanie pierwszemu programowi który jej zażąda.

/NUMHANDLES=n - parametr n jest liczbą z zakresu 1-128 i oznacza ilość uchwytów bloków EMB. Za każdym razem gdy wystąpi żadanie przydziału bloku pamięci rozszerzonej, przydzielany jest automatycznie uchwyt będący identyfikatorem bloku. W przypadku braku dostępnego uchwytu blok nie zostanie przydzielony. Domyślną wartością jest 32.

/INT15=n - parametr n (podawany w kilobajtach) jest liczbą z zakresu 64-65536 i oznacza ilość pamięci dostępnej dla schematu alokacji TOP-DOWN (INT 15). Domyślną wartością jest 0.

/MACHINE=n - parametr n jest kodem, który oznacza system sterowania linią A20, zależny od platformy sprzętowej. Powinien być używany w przypadku stwierdzenia problemu obsługi lini A20 przez sterownik XMM.

/A20CONTROL:ON|OFF - opcja ta determinuje w jakim przypadku kontrola nad stanem lini A20 zostanie przejęta przez sterownik XMM. Wartość ON oznacza bezwarunkowe przejęcie kontroli, natomiast wartość OFF tylko w przypadku gdy linia A20 była wcześniej zablokowana. Domyślną wartością jest ON.

/EISA - opcja ta informuje sterownik XMM, że architektura systemu jest zgodna ze standardem EISA.

/SHADOWRAM:ON|OFF - opcja ta determinuje przyłączenie obszaru shadow RAM do obsługiwanych bloków pamięci górnej. Wartość OFF oznacza dołączenie shadow RAM do UMB. Dla komputerów z pamięcią poniżej 2Mb domyślną wartością jest OFF.

/VERBOSE - opcja ta wymusza wyświetlanie wszelkich komunikatów.

EMM

Sterownik EMM znajduje się w pliku EMM386.EXE. Aby go zainstalować, należy umieścić stosowną linię w pliku CONFIG.SYS. Jej postać ukazana jest poniżej (w nawiasach kwadratowych podane są opcjonalne parametry):

DEVICE=[dysk:][ścieżka]EMM386.EXE [ON|OFF|AUTO] [memory] [MIN=n] [W=ON|OFF] [Mn|FRAME=n|/Pn] [Pn=m] [X=n-m] [I=n-m] [B=n] [L=n] [D=n] [A=n] [H=n] [RAM=n-m] [NOEMS] [NOVCPI] [HIGHSCAN] [VERBOSE] [WIN=n-m] [NOHI] [ROM=n-m] [NOMOVEXBDA] [ALTBOOT]

        Poniżej znajduje się opis wszystkich parametrów sterownika EMM:

ON|OFF|AUTO - za pomocą tych parametrów można określić tryb pracy sterownika EMM. Parametry ON/OFF włączają/wyłączają mechanizmy obsługi pamięci EMS. Parametr AUTO włącza je w chwili zażądania przydziału pamięci. Domyślny jest parametr ON.

memory - parametr memory (podawany w kilobajtach) jest liczbą z zakresu 64-32768. Określa on maksymalny rozmiar pamięci XMS wykorzystywanej do implementacji pamięci EMS i VCPI. Domyślnie sterownik wykorzystuje całą dostępną pamięć.

MIN=n - parametr n (podawany w kilobajtach) jest liczbą z zakresu 64-memory. Określa on minimalny rozmiar pamięci XMS wykorzystywanej do implementacji pamięci EMS i VCPI. Obszar ten jest automatycznie alokowany co zmniejsza rozmiar pamięci XMS. Domyślną wartością jest 256.

W=ON|OFF - parametr ON uatywnia a OFF blokuje obsługę koprocesora Weitek.

Mn|FRAME=n|/Pn - parametry określają adres segmentowy ramki stron. Dla M parametr n jest kodem z zakresu 1-14 za którym kryje się zdefiniowany adres. Dla FRAME i P parametr n jest adresem segmentowym z zakresu 8000H-9000H i C000H-E000H (będącym wielokrotnością 400H). Dodatkowo dla FRAME n może mieć wartość NONE która uniemożliwia stworzenie ramki.

Pn=m - definiuje adres segmentowy strony fizycznej. Parametr n jest numerem strony z zakresu 0-255 natomiast m jest adresem segmentowym z zakresu 8000H-9C00H i C000H-EC00H (będącym wielokrotnością 400H). Strony 0-3 muszą występować po sobie kolejno i nie można ich definiować w przypadku podania adresu ramki stron (Mn|FRAME=n|/Pn).

X=n-m - blokuje tworzenie ramki stron w obszarze od adresu n do adresu m. Zakres adresów wynosi od A000H-0FFFFH. Opcja ta ma wyższy priorytet od I=n-m.

I=n-m - definiuje obszar od adresu n do adresu m w którym możliwe jest utworzenie ramki stron. Zakres adresów wynosi od A000H-0FFFFH.

B=n - parametr n określa najniższy adres segmentowy obszaru z zakresu 1000H-4000H, w którym może nastąpić wymiana stron. Domyślną wartością jest 4000H.

L=n - parametr n (podawany w kilobajtach) określa minimalny obszar pamięci XMS, która nie zostanie wykorzystana do implementacji pamięci EMS i VCPI. Domyślną wartością jest 0.

D=n - parametr n (podawany w kilobajtach) jest liczbą z zakresu 16-256 i określa rozmiar pamięci wykorzystywanej jako bufor transmisji DMA. Domyślną wartością jest 16.

A=n - parametr n jest liczbą z zakresu 0-254 i rezerwuje liczbę grup rejestrów przeznaczonych do realizacji wielozadaniowości. Domyślną wartością jest 7. Każda grupa zajmuje ok. 200 bajtów.

H=n - parametr n jest liczbą z zakresu 2-255 określającą liczbę uchwytów. Domyślną wartością jest 64.

RAM=n-m - definiuje obszar od adresu n do adresu m, który zostanie wykorzystany na bloki UMB i obsługę pamięci EMS. Domyślnie sterownik wykorzystuje cały dostępny obszar pamięci górnej.

NOEMS - wyłącza obsługę pamięci EMS.

NOVCPI - wyłącza obsługę interfejsu VCPI. Opcja musi być podana w połączeniu z opcją NOEMS. W przypadku jej podania ignorowane są parametry memory i MIN.

HIGHSCAN - opcja nakazuje przeszukanie obszarów BIOSu w celu znalezienia dodatkowych niewykorzystanych przez BIOS bloków pamięci.

VERBOSE - opcja ta wymusza wyświetlanie wszelkich komunikatów.

WIN=n-m - definiuje obszar od adresu n do adresu m do wykorzystania przez system Windows. Zakres adresów wynosi od A000H-0FFFFH. Opcja X=n-m ma wyższy priorytet, natomiast opcje RAM=n-m, ROM=n-m oraz I=n-m niższy.

NOHI - blokuje ładowanie sterownika EMM do pamięci górnej.

ROM=n-m - definiuje obszar od adresu n do adresu m który wykorzystany będzie na pamięć shadow RAM. Zakres adresów wynosi od A000H-0FFFFH.

NOMOVEXBDA - blokuje przesunięcie obszaru dodatkowych danych BIOSu z pamięci bazowej do pamięci górnej.

ALTBOOT - nakazuje przejęcie kontroli nad restartem systemu (w momencie naciśnięcia kombinacji CTRL-ALT-DEL).

2



Wyszukiwarka

Podobne podstrony:
Przenoszenie plików systemowych do pamięci operacyjnej
8 Systemy Operacyjne 21 12 2010 Zarządzanie Pamięcią Operacyjną
PAMIECI OPERACYJNE QULCAZM6ZU7S Nieznany
9 Systemy Operacyjne 04 01 2011 Zarządzanie Pamięcią Operacyjną2
Pamięć operacyjna
Katechizm WINDOWS, 11 Pamięć operacyjna
Pamięć w operacjach
Pamiec operacyjna
Błędy w pamięciach operacyjnych
pamiec operacyjna bns
Zarządzanie pamięcią operacyjną
05 Model pamięci operacyjnej Pamięć dłu gotrwała wprowadzenieid 5541 ppt
3 Pamięć operacyjna
Wrocław Sedek10 rola pamieci operacyjnej (OSPAN)
Pamięć operacyjna
USB niekompatybilne z ReadyBoost Możliwość wykorzystania tanich przenośnych pamięci USB jako rozs
Maruszewski Świadomość, pamięć operacyjna i emocje str 83 97

więcej podobnych podstron