W dalszej czesci opisu bede uzywal pojecia strona na okreslenie bloku pamieci widzianego przez proces do ktorego odwoluje sie on przez mechanizm tlumaczenia adresu na jego fizyczne polozenie w pamieci. Blok o tym samym rozmiarze w pamieci fizycznej jest nazywany ramka. Adres liniowy jest to adres z ciaglej przestrzeni adresowej procesu uzyskany w procesie segmentacji
asm/page.h
.
Podkatalog asm w kodzie źródłowym linuxa skrótem (soft-link) do katalogu
dotyczącego procesora na który kompilowane jest jądro, np. asm-i386, asm-mips
czy asm-alpha. Automatycznie więc definicje dotyczące stronicowania będą
odpowiadać wybranemu procesorowi.
W przypadku procesora i386 i wyższych jest to 4kB = 4096 bajtow
ustalone na sztywno (procesor nie ma możliwości ustalenia innej wielkości
strony).
Funkcja kmalloc umożliwia obsługę pamięci
dla rozmiarów strony 4 i 8kB.
W efekcie bez dopisywania kodu mozna uzywac tych rozmiarow ramek.
Mniejsze byc nie moga z powodu sposobu przechowywania informacji w
pozycjach tablicy stron.
Natomiast wieksze mozna probowac zaimplementować.
arch/i386/kernel/head.S
(asembler).
Tam tez tworzony jest katalog stron jadra (swapper_pg_dir) i ustawiany jest
pierwszy wpis w tym katalogu, który
odwzorowuje pierwsze 4MB pamieci identycznosciowo.
Jadro tworzy sobie specjalny katalog BAD_PAGE
uzywany
tylko przy bledach braku strony,
kiedy brak jest pamieci fizycznej i dyskowej.
Poprzednie wersje systemu konczyly proces w trybie jadra,
co moglo powodowac niezwalnianie pamieci uzytkownika.
W dalszej fazie inicjacji swapper_pg_dir
zostaje rozszerzony identycznosciowo na cala pamiec fizyczna.
Fizyczna strona zerowa zostaje wyzerowana i nigdy
nie jest potem zapisywana.
Rowniez dla jadra zostaje zabezpieczona przed zapisem,
aby wykryc odwolania przez wskaznik NULL.
Kazdy proces ma swoj wlasny katalog tablic stron.
(Rozmiaru jednej ramki - tak, jak i tablica stron).
Wskaznik do niego znajduje sie w strukturze mm_struct
pod nazwa pgd
. Przy zmianie kontekstu Linux dba o to by zaladowac
odpowiedni rejestr procesora jego wartoscia.
Przesuniecie w adresie liniowym jest rownoczesnie przesunieciem
wzgledem poczatku wyznaczonej ramki.
Nie wymaga to chyba specjalnych wyjasnien.
Procesor Intela znajduje adres danej strony przez wskaznik podwojnie posredni.
Linux implementuje organizacje tablic zawierajacych adresy ramek trojpoziomowo.
Poprzez odpowiednie dyrektywy #define
srodkowa tablica jest traktowana
jako pojedynczy wpis w katalogu tablic stron. W tej sytuacji procedury
dotyczace srodkowych tablic czesto tylko wywoluja te dotyczace tablic
trzeciego poziomu w petli while
wykonujacej zawsze
jeden obrot.
Nie wystarczy jednak zmienic stale, aby system mogl dzialac na procesorze
o potrojnie posrednim odwolaniu do pamieci, poniewaz wiele procedur
zaklada, ze srodkowe tablice nie istnieja.
Np. funkcja alokujaca pamiec na ta tablice jest pusta.
adres | adres | adres | 4M | DIRTY | ACCESSED | PCD | PWT | USER | RW | PRESENT=1 |
Opis poszczegolnych bitow:
PRESENT
RW
PWT
PCD
ACCESSED
DIRTY
4M
fork
)
odwzorowywanie pamieci w dany obszar, zwalnianie tablic.
Kod Linuxa obsluguje tez przy tych operacjach pamiec podreczna procesora,
wychodzac z zalozenia, ze system operacyjny moze w duzym stopniu
przewidywac przyszle uzycie danej ramki.
Na Intelu wlasciwosc ta jest niewykorzystywana.
Do wazniejszych funkcji operujacych na pamieci logicznej naleza:
get_empty_page
,
alokujaca nowa strone dla procesu
new_page_tables
,
tworzaca nowe tablice dla procesu
get_empty_page()
Myli sie jednak ten kto sadzi, ze opisze tutaj sposob alokowania pamieci. Alokowanie pamieci dla procesu odbywa sie przez rozszerzenie segmentu, co jest opisane w dokumencie o sys_brk. Natomiast uzyskiwanie pamieci fizycznej jest realizowane w systemie zarzadzania ramkami
O funkcji get_empty_page powiem tyle, ze uzyskuje ramke od
wyzej wymienionego modulu zeruje ja i zwraca jej adres fizyczny.
Stad wniosek, ze program dostaje nowa pamiec wyzerowana.
new_page_tables()
swapper_pg_dir
)
Zera w katalogu stron oraz w tablicy stron,
jak juz wczesniej wspomnialem,
sa traktowane jako strona alokowana przy pierwszym dostepie.
Gorny gigabajt jest przy przepisywaniu ustawiany na systemowy
(bit USER).
mm/memory.c
- czesc funkcji
arch/i386/kernel/entry.S
- organizacja katalogow jadra
include/asmi386/page.h
- stale, makra odwolujace sie do elementow tablic
include/asmi386/pgtable.h
- obsluga pamieci podrecznej, funkcje alokujace struktury,
kontrolujace ich poprawnosc.
#define
.
Dla Intela zdarzaja sie dyrektywy puste, ktore
w przypadku innych architektur wykonuja niewielki kawalek kodu w
asemblerze np: zaznaczajacy bit uzycia strony. Procedury na wyzszym
poziomie nie musza wiedziec jak sa zaznaczane odpowiednie bity.
Jest jednak pewien zasob czynnosci, ktore procesor musi umiec
wykonywac np:adresowanie pamieci przez tablice stron, ochrona
pamieci nieprzydzielonej oraz dzielonej do odczytu.