44
Betriebssystembau (BSB) 3. Übung https://ess.cs.tu-dortmund.de/DE/Teaching/WS2017/BSB/ Olaf Spinczyk [email protected] https://ess.cs.tu-dortmund.de/~os AG Eingebettete Systemsoftware Informatik 12, TU Dortmund

Betriebssystembau (BSB): Übung 3 · 6. Nov 2017 Betriebssystembau: 3. Übung 2 Agenda Traps Unterbrechungssynchronisation Aufgabe 2 – Was macht startup.asm für uns? – Was soll

Embed Size (px)

Citation preview

Betriebssystembau (BSB)

3. Übung

https://ess.cs.tu-dortmund.de/DE/Teaching/WS2017/BSB/

Olaf Spinczyk

[email protected]://ess.cs.tu-dortmund.de/~os

AG Eingebettete SystemsoftwareInformatik 12, TU Dortmund

6. Nov 2017 Betriebssystembau: 3. Übung 2

Agenda● Traps

● Unterbrechungssynchronisation

● Aufgabe 2– Was macht startup.asm für uns?

– Was soll in Teil c) und d) passieren?

– Wiederholung: Referenzen in C++● Plugbox und Gate

● Aufgabe 3– Vorstellung

– Wiederholung: Zeiger in C++● Die (komische?) Queue-Klasse

6. Nov 2017 Betriebssystembau: 3. Übung 3

Agenda● Traps

● Unterbrechungssynchronisation

● Aufgabe 2– Was macht startup.asm für uns?

– Was soll in Teil c) und d) passieren?

– Wiederholung: Referenzen in C++● Plugbox und Gate

● Aufgabe 3– Vorstellung

– Wiederholung: Zeiger in C++● Die (komische?) Queue-Klasse

6. Nov 2017 Betriebssystembau: 3. Übung 4

Interrupts und Traps● Interrupts

– durch Hardware ausgelöste Ereignisse

– asynchron zum Programmablauf

– nicht vorhersagbar

– unterbrochener Programmablauf wird nach Bearbeitung wieder aufgenommen

● Traps– durch Instruktion (direkt oder indirekt) ausgelöst

– synchron zum Programmablauf

– unterbrochener Programmablauf kann wieder aufgenommen oder auch abgebrochen werden

6. Nov 2017 Betriebssystembau: 3. Übung 5

Traps – Überblick● Traps werden von der CPU ausgelöst, wenn während der

Ausführung der aktuellen Instruktion ein Problem festgestellt wird …– Division durch Null

– Busfehler – d.h., ein Programm generiert ungültige Adresse

– Betriebssystem-Eingriff erforderlich (z.B. Seitenfehler)

– ungültige Instruktion

● … oder aber auch, wenn die ausgeführte Instruktion direkt einen Trap hervorrufen soll– int 0x80

– syscall / sysenter

6. Nov 2017 Betriebssystembau: 3. Übung 6

(nochmal) x86 IDT: Aufbau

Traps Hardware/Software-IRQs

0 31 255

IDT

Number Description 0 Divide-by-zero 1 Debug exception 2 Non-Maskable Interrupt (NMI) 3 Breakpoint (INT 3) 4 Overflow 5 Bound exception 6 Invalid Opcode 7 FPU not available 8 Double Fault 9 Coprocessor Segment Overrun 10 Invalid TSS 11 Segment not present 12 Stack exception 13 General Protection 14 Page fault 15 Reserved 16 Floating-point error 17 Alignment Check 18 Machine Check 19-31 Reserved By Intel

– Einträge 0-31 für Traps (fest)

– Trap = Ausnahme, die synchronzum Kontrollfluss auftritt

● Division durch 0● Seitenfehler● Unterbrechungspunkt● ...

– Einträge 32-255 für IRQs (variabel)

● Software (INT <nummer>)● Hardware (INT-Pin der CPU

auf HIGH, Nummer auf Datenbus)

