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 Kernels 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 -m32 -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 [[Dateisystem]] 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]]