Pisze bootloader z obsługą FAT16.
Ma załadować jakiś plik i skoczyć do niego.
Dlaczego bootloader nie może znaleźć pliku z jądrem ???
org 0x7C00
mov si, M4
call print
jmp start
OEM_Name db "MyOperatingSystem" ; nazwa systemu
BytesPerSector dw 0x0200 ; bajtow na sektor - 512
SectorsPerCluster db 0x04 ; sektorow na klaster - 4
ReservedSectors dw 0x0001 ; zarezerwowanych sektorow - 1
FATCopies db 0x02 ; liczba kopii FAT - 2
MaxRootDirEntries dw 0x0200 ; liczba wpisow w katalogu glownym - 512
NumberOfSectorsSmall dw 0xFFF0 ; liczba sektorow dla malych partycji - 65520
MediaDescriptor db 0xF8 ; F8 - dysk twardy, F0 - dyskietka - 248
SectorsPerFAT dw 0x0040 ; liczba sektorow przypadajacych na jedna FAT - 64
SectorsPerTrack dw 0x0020 ; liczba sciezek - 32
NumberOfHeads dw 0x0040 ; liczba glowic - 64
HiddenSectors dd 0x00000000 ; liczba ukrytych sektorow - 0
NumberSectorsHuge dd 0x00000000 ; Liczba sektorow dla duzych dyskow
;(NumberOfSectorsSmall jakby nie styklo) - 0
LogicalDriveNumber dw 0x0080 ; numer napedu - 128
ExtendedSignature db 0x29 ; sygnaturka - 41
SerialNumber dd 0x5678D47D; numer seryjny - 5667028
VolumeName db "CursedOS "; etykietka
FATName db "FAT16 " ; nazwa wersji fata
print: ; Funkcja sluzy wyswietlaniu
.pisz:
lodsb
or al, al
jz .napisalem
mov ah, 0x0E
int 0x10
jmp .pisz
.napisalem:
ret
start: ; tu zaczynamy impreze
cli ; wylaczamy obsluge przerwan - bedziemy ustawiac rejestry segmentowe
push word 0x0000 ; adres do naszego wykorzystania - OD - 0
pop ss ; ustawiamy tam segment stosu
push word 0xFFF0 ; a wielkosc ustawiamy na najwieksza - DO - 65520
pop sp ; ustawiamy wskażnik stosu
mov ax, cs ; tak
mov ds, ax
mov es, ax ; ladujemy do dwoch rejestrow segmentowych
mov fs, ax
mov gs, ax
sti ; i odpalamy obsluge przerwan
; W tym miejscu za pomoca przerwania 13h i funkcji 0x08h pobierzemy dane o dysku i zapiszemy je w pamieci
mov ah, 0x08 ; funkcja 0x08h przerwania numer 13
mov dl, byte [LogicalDriveNumber] ; numer dysku
int 13h ; wywolanie przerwan
; te zamotanie to dlatego ze z byte musialem word zrobic
inc ch ; zwiekszamy ch o 1
xor ax, ax ; zerojemy AX
mov al, ch ; przenosimy wartosc ch do al
mov word [maxTrack], ax ; wrzucamy tutaj parametry - ???
inc dh ;
mov al, dh ;
mov word [maxHead], ax ;
mov al, cl ;
mov word [maxSector], ax ;
; Obliczamy wielkosc Root Directory i zapisujemy w CX zeby pasowalo do funkcji ReadSectors
mov ax, 0x0020 ; 32-bajtowy opis kazdego pliku w katalogu
xor dx, dx ; czyscimy DX (DX:AX mul costam)
mul word [MaxRootDirEntries] ; mnozymy przez maksymalna liczbe wpisow otrzymujac wielkosc :)
div word [BytesPerSector] ; i dzielimy przez liczbe bajtow na sektor otrzymujac ilosc sektorow ktore to zajmuje
xchg ax, cx ; wsadzamy do cx wartosc ax - wymienia zawartości operandów między sobą
; Obliczamy polozenie Root Directory i zapisujemy w AX z tego samego powodu co wyzej ;)
mov ax, word [SectorsPerFAT] ; wrzucamy liczbe sektorow na jedna tablice FAT
xor dx, dx ; zerowanie dx
mul word [FATCopies] ; mnozymy przez liczbe tablic FAT
add ax, word [ReservedSectors] ; dodajemy liczbe sektorow
mov word [DataSector], ax ; zapisujemy to w pamieci
add word [DataSector], cx ; i dodajemy wielkosc root dir otrzymujac poczatek sekcji z danymi
; Odczytujemy ten sztycht
mov bx, 0x7E00 ; odczytujemy po 512 bajtow wiec zaczynamy impreze od 0x0000:0x7E00 (obszar zaraz za bootloaderem)
call ReadSectors
; Tutaj zaczynamy szukac naszego pliku i sprawdzac czy wogole on tam jest
mov cx, word [MaxRootDirEntries] ; bedziemy odczytywac nie wiecej razy niz jest mozliwe. W CX jest licznik dla instrukcji loop
xor di, di
mov di, 0x7E00 ; adres poczatku obszaru przeszukiwanego
xor si, si
mov si, KernelName ; adres nazwy do wyszukania
SearchForKernel:
push cx ; zeby nam czasem licznik sie nie zepsul
mov cx, 0xB ; 11 znakow ma kernelek
push di ; di / si jest zmieniane przez cmpsb to trzeba zachowac
push si
rep cmpsb ; sprawdz ten sztycht - Opis : Porównuje bajt o adresie DS:SI lub DS:ESI z bajtem o adresie ES:DI lub ES:EDI
; i w zależności od wyniku ustawia odpowiednie flagi (takie same jak CMP ).
; Następnie, w zależności od DF (destination flag, wskaźnika kierunku) zmniejsza (gdy DF=1) lub zwiększa (gdy DF=0) SI i DI (lub ESI i EDI).
pop si ; polozylismy to podnosimy
pop di
je LoadKernel ; jesli nazwa pasuje to ladujemy kernela
pop cx ; jesli nie to bierzemy licznik ktory schowalismy
add di, 0x20 ; przestawiamy na nastepny wpis w RootDirectory (kazdy ma 32b)
loop SearchForKernel ; i patrzymy na nastepny
jmp KernelNotFound ; jesli nie ma no to skaczemy ze nie ma ;)
LoadKernel:
mov si, M1
call print
mov ax, [di+0x1A] ; na tej pozycji jest numer klastra gdzie lezy nasz kernelson
mov word [cluster], ax ; zapisujemy pierwszy klaster
; tutaj zaladujemy tablice FAT
mov cx, word [SectorsPerFAT] ; ladujemy do CX liczbe sektorow ktora zajmuje FAT
mov ax, word [ReservedSectors] ; a do ax poczatek
mov bx, 0x7E00 ; ladujemy to zamiast wczesniej odczytanego RootDir - bo nam juz niepotrzebny
call ReadSectors
push word 0x0100 ; ustawiamy wartosc ES
pop es
mov ax, word [cluster]
xor bx, bx ; adres pod ktory wrzucamy (zaczynamy od 0x0100:0x0000)
FATLoop:
call ClusterToSector ; zamieniamy numer klastra na adres
mov cl, byte [SectorsPerCluster] ; ilosc sektorow do odczytania
call ReadSectors ; odczytujemy pierwszy sektor
push bx
mov ax, word [cluster]
shl ax, 1 ; mnozymy klaster razy 2 otrzymujac offset z ktorego odczytamy
mov bx, ax ; wrzucamy do bx
mov ax, [bx+0x7E00] ; odczytujemy wartosc z tablicy FAT
mov word [cluster], ax ; wrzucamy to do numeru klastra bez wzgledu na to co tam jest
pop bx
cmp ax, 0xFFFF ; porownujemy wartosc odczytana, jesli jest 0xFFFF to znaczy ze to ostatni klaster pliku
jne FATLoop ; wiec jesli nie pasuje to czytamy nastepny
mov si, M3
call print
jmp 0x0100:0x0000 ; i odpalamy odczytany kernel
KernelNotFound:
mov si, M2
call print
jmp $
; --------
; Potrzebne funkcyjki
; --------
; --------
; ClusterToSector
; Funkcja przyjmuje numer klastra i przelicza go na adres pliku (w AX)
; --------
ClusterToSector:
push dx ; kladziemy uzywane zmienne na stos
push cx
sub ax, 2 ; odejmujemy 2
xor dx, dx
xor cx, cx
mov cl, byte [SectorsPerCluster] ; mnozymy przez liczbe sektorow na klaster
mul cx
add ax, word [DataSector] ; i dodajemy miejsce poczatku sektora z danymi majac polozenie pliku
pop cx
pop dx ; przywracamy zmienne
ret
; --------
; SectorCHS - konwersja adresu w postaci numeru sektora liczac od poczatku na CHS (czyli cylinder head sector)
; Funkcja przyjmuje w rejestrze AX numer
; --------
SectorCHS:
push bx ; kladziemy ax na stos
push ax
xor bx, bx
mov ax, word [maxSector]
mul word [maxHead]
xor dx, dx
xchg ax, bx ; tu mamy obliczenie cylindra
pop ax
div bx
mov byte [absoluteTrack], al
mov ax, dx
xor dx, dx ; zerujemy do dzielenia. Dzielenie wyglada tak: (DX:AX div costam) stad musimy wyzerowac dx...
div word [maxSector] ; dzielimy przez maksymalna liczbe sektorow otrzymujac tym samym w ax numer glowicy a w dx sektor
mov byte [absoluteHead], al ; zapisujemy ;)
inc dl
mov byte [absoluteSector], dl
pop bx
ret ; i wracamy
;-------
; ReadSectors - odczytuje cx sektorow z dysku zaczynajac od ax pod adres es:bx
; Przyjmowane argumenty:
; cx - liczba sektorow do odczytu
; ax - poczatek obszaru do odczytu
; es:bx - adres w pamieci pod ktory odbywa sie odczyt
;-------
ReadSectors:
push ax
push bx
push cx ; zapisujemy je na stosie bo bedziemy zmieniac a sa nam potrzebne
call SectorCHS ; zamieniamy adres na CHS
mov ah, 0x02 ; czytanie sektorow z dysku
mov al, 0x01 ; ilosc - 1
mov ch, byte [absoluteTrack] ; sciezka
mov cl, byte [absoluteSector] ; sektor
mov dh, byte [absoluteHead] ; glowica
mov dl, byte [LogicalDriveNumber] ; dysk
int 13h ; czytamy
pop cx
pop bx
pop ax
add bx, word [BytesPerSector] ; przelaczamy sie na nastepny sektor
inc ax
loop ReadSectors ; i powtarzamy az sie nie skonczy ilosc sektorow do odczytania
ret ; jesli koniec to wracamy
; -------
; Zmienne
; -------
absoluteTrack db 0x00 ; sciezka (cylinder)
absoluteHead db 0x00 ; glowica
absoluteSector db 0x00 ; sektor
maxTrack dw 0x0000
maxHead dw 0x0000 ; miejsce na dane o nosniku
maxSector dw 0x0000
DataSector dw 0x0000 ; polozenie sektora z danymi (jego poczatku)
cluster dw 0x0000
KernelName db "krenel.bin" ; nazwa szukanego pliku
M1 db "Ladowanie kernel'a...", 13, 10, 0
M2 db "Nie odnaleziono pliku...", 13, 10, 0
M3 db "Zaladowano poprawnie...", 13, 10, 0
M4 db "Szukam...", 13, 10, 0
times 510-($-$$) db 0x00
dw 0xAA55
Dodam jeszcze paczkę z plikami potrzebnymi po kompilacji