Autor Thema: Bootloader von der 1. Lowlevel Ausgabe  (Gelesen 5503 mal)

JG

  • Beiträge: 189
    • Profil anzeigen
Gespeichert
« am: 16. February 2005, 16:05 »
Hallo,
ich hab ein paar Fragen zum Bootloader.
Hier mal der Code:
org 0x7C00 ; Unsere Startadresse

; -----------------------------------------
; Unser Bootloader
; -----------------------------------------

start:
                ; Erst brauchen wir einen Stack.
cli             ; Keine Interrupts!
mov ax, 0x9000  ; Stackadresse
mov ss, ax      ; SS = 9000 (unser Stack)
mov sp, 0       ; SP = 0000  (der Stackpointer)
sti             ; Interrupts zulassen

; Bootlaufwerk aus DL speichern
mov [bootdrv], dl

;Lade unseren Kernel
call load

;Springe zu diesem Kernel
mov ax, 0x1000 ; Die Adresse des Programms
mov es, ax     ; Segmentregister updaten
mov ds, ax
push ax
mov ax, 0
push ax
retf

; ----------------------------------------------
; Funktionen und Variablen
; ----------------------------------------------

bootdrv db 0 ;Das Bootlaufwerk
loadmsg db "Loading...",13,10,0

; Einen String ausgeben:
putstr:
lodsb             ; Byte laden
or al,al
jz short putstrd  ; 0-Byte? -> Ende!

mov ah,0x0E       ; Funktion 0x0E
mov bx,0x0007     ; Attribut-Byte (wird nicht benötigt)
int 0x10          ; schreiben
jmp putstr        ; Nächstes Byte
putstrd:
retn

; Lade den Kernel vom Bootlaufwerk
load:

; Diskdrive reset (Interrupt 13h, 0)
push ds            ; Sichere DS
mov ax, 0          ; Die gewünschte Funktion (reset)
mov dl, [bootdrv]  ; Dieses Laufwerk ist gewünscht
int 13h            ; Den Interrupt ausführen
pop ds             ; DS wiederherstellen
jc load            ; Geht nicht? -> Noch mal!

load1:
mov ax,0x1000      ; ES:BX = 10000
mov es,ax
mov bx, 0

; Sektoren lesen (Interrupt 13h, 2)
mov ah, 2       ; Funktion 2 (Lesen)
mov al, 5       ; Lese 5 Sektoren
mov cx, 2       ; Cylinder=0, Sector=2
mov dx, 0       ; Head=0, Laufwerk=0
int 13h         ; ES:BX =  Daten vom Laufwerk
jc load1        ; Fehler? Noch mal!
mov si,loadmsg
call putstr     ; Meldung ausgeben
retn

times 512-($-$$)-2 db 0   ; Dateilänge: 512 Bytes
dw 0AA55h                 ; Bootsignatur

So nun die Fragen:
1. Was ist [bootdrv]?

2. bei loadmsg db "Loading...",13,10,0
Was beuteuten da die Zahlen dahinter?

3. Wie wird der Kernel gelesen?
 
4. Gibt es irgendwo eine übersicht mit allen interrupts?

5. Wie rechnet man hex in dezimal Zahlen um?

Ich weiß es sind viele Fragen...

BigOlly

  • Beiträge: 88
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 16. February 2005, 16:50 »
Hmmmmm...

zu 1.:
Das BIOS übergibt beim Start des Bootsectors im Register DL die BIOS-Laufwerks-Nummer von dem gebootet wurde. Diese sollte man eben sichern bevor man DL bzw. DX benutzt.
Außerdem könntest Du korrekter Weise beim lesen der Sectoren anstat:
mov dx, 0       ; Head=0, Laufwerk=0
auch:
mov dh, 0                   ; Head=0
mov dx, [bootdrv]       ; Laufwerk
schreiben.


zu 2.:
Die 13 ist der Stereucode "Cursor auf Zeilenanfang" (Caridge Return) und die 10 ist der Steuercode "neue zeile" (LineFeed). Damit wird der Cursor auf den Anfang der nächsten Zeile gesetzt. Das könntest Du auch weglassen, dann würde der Cursor halt hinter dem letzten punkt von "Loading..." stehen bleiben.


zu 3.:
Das ist nicht in 2 Worten erklärt. Entweder Du speicherst den Kernel in bestimmten Sectoren die Du dann von Deinem Bootloader aus lädst (und Dein Boot-Code sieht dannach aus, das Du dies willst), oder Du speicherst den Kernel als Datei auf der Diskette und liest ihn anhand von BiosParameterBlock, FAT und RootDir (jedenfalls wenn du FAT12 und FAT16 benutzt). Ich kann nur immer wieder auf TeeJay's Bootloader-tutorial verweisen.


