Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: Snake707 am 22. July 2007, 20:42
-
Hallo,
ich will einen Kernel in C schreiben (bzw, schreibe schon), allerdings weiß ich nicht, wie ich zum Einsprungpunkt komme. Mein Bootloader lädt den Kernel an eine bestimmte Stelle im Speicher und geht dann in den Protected Mode um dann zum Kernel zu springen. Nur weiß ich nicht wie ich dort zur Main springen kann?
mfg Snake707
-
welcher Compiler/Linker/Assembler? Wo ist das Problem? Was hast du schon probiert? :roll:
Code in intelsyntax:
extern main ; oder auch extern _main je nach compiler(einstellung)
pmode:
call main ; oder auch _main, je nach compiler(einstellung)
-
hi
gcc, ld, nasm
aber gibt es da nicht so eine crt0 Funtion?
Also um vllt Missverständnissen aus dem Weg zu gehen. Der Bootloader, soll den Kernel von Diskette laden und in den pm gehen. Soweit nicht so schwer. Es ist ein C-Kernel. Frage: Da Bootlader und Kernel getrennt sind, woher soll der Bootloader dann wissen wo sich die main Funktin befindet? Das ist mir schleierhaft.
-
Das kommt wohl auf das Binärformat deines Kernels an. Wenn es flache Binaries sind, mußt du es einfach wissen (zu empfehlen wäre dann wohl, daß es einfach vorne losgeht). Bei ELF kannst du den Entrypoint aus der Datei auslesen.
-
Bei ELF binaries wäre es aber nicht mit dem auslesen des entrypoint getan ;) Da muss man schon noch die ganzen Segmente durchgehen, richtig in den speicher kopieren... Falls du das vorhast würd ich dir wirklich grub nahe legen.
Du kannst auch die ersten 4byte deiner Datei dazu hernehmen die Adresse des entrypoint zu speichern. Damit das dann wirklich am Anfang der Datei landet musst du das halt in ne extra section packen und dein Linkerscript entsprechend anpassen,
btw. für Diskussionen gibts im Wiki zu jedem Artikel ne Diskussionsseite (falls das immernoch unklar ist). :-)
-
GRUB wäre eine Variante;
ich würde mich aber trotzdem gerna an einem eigenen Bootloader versuchen :P;
also ich habe jetzt noch immer keinen Anhaltspunkt^^
kennt jemand ein gutes Tutorial zu Linkerscripts? Damit hatte ich bisher noch nicht viel zu tun.
-
Hi
du must beim linken deines C codes darauf auchten, das dein einsprungspunkt an eine bestimmte stelle gelinkt wird. Als ausgabe muss eine flat binary rauskommen. Der einsprung muss dabei nicht umbedingt main heissen.
wie das im einzelnen genau geht, ist linker abhängig. Bei properitären compilern aus dem embedded bereich kann man sowas bereits im code ngeben __root const CPU_INT32U FLASH_MARKER @ 0x104FF800 = 0xAA55AA55; (IAR für arm) oder über compilerschalter bzw. Linker dateien, die man als parameter übergibt.
gruss
-
Ok, ich habe jetzt einfach mal nur Bahnhof verstanden. Vielleicht wäre es einfacher, wenn ich mich erstmal mit dem Linker auseinandersetze. Da habe ich nämlich noch gar keine Ahnung. Soll ich da die man pages von ld verwenden? Oder kennt jemand zufällig ein gutes Tutorial.
Das wäre auch sehr nützlich, weil ich die Makefiles noch schreiben will.
mfg Snake707
-
hey,
pass auf, probier einfach folgendes und versuch beim coden nachzuvollziehen, was genau passiert:
du hast einen bootloader, der den kernel lädt und dann in den pm springt. das sieht in etwa so aus:
;boot.asm
[BITS16]
org 0x7c00
start:
...; hier steht der code, der dir den kernel an eine bestimmte adresse lädt
...; du musst dabei darauf achten, dass du dir vorher überlegst, wohin du den kernel laden willst
...; sagen wir du hättest dir die lineare adresse 0x20000 ausgesucht
;
; so, jetzt steht der kernel bei 0x20000
; jetzt musst du in den pm schalten
;
lgdt ...
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8 : pmode
;
; das müsstest du ja soweit implementiert haben
[BITS32]
pmode:
mov eax, 0x10
mov ds, eax
mov es, eax
mov ss, eax
mov gs, eax
mov fs, eax
mov esp, stack_size
; na das kennst ja alles
; soooo
; das tolle ist, dass du weißt, wo dein kernel liegt. du hast ihn ja nach 0x20000 geladen
; da springen wir nun hin...
jmp 0x8 : 0x20000
;
; fertig
jetzt brauchst du noch einen kernel...
// kernel.c
void main()
{
// welcome
for(;;);
}
jetzt noch etwas, das nicht unbedingt notwendig ist, aber manchmal ganz nützlich ist...
; asm32.asm
[BITS 32]
[global _stopsystem]
[extern _main]
_start:
call _main
_stopsystem:
cli
hlt
jetzt musst du nur noch gucken, wie das alles zusammen gehört.
also den bootlader assemblierst du ganz normal mit nasm:
nasm -f bin -o boot.bin boot.asm
boot.bin schreibst in sektor null...
asm32.asm musst du anders assemblieren:
nasm -f aout -o asm32.o asm32asm
jetzt hast du die erste objekt-datei asm32.o
den kernel kompilierst du so:
gcc -ffreestanding -c -o kernel.o kernel.c
jetzt hast du die zweite objekt-datei.
um alles zusammen zu linken, brauchst du noch eine sogenannte linker-file:
OUTPUT_FORMAT("binary")
INPUT(asm32.o kernel.o)
ENTRY(_start)
SECTIONS
{
.text 0x20000 : {
*(.text)
}
.data : {
*(.data)
}
.bss :
{
*(.bss)
}
}
die datei erklärt sich ja sogut wie von selbst... wenn nicht, fragen!
das ganze muss nur noch gelinkt werden:
ld -T link.ld -o kernel.bin
nach diesem befehl hast du eine datei namens kernel.bin, die der bootloader laden kann...
da du in der link.ld die reihenfolge INPUT(asm32.asm kernel.o) hast, ist der allererste befehl in kernel.bin "jmp _main"... dadurch ist sichergestellt, dass selbst wenn _main nicht ganz vorne anfängt, trotzdem der kernel-code aufgerufen wird.
gruß
Cheebi
ps: meld dich, wenns funktioniert... hab den code jetzt nicht getestet...