# Lista 1 ###### tags: `sju21` `ćwiczenia` :::warning <small>**Uwaga!** Zadanie 1-7 jest za dwa punkty!</small> ::: ## Deklaracje Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie w trakcie dyskusji (co najwyżej jedno!) oznacz je znakiem ==X== na żółtym tle. **UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!** :::danger | | 1-1 | 1-2 | 1-3 | 1-4 | 1-5 | 1-6 |1-7(2)| | ---------------------:| --- | --- | --- | --- | --- | --- | --- | | Jacek Bizub | X | X | X |==X==| X | X | X | 8 | Maciej Dudek | X | X | X | X | | | | 4 | Wojciech Jasiński | X | X | X | | | | | 3 | Artur Juraszek | X | X | | | | | | 2 | Aleksandra Kosińska | | | | | | | | 0 | Michał Myczkowski | | | | | | | | 0 | Michał Jan Odorczuk | X | X | X | X |==X==| | | 5 | Damian Ratajski | | | | | | | | 0 | Łukasz Siudek | | | | | | | | 0 | Błażej Sowa | | | | | | | | 0 | Cezary Stajszczyk | | | | | | | | 0 | Andrzej Turko | X | X | X | X |==X==| X | X | 8 | Maksymilian Zawartko | X | X | X | X | X | X | | 6 ::: ## Zadanie 1-1 :::info Autor: Artur Juraszek ::: tryb użytkownika - przeznaczony dla programów wykonywanych pod kontrolą systemu operacyjnego stan procesora, podczas trwania którego każda próba wykonania instrukcji uprzywilejowanej skończy się wygenerowaniem wyjątku tryb nadzorcy - stan przeznaczony dla systemu operacyjnego, w którym dozwolone jest wykonywanie wszystkich instrukcji instrukcje uprzywilejowane - takie, które mogą być wykonane jedynie w trybie nadzorcy. Gdyby pozwolić na ich wykonanie programom działającym w przestrzeni użytkownika, mogłyby one dokonać niepożądanych w ich przypadku działań takich jak STOP lub RESET lub, w przypadku instrukcji operujących na rejestrze SR, po prostu zmienić swój tryb na uprzywilejowany. Lista instrukcji uprzywilejowanych: - ANDI to SR -> AND na rejestrze stanu procesora (przy użyciu wartości _immediate_) - EORI to SR -> eXclusive OR na SR (jak wyżej, przy użyciu _immediate_) - MOVE from SR -> wykonanie kopii rejestru SR (uprzywilejowana jedynie na Motoroli 68010 [i późniejszych?], na której to wprowadzono instrukcję MOVE from CCR odczytującą fragment SR kodujący stan _condition codes_, czyli tę jego część, która może okazać się interesująca dla programów uruchomionych w trybie użytkownika) - MOVE to SR -> zapisanie wartości operandu źródłowego w rejestrze SR - MOVE USP -> kopia z/do rejestru stosu użytkownika - analogiczny efekt w trybie użytkownika można osiągnąć używając po prostu MOVE SP/A7, w trybie nadzorcy jednak SP oraz A7 wskazują na stos odrębny - MOVEC -> operacje na rejestrach kontrolnych, np VBR - MOVES -> operacja na adresach z przestrzeni adresowych oznaczonych w rejestrach SFC lub DFC - ORI to SR -> bitowa alternatywa wartości immediate oraz rejestru SR - RESET -> wysyła sygnał rozkazu zresetowania się do podłączonych urządzeń - RTE -> powrót z procedury obsługi wyjątku, przywraca zapisane wcześniej wartości SR oraz PC - STOP -> wstrzymuje działanie procesora do momentu nadejścia przerwania ## Zadanie 1-2 :::info Autor: Wojciech Jasiński ::: * Kiedy procesor znajduje się w trybie uprzywilejowanym? - kiedy bit S (Supervisor State) w SR jest zapalony * Czemu procesor ma odrębny wskaźnik stosu dla trybu użytkownika «USP» i nadzorcy «SSP»? - żeby system nie martwił się co nabroił użytkownik na swoim stosie (i na odwrót). Użytkownik mógłby np. ustawić swój wskaźnik stosu na dziwne miejsce (jak początek pamięci), z którego brakowałoby miejsca dla systemu na rozwinięcie ramek stosu do obsługi przerwania; albo na adres, w którym jądro trzyma ważne dane (które zostałyby nadpisane) * Czemu skonstruowanie bezpiecznego systemu operacyjnego jest niemożliwe bez takiego wsparcia ze strony procesora? - patrz wyżej ## Zadanie 1-3 :::info Autor: Maciej Dudek ::: Aby procesor przeszedł z trybu użytkownika do trybu nadzorcy dzieje się tylko gdy: * program użytkownika wywoła doprowadzi do przerwania(trapy, nielegalne instrukcji) * przyszło zewnętrzne przerwanie Aby przejśc z trybu nadzorcy do trybu użytkownika można wykonać kilka instrukcji: * RTE (return from exception) * MOVE to SR * ANDI to SR * EORI to SR Każda instrukcja poza RTE pozwala na zmienienie SR w tym bitu S, ale kontynuacja odbywa się bez zmiany wskaźnika instrukcji. Instruckja RTE ładuje nowy stan procesora ze stosu. Inne zachowanie wynika z wprowadzenia nowych formatów ramek stosu fraz z serią 68010. ## Zadanie 1-4 :::danger Autor: Jacek Bizub ::: > Załóżmy, że program działający w trybie użytkownika na procesorze M68010 wykonał dzielenie przez zero. Co robi procesor [2, 6.2] zanim wskoczy pod etykietę «ZeroDivTrap»? Procesor musi zapisać na stosie obecny stan rejestru `SR` (status register) oraz przejść w tryb uprzywilejowany ustawiając flagę `S` oraz wyłączyć śledzenie poprzez zgaszenie bitu`T`. Konstruuje ramkę wyjątku (`SR`, `PC` oraz `vector offset`). > Przeprowadź uczestników zajęć przez procedurę `vPortSetupExceptionVector`, w której zainicjowano wektor wyjątków procesora. Na podstawie tabeli [2, 6-2] omów warunki jakie zmuszą procesor do wejścia do poszczególnych procedur. ```c= ExcVecBase = (ExcVec_t *)aBootData->bd_vbr; ``` Uwzględniamy offset z rejestru `VBR` ```c /* Set up magic number and pointer to boot data for debugger. */ 111 ExcVec[0] = (ESR_t)0x1EE7C0DE; 112 ExcVec[1] = (ESR_t)aBootData; ``` Początek wektora wyjątków zawiera obsługę resetu. Ustawiamy kolejno początkową wartość stack pointera oraz adres programu bootującego. ```c /* Initialize M68k interrupt vector. */ 115 for (int i = EXC_BUSERR; i <= EXC_LAST; i++) 116 ExcVec[i] = BadTrap; ``` Inicializujemy wektor domyślnym adresem. Nie będziemy wypełniać wszystkich 255 pól a nie chcemy wylecieć w kosmos. ```c 118 /* Initialize exception handlers. */ 119 ExcVec[EXC_BUSERR] = BusErrTrap; 120 ExcVec[EXC_ADDRERR] = AddrErrTrap; 121 ExcVec[EXC_ILLEGAL] = IllegalTrap; 122 ExcVec[EXC_ZERODIV] = ZeroDivTrap; 123 ExcVec[EXC_CHK] = ChkInstTrap; 124 ExcVec[EXC_TRAPV] = TrapvInstTrap; 125 ExcVec[EXC_PRIV] = PrivInstTrap; 126 ExcVec[EXC_TRACE] = TraceTrap; 127 ExcVec[EXC_LINEA] = IllegalTrap; 128 ExcVec[EXC_LINEF] = IllegalTrap; 129 ExcVec[EXC_FMTERR] = FmtErrTrap; ``` Wpisujemy odpowiednie handlery dla danych wyjątków. Opis znaczenia wyjątków: | wyjątek | powód | | --- | --- | | EXC_BUSERR | najczęściej: bug w programie, odwołanie do nieistniejącej pamięci ;; rzadziej: uszkodzenie hardware'u| | EXC_ADDRERR | próba odczytania słowa/longa z nieparzystego adresu | | EXC_ILLEGAL | procesor nie rozpoznał słowa jako znanej instrukcji | | EXC_ZERODIV | dzielenie przez zero | | EXC_CHK | "asercja" z instrukcji CHK nie została spełniona | | EXC_TRAPV | robiliśmy arytmetykę i się przekręciliśmy | | EXC_PRIV | próba wykonania instrukcji uprzywilejowanej z konstekstu użytkownika | | EXC_TRACE | jeśli program działa w trybie śledzenia to wyjątek jest rzucany po każdej instrukcji | | EXC_LINEA/EXC_LINEF | instrukcja oddelegowana do emulatora (linia 1010 lub 1111) | | EXC_FMTERR | niepoprawny format ramki wyjątku | ```c= /* Initialize level 1-7 interrupt autovector in Amiga specific way. */ 132 ExcVec[EXC_INTLVL(1)] = AmigaLvl1Handler; 133 ExcVec[EXC_INTLVL(2)] = AmigaLvl2Handler; 134 ExcVec[EXC_INTLVL(3)] = AmigaLvl3Handler; 135 ExcVec[EXC_INTLVL(4)] = AmigaLvl4Handler; 136 ExcVec[EXC_INTLVL(5)] = AmigaLvl5Handler; 137 ExcVec[EXC_INTLVL(6)] = AmigaLvl6Handler; 139 for (int i = INTB_TBE; i <= INTB_EXTER; i++) 140 IntVec[i].code = DummyInterruptHandler; ``` Ustawiamy domyślną obsługę przerwań ```c= 152 /* Intialize TRAP instruction handlers. */ 153 for (int i = EXC_TRAP(0); i <= EXC_TRAP(15); i++) 154 ExcVec[i] = TrapInstTrap; ``` Kierujemy wszystkie 15 trapów do handlera `TrapInstTrap` ## Zadanie 1-5 :::info Autor: Michał Jan Odorczuk ::: "W pliku trap.S zaimplementowano wejście do jądra w wyniku otrzymania wyjątku procesora lub pułapki. Wykonaj deasemblację pliku «trap.o» przy pomocy polecenia m68k-elf-objdump. Następnie przeprowadź uczestników zajęć od «ZeroDivTrap» do końca procedury «EnterTrap». Co znajduje się na stosie przed wejściem do «EnterTrap», a co w momencie wołania «vPortTrapHandler»? Co robią poszczególne instrukcje manipulujące wskaźnikiem stosu?" ```c= #define HANDLER(name,trap) \ ENTRY(name); \ move.w __IMMEDIATE trap,-(sp); /* save trap number */ \ // Odkładamy na stos numer pułapki (stan przed EnterTrap) jra EnterTrap; \ // Wkraczamy w handler END(name) # List of trap handlers HANDLER(BadTrap,T_UNKNOWN) HANDLER(BusErrTrap,T_BUSERR) HANDLER(AddrErrTrap,T_ADDRERR) HANDLER(IllegalTrap,T_ILLINST) HANDLER(ZeroDivTrap,T_ZERODIV) HANDLER(ChkInstTrap,T_CHKINST) HANDLER(TrapvInstTrap,T_TRAPVINST) HANDLER(PrivInstTrap,T_PRIVINST) HANDLER(TraceTrap,T_TRACE) HANDLER(FmtErrTrap,T_FMTERR) HANDLER(TrapInstTrap,T_TRAPINST) ENTRY(EnterTrap) movem.l d0-a7,-(sp) /* save all registers */ move.l usp,a0 move.l a0,-(sp) /* save user stack pointer */ move.l sp,-(sp) /* pass trap frame as an argument */ // Stan przed vPortTrapHandler: // - numer pułapki // - rejestry procesu // - wskaźnik na stos użytkownika // - ramka stosu jsr vPortTrapHandler addq.l #4,sp move.l (sp)+,a0 move.l a0,usp /* restore user stack pointer */ movem.l (sp)+,d0-a7 /* restore all registers */ addq.l #2,sp /* pop trap number */ rte END(EnterTrap) # vim: ft=gas:ts=8:sw=8:noet: ``` ## Zadanie 1-6 :::info Autor: Maksymilian Zawartko ::: Skrót procedury `vPortDefaultTrapHandler`: ``` set pc and sr depending on processor model if supervisor mode { Determine real stack pointer value, as processor pushes data on stack before it enters the trap handler. } else { sp = frame->usp } print registers contents if memory fault { print info what data/instruction caused the fault } ``` Pola TrapFrame odkładane na stos przez procesor to sr, pc i inne pola zawarte w jednej ze struktur: ```c= typedef struct { uint16_t sr; uint32_t pc; } trap_stk_000_t; typedef struct { uint16_t status; uint32_t address; uint16_t instreg; // never used uint16_t sr; uint32_t pc; } trap_stk_000_memacc_t; typedef struct { uint16_t sr; uint32_t pc; uint16_t format; } trap_stk_010_t; typedef struct { uint16_t sr; uint32_t pc; uint16_t format; uint16_t ssw; uint32_t address; uint16_t pad[22]; } trap_stk_010_memacc_t; ``` usp, d0-a6, sp, trapnum są odkładane przez kod wejścia do procedury obsługi pułapki. Po napotkaniu błędu adresu M68010 odkłada na stos te same informacje, co w przypadku błędu szyny (bus error), czyli to, co na rysunku 6-8 z "M68000 Microprocessor’s User Manual". ![](https://i.imgur.com/jjDQ2aG.png) Jądro może chcieć zmienić zawartość TrapFrame i wrócić do przerwanego kontekstu, gdy użytkownik woła coś w stylu printStackTrace. ## Zadanie 1-7 :::info Autor: Andrzej Turko ::: Kod (preemption/main.c): ```c= extern void vPortDefaultTrapHandler(struct TrapFrame *); void vPortTrapHandler(struct TrapFrame *frame) { static int cnt = 0; if (frame->trapnum == T_TRAPINST) { printf ("It's a trap! -- %d\n", cnt++); return; } vPortDefaultTrapHandler(frame); } ``` Uruchomienie debuggera: ``` examples/preemption$ make debug-rom ``` 1. trap #1 -- okłada status register (ps) oraz program counter na stos 2. Zapisanie id trapa (trap.S: **niekoniecznie ten sam, z którym trap był zawołany!**) 3. zapisanie stanu procesora (pozostałe rejestry) 4. branch do obsługi wyjątku ... obsługa wyjątku ... 6. Odzyskujemy wartości rejestrów zapisane w punkcie 3. 5. RTE -- przywracamy to, co trap wrzuciło na stos