ich verwende den Bootloader von TJ
FileSysType db "FAT12 "
BOOTINFOBLOCK_END:
;########################################################################
;BOOTSECTOR_CODE_START
org 0x7C00 ;Code-Start-Adresse auf 0x7C00 setzen
cli ;Interruptflag löschen (keine Interrupts zulassen)
mov ax, 0x9000
mov ss, ax ;Stacksegment auf AX(0x9000) setzen
xor sp, sp ;Stackpointer auf 0 setzen
sti ;Interruptflag setzen (Interrupts wieder zulassen)
call func_FindFileSector ;Startsektor der Kerneldatei finden lassen (Rückgabe in AX)
or ax, ax ;AX = 0? -> Datei nicht gefunden
jz KernelNotFound ;Zur Ausgabe (File not found) springen
call func_ReadFATTable ;FAT-Tabelle in den Speicher lesen lassen
mov bx, 0x1000 ;Segmentadresse festlegen an die der Kernel geladen werden soll
mov dx, [RootEntCnt] ;Startsektor der Datensektoren errechnen
shl dx, 5
add dx, [BytesPerSec]
dec dx
shr dx, 9
add [Temp], dx ;Und das Ergebnis in Temp-Variable speichern
LoadKernelFile:
mov dx, [Temp] ;Startsektor der Datensektoren in DX schreiben
add dx, ax ;Zum Startsektor der Datensektoren den Startsektor der Datei addieren
dec dx ;DX um 2 verringern
dec dx ;Zweimal "dec dx" braucht weniger Bytes als einmal "sub dx, 2"
push bx ;Segmentadresse an die der Sektor gelesen werden soll auf den Stack pushen
push dx ;Sektornummer die gelesen werden soll auf den Stack pushen
call func_ReadSector ;Sektor lesen lassen
add sp, 4 ;2 Parameter vom Stack löschen
push ax ;FAT-Eintrag-Nummer auf den Stack pushen
call func_ReadFATEntry ;Wert des FAT-Eintrags lesen (Rückgabe in AX)
add sp, 2 ;1 Parameter vom Stack löschen
cmp ax, 0xFFF ;Ist das der letzte FAT-Eintrag der Kernel-Datei?
je ExecuteKernel ;Wenn Ja -> Springe zum Kernel
add bx, 32 ;Segmentadresse um 32 erhöhen. Dort wird der nächste Sektor hingelesen
jmp LoadKernelFile ;Springe wieder nach oben um nächsten Sektor der Kernel-Datei zu lesen
ExecuteKernel:
mov ax, 0x1000
push ax ;Segmentadresse an welcher der Kernel ist auf den Stack pushen
mov ax, 0
push ax ;Offsetadresse des Kernels (0) auf den Stack pushen
retf ;Einen FAR-Rücksprung zum Kernel machen
KernelNotFound:
push WORD MsgFileNotFound ;Offset der "File not Found" Meldung auf den Stack pushen
call func_PrintString ;Meldung ausgeben lassen
add sp, 2 ;1 Parameter vom Stack löschen
WaitForKeyToReboot:
mov ah, 0 ;Auf Tastendruck warten
int 0x16
Reboot:
db 0xEA ;Reboot
dw 0x0000
dw 0xFFFF
;BOOTSECTOR_CODE_END
;########################################################################
;DATABLOCK_START
MsgFileNotFound db "File not found.",13,10,0 ;Meldung wenn kein Kernel gefunden wurde
Filename db "KERNEL BIN" ;Dateiname des Kernels
Temp dw 0 ;Tempvariable
;DATABLOCK_END
;########################################################################
;FUNCTIONS_START
;------------------------------------------------------------------------
;Funktion um einen NULL-Terminierten String auszugebens
;1. Paramtere: Offset an dem sich der String befindet
func_PrintString:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen
pusha ;Alle Register sichern
mov si, [Param1] ;1. Parameter(Offset des Strings) nach SI kopieren
mov ah, 0x0E ;Funktion zur Zeichenausgabe
mov bx, 0x0007 ;Farbattribut des Zeichens
.1:
lodsb ;Zeichen von SI-Pointer nach AL kopieren und SI um 1 erhöhen
or al, al ;AL = 0? String zu Ende?
jz .2 ;Wenn JA -> Springe zum Ende
int 0x10 ;Zeichen ausgeben lassen
jmp .1 ;Wieder nach oben springen um nächstes Zeichen auszugeben
.2:
popa ;Register wiederherstellen
mov sp, bp ;Stackpointer wieder in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return
;------------------------------------------------------------------------
;Funktion um den Startsektor der Kernel-Datei zu finden
func_FindFileSector:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen
sub sp, 2 ;Platz für eine lokale Variable auf dem Stack schaffen
pusha ;Alle Register sichern
mov ax, 0x9200 ;Segmentadresse festlegen an die ein Sektor zwischengespeichert wird
mov es, ax
mov ax, [FATSize] ;Startsektor des Root-Directorys errechnen
mov bl, [NumFATs]
mul bl
add ax, [ResvdSecCnt]
mov [Temp], ax ;Startsektor des Root-Directorys in Temp-Variable speichern
xor dx, dx ;DX auf 0 setzen (Braucht weniger Bytes als "mov dx, 0")
.E:
cmp dx, [RootEntCnt] ;Wurden schon alle Root-Dir-Einträge durchsucht?
je .A ;Wenn JA -> Datei nicht gefunden
test dx, 15 ;DX durch 16 ohne Rest teilbar?
jnz .B ;Wenn JA -> Nächsten Sektor lesen
push es ;Segmentadresse für zwischenspeichern eines Sektors auf Stack pushen
push ax ;Sektornummer auf Stack pushen
call func_ReadSector ;Sektor lesen lassen
add sp, 4 ;2 Parameter vom Stack löschen
inc ax ;AX um 1 erhöhen (Braucht weniger Bytes als "add ax, 1")
xor bx, bx ;BX auf 0 setzen (Braucht weniger Bytes als "mov bx, 0")
.B: ;Wenn DX NICHT durch 32 OHNE Rest teilbar ist, fahre HIER fort
cmp BYTE [es:bx], 0x0E ;Erstes Zeichen des Root-Dir-Eintrags = 0x0E?
je .D ;Wenn JA -> Nächsten Eintrag lesen
cmp BYTE [es:bx], 0 ;Erstes Zeichen des Root-Dir-Eintrags = 0?
je .A ;Wenn JA -> Keine weiteren Einträge mehr. Datei nicht gefunden
mov si, Filename ;Offset des Dateinamens nach SI kopieren
mov di, bx ;Offset des Root-Dir-Eintrags nach DI kopieren
mov cx, 11 ;11 Zeichen sollen verglichen werden
repe cmpsb ;Solange vergleichen bis CX = 0 oder ungleiche Zeichen
or cx, cx ;CX = 0?
jz .C ;Wenn JA -> Alle Zeichen stimmen überein. Datei gefunden
.D:
inc dx ;DX um 1 erhöhen
add bx, 32 ;BX um 32 erhöhen (Offset des nächsten Root-Dir-Eintrags)
jmp .E ;Wieder nach oben springen um nächsten Eintrag zu vergleichen
.A: ;Wenn die NICHT Datei gefunden wurde, HIER fortfahren
popa ;Alle Register wiederherstellen
xor ax, ax ;AX auf 0 setzen (Braucht weniger Bytes als "mov ax, 0")
jmp .Ende ;Zum Ende Springen
.C: ;Wenn die Datei gefunden wurde, HIER fortfahren
push WORD [es:bx+26] ;Startsektornummer der Datei auf den Stack pushen
pop WORD [Var1] ;Startsektornummer in lokale Variable popen
popa ;Alle Register wiederherstellen
mov ax, [Var1] ;Startsektornummer der Datei nach AX kopieren
.Ende:
mov sp, bp ;Stackpointer in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return
;------------------------------------------------------------------------
;Funktion um einen Sektor zu lesen
;1. Parameter: Logische Sektornummer des Sektors welcher gelesen werden soll
;2. Parameter: Segmentadresse an die der Sektor gespeichert werden soll
func_ReadSector:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen
sub sp, 6 ;Platz für 3 lokale Variablen auf dem Stack schaffen
pusha ;Alle Register sichern
;Aus Logischer Sektornummer die CHS Adresse errechnen
mov ax, [Param1] ;Aus logischer Sektornummer den Cylinder errechnen
mov bx, 36
mov dx, 0
div bx
mov [Var1], ax
mov ax, dx ;Aus logischer Sektornummer den Head errechnen
push ax
mov bx, 18
mov dx, 0
div bx
mov [Var2], ax
pop ax ;Aus logischer Sektornummer den Sektor errechnen
mov dx, 0
div bx
mov ax, dx
add ax, 1
mov [Var3], ax
.1:
mov ax, [Param2] ;Segmentadresse zum speichern des Sektors festlegen
mov es, ax
mov bx, 0 ;Offset zum speichern des Sektors festlegen
mov ah, 2 ;Funktion zum Sektorlesen
mov al, 1 ;1 Sektor soll gelesen werden
mov ch, [Var1] ;Angabe des Cylinders an dem der Sektor gelesen werden soll
mov cl, [Var3] ;Angabe des Sektors an dem der Sektor gelesen werden soll
mov dh, [Var2] ;Angabe des Heads an dem der Sektor gelesen werden soll
mov dl, 0 ;Von Laufwerk A: lesen
int 0x13 ;Sektor lesen lassen
jc .1 ;Bei Fehler nochmal versuchen
popa ;Alle Register wiederherstellen
mov sp, bp ;Stackpointer in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return
;------------------------------------------------------------------------
;Funktion um einen FAT-Eintrag zu lesen
;1. Parameter: Nummer des Eintrags der gelesen werden soll
;In AX wird der Wert des gelesenen FAT-Eintrag zurückgegeben
func_ReadFATEntry:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen
sub sp, 2 ;Platz für eine lokale Variable auf dem Stack schaffen
pusha ;Alle Register sichern
mov ax, [Param1] ;Offset errechnen an dem sich der FAT-Eintrag im Speicher befindet
mov bx, 3
mul bx
mov bx, 2
xor dx, dx
div bx
mov bx, 0x9200 ;Segmentadresse angeben an der die FAT-Tabelle im Speicher liegt
mov es, bx
mov bx, ax
mov ax, [es:bx]
mov [Var1], ax ;FAT-Eintrag (16 Bit) in lokale Variable speichern
mov cx, [Param1] ;Testen ob der zu lesende FAT-Eintrag gerade oder ungerade ist
test cx, 1
jz .Gerade ;Wenn GERDADE -> Springe
;Wenn der zu lesende FAT-Eintrag UNGERADE ist, HIER fortfahren
popa ;Alle Register wiederherstellen
mov ax, [Var1]
shr ax, 4 ;FAT-Eintrag(12 Bits) aus den 16 Bits extrahieren
jmp .Ende
.Gerade: ;Wenn der zu lesende FAT-Eintrag GERADE ist, HIER fortfahren
popa ;Alle Register wiederherstellen
mov ax, [Var1]
and ax, 0xFFF ;FAT-Eintrag(12 Bits) aus den 16 Bits extrahieren
.Ende:
mov sp, bp ;Stackpointer in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return
;------------------------------------------------------------------------
;Funktion zum einlesen der FAT-Tabelle in den Speicher
func_ReadFATTable:
pusha ;Alle Register sichern
mov bx, 0x9200 ;Segmentadresse festelegen an welche die FAT-Tabelle gelesen werden soll
mov ax, [ResvdSecCnt] ;Startsektor der FAT-Tabelle eintragen
mov cx, [FATSize] ;Anzahl der FAT-Tabellen-Sektoren eintragen
.A:
push bx ;Segmentadresse auf den Stack pushen
push ax ;Sektornummer auf den Stack pushen
call func_ReadSector ;Sektor lesen lassen
add sp, 4 ;2 Parameter vom Stack löschen
inc ax ;Nächsten Sektor auswählen
add bx, 32 ;Segmentadresse um 32 erhöhen (Dort wird nächster Sektor gespeichert)
loop .A ;Solange wiederholen bis alle Sektoren gelesen wurden
popa ;Alle Register wiederherstellen
ret ;Return
;------------------------------------------------------------------------
;FUNCTIONS_END
;########################################################################
times 512-($-$$)-2 db 0 ;Den Rest des Bootsektors mit Nullen Füllen
dw 0AA55h ;0xAA55 am Ende des Bootsektors schreiben