Autor Thema: C - Kernel wird nicht geladen  (Gelesen 10977 mal)

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« am: 19. August 2009, 17:39 »
Hallo, ich versuche schon seit Stunden meinen C Kernel zum laufen zu bringen.
Einen Bootloader habe ich schon gemacht, der in den ProtectMode schaltet, wenn ich aber dann in den Kernel springen will passiert garnichts.

Hier mal der Bootloader:

[BITS 16]
        org 0x7c00

        %define STACKSEGMENT  0x9000                ; lineare Adresse des Stacks  : 0x90000
        %define STACKSIZE     0x200                 ; Größe des Stacks            : 512Byte
        %define KERNELSEGMENT 0x10000               ; lineare Adresse des Kernels : 0x40000

        jmp START
 
GDTR:
 limit  dw              (GDT_END - GDT - 1)
 base   dd              (0)

GDT:
NULL_DESCRIPTOR EQU $-GDT
        dd              0
        dd              0
CODE_DESCRIPTOR EQU $-GDT
        dw              0ffffh
        dw              0
        db              0
        db              09ah
        db              0cfh
        db              0
DATA_DESCRIPTOR EQU $-GDT
        dw              0ffffh
        dw              0
        db              0
        db              092h
        db              0cfh
        db              0
GDT_END:

START:
        cli                                         ; keine Interrupts
        mov             ax,        STACKSEGMENT
        mov             ss,        ax               ; Stacksegment setzen
        mov             sp,        STACKSIZE        ; Größe des Stacks festlegen
        xor             ax,        ax               ; ax = 0
        mov             ds,        ax               ; Datensegment auf 0 setzen
        sti

        xor             bx,        bx               ; Ziel-Offset         : 0x0
        mov             ax,        KERNELSEGMENT    ; Ziel-Segment        : 0x4000
        mov             es,        ax
        mov             ah,        0x2              ; Funktion 0x2        : Sektor lesen
        mov             al,        1                ; Anzahl der Sektoren : 1
        mov             ch,        0                ; Track               : 0
        mov             cl,        2                ; LSN                 : 2
        mov             dh,        0                ; Head                : 0
        mov             dl,        0                ; Laufwerk            : A
        int             0x13                        ; Interrupt           : 0x13
 
        cli                                         ; keine Interrupts
        mov             ax,         cs              ; Code-Segment holen
        mov             ds,         ax              ; Daten-Segment gleichsetzen
        xor             eax,        eax             ; ax = 0
        mov             es,         ax              ; Extra-Segment auf Null setzen
 
        mov             si,         GDT             ; Quelle : GDT
        xor             di,         di              ; Ziel : 0x0000
        mov             cx,         6               ; 6 DoubleWords kopieren (ganze GDT)
        rep             movsd

        lgdt            [GDTR]
 
        mov             eax,        cr0
        or              eax,        1               ; Bit0 setzen (PE-Bit enabled)
        mov             cr0,        eax

        db              0xea                        ; FAR-JUMP zum Codesegment
        dw              (PMODE)
        dw              0x8
 
        [BITS 32]                                   ; 32 Bit-Code erstellen
 
PMODE:
        xor             eax,        eax
        mov             eax,        2               ; Selektor für das Datensegment erstellen
        shl             eax,        3
 
        mov             ds,         ax              ; Daten-, Stack- und Extrasegment mit
        mov             ss,         ax              ; Datensegmentdeskriptor laden
        mov             es,         ax
        xor             ax,         ax
        mov             fs,         ax              ; fs und gs mit Nulldeskriptor laden
        mov             gs,         ax
        mov             esp,        09000h         ; Stack setzen

jmp             08h:010000h

stop:
jmp stop

        times 512-($-$$)-2 db 0
        dw 0x0AA55

Der Kernel (*.c)

int begin()
{
char *Text = "Welcome to Protected Mode";
char *VideoMem = (char*)0xA8000;

while(*Text) 
{
*VideoMem = *Text; 
*VideoMem++; 
*VideoMem = 7; 
*VideoMem++; 
*Text++; 
}

return(0);
}

Linker-Script (*.ld)

OUTPUT_FORMAT("binary")
INPUT("kernel.o")
ENTRY(_begin)
SECTIONS
{
  .text  0x10000 :
  {
    *(.text)
  }
  .data  :
  {
    *(.data)
  }
  .bss  :
  {
    *(.bss)
  }
}

