Boot loader cz. 1.
Pierwsze kroki
Jak na razie dla wygody nasz system będziemy umieszczać na dyskietce. W końcu jak na razie pewnie nikt nie chce sobie zepsuć boot sektora, który jest na dysku twardym :P. A na początku póki nie opisze systemu plików (o tym będzie osobny art), zepsujemy cały system plików, który jest na dyskietce, albo inaczej "stworzymy własny system plików" - tak ładniej brzmi :]
Zanim zaczniemy pisać nasz pierwszy system operacyjny, musimy napisać boot loadera, który nam to jądro załaduje. No to zaczynamy:
Co to w ogóle jest boot loader?
Boot loader jest to mały program który ma za zadanie załadować i uruchomić system operacyjny.
Bios ładuje do ramu tak zwany
boot sektor (inaczej
MBR - Master Boot Record), czyli pierwszy sektor pod zerową głowicą i na zerowej ścieżce pierwszego ustawionego urządzenia bootującego, pod warunkiem, że znajduje się tam boot loader. Boot loader musi zajmować dokładnie 512 bajtów (czyli tyle ile jeden segment w trybie rzeczywistym) a dwa ostatnie bajty musza mieć wartość AA55h. Jeżeli nie ustawimy takiej ostatniej wartości to Bios uzna, że nie ma boot loadera. Jeżeli jednak wszystko pójdzie dobrze to w pamięci pod adresem 0000:7C00H będzie boot loader. Gdy bios oddaje kontrolę boot loaderowi wszystkie rejestry segmentowe są wyzerowane, a DL zawiera numer dysku, z którego pochodzi boot sektor (0 to dyskietka, 80h - pierwszy dysk twardy).
A oto przykład najprostszego boot loadera:
Boot.asm:
Kod:
aa: ;wykonujemy nieskończoną pętle
jmp aa ;aby nie wywołać błędu.
times 510-($-$$) db 0 ;zapełniamy plik do końca, aby miał 510bajtow
dw 0AA55h ;No i na końcu dodajemy wartość 0AA55h
A teraz kompilujemy:
nasm boot.asm -o boot.bin
Teraz programem
RawWrite kopiujemy nasz plik
boot.bin na dyskietkę(traktujemy go jako obraz). No i uruchamiamy emulator i widzimy czarny ekran :] Czyli wszystko się udało, nasz pierwszy boot loader został załadowany bez żadnych błędów.
Wcześniej wspomniałem o "własnym formacie plików", jest on bardzo prosty - w pierwszy sektorze będzie znajdował się boot loader a zaraz w drugim początek naszego kernela. Czyli teraz rozbudujemy boot loadera o to ze będzie wczytywał do pamięci drugi sektor i przekazywał mu kontrole. Do czytania użyjemy przerwania biosu 13h.
Kod na wczytanie drugiego sektora z dyskietki pod adres 0800h:
Kod:
mov ah, 2 ;funkcja 2 przerwania 13h
mov al, 10 ;ilość sektorów do przeczytania (10*512 = 5kb)
mov ch, 0 ;cylinder
mov cl, 2 ;sektor (w 1 jest bootsector)
mov dh, 0 ;głowica
mov bx, 0800h ;gdzie załadować kernel (es:bx)
mov es, bx ;dane do ES możemy umieścić tylko przez inny rejestr
xor bx, bx ;bx równy 0
int 13h ;wywołujemy przerwanie
Aby teraz boot loader uruchomił to, co załadował do pamięci (czyli coś, co nazywamy kernelem) musimy wykonać skok do tego miejsca, czyli krótko i na temat:
I to już cały boot loader. A oto cały kod:
Kod:
org 7C00h
start:
mov ah, 2
mov al, 10
mov ch, 0
mov cl, 2
mov dh, 0
mov bx, 0800h
mov es, bx
xor bx, bx
int 13h
jmp 0800h:0000h
times 510 - ($ - start) db 0
dw 0AA55h
Aby sprawdzić czy nasz boot loader działa musimy jeszcze napisać jakiegoś przykładowego kernela. A oto on:
Kernel.asm:
Kod:
mov ah, 9
mov al, '='
mov bx, 7
mov cx, 10
int 10h
hang:
jmp hang
Dobra, mamy boot loader i kernela, pozostaje tylko jedno pytanie jak skopiować na dyskietkę boot loadera do pierwszego sektora a kernela do drugiego?
Teraz napiszemy sobie w delphi prosty program, który połączy nam te dwa pliki w jeden (krótko mówiąc zrobimy sobie obraz dyskietki). Cały czas kompilujemy z linii poleceń, więc dla wygody napiszemy sobie tez taki programik, nie będziemy się tu bawić komponentami VCL, bo w tym przypadku to strata czasu.
Kod:
program zlacz;
{$APPTYPE CONSOLE}
var
final, f: file of byte;
buf, q: byte;
begin
if (paramcount < 3) then
writeln('uzycie: zlacz ')
else begin
assignfile(final, paramstr(paramcount));
rewrite(final);
for q := 1 to paramcount -1 do begin
writeln(paramstr(q));
assignfile(f, paramstr(q));
reset(f);
while not eof(f) do begin
blockread(f, buf, sizeof(buf));
blockwrite(final, buf, sizeof(buf));
end;
closefile(f);
end;
closefile(final);
writeln('Gotowe!!!');
end;
end.
A teraz kompilujemy całość:
nasm boot.asm -o boot.bin
nasm kernel.asm -o kernel.bin
zlacz boot.bin kernel.bin image.img
I teraz RawWritem nagrywamy plik
image.img. Odpalamy emulator i widzimy naszego pierwszego kernela :]
Autor:
Michał Ślaga (Destruction)
gg: 4029168
Autor: Destruction
Artykuły mogą być komentowane wyłącznie przez zarejestrowanych użytkowników.
Zaloguj się |
Załóż nowe konto