| 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 | + | 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" | + | 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" // | + | #include "MyOS.h" // Einbinden unseres Header |
void main(void){ | void main(void){ | ||
| − | Video 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 | + | 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 | + | 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; // | + | 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 | + | 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; | + | screen_color = color; |
} | } | ||
#endif | #endif | ||
| Zeile 80: | Zeile 80: | ||
=== cKernel.c === | === cKernel.c === | ||
| − | Um den | + | 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 | + | 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: | ||
| − | + | ||
| − | nasm -f elf -o asmKernel.o asmKernel.asm | + | nasm -f elf -o asmKernel.o asmKernel.asm |
| − | + | ||
Kernel.cpp: | Kernel.cpp: | ||
| − | + | ||
| − | gcc -nostdlib -fno-builtin -fno-rtti -ffreestanding -fno-exceptions -c -Os -o | + | gcc -nostdlib -fno-builtin -fno-rtti -ffreestanding -fno-exceptions -c -Os -o Kernel.o Kernel.cpp |
| − | + | ||
cKernel.cpp: | cKernel.cpp: | ||
| − | |||
| − | |||
| − | |||
| − | Nun zu | + | 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 | + | Unser Linkerscript (link.txt) |
<pre> | <pre> | ||
ENTRY(loader) | ENTRY(loader) | ||
| Zeile 194: | Zeile 194: | ||
</pre> | </pre> | ||
| − | Wir | + | 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 | + | Nur noch ein kurzer Aufruf von LD, und wir haben unseren fertigen Kernel in der Hand (bzw. Maus ;-)): |
| − | + | ||
| − | 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 |
| − | + | ||
| − | Und fertig ist unser 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 | + | 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]] | ||