Zarządzanie pamięcią w 32 i 64-bitowych systemach Windows, cz. II .png)
Windows 2000/XP/2003/Vista/2008
Autor: Jacek Światowiak
Opublikowano: 11 grudnia 2007
Zawartość strony
![]() |
W poprzedniej części |
![]() |
Systemowe struktury danych trybu chronionego |
![]() |
Segmentacja |
![]() |
Selektor |
![]() |
Deskryptor |
![]() |
Rejestr Globalnej tablicy deskryptorów |
![]() |
Rejestr lokalnej tablicy deskryptorów |
![]() |
Przeczytaj pozostałe części tego artykułu |
W poprzedniej części
Omówiono ogólnie tryby pracy procesora zgodnego z i386 w tym adresowanie w trybie rzeczywistym i chronionym, przedstawiono pojęcie adresacji logicznej, liniowej i fizycznej. Zaprezentowano zastosowanie rejestrów procesora, oraz ogólnie mechanizm współpracy z pamięcią.
Do początku strony
Systemowe struktury danych trybu chronionego
W trybie z ochroną procesor musi mieć dostęp do specjalnych struktur danych (umieszczonych w pamięci). Te struktury danych to:
- tablica opisu segmentów globalnych – GDT (istnieje tylko jedna),
- tablice opisu segmentów lokalnych – LDT (przypisane poszczególnym zadaniom lub grupom zadań),
- tablica wektorów (deskryptorów) przerwań – IDT (istnieje tylko jedna),
- segmenty stanu zadania – TSS (ang. Task State Segment),
Procesor wykorzystuje zestaw rejestrów wewnętrznych ładowanych zmiennymi systemowymi z pamięci. Zmienne te to:
- Deskryptory aktualnie używanych segmentów CS, DS, SS, ES,
- Adres bazowy (początkowy) i długość tablicy opisu segmentów globalnych – GDT,
- Adres bazowy (początkowy) i długość tablicy opisu segmentów lokalnych – LDT,
- Indeks (w tablicy GDT) deskryptora aktualnej tablicy LDT,
- Indeks (w tablicy GDT lub LDT) deskryptora segmentu TSS aktualnie wykonywanego zadania (procesu, aplikacji),
- Adres bazowy (początkowy) i długość segmentu TSS,
- Indeks (w tablicy GDT lub LDT) deskryptora bieżącego zadania
- Adres bazowy (początkowy) i długość tablicy wektorów przerwań.
Uwaga
Rejestry zawierające zmienne oznaczone jako 1, 2 i 6 są niedostępne dla programisty.
Do początku strony
Segmentacja
Dla trybu 32-bitowego z ochroną. Rejestr segmentowy, który w trybie rzeczywistym wskazuje adres bazowy segmentu, jest tu ładowany pewnym wskaźnikiem zwanym deskryptorem segmentu.
Procesor wyposażony jest w cztery rejestry segmentowe i każdy z nich wykorzystywany jest do obsługi odrębnych zadań systemowych.
GDTR – rejestr deskryptorów globalnych – ang. Global Descriptor Table Register
LDTR – rejestr deskryptorów lokalnych – ang. Local Descriptor Table Register
IDTR – rejestr deskryptorów przerwań – ang. Interrrupt Descriptor Table Register
TR – rejestr zadań – ang. Task Register
Rys. 2.1. Format ogólny rejestru GDTR i IDTR.
Rys. 2.2. Format ogólny rejestru LDTR i TR. Część pogrubiona – to cześć widoczna .
Każdy z rejestrów segmentowych podzielony jest na część widoczną (dostępną) dla programisty i część ukrytą (niewidoczną). Dla każdej aplikacji (procesu) dysponujemy 6 rejestrami segmentowymi. Aby zaadresować dany fragment pamięci dla danej aplikacji należy wstępnie wybrać typ segmentu dla kodu, danych czy stosu. Wybór danego typu segmentu de facto skutkuje wybraniem do procesu obliczenia adresu efektywnego konkretnego rejestru segmentowego.
W trybie rzeczywistym rejestr segmentowy zawierał adres bazowy danego segmentu. W trybie z ochroną pełni rolę selektora i zawiera indeks tablicy deskryptorów globalnych GDT (ang. Global Descriptor Table) lub lokalnych LDT (ang. Local Descriptor Table).
Selektor wskazuje więc bezpośrednio na deskryptor segmentu, a pośrednio na segment. Deskryptory segmentów są umieszczane w pamięci, kolejno tworząc tzw. tablice deskryptorów (ang. Descriptor Table). Wykonywany program ma dostęp do dwóch tablic deskryptorów: globalnej tablicy deskryptorów GDT (ang. Globar Descriptor Table) i lokalnej tablicy deskryptorów LDT (ang. Local Descriptor Table). Takie podejście umożliwia realizacje ochrony pamięci w systemach wielozadaniowych. W systemie może istnieć zatem wiele tablic LDT. Każde zadanie, proces, wątek ma swoją własną tablicę deskryptorów.
Do początku strony
Selektor
Ogólny format selektora przedstawiony jest niżej:
Rys. 2.3. Selektor ładowany do rejestru segmentowego.
Gdzie:
RPL – oznacza poziom ochrony (ang. Requestor’s Privilege Level) – omówiony zostanie oddzielnie
TI – wskaźnik tablicy (ang. Table Indicator),
O – oznacza, iż deskryptor odnosi się do globalnej tablicy deskryptorów,
1 - oznacza tablicę lokalną,
Numer deskryptora – 13-bitowe pole. Zatem każda z tablic może zawierać do 8192 deskryptorów.
Uwaga
W ukrytym rejestrze związanych z rejestrem segmentowym zawarty jest wyliczony automatycznie adres bazowy (ang. Segment Base Address) i wielkość (ang. Segment Size) segmentu wskazanego przez selektor oraz dodatkowe atrybuty używane przez mechanizmy ochrony procesora.
Pola Segment Size i Segment Base Address są liczbami 32 bitowymi (lub 64-bitowymi – dla trybu 64-bitowego).
Do początku strony
Deskryptor
Deskryptor jest 8-bajtowym rekordem opisującym m.in. położenie i wielkość danego segmentuw pamięci.
Rys. 2.4. Generalny format deskryptora segmentu.
Dla segmentu danych bity 8, 9 i 10 oznaczane są również, jako:
A – Accessed
W – Write Enable
E – Expansion-Direction.
Dla segmentu kodu bity 8, 9 i 10 oznaczane są również, jako:
A – Accessed
R – Read Enabled
C - Conforming
Tabela 2. Konfiguracje bitów 8-11 a właściwości operacji przeprowadzanych na segmentach kodu i danych | ||||||
Wartość dziesiętnie | Bit 11 | Bit 10 | Bit 9 | Bit 8 | Typ segmentu | Opis |
E | W | A | ||||
0 | 0 | 0 | 0 | 0 | Dane | tylko odczyt |
1 | 0 | 0 | 0 | 1 | Dane | odczyt i dostęp |
2 | 0 | 0 | 1 | 0 | Dane | odczyt i zapis |
3 | 0 | 0 | 1 | 1 | Dane | odczyt, zapis, dostęp |
4 | 0 | 1 | 0 | 0 | Dane | segment rozszerzalny w dół – tylko odczyt |
5 | 0 | 1 | 0 | 1 | Dane | segment rozszerzalny w dół – odczyt i dostęp |
6 | 0 | 1 | 1 | 0 | Dane | segment rozszerzalny w dół – odczyt i zapis |
7 | 0 | 1 | 1 | 1 | Dane | segment rozszerzalny w dół – odczyt, zapis i dostęp |
C | R | A | ||||
8 | 1 | 0 | 0 | 0 | Kod | tylko wykonywanie |
9 | 1 | 0 | 0 | 1 | Kod | wykonywanie i dostęp |
10 | 1 | 0 | 1 | 0 | Kod | wykonywanie i odczyt |
11 | 1 | 0 | 1 | 1 | Kod | wykonywanie, odczyt i dostęp |
12 | 1 | 1 | 0 | 0 | kod | tylko wykonywanie – segment zgodny |
13 | 1 | 1 | 0 | 1 | Kod | wykonywanie i dostęp – segment zgodny |
14 | 1 | 1 | 1 | 0 | Kod | wykonywanie i odczyt – segment zgodny |
15 | 1 | 1 | 1 | 1 | Kod | Wykonywanie, odczyt i dostęp – segment zgodny |
S – (ang. Segment Descriptor System/Code and Data) - rodzaj segmentu
Gdzie:
1 – oznacza segmenty pamięci – kodu lub danych,
0 – oznacza segmenty specjalne (tzw. systemowe struktury danych) i furtki (ang. Gates),
Systemowe segmenty zostały podzielone na następujące kategorie:
- lokalne tablicy deskryptorów LDT (ang. Local Descriptor Table)
- deskryptory stanu zadania TSS (ang. Task-State segment)
- deskryptory furtek wywołania (ang. Call-Gate descriptor)
- furtki przerwań (ang. Interrupt-Gate descriptor)
- furtki potrzasku (ang. Trap-Gate descriptor)
- furtki zadań (ang. Task-Gate descriptor)
Dla S=0 dostępne są następujące typy segmentów:
Tabela 3. Segmenty systemowe | ||||||
Wartość dziesiętnie | Bit 11 | Bit 10 | Bit 9 | Bit 8 | Tryb IA-32 (32-bitowy) | Tryb IA-32e ( 64-bitowy) |
0 | 0 | 0 | 0 | 0 | Zarezerwowany | Górny 8 lub 16-bajtowy deskryptor |
1 | 0 | 0 | 0 | 1 | 16-bit TSS (dostępne) | Zarezerwowany |
2 | 0 | 0 | 1 | 0 | LDT | LDT |
3 | 0 | 0 | 1 | 1 | 16-bit TSS (zajęte) | Zarezerwowany |
4 | 0 | 1 | 0 | 0 | 16-bit Call-Gate | Zarezerwowany |
5 | 0 | 1 | 0 | 1 | Task Gate | Zarezerwowany |
6 | 0 | 1 | 1 | 0 | 16-bit Interrupt-Gate | Zarezerwowany |
7 | 0 | 1 | 1 | 1 | 16-bit Trap-Gate | Zarezerwowany |
8 | 1 | 0 | 0 | 0 | Zarezerwowany | Zarezerwowany |
9 | 1 | 0 | 0 | 1 | 32-bit TSS (dostępne) | 64-bit TSS (dostępne) |
10 | 1 | 0 | 1 | 0 | Zarezerwowany | Zarezerwowany |
11 | 1 | 0 | 1 | 1 | 32-bit TSS (zajęte) | 64-bit TSS (zajęte) |
12 | 1 | 1 | 0 | 0 | 32-bit Call-Gate | 64-bit Call-Gate |
13 | 1 | 1 | 0 | 1 | Zarezerwowany | Zarezerwowany |
14 | 1 | 1 | 1 | 0 | 32-bit Interrupt-Gate | 64-bit Interrupt-Gate |
15 | 1 | 1 | 1 | 1 | 32-bit Trap-Gate | 64-bit Trap-Gate |
DPL – (ang. Descriptor Privilage Level) - poziom ochrony opisywanego segmentu – opisany zostanie oddzielnie,
P - (ang. Present) - segment obecny,
AVL – (ang. Available to software) - pole dostępne dla programu (nie wykorzystywane wewnętrznie przez procesor),
D (czasami oznaczany jako B - BIG) – (ang. Default) - bit długości słowa. Ma znaczenie tylko w segmentach kodu, rozszerzalnych w dół, albo w segmentach adresowanych za pomocą rejestru SS. Krótko mówiąc oznacza naturalną dla danego trybu pracy procesora długość wykorzystywanych argumentów (16 lub 32 bitowe).
W przypadku segmentu kodu: D=1 oznacza stosowanie 32-bitowego przemieszczenia w adresie argumentu oraz 32-bitowych (obok 8-bitowych) argumentów, D=0 oznacza stosowanie 16-bitowego przemieszczenia w adresie argumentu oraz 16-bitowych (obok 8-bitowych) argumentów, |
W przypadku segmentu rozszerzalnego w dół, oznacza największe możliwe przemieszczenie w obrębie segmentu: D=1 oznacza przemieszczenie 4 GB D=0 oznacza przemieszczenie 64 KB |
Ważne:
W przypadku operacji z wykorzystaniem segmentu stosu SS:
D=1 oznacza, iż w operacjach bierze udział 32-bitowy wskaźnik stosu (ESP),
D=0 oznacza, iż w operacjach bierze udział 16-bitowy wskaźnik stosu (SP),
Bit D ma zastosowanie przy pracy z trybem 32-bitowego adresowania pamięci w trybie płaskim (ang. Flat Model),
G – (ang. Granularity) - ziarnistość – umożliwia opis segmentu o wielkości 4 GB za pomocą tylko 20 bitów. Jednostką wielkości segmentu może być:
G=0 – 1 bajt – wtedy długość segmentu może wynosić maks. 1 MB,
G=1 – 1 blok o wielkość 4 KB – wtedy segment może mieć wielkość 4 GB,
Bit ziarnistości opisuje jedynie wielkość segmentu. Adres bazowy opisany jest zawsze z dokładnością do 1 bajtu (adres bazowy jest liczbą 32-bitową).
L – (ang. Large) - 64-bitowy segment kodu (ma znaczenie tylko dla trybu IA-32e).
Uwaga
Rozmiar logicznej przestrzeni adresowej, określa się jako maksymalną wielkość pamięci widzianą przez jedno zadanie. Każdy program ma dostęp do tablicy GDT i jednej tablicy lokalnej LDT, może więc korzystać z 16384 segmentów (8192 w GDT + 8192 w swojej LDT razem 16K).
O wielkości logicznej przestrzeni adresowej decyduje liczba segmentów i ich długość. Dla procesora 80386 (gdzie maksymalna wielkość segmentu i przemieszczenie (przesunięcie, offset lub limit – w literaturze występują różne określenia) jest liczbą 32 bitową); maksymalna wielkość logicznej (wirtualnej) przestrzeni adresowej wynosi 16K * 4 GB = 64 TB. |
Rys. 2.5. Tabele deskryptorów: globalna (GDT), lokalna (LDT) i ich zależności.
W celu zoptymalizowania procesu adresowania wprowadzono ukryte rejestry deskryptorów, są one automatycznie ładowane danymi z odpowiedniego deskryptora podczas umieszczania selektora w danym rejestrze segmentowym.
Położenie w pamięci tablicy deskryptorów globalnych GDT i aktualnie wykorzystywanej tablicy lokalnej LDT jest określane przez zawartość specjalnych rejestrów procesora:
Do początku strony
Rejestr Globalnej tablicy deskryptorów
GDTR – rejestr globalnej tablicy deskryptorów (ang. Globar Descriptor Table Register).
Rys. 2.6. Format tablicy GDTR.
Do początku strony
Rejestr lokalnej tablicy deskryptorów
LDTR – rejestr lokalnej tablicy deskryptorów (ang. Local Descriptor Table Register).
Rys. 2.7. Format tablicy LDTR.
Uwaga
W ukrytym rejestrze związanych z rejestrem segmentowym LDTR zawarty jest wyliczony automatycznie adres bazowy (ang. Segment Base Address) i wielkość (ang. Segment Size) segmentu wskazanego przez powyższy selektor oraz dodatkowe atrybuty używane przez mechanizmy ochrony procesora.
Pola Segment Size i Segment Base Address są liczbami 32-bitowymi (lub 64-bitowymi dla trybu 64-bitoweg).
W każdym z rejestrów jest umieszczony adres początku odpowiedniej tablicy (adres liniowy w procesorze 80386 i późniejszych). Struktura rejestru LDTR jest analogiczna do rejestru segmentowego; zawiera również część ukrytą będącą odpowiednikiem rejestru deskryptora segmentu.
LDTR sama stanowi odrębny segment danych, należący do tzw. segmentów systemowych. Jako segment ma swój deskryptor, który to musi być umieszczony w globalnej tablicy deskryptorów.
Tablica LDTR jak i GDTR może zawierać do 8192 deskryptorów, tzn. jej długość nie może przekraczać 64 KB.
Poniżej na rysunku przedstawiano mechanizm translacji adresu logicznego na liniowy dla segmentu opisanego w lokalnej tablicy deskryptorów.
Rys. 2.8. Sposób translacji adresu logicznego na liniowy dla segmentu opisanego w lokalnej tablicy deskryptorów.
W następnej części przedstawimy mechanizm stronicowania i współpracę z pamięcią wirtualną.
Do początku strony
Przeczytaj pozostałe części tego artykułu
- Zarządzanie pamięcią w 32 i 64-bitowych systemach Windows, cz. I
- Zarządzanie pamięcią w 32 i 64-bitowych systemach Windows, cz. III
- Zarządzanie pamięcią w 32 i 64-bitowych systemach Windows, cz. IV
- Zarządzanie pamięcią w 32 i 64-bitowych systemach Windows, cz. V
![]() |
Jacek Światowiak (MCT, MCSE, MCSE+M, MCSE+S, MCTS, MCP) Absolwent Wydział Elektroniki, Telekomunikacji i Informatyki Politechniki Gdańskiej. Obecnie zatrudniony w Altkom Akademia S.A. jako Trener Technologii Microsoft. Posiada bogate doświadczenie w zakresie wdrażania różnych technologii informatycznych. Od 2002 roku wykładowca Technologii i Protokołów Sieciowych na Podyplomowym Studium Politechniki Gdańskiej. Jest współautorem skryptu dla studentów informatyki: „Protokoły IPv6 – Opis protokołów. Materiały do laboratorium”. Posiada certyfikaty MCT, MCSE, MCSE+M, MCSE+S, MCTS Microsoft Exchange Server 2007, MCP ID 3621156. |
![]() |