zu 4.:
ja, z.b. Ralph Browns Interrupt-List oder in Büchern wie PC-Intern. Sieh mal in die Linkliste.


zu 5.:
Ich kann hier nicht das ganze Hexadezimal-System erklären, aber viellecht eine Beispiel-Berechnung:

h2F8A

   2 * 16 * 16 * 16    (=8192)
+ F * 16 * 16           (=3840)
+ 8 * 16                  (=128)
+ A                         (=10)
= 12170

(A=10, B=11 .....  F=15)

...oder Du nimmst einfach den Windows-Taschenrechner!



okay, Alle Klarheiten beseitigt? :-)
====================================================
Zitat: "Es ist schwierig zu antworten, wenn man die Frage nicht versteht."
(würde mich ja mal interessieren ob jemand weiß woher dieser Satz stammt...)

fasmat

  • Gast
Gespeichert
« Antwort #2 am: 16. February 2005, 17:05 »
1. Was ist [bootdrv]?

bootdrv ist die Abkürzung von Boot Drive, zu deutsch Boot-Laufwerk. Mit dieser Variable übergibt das BIOS deinem Bootsektor die Nummer des Laufwerks, auf dem er sich befindet.

2. bei loadmsg db "Loading...",13,10,0
Was beuteuten da die Zahlen dahinter?

13 steht in C für \n also Next Line=Zeilenumbruch
10 steht in C für \r also Carrage Return=Wagenrücklauf (der Cursor springt an die Stelle des 1. Zeichens der aktuellen Zeile)
0 deswegen, damit das BIOS weiß, wo die Zeichenkette aufhört.

3. Wie wird der Kernel gelesen?
Das geschieht in mehreren Schritten:

Zuerst wird mit:

mov ax, 0          ; Die gewünschte Funktion (reset)
mov dl, [bootdrv]  ; Dieses Laufwerk ist gewünscht
int 13h            ; Den Interrupt ausführen


das Bootlaufwerk reseted. Das muss man machen bevor man darauf zugreifen kann.

Hier:

mov ax,0x1000      ; ES:BX = 10000
mov es,ax
mov bx, 0


wird die Adresse angegeben an die der Kernel geladen wird. In diesem Fall 0x10000 (1 MB)

Danach wird mit:

; Sektoren lesen (Interrupt 13h, 2)
mov ah, 2       ; Funktion 2 (Lesen)
mov al, 5       ; Lese 5 Sektoren
mov cx, 2       ; Cylinder=0, Sector=2
mov dx, 0       ; Head=0, Laufwerk=0
int 13h         ; ES:BX =  Daten vom Laufwerk


Der Kernel aus Sektor 2 in den Speicher an die oben angegebene Adresse geladen.

Und mit diesen Zeilen:

mov ax, 0x1000 ; Die Adresse des Programms
mov es, ax     ; Segmentregister updaten
mov ds, ax
push ax
mov ax, 0
push ax
retf


Springt das Programm an die Adresse, an die vorher der Kernel geladen wurde...
 
4. Gibt es irgendwo eine Übersicht mit allen interrupts?
Ja, die findest du zum Beispiel hier:
http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte1at0.htm
Is leider englisch, aber wenn du ein bisschen googlest findest du sicher auch was auf deutsch ;)
Wichtig: Du kannt bei deinem Betriebssystem keine Dos Interrupts verwenden!

5. Wie rechnet man hex in dezimal Zahlen um?
Im Hexadezimalsystem verwendet man statt 10 16 Ziffern um Zahlen darzustellen: 0123456789ABCDEF

Wenn du jetzt dezimal in hexadezimal umrechnen willst musst du die dezimale Zahl zuerst durch 16 dividieren um die 1. Ziffer zu erhalten und der Rest gibt dir die 2. Ziffer an:

22 : 16 = 1, 6 Rest  => 22 = 0x16
250 : 16 = 15, 10 Rest => 250 = 0xFA (F steht für 15 und A für 10)

Zitat
Ich weiß es sind viele Fragen...

Macht doch nichts... dafür gibt es ja dieses Forum ;)

WM_HOPETHISHELPS
fasmat

EDIT: sehe gerade, da war jemand schneller als ich ;)

JG

  • Beiträge: 189
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 16. February 2005, 17:53 »
Danke  :D

Edit:
Nun hab ich trotzdem noch einn paar Fragen zum Kernel...


; ---------------------------------------------------
; Unser Kernel
; ---------------------------------------------------