Und so mach ich das ganze zu einer IMG-Datei.

nasm -f bin -o boot.bin boot.asm
gcc -ffreestanding -c -o kernel.o kernel.c
ld link.ld -o kernel.bin

copy /b boot.bin + kernel.bin os.img

Weiß jemand woran das liegt das der Kernel nicht geladen wird?
Hab schon viel rumprobiert, z.B. die Addresse dess Kernels,
hat alles nichts geholfen  :-(.

Bitte um Hilfe!

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 19. August 2009, 17:48 »
Ich glaube, das ist jetzt nicht alles, was falsch ist, aber da kann sicher jemand mit mehr Ahnung weiterhelfen (Kein Plan vom Linken  :-D), aber:

Dein größter Fehler besteht zuerst einmal darin, dass dein Bootloader den Kernel aufrufen muss. Nur weil du Bootloader und Kernel im/auf dem Image hast, tut sich da nix. Dein Bootloader muss halt einen call oder einen jmp (Ja gut, es gibt auch andere Möglichkeiten) machen, damit dein Kernel auch überhaupt aufgerufen wird. Dafür sollte dem Bootloader auch der Einstiegspunkt des Kernels bekannt sein.

Eventuell solltest du dir nochmal ganz genau visualisieren, wie der Programmfluss denn abläuft, dann klappt das auch ;-)

PS: Bevor ichs vergesse und irgendjemand Anderes es loswerden will: Wir empfehlen GRUB als Bootloader.


Uppala, da hab ich doch glatt was überlesen...
« Letzte Änderung: 19. August 2009, 18:01 von SHyx0rmZ »
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 19. August 2009, 18:00 »
Hi,

%define KERNELSEGMENT 0x10000 Das soll wohl 0x1000 sein, wenn ich mir den Rest des Codes anschaue. Mein NASM 2.02 hat mir deswegen auch eine Warnung gegeben.

char *VideoMem = (char*)0xA8000;Der Videospeicher ist bei 0xB8000. Der Wert 0xA8000 stammt aus einem total verkorkstem Tutorial.

An das Ende von begin() muss außerdem eine Endlosschleife, weil du aus der Funktion nicht zurückkehren darfst. Du bist ja mit jmp dahin gesprungen.

Zitat
ld link.ld -o kernel.bin
Da muss ein -T vor das link.ld.
« Letzte Änderung: 19. August 2009, 18:04 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #3 am: 19. August 2009, 19:13 »
Zitat
Der Videospeicher ist bei 0xB8000. Der Wert 0xA8000 stammt aus einem total verkorkstem Tutorial.

Achso, na dann kein Wunder das nix auf dem Bildschirm kommt :).

Zitat
An das Ende von begin() muss außerdem eine Endlosschleife, weil du aus der Funktion nicht zurückkehren darfst. Du bist ja mit jmp dahin gesprungen.

Ich hab nach diesem Jump zum Kernel ein "Endlossjump" gemacht also

stop:
jmp stop

Funktioniert doch auch, oder?

Zitat
Da muss ein -T vor das link.ld.

Wenn ich das mache, bekomme ich folgende Fehlermeldung:

ld: cannot perform PE operations on non PE out put file 'kernel.bin'.

Den rest werde ich verbessern und mal schaun obs geht.
Danke für die Antworten  :wink:!

XanClic

  • Beiträge: 261
    • Profil anzeigen
    • github
Gespeichert
« Antwort #4 am: 19. August 2009, 19:56 »
Ich hab nach diesem Jump zum Kernel ein "Endlossjump" gemacht also

stop:
jmp stop

Funktioniert doch auch, oder?

Nein, da du den Kernel mit "jmp" aufgerufen hast, er weiß also nicht, wohin er zurückkehren soll. Um das zu korrigieren, müsstest du "call" verwenden. :wink:

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 19. August 2009, 19:57 »
Ich hab nach diesem Jump zum Kernel ein "Endlossjump" gemacht also

stop:
jmp stop

Funktioniert doch auch, oder?
In diesem Fall nicht, weil du ja nie dahinkommst. Du springst mit jmp 0x08:0x10000 zum Kernel, aber der Kernel weiß nicht, wie er zurückkommt. Du könntest mit call statt jmp zum Kernel springen, dann funktioniert das.

Zitat
Da muss ein -T vor das link.ld.