6. Nov 2017 Betriebssystembau: 3. Übung 7

Traps – Beispiele● Division durch Null

1 int main() {2 int i, j;34 i=3;5 j=0;67 return i/j;8 }

$ gdb ./divnull(gdb) runProgram received signal SIGFPE, Arithmetic exception.0x0804836b in main () at divnull.c:77 return i/j;

main: pushq %rbp movq %rsp, %rbp movl $3, -4(%rbp) movl $0, -8(%rbp) movl -4(%rbp), %eax cltd idivl -8(%rbp) popq %rbp ret

6. Nov 2017 Betriebssystembau: 3. Übung 8

Traps – Beispiele● Schutzverletzung

1 int main() {2 int *p;34 p = (int *)0;5 6 return *p;7 }

$ gdb ./segfault(gdb) runProgram received signal SIGSEGV, Segmentation fault.0x0804835f in main () at segfault.c:66 return *p;

main: pushq %rbp movq %rsp, %rbp movq $0, -8(%rbp) movq -8(%rbp), %rax movl (%rax), %eax popq %rbp ret

6. Nov 2017 Betriebssystembau: 3. Übung 9

Agenda● Traps

● Unterbrechungssynchronisation

● Aufgabe 2– Was macht startup.asm für uns?

– Was soll in Teil c) und d) passieren?

– Wiederholung: Referenzen in C++● Plugbox und Gate

● Aufgabe 3– Vorstellung

– Wiederholung: Zeiger in C++● Die (komische?) Queue-Klasse

6. Nov 2017 Betriebssystembau: 3. Übung 10

Race ConditionsWikipedia:

