View
213
Download
0
Category
Preview:
Citation preview
Betriebssystembau (BSB)
3. Übung
https://ess.cs.tu-dortmund.de/DE/Teaching/WS2017/BSB/
Olaf Spinczyk
olaf.spinczyk@tu-dortmund.dehttps://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) ...
Recommended