osdev.labedz.org

Troche teorii..

Procesor Intel386 przekształca adres logiczny (adres jaki widzi programista) w adres fizyczny (fizyczny adres komórki pamięci) w dwóch krokach:

  • translacja segmentacji, w której adresy logiczne (złożone z selektora segmentu i przesunięcia) są przekształcane w adres liniowy
  • translacja stronicowania, w której adresy liniowe są przekształcane w adresy fizyczne. Ten krok jest opcjonalny - w zależności od konstrukcji systemu.

Przekształcenia te są realizowane w sposób niewidoczny dla programisty aplikacji.

Tworzenie adresu fizycznego w trybie chronionym
Rys. Tworzenie adresu fizycznego w trybie chronionym

Translacja segmentacji

W celu wykonania translacji segmentacji procesor potrzebuje następujących struktur danych:

  • deskryptorów
  • tablic deskryptorów
  • selektorów
  • rejestrów segmentowych

Deskryptory segmentowe dostarczają procesorowi danych niezbędnych do przekształcenia adresu logicznego w adres liniowy. Tworzone są one przez programy kompilatora, konsolidatora, programy ładowania systemu lub przez system operacyjny. Operacje na deskryptorach, z założenia, nie występują w programach aplikacyjnych. Rysunki przedstawiają dwa podstawowe formaty deskryptorów - pozostałe rodzaje deskryptorów są ich pochodnymi.

Ogólny format deskryptorów - deskryptor segmentów danych i kodu aplikacji
Rys. Ogólny format deskryptorów - deskryptor segmentów danych i kodu aplikacji
Ogólny format deskryptorów - deskryptor specjalnych segmentów systemowych
Rys. Ogólny format deskryptorów - deskryptor specjalnych segmentów systemowych

Opis pól deskryptorów:

  • Adres bazowy segmentu - określa położenie segmentu w 4GB przestrzeni adresowej. Procesor łączy trzy fragmenty adresu bazowego w jeden 32-bitowy.
  • Limit segmentu - określa rozmiar segmentu. Procesor łączy dwa fragmenty limitu w jeden 20-bitowy. Wartość tego pola jest interpretowana w zależności od ustawienia bitu ziarnistości:
    • w bajtach - możliwość ustawienia limitu do jednego megabajta
    • w jednostkach po 4 KB - możliwość ustawienia limitu do 4 GB. W tym przypadku wartość limitu jest przesuwana w lewo o 12 bitów, a wartość najmniej znaczących bitów wynosi 1
  • G bit ziarnistości - określa sposób interpretowania wartości limitu segmentu. Kiedy bit wynosi 0 limit jest liczony w bajtach, gdy wartość wynosi 1 limit jest liczony po 4KB
  • Typ segmentu - określa rodzaj segmentu spośród kilku możliwych
  • DPL poziom uprzywilejowania deskryptora (ang. descriptor privilege level) - używany przez mechanizm ochrony zasobów (patrz podpunkt II rozdziału)
  • P - bit 'obecności' - jeśli posiada wartość zero deskryptor nie jest odpowiedni do używania w transformacji adresów. Jeśli taki deskryptor zostanie użyty procesor wywoła wyjątek. Bit ten jest używany, gdy stosowana jest mechanizm pamięci wirtualnej opartej na wymianie segmentów. Wartość tego bitu jest zmieniana na '0' gdy przestrzeń adresowa zajmowana przez dany segment nie jest pokryta przez mechanizm wymiany, lub gdy dany segment nie jest obecny w pamięci.
  • AVL - bity nie używane przez procesor - możliwość ich wykorzystania w systemie operacyjnym
  • A - bit dostępu - procesor ustawia ten bit, gdy dany segment jest 'używany'; np. selektor tego deskryptora jest załadowany do rejestru segmentowego lub jest testowany instrukcją testującą selektor. Bit ten może też być używany przez mechanizm wymiany segmentów do sprawdzenia częstotliwości dostępu do tego segmentu. Traktowany też jako jeden z bitów 'typu'.

