Zaawansowane Architektury Procesorów 1. Rozwój

Transkrypt

Zaawansowane Architektury Procesorów 1. Rozwój
Zaawansowane Architektury Procesorów
Część 1
1. Rozwój architektury x86
Intel 8086:
Procesor w architekturze CISC. Posiadał tylko jeden tryb pracy tj. rzeczywisty, a więc wszystkie
programy działały na poziomie zaufania systemowym. W stosunku do 8080 wprowadzono
rozdzielnie pamięci na obszary danych, kodu i stosu.
- przestrzeń adresowa pamięci - 1MB w trybie rzeczywistym;
- 16-bitowa magistrala danych;, 20-bitowa magistrala adresowa;
- 91 podstawowych typów rozkazów;
- 7 trybów adresowania argumentów w pamięci;
Intel 286:
- potrafił jedynie przełączyć się w tryb chroniony, powrót do trybu rzeczywistego nie był możliwy
bez resetu procesora
- 24 bitowa magistrala adresowa ( 16 MB pamięci )
- pamięć powyżej 1 MB dostępna jedynie w trybie emulacji pamięci rozszerzonej ( tryb chroniony )
- możliwość wrzucenia na stos stałej natychmiastowej
Intel 386:
Pierwszy 32 bitowy procesor, posiadał 32 bitowe szyny danych i adresu. Rejestry zostały
rozszerzone do 32 bitów ( przedrostek E- ) i rejestry ogólnego przeznaczenia mógłby być używane
dowolnie poza
- adres postaci [Rejestr_bazowy + Rejestr_indeksowy * skala + stała_przemieszczenia]
- dodanie trybu wirtualnego ( v86 emulacja tryby rzeczywistego w trybie chronionym )
Format instrukcji 386:
Prefiksy
Kod operacyjny
ModRM
SIB
Przemieszczenie
0..1B
1..3B
1..3B
0..1B
0,1,2,4B
ModRM – specyfikacja argumentów lub rozszerzenie kodu operacyjnego
SIB – Bajt specyfikacji trybu adresowania pamięci dla trybu indeksowego
Stała
0,1,2,4B
ModRM ( bajt różnie interpretowany w trybach 16- i 32-bitowym ) :
- jeśli nie ma indeksu [czyli Rej_indeksowy=0], to cała informacja o trybie adresowania jest
zakodowana w ModRM;
- jeśli jednakże adresujemy z wykorzystaniem rejestru indeksowego, to jeszcze dodatkowo w SIB
znajduje się informacja o skali i numer rejestru [czyli który rejestr jest wybierany do roli rejestru
indeksowego]
2. Model systemowy x86
2.1 Globalna tablica deskryptorów, segmentacja
Kiedy odwołujemy się do pamięci w trybie chronionym, wszystkie odwołania przechodzą przez
globalną tablicę deskryptorów segmentów GDT ( lub przez lokalną LDT, ale w praktyce nie jest
ona używana ). Deskryptory segmentów zawierają informację o adresie bazowym segmentu,
prawach dostępu, długości segmentu oraz dodatkowe informacje jak np określenie czy jest to
segment zwykły.
Każdy deskryptor segmentu zawiera powiązany ze sobą selektor. Program chcąc odwołać się do
obszaru w pamięci, musi przejść przez selektor, który wskazuje na deskryptor segmentu w GDT,
który to zawiera adres bazowy obszaru w pamięci. Aby to było możliwe, procesor musi pracować w
większym lub równym poziomie zaufania ( CPL ) niż określony w deskryptorze minimalny poziom
zaufania ( DPL ), upoważniający do dostępu do danego segmentu. Jeżeli DPL posiada mniejszy
poziom zaufania niż CPL, nadpisuje on CPL.
Wyjątkiem są tzw. Conforming Code Segments, do których dostęp można uzyskać posiadając
jedynie równy lub niższy poziom zaufania niż ich DPL oraz w takim wypadku CPL nie ulega
zmianie.
Poza segmentami niezbędnymi to działania systemu czyli segmencie danych, kodu oraz stosu,
architektura x86 określa też segment stanu zadania ( TSS ) oraz segment lokalnej tablicy
deskryptorów ( LDT ). GDT nie jest określane jako oddzielny segment, ponieważ nie istnieje
selektor ani deskryptor segmentu dla niej. TSS i LDT posiadają zdefiniowane dla siebie selektory i
deskryptory segmentów.
Selektor jest 16 bitowym identyfikatorem segmentu. Składa się z indeksu ( 3-15 bitu )
wskazującego na jeden z 8192 deskryptorów w GDT lub LDT, bitu TI wskazującego, czy selektor
wskazuje na deskryptor w LDT lub GDT oraz 2 bitów RPL ( Requested Privilege Level ). RPL
porównuje aktualny CPL i określa, czy proces ma prawo do czytania deskryptora segmentu. Jeżeli
autoryzacja się powiedzie, a RPL ma mniejszy poziom zaufania niż CPL, nadpisuje on CPL.
2.2 Bramy:
Architektura x86 określa dodatkowo specjalne deskryptory segmentów zwane bramami. Kiedy
jakiś proces chce uzyskać dostęp do jakiegoś bloku kodu, dostarcza on selektor wskazujący na
bramę. Ta natomiast porównuje aktualny CPL z minimalną wartością poziomu zaufania która
upoważnia do dostępu do danego kawałka kodu. Następnie po stwierdzeniu możliwości odwołania
się przez wołający proces do danego bloku, procesor uzyskuje selektor wskazujący na odpowiedni
deskryptor segmentu i offset do bloku kodu. Jeżeli wołanie wymaga zmiany CPL, procesor
zamienia w tym momencie stosy. Selektor segmentu jest uzyskiwany z TSS. Bramy dodatkowo
ułatwiają przełączanie się między segmentami kodu 16 i 32 bitowego
Wprowadzono cztery rodzaje bram:
a) Brama pułapki – stwierdza, czy dana procedura
ma prawo do wołania procedury lub handlera w
segmencie kodu wedle CPL i jeśli tak ładuje
odpowiedni deskryptor do CS.
b) Brama przerwania – analogicznie do bramy
pułapki, jednak dodatkowo blokuje przerwania
c) Brama wołania -analogicznie do bramy pułapki,
dodatkowo kopiowanie ze stosu użytkownika
danych z pola limitu do stosu systemowego
d) Brama zadania – wskazuje na selektor TSS
2.3 Segment stanu zadania
Segment stanu zadania definiuje stan środowiska
dla aktualnie wykonywanego procesu.
Dostęp do TSS odbywa się za pomocą deskryptora
TSS zawartego w GDT, na który wskazuje rejestr
zadania ( TR ). TSS jest obsługiwane przez
mikrokod procesora.
TSS zawiera aktualną zawartość dla rejestrów ogólnego przeznaczenia, rejestry segmentów, rejestr
znaczników EFLAGS, rejestr wskaźnika instrukcji EIP oraz selektory segmentów. Zawiera też
selektor dla LDT skojarzonego z aktualnym procesem oraz adres bazowy do jednostki
stronicowania.
Podczas przełączania się do innego procesu za pomocą instrukcji JUMP lub CALL, procesor
otrzymuje selektor na TSS wołanego procesu, a następnie:
a) Zapamiętywany jest kontekst aktualnego zadania w TSS
b) Do rejestru zadań ładowany jest selektor wskazujący na TSS wołanego procesu
c) Uzyskiwany jest dostęp do nowego TSS za pomocą deskryptora zawartego w GDT
d) Do rejestrów procesora ładowane są dane z TSS ( wymienione wcześniej )
v86: TSS zostało później rozszerzone o mapę odbić wyjątków, wskazującą, czy dany wyjątek ma
być obsługiwany przez system, czy też obsługa może zostać w trybie v86
Zawiera cztery wskaźniki stosu, po jednym dla każdego poziomu zaufania.
IO Map Adress Base – offset od adresu TSS który wskazuje, gdzie znajduje się tablica portów I/O
do których proces ma dostęp.
2.4 Obsługa przerwań
Wszystkie przerwania w architekturze x86 są obsługiwane przez tablicę deskryptorów przerwań
( IDT ). Zawiera ona kolekcje deskryptorów bram ( maksymalnie 256 ) , które umożliwiają dostęp
do handlerów obsługi przerwań i wyjątków. Podobnie jak GDT, IDT nie jest segmentem. Adres do
IDT przechowywany jest w rejestrze IDTR. Wyjątki systemowe i przerwania mają minimalny
poziom zaufania ustawiony na 0 czyli systemowy.
Sprzęt, dodatkowy kontroler obsługi przerwań lub oprogramowanie dostarcza procesowi wektor
obsługi przerwań. Wektor obsługi przerwań zawiera indeks do IDT. Jeżeli wskazywana brama jest
bramą pułapki lub przerwań, dostęp do procedury obsługi przerwania jest analogiczny jak wołanie
procedury przez bramę wołania. Jeżeli jest to brama zadania, dostęp do procedury obsługi jest
wykonywany poprzez przełączanie zadań.
W trybie rzeczywistym każdy program może ładować własne deskryptory do IDT i w ten sposób
nadpisywać obsługę przerwań własnymi handlerami. W trybie chronionym muszą tam znajdować
się bramy których program użytkownika nie może modyfikować.
W trybie v86 generowany jest wyjątek, procesor przechodzi do poziomu zaufania systemowego, a
następnie pyta jednostkę stronicowania, gdzie w pamięci znajduje się sesja DOSowa, sięga w niej
do zapisanej dla niej tablicy przerwań i tam dopiero przechodzi do obsługi wyjątku ( co jest bardzo
nieoptymalne ). Mikrokod procesora zapamiętuje na stosie starą ramkę obsługi wyjątku i
przygotowuje nową – odbijanie wyjątków.
Błąd podwójny – jeżeli proces wyleci na wyjątku, a następnie w obsłudze tego wyjątku przez
system znów wygenerowany zostanie wyjątek. Taka sytuacja nie powinna mieć miejsca w dobrze
napisanym systemie operacyjnym.
3. Tryby działania w x86
a) Tryb rzeczywisty: procesor zawsze startuje w tym trybie. Działa wtedy na poziomie zaufania
systemowym i posiada dostęp do pierwszego megabajta pamięci.
b) Tryb chroniony: tryb z ochroną zasobów.
c) Tryb wirtualnej emulacji 8086: tryb udawanego tryby rzeczywistego. Umożliwia za pomocą
emulacji maszyny wirtualnej odpalanie programów DOSowych, które muszą pracować w trybie
rzeczywistym ( albo myśleć jedynie, że w takim pracują, czyli właśnie w trybie emulacji 8086 ) .
Tryb ten nie może działać bez stronicowania. W trybie v86 sesja jest uruchamiana na poziomie
zaufania 3 i udaje tryb niechroniony, czyli proces ze swojego punktu widzenia może pisać po
wszystkich rejestrach i znacznikach ( ale tak naprawdę czuwa nad tym system )
d) Tryb SMM: urzęduje w pierwszym megabajcie pamięci, jest on równoległym trybem
przeznaczonym do obsługi specyficznych zadań sprzętu, jak np zarządzaniu energią w
notebookach. System operacyjny nie widzi zasobów tego trybu. Procesor przechodzi do trybu SMM
poprzez przerwanie SMI
e) Tryb IA-32e: czyli jak sama nazwa wskazuje tryb pracy 64 bitowy. W tym trybie procesor
udostępnia dwa tryby: tryb zgodności oraz tryb 64 bitowy.
3.1 Przejście z trybu rzeczywistego do tryby chronionego
Aby przejść z trybu rzeczywistego do tryby chronionego muszą zostać zainicjowane następujące
struktury danych:
a) IDT, GDT, TSS
b) chociaż jedna strona oraz tablica stron dla stronicowania
c) segment kodu, który zawiera kod jaki zostanie wykonany po przejściu w tryb chroniony
d) części kodu zawierające kod obsługi przerwań i wyjątków
Ponadto trzeba zainicjować rejestry systemowe:
a) GDTR, CR0 do CR4, IDTR
Procedura przełączania trybu jest następująca:
a) Wyłączenie przerwań
b) Wywołanie instrukcji LGDT, w celu załadowania adresu bazowego GDT do GDTR
c) Ustawienie flagi PE w rejestrze CR0
d) Wywołanie instrukcji CALL lub JMP
e) Wywołanie LTR w celu załadowania adresu bazowego TSS do TR
f) Ponowne wywołanie JMP lub CALL aby przełączyć procesor na nowe zadanie
g) Wywołanie LIDT w celu załądowania adresu bazowego IDT do IDTR
h) Włączenie przerwań STI
4. Znaczniki systemowe w rejestrze EFLAGS
Skrót
Nazwa
Opis
TF
Trap Flag
po każdej instrukcji będzie wywoływana pułapka śledzenia, co jest
potrzebne do debugowania programu.
IF
Interrupt Flag
kontroluje odpowiedź procesora na sprzętowe przerwania maskowalne.
Wyzerowana powoduje brak reakcji na sprzętowe przerwania
maskowalne przez procesor.
IOPL I/O Privilege
Level
ustawiana podczas przełączania zadań, informuje o tym na jakim
poziomie zaufania można wykonywać instrukcje I/O
NT
Nested Task
kontroluje łańcuch wywołań przerwań lub przełączania zadań.
Ustawiana w przypadku wołania innego zadania lub osługi wyjątku
RF
Resume Flag
wyłączenie pułapki śledzenie na czas trwania jeden instrukcji, dzięki
czemu można uniknąć zakleszczenia
VM
Virtual Machine ustawiona, oznacza, że proces pracuje w trybie v86
AC
Aligment Check ustawiona, powoduje sprawdzanie wyrównania danych. W przypadku
negatywnej weryfikacji generowany jest wyjątek braku wyrównania
danych.
ID
Identyfication
VIF
umożliwia wywołanie instrukcji CPUID, która zwraca informacje o
procesorze ( dzięki czemu wiadomo jakie instrukcje on obsługuje np. )
odpowiednik IF w trybie wirtualnym.
5. Rejestry Kontrolne ( CR0..4 )
a) CR0 – zawiera znaczniki systemowe oraz stany procesora
b) CR2 – zawiera adres bazowy strony która spowodowała błąd stronicowania
c) CR3 – zawiera adres bazowy do tablicy deskryptorów jednostki stronicowania
d) CR4 – zawiera rejestr znaczników, które rozszerzają architekturę o specyficzne ficzery które
oferuje dany model procesora
Znaczniki CR0:
Skrót
Nazwa
Opis
PG
Paging
CD
Cache Disable
NW
włącza jednostkę stronicowania
wyłączenie kieszeni
Not Write through wyłączenie „write-back” czyli zapisu do pamięci podręcznej z
odłożeniem zapisu do pamięci głównej na później oraz „writethrough” czyli zapisu i do kieszeni i do pamięci głównej
AM
Aligment Mask
włączenie automatycznego wyrównania danych
WP
Write Protection uniemożliwienie zapisu strony przez system, która jest tylko do
odczytu, umożliwia leniwą alokację
NE
Numeric Error
włącza natywny mechanizm komunikowania błędów przez jednostkę
zmiennopozycyjną
TS
Task Switched
włącza leniwe przełączanie kontekstu
EM
Emulation
Znaczniki CR3:
Skrót
włącza emulowanie jednostki zmiennopozycyjnej
Nazwa
Opis
TSD
Time Stamp Disable
wyłącza licznik czasu, określa czy aplikacja może używać
TSC
DE
Debugging Extenstions
włącza dodatkowe rejestry dla debuggowania
PGE
Page Global Enable
włącza włącza obsługę globalnych deskryptorów stron,
które nie bedą wyrzucane z bufora translacji przy
przełączaniu kontekstów ( co jest drogie )
PSE
Page Size Extensions
Włącza 4MB strony
PAE
Page Adress Extensions
włącza ulepszone stronicowanie, generowanie adresu z
więcej niż 32 bitów, wymagane do obsługi trybu 64bitowego
MCE
Machine Check Enable
włącza diagnostyki sprzętowej
PCE
Performance Monitoring włączenie licznika wydajności
Enable
OSFXSR
Operating System
włącza instrukcje SSE
Support for FXSAVE and
FXRSTOR
PCIDE
PCID-Enable Bit
włącza identyfikowanie właściciela strony
Tryb 64 bitowy ( IA-32e )
Tryb 64 bitowy wprowadza zestaw 2x więcej rejestrów, stare zostają rozszerzone do 64 bitów
( dodano przedrostek R, który umożliwa dostęp do dodatkowych rejestrów, operowanie na 64
bitowych rejestrach oraz do SK i DPL ). Dodano dwa razy więcej rejestrów dla jednostki
wektorowej i opcjonalność wołanie rejestru ramki. Wszystkie rejestry mają widoczne 8 bitowe
części. Usunięto parę nadmiarowych instrukcji ( np. 1 bajtowe INC ).
Wprowadzono podział pamięci na cześć użytkownika ( od 0 do 2^48 ) i część systemu ( 2^64 do
2^64 – 2^48 ). Część pamięci między nimi jest niemożliwa do zaadresowania.
Maszyna Wirtualna - Udawanie przed systemem operacyjnym, że ten ma dostęp do sprzętu i
zasobów, do których on tak naprawdę nie ma dostępu. Aby ten mechanizm działał, system nie może
się dowiedzieć, że nie jest prawdziwym systemem operacyjnym.
W wirtualizacji spychamy emulowany system operacyjny do poziomu użytkownika. Aby komputer
umiał się wirtualizować, musi mieć możliwość zabraniania dostępu do zasobów systemowych, co
spowoduje, że emulowany program wyleci na błędzie i już prawdziwy system będzie mógł
zasymulować działanie tych zasobów.
Leniwa alokacja - Kiedy proces chce zaalokować pamięć, system wpisuje do tablicy deskryptorów
deskryptory jednej strony oznaczone jako tylko do odczytu. Kiedy później użytkownik próbuje
zapisać coś do tych stron, wylatuje na błędzie i dopiero wtedy jest ona odblokowywana i fizycznie
przydzielana.

Podobne dokumenty