Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: üäpöol am 19. May 2012, 20:42

Titel: Sprung in den RealMode
Beitrag von: üäpöol am 19. May 2012, 20:42
Hi,

ich würde gerne am Anfang meines kernels (ich benutze GRUB) kurz in den RealMode zurück springen. Nur um zu testen, ob ich etwas falsch mache, habe ich den code von osdev.org kopiert. Leider tritt der Fall ein, dass ich irgendetwas falsch machen muss, da der Code Fehlermeldungen beim Linken auslöst.
Hier erstmal der Code.
[bits 16]
 
idt_real:
dw 0x3ff ; 256 entries, 4b each = 1K
dd 0 ; Real Mode IVT @ 0x0000
 
savcr0:
dd 0 ; Storage location for pmode CR0.
 
Entry16:
        ; We are already in 16-bit mode here!
 
cli ; Disable interrupts.
 
; Need 16-bit Protected Mode GDT entries!
mov eax, 0x20 ; 16-bit Protected Mode data selector.
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
 
; Disable paging (we need everything to be 1:1 mapped).
mov eax, cr0
mov [savcr0], eax ; save pmode CR0
and eax, 0x7FFFFFFe ; Disable paging bit & enable 16-bit pmode.
mov cr0, eax

jmp 0:GoRMode ; Perform Far jump to set CS.
 