„A race condition […] is a flaw in a systemor process whereby the output of theprocess is unexpectedly and criticallydependent on the sequence or timing ofother events.“[http://en.wikipedia.org/wiki/Race_condition]

Ursprung des Begriffsim Elektronikentwurf

6. Nov 2017 Betriebssystembau: 3. Übung 11

Race Conditions in Software● Parallel ablaufende Vorgänge (Prozesse, Threads) verwenden

gemeinsamen Status

● Beispiel:– zwei „gleichzeitig“ ablaufende Prozesse wollen den (ASCII-)Wert eines

Zeichens im Bildschirmspeicher erhöhen. Die Prozesse sehen beide wie folgt aus:

1 int main(void) {2 volatile unsigned char *p;34 p = (unsigned char *)0xb8000;5 6 (*p)++;7 return 0;8 } ???

6. Nov 2017 Betriebssystembau: 3. Übung 12

Race Conditions in Software● Parallel ablaufende Vorgänge (Prozesse, Threads) verwenden

gemeinsamen Status

● Beispiel:– zwei „gleichzeitig“ ablaufende Prozesse wollen den (ASCII-)Wert eines

Zeichens im Bildschirmspeicher erhöhen. Die Prozesse sehen beide wie folgt aus:

1 int main(void) {2 volatile unsigned char *p;34 p = (unsigned char *)0xb8000;5 6 (*p)++;7 return 0;8 }

!!!

6. Nov 2017 Betriebssystembau: 3. Übung 13

Race Conditions in Software● Die harmlos aussehende Anweisung (*p)++; ist nicht atomar!

– In Assembler sieht das wie folgt aus:

main: pushq %rbp movq %rsp, %rbp movq $753664, -8(%rbp) movq -8(%rbp), %rax movzbl (%rax), %eax leal 1(%rax), %edx movq -8(%rbp), %rax movb %dl, (%rax) movl $0,%eax popq %rbp ret

4 p = (...)0xb8000; 6 (*p)++;

Interruptund Kontext-wechsel

Interruptund Kontext-wechsel

6. Nov 2017 Betriebssystembau: 3. Übung 14

Race Conditions in Softwaremovq $753664, -8(%rbp)movq -8(%rbp), %raxmovzbl (%rax), %eaxleal 1(%rax), %edx

movq -8(%rbp), %raxmovb %dl, (%rax)

movq $753664, -8(%rbp)movq -8(%rbp), %raxmovzbl (%rax), %eaxleal 1(%rax), %edxmovq -8(%rbp), %raxmovb %dl, (%rax)

Interrupt, führt zuKontextwechsel

'A' = 0x41

'A' = 0x41

'B' = 0x42

'B' = 0x42

'B' = 0x42

Das Resultat ist falsch (erwartet: 'C' = 0x43), weil der Compiler das Zeichen im Bildschirmspeicher in einem Register zwischengespeichert hat. Jeder Prozess ist dann von diesem Wert als aktuell ausgegangen.Wäre der Interrupt zwei Instruktionen vorher oder später aufgetreten, wäre das Ergebnis korrekt! Race Conditions sind schwer zu finden und zu debuggen!

Das Resultat ist falsch (erwartet: 'C' = 0x43), weil der Compiler das Zeichen im Bildschirmspeicher in einem Register zwischengespeichert hat. Jeder Prozess ist dann von diesem Wert als aktuell ausgegangen.Wäre der Interrupt zwei Instruktionen vorher oder später aufgetreten, wäre das Ergebnis korrekt! Race Conditions sind schwer zu finden und zu debuggen!

6. Nov 2017 Betriebssystembau: 3. Übung 15

Konsistenzprobleme bei Interrupts

Beispiel 1: Systemzeit

hier schlummert möglicherweise ein Fehler ... das Lesen von global_time erfolgt nicht notwendigerweise atomar!

kritisch ist eine Unterbrechung zwischen den beiden Leseinstruktionen bei der 16-Bit-CPU

32-Bit-CPU:mov global_time, %eax

16-Bit-CPU (little endian):mov global_time, %r0; lomov global_time+2, %r1; hi

global_timehi / lo

Resultatr1 / r0Instruktion

002A?

mov global_time, %r0

FFFF ? ?

002A FFFF ? FFFF

/* Inkrementierung */ 002B 0000 ? FFFF

mov global_time+2, %r1 002B 0000 002B FFFF

Beispiel 1: Systemzeit

hier schlummert möglicherweise ein Fehler ... das Lesen von global_time erfolgt nicht notwendigerweise atomar!

kritisch ist eine Unterbrechung zwischen den beiden Leseinstruktionen bei der 16-Bit-CPU

32-Bit-CPU:mov global_time, %eax

16-Bit-CPU (little endian):mov global_time, %r0; lomov global_time+2, %r1; hi

global_timehi / lo

Resultatr1 / r0Instruktion

002A?

mov global_time, %r0

FFFF ? ?

002A FFFF ? FFFF

/* Inkrementierung */ 002B 0000 ? FFFF

mov global_time+2, %r1 002B 0000 002B FFFF

ZustandAusführung

char consume() { int elements = occupied; // 1 if (elements == 0) return 0; char result = buf[nextout]; //'a' nextout++; nextout %= SIZE;

void produce(char data) { // 'b' int elements = occupied; // 1! if (elements == SIZE) return; buf[nextin] = data; nextin++; nextin %= SIZE; occupied = elements + 1; // 2 }

occupied = elements – 1; // 0 return result; // 'a' }

'a' ? ?buf

1 01[0] [1] [2] nextin nextoutocc.

'a' ? ?buf

1 01[0] [1] [2] nextin nextoutocc.

'a' 'b' ?buf

2 02[0] [1] [2] nextin nextoutocc.

'a' 'b' ?buf

2 00[0] [1] [2] nextin nextoutocc.

auch die Pufferimplementierung ist kritisch ...

Beispiel 2: Ringpuffer

ZustandAusführung

char consume() { int elements = occupied; // 1 if (elements == 0) return 0; char result = buf[nextout]; //'a' nextout++; nextout %= SIZE;

void produce(char data) { // 'b' int elements = occupied; // 1! if (elements == SIZE) return; buf[nextin] = data; nextin++; nextin %= SIZE; occupied = elements + 1; // 2 }

occupied = elements – 1; // 0 return result; // 'a' }

'a' ? ?buf

1 01[0] [1] [2] nextin nextoutocc.

'a' ? ?buf

1 01[0] [1] [2] nextin nextoutocc.

'a' 'b' ?buf

2 02[0] [1] [2] nextin nextoutocc.

'a' 'b' ?buf

2 00[0] [1] [2] nextin nextoutocc.

auch die Pufferimplementierung ist kritisch ...

Beispiel 2: Ringpuffer

Beispiele aus der letzten VorlesungBeispiele aus der letzten Vorlesung

6. Nov 2017 Betriebssystembau: 3. Übung 16

Ursache

BS-KernBS-Kernconsume()

main()

handler()

produce()

buf[...]

Kontrollflüsse …… „von oben“ …

… und „von unten“ …

… „begegnen“ sich im Kern.

Anwendungskontrollfluss (A)

Unterbrechungsbehandlung (UB)

Wir müssen (irgendwie) die Konsistenz sicherstellen.

Wir müssen (irgendwie) die Konsistenz sicherstellen.

6. Nov 2017 Betriebssystembau: 3. Übung 17

Naiver Lösungsansatz

BS-KernBS-Kernconsume()

main()

handler()

produce()

buf[...]

Anwendungskontrollfluss (A)

Unterbrechungsbehandlung (UB)

● Zweiseitige Synchronisation– gegenseitiger Ausschluss durch Schlossvariable

(Mutex, Spin-Lock, …)

– wie zwischen zwei Prozessenchar consume() { mutex.lock(); ... char result = buf[nextout++]; ... mutex.unlock(); return result; }

void produce(char data) { mutex.lock(); ... buf[nextin++] = data; ... mutex.unlock();}

Zweiseitige Synchronisation funktioniert natürlich nicht!Zweiseitige Synchronisation funktioniert natürlich nicht!

6. Nov 2017 Betriebssystembau: 3. Übung 18

Besserer Lösungsansatz

BS-KernBS-Kernconsume()

main()

handler()

produce()

buf[...]

Anwendungskontrollfluss (A)

Unterbrechungsbehandlung (UB)

● Einseitige Synchronisation– Unterdrückung der Unterbrechungsbehandlung im Verbraucher

– Operationen disable_interrupts() / enable_interrupts() (im Folgenden o.B.d.A. in „Intel“-Schreibweise: cli() / sti())

char consume() { cli(); ... char result = buf[nextout++]; ... sti(); return result; }

void produce(char data) { // hier nichts zu tun ... buf[nextin++] = data; ... // hier nichts zu tun}

Mit einseitiger Synchronisation funktioniert es …

[warum eigentlich?]

Mit einseitiger Synchronisation funktioniert es …

[warum eigentlich?]

6. Nov 2017 Betriebssystembau: 3. Übung 19

Erstes Fazit● Konsistenzsicherung zwischen Anwendungskontrollfluss (A)

und Unterbrechungsbehandlung (UB) muss anders erfolgen als zwischen Prozessen.

● Die Beziehung zwischen A und UB ist asymmetrisch– Es handelt sich um „verschiedene Arten“ von Kontrollflüssen

– UB unterbricht Anwendungskontrollfluss● implizit, an beliebiger Stelle● hat immer Priorität, läuft durch (run-to-completion)

– A kann UB unterdrücken (besser: verzögern)● explizit, mit cli / sti (Grundannahme 5 aus der letzten Vorlesung)

● Synchronisation / Konsistenzsicherung erfolgt einseitig

Diese Tatsachen müssen wir beachten!(Das heißt aber auch: Wir können sie ausnutzen)

Diese Tatsachen müssen wir beachten!(Das heißt aber auch: Wir können sie ausnutzen)

6. Nov 2017 Betriebssystembau: 3. Übung 20

Agenda● Traps

● Unterbrechungssynchronisation

● Aufgabe 2– Was macht startup.asm für uns?

– Was soll in Teil c) und d) passieren?

– Wiederholung: Referenzen in C++● Plugbox und Gate

● Aufgabe 3– Vorstellung

– Wiederholung: Zeiger in C++● Die (komische?) Queue-Klasse

6. Nov 2017 Betriebssystembau: 3. Übung 21

x86_64-Interrupt-Deskriptortabelle

IDTRIDTR

● maximal 256 Einträge– Basisadresse und Größe in IDTR

● 16 Byte pro Eintrag (Gate)– Task-Gate (Hardwaretasks)

– Trap-Gate (Ausnahmehandler)

– Interrupt-Gate (Ausnahmehandler + cli)

6. Nov 2017 Betriebssystembau: 3. Übung 22

x86_64-Interrupt-Deskriptortabelle

IDTRIDTR

– maximal 256 Einträge● Basisadresse und Größe in IDTR

– 8 Byte pro Eintrag (Gate)● Task-Gate (Hardwaretasks)● Trap-Gate (Ausnahmehandler)● Interrupt-Gate (Ausnahmehandler + cli)

[SECTION .data]

; 'interrupt descriptor table' mit 256 Eintraegen.

idt:%macro idt_entry 1 dw (wrapper_%1 - wrapper_0) & 0xffff dw 0x0010 dw 0x8e00 dw ((wrapper_%1 - wrapper_0) & 0xffff0000) >> 16 dq ((wrapper_%1 – wrapper_0) & 0xffffffff00000000) >> 32%endmacro

; ... wird automatisch erzeugt.

%assign i 0%rep 256idt_entry i%assign i i+1%endrep

idt_descr: dw 256*8-1 ; idt enthaelt 256 Eintraege dq idt

6. Nov 2017 Betriebssystembau: 3. Übung 23

x86_64-Interrupt-Deskriptortabelle

IDTRIDTR

– maximal 256 Einträge● Basisadresse und Größe in IDTR

– 8 Byte pro Eintrag (Gate)● Task-Gate (Hardwaretasks)● Trap-Gate (Ausnahmehandler)● Interrupt-Gate (Ausnahmehandler + cli)

[SECTION .data]

; 'interrupt descriptor table' mit 256 Eintraegen.

idt:%macro idt_entry 1 dw (wrapper_%1 - wrapper_0) & 0xffff dw 0x0010 dw 0x8e00 dw ((wrapper_%1 - wrapper_0) & 0xffff0000) >> 16 dq ((wrapper_%1 – wrapper_0) & 0xffffffff00000000) >> 32%endmacro

; ... wird automatisch erzeugt.

%assign i 0%rep 256idt_entry i%assign i i+1%endrep

idt_descr: dw 256*8-1 ; idt enthaelt 256 Eintraege dq idt

setup_idt: mov rax, wrapper_0 ; ax: Bit 0 .. 15 mov rbx, rax mov rdx, rax shr rbx, 16 ; bx: Bit 16 .. 31 shr rdx, 32 ; edx: Bit 32 .. 64 mov r10, idt ; Zeiger auf Gate mov rcx, 255 ; Zähler.loop: add [r10+0], ax adc [r10+6], bx adc [r10+8], edx add r10, 16 dec rcx jge .loop

lidt [idt_descr] ret

6. Nov 2017 Betriebssystembau: 3. Übung 24

Zustandssicherung● Jede CPU besitzt einen internen Status, der nur einmal

vorhanden ist– repräsentiert als Registerinhalte

● Bei x86_64-Prozessoren siehtdieser wie folgt aus:

Komplette Sicherung (Stack): 22 Register == 176 Bytes!

RAX RSI R8 R12

RBX RDI R9 R13

RCX RBP R10 R14

RDX RSP R11 R15

CS FS

DS GS

ES SS

RFLAGS

6. Nov 2017 Betriebssystembau: 3. Übung 25

Beispiel (Linux arch/x86/entry/calling.h)

97 .macro SAVE_C_REGS offset=0 98 movq %r11, 6*8+\offset(%rsp) 99 movq %r10, 7*8+\offset(%rsp)100 movq %r9, 8*8+\offset(%rsp)101 movq %r8, 9*8+\offset(%rsp)102 movq %rax, 10*8+\offset(%rsp)103 movq %rcx, 11*8+\offset(%rsp)104 movq %rdx, 12*8+\offset(%rsp)105 movq %rsi, 13*8+\offset(%rsp)106 movq %rdi, 14*8+\offset(%rsp)107 .endm

● Implementation als Makro … wird häufiger benötigt :-)– RESTORE_C_REGS entsprechend

6. Nov 2017 Betriebssystembau: 3. Übung 26

Beispiel (Linux arch/x86/kernel/entry_64.S)

1088 ENTRY(error_entry)1089 SAVE_C_REGS 81090 SAVE_EXTRA_REGS 81091 xorl %ebx, %ebx1092 testb $3, CS+8(%rsp)1093 jz .Lerror_kernelspace

[…]

1109 call enter_from_user_mode

● Verwendung z.B. in Interrupthandlern:

6. Nov 2017 Betriebssystembau: 3. Übung 27

Kontextsicherung: Wer macht was?● Kontextsicherung:

– rflags, rsp, cs, ss und rip wurden bereits von der CPU gesichert

– alle weiteren Register müssen vom IRQ-Handler gesichert werden● entweder im Assembler-Teil● oder der Compiler generiert bereits entsprechenden Code

● Kontextsicherung beim Aufruf von Funktionen– Lösung 1: Aufrufende Funktion sichert alle

Register, die sie später noch braucht

– Lösung 2: Aufgerufene Funktion sichert alle Register, die sie verändert

– Lösung 3: Ein Teil der Register wird vom Aufrufer, ein anderer Teil vom Aufgerufenen gesichert

6. Nov 2017 Betriebssystembau: 3. Übung 28

Kontextsicherung in Hochsprachen● In der Praxis wird Lösung 3 verwendet

– Grundsätzlich hängt das natürlich vom Compiler ab– CPU-Hersteller definiert jedoch Konventionen, damit

Interoperabilität auf Binärcodeebene sichergestellt ist–

● Register werden in 2 Subsets aufgeteilt– Flüchtige Register („scratch registers“)

● Compiler geht davon aus, dass Unterprogramm den Inhalt verändert● Aufrufer muss Inhalt gegebenenfalls sichern● bei x86_64 sind rdi, rsi, rdx, rcx und r8 bis r11 als flüchtig definiert

– Nichtflüchtige Register („non-scratch registers“)● Compiler geht davon aus, dass der Inhalt nicht verändert wird● Aufgerufene Funktion muss Inhalt gegebenenfalls sichern● bei x86_64 sind alle sonstigen Register als nicht-flüchtig definiert

– Interrupt-Handler müssen auch flüchtige Register sichern!

6. Nov 2017 Betriebssystembau: 3. Übung 29

Zustandssicherung im Wrapper; Spezifischer Kopf der Unterbrechungsbehandlungsroutinen%macro wrapper 1wrapper_%1: push rbp mov rbp, rsp push rax mov al, %1 jmp wrapper_body%endmacro

; Gemeinsamer Rumpfwrapper_body: cld ; Das erwartet der gcc so. push rcx ; Sichern der flüchtigen Register push rdx ; … rdi, rsi, r8, r9, r10 … push r11 and rax, 0xff ; Der generierte Wrapper liefert nur 8 Bits mov rdi, rax ; Nummer der Unterbrechung übergeben call guardian pop r11 ; Flüchtige Register wieder herstellen ; … r10, r9, r8, rsi, rdi … pop rdx pop rcx pop rax ; Auch die aus dem Kopf pop rbp iretq ; Fertig!

6. Nov 2017 Betriebssystembau: 3. Übung 30

Initialisierung der PICs – Teil 1OO-Stubs Einstellung:

00010001

Master

00010001

Slave

OO-Stubs Einstellung:

00100000

Master

00101000

Slave

6. Nov 2017 Betriebssystembau: 3. Übung 31

Initialisierung der PICs – Teil 1OO-Stubs Einstellung:

00010001

Master

00010001

Slave

OO-Stubs Einstellung:

00100000

Master

00101000

Slave

; Neuprogrammierung der PICs (Programmierbare Interrupt-Controller),; damit alle 15 Hardware-Interrupts nacheinander in der idt liegen.

reprogram_pics: mov al,0x11 ; ICW1: 8086-Modus mit ICW4 out 0x20,al call delay out 0xa0,al call delay mov al,0x20 ; ICW2 Master: IRQ # Offset (32) out 0x21,al call delay mov al,0x28 ; ICW2 Slave: IRQ # Offset (40) out 0xa1,al call delay

6. Nov 2017 Betriebssystembau: 3. Übung 32

Mapping der HW-IRQs (OO-Stubs)

IRQ 0 System Timer IRQ 1 Tastatur (Keyboard) IRQ 2 PIC Kaskadierung IRQ 3 COM 2 IRQ 4 COM 1 IRQ 5 IRQ 6 Floppy IRQ 7 LPT 1 IRQ 8 CMOS Echtzeituhr IRQ 9 (HW-Mapping von IRQ 2) IRQ10 IRQ11 IRQ12 PS/2 IRQ13 numerischer Coprozessor IRQ14 1. IDE Port IRQ15 2. IDE Port

Traps <unbenutzt>

0 255

IDT HW

4732

Standard AT-IRQ-BelegungStandard AT-IRQ-Belegung

6. Nov 2017 Betriebssystembau: 3. Übung 33

Initialisierung der PICs – Teil 2OO-Stubs Einstellung:

00000100

Master

0000010

Slave

OO-Stubs Einstellung:

00000011

Master

00000011

Slave

6. Nov 2017 Betriebssystembau: 3. Übung 34

Initialisierung der PICs – Teil 2OO-Stubs Einstellung:

00000100

Master

0000010

Slave

OO-Stubs Einstellung:

00000011

Master

00000011

Slave

...mov al,0x04 ; ICW3 Master: Slaves an IRQsout 0x21,alcall delaymov al,0x02 ; ICW3 Slave: Verbunden mit IRQ2 des Mastersout 0xa1,alcall delaymov al,0x03 ; ICW4: 8086-Modus und automatischer EIOout 0x21,alcall delayout 0xa1,alcall delay...

6. Nov 2017 Betriebssystembau: 3. Übung 35

Programmierung der PICsInterruptmaske (IMR)

● schreiben und lesen über Port 0x21 / 0xa1

Interruptmaske (IMR)● schreiben und lesen

über Port 0x21 / 0xa1

6. Nov 2017 Betriebssystembau: 3. Übung 36

Programmierung der PICsInterruptmaske (IMR)

● schreiben und lesen über Port 0x21 / 0xa1

Interruptmaske (IMR)● schreiben und lesen

über Port 0x21 / 0xa1

...mov al,0xff ; Hardware-Interrupts durch PICsout 0xa1,al ; ausmaskieren. Nur der Interrupt 2,call delay ; der der Kaskadierung der beidenmov al,0xfb ; PICs dient, ist erlaubt.out 0x21,al

ret

6. Nov 2017 Betriebssystembau: 3. Übung 37

Agenda● Traps

● Unterbrechungssynchronisation

● Aufgabe 2– Was macht startup.asm für uns?

– Was soll in Teil c) und d) passieren?

– Wiederholung: Referenzen in C++● Plugbox und Gate

● Aufgabe 3– Vorstellung

– Wiederholung: Zeiger in C++● Die (komische?) Queue-Klasse

6. Nov 2017 Betriebssystembau: 3. Übung 38

Agenda● Traps

● Unterbrechungssynchronisation

● Aufgabe 2– Was macht startup.asm für uns?

– Was soll in Teil c) und d) passieren?

