In diesem Tutorial werde ich beschreiben wie man einen in [[C]] programmierten [[Kernel]] mithilfe von [[GRUB]] bootet.
== Hinweis für Windowsianer ==
Ich werde hier beschreiben, wie ich es unter [[Linux]] mache. Unter [[Windows]] geht es auch, aber du musst sicherstellen, dass du ELF als Binärformat benutzt - das heißt, du solltest dir erst den Artikel [[Crosscompiler für Windows]] durchlesen und eine entsprechende Entwicklungsumgebung aufsetzen.
== Kernel ==
Der eigentliche Kernel soll ja in [[C]] programmiert sein. Ein Teil des [[Kernel]]s muss aber immernoch in [[Assembler]] sein.
=== Kernel - C ===
Als erstes kannst du dir einen kleinen Test-[[Kernel]] ausdenken, oder einfach den hier benutzen:
int main() {
// Pointer zum Videospeicher
char *video = (char*)0xB8000;
// String zum Ausgeben
char *hello = "Hello World";
// Zuerst den Speicher leeren
for(video+=4000; video !=(char*)0xB8000 ;video--)
*video=0;
// String ausgeben
while (*hello) {
*video = *hello;
video++;
*video = 0x07;
video++;
hello++;
}
// jetzt wo wir schon im Kernel drin sind, wollen wir auch nicht mehr raus ;)
while (1);
return 0;
}
=== Kernel - Assembler ===
Dieser Code macht eigentlich nichts anderes als in die main-Funktion unseres C-Kernels zu springen.
global loader ; loader für Linker sichtbar machen
extern main ; main-Funktion des C-Kernels
FLAGS equ 0
MAGIC equ 0x1BADB002 ; Magicnumber - Erkennungsmerkmal für GRUB
CHECKSUM equ -(MAGIC + FLAGS) ; Checksum
section .text
align 4
MultiBootHeader:
dd MAGIC ; Magic number
dd FLAGS ; Flags
dd CHECKSUM ; Checksum
loader:
mov esp,0x200000 ; Stack an die 2MB-Grenze platzieren
push eax ; Multiboot Magicnumber auf den Stack legen
push ebx ; Adresse der Multiboot-Structure auf den Stack legen
call main ; main-Funktion des C-Kernels aufrufen
cli ; falls der Kernel bis hier her kommt, CPU anhalten
hlt
Der Code sollte eigentlich gut verständlich sein, trotzdem ist noch was zu klären:
* Die Flags können geändert werden, am besten schaut man sich die [[Multiboot]]-Spezifikation an.
* Den Stack kann man natürlich an eine beliebige Stelle setzen, aber an der 2MB-Grenze wird er uns nicht stören.
* Es wird die Adresse der [[Multiboot]]-Structure nicht umsonst an den C-Kernel übergeben. Am besten liest man so ziemlich am Anfang des Kernels die Informationen aus ihr. In der [[Multiboot]]-Structure steht z.B wie viel Speicher der Rechner hat, oder welche Module von GRUB mitgeladen wurden.
== Zusammenbauen ==
Nun müssen wir den [[Kernel]] "zusammenbauen". Dafür müssen wir den [[Assembler]]-Code assemblieren, den [[C]]-Code kompilieren und am Ende beides linken.
=== Assemblieren ===
Dies geschieht ganz einfach mit diesem Befehl:
$ nasm -f elf -o kernel_asm.o kernel.asm
Damit wird eine [[ELF]]-Datei erzeugt, die wir später noch linken können.
=== Kompilieren ===
Der C-Kernel wird mit diesem Befehl kompiliert:
$ gcc -ffreestanding -o kernel_c.o -c kernel.c -Wall -Werror -nostdlib -nostartfiles -nodefaultlibs
Damit erstellen wir eine Objektdatei, mit der wir nachher noch linken können. Es ist wichtig, dass keine Standardbibliotheken benutzt werden.
=== Linken ===
Meiner Meinung nach ist dies der schwierigste Teil des "Zusammenbauens". Beim Linken wird unser Assembler-Kernel und unser C-Kernel miteinander verbunden und es wird z.B dem Assembler-Kernel auch gesagt wo die main-Funktion des C-Kernels liegt. Wir brauchen erstmal eine Konfigurationsdatei für ''ld'':
ENTRY (loader)
SECTIONS
{
. = 0x00100000;
.text :
{
*(.text)
}
.rodata ALIGN (0x1000) :
{
*(.rodata)
}
.data ALIGN (0x1000):
{
*(.data)
}
.bss :
{
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
}
Ich bin mir nicht 100%ig sicher ob dies die optimalste Linkerfile ist, aber sie funktioniert ;)
Nun wird gelinkt:
$ ld -T -o kernel.bin kernel_asm.o kernel_c.o
Wenn man später mehr Dateien hat, können diese natürlich auch dazugelinkt werden. Man sollte den fertigen Kernel jetzt in einer Datei namens ''kernel.bin'' haben.
== GRUB-Image erstellen ==
Wir müssen jetzt natürlich noch ein Disketten-Image erstellen und dann [[GRUB]] und unseren [[Kernel]] draufladen.
=== Floppy-Image erstellen ===
Wir erstellen uns erstmal ein Floppy-Image und formatieren es mit [[ext2]]. Es können auch andere [[Dateisysteme]] benutzt werden, z.B [[FAT]], man muss nur drauf achten, dass [[GRUB]] dieses [[Dateisystem]] unterstützt.
Mit ''dd'' erzeugen wir ein 1,44MB großes Floppy-Image:
$ dd if=/dev/zero of=floppy.img bs=1024 count=1440
Dann formatieren wir es mit ext2:
$ /sbin/mke2fs -F floppy.img
=== Dateien auf die Diskette kopieren ===
Jetzt mounten wir schnell das Image (ein Verzeichnis namens ''floppy'' wird benötigt)
$ mount -o loop floppy.img floppy/
und kopieren unseren Kernel drauf
$ cp kernel.bin floppy/
[[GRUB]] muss auch noch drauf. Hierzu legen wir einen Ordner namens ''grub'' auf der Diskette an und kopieren ''stage1'' und ''stage2'' aus ''/boot/grub'' auf die Diskette.
$ mkdir floppy/grub
$ cp /boot/grub/stage1 floppy/grub
$ cp /boot/grub/stage2 floppy/grub
Wir brauchen natürlich noch eine GRUB-Konfigurationsdatei. Diese sollte folgendermaßen aussehen:
default 0
timeout 10
title Mein super tolles OS
kernel /kernel.bin
root (fd0)
Die Konfigurationsdatei wird als ''floppy/grub/menu.lst'' gespeichert.
Jetzt können wir das Floppy-Image schon wieder unmounten
$ umount floppy/
aber GRUB muss noch in den Bootsektor
$ /usr/sbin/grub
Und dann folgendes eingeben:
device (fd0) floppy.img
root (fd0)
setup (fd0)
quit
Fertig ist unser GRUB-Image! Man kann es jetzt noch mit
$ dd if=floppy.img of=/dev/fd0
auf eine Floppydisk kopieren und damit booten. Wenn alles klappt seht ihr "Hello World" auf dem Bildschirm.
== Vorschläge ==
* Auf Dauer wird es anstregend die ganzen Befehl einzutippen. Am einfachsten ist es eine [[Makefile]] zu benutzen.
* Um nicht immer neustarten zu müssen, kann man einen Emulator wie [[Qemu]] oder [[Bochs]] nehmen. Dann muss man das Image auch erst gar nicht auf Diskette kopieren.
* Mit ''color light-blue/black light-cyan/blue'' in menu.lst kann man dem Bootloader Farbe verpassen.
== Nachwort ==
Bei Fehlern in Text oder Code bitte an das Lowlevel-Team wenden.
== Siehe auch ==
* [[C-Kernel starten]]
* [[GRUB-Image erstellen]]
* [[Multiboot]]
* [[GRUB]]
* [[GRUB auf CD]]
[[Kategorie:Tutorials]]