Autor Thema: merkwürdiges Verhalten bei jmp Befehl  (Gelesen 6026 mal)

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« am: 07. February 2012, 00:23 »
Moin,

Ich beschäftige mich seit einer Weile mit dem Thema des bootloaders.
Bei meinem kleinen loader kommt es allerdings zu einem für mich merkwürdigen verhalten.
Ich hoffe nur das mir jemand beschreibt warum dieses Verhalten auftritt.

Und zwar habe ich einen kleinen bootloader der den zweiten Sector einer Floppy einliest, ihn dann in 0x1000:0x0000
speichert und anschliesend an diese Stelle springt. Wenn ich den jmp Befehl an diese Position ausführe Passiert jedoch nichts.
Dabei sind mir jedoch folgende verhalten aufgefallen:

  • Wenn ich den 1 Sector der Floppy einlese und dann an die neue Position springe, passiert genau das was ich erwarte, der Rechner rebootet
  • Wenn ich den Rest des zweiten Sectors mit Nullen auffülle und die Standart boot Signatur anhänge wird der zweite Sector ausgeführt, so wie ich es will
  • Dies geschieht auch wenn ich "times 512-($-$$) hlt" anhänge. (Das kommt mir aber mehr als unsauber vor, hab ich auch nur mal kurz ausprobiert ;-) )
Hier der Code:

Der bootloader
BITS 16

org 0x7C00

start:
;erzeuge Stack
cli

mov ax, 0x9000
mov ss, ax ;stack nach 0x9000
mov sp, 0 ;stackpointer auf anfang

mov ax, 0x0000 ;
mov es, ax ;Setzt das Datensegment nach 0x0000
mov ds, ax ;
sti

;Stack erzeugt an Pos. 0x7F00

call test

;--------------Kernel laden---------------
call read_floppy ;Kernel aus 2tem Sektor laden
cli ;keine interupts
mov ax, 0x1000 ;Datensegment zur neuen Kernel Pos.
mov es, ax
mov ds, ax
sti ;interupts an
jmp 0x1000:0x0000 ;wechsel zum kernel
;------------------------------------------

call reboot

read_floppy:
mov ah, 0x02 ;int funktion 0x02
mov bx, 0x1000
mov es, bx ;read into 1000:0000
mov bx, 0x0000 ;offset 0
mov al, 1 ; 1 Sektor lesen
mov ch, 0 ; auf Track 0
mov cl, 2 ; Sektor 2
mov dh, 0 ; Auf head 0 (oben)
mov dl, 0 ;Auf std. Floppy
int 0x13
jc read_floppy ;wenn fehler, neu versuchen (jc = jump if carry)
ret

test:
mov ah, 0x0E
mov al, 0xA5
int 0x10
ret

reboot:
;jmp 0xffff:0x0000
mov ax, 0
int 0x16
int 0x19

times 510-($-$$) db 0 ; Setzt die boot signatur am ende des boot Sectorsc
dw 0xAA55 ; The standard PC boot signature


Der "kernel" ;-)
org 0x1000
jmp start

start:
call test
hlt

test:
mov ah, 0x0E
mov al, 0x68
int 0x10
ret

times 512-($-$$) hlt
;times 510-($-$$) db 0 ; Setzt die boot signatur am ende des boot Sectorsc
;dw 0xAA55 ; The standard PC boot signature


Ich hoffe ihr könnt mir dieses Verhalten erläutern.
Großen Dank im vorraus!

Ps: Ich arbeite unter Linux (Fedora 16) falls das irgendwie behilflich sein könnte

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 07. February 2012, 00:29 »
1. Die Signatur hat nichts mit dem Kernel zu tun. Die kennzeichnet einen bootfähigen Bootsektor für das BIOS.

2. Nicht jedes Programm, was Images auf Disketten schreibt, schreibt auch unvollständige Blöcke. Sorge dafür, dass deine Image-Datei immer eine durch die Blockgröße teilbare Dateigröße hat.

3. Sicher, dass du einen Bootloader schreiben willst?

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 07. February 2012, 00:40 »
Danke für die Schnelle Antwort.

