Bootstrapping:
--------------
Moeilijkheidsgraad: makkelijk
Voorkennis: matige i386 assembly
Referenties: Ralfs Brown Interrupt List
Tools: bochs, dd, nasm
Bootstrapping is het process dat gestart wordt als je je computer hebt aangezet en nadat de BIOS zijn tests heeft uitgevoerd (de zogenaamde POST - power on self test). Je BIOS laadt vanaf de boot-drive 1 sector (512 bytes) in zijn geheugen en springt naar dat stukje code. Dat stukje code zorgt voor het laden van de rest van het OS (of voor andere dingen, zoals het verzorgen voor virussen of spelletjes als tetris). De sector van de schijf waarop dit stukje code staat heet de bootsector en staat per definitie op de eerste sector (sector 1) van de schijf.
Op een harddisk kun je meestal meerdere partities kwijt, met elk een eigen bootsector. Hierdoor kan de bootsector van partitie 2 nooit op de eerste sector van de schijf staan (omdat hier al de bootsector van partitie 1 staat). Om dit op te lossen staat op de eerste sector van een harddisk meestal geen bootsector, maar een master boot record (MBR). Dit is ook een stuk code dat wordt ingeladen door de bios, maar bevat extra informatie over de partities op de schijf (de partitie table). Dit moet ook allemaal in 512 bytes gebeuren, dus een MBR heeft minder ruimte voor programma-code dan een bootsector.
Een MBR en bootsector worden allebei beeindigd door 0xAA55 op plaats 510. Dit is de bootsector terminator en je bios *KAN* (maar hoeft niet altijd) kijken of dit bestaat. Als het niet bestaat, dan kan je bios zeggen dat er geen legale bootsector is en stoppen met booten. Dit moet er dus altijd instaan wil je je OS laten booten op verschillende computers (en BIOS'en).
Ook kunnen sommige file-systemen kunnen in de bios een header zetten waarin gegevens staan over de schijf (volume naam, fat-type etc). Hiermee gaan we pas in het volgend hoofdstuk aan de gang. Hierdoor is het mogelijk om bijvoorbeeld je OS en de benodigde files te kopieren naar een normale DOS-floppy.
In dit hoofdstuk gaan we een bootsector maken die geen OS inlaad, maar wat text laat zien op het beeldscherm. We gaan op dit moment nog geen enge en moeilijke dingen doen zoals het inladen van sectoren etc. Als je geen assembly kent, dan worden sommige dingen hieronder al best pittig, maar ik probeer zoveel mogelijk uitleg te geven in wat ik doe, en als je er dan nog niet uitkomt, dan heb je altijd nog the gathering...
Het eerste wat we moeten weten is dat de bootsector normale, ruwe code is zonder headers (zoals exe-files). We weten dat de laatste 2 bytes van de code 0xAA55 moet zijn, en dat de code precies 512 bytes lang moet zijn (we kunnen heel makkelijk de code uitvullen met 00'tjes of NOP'jes).
We weten dat de bootsector door de BIOS geladen word op positie 0000:7C00 of 07C0:0000. Alletwee zijn mogelijk, dus moeten wij er zelf voor zorgen dat dit op elk systeem gelijk is.
Wat ook handig is, is dat de BIOS in het DL-register het ID van de drive laad waarvan we booten. Floppy drives beginnen bij 0: 00 is de A:, 01 is de B:, en harde schijven (fixed disks) beginnen bij 0x80: 80 is de C:, 81 de D: etc etc..
Hou er rekening mee dat wanneer je in de bootsector zit, je niet alles kunt gebruiken wat je normaal wel kunt. Je kunt niet alle interrupts die je wilt aanspreken, en dingen zoals de muis werken nog niet. Je moet dus zo minimaal mogelijk gebruik maken van interrupts, en zoveel mogelijk zelf doen (zover dat dat kan).
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
| [bits 16] ; 16 bits code
org 0 ; We staan op offset 0
; We weten niet of we op 0000:7C00 of 07C0:0000 staan, daarom kiezen
; we er zelf een.
mov ax, 0x7C0 ; Segment 07C0
mov ds, ax ; Data staat op 07C0:0000 ipv 0000:7C00
cli
xor ax, ax ; Stack Segment Goedzetten
mov ss, ax
mov sp, 0xFFFF
sti
mov [bootdrive],dl ; Onthoud de bootdrive
; De volgende code maakt van het duffe zwarte achtergrond een
; mooi blauw kleurtje.
mov dx,0x3c8 ; VGA Palette register (werkt dus alleen
xor al,al ; op een VGA)
out dx,al ; We willen kleur 0 (background) instellen
inc dx ; VGA Data register (0x3c9)
mov al,8
out dx,al ; Output rood component
xor al,al
out dx,al ; Output groen component
mov al,32
out dx,al ; Output blauw component
dec dx ; En doe hetzelfde voor kleur 1
mov al,1
out dx,al
inc dx
mov al,63
out dx,al
out dx,al
out dx,al
; Nu hebben we een mooi kleurtje, print de string op
; het beeld.
mov si, msg ; Print string op het beeld
call PrintMsg
xor ah,ah ; Wacht op een toets
int 0x16
int 0x19 ; En reboot, de rest komt later...
; ------------------------------------------------------------------------
; Routine die een string in SI print die eindigt op een 0.
PrintMsg:
cld
lodsb ; Laad uit DS:SI naar AL
cmp al,0
jz End_Of_String ; Is het een 0, dan einde
call PrintChar ; Print character
jmp PrintMsg ; En volgende character
End_Of_String:
ret
; -------------------------------------------------------------------------
; Routine die een karakter in AL op het scherm print. Deze routine maakt
; gebruik van BIOS-interrupt 0x10 om een karakter te plotten.
PrintChar:
mov ah,0x0E ; BIOS functie 15
mov bx,0x0001 ; Print op page 0 in kleur 1
int 0x10
ret
; -------------------------------------------------------------------------
; Data die we gebruiken in de bootsector
msg db 'hello bootsector!',13,10,0
bootdrive db 0
times 510-($-$$) db 0x90 ; Opvullen met NOP (doet niets)
dw 0xAA55 ; En de boot terminator |
Ik hoop dat het een beetje duidelijk is wat ik hierboven gedaan heb. We weten als bootsector zijnde niet zeker of we op 0000:7C00 of 07C0:0000 bevinden (dat is per BIOS verschillend). Voor onze data is dit relevant om te weten en dus kiezen wij zelf maar wat het gaat worden. Daarna zetten we een stack-framepje op en bewaren wij de bootdrive-id. Het stukje daarna zorgt ervoor dat we van dat saaie grijs-op-zwart kleurtje afzijn door de achtergrondkleur (kleur 0) mooi blauw te maken en de letters (kleur 1) wit. Als dat gebeurd is, printen we een string af op het scherm, wachten we op een toets en rebooten we het systeem.
Voordat je je bootsector op een schijf kunt zetten moet je het eerst assembleren met nasm:
code:
1
| nasm -o bootsect.dat bootsect.asm |
Als dat gedaan is, kun je je bootsector wegschrijven naar de eerste sector van je schijfje. Ik doe het eventjes linux-style, maar voor de windows-mensen onder ons kunnen (hopelijk) zelf wel iets verzinnen (rawrite.exe ofzow). Zoniet, dan zal ik kijken of ik daarvoor een simpel programmatje voor kan vinden.
code:
1
| dd if=bootsect.dat of=/dev/fd0 bs=512 |
Voila, je eerste bootsector, en begin van je eigen OS is af... Reboot je test-systeem met de schijf, of probeer het via BOCHS uit (je A-drive is /dev/fd0). Werkt het? simpel toch? :-)
Huiswerk: maak een bootsector dat een stukje tekst laat zien en de gebruiker laat kiezen wat hij wil kiezen (bijvoorbeeld: laat de gebruiker een driveletter kiezen en bewaar deze in een aparte variable). Hierbij kun je gebruik maken van Ralph Brown Interrupt lists.
In het volgende hoofdstuk gaan we een MS-DOS (en tevens windows) compatible floppy maken met onze eigen bootsector. Deze bootsector kan kijken of er een file op de floppy staat die we nodig hebben (bijvoorbeeld kernel.sys) en deze in het geheugen laden.
Yo dawg, I heard you like posts so I posted below your post so you can post again.