C++-Kernel mit GRUB — Änderungen 6395 → 6398

Zeile 1: Zeile 1:
−
Die Programmierung eines [[Kernel|Kernels]] in [[C++]] unterscheidet sich in einigen Punkten von der mit [[C]]. Da wären zum Beispiel der Aufruf der Constructoren, bzw. der Destructoren, die vor bzw. nach dem eigentlichen Kernel aufgerufen werden. Unser Kernel wird mittels [[GRUB]] geladen.
+
Die Programmierung eines [[Kernel|Kernels]] in [[C++]] unterscheidet sich in einigen Punkten von der mit [[C]]. Da wären zum Beispiel der Aufruf der Konstruktoren, bzw. der Destruktoren, die vor bzw. nach dem eigentlichen Kernel aufgerufen werden. Unser Kernel wird mittels [[GRUB]] geladen.
  
  
 
== Kernel ==
 
== Kernel ==
−
Wir werden mit [[GCC]] und [[NASM]] arbeiten. Ich verwende den Cross-Compiler von Jidder, es sollte aber keinen Unterschied zu einem "normalen" GCC unter Linux geben.
+
Wir werden mit [[GCC]] und [[NASM]] arbeiten. Ich verwende den [[Crosscompiler_f%C3%BCr_Windows]]Cross-Compiler von [[Benutzer:Jidder|Jidder]], es sollte aber keinen Unterschied zu einem "normalen" gcc unter Linux geben.
  
 
=== Kernel.cpp ===
 
=== Kernel.cpp ===
 
Da wir ja schon mit C++ arbeiten, wäre auch etwas OOP angebracht. Deshalb erstellen wir ein Klasse namens Video, die wir in einen Header stecken. Dadurch ist unsere kernel.cpp sehr übersichtlich:
 
Da wir ja schon mit C++ arbeiten, wäre auch etwas OOP angebracht. Deshalb erstellen wir ein Klasse namens Video, die wir in einen Header stecken. Dadurch ist unsere kernel.cpp sehr übersichtlich:
 
<cpp>
 
<cpp>
−
#include "MyOS.h" //einbinden unseres Header
+
#include "MyOS.h" // Einbinden unseres Header
  
 
void main(void){
 
void main(void){
−
Video screen; //erzeugen von screen
+
Video screen; // Screen instanzieren
−
screen.color(0x7000); //Vordergrund Schwarz, Hintergrund Dunkelgrau
+
screen.color(0x7000); // Vordergrund Schwarz, Hintergrund Dunkelgrau
−
screen.clear(); //Bildschirm leeren
+
screen.clear(); // Bildschirm leeren
−
screen.write((char *)"Wilkommen im C++-TestKernel!"); //Textausgabe
+
screen.write((char *)"Wilkommen im C++-TestKernel!"); // Textausgabe
 
}
 
}
 
</cpp>
 
</cpp>
Zeile 20: Zeile 20:
 
=== MyOS.h ===
 
=== MyOS.h ===
  
−
Der Header ist dann doch etwas Umfangreicher:
+
Der Header ist dann doch etwas umfangreicher:
  
 
<cpp>
 
<cpp>
Zeile 28: Zeile 28:
 
{
 
{
 
public:
 
public:
−
Video(); //Konstruktor
+
Video(); // Konstruktor
−
~Video(); //Destruktor
+
~Video(); // Destruktor
−
void clear(); //Leeren des Bildschirms, die Gräße liegt bei 80x25 Zeichen
+
void clear(); // Leeren des Bildschirms, die Größe liegt bei 80x25 Zeichen
−
void write(char *cp); //Textausgabe
+
void write(char *cp); // Textausgabe
−
void put(char c); //Ausgabe eines einzelnen Zeichens
+
void put(char c); // Ausgabe eines einzelnen Zeichens
−
void color(int color); //Setzen der FG/BG Farben
+
void color(int color); // Setzen der FG/BG Farben
 
private:
 
private:
−
unsigned short *videomem; //Zeiger auf den Videospeicher
+
unsigned short *videomem; // Zeiger auf den Videospeicher
−
unsigned int off; //Y-Position der Textausgabe, je volle Zeile +80
+
unsigned int off; // Y-Position der Textausgabe, je volle Zeile +80
−
unsigned int pos; //X-Position der Textausgabe, ab Zeilenanfang
+
unsigned int pos; // X-Position der Textausgabe, ab Zeilenanfang
−
unsigned int screen_color; //FB/BG Farbe
+
unsigned int screen_color; // FB/BG Farbe
 
};
 
};
 
