---
# System prepended metadata

title: Lista 1
tags: [sju21, ćwiczenia]

---

# 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