Zaawansowane Architektury Procesorów Część 2 1.Opis

Transkrypt

Zaawansowane Architektury Procesorów Część 2 1.Opis
Zaawansowane Architektury Procesorów
Część 2
1.Opis architektury 64-bitowej ( IA-32e )
- Tryb IA-32e może pracować w dwóch trybach – pełnym 64 bitowym, oferującym 64 bitowe
liniowe adresowanie pamięci lub w trybie zgodności, w którym to aplikacje 32 bitowe działają
praktycznie w ten sam sposób. Zrezygnowano z trybu v86
- Zostawiono bramy pułapki i wołania, nie ma bram zadania, bramy przerwania wykorzystywane są
do wołania aplikacji 32 bitowych
- W architekturze 64 bitowej pamięć została podzielona na tylko dwa obszary: użytkownika,
znajdujący się pod adresami od 0 do 2^47 oraz systemowy, który został ulokowany w obszarze od
2^64-2^47 do 2^64. Wymusiło to zastąpienie adresowanie absolutnego adresowaniem postaci
[RIP+d32], gdzie d32 jest liczbą ze znakiem. Adres składa się z maksymalnie 48 bitów, pozostałe - 17 bitów nie jest wykorzystywanych i musi zawsze musi mieć tę samą wartość.
- Zmiana dotknęła też strukturę TSS, która w przeciwieństwie do x86 jest wspólna dla całego
systemu i nie jest przełączana podczas przełączania procesów, służy tylko do przełączania
wskaźników stosu. Zawiera 8 rejestrów IST0..7 zawierających wskaźniki stosu dla obsługi
wyjątków
2. Wołanie systemu operacyjnego w trybie 64 bitowym
W trybie 64 bitowym wołanie systemu operacyjnego nie jest obsługą wyjątku i następuje bez
odwołań do pamięci i bez użycia bram, wszystkie potrzebne informacje znajdują się w rejestrach,
co diametralnie przyśpiesza pracę systemu. System woła się za pomocą SYSCALL, a z wołania
wychodzi za pomocą instrukcji SYSRET.
Dodano rejestry MSR, specyficzne dla danego modelu procesora. W architekturze 64 bitowej
założono, że ilość rejestrów procesora będzie rosła. Odczyt i zapis do tych rejestrów następuje za
pomocą instrukcji RDMSR i WRMSR
SYSCALL i SYSRET - skoki między poz. zaufania 0 i 3 (bardzo szybkie) - nie używają pamięci,
więc: w tablicy GDT muszą być umieszczone obok siebie selektory segmentów kodu i stosu (SS o 8
bajtów dalej niż CS).Wskaźnik stosu nie jest przeładowywany przez SYSCALL, następuje to
dopiero w procedurze systemowej.
Adresy funkcji systemowych są w rejestrach (MSR). Instrukcja ładuje licznik instrukcji z MSR.
Ślad zostaje w rejestrze ECX
3. Stronicowanie i segmentacja w trybie 64 bitowym
Jednostka stronicowania praktycznie zastąpiła jednostkę segmentacji w trybie 64 bitowym. Może
dzielić pamięć na strony 4kB, 2MB lub 1 GB ( potrzebne np do sterownika graficznego ). W
rejestrze CR3 znajduje się wskaźnik na pierwszą tablicę stron. Deskryptory stron zostały
rozszerzone do 64 bitów ( składają się z dwóch deskryptorów 32b ) i zwierają informacje o
poziomie zaufania, oraz czy wskazują na kod 32 czy 64 bitowy. Deskryptory są wpierw szukane w
buforze translacji i dopiero w przypadku nie znalezienia tam szukanego jest wykonywany dostęp do
pamięci
Jednostka stronicowania może działać w jednym z trzech trybów:
a) 32 bitowym: strony 4kB lub 4MB
b) PAE: 64 bitowy deskryptory stron, dodatkowa 4 elementowa tablica 3 poziomu, dzieląca obszary
w pamięci na dane i kod użytkownika i systemu
c) IA-32e: musi być przełączona na ten tryb w trybie 64 bitowym, przyjmowany jest najbardziej
restrykcyjny atrybut odczytu i zapisu z deskryptorów różnych poziomów
Uproszono jednostkę segmentacji. O ile w trybie zgodności segmentacja działa tak samo jak w
przypadku 32 bitowej architektury, o tyle w trybie pełnych 64 bitów, jednostka segmentacji jest
praktycznie wyłączona – tworzy jeden, liniowy segment na cały obszar pamięci ( adres bazowy =
0 ), bez sprawdzania limitu. Wyjątkiem są jedynie rejestry FS i GS, które mogą zawierać inny adres
bazowy. Używane są przez system operacyjny do trzymania wskaźnika na TSS oraz tablic łączenia
dla dynamicznych bibliotek
4. Zarządzanie pamięcią w trybie 64 bitowym
Problem z zarządzaniem pamięcią objawia się w systemach wieloprocesorowych i specyficznych
sterowników urządzeń ( np takich, które są wrażliwe na odczyt ). Instrukcje proces wykonuje
spekulatywnie, więc nie jesteśmy pewni, czy rzeczywiście odczyt z pamięci na pewno się wykona
( a taka sytuacja byłaby tragiczna dla wcześniej wymienionych sterowników urządzeń ). Dlatego też
wprowadzono sześć różnych kategorii możliwości buforowania danych w kieszeni:
Typ
Wykorzystanie kieszeni Writeback Spekulatywny odczyt
Uncacheable
Nie
Nie
Nie
Write Combining
Nie
Nie
Tak
Write Through
Tak
Nie
Tak
Write Back
Tak
Tak
Tak
Write Protected
Tak dla odczytu
Nie dla zapisu
Nie
Tak
Write combining: wykorzystanie bufora zapisu w celu opóźnienia operacji zapisu. Diametralnie
szybciej jest wykonać jeden większy zapis raz, niż parę mniejszych oddzielnie. Tak więc dane do
zapisu są przechowywane w buforze i dopiero w przypadku jego zapełnienia inicjowany jest zapis,
a bufor czyszczony
Write Through: zapis przezroczysty, następuje zapis w każdym poziomie kieszeni oraz pamięci
Write Back: opóźniony zapis, który następuje dopiero wtedy, gdy usuwamy te dane z kieszni
Każde urządzenia posiada swój rejestr MTRR, tworzony i wypełniany na starcie przez system
operacyjny, który określa do której z powyższych klas należy jakie urządzenie.
5. Jednostka wektorowa
Pierwsza jednostka wektorowa MMX współdzieliła zasoby ( wykorzystywała pierwsze 64 bity
rejestrów FPU ) z jednostką zmiennoprzecinkową, co skutkowało brakiem potrzebny zmiany samej
architektury x86. Aktualnie rejestry te są fizycznie oddzielone. Skutkiem współdzielenia rejestrów
jest niemożliwość wykorzystywania jednocześnie jednostki wektorowej i koprocesora. MMX
umożliwiał tylko proste operacje x?y:z i nie wykorzystywał rejestru znaczników.
Aktualnie MMX nie jest już wykorzystywany, zastąpiony został przez instrukcje SSE operujące na
dedykowanych rejestrach 128 bitowych. Przejście do trybu SSE odbywa się po wykonaniu
dowolnej instrukcji należacej do zestawu SEE, a ponowne przełączenie na koprocesor odbywa się
przez jawne wywołanie instrukcji EMMS.
Ważnymi instrukcjami jednostki wektorowej są instrukcje pakowania i rozpakowania
AMD wprowadziło swoją własną wersję MMX pod nazwą 3dNow! Domyślnie SSE ma całkowicie
zastąpić 3dNow! oraz jednostkę zmiennopozycyjną
6. Przerwania w systemach
Programy w komputerze tak naprawdę są napędzane przerwaniami – rzadko który program jest
całkowicie obliczeniowy.
W domorosłych systemach operacyjnych nie występuje już sytuacja w której program po przyjściu i
obsłużeniu przerwania jest natychmiast wznawiany. Zazwyczaj sama obsługa wyjątku może zostać
przerwana, jak też po zakończeniu obsługi wyjątku zazwyczaj wznawiany jest inny proces.
Jedynym sposobem powrotu z przerwania jest system powrotu z obsługi wyjątku.
W ogólnym przypadku mamy system priorytetyzacji przerwań – przerwania mniej ważne mogą być
przerywane przez te ważniejsze ( eleganckie zagnieżdżanie wyjątków ). W wielopoziomowej
obsłudze przerwań występują sekcje krytyczne – niektóre procesory posiadają oddzielne bity do
ustawiania poziomu priorytetu aktualnie przetwarzanego przerwania jak i do całkowitego
zablokowania przerwań.
Wymogiem do konstrukcji systemu rzeczywistego jest to, aby wszystko było zgłaszane jako
przerwanie. W przypadku braku oczekującego na obsłużenie przerwania procesor powinien być
usypiany ( posiadać budowę: loop1: halt; jmp loop1; ) Najnowocześniejsze urządzenia działają
tylko na przerwaniach – często nie posiadają nawet interfejsu umożliwiającego aktywne zapytanie
ich o stan.
Często wymogiem do budowy systemu czasu rzeczywistego jest nie tylko to, aby spełniał wymóg
maksymalnego czasu odpowiedzi, ale też czas odpowiedzi zawierał się w określonym przedziale
( był nie mniejszy niż ) ( z tych powodów x86 nie nadaje się do systemów czasu rzeczywistego )
Procesor ARM Cortex: Architektura głównie RISC-owa, a więc nie ma rejestrów specyficznego
przeznaczenia. Na poziomie instrukcji zachowuje się jak zwykły proces ARM, jednak ma
diametralnie przebudowaną obsługę wyjątków: procedura obsługi wyjątku dla kompilatora ma
wyglądać jak obsługa zwykłej procedury. Realizuje to poprzez zrzucenie rejestrów SCRATCH oraz
PC, LR, SP i IP i wpisuje do rejestru LR nielegalną wartość 0xFFFFFF i po tym właśnie poznaje, że
powrót będzie z obsługi wyjątku
Procedura powrotu z obsługi wyjątku różni się od powrotu ze zwykłej procedury:
- powrót realizowany za pomocą instrukcji IRET a nie RET
- poza rejestrami grupy save, również te z grupy temporary są zapamiętywane
Założono, że proces pracuje w dwóch trybach: aplikacji i obsługi wyjątku. Inaczej niż w x86
wpierw składujemy kontekst, a dopiero potem patrzymy jakie przerwanie przyszło. W ten sposób
zabezpieczamy się przed tym, że w czasie składowania kontekstu nie przyszło ważniejsze
przerwanie. Skutkuje to też tym, że nie musimy zapamiętywać kontekstu przerwania mniej
ważnego, od razu przechodzimy do obsługi przerwania ważniejszego ( Interrupt Chaining ):
↓6 ↓5
↓3
↓1
↓2
app↓
5
5↓
1
3
5↑
2
5↑
5
6
app↑
(w tabeli: ↓ składowanie kontekstu, ↑ przywracanie kontekstu, nad tabelą: ↓ przerwanie )
7. Wirtualizacja
Maszyna wirtualna – może to być symulator napisany w języku wysokiego poziomu albo
symulatory takie jak C# lub Java ( maszyny całkowicie wirtualne ). W naszym rozumieniu jest to
wirtualizowanie za pomocą sprzętu, dzięki czemu zyskujemy wydajność z powodu korzystania
główne z własnych zasobów sprzętowych.
Parawirtualizm – stworzenie maszyny wirtualnej dla konkretnego komputera przy dużym
wsparciu sprzętowym. Część akcji nie jest wykonywana na sprzęcie ale przy odwołaniu do
Hypervisora. Pisząc programy dla maszyny wirtualnej wiemy, że pracujemy na maszynie
wirtualnej, dzięki czemu możemy ogromnie zyskać na wydajności.
Pod kontrolną Hypervisora działa parę systemów operacyjnych. Z systemu operacyjnego kontrolę
na zasobami przeniesiono wyżej, wywłaszczono systemy operacyjne z całkowitej kontroli nad
sprzętem.
Do parawirtualizacji potrzebujemy:
- możliwości uruchomienia maszyny wirtualnej przez Hypervisora
- jakiś mechanizm przechwycenia ( Intercept )
- bogate mechanizmy kontroli maszyny przez Hypervisora np Wstrzykiwanie Wyjątków
AMD: komputer budzi się w trybie Hypervisora
Intel: komputer budzi się w trybie systemowym i musimy jawnie uruchomić tryb Hypervisora
W komputerze mamy najczęściej tylko parę typów urządzeń: karty sieciowe, urządzenia pamięci
masowej i konsolę – te urządzenia należy zwirtualizować ( przeważnie nie jest to skomplikowane ).
Jednak w typowym PC posiadamy urządzenia o wiele bardziej złożone.
W minimalistycznej wersji wirtualizacji, dzielimy sprzęt po równo dla każdego systemu
operacyjnego ( np po jednym dysku ).
Instrukcje można podzielić na takie, które nie zależą i nie wpływają na kontekst ( np. Dodawanie ),
takie które wpływają na kontekst oraz na takie, których wynik zależy od aktualnego kontekstu i te
instrukcje należy zakazać użytkownikowi. Spychamy więc system do poziomu użytkownika ( np.
Jeżeli użytkownik chce odczytać rejestr stanu procesora, zgłaszany jest błąd do Hypervisora )
Obsługa wyjątków musi zachodzić pod kontrolą Hypervisora – część z nich powinien obsługiwać
on, a część odbijać do systemu operacyjnego. W celu zapewnienia optymalnej wydajności należało
stworzyć mechanizm do efektywnej komunikacji między systemem a Hypervisorem. Tak powstal
mechanizm Przechwycenia (Intercept), czyli zdarzenia, które powoduje zatrzymanie maszyny
wirtualnej i przekierowanie sterowania do Hypervisora.
Pułapki nie generują przechwyceń, błędy w zależności od potrzeb. Przechwycenia generowane są
też przez niektóre akcje, instrukcje procesora, I/O.
Zazwyczaj Hypervisor sam obsługuje przechwycenie, czasami jednak musi odbić je z powrotem do
systemu operacyjnego i do tego służy dodatkowy mechanizm nazwany Wstrzykiwaniem
Wyjątków: Hypervisor udaje przed systemem jakieś urządzenie, które zgłasza przerwania
Dochodzi drugi poziom zarządzania pamięcią. To Hypervisor ma wiedzę na temat, gdzie znajdują
się prawdziwe tablice stron i przy próbie odwołania się do pamięci przez system odwzorowuje on
adres wskazany przez system na fizyczny sprzętowy:
Wirtualny_Gościa -> Fizyczny_Gościa / Wirtualny_Hypervisora -> Fizyczny_Hypervisora
Jeżeli w buforze translacji nie znajduje się poprawny deskryptor to Hypervisor musi przetłumaczyć
adres fizyczny gościa na swój fizyczny, a jest to operacja nietrywialna w x86: zamiast 3 dostępów
do pamięci, należy wykonać 3 ( VG -> FG ) * 3 ( VH -> FH ) = 9 odwołań.
Dodatkowo dochodzi problem, że czyszczenie bufora translacji dla jednego systemu operacyjnego
czyści też translacje innym systemom. Rozwiązaniem powyższym problemów jest
parawirtualizacja: Hypervisor na początku ustawia wszystkie strony jako nieważne i wypełnia je
przy obsłudze błędów.
Aby ograniczyć straty wydajności spowodowane czyszczeniem bufora translacji powstały dwa
mechanizmy:
a) Dodanie identyfikatora maszyny wirtualnej do adresu wirtualnego
b) Mechanizm Nested Paging: dołożenie sprzętu odpowiedzialnego za równoległą translację
adresów gościa oraz Hypervisora ( sklejony adres fizyczny gościa, fizyczny HV )
Ostatecznie mikrokod jednostki stronicowania stworzy deskryptor strony, w którego skład wchodzi:
- ID gościa
- adres wirtualny gościa
- adres fizyczny Hypervisora
Następnie załaduje ten deskryptor natychmiast do TLB – bufora translacji
Plusem stosowania powyższych mechanizmów jest też to, że translacją nie zajmuje się
oprogramowanie, ale mikrokod co diametralnie przyśpiesza czas wykonania translacji.
Dodatkowo możemy przyśpieszyć translacje poprzez usunięcie dodatkowych poziomów tablic dla
Hypervisora. Nie potrzebuje on granularności 4kb, a nawet 2Mb, może on wskazywać od razu na
strony 1Gb przydzielone dla każdego systemu.
Pytania kontrolne i odpowiedzi
1. W jaki sposób normalny OS przełącza procesy?
OS przygotowuje stos procesu, wrzuca na niego przynajmniej PC i SR, na stos systemowy
tworzonego procesu wrzuca to co proces spodziewa się tam zastać. Następnie blokuje przerwania,
przeładowuje SP i robi powrót z obsługi wyjątku. Tak więc proces przełączamy w procedurze
obsługi wyjątku.
2. Wymień sposoby realizacji priorytetów przerwań
a) procedura obsługi przerwania rozpoczyna wykonanie na poziomie 3 z zablokowanymi
przerwaniami. Po zakończeniu sekcji krytycznej odblokowujemy przerwania i procedura może być
przerwana przez inne przerwanie.
b) pole poziomu + osobne pole zezwolenia na przerwanie - tak jest w niektórych CPU
3. Wymień podstawowe różnice między procedurą obsługi przerwania, a zwykłą procedurą.
- musi zachować rejestry typu scratch
- kończy się instrukcją RETI
4. Do czego w procesorze ARM służy rejestr IP?
Jest to Intra-procedure call scratch register. Służy on do wykonywania dalekich skoków w
następujący sposób:
- kompilator / konsolidator wstawia tablice stałych między procedury - są to stałe wykorzystywane
przez procedurę, m.in. adres skoku.
- konsolidator wstawia do kodu wstawkę: "załaduj adres z pamięci do IP, skacz pod adres z IP"
5. Opisz jak zrealizowany został powrót z obsługi wyjątku w procesorach ARM Cortex
Skoki w ARM są wykonywane ze śladem w rejestrze LR - jest on zrzucany na stos, gdy trzeba
znowu skoczyć. Możliwe jest wykonanie instrukcji POP PC (wczytanie LR ze stosu do PC).
Procedura obsługi wyjątku zapamiętuje a1,a2,a3,a4 (scratch),PC,LR,SP,IP na stosie, następnie
wpisuje 0xFFFFFFFx do LR (jest to nielegalny adres powrotu, tam znajdują się rejestry sterujące).
Powrót z procedury (JR/POP) w momencie, gdy w LR znajduje się nielegalny adres spowoduje
włączenie się mikrokodu wykonującego powrót z obsługi wyjątku -> mikrokod zdejmie ze stosu
zachowane rejestry. Procedura poziomu użytkownika próbując zrobić coś takiego wyleci na błędzie.
Dzięki temu piszemy procedurę obsługi przerwań jak normalną procedurę, np. w C.
The Definitive Guide to the ARM Cortex-M3
6. Na czym polega specyfika mikrokodu ARM?
Procesor nie wykonuje klasycznie rozumianego mikrokodu. Generuje sobie sam instrukcje i
wykonuje je jak normalne instrukcje - zmniejszony czas reakcji procesora dzięki eliminacji czasu
wykonania mikrokodu.
7. Opisz sposób realizacji priorytetów procedur obsługi wyjątków w ARM - Cortex
- przyjście przerwania w trakcie wykonywania aplikacji powoduje składowanie kontekstu
- przyjście przerwania o wyższym priorytecie podczas wykonywania innego przerwania, powoduje
składowanie kontekstu
- po zeskładowaniu kontekstu (aplikacji bądź przerwania) wybierane jest do obsługi przerwanie o
najwyższym priorytecie (może to być inne przerwanie niż te, które uruchomiło składowanie
kontekstu)
- jeśli w trakcie odtwarzania kontekstu przyjdzie przerwanie o wyższym priorytecie, niż
odtwarzane, zapominamy o tym że odtworzyliśmy fragment kontekstu i natychmiast przechodzimy
do obsługi przerwania o wyższym priorytecie.
1. Wymień kategorie VM
a) maszyny czysto wirtualne - np. Java, .NET - zrealizowane czysto programowo, nie
odzwierciedlają żadnego rzeczywistego komputera
b) parawirtualizacja - gość wie, że działa na maszynie wirtualnej, nie na rzeczywistym sprzęcie.
Część zadań realizujemy przez jawne odwołania do hypervisora. Dzięki temu VM działa wydajnie,
a jej napisanie jest prostsze, bo musi mniej zachowań symulować dla gościa. VM realizujemy z
mocnym wsparciem sprzętowym.
c) maszyna realizująca komputer identyczny programowo z istniejącym w rzeczywistości. Mocne
wsparcie sprzętowe.
2. Opisz problem stronicowania w VM
(Realizacja przekształcenia VG -> PG/VH -> PH). W momencie gdy Gość wylatuje na błędzie
jednostki stronicowania, hypervisor musi przejrzeć jego tablice stron (ma do nich dostęp, bo gość
podał mu swoją wartość cR3 - próbując ją wpisać do CR3 wyleciał na błędzie). Jeśli nie znajdzie
deskryptora w tablicach stron gościa, a na błędzie wyleciała aplikacja, niech gość ją ukarze. Jeśli
było to legalne odwołanie, to hypervisor wpisuje do rzeczywistej tabeli stron deskryptor który dla
adresu VG wskazuje na PH. Operacja ta wymaga przejścia po całym drzewie rzeczywistej jednostki
stronicowania dla odczytania każdego poziomu tablicy stron gościa - jest bardzo kosztowna
czasowo. (Rozwiązaniem może być np. parawirtualizacja) Dodatkowym problemem jest
czyszczenie całego bufora translacji stron przy przełączaniu gości.
3. Na czym polega mechanizm intercept?
Jest to mechanizm przechwycenia w hypervisorze, analogiczny do mechanizmu wyjątków w OS.
Przechwycenie polega na przerwaniu wykonywania się kodu gościa i przekazaniu sterowania
hypervisorowi. Przechwycenie powinny powodować:
- przerwania sprzętowe
- błędy
- operacje I/O
- niektóre akcje i operacje procesora, które nabierają nowego znaczenia w kontekście VM
Przechwyceniem nie powinny kończyć się pułapki, które są wewnętrznym mechanizmem OS.
Część przechwyceń będzie się kończyć odbiciem przerwania do gościa. Ponadto potrzebujemy
mechanizmu wstrzykiwania dowolnych wyjątków do gościa.
Można skonfigurować na poziomie sprzętu, jakie akcje będą powodować przechwycenie (dostęp do
rejestrów, wybrane wyjątki systemowe, odczyt CPUID, instrukcje: NOP, PAUSE, HLT, odczyt
rejestru TSC mierzącego czas itd)
4. Opisz usprawnienie w obsłudze stronicowania VM i TLB zastosowane u Intela.
a) Wydłużanie adresu wirtualnego - na jego początku dopisywana jest wartość rejestru
identyfikatora VM - dla hypervisora jest to 0, dla gości wartości niezerowe. Dopiero takie adresy są
wpisywane do bufora translacji adresów, dzięki czemu nie musimy go czyścić przy przełączaniu
gości.
b) Jednostka stronicowania dokonuje dwóch translacji jednocześnie - działa ona jednocześnie na
dwóch strukturach : gościa i hypervisora (nested paging). Za tablewalk w momencie chybienia
TLB, zarówno po strukturach gościa jak i hypervisora odpowiada mikrokod. Mikrokod wpisuje
deskryptor ["id_gościa" + VG -> PH] bezpośrednio do TLB, taki deskryptor nie jest składowany
nigdzie w pamięci.
Wciąż potrzebne jest 20 dostępów do pamięci w pesymistycznym przypadku (4 poziomy tablic
stron hypervisora x 4 poziomy tablic stron gościa dla translacji VG -> PG + 4 poziomy tablic stron
hypervisora dla translacji PG/VH -> PH), ale dzięki temu że wykonuje je mikrokod, zyskujemy 310% przyspieszenia.

Podobne dokumenty