tryby rzeczywistości 3/9 #Po co abstrakcja pierwszej warstwy;
//wróć do spisu treści; tekst jest fragmentem większej całości;
#Po co abstrakcja pierwszej warstwy;
Zauważcie, że bez względu w jakim trybie bitowym byście nie startowali (czyli jaka jest długość rejestrów danych, czy one są z ixem – rozszerzone, czy bez ixa) tak czy siak trzeba sprawdzić czy po kablach leci prąd i czy wraca na pewno to co chcieliśmy. Nie ma tu żadnej abstrakcji.
Pierwszą “abstrakcją” jako sobie zapisujemy w RAM jest lista “urządzeń podpiętych do kabla i numery kabli”. Oraz zwrotka czy urządzenie odpowiada. To wszystko jest we flashu (ROM) hardcoded. Niezależnie czy to jest UEFI czy BIOS czy cokolwiek innego sobie podepniecie. Same podpięcia (lista IVT, PIC -> IRQ) to taka ściągawka. Abstraktem jest wyznaczenie takiego zakresu pamięci, którego na razie umownie (później wpisane będą wołane GPfaulty) nie ruszamy, ale rozmiar tej zajętej, pamięci pierwsze 256 pozycji po 4 jest stały. Nawet jeśli jest inny (bo tak sobie ktoś wymyślił) to wynika z dokumentacji i umownie “na razie tego w kodzie nie ruszamy”.
Uczynienie abstrakcji (umówienie się) służy temu, aby urządzenia pytane były później przez załadowany sterownik. Uruchomienie go polega na tym, że wysyłamy na In/Out sygnał do urządzenia, który czyni je Panem (Master) i będzie odpowiadał na zapytania jedynie w formacie “grzecznie pytam, grzecznie proszę”. Format grzecznie pytam, grzecznie proszą to get/set czy read/write. Po otrzymaniu takiej instrukcji urządzenie ją samodzielnie rozpatruje zgodnie z dołączonym na szynie ustawieniem bitowym (o co jest pytanie). Długość tego argumentu (w bitach) wyznacza z jaką rozdzielczością urządzenie może dyskryminować polecenie. Czyli do ilu różnych ustawień się odwołać. Kiedyś można po prostu było policzyć przewody w taśmie na hdd (czy flopie), dziś sygnał leci przez nieco bardziej złożony przetwornik na obu końcach, żeby się na każdym przewodzie upchnęło “wektor” czyli taką funkcję prądu w czasie, aby wyznaczała paczkę bitów. Skutek jest ten sam – ustawienie przełączników, które fizycznie są tranzystorami, ale gdyby to robić “powoli” na dużym prądzie spokojnie mogłyby to być inne urządzenia robiące dokładnie to samo tylko baaaardzo powoli.
Ponieważ pierwsze oflagowanie jako Pan/Niewolnik jest zadawane przez In/Out to wykorzystanie dokładnie tego samego kanału komunikacji później (czyli instrukcji In/Out) może wymusić dokładnie takie same skutki (na twardo przekazać ustawienia tak jak się to robi brzęczykowi). Z racji, że urządzenia będzie używać małpa łysa to pewne procesy (takie jak ten) chcemy później wykluczyć. Zwirtualizować do get/set czy write/read czy jakkolwiek sobie to nazwiecie na ludzkie potrzeby.
W dalszych procesach, jakie wykonamy uruchamiając kolejne warstwy urządzenia (uruchamiając kolejne programy) będziemy tworzyć umowne (abstrakcyjne) ograniczenia warunkowe. Którę będą harcerskim słowem honoru, czyli zmianą przełączników kierujących do funkcji i to innej. Ta funkcja to będzie takie grzeczne “Pan był łaskaw prosić, aby tego polecenia nie wykonywać i odpowiedzieć GPfault” (GPF to general protection fault). Czyli zabronimy sami sobie dostępu do pewnych ustawień pamięci. Oczywiście nikt nie broni nam dopisania na tablicy przecinka “bez powodu”. Żadne zwierzę nie zabije innego. Bez powodu. Czyli możemy stworzyć jakiś warunek, że wysyłając jakąś sekwencję (wirtualizacja) odwołujemy się obszaru pamięci, który jest uprawniony załadować się na rejestr instrukcji z taką komendą i pobrać z innego (wcześniej wyznaczonego) obszaru pamięci ustawienia (które urządzenie/kable, co mu zrobić). A możemy w ogóle takich warunków nie tworzyć (nie zabraniać sobie) przy czym trzeba tego pilnować, co oznacza, że musimy to uwzględnić w programie jakie uruchomimy (a można przytomnie przyjąć, że będziecie chcieli załadować z bootloadera OS, a nie tylko Pong:
). Pong w tym trybie “tekstowym” VGA to jest tak zgrubnie mniej niż sto linijek kodu, gra poleci w rozdzielczości 80×25. Którą możecie sobie dodać na końcu sekwencji sprawdzania bootable devices zamiast wyświetlania “No Bootable Device” i haltowania kloca. Albo przed – najpierw Pong, później (po wciśnięciu esc, bo się znudził) pytanie o sektory rozruchowe.
Choć oczywiście napisanie sobie Ponga pod bootloader (czyli jedynego ładowanego programu), których chodzi na 64 bitowej architekturze i jest odpalany z USB stick nie jest niczym zdrożnym. Tylko nie wiem po kiego odpalać 64, można zostać w 16 na real mode i też będzie klawo.
Te udziwnione warunki możemy stworzyć wyłącznie w jednym celu – ponieważ OS (konkretnie jego kernel), który sobie skompilujemy dalej będzie tę dziurę w bezpiece przepuszczał i nie uruchomi SMAP/SMEP (ochrona przed dostępem do pamięci oflagowanej jako inny poziom dostępu / ochrona przed wykonaniem instrukcji z innego poziomu dostępu). Wszystkie te warunki jakie stworzymy, i poziomy dostępu (ring 0-3) to oczywiście nasza wola, ale architektura jest do tego przygotowana (ma układy do flagowania, które możemy uruchomić bądź nie).
Jeśli sobie taką dziurę zrobimy to sami jesteśmy sobie winni co zostanie do niej wsadzone i jakie będą po tym wrażenia. Oczywiście nikt nie zmusza do używania całego klocka i spokojnie możecie sobie zrobić program, który wczytany jako pierwszy się z tym nie pofatyguje zostawiając Wam całą maszynę otwartą do zabawy. Nawet możecie sobie we flashu (startowy ROM) zrobić coś innego niż przewiduje producent płyty. Wszystkie abstrakcje które są dodawane, wszystkie zabezpieczenia są wymuszane przez Was. Wiążecie sobie ręce, aby czegoś przez nieuwagę nie sponiewierać. O ile te kilka kilo kodu na starcie jesteście w stanie ogarnąć z kartką i ołówkiem, to robienie tego tak dalej na giabajtach albo by powodowało dość sztywny i nieefektywny podział pamięci (tak jak w IVT wykluczenie pierwszego 256×4) gdy nie potrzebujecie całego bufora i wozicie się z kupą zer, albo problemy obsługi “a jeśli wrzuciłem więcej niż mogę”. Czyli wszystkie reguły abstrakcyjne, które wprowadzicie (choćby ładując komercyjny boot i OS) są po to, żeby zrobić bezpieczną piaskownicę.
Wiele z tego wiązania rąk wynika z faktu, że uruchomicie programy pisane przez zespoły ludzi, którzy nie zawsze się dogadali co pozmieniają, i też wyznaczają sobie piaskownice coby się grabkami i łopatkami nie kaźnić. Te wszystkie poziomy abstrakcji, które dodamy mają Wam ułatwiać życie. Zużyje to zasoby na przetwarzanie tych abstrakcji i wielokrotnie uruchomi bezpiekę, która wywali do kosza przygotowaną paczkę instrukcji marnując cykle na przywrócenie procesu (dalej opiszę jak to z ring3 robimy w programach, niektórzy robią to nieświadomie; inni z konieczności; i są obejścia bo na gpu ten numer się nie uda).
Istotne jest to (w procesie tworzenia abstraktów) iż ograniczamy sobie dostęp do rzeczywistości (odklejamy się) aby przetrwać w środowisku, które okaże się dla naszego pojmowania nazbyt złożone. A takie wytworzymy samą liczbą bardzo prostych poleceń, które wydamy (zwyczajowo wczytując je z pamięci zewnętrznej).