mov ax, 1000h ; Segmentregister updaten
mov ds, ax
mov es, ax

start:
mov si, msg
call putstr   ; Schicke Bootmessage :)

mov si,msg_boot
call putstr   ; Noch eine Message :D

call getkey   ; Warte auf einen Tastendruck
jmp reboot    ; Reboot

; -------------------------------------------------
; Funktionen und Variablen
; -------------------------------------------------

msg db "Welcome to StupidOS 1.0",13,10,0
msg_boot db "Press any key...",10,0

; Stringausgabe
putstr:
lodsb            ; Byte laden
or al,al
jz short putstrd ; 0-Byte? -> Ende!
mov ah,0x0E      ; Funktion 0x0E
mov bx,0x0007    ; Atrribut-Byte
int 0x10         ; schreiben
jmp putstr       ; nächstes Byte
putstrd:
retn

; Warte auf einen Tastendruck
getkey:
mov ah, 0 ; Funktion 0
int 016h  ; Ausführen
ret

; Rebooten (HEX Dump).
reboot:
db 0EAh
dw 0000h
dw 0FFFFh


1. mov ax, 1000h ; Segmentregister updaten
 Wozu ist das gut?

2. lodsb
  irgendwie kenn ich den Befehl net....

3.retn
  Ist das ein Sprung befehl?

joachim_neu

  • Beiträge: 1 228
    • Profil anzeigen
    • http://www.joachim-neu.de
Gespeichert
« Antwort #4 am: 16. February 2005, 18:30 »
Zitat von: BigOlly
Außerdem könntest Du korrekter Weise beim lesen der Sectoren anstat:
mov dx, 0       ; Head=0, Laufwerk=0
auch:
mov dh, 0                   ; Head=0
mov dx, [bootdrv]       ; Laufwerk
schreiben.


das mit dem "mov dx,[bootdrv]" denke ich geht nicht, weil bootdrv ne bytestelle is, und dann in dh bootdrv und in dl das byte danach (in dem fall mit code) sein dürfte...
http://www.joachim-neu.de | http://www.orbitalpirates.de | http://www.middleageworld.de

System: 256 RAM, GeForce 2 MX 400, AMD Athlon XP 1600+, Windows XP, 1x Diskette, 1x DVD-ROM, 1x CD-R(W) Brenner,...

BigOlly

  • Beiträge: 88
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 16. February 2005, 18:47 »
an joachim_neu:


Ja Richtig! Mein Fehler! Hast gut aufgepasst..:lol:
Hab halt copy und paste gemacht und DX nicht geändert. :-)

Muß also heissen:
mov dh, 0 ; Head=0
mov dl, [bootdrv] ; Laufwerk



Allerdings: Stimmt Deine Erklärung nicht! ;-)  In DH würde nicht das bootdrv stehen sondern in DL!!!  Weil: Bei Intel werden die Bytes beim Speichern eines Wortes vertauscht. Wenn in [bootdrv]  0x0102 steht und Du lädst das Wort nach DX (mov dx, [bootdrv]) dann steht in DX: 0x0201 ! Trotzdem bleibt das natürlich ein Fehler weil das zuvor geladene DH ja wieder überschrieben wird.

Wenn ich die Zeilen aber vertausche und schreibe:
mov dx, [bootdrv]
mov dh, 0
dann würde es sogar fehlerfrei funktionieren! In DL steht das korrekte bootrv!
...aber das nur am Rande... ;-)
====================================================
Zitat: "Es ist schwierig zu antworten, wenn man die Frage nicht versteht."
(würde mich ja mal interessieren ob jemand weiß woher dieser Satz stammt...)

JG

  • Beiträge: 189
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 17. February 2005, 14:48 »
Hat jemand ne antwort auf meine Fragen?

Roshl

  • Beiträge: 1 128
    • Profil anzeigen
    • http://www.lowlevel.net.tc
Gespeichert
« Antwort #7 am: 17. February 2005, 15:26 »
Naja Assembler lernen wäre für dich hilfreich;M)
also lodsb steht für LOaDStringByte man könnte es dadurch ersetzen:
mov al,[si]
inc si

retn steht für RETurN und kennzeichnet einen Rücksprung aus einer Funktion
mov ax,0x1000 belegt ax mit dem wert 0x1000 mehr nicht
[schild=1]Wieder ein wertvoller(?) Beitrag von Roshl[/schild]

JG

  • Beiträge: 189
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 17. February 2005, 15:36 »
Hab ich ja schon, aber bei manchen sachen weiß ich net was es heißen soll...

 

Einloggen