– Wiederholung: Referenzen in C++● Plugbox und Gate

● Aufgabe 3– Vorstellung

– Wiederholung: Zeiger in C++● Die (komische?) Queue-Klasse

6. Nov 2017 Betriebssystembau: 3. Übung 39

Interrupthandler in OO-Stubs

// ASSIGN: Einstoepseln einer Behandlungsroutine, die in Form eines Gate-// Objekts angegeben wird.void assign (unsigned int slot, Gate& gate);

// REPORT: Abfrage eines eingetragenen Gate Objekts.Gate& report (unsigned int slot);

Keyboard

Keyboard_Controller

Key

CPU

PIC Plugbox

guard

Gate

Panic

device

machine

6. Nov 2017 Betriebssystembau: 3. Übung 40

Was sind C++-Referenzen?● Sprachlich: Aliase für Objekte

● Technisch: Initialisierte und unveränderliche Zeiger– Wenn eine Referenz initialisiert wird, wird automatisch die Adresse

des Initialisierers gebildet.

– Wenn eine Referenz in einem Ausdruck benutzt wird, wird automatisch das referenzierte Objekte benutzt.

int v1;int &ref = v1;int v2 = ref;

int &f(int &refarg) { refarg = 42; return refarg;}

int v3 = f(v2);

int v1;int *ref = &v1;int v2 = *ref;