Mir ist schon klar das die Signatur nichts mit dem Kernel zu tun hat.
Mir ist aufgefallen, dass das geht als ich den Loader 2 mal hintereinander auf die Floppy geschrieben habe, weil das laden und aufrufen des loaders ja funktioniert,
und dann den loader zu einem "Kernel" "abgebaut" habe, dh ich habe einfah alles bootloader typisches entfernt und nur die Char ausgabe drinne gelassen.
Das war auch nur pure Verzweiflung. Dabei habe ich dann bemerkt das es mit der Signatur geht.

Das mit der Größer der Image Datei werde ich sofort testen, danke für den Hinweis.

Und ja ich will einen bootloader schreiben. Da ich mich zurzeit tiefer mit der Funktionsweise von Betriebsystemen und Computern im allgemeinen befasse, finde ich es eigentlich ganz logisch von ganz unten anzufangen.
Ich habe nicht vor das dadraus etwas deutlich größeres werden soll.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 07. February 2012, 01:57 »
Hallo,

geht es?

Und ja ich will einen bootloader schreiben. Da ich mich zurzeit tiefer mit der Funktionsweise von Betriebsystemen und Computern im allgemeinen befasse, finde ich es eigentlich ganz logisch von ganz unten anzufangen.
Ich habe nicht vor das dadraus etwas deutlich größeres werden soll.
Na das ist doch mal eine gute Begründung. ;-)

Gruß,
Svenska

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 07. February 2012, 09:51 »
Und ja ich will einen bootloader schreiben. Da ich mich zurzeit tiefer mit der Funktionsweise von Betriebsystemen und Computern im allgemeinen befasse, finde ich es eigentlich ganz logisch von ganz unten anzufangen.
Dann solltest du aber mit einem BIOS anfangen.

Problem ist halt, dass wenn du dich mit einem BIOS oder einem Bootloader beschäftigst, nicht ganz so viel über die Funktionsweise von Betriebssystemen lernst.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 07. February 2012, 12:15 »
Moin,

Du hast recht, wenn ich den kernel mit der Endung assembliere wird das Image insgesammt 1024 byte groß.
Wenn ich die Signatur weglasse nur ~532. Wie könnte ich das Problem denn sauber lösen?
Ich assembliere die beiden Dateien, und kopiere beide per cat in die Datei "system.bin" etc..
Danach schreibe ich diese per dd auf ein floppy Image (.flp)
Mit qemu boote ich dann vim Image.
Muss ich einen bestimmten befehl an den Assembler (nasm) oder an dd übergeben, damit die Sectoren richtig geschrieben werden? Ich tippe mal eher auf dd...
Oder etwas vollkommen anderes?

Dann solltest du aber mit einem BIOS anfangen.
Ich wollte schon noch im bereich des für mich möglichen bleiben ;-) aber wenn das auch machbar ist sag bescheid :-)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 07. February 2012, 15:15 »
Du hast recht, wenn ich den kernel mit der Endung assembliere wird das Image insgesammt 1024 byte groß.
Wenn ich die Signatur weglasse nur ~532. Wie könnte ich das Problem denn sauber lösen?
Das entscheidende ist nicht die Signatur, sondern dass du davor das Image auf 510 Bytes auffüllst. Du kannst auch einfach auf 512 Bytes auffüllen und die Signatur weglassen.

Ein anständiger Bootloader lädt den Kernel übrigens nicht von einem hartkodierten Sektor, sondern er liest eine Datei vom Dateisystem auf der Platte/Diskette. Wenn er feste Blocknummern benutzt, dann höchstens, um den zweiten Teil des Bootloaders nachzuladen (in 512 Bytes geht eben nicht besonders viel). Die werden in der Regel beim Installieren des Bootloaders reingepatcht und liegen auch irgendwo in einem Dateisystem.

Zitat
Dann solltest du aber mit einem BIOS anfangen.
Ich wollte schon noch im bereich des für mich möglichen bleiben ;-) aber wenn das auch machbar ist sag bescheid :-)
Viel Spaß. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 07. February 2012, 15:20 »
Hallo,

