Erste Hilfe — Änderungen 8002 → 8003

Zeile 95: Zeile 95:
 
Num wird bei jedem Schleifendurchlauf der Wert von key_pressed neu geladen und getestet.
 
Num wird bei jedem Schleifendurchlauf der Wert von key_pressed neu geladen und getestet.
 
=== __attribute__((packed)) ===
 
=== __attribute__((packed)) ===
−
Und wieder macht uns der Compiler ein schönes Codekonstrukt kaputt, weil er structs "optimiert". Folgender Code erstellt einen IDT-Eintrag:
+
Und wieder macht uns der Compiler ein schönes Codekonstrukt kaputt, weil er structs „optimiert“. Folgender Code erstellt einen IDT-Eintrag:
 
<c>
 
<c>
−
VOID idt_set_entry(uint8 n, unit16 sel, void* handler, uint8 flags)
+
VOID idt_set_entry(uint8_t n, uint16_t sel, void* handler, uint8_t flags)
 
{
 
{
 
   idt_entry[n].resreved = 0;
 
   idt_entry[n].resreved = 0;
 
   idt_entry[n].flags  = flags;
 
   idt_entry[n].flags  = flags;
 
   idt_entry[n].sel    = sel;
 
   idt_entry[n].sel    = sel;
−
   idt_entry[n].baseLo  = (handler) & 0x0000FFFF;
+
   idt_entry[n].baseLo  = (uintptr_t)(handler) & 0x0000FFFF;
−
   idt_entry[n].baseHi  = (handler) >> 16;
+
   idt_entry[n].baseHi  = (uintptr_t)(handler) >> 16;
 
   return;
 
   return;
 
}
 
}
Zeile 112: Zeile 112:
 
struct idt_entry
 
struct idt_entry
 
{
 
{
−
     unit16 baseLo;
+
     uint16_t baseLo;
−
     uint16 sel;
+
     uint16_t sel;
−
     uint8 always0; //reserved
+
     uint8_t always0; //reserved
−
     uint8 flags;
+
     uint8_t flags;
−
     uint16 baseHi;
+
     uint16_t baseHi;
−
}
+
};
 
</c>
 
</c>
−
Und genau an dieser Stelle produziert der Compiler mit seiner Optimierung einen Fehler und die CPU wird sich mit einem freundlichen Triple-Fault verabschieden. Denn der Compiler hat die Eigenart, die Elemente eines structs an DWORD-Grenzen auszurichten, weil dann die CPU schneller arbeiten kann. Das hat in diesem Fall aber fatale Folgen, denn aus dem angegebenen WORDs/BYTEs macht der Compiler einfach mal DWORDs. Und damit ist natürlich der IDT-Eintrag komplett falsch. Glücklicherweise gibt es aber eine ganz einfache Lösung:
+
Und genau an dieser Stelle produziert der Compiler mit seiner Optimierung einen Fehler und die CPU wird sich mit einem freundlichen Triple-Fault verabschieden. Denn der Compiler hat die Eigenart, die Elemente eines structs an DWORD-Grenzen auszurichten (auf i386), weil dann die CPU schneller arbeiten kann. Das hat in diesem Fall aber fatale Folgen, denn aus dem angegebenen WORDs/BYTEs macht der Compiler einfach mal DWORDs. Und damit ist natürlich der IDT-Eintrag komplett falsch. Glücklicherweise gibt es aber eine ganz einfache Lösung:
 
<c>
 
<c>
 
struct idt_entry
 
struct idt_entry
Zeile 134: Zeile 134:
  
 
==== „==“ ist ungleich „=“ ====
 
==== „==“ ist ungleich „=“ ====
−
Es ist eigentlich ein totaler Anfängerfehler, in Bedingungen das Zuweisungszeichen '=' mit dem Vergleichsoperator '==' zu verwechseln. Also bitte aufpassen!
+
Es ist eigentlich ein totaler Anfängerfehler, in Bedingungen das Zuweisungszeichen „=“ mit dem Vergleichsoperator „==“ zu verwechseln. Also bitte aufpassen!
  
 
==== Zahlensysteme ====
 
==== Zahlensysteme ====
Zeile 153: Zeile 153:
 
==== Wie ging nochmal dieses NOT?! ====
 
==== Wie ging nochmal dieses NOT?! ====
 
Ganz einfache Aufgabe: Alle Bits in einer Maske umkippen, also ein logisches NOT. Wie hieß nochmal der Operator? Achja:
 
Ganz einfache Aufgabe: Alle Bits in einer Maske umkippen, also ein logisches NOT. Wie hieß nochmal der Operator? Achja:
−
  int gekippt = !0xFA;
+
<c>int gekippt = !0xFA;</c>
 