Gdzie te deskryptory są przechowywane?

Deskryptory segmentów są przechowywane w tablicach deskryptorów dwóch rodzajów:

  • globalnej tablicy deskryptorów (GDT)
  • lokalnej tablicy deskryptorów (ang. local descriptor table - LDT)

Istnieje również tablica deskryptorów przerwań, jednak nie bierze ona udziału w translacji pamięci.

Tablica deskryptorów jest to po prostu obszar pamięci wypełniony 8-bajtowymi wpisami zawierającymi deskryptory. Posiada ona zmienną wielkość i maksymalnie może pomieścić do 8192 (2^13) deskryptorów. Pierwszy wpis w tablicy (indeks = '0') GDT jest nieużywany i powinien być wypełniony zerami. Jest to tak zwany deskryptor zerowy (ang. null descriptor).

Procesor wie o położeniu tablic GDT i LDT dzięki wartościom rejestrów GDTR i , które wskazują adresy bazowe tablic w liniowej przestrzeni adresowej. Rejestry te jednocześnie przechowują wielkość tablicy deskryptorów.

Selektor

Selektor jest częścią adresu logicznego i określa, który z deskryptorów powinien być użyty. Selektory są widoczne dla programu aplikacji, lecz ich wartości są najczęściej ustawiane przez program konsolidatora, program ładujący system, bądź też przez sam system operacyjny. Format selektora przedstawia poniższy rysunek:

Format selektora
Rys. Format selektora

Opis pól selektora:

  • Indeks - wybór jednego z 8192 deskryptorów w tablicy deskryptorów. Procesor, aby otrzymać adres odpowiedniego wpisu, mnoży wartość indeksu przez 8 (wielkość deskryptora), a następnie dodaje wynik do adresu bazowego odpowiedniej tablicy deskryptorów.
  • TI wskaźnik tablicy (ang. table indicator) - określa do której tablicy deskryptorów odnosi się dany selektor; wartość zerowa oznacza GDT, wartość jeden oznacza LDT.
  • RPL żądany poziom uprzywilejowania (ang. requested privilege level) - używany przez mechanizm ochrony zasobów (patrz podpunkt II rozdziału)

Ponieważ pierwszy wpis w GDT jest nie używany przez procesor, selektor który posiada zerową wartość indeksu może służyć jako selektor zerowy (ang. null selector). Procesor wywoła wyjątek jedynie po załadowaniu takiego selektora do rejestrów CS i SS. Wyjątek wystąpi jednak, gdy taki selektor zostanie użyty do adresacji pamięci.

Procesor Intel386 przechowuje informacje z używanych deskryptorów w rejestrach segmentowych, dzięki czemu unika się częstego odwoływania do obszaru pamięci z tablicą deskryptorów. Każdy rejestr segmentowy dzieli się na część widoczną i niewidoczną dla programisty. Część widoczna jest dostępna z poziomu aplikacji tak jakby była zwyczajnym rejestrem 16-bitowym, część niewidoczna jest obsługiwana tylko i wyłącznie przez procesor. Po załadowaniu rejestru segmentowego (zwyczajne instrukcje bezpośrednie typu MOV, POP, LxS, czy też instrukcje odwołujące się do rejestru CS typu CALL, JMP) procesor pobiera automatycznie adres bazowy, wartość limitu, typ, oraz inne informacje z tablicy deskryptorów i zachowuje je w części niewidocznej rejestru.

Translacja segmentacji
Rys. Translacja segmentacji

Proces translacji adresu logicznego na adres liniowy polega (w skrócie) na zsumowaniu przez procesor adresu bazowego (pobranego z określonego przez selektor deskryptora segmentu) z wartością przesunięcia adresu logicznego. Powstała wartość jest adresem liniowym.