Full memory management support (memory.c & memory.h & mem.S)
[reactos.git] / freeldr / bootsect / fat.asm
1 ; FAT.ASM
2 ; FAT12/16 Boot Sector
3 ; Copyright (c) 1998, 2001 Brian Palmer
4
5
6
7 ; This is a FAT12/16 file system boot sector
8 ; that searches the entire root directory
9 ; for the file freeldr.sys and loads it into
10 ; memory.
11 ;
12 ; The stack is set to 0000:7C00 so that the first
13 ; DWORD pushed will be placed at 0000:7BFC
14 ;
15 ; When it locates freeldr.sys on the disk it will
16 ; load the first sector of the file to 0000:7E00
17 ; With the help of this sector we should be able
18 ; to load the entire file off the disk, no matter
19 ; how fragmented it is.
20 ;
21 ; We load the entire FAT table into memory at
22 ; 7000:0000. This improves the speed of floppy disk
23 ; boots dramatically.
24
25
26
27 org 7c00h
28
29 segment .text
30
31 bits 16
32
33 start:
34 jmp short main
35 nop
36
37 OEMName db 'FrLdr1.0'
38 BytesPerSector dw 512
39 SectsPerCluster db 1
40 ReservedSectors dw 1
41 NumberOfFats db 2
42 MaxRootEntries dw 224
43 TotalSectors dw 2880
44 MediaDescriptor db 0f0h
45 SectorsPerFat dw 9
46 SectorsPerTrack dw 18
47 NumberOfHeads dw 2
48 HiddenSectors dd 0
49 TotalSectorsBig dd 0
50 BootDrive db 0
51 Reserved db 0
52 ExtendSig db 29h
53 SerialNumber dd 00000000h
54 VolumeLabel db 'NO NAME '
55 FileSystem db 'FAT12 '
56
57 main:
58 cli
59 cld
60 xor ax,ax
61 mov ss,ax
62 mov bp,7c00h
63 mov sp,bp ; Setup a stack
64 mov ax,cs ; Setup segment registers
65 mov ds,ax ; Make DS correct
66 mov es,ax ; Make ES correct
67
68
69 sti ; Enable ints now
70 mov [BYTE bp+BootDrive],dl ; Save the boot drive
71 xor ax,ax ; Zero out AX
72
73 ; Reset disk controller
74 int 13h
75 jnc Continue1
76 jmp BadBoot ; Reset failed...
77
78 Continue1:
79 ; Now we must find our way to the first sector of the root directory
80 xor ax,ax
81 xor dx,dx
82 mov al,[BYTE bp+NumberOfFats] ; Number of fats
83 mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat
84 add ax,WORD [BYTE bp+HiddenSectors]
85 adc dx,WORD [BYTE bp+HiddenSectors+2] ; Add the number of hidden sectors
86 add ax,WORD [BYTE bp+ReservedSectors] ; Add the number of reserved sectors
87 adc dx,byte 0 ; Add carry bit
88 push ax ; Store it on the stack
89 push dx ; Save 32-bit logical start sector
90 push ax
91 push dx ; Save it for later use also
92 ; DX:AX now has the number of the starting sector of the root directory
93
94 ; Now calculate the size of the root directory
95 mov ax,0020h ; Size of dir entry
96 mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
97 mov bx,[BYTE bp+BytesPerSector]
98 add ax,bx
99 dec ax
100 div bx ; Divided by the size of a sector
101 ; AX now has the number of root directory sectors
102
103 xchg ax,cx ; Now CX has number of sectors
104 pop dx
105 pop ax ; Restore logical sector start
106 push cx ; Save number of root dir sectors for later use
107 mov bx,7c0h ; We will load the root directory
108 add bx,byte 20h ; Right after the boot sector in memory
109 mov es,bx
110 xor bx,bx ; We will load it to [0000:7e00h]
111 call ReadSectors ; Read the sectors
112
113
114 ; Now we have to find our way through the root directory to
115 ; The OSLOADER.SYS file
116 mov bx,[BYTE bp+MaxRootEntries]; Search entire root directory
117 mov ax,7e0h ; We loaded at 07e0:0000
118 mov es,ax
119 xor di,di
120 mov si,filename
121 mov cx,11
122 rep cmpsb ; Compare filenames
123 jz FoundFile ; If same we found it
124 dec bx
125 jnz FindFile
126 jmp ErrBoot
127
128 FindFile:
129 mov ax,es ; We didn't find it in the previous dir entry
130 add ax,byte 2 ; So lets move to the next one
131 mov es,ax ; And search again
132 xor di,di
133 mov si,filename
134 mov cx,11
135 rep cmpsb ; Compare filenames
136 jz FoundFile ; If same we found it
137 dec bx ; Keep searching till we run out of dir entries
138 jnz FindFile ; Last entry?
139 jmp ErrBoot
140
141 FoundFile:
142 ; We found freeldr.sys on the disk
143 ; so we need to load the first 512
144 ; bytes of it to 0000:7E00
145 xor di,di ; ES:DI has dir entry
146 xor dx,dx
147 mov ax,WORD [es:di+1ah]; Get start cluster
148 dec ax ; Adjust start cluster by 2
149 dec ax ; Because the data area starts on cluster 2
150 xor ch,ch
151 mov cl,BYTE [BYTE bp+SectsPerCluster] ; Times sectors per cluster
152 mul cx
153 pop cx ; Get number of sectors for root dir
154 add ax,cx ; Add it to the start sector of freeldr.sys
155 adc dx,byte 0
156 pop cx ; Get logical start sector of
157 pop bx ; Root directory
158 add ax,bx ; Now we have DX:AX with the logical start
159 adc dx,cx ; Sector of OSLOADER.SYS
160 mov cx,1 ; We will load 1 sector
161 push WORD [es:di+1ah] ; Save start cluster
162 mov bx,7e0h
163 mov es,bx
164 xor bx,bx
165 call ReadSectors ; Load it
166 pop ax ; Restore start cluster
167 jmp LoadFile
168
169
170
171 ; Reads logical sectors into [ES:BX]
172 ; DX:AX has logical sector number to read
173 ; CX has number of sectors to read
174 ; CarryFlag set on error
175 ReadSectors:
176 push ax
177 push dx
178 push cx
179 xchg ax,cx
180 xchg ax,dx
181 xor dx,dx
182 div WORD [BYTE bp+SectorsPerTrack]
183 xchg ax,cx
184 div WORD [BYTE bp+SectorsPerTrack] ; Divide logical by SectorsPerTrack
185 inc dx ; Sectors numbering starts at 1 not 0
186 xchg cx,dx
187 div WORD [BYTE bp+NumberOfHeads] ; Number of heads
188 mov dh,dl ; Head to DH, drive to DL
189 mov dl,[BYTE bp+BootDrive] ; Drive number
190 mov ch,al ; Cylinder in CX
191 ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits
192 ror ah,1 ; in CL shifted to bits 6 & 7
193 or cl,ah ; Or with sector number
194 mov ax,0201h
195 int 13h ; DISK - READ SECTORS INTO MEMORY
196 ; AL = number of sectors to read, CH = track, CL = sector
197 ; DH = head, DL = drive, ES:BX -> buffer to fill
198 ; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
199
200 jc BadBoot
201
202 pop cx
203 pop dx
204 pop ax
205 inc ax ;Increment Sector to Read
206 jnz NoCarry
207 inc dx
208
209
210 NoCarry:
211 push bx
212 mov bx,es
213 add bx,byte 20h
214 mov es,bx
215 pop bx
216 ; Increment read buffer for next sector
217 loop ReadSectors ; Read next sector
218
219 ret
220
221
222
223 ; Displays a bad boot message
224 ; And reboots
225 BadBoot:
226 mov si,msgDiskError ; Bad boot disk message
227 call PutChars ; Display it
228 mov si,msgAnyKey ; Press any key message
229 call PutChars ; Display it
230
231 jmp Reboot
232
233 ; Displays an error message
234 ; And reboots
235 ErrBoot:
236 mov si,msgFreeLdr ; FreeLdr not found message
237 call PutChars ; Display it
238 mov si,msgAnyKey ; Press any key message
239 call PutChars ; Display it
240
241 Reboot:
242 xor ax,ax
243 int 16h ; Wait for a keypress
244 int 19h ; Reboot
245
246 PutChars:
247 lodsb
248 or al,al
249 jz short Done
250 mov ah,0eh
251 mov bx,07h
252 int 10h
253 jmp short PutChars
254 Done:
255 retn
256
257 msgDiskError db 'Disk error',0dh,0ah,0
258 msgFreeLdr db 'FREELDR.SYS not found',0dh,0ah,0
259 msgAnyKey db 'Press any key to continue.',0dh,0ah,0
260 filename db 'FREELDR SYS'
261
262 times 510-($-$$) db 0 ; Pad to 510 bytes
263 dw 0aa55h ; BootSector signature
264
265
266
267 ; End of bootsector
268 ;
269 ; Now starts the extra boot code that we will store
270 ; in the first 512 bytes of freeldr.sys
271
272
273
274 LoadFile:
275 ; Display "Loading FreeLoader..." message
276 push ax
277 mov si,msgLoading ; Loading message
278 call PutChars ; Display it
279 pop ax
280
281 ; AX has start cluster of freeldr.sys
282 push ax
283 call ReadFatIntoMemory
284 pop ax
285
286 mov bx,7e0h
287 mov es,bx
288
289 LoadFile2:
290 push ax
291 call IsFat12
292 pop ax
293 jnc LoadFile3
294 cmp ax,0ff8h ; Check to see if this is the last cluster in the chain
295 jmp LoadFile4
296 LoadFile3:
297 cmp ax,0fff8h
298 LoadFile4:
299 jae LoadFile_Done ; If so continue, if not then read then next one
300 push ax
301 xor bx,bx ; Load ROSLDR starting at 0000:8000h
302 push es
303 call ReadCluster
304 pop es
305
306 xor bx,bx
307 mov bl,BYTE [BYTE bp+SectsPerCluster]
308 shl bx,5 ; BX = BX * 512 / 16
309 mov ax,es ; Increment the load address by
310 add ax,bx ; The size of a cluster
311 mov es,ax
312
313 call IsFat12
314 pop ax
315 push es
316 jnc LoadFile5
317 call GetFatEntry12 ; Get the next entry
318 jmp LoadFile6
319 LoadFile5:
320 call GetFatEntry16
321 LoadFile6:
322 pop es
323
324 jmp LoadFile2 ; Load the next cluster (if any)
325
326 LoadFile_Done:
327 mov dl,BYTE [BYTE bp+BootDrive]
328 xor ax,ax
329 push ax
330 mov ax,8000h
331 push ax ; We will do a far return to 0000:8000h
332 retf ; Transfer control to ROSLDR
333
334
335 ; Reads the entire FAT into memory at 7000:0000
336 ReadFatIntoMemory:
337 mov ax,WORD [BYTE bp+HiddenSectors]
338 mov dx,WORD [BYTE bp+HiddenSectors+2]
339 add ax,WORD [BYTE bp+ReservedSectors]
340 adc dx,byte 0
341 mov cx,WORD [BYTE bp+SectorsPerFat]
342 mov bx,7000h
343 mov es,bx
344 xor bx,bx
345 call ReadSectors
346 ret
347
348
349 ; Returns the FAT entry for a given cluster number for 16-bit FAT
350 ; On entry AX has cluster number
351 ; On return AX has FAT entry for that cluster
352 GetFatEntry16:
353
354 xor dx,dx
355 mov cx,2 ; AX = AX * 2 (since FAT16 entries are 2 bytes)
356 mul cx
357 shl dx,0fh
358
359 mov bx,7000h
360 add bx,dx
361 mov es,bx
362 mov bx,ax ; Restore FAT entry offset
363 mov ax,WORD [es:bx] ; Get FAT entry
364
365 ret
366
367
368 ; Returns the FAT entry for a given cluster number for 12-bit FAT
369 ; On entry AX has cluster number
370 ; On return AX has FAT entry for that cluster
371 GetFatEntry12:
372
373 push ax
374 mov cx,ax
375 shr ax,1
376 add ax,cx ; AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits)
377
378 mov bx,7000h
379 mov es,bx
380 mov bx,ax ; Put FAT entry offset into BX
381 mov ax,WORD [es:bx] ; Get FAT entry
382 pop cx ; Get cluster number from stack
383 and cx,1
384 jz UseLow12Bits
385 and ax,0fff0h
386 shr ax,4
387 jmp GetFatEntry12_Done
388
389 UseLow12Bits:
390 and ax,0fffh
391
392 GetFatEntry12_Done:
393
394 ret
395
396
397 ; Reads cluster number in AX into [ES:0000]
398 ReadCluster:
399 ; StartSector = ((Cluster - 2) * SectorsPerCluster) + + ReservedSectors + HiddenSectors;
400
401 dec ax
402 dec ax
403 xor dx,dx
404 movzx bx,BYTE [BYTE bp+SectsPerCluster]
405 mul bx
406 push ax
407 push dx
408 ; Now calculate the size of the root directory
409 mov ax,0020h ; Size of dir entry
410 mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
411 mov bx,WORD [BYTE bp+BytesPerSector]
412 add ax,bx
413 dec ax
414 div bx ; Divided by the size of a sector
415 mov cx,ax
416 ; CX now has the number of root directory sectors
417 xor dx,dx
418 movzx ax,BYTE [BYTE bp+NumberOfFats]
419 mul WORD [BYTE bp+SectorsPerFat]
420 add ax,WORD [BYTE bp+ReservedSectors]
421 adc dx,byte 0
422 add ax,WORD [BYTE bp+HiddenSectors]
423 adc dx,WORD [BYTE bp+HiddenSectors+2]
424 add ax,cx
425 adc dx,byte 0
426 pop cx
427 pop bx
428 add ax,bx
429 adc dx,cx
430 xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
431 movzx cx,BYTE [BYTE bp+SectsPerCluster]
432 call ReadSectors
433 ret
434
435 ; Returns CF = 1 if this is a FAT12 file system
436 ; Otherwise CF = 0 for FAT16
437 IsFat12:
438
439 ; Now calculate the size of the root directory
440 mov ax,0020h ; Size of dir entry
441 mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
442 mov bx,WORD [BYTE bp+BytesPerSector]
443 add ax,bx ; Plus (BytesPerSector - 1)
444 dec ax
445 div bx ; Divided by the size of a sector
446 ; AX now has the number of root directory sectors
447
448 mov bx,ax
449 ; Now we must find our way to the first sector of the root directory
450 xor ax,ax
451 xor dx,dx
452 mov al,BYTE [BYTE bp+NumberOfFats] ; Number of fats
453 mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat
454 add ax,WORD [BYTE bp+HiddenSectors]
455 adc dx,WORD [BYTE bp+HiddenSectors+2] ; Add the number of hidden sectors
456 add ax,[BYTE bp+ReservedSectors] ; Add the number of reserved sectors
457 adc dx,byte 0 ; Add carry bit
458 add ax,bx
459 adc dx,byte 0 ; Add carry bit
460 ; DX:AX now has the number of the starting sector of the data area
461
462 xor cx,cx
463 mov bx,WORD [BYTE bp+TotalSectors]
464 cmp bx,byte 0
465 jnz IsFat12_2
466 mov bx,WORD [BYTE bp+TotalSectorsBig]
467 mov cx,WORD [BYTE bp+TotalSectorsBig+2]
468
469 ; CX:BX now contains the number of sectors on the volume
470 IsFat12_2:
471 sub bx,ax ; Subtract data area start sector
472 sub cx,dx ; from total sectors of volume
473 mov ax,bx
474 mov dx,cx
475
476 ; DX:AX now contains the number of data sectors on the volume
477 movzx bx,BYTE [BYTE bp+SectsPerCluster]
478 div bx
479 ; AX now has the number of clusters on the volume
480 stc
481 cmp ax,4085
482 jb IsFat12_Done
483 clc
484
485 IsFat12_Done:
486 ret
487
488
489
490 times 998-($-$$) db 0 ; Pad to 998 bytes
491
492 msgLoading db 'Loading FreeLoader...',0dh,0ah,0
493
494 dw 0aa55h ; BootSector signature