int *f(int *refarg) { *refarg = 42; return &*refarg;}

int v3 = *f(&v2);

technisch äquivalent

6. Nov 2017 Betriebssystembau: 3. Übung 41

Agenda● Traps

● Unterbrechungssynchronisation

● Aufgabe 2– Was macht startup.asm für uns?

– Was soll in Teil c) und d) passieren?

– Wiederholung: Referenzen in C++● Plugbox und Gate

● Aufgabe 3– Vorstellung

– Wiederholung: Zeiger in C++● Die (komische?) Queue-Klasse

6. Nov 2017 Betriebssystembau: 3. Übung 42

Queue

Locker

Guard Secure

Gate

Chain

Keyboard

guard

device

object

Panic

Aufgabe 3: Pro-/Epilog-Modell

Die Hauptarbeit steckt in GuardDie Hauptarbeit steckt in Guard

Das Modell wird ausführlich in der kommenden Vorlesung besprochen.Das Modell wird ausführlich in der kommenden Vorlesung besprochen.

6. Nov 2017 Betriebssystembau: 3. Übung 43

Knifflige Zeiger: Queue in Aufgabe 3● Queue-Elemente erben von Chain

– Sie erben damit auch einen Zeigerauf das nächste Element

● Ein Queue-Objekte enthält– einen Zeiger auf das erste Element

– einen Zeiger auf einen Zeiger namens 'tail'!?

class Queue { Chain* head; Chain** tail;public: Queue () { head = 0; tail = &head; } void enqueue (Chain* item); Chain* dequeue (); void remove (Chain*);};

class Chain {public: Chain* next;};

6. Nov 2017 Betriebssystembau: 3. Übung 44

Knifflige Zeiger: Queue in Aufgabe 3● 'tail' ist ein Zeiger auf den 'next' Zeiger im letzten Element

– Das macht das Anhängen (enqueue) sehr einfach:

NULL

q

'a'

NULL

e1q.enqueue(&e1)

'b'

?

e2

'a'

NULL

'b'

?

'a'

NULL

'b'

?

item->next = NULL;

*tail = item;

tail = &item->next;

item->next = NULL;*tail = item;tail = &item->next;

'a' 'b'

NULL

q.enqueue(&e2) ...