Wenn ich das mache, bekomme ich folgende Fehlermeldung:

ld: cannot perform PE operations on non PE out put file 'kernel.bin'.
Ohne -T sieht der ld das Linker-Skript nicht als das primäre Linkerskript an und erzeugt eine .exe-Datei. (Davon kannst du dich mittels objdump -p kernel.bin überzeugen.)

Es gibt zwei Möglichkeiten, um doch eine Binärdatei zu bekommen: Entweder nimmst du einen Cross Compiler (z.B. einen, den ich erstellt habe, oder machst dir einen selbst) oder du baust deinen Build-Prozess um: Aus link.ld entfernst du die Zeile OUTPUT_FORMAT("binary") und rufst nach dem Linken noch objcopy auf um die Datei ins Binärformat zu wandeln: objcopy -O binary kernel.bin
« Letzte Änderung: 19. August 2009, 19:59 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #6 am: 19. August 2009, 20:03 »
So, habe jetzt alles verbessert. Jedoch passiert wieder nichts :(.
Liegt das vielleicht an der Addresse dess Kernels? Der Kernel is im moment
auf 0x1000 und aufrufen tu ich ihn mit jmp 08h:01000h , eine Endlosschleife
ist auch am Ende dess Kernels.

Ich versteh nicht warum das nicht geht.... :(.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 19. August 2009, 20:15 »
Warum hast du ihn jetzt an diese Adresse gelegt?
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #8 am: 19. August 2009, 21:05 »
Wenn ich ihn an eine Addresse tu, die größer als 0x10000 ist, dann meldet mir nasm.exe das die Addresse zu groß ist.

Achja, das objcopy funktioniert bei mir nicht. Da kommt immer eine
Meldung, in der steht, das das Dateiformat *.bin nicht bekannt ist.
« Letzte Änderung: 19. August 2009, 21:14 von Pk3 »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 19. August 2009, 21:14 »
Also das Zusammenfassen von Fehlermeldungen ist immer so eine Sache ...

Wo gibt dir NASM die Fehlermeldung? Was sagt der genau? Was ist die genaue Fehlermeldung von objcopy?
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #10 am: 19. August 2009, 21:15 »
Das gebe ich ein:
objcopy -O binary kernel.bin

Und das kommt:
objcopy:kernel.bin: File format not recognized

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 19. August 2009, 21:24 »
Kommt die Meldung immer? Auch wenn du vorher kernel.bin löschst, und sie mit ld erneut erstellst?
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #12 am: 19. August 2009, 21:31 »
Die Meldung kommt immer, oder kann das sein das ich eine alte Version
von objcopy.exe habe? Wenn ja, kannst du mir bitte einen Downloadlink
schicken wo man die neue findet? Ich hab bei Google lange gesucht
bis ich die gefunden habe.

Hier die Batch - Datei:

ECHO OFF
nasmw -f bin -o boot.bin boot.asm

D:\Programme\CodeBlocks\MinGW\Bin\gcc -ffreestanding -c -o kernel.o kernel.c

D:\Programme\CodeBlocks\MinGW\Bin\ld -T link.ld -o kernel.bin

objcopy -O binary kernel.bin

copy /b boot.bin + kernel.bin os.img

pause

rawwritewin.exe C:\Users\Pk3\Desktop\C_Kernel\os.img a:


Edit:
objcopy.exe ist bei mir 676kb groß.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 19. August 2009, 22:29 »
In diesem Fall ist sowohl Eingabe wie Ausgabe. Wenn du objcopy -O binary kernel.bin kernel-output.bin schreibst, dann ist kernel-output.bin die Ausgabe.

Ich kann mir nicht erklären, warum das so nicht funktioniert.
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #14 am: 19. August 2009, 22:40 »
Versteh ich auch nicht.... wie gesagt, vielleicht liegt das an der Version von objcopy.exe. Bei mir ist die 676kb groß. Das Linke - Script sieht jetzt so aus:

INPUT("kernel.o")
ENTRY(_begin)
SECTIONS
{
  .text  0x1000 :
  {
    *(.text)
  }
  .data  :
  {
    *(.data)
  }
  .bss  :
  {
    *(.bss)
  }
}

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #15 am: 19. August 2009, 22:47 »
objcopy -O binary --input-target binary kernel.bin kernel-output.bin

Mit --input-target binary funktionierts ohne Meldung.
Aber so ist es doch sinnlos, weiß jemand wie der richtige
input-target heißt?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 19. August 2009, 22:52 »
Die Version kannst du mit objcopy -V feststellen.

Das Problem an MinGW ist, dass es halt stark auf Windows spezialisiert ist. Eventuell solltest du wie ich bereits oben vorgeschlagen habe auf einen Cross Compiler umsteigen.
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #17 am: 19. August 2009, 23:23 »
Habe mir jetzt einen CrossCompiler heruntergeladen und es damit probiert.
Das objcopy geht jetzt endlich :). Die größe der IMG Datei hat sich auch verändert (von 5kb auf 1kb).

Und wenn ich das Image auf eine Diskette schreibe, und darauf boote, dann
rebootet sich der PC von alleine, ohne das ich irgentwas mache.

Ich weiß nicht wo der Fehler liegt.... hab schon so viel rumprobiert
und nichts klappt....   :-(.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 19. August 2009, 23:37 »
Hi,

für den Anfang solltest du zum Testen Bochs oder Qemu benutzen. Die können dir meistens auch Hinweise geben, was schief gelaufen ist.

Zum Beispiel erstellt Bochs ein Log, in dem die Instruktion bei der das Problem aufgetreten ist, sowie der Zustand der CPU (Register, etc.) stehen.

Ich benutze meistens diese Konfigurationsdatei für Bochs:
floppya: 1_44="os.img", status=inserted
boot: floppy

romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xe0000
cpu: count=1, ips=10000000, reset_on_triple_fault=1
megs: 8

vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
vga: extension=vbe

log: bochs.log
logprefix: %t-%e-@%i-%d

In einer Datei namens bochs.bxrc oder so speichern, und in das Verzeichnis mit deinem os.img kopieren und dann per Doppelklick starten.
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #19 am: 20. August 2009, 10:04 »
Danke für den Tipp, hab das jetzt mal gemacht und folgende Log-Datei
bekommen.

http://xyross.de/bochs.log

Darin fällt mir nur auf, das der Protect-Mode eingeschaltet wurde (Zeile 756)

00065895575-i-@006f0018-[CPU0 ] protected mode
und das er beendet

00065895575-e-@006f0018-[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
nachdem

00065895575-i-@006f0018-[CPU0 ] >> add dword ptr ds:[eax], eax : 0100
ausgeführt wurde. Also muss da der Fehler sein.
Jedoch finde ich im Assembler-Code (boot.asm) kein
"add", aber den Register "eax". Die 0100 ähnelt der Addresse
dess Kernels, fehlt halt eine Null, die habe ich anschließend rangehängt
also beim jmp, jetzt siehts so aus:

jmp 08h:010000h
Dann habe ich das ganze nochmal gemacht und jetzt sagt Bochs das:

00002609039-i-@00010006-[CPU0 ] >> and byte ptr gs:[edi+ebp*2+0x20], dh : 6520746F20
00002609039-e-@00010006-[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting

(Hier die Log-Datei: http://xyross.de/bochs2.log)


Da weiß ich nicht was ich machen soll, damits funktioniert.
Es passiert aber aufjedenfall nach dem Jump zum Kernel.

Edit:

Ich habe den Fehler gefunden, er liegt im C - Code:

char *Text = "Welcome to Protected Mode";
char *VideoMem = (char*)0xB8000;

while(*Text) 
{
*VideoMem = *Text; 
*VideoMem++; 
*VideoMem = 7; 
*VideoMem++; 
*Text++; 
}

Ich habe mal alles aus der begin() - Funtkion raus, auser die
Endlosschleife ( for(;;); ), jetzt sagt Bochs folgendes:

00141710000-i-@00010004-[CPU0 ] >> jmp .+0xfffffffe (0x00010004) : EBFE
Hab dann mal bei Google nach einer printf - Funktion gesucht und diese
verwendet:

void printf(char *text)
{
  char *ptr;
 
  for ( ptr = (char *)0xB8000; *text != 0; text++ )
  {
    *(ptr++) = *text;
    *(ptr++) = 0xe;
  }
}

int begin()
{
printf("Test");

for(;;);
}

als Fehler bekomme ich:
00026099052-i-@00000008-[CPU0 ] >> (invalid)  : FFFF
« Letzte Änderung: 20. August 2009, 11:09 von Pk3 »

 

Einloggen