Leider falsch geraten. Das Ausrufezeichen liefert nur Null (false) und Eins (true), egal welchen Operanden man ihm liefert. Zweiter Versuch:
 
Leider falsch geraten. Das Ausrufezeichen liefert nur Null (false) und Eins (true), egal welchen Operanden man ihm liefert. Zweiter Versuch:
−
  int gekippt = -0xFA;
+
<c>int gekippt = -0xFA;</c>
 
Nein, wieder falsch. Das Minuszeichen negiert den Wert doch nur, bildet also das Zweierkomplement. Richtig gewsen wäre:
 
Nein, wieder falsch. Das Minuszeichen negiert den Wert doch nur, bildet also das Zweierkomplement. Richtig gewsen wäre:
−
  int gekippt = ~0xFA;
+
<c>int gekippt = ~0xFA;</c>
 
Diese Operation liefert das gewünschte 0x05.
 
Diese Operation liefert das gewünschte 0x05.
  
Zeile 215: Zeile 215:
  
 
=== Ladeadresse nicht berücksichtigt ===
 
=== Ladeadresse nicht berücksichtigt ===
−
Ein kleiner aber gemeiner Fehler: Man hat einen schönen Kernel, der von dem genauso schönen Bootloader in den RAM geladen wird z.B. nach 0x10000. Dieser wird dann gelinkt:
+
Ein kleiner aber gemeiner Fehler: Man hat einen schönen Kernel, der von dem genauso schönen Bootloader in den RAM geladen wird, z.&nbsp;B. nach 0x10000. Dieser wird dann gelinkt:
 +
<pre>
 
OUTPUT_FORMAT("binary")
 
OUTPUT_FORMAT("binary")
 
INPUT("kernel.o")
 
INPUT("kernel.o")
Zeile 231: Zeile 232:
 
}
 
}
 
</pre>
 
</pre>
−
- die CPU verabschieded sich, da man die Ladeadresse auch im Linkerscript berücksichtigen muss (die Standartadresse ist 0x00, aber das stimmt ja hier nicht). Desshalb:
+
– die CPU verabschiedet sich, da man die Ladeadresse auch im Linkerscript berücksichtigen muss (die Standardadresse ist 0x00, aber das stimmt ja hier nicht). Deshalb:
 +
<pre>
 
OUTPUT_FORMAT("binary")
 
OUTPUT_FORMAT("binary")
 
INPUT("kernel.o")
 
INPUT("kernel.o")
Zeile 281: Zeile 283:
 
</pre>
 
</pre>
  
−
Funktioniert natürlich nicht. Interessanterweise führt das Ändern des Textes zu ganz anderen Fehlern. Die Begründung ist simpel: Der Text ("Hallo Welt!") landet nicht etwa in der .data-Sektion sondern in der sogenannten .rodata-Sektion. Und da wir diese hier nicht im Linkerscript angeben, wird sie einfach an den Anfang der Ausgabedatei gesetzt. Das führt natürlich zwangsweise zu Fehlern, weil ein Text ja kein Code ist. Es gibt nun zwei Möglichkeiten:
+
Funktioniert natürlich nicht. Interessanterweise führt das Ändern des Textes zu ganz anderen Fehlern. Die Begründung ist simpel: Der Text („Hallo Welt!“) landet nicht etwa in der .data-Sektion sondern in der sogenannten .rodata-Sektion. Und da wir diese hier nicht im Linkerscript angeben, wird sie einfach an den Anfang der Ausgabedatei gesetzt. Das führt natürlich zwangsweise zu Fehlern, weil ein Text ja kein Code ist. Es gibt nun zwei Möglichkeiten:
 
# Man ergänzt das Linkerscript um die .rodata-Sektion ''oder noch besser''
 
# Man ergänzt das Linkerscript um die .rodata-Sektion ''oder noch besser''
−
# Man schaltet eine Assemblerdatei vor den eigentlichen Kernel, die zum Label _main springt. Da man irgendann sowieseo Assembler benötigt, bietet es sich an, das gleich hiermit zu erledigen.
+
# Man schaltet eine Assemblerdatei vor den eigentlichen Kernel, die zum Label main springt. Da man irgendann sowieseo Assembler benötigt, bietet es sich an, das gleich hiermit zu erledigen.
−
Diese Assembler-Datei, die dann assembliert wird zu 'start.o', könnte so aussehen:
+
Diese Assembler-Datei, die dann zu „start.o“ assembliert wird, könnte so aussehen:
  
 
<asm>
 
<asm>
−
extern _main ;das ist unser Einsprunglabel im eigentlichen Kernel
+
extern main ;das ist unser Einsprunglabel im eigentlichen Kernel
 
global start
 
global start
  
 
start:
 
start:
−
jmp _main
+
jmp main
 
</asm>
 
</asm>