092769e87c0ee52a9d7ae8e345312b139da53316
[reactos.git] / freeldr / bootsect / BTSECT32.ASM
1 ; BTSECT32.ASM
2 ; FAT32 Boot Sector
3 ; Copyright (c) 1998, 2000 Brian Palmer
4
5 org 7c00h
6
7 segment .text
8
9 bits 16
10
11 start:
12 jmp short main
13 nop
14
15 OEMName db 'FreeLDR!'
16 BytesPerSector dw 512
17 SectsPerCluster db 1
18 ReservedSectors dw 1
19 NumberOfFats db 2
20 MaxRootEntries dw 0 ;512 - Always zero for FAT32 volumes
21 TotalSectors dw 0 ;2880 - Always zero for FAT32 volumes
22 MediaDescriptor db 0f8h
23 SectorsPerFat dw 0 ;9 - Always zero for FAT32 volumes
24 SectorsPerTrack dw 18
25 NumberOfHeads dw 2
26 HiddenSectors dd 0
27 TotalSectorsBig dd 0
28 ; FAT32 Inserted Info
29 SectorsPerFatBig dd 0
30 ExtendedFlags dw 0
31 FSVersion dw 0
32 RootDirStartCluster dd 0
33 FSInfoSector dw 0
34 BackupBootSector dw 6
35 Reserved1 times 12 db 0
36 ; End FAT32 Inserted Info
37 BootDrive db 0
38 Reserved db 0
39 ExtendSig db 29h
40 SerialNumber dd 00000000h
41 VolumeLabel db 'FreeLoader!'
42 FileSystem db 'FAT32 '
43
44 main:
45 cli
46 cld
47 xor ax,ax
48 mov ss,ax
49 mov sp,7c00h ; Setup a stack
50 mov ax,cs ; Setup segment registers
51 mov ds,ax ; Make DS correct
52 mov es,ax ; Make ES correct
53
54
55 sti ; Enable ints now
56 mov [BootDrive],dl ; Save the boot drive
57 xor ax,ax ; Zero out AX
58
59 ; Reset disk controller
60 int 13h
61 jnc Continue
62 jmp BadBoot ; Reset failed...
63
64 Continue:
65 ; First we have to load our extra boot code at
66 ; sector 14 into memory at [0000:7e00h]
67 xor dx,dx
68 mov ax,0eh
69 add ax,WORD [HiddenSectors]
70 adc dx,WORD [HiddenSectors+2] ; Add the number of hidden sectors
71 mov cx,1
72 mov bx,7e0h
73 mov es,bx ; Read sector to [0000:7e00h]
74 xor bx,bx
75 call ReadSectors
76 jnc Continue1
77 jmp BadBoot
78
79
80 Continue1:
81 ; Now we must get the first cluster of the root directory
82 mov eax,DWORD [RootDirStartCluster]
83 cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
84 jb Continue2 ; If not continue, if so BadBoot
85 jmp ErrBoot
86 Continue2:
87 mov bx,800h
88 mov es,bx ; Read cluster to [0000:8000h]
89 call ReadCluster ; Read the cluster
90
91
92 ; Now we have to find our way through the root directory to
93 ; The OSLOADER.SYS file
94 xor bx,bx
95 mov bl,[SectsPerCluster]
96 shl bx,4 ; BX = BX * 512 / 32
97 mov ax,800h ; We loaded at 0800:0000
98 mov es,ax
99 xor di,di
100 mov si,filename
101 mov cx,11
102 rep cmpsb ; Compare filenames
103 jz FoundFile ; If same we found it
104 dec bx
105 jnz FindFile
106 jmp ErrBoot
107
108 FindFile:
109 mov ax,es ; We didn't find it in the previous dir entry
110 add ax,2 ; So lets move to the next one
111 mov es,ax ; And search again
112 xor di,di
113 mov si,filename
114 mov cx,11
115 rep cmpsb ; Compare filenames
116 jz FoundFile ; If same we found it
117 dec bx ; Keep searching till we run out of dir entries
118 jnz FindFile ; Last entry?
119
120 ; Get the next root dir cluster and try again until we run out of clusters
121 mov eax,DWORD [RootDirStartCluster]
122 call GetFatEntry
123 mov [RootDirStartCluster],eax
124 jmp Continue1
125
126 FoundFile:
127 xor di,di ; ES:DI has dir entry
128 xor dx,dx
129 mov ax,WORD [es:di+14h] ; Get start cluster high word
130 shl eax,16
131 mov ax,WORD [es:di+1ah] ; Get start cluster low word
132
133 mov bx,800h
134 mov es,bx
135
136 FoundFile2:
137 cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
138 jae FoundFile3 ; If so continue, if not then read then next one
139 push eax
140 xor bx,bx ; Load ROSLDR starting at 0000:8000h
141 push es
142 call ReadCluster
143 pop es
144
145 xor bx,bx
146 mov bl,[SectsPerCluster]
147 shl bx,5 ; BX = BX * 512 / 16
148 mov ax,es ; Increment the load address by
149 add ax,bx ; The size of a cluster
150 mov es,ax
151
152 pop eax
153 push es
154 call GetFatEntry ; Get the next entry
155 pop es
156
157 jmp FoundFile2 ; Load the next cluster (if any)
158
159 FoundFile3:
160 mov dl,[BootDrive]
161 xor ax,ax
162 push ax
163 mov ax,8000h
164 push ax ; We will do a far return to 0000:8000h
165 retf ; Transfer control to ROSLDR
166
167
168
169 ; Reads logical sectors into [ES:BX]
170 ; DX:AX has logical sector number to read
171 ; CX has number of sectors to read
172 ; CarryFlag set on error
173 ReadSectors:
174 push ax
175 push dx
176 push cx
177 xchg ax,cx
178 xchg ax,dx
179 xor dx,dx
180 div WORD [SectorsPerTrack]
181 xchg ax,cx
182 div WORD [SectorsPerTrack] ; Divide logical by SectorsPerTrack
183 inc dx ; Sectors numbering starts at 1 not 0
184 xchg cx,dx
185 div WORD [NumberOfHeads] ; Number of heads
186 mov dh,dl ; Head to DH, drive to DL
187 mov dl,[BootDrive] ; Drive number
188 mov ch,al ; Cylinder in CX
189 ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits
190 ror ah,1 ; in CL shifted to bits 6 & 7
191 or cl,ah ; Or with sector number
192 mov ax,513
193 int 13h ; DISK - READ SECTORS INTO MEMORY
194 ; AL = number of sectors to read, CH = track, CL = sector
195 ; DH = head, DL = drive, ES:BX -> buffer to fill
196 ; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
197 pop cx
198 pop dx
199 pop ax
200 jc ReadFail
201 inc ax ;Increment Sector to Read
202 jnz NoCarry
203 inc dx
204
205
206 NoCarry:
207 push bx
208 mov bx,es
209 add bx,20h
210 mov es,bx
211 pop bx
212 ; Increment read buffer for next sector
213 loop ReadSectors ; Read next sector
214
215
216 ReadFail:
217 ret
218
219
220
221
222 ; Displays a bad boot message
223 ; And reboots
224 BadBoot:
225 mov si,msgDiskError ; Bad boot disk message
226 call PutChars ; Display it
227 mov si,msgAnyKey ; Press any key message
228 call PutChars ; Display it
229
230 jmp Reboot
231
232 ; Displays an error message
233 ; And reboots
234 ErrBoot:
235 mov si,msgFreeLdr ; FreeLdr not found message
236 call PutChars ; Display it
237 mov si,msgAnyKey ; Press any key message
238 call PutChars ; Display it
239
240 Reboot:
241 xor ax,ax
242 int 16h ; Wait for a keypress
243 int 19h ; Reboot
244
245 PutChars:
246 lodsb
247 or al,al
248 jz short Done
249 mov ah,0eh
250 mov bx,07h
251 int 10h
252 jmp short PutChars
253 Done:
254 retn
255
256 msgDiskError db 'Disk error',0dh,0ah,0
257 msgFreeLdr db 'FREELDR.SYS not found',0dh,0ah,0
258 msgAnyKey db 'Press any key to continue.',0dh,0ah,0
259 filename db 'FREELDR SYS'
260
261 times 510-($-$$) db 0 ; Pad to 510 bytes
262 dw 0aa55h ; BootSector signature
263
264
265 ; End of bootsector
266 ;
267 ; Now starts the extra boot code that we will store
268 ; at sector 14 on a FAT32 volume
269 ;
270 ; To remain multi-boot compatible with other operating
271 ; systems we must not overwrite anything other than
272 ; the bootsector which means we will have to use
273 ; a different sector like 14 to store our extra boot code
274 ;
275 ; Note: Win2k uses sector 12 for this purpose
276
277
278 ; Returns the FAT entry for a given cluster number
279 ; On entry EAX has cluster number
280 ; On return EAX has FAT entry for that cluster
281 GetFatEntry:
282
283 shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes)
284 mov ecx,eax ; Save this for later in ECX
285 xor edx,edx
286 movzx ebx,WORD [BytesPerSector]
287 push ebx
288 div ebx ; FAT Sector Number = EAX / BytesPerSector
289 movzx ebx,WORD [ReservedSectors]
290 add eax,ebx ; FAT Sector Number += ReservedSectors
291 movzx ebx,WORD [HiddenSectors]
292 add eax,ebx ; FAT Sector Number += HiddenSectors
293 pop ebx
294 dec ebx
295 and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector
296 ; EAX holds logical FAT sector number
297 ; ECX holds FAT entry offset
298 push ecx
299 ror eax,16
300 mov dx,ax
301 ror eax,16
302 ; DX:AX holds logical FAT sector number
303 mov bx,7000h
304 mov es,bx
305 xor bx,bx ; We will load it to [7000:0000h]
306 mov cx,1
307 call ReadSectors
308 jnc GetFatEntry1
309 jmp BadBoot
310 GetFatEntry1:
311 mov bx,7000h
312 mov es,bx
313 pop ecx
314 mov eax,DWORD [es:ecx] ; Get FAT entry
315 and eax,0fffffffh ; Mask off reserved bits
316
317 ret
318
319
320 ; Reads cluster number in EAX into [ES:0000]
321 ReadCluster:
322 ; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
323
324 dec eax
325 dec eax
326 xor edx,edx
327 movzx ebx,BYTE [SectsPerCluster]
328 mul ebx
329 push eax
330 xor edx,edx
331 movzx eax,BYTE [NumberOfFats]
332 mul DWORD [SectorsPerFatBig]
333 movzx ebx,WORD [ReservedSectors]
334 add eax,ebx
335 add eax,DWORD [HiddenSectors]
336 pop ebx
337 add eax,ebx ; EAX now contains the logical sector number of the cluster
338 ror eax,16
339 mov dx,ax
340 ror eax,16
341 xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
342 movzx cx,BYTE [SectsPerCluster]
343 call ReadSectors
344 jnc ReadCluster1
345 jmp BadBoot
346
347 ReadCluster1:
348 ret
349
350 times 1022-($-$$) db 0 ; Pad to 1022 bytes
351 dw 0aa55h ; BootSector signature