1. Mechanizmy tłumaczenia adresów.adres logiczny (wirtualny) -> adres liniowy stronicowanie:
|
Segmentacja.Adresy segmentowe są wykorzystywane do otrzymywania adresu liniowego z adresu logicznego (wirtualnego). Adres liniowy jest później przekształcany przez stronicowanie do adresu fizycznego. Każdy segment w systemie opisany jest przez ośmiobajtowy deskryptor segmentu, który zawiera niezbędne informacje (adres liniowy, wielkość, typ, prawa).
- segmenty kodu/danych
- Task State Segments (TSS) ...czyli segmenty stanu procesu - Local/Global Descriptor Tables (LDT/GDT) ...czyli lokalne tablice deskryptorów |
Format selektora jest następujący:
TI - Table Indicator (odnośnik do tabeli)
RPL - poziom praw; Linux wykorzystuje tylko dwa
poziomy:
Linux wykozystuje teraz tylko globalną tablicę deskryptorów, gdyż lokalne tablice zawierały zawsze te same wartości 1-segment kodu 2-segment danych. |
Format deskryptora:
R - zarezerwowane
|
StronicowaniePamięć wirtualna podzielona jest na kawałki nazywane stronami. Pamięć fizyczna podzielona na kawałki (tej samej wielkości co strony) nazywane ramkami. Tłumaczeniem adresów zajmuje się Memory Management Unit (MMU) czyli sprzętowa jednostka zarządzania pamięcią. Na procesorach Intel 386 dostępne są katalogi stron oraz tablice stron. Każdy proces ma własny katalog tablic stron. Kiedy proces jest wznawiany, jądro ładuje do rejestru CR3 adres fizyczny (!) katalogu tablic stron tego procesu. |
Format adresu liniowego uzyskiwanego z przekształcenia adresu logicznego (wirtualnego):
Adres fizyczny oblicza się następująco:
adres_tablicy_stron + TABLICA
adres_ramki + OFFSET
|
Adresy katalogów stron (tablic stron) są wyrównane
do wielkości strony a 12 najmłodszych bajtów jest wykorzystywane do przechowywania
informacji o tablicy stron (stronie) wskazywanej przez element tablicy.
Format elementu katalogu/tablicy stron:
D - dirty page
|
Stronicowanie jest włączane przez ustawienie najwyższego
bitu rejestru CR0. Przy każdym dostępie do strony sprawdzane są prawa dostępu
i przy naruszeniu praw dostępu albo nieobecności strony w pamięci wystepują
błędy strony (page faults). Sterowanie jest wtedy przekazywane do jądra,
które wczytuje stronę albo robi coś innego, co trzeba.
Obsługiwanie błędów stron. W momencie zdarzenia, rejestr CR2 zawiera liniowy adres, który spowodował ostatni błąd strony. Znaczenie bitów w kodzie błędu strony:
|
Pamięci podręczneW procesorach Intel 386 istnieje Translation Lookaside Buffer (TLB), czyli bufor translacji bliskiego otoczenia. Zawiera on adresy fizyczne ramek ostatnio używanych adresów logicznych (liniowych) stron. Kiedy trzeba uzyskać adres fizyczny jakiejś strony, 386 pierw patrzy do TLB czy nie ma tam tej informacji. Jeśli nie ma, to wykonywanych jest kilka odwołań do pamięci tzn. do katalogu oraz tablicy stron i dopiero odczytywany jest adres fizyczny strony. Bez TLB pojedyncze odwołanie do pamięci wymagałoby trzech wcześniejszych odwołań co byłoby bardzo czasochłonne.TLB jest "czyszczone" przy zmianie wartości adresu CR3 oraz przy przełączaniu zadań (co powoduje zmianę rejestru CR0). W Linuxie jest także czyszczone bezpośrednio przez wywołanie procedury invalidate (), która ładuje ponownie wartość rejestru CR3.
|
Ramki i tablice ramek
Pamięć w systemie linux podzielona jest na ramki rozmiaru okreslonego poprzez zmiannę PAGE_SIZE w pliku include/asm-<platforma>/page.h. Informacja o wszystkich ramkach w systemie przechowywana jest w tablicy mem_map, której elemantami są strukty mem_map_t zdefinowana w include/linux/mm.h. Definicja mem_map_t typedef struct page {
|
Omówienie poszczegulnych pól:
|
Znaczenia istotniejszych flag
|
Wolne ramki w systemie
Informacja o wolnych ramkach w systemie przechowywana jest w tablicy zdefiniowanej w pliku mm/page_alloc.c struct free_area_struct {
static struct free_area_struct free_area[NR_MEM_LISTS];
|
Stała NR_MEM_LISTS wynosi 10 dla wszytkich typów
komputerów oprócz AP1000, dla którego wynosi 12.
W elemencie free_area[i] przechowywana jest informacja o wolnych blokach ramek wielkości 2^i. Pola next i prev to wskaźniki do kolejki cyklicznej, tworzą ją struktury page oraz ich pola next i prev. Wskaźnik map jest wskaźnikiem na bitmapę. Każdy jej bit jest przeznaczony dla dwóch bloków tej samej wielkości (bloków bliźniaczych). Bit jest ustawiany gdy jeden z bloków jest wolny natomiast drugi częściowo lub całkowicie zajęty. |
Algorytm buddy
zajmowanie ramek:
-podziel obszar na połowy; size:=size-1 -wstaw pierwsza połówkę na odpowiednią listę (druga do do dalszej "obróbki")-uaktualnij odpowiedni bit w free_area[size].map |
zwalnianie ramek:
|
Algorytm buddy - tablica free_area |
Algorytm buddy - zajmowanie bloków |
Algorytm buddy - zajmowanie i dzielenie bloków |
Algorytm buddy - zajmowanie i dzielenie bloków cz.2 |
Algorytm buddy - zwalnianie i łączenie bloków |
Algorytm buddy - zwalnianie i łączenie bloków cz.2 |
Pliki wykonywalne
Typy plików (formaty binarne) - standardowe
- struktura linux_binfmt (include/binfmts.h) int (*load_binary)(...) - funkcja ładująca program, int (*load_shlib)(int fd) - funkcja ładująca bibliotekę, int (*core_dump)(...) - funkcja dokonująca zrzutu
obrazu 'core'
|
Formaty standardowe
- pliki
- można rejestrować:
|
Format a.out
- prosty ("klasyczny") format, - zawartość pliku binarnego (w kolejności):
|
|
- tablice relokacji dla text i data mają ten sam format,
tablica symboli - tablica struktur nlist (include/linux/a.out.h)
|
Standardem dla plików wykonywalnych jest w Linuksie format ELF. Wprowadzony został aby rozwiazać min problem dostepu do bibliotek dzielonych (wczesniej byly one linkowane statycznie, każda pod innym adresem, pomiedzy sterta i stosem). Format elf jest formatem nowym, o dużej elastycznosci - biblioteki są linkowane do niego w czasie uruchamiania. Plik spelniający ten standard musi mieć zdefiniowaną architekturę docelową (platformę sprzetową); wystepuję min w jednym z typów: |
Niezależnie istnieja dwa rodzaje klas plików (zależne od architektury) : Wewnetrzna struktura pliku jest modularna - stałe jest polożenie nagłowka (na poczatku pliku), w którym są dowiązania do podbloków definiujących położenie segmentów logicznych w pliku i przestrzeni adresowej procesu. Jakkolwiek dla wykonania kodu zawartego w pliku informacje symboliczne nie są nieodzownie konieczne, to dla programow sledzących (debuggerow) tablica symboli stanowi źródlo, które ułatwia zrozumienie deasemblowanego kodu. |
|
Nagłówek pliku elf**_hdr
:
Program header Elf**_Phdr - nagłówek segmentu, zawiera informacje o położeniu w pliku, pamieci, rozmiarach (też i w pliku i pamięci), prawach dostepu do segmentu i wyrownaniu (wspólnym dla pamieci i pliku). Suma dlugośći deklaracji segmentów nie może być wieksza niz 64kB.struct elf32_hdr{ Jednostki relokacji elf**_rel i elf**_rela służa do relokacji adresów podczas ładowania programu. Tablica symboli, złożona z jednostek elf**_sym pozwala definiować symbole w programie (adres, wskaźnik do tablicy nazw, typ i wielkość). |
Jest (w bloku kontrolnym pliku) informacja o interpreterze dla kodu (bibliotece systemowej, do której beda sie odnosily odwolania). Co do samych bibliotek, to jest wymaganie (z uwagi na dynamiczne ich linkowanie z programem), by były one relokowalne (ang. relocatable), co sprowadza sie do braku odwolan absolutnych (PIC - position independet code).Źrodla: "Linux Kernel - jądro systemu" ~/include/linux/elf.h ~/fs/binfmt_elf.c Dodatkowe informacje:
|