der Bootsektor sollte exakt 512 Bytes haben, die letzten beiden Bytes sind die Signatur. Der Kernel kommt dahinter und kann so groß sein, wie er will; du musst nur wissen, wieviele Sektoren er belegt. Dein Image belegt also mindestens zwei Sektoren, also mindestens 1024 Byte.

dd kann auch halbe Sektoren schreiben, das siehst du auch in der Ausgabe ("1+1 records in, 1+1 records out" ist ein ganzer und ein halber Sektor).

Ich wollte schon noch im bereich des für mich möglichen bleiben ;-) aber wenn das auch machbar ist sag bescheid :-)
Guck dir coreboot an, die machen das. Dazu gab es mehrere erklärende Vorträge (z.B. hier, hier] und entscheide die Machbarkeit dann.

Gruß,
Svenska

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 07. February 2012, 15:30 »
Ok danke, wenn ich den rest dest zweiten Sektores mit Nullen fülle gehts, danke.
Das ein Kernel nicht direkt geladen wird ist mir auch klar, ich wollte halt so etwas wie ein Dateisystem zum
Anfang raus lassen, damit alles möglichst einfach ist. Ich will mir daran ja auch nur ansehen wie ganz grundsätzlich
ein Programm geladen wird, ist halt alles nur zum selbstlehrn zweck.
Aber danke an euch für die schnelle und gute Hilfe.

Und das mit dem BIOS hat glaub ich noch ein wenig Zeit ;-)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 07. February 2012, 15:36 »
Die Vorträge sind trotzdem sehr interessant, wenn man sich mal mit der Technik befassen möchte. ;-)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 07. February 2012, 15:43 »
Ja, ich glaube auch, dass das mit dem BIOS noch Zeit hat. Und das mit Bootloader eben auch. ;)

Das Problem ist, dass du wahrscheinlich versuchen willst, auf diesem Bootloader ein OS aufzusetzen. Du hast dann aber keinen anständigen Bootloader implementiert, sondern irgendwas möglichst einfaches und damit auch was ziemlich eingeschränktes. Ich kann dir fast sicher vorhersagen, dass diese Entscheidung Einfluss auf deinen OS-Kernel haben wird - weil du den nämlich so bauen wirst, dass ein primitiver Bootloader dafür irgendwie noch reicht. Ein Bootloader, der (ungeplant) vorgibt, welches Design das OS hat, ist keine gute Sache.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 07. February 2012, 16:11 »
Ok danke für den Rat, ich werde dann auf was fertiges umsteigen.
Ist Grub dafür ganz ok, oder gibt es irgendwas geeigneteres?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 07. February 2012, 17:14 »
GRUB ist in Ordnung. Einen Multibootkernel kannst du übrigens nicht nur mit GRUB, sondern auch direkt mit qemu -kernel booten, das ist auch recht praktisch.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 07. February 2012, 17:25 »
Stimmt den -kernal parameter kenn ich auch noch.
Ich werde es dann wohl mit dem machen, GRUB ist mir zu mächtig dafür.

Dimension

  • Beiträge: 155
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 07. February 2012, 20:11 »
@corvo: schau dir im wiki mal die memory map an linear 0x0009C000 .. 0x000FFFFF ist reserviert und darüber geht nur mit A20-gate.

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 07. February 2012, 20:53 »
Ok werde ich machen, danke.

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 26. February 2012, 16:20 »
Ich entschuldige mich direkt mal für's Ausgraben, meine aber, den ursprünglichen Fehler identifiziert zu haben:

Du lädst den Kernel an 0x1000:0x0000, also an 0x10000, teilst ihm aber per "org" mit, dass er an 0x1000 liegt. Dadurch verschiebt sich auch die Sprungadresse von "start". Das Endergebnis ist eine wunderbar kaputte Endlosschleife.
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

corvo

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 14. March 2012, 22:27 »
Moin,

mh...
Ich dachte ich konnte nicht in den code springen da mein gcc den nicht als 16-Bit code kompiliert.
Aber ich probiere mal aus ob das so funktioniert.
Danke nochmal

 

Einloggen