Video::Video(){
 
Video::Video(){
−
screen_color = 0x0700; //Setzen der Farbe auf Dunkelgrau auf Schwarz
+
screen_color = 0x0700; // Setzen der Farbe auf Dunkelgrau auf Schwarz
−
pos=0; //Setzen der Textausgabe auf
+
pos=0; // Setzen der Textausgabe auf
−
off=0; //Linksoben.
+
off=0; // link soben.
−
videomem = (unsigned short*) 0xb8000; //Startadresse des Videospeichers
+
videomem = (unsigned short*) 0xb8000; // Startadresse des Videospeichers
 
}
 
}
 
Video::~Video(){}
 
Video::~Video(){}
Zeile 50: Zeile 50:
 
for(int i=0;i<(80*25);i++)
 
for(int i=0;i<(80*25);i++)
 
{
 
{
−
videomem[i] = (unsigned char)' ' |screen_color; //Füllen des Bildschirms mit Leerzeichen
+
videomem[i] = (unsigned char)' ' |screen_color; // Füllen des Bildschirms mit Leerzeichen
 
}
 
}
−
pos = 0; //Zurücksetzen der Textausgabe nach Linksoben
+
pos = 0; // Zurücksetzen der Textausgabe nach links oben
−
off = 0; //
+
off = 0;
 
}
 
}
 
void Video::write(char *cp){
 
void Video::write(char *cp){
 
char *str = cp, *ch;
 
char *str = cp, *ch;
 
for(ch = str; *ch; ch++){
 
for(ch = str; *ch; ch++){
−
put(*ch); //Für jedes einzelne Zeichen wird put() aufgerufen
+
put(*ch); // Für jedes einzelne Zeichen wird put() aufgerufen
 
}
 
}
 
}
 
}
 
void Video::put(char c){
 
void Video::put(char c){
−
if(pos >= 80){ //Wenn die Textausgabe den rechten  
+
if(pos >= 80){ // Wenn die Textausgabe den rechten...
 
pos = 0;
 
pos = 0;
 
off += 80;
 
off += 80;
 
}
 
}
−
if(off>=(80*25)){ //oder den unteren Bildschirmrand erreicht, gibt es einen  
+
if(off>=(80*25)){ // ...oder den unteren Bildschirmrand erreicht, gibt es einen  
−
clear(); //Umbruch bzw. es wird aufgeräumt.
+
clear(); // Umbruch bzw. es wird aufgeräumt.
 
}
 
}
 
videomem[off + pos] = (unsigned char)c|screen_color;  // Setzen des Zeichens und der Farbe in den Videospeicher
 
videomem[off + pos] = (unsigned char)c|screen_color;  // Setzen des Zeichens und der Farbe in den Videospeicher
Zeile 73: Zeile 73:
 
}
 
}
 
void Video::color(int color){
 
void Video::color(int color){
−
screen_color = color; //eigentlcih selbsterklärend
+
screen_color = color;
 
}
 
}
 
#endif
 
#endif
Zeile 80: Zeile 80:
 
=== cKernel.c ===
 
=== cKernel.c ===
  
−
Um den Constructor bzw. den Destructor aufzurufen, verlinken wir später diese zwei Funktionen mit:
+
Um den Konstruktor bzw. den Destruktor aufzurufen, werden diese beiden Funktionen später mit in den Kernel gelinkt:
  
 
<c>
 
<c>
Zeile 117: Zeile 117:
 
   
 
   
 
global loader ; Unser Einsprungspunkt
 
global loader ; Unser Einsprungspunkt
−
extern main ; main() aus Kernel.cpp
+
extern main ; main() aus Kernel.cpp
 
extern _cmain ; _cmain() aus cKernel.c
 
extern _cmain ; _cmain() aus cKernel.c
 
extern _catexit ; _catexit() aus cKernel.c
 
extern _catexit ; _catexit() aus cKernel.c
Zeile 148: Zeile 148:
 
== Kompilieren und Linken ==
 