GoRMode:
mov sp, 0x8000 ; pick a stack pointer.
mov ax, 0 ; Reset segment registers to 0.
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
lidt [idt_real]
sti ; Restore interrupts -- be careful, unhandled int's will kill it.
Und hier die Fehlermeldungen:
In function `Entry16':
(.text+0x2a): relocation truncated to fit: R_386_16 against `.text'
(.text+0x36): relocation truncated to fit: R_386_16 against `.text'
In function `GoRMode':
(.text+0x4b): relocation truncated to fit: R_386_16 against `.text'
Das bezieht sich auf diese Zeilen:
mov [savcr0], eax   ; save pmode CR0
; ...
jmp 0:GoRMode       ; Perform Far jump to set CS.
; ...
lidt [idt_real]
Da ich erstmal davon ausgehe, dass der Code an sich korrekt ist, poste ich hier mal, wie ich das builde.
building\NASM\NASM.exe -f elf -o kernel\kernel.ao kernel\kernel.asm
"building\GCC & LD\bin\i586-elf-ld.exe" -melf_i386 -T "building\GCC & LD\bin\link.ld" -o kernel\kernel.elf kernel\kernel.ao
Hier das Linkerskript:
OUTPUT_FORMAT("elf32-i386")
ENTRY(start)
SECTIONS
{
  .text 0x100000 :
  {
    code = .; _code = .; __code = .;
    *(.text)
    . = ALIGN(4096);
  }
 
  .data :
  {
     data = .; _data = .; __data = .;
     *(.data)
     *(.rodata)
     . = ALIGN(4096);
  }
 
  .bss :
  {
    bss = .; _bss = .; __bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
 
  end = .; _end = .; __end = .;
}
Danke im Voraus für eure Hilfe. :)
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 19. May 2012, 21:06
Der Code von osdev.org ist nicht dafür gedacht in den Kernel gelinkt zu werden. Insbesondere ist es ein Problem, dass dein Kernel nach 0x100000 geladen ist, was zur Folge hat, dass dieser Code im Real Mode nicht mehr addressierbar ist. Die Fehlermeldungen von ld gehen in die selbe Richtung und versuchen dir zu sagen, dass du über 16-Bit-Adressierung nicht auf die 32-Bit-Adressen, die das ELF-Format erzeugt, zugreifen kannst.

Du hast 3 Möglichkeiten:
1. Du erzeugst mit NASM eine flache Binary (-f bin) und fügst die über INCBIN (http://www.nasm.us/doc/nasmdoc3.html#section-3.2.3) in eine weitere .asm-Datei ein. Dann kopierst du diese Daten (zur Laufzeit) an eine Adresse unter 1 MB und springst dorthin. Dazu brauchst du natürlich labels vor und hinter dem INCBIN.

2. Wie 1. nur du linkst die .bin-Datei einfach mit. Dann schauste da mal mit objdump in den Kernel rein, welche Symbole für Anfang und Ende der Daten erzeugt werden (Tipp: die sind ähnlich wie der Dateiname), damit du dann die Binary unter 1 MB kopieren kannst.

3. Du passt den Code für relative Addressierung an. Anstatt [savcr0] schreibst du dann [savcr0 - idt_real], statt [idt_real] nur [idt_real - idt_real] oder gleich [ 0] und jmp 0:GoRMode - idt_real statt jmp 0:GoRMode (falls der Assembler das nimmt ...). Dann musst du den gesamten Code an den Anfang eines Segments kopieren (weil idt_real am Anfang der Quellcode-Datei steht, und wir von jeder Adresse die Adresse von idt_real abziehen.)

Das alles funktioniert natürlich erst nachdem du den osdev.org-Code soweit angepasst hast, dass er auch mehr tut als nur in den Real Mode zu springen und dann im Nirvana zu verschweinden. Außerdem musst du aufpassen, dass du die Segmente richtig beachtest. Der Code erwartet ans Segment 0 geladen zu werden. Für Methode 3 solltest du das ändern, sonst ist die IVT weg. Für Methoden 1 und 2 solltest du dem Code gegegebenfalls noch mit .org ein Offset verpassen, das dann zusammen mit dem Segment auf die Adresse abgestimmt ist, an die die Binary kopiert wird.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 19. May 2012, 21:21
Hm. OK. Ich habe jetzt mal mit Möglichkeit 3 versucht. Ich bekomme jetzt zwar keine Fehlermeldungen mehr, aber sonst passiert wie erwartet nichts. Ich bin wohl immernoch nicht im RealMode.
Zitat
Das alles funktioniert natürlich erst nachdem du den osdev.org-Code soweit angepasst hast, dass er auch mehr tut als nur in den Real Mode zu springen und dann im Nirvana zu verschweinden.
Was meinst du damit genau? Ich habe einfach mal versucht, interrupts auszuführen, was nicht funktioniert.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 19. May 2012, 21:37
Ja, Interrupts Ausführen wäre etwas das ich meine.

Dann musst du mal mit einem Debugger im Single Step durch den Code durchgehen. Am besten fängst du beim Sprung zu der Binary an.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 19. May 2012, 21:42
Was wäre denn ein solcher Debugger? Ich bin leider noch ziemlicher Anfänger.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 19. May 2012, 22:00
Du kannst entweder den GDB an Qemu anhängen oder den integrierten Debugger von Bochs benutzen. Wobei ich gar nicht weiß, ob GDB geeignet ist, um 16-Bit-Code zu debuggen. Vielleicht fängst du dir erstmal an einen Überblick zu verschaffen:

Qemu:
http://www.lowlevel.eu/wiki/Debugging#bochs_.2F_QEMU
http://wiki.osdev.org/How_Do_I_Use_A_Debugger_With_My_OS#Use_gdb_with_Qemu

Bochs:
http://www.lowlevel.eu/wiki/Bochs_Debugger
osdev.org erwähnt auch was von einem graphischen Debugger für Bochs. http://wiki.osdev.org/Bochs#Bochs_debugging_facilities Keine Ahnung ob der was taugt.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 19. May 2012, 22:27
Ich habe leider größere Probleme mit Bochs, weshalb ich im Moment VirtualBox benutze. QEMU habe ich noch nie benutzt, ich habe es mir jetzt aber mal runtergeladen. Was muss ich machen, wie muss ich qemu.exe aufrufen? Ich finde nur seltsames beim googeln.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 19. May 2012, 22:48
Du musst Qemu mit dem Disketten-/Festplatten-/Kernelimage + die Parameter -s -S aufrufen. Also zum Beispiel wenn du ein Diskettenimage benutzt: qemu -fda disk.img -s -S, oder wenn der Kernel multibootfähig ist qemu -kernel mykernel.bin -s -S

Dann brauchst du ein zweites Terminal/Konsole und startest darin gdb mit dem Kernel als Parameter:
gdb mykernel.bin

In gdb verbindest du dich mit Qemu über target remote:1234 (1234 ist der Standardport)

Den ersten Breakpoint kannst du mit break _start setzen, wobei _start der Einstiegspunkt für deinen Kernel ist. GDB sollte dir bestätigen, dass das geklappt hat.

Dann startest du die Ausführung mit continue. Der Emulator sollte nach kurzer Zeit wieder anhalten.

Mit si kannst du einen Assemblerbefehl single steppen. Mit s kannst du einen C-Befehl single steppen. Für diesen Fall ist si das richtige.

Du solltest jetzt display/i $pc eingeben, damit er dir immer den nächsten Befehl disassembliert zeigt.

Bevor du anfängst sollest du dir deinen Kernel (mit z.B. objdump -d mykernel.bin) disassemblieren oder sonst wie rauskriegen an welchem Offset der Sprungbefehl steht, der zu dem Code, der in den unteren Speicher kopiert wurde, springt.

Dann setzt du mit break *0x123456 den Breakpoint auf diesen Befehl, wobei du natürlich die richtige Adresse einsetzen musst. Dann continue bis er dort hoffentlich angelangt, und dann mit si durchsteppen bis was interessantes passiert. Interessant könnte zum Beispiel sein, dass er anderen Code ausführt, als an dieser Adresse stehen müsste.

Hoffe das hilft erstmal weiter.

Sonstiges: Unter Windows versucht Qemu eventuell IPv6 zu nutzen. Um das zu verhindern, muss es so gestartet werden: qemu -fda disk.img -S -gdb tcp:127.0.0.1:1234
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 19. May 2012, 23:01
Was ist denn gdb?
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 19. May 2012, 23:05
Das ist der GNU Debugger.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 19. May 2012, 23:11
Ah, OK. Der ist nicht dabei, oder? Hast du vielleicht einen Link für mich? Ich lade ungerne von "irgendwelchen" Seiten solche Sachen runter. Bei gnu.org finde ich es nicht.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 19. May 2012, 23:18
Unter Linux sollte den deine Paketverwaltung kennen. Unter MinGW einfach mingw-get install gdb.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 19. May 2012, 23:35
GDB gibt folgende Fehlermeldung aus: "floppy.img": not in executable format: File format not recognized
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 20. May 2012, 00:25
gdb musst du mit der Binary des Kernels aufrufen. Das was du mit ld erzeugst. (Es ist hoffentlich im ELF-Format.)
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 20. May 2012, 00:53
Ja, ist es. Jetzt bekomme ich andere Fehler:
kernel.elf...(no debugging symbols found)...done.
(gdb) target remote:1234
:1234: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 20. May 2012, 01:29
Du kannst noch mal target remote localhost:1234 versuchen. Oder target remote 127.0.0.1:1234. Wenn du unter Windows bist, hast du hoffentlich die alternativen Parameter für Qemu beachtet. Aber das sind auch schon alles Verzweiflungsaussagen. Wenn das nicht klappt, kann ich dir auch nicht weiter helfen.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 20. May 2012, 13:54
OK, es funktioniert jetzt. Was meinst du denn damit genau?
Zitat
Bevor du anfängst sollest du dir deinen Kernel (mit z.B. objdump -d mykernel.bin) disassemblieren oder sonst wie rauskriegen an welchem Offset der Sprungbefehl steht, der zu dem Code, der in den unteren Speicher kopiert wurde, springt.
Was ist der untere Speicher?
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 20. May 2012, 14:01
Das erste, was mit aufgefallen ist, ist, dass es keine Funktion idt_real gibt. Ich habe keine Ahnung, warum das so ist.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 20. May 2012, 14:29
Der untere Speicher (Low Memory) ist der Speicherbereich, der im Real Mode addressierbar (über 16-Bit Segment + 16-Bit Offset) ist, also Adressen unter 1 MB. Damit die Labels exportiert werden musst du sie als global deklarieren.
global idt_real
idt_real:
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 20. May 2012, 14:40
Sehr komisch. Bis
mov [savcr0 - idt_real], eax
ist alles, in Ordnung, danach wird (bad) angezeigt und danach nur noch Schwachsinn.
Das bedeutet, bei
and eax, 0x7FFFFFFe ; Disable paging bit & enable 16-bit pmode.
muss etwas schief gehen.
Ich weiß aber leider nicht, was.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 20. May 2012, 14:43
Ich kann dir da leider auch nicht weiterhelfen. Die Sache ist ziemlich kompliziert und unmöglich über das Internet zu debuggen.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 20. May 2012, 17:30
Ich habe es jetzt mal mit incbin versucht.
Zitat
1. Du erzeugst mit NASM eine flache Binary (-f bin) und fügst die über INCBIN in eine weitere .asm-Datei ein. Dann kopierst du diese Daten (zur Laufzeit) an eine Adresse unter 1 MB und springst dorthin. Dazu brauchst du natürlich labels vor und hinter dem INCBIN.
Ich habe jetzt einfach mal eine Datei mit dem originalen osdev.org gemacht, die ich mit -f bin assembliere und die dann mit incbon inkludiert. Das hat nicht funktioniert. Was meinst du mit Daten zur Laufzeit kopieren?
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 20. May 2012, 18:01
Ich glaube dir ist nicht ganz klar, was genau es bedeutet in den Real Mode zu springen. Im Real Mode kannst du nur Speicher bis 1 MB adressieren. Bei der Adressierung werden 16-Bit Segment und 16-Bit Offset miteinander über Segment * 16 + Offset zur linearen Adresse verrechnet. Dein Kernel ist nach 0x100000 gelinkt, was bedeutet, dass sich der Code über 1 MB befindet. Es ist also nicht möglich diese Adresse des Codes mittels Segment und Offset dazustellen.

Wenn dein Code vom Protected Mode in den Real Mode springt, und die CPU noch Code über 1 MB ausführt, wird sie nach dem Sprung irgendeinen anderen Code ausführen und dein System stürzt ab. Das heißt du musst bevor du in den Real Mode wechselst bereits an eine Adresse unter 1 MB springen. Und um deinen Code dahinzubekommen, musst du ihn dahin kopieren.

Ich rate dir allerdings dazu, erstmal nicht weiter zu versuchen in den Real Mode zu springen. Du musst für einen kompletten Sprung hin und zurück wesentlich mehr Aufwand treiben, als diese 20 Zeilen im Schnipsel von osdev.org suggerieren.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 20. May 2012, 18:24
Hm. Ja, du hast Recht. Ich werde es wohl erstmal ein lassen. Danke trotzdem für deine Hilfe.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 23. May 2012, 21:05
Ich habe es zwar vorzeitig aufgegeben, habe aber trotzdem generell noch eine Frage zu Möglichkeit 2. Wie kann ich eine flache bin mit linken? ld sagt mir, dass das Dateiformat nicht erkannt wird. Brauche ich dazu ein spezielles Linkerskript?
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 23. May 2012, 21:23
Hm, ich glaube dazu musst du die erst mit objcopy ins ELF-Format wandeln. objcopy -B i386 -I binary -O elf32-i386 inputfile outputfile oder so
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 24. May 2012, 21:48
OK. Das funktioniert, aber wie kann ich dann eine Funktion aufrufen?
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 24. May 2012, 22:00
Gar nicht. Du kannst aber an den Anfang von dem Blob springen. Das setzt natürlich voraus, dass da auch Code steht.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 24. May 2012, 22:21
Tut mir Leid, dass ich so blöd frage, aber was ist ein Blob?
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 24. May 2012, 22:35
Damit meine ich die Binary. Da sind nur noch unstrukturiere Daten drin, mit denen du nach dem Assemblieren nichts mehr anfangen kannst, insbesondere keine Informationen wie Symbole für Funktionen, etc. extrahieren.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 25. May 2012, 13:19
Vielen Dank. Ich denke, ich habe es jetzt verstanden. Ich habe allerdings noch ein anderes Problem, das zwar nicht ganz zu dem Thema passt, aber ich glaube, es ist besser als einen anderen Thread zu erstellen. Da ein Sprung in den RealMode im Moment ja nicht möglich ist und ich bisher GRUB benutzt habe, ich aber kurz BIOS Interrupts ausführen muss, habe ich mich entschieden, einen eigene Bootloader zu schreiben und dann mit ASM noch in den ProtecedMode zu springen. Das funktioniert auch alles super, aber plötzlich habe ich ein Problem mit GCC. Ich rufe die main Funktion auf, aber plötzlich nichts mehr. Damit meine ich genau, dass es keine Fehlermeldungen gibt, aber das irgendwie keine externen Funktionen mehr aufgerufen werden können; glaube ich zumindest. :D Debugged habe ich das schon, aber das sieht alles super. Mit GRUB hat das alles funktioniert. Ich verwende denselben Code wie bei GRUB. Habe ich einen offensichtlichen Fehler gemacht, oder soll ich ein bisschen Code posten?
Titel: Re: Sprung in den RealMode
Beitrag von: kevin am 25. May 2012, 14:05
Der offensichtliche Fehler ist, einen eigenen Bootloader zu schreiben. Vermutlich hat entweder deine Funktion, die den Kernel von der Platte liest, ein Problem, oder dein ELF-Loader.

Was heißt denn "kann nicht mehr aufgerufen werden"? Irgendwas muss ja passieren, wenn du es versuchst.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 25. May 2012, 14:33
Natürlich ist es in meinem Fall Schwachsinn, einen Bootloader zu schreiben, aber ich brauche kurz und nur zum Testen BIOS Interrupts. Der Kernel wird einwandfrei geladen und ich lade keine elf-Dateien, sondern linke die zu einer flachen binary zusammen, die ich dann zum Bootloader kopiere. Wenn ich den Kernel debugge (dazu linke ich die Dateien zu einer elf Datei zusammen), sieht das alles super aus. Es scheint so, als würde das Aufrufen einer C Funktion (nicht einer externen Funktion) dazu führen, dass kein weitere Code geladen wird.
Titel: Re: Sprung in den RealMode
Beitrag von: kevin am 25. May 2012, 14:48
Lädt der Bootloader eventuell nur einen halben Kernel?
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 25. May 2012, 14:51
Das könnte sein, ich zeig den Bootloader einfach mal:
[ORG 0x7C00]
start:
cli
mov ax, 0x9000
mov ss, ax
mov sp, 0
sti
mov [bootdrive], dl
call load
mov ax, 0x1000
mov es, ax
mov ds, ax
push ax
mov ax, 0
push ax
retf

load:
push ds
mov ax, 0
mov dl, [bootdrive]
int 0x13
pop ds
jc load
 
load1:
mov ax, 0x1000
mov es, ax
mov bx, 0
mov ah, 2
mov al, 30
mov cx, 2
mov dx, 0
int 0x13
jc load1
retn

bootdrive db 0

times 510-($-$$) db 0
dw 0xAA55
Ich kenne mich leider nicht wirklich aus und Tutorials dazu sind ja auch Mangelware. :D
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 02. June 2012, 15:04
Hat niemand eine Idee?
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 02. June 2012, 15:26
taljeths Theorie könnte hinkommen. Du lädst nur zwei Sektoren (cx = 2). Wenn dein Kernel größer als 1 KB ist, reicht das nicht. Beim Lesen ignorierst du außerdem den Wert in [bootdrive]. Das könnte ein Problem sein, wenn du nicht vom ersten Laufwerk bootest.

Die Parameter für den BIOS-Aufruf sind zum Beispiel hier dokumentiert: http://www.ctyme.com/intr/rb-0607.htm
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 02. June 2012, 17:10
Ja, eine andere Erklärung gibt es eigentlich nicht - glaube ich.
Leider funktioniert nichts mehr, wenn etwas anderes in cx steht. Ich habe es auch so verstanden, dass die Sektoren in al stehen. Im Moment sind es übrigens bei mir 16 Sektoren. Ich glaube auch, cl ist der Anfangssektor, der gelesen werden soll. Ich bin mir aber nicht sicher. Habt ihr noch andere Ideen? Ich bin leider echt überfragt. :(
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 02. June 2012, 20:23
Und wieder mal hab ich die Doku, die ich selbst verlinkt habe, nicht richtig gelesen ... Hast Recht, das ist der Anfangssektor. Du könntest mal prüfen, wieviele Sektoren tatsächlich transferiert wurden.
Titel: Re: Sprung in den RealMode
Beitrag von: Dimension am 02. June 2012, 21:50
Und wieder mal hab ich die Doku, die ich selbst verlinkt habe, nicht richtig gelesen
Das beunruhigt dich? Ich kann einen Abschnitt 20x lesen und immer noch nicht verstanden haben.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 02. June 2012, 22:00
Ja ... Es werden tatsächlich so viele Sektoren geladen, wie angegeben. Ich frage nur zur Sicherheit nach, ob ich etwas falsch gemacht habe:
    mov ax, 0x1000
    mov es, ax
    mov bx, 0
    mov ah, 2
    mov al, 16
    mov ch, 0
    mov cl, 2
    mov dh, 0
    mov dl, 0
    int 0x13
    jc read
    cmp al, 16
    jne fail
    mov al, '|'
    mov ah, 0x0E
    int 0x10
Hier wird ein | ausgegeben. Ich weiß leider nicht mehr weiter, weil das ja offensichtlich funktioniert.
Achja, eine Idee habe ich noch: Welche Zahl muss ich im Linkerskript für phys angeben? 0x1000 oder 0x0? Mit 0x0 funktioniert noch ein bisschen mehr. Der Kernel wird aber in beiden Fällen geladen. Möglicherweise könnte es auch am Sprung in den PMode liegen? Gibt es eine einfach Möglichkeit zu testen, ob der Sprung geklappt hat?
PS: Schönen Feierabend noch, Jidder! ;)
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 02. June 2012, 22:09
Da du deinen Kernel für 32-Bit kompilierst, musst du 0x10000 angeben, wenn du ihn an das Segment 0x1000 und Offset 0 lädst.

0x1000 * 16 + 0 = 0x10000

In den Logs deines Emulators sollten hinweise stehen, wenn der Wechsel in den Protected Mode nicht geklappt hat. Zum Beispiel eine Exception. Wenn keine Exception auftritt, solltest du es mit Debugausgaben versuchen.
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 02. June 2012, 23:12
Das stimmt nicht ganz, leider. Am Anfang bin ich noch im RealMode. Deshalb gibt es wieder ein paar "truncated relocations". Was ist es dann? Es sieht so aus, als gäbe es keine exception.
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 02. June 2012, 23:27
Das stimmt nicht ganz, leider. Am Anfang bin ich noch im RealMode. Deshalb gibt es wieder ein paar "truncated relocations".
Nur damit es keine Missverständnisse gibt: Beim Linken, oder?

Du darfst halt keine Symbole (globale C-Funktionen z.B.) im 16-Bit-Code als Operanden verwenden. Kein mov ax, c_main und kein jmp c_main, außer du schreibst vorher [bits 32] (Sag ich mal ohne diese Behauptung jetzt getestet zu haben. Hybriden 16-/32-Bit-Code kann ich auch nicht aus dem Kopf schreiben.)
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 02. June 2012, 23:33
Richtig, beim Linken natürlich.
Ich poste einfach mal den Kernel, um Missverständnisse zu vermeiden:
[GLOBAL start]
start:
[BITS 16]
cli
mov eax, cs
mov ds, ax
shl eax, 4
mov [CODE_Desc+2], ax
mov [DATA_Desc+2], ax
shr eax, 16
mov [CODE_Desc+4], al
mov [DATA_Desc+4], al
mov eax, cs
shl eax, 4
add eax, NULL_Desc
mov [Base], eax
mov [Limit], word gdt - NULL_Desc -1
lgdt [gdt]
mov eax, cr0
or eax, 1
mov cr0, eax
db 0xea
dw PMODE
dw 0x8
[BITS 32]
PMODE:
mov word [CODE_Desc+2], 0
mov word [DATA_Desc+2], 0
mov byte [CODE_Desc+4], 0
mov byte [DATA_Desc+4], 0
mov eax, 2 
shl eax, 3
mov ds, ax 
mov ss, ax
mov es, ax
mov eax, 0 
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF
jmp 0x8:0x10000+PMODE2
PMODE2:
[EXTERN main]
call main
[GLOBAL kernelerror]
kernelerror:
mov byte [0xB8000], 'K'
mov byte [0xB8001], 0x07
mov byte [0xB8002], 'e'
mov byte [0xB8003], 0x07
mov byte [0xB8004], 'r'
mov byte [0xB8005], 0x07
mov byte [0xB8006], 'n'
mov byte [0xB8007], 0x07
mov byte [0xB8008], 'e'
mov byte [0xB8009], 0x07
mov byte [0xB800A], 'l'
mov byte [0xB800B], 0x07
mov byte [0xB800C], 'e'
mov byte [0xB800D], 0x07
mov byte [0xB800E], 'r'
mov byte [0xB800F], 0x07
mov byte [0xB8010], 'r'
mov byte [0xB8011], 0x07
mov byte [0xB8012], 'o'
mov byte [0xB8013], 0x07
mov byte [0xB8014], 'r'
mov byte [0xB8015], 0x07
endless_loop:
cli
hlt

NULL_Desc:
dd 0
dd 0
   
CODE_Desc:
dw 0xFFFF   
dw 0           
db 0           
db 10011010b           
db 11001111b   
db 0           
   
 
DATA_Desc:
dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0
 
gdt:
Limit dw 0
Base dd 0
Ich glaube, die main Funktion ist erstmal nebensächlich, außerdem ist sie ziemlich groß. Ist soweit alles richtig? Hier noch das Linkerskript:
OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x1000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(0);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(0);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(0);
  }
  end = .;
}
Titel: Re: Sprung in den RealMode
Beitrag von: Jidder am 03. June 2012, 00:30
Der Code schon wieder. Ich weiß nicht, warum die Leute glauben, dass sie in der GDT rumfummeln müssen ... Ich und der Autor des Tutorials, aus dem der Code stammt, wissen warum man das macht, und keiner von uns beiden hat Lust das zu erklären. Einer von uns beiden hätte das besser erklären müssen. (Ich bin das nicht.) Deswegen geht das immer schief, wenn die Leute den Code kopieren.

Ich hab mal deine kernel.asm frisiert. Die funktioniert bei mir in qemu.

Die entscheidenen Unterschiede sind, dass ich überall im 16-Bit Code start abziehe, und damit praktisch auf relative Adressierung umsteige.
Dann generiert der Assembler keine globalen Referenzen mehr, weil er das selbst berechnen kann, und der Linker stört sich daran nicht. Das funktioniert, weil der Ladeoffset (=bx) 0 ist. Der Sprung in den Protected-Mode muss dann ein 32-Bit-Sprung sein (db 0x66, ...), weil das Ziel an einer Adresse über 0x10000 liegt, also nicht mehr mit 16-Bit darstellbar ist.

[GLOBAL start]
start:
[BITS 16]
cli
; <------------- unfug gelöscht
mov eax, cs
shl eax, 4
add eax, NULL_Desc-start ; <-------------
mov [Base-start], eax ; <-------------
mov [Limit-start], word gdt - NULL_Desc -1 ; <-------------
lgdt [gdt-start] ; <-------------
mov eax, cr0
or eax, 1
mov cr0, eax
db 0x66 ; <-------------
db 0xea
dd PMODE-start+0x10000 ; <-------------
dw 0x8
[BITS 32]
PMODE:
mov eax, 2 
shl eax, 3
mov ds, ax 
mov ss, ax
mov es, ax
mov eax, 0 
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF
jmp 0x8:PMODE2 ; <-------------
PMODE2:
[EXTERN main]
call main
[GLOBAL kernelerror]
kernelerror:
mov byte [0xB8000], 'K'
mov byte [0xB8001], 0x07
mov byte [0xB8002], 'e'
mov byte [0xB8003], 0x07
mov byte [0xB8004], 'r'
mov byte [0xB8005], 0x07
mov byte [0xB8006], 'n'
mov byte [0xB8007], 0x07
mov byte [0xB8008], 'e'
mov byte [0xB8009], 0x07
mov byte [0xB800A], 'l'
mov byte [0xB800B], 0x07
mov byte [0xB800C], 'e'
mov byte [0xB800D], 0x07
mov byte [0xB800E], 'r'
mov byte [0xB800F], 0x07
mov byte [0xB8010], 'r'
mov byte [0xB8011], 0x07
mov byte [0xB8012], 'o'
mov byte [0xB8013], 0x07
mov byte [0xB8014], 'r'
mov byte [0xB8015], 0x07
endless_loop:
cli
hlt

NULL_Desc:
dd 0
dd 0
   
CODE_Desc:
dw 0xFFFF   
dw 0           
db 0           
db 10011010b           
db 11001111b   
db 0           
   
 
DATA_Desc:
dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0
 
gdt:
Limit dw 0
Base dd 0

Damit der Code funktioniert, musst du im Linkerskript phys auf 0x10000 setzen. Mich wundert, dass das setzen der Ladeadresse funktioniert. Ich würde eher die Linkadresse setzen, also so:
OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
  . = 0x10000;
  .text : {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(0);
  }
  .data :
  {
    data = .;
    *(.data)
    . = ALIGN(0);
  }
  .bss :
  {
    bss = .;
    *(.bss)
    . = ALIGN(0);
  }
  end = .;
}
Titel: Re: Sprung in den RealMode
Beitrag von: üäpöol am 03. June 2012, 00:39
Wow, der Code funktioniert. Das ist schonmal super, weil ich jetzt endlich anfangen kann, einen funktionierenden Code zu verstehen. :) Vielen Dank. Wenn ich noch Fragen habe, melde ich mich.