Autor Thema: Sprung in den RealMode  (Gelesen 19314 mal)

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« 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. :)

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 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 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.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #2 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.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 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.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 19. May 2012, 21:42 »
Was wäre denn ein solcher Debugger? Ich bin leider noch ziemlicher Anfänger.
« Letzte Änderung: 19. May 2012, 21:44 von üäpöol »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #5 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.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #6 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.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 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
« Letzte Änderung: 19. May 2012, 22:50 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 19. May 2012, 23:01 »
Was ist denn gdb?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 19. May 2012, 23:05 »
Das ist der GNU Debugger.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #10 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.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 19. May 2012, 23:18 »
Unter Linux sollte den deine Paketverwaltung kennen. Unter MinGW einfach mingw-get install gdb.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 19. May 2012, 23:35 »
GDB gibt folgende Fehlermeldung aus: "floppy.img": not in executable format: File format not recognized

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #13 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.)
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #14 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.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #15 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.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #16 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?

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #17 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.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #18 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:
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #19 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.

 

Einloggen