== Kompilieren und Linken ==
 
Die asmKernel.asm:
 
Die asmKernel.asm:
−
<pre>
+
 
−
nasm -f elf -o asmKernel.o asmKernel.asm
+
nasm -f elf -o asmKernel.o asmKernel.asm
−
</pre>
+
 
 
Kernel.cpp:
 
Kernel.cpp:
−
<pre>
+
 
−
gcc -nostdlib -fno-builtin -fno-rtti -ffreestanding -fno-exceptions -c -Os -o Kernel.o Kernel.cpp
+
gcc -nostdlib -fno-builtin -fno-rtti -ffreestanding -fno-exceptions -c -Os -o Kernel.o Kernel.cpp
−
</pre>
+
 
 
cKernel.cpp:
 
cKernel.cpp:
−
<pre>
 
−
gcc -m32 -ffreestanding -fno-leading-underscore -c -o cKernel.o cKernel.c -Wall -Werror -nostdinc
 
−
</pre>
 
  
−
Nun zu einem der wichtigsten Stellen: das Linken.
+
gcc -Wall -Werror -nostdinc -m32 -ffreestanding -fno-leading-underscore -c -o cKernel.o cKernel.c
 +
 
 +
 
 +
Nun zu einer der wichtigsten Stellen: Dem Linkvorgang:
 
Wir müssen die asmKernel.o, die Kernel.o und die cKernel.o zu einer Kernel.bin linken, die dann von GRUB geladen werden kann.
 
Wir müssen die asmKernel.o, die Kernel.o und die cKernel.o zu einer Kernel.bin linken, die dann von GRUB geladen werden kann.
  
−
Unser Linkerscript, wir speichern es in link.txt:
+
Unser Linkerscript (link.txt)
 
<pre>
 
<pre>
 
ENTRY(loader)
 
ENTRY(loader)
Zeile 194: Zeile 194:
 
</pre>
 
</pre>
  
−
Wir sagen dem Linker zusätzlich zu einem Script für eine C-Kernel, dass wir die Labels __CTOR_LIST__, __CTOR_END, __DTOR_LIST__ und __DTOR_END__ haben.
+
Wir teilen dem Linker mit, dass wir die Labels __CTOR_LIST__, __CTOR_END, __DTOR_LIST__ und __DTOR_END__ in der Datei cKernel.c haben und er diese beim Linken berücksichtigen soll.
−
Nur noch ein kurzer Aufruf von LD, und wir haben unseren fertigen Kernel in der Hand, äh Maus ^^.
+
Nur noch ein kurzer Aufruf von LD, und wir haben unseren fertigen Kernel in der Hand (bzw. Maus ;-)):
−
<pre>
+
 
−
ld -T link.txt -o kernel.bin asmKernel.o cKernel.o Kernel.o
+
ld -T link.txt -o kernel.bin asmKernel.o cKernel.o Kernel.o
−
</pre>
+
 
−
Und fertig ist unser Kernel! Unsere Kernel.bin kann die Kernel.bin auf dem Disketten-Image aus [[C-Kernel mit GRUB]] ohne weiteres ersetzen, und schon Startet unsser C++-Kernel!
+
Und fertig ist unser Kernel! Wie der Kernel nun mitsamt GRUB auf einer Diskette landet kann im Artikel [[C-Kernel_mit_GRUB|C-Kernel mit GRUB]] nachgelesen werden, dort verfährt man einfach analog.
 
== Anmerkungen ==
 
== Anmerkungen ==
−
Es kann unter umständen nötig sein __CTOR_LIST__ etc. durch _CTOR_LIST__ zu ersetzen, also das _ weglassen. Ich vermute, dass das von der GCC Version abhängig ist.
+
Es kann unter Umständen nötig sein, __CTOR_LIST__ etc. durch _CTOR_LIST__ zu ersetzen, also das _ weglassen. Ich vermute, dass das von der GCC Version abhängig ist.
 +
 
 +
 
 +
== Siehe auch ==
 +
* [[C-Kernel_mit_GRUB|C-Kernel mit GRUB]]
 +
* [[GRUB]]
 +
* [[C++]]
 +
* [[Multiboot]]
 +
* [[Linkerscript]]
 +
 
 +
[[Kategorie:Tutorials]]