Full memory management support (memory.c & memory.h & mem.S)
[reactos.git] / freeldr / bootsect / fat32.asm
1 ; FAT32.ASM
2 ; FAT32 Boot Sector
3 ; Copyright (c) 1998, 2000, 2001 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 'FrLdr1.0'
16 BytesPerSector dw 512
17 SectsPerCluster db 1
18 ReservedSectors dw 32
19 NumberOfFats db 2
20 MaxRootEntries dw 0 ; Always zero for FAT32 volumes
21 TotalSectors dw 0 ; Always zero for FAT32 volumes
22 MediaDescriptor db 0f8h
23 SectorsPerFat dw 0 ; 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 'NO NAME '
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 cmp word [TotalSectors],byte 0x00 ; Check the old 16-bit value of TotalSectors
60 jnz ErrBoot ; If it is non-zero then exit with an error
61
62 cmp word [FSVersion],byte 0x00 ; Check the file system version word
63 ja ErrBoot ; If it is not zero then exit with an error
64
65
66 ; Reset disk controller
67 int 13h
68 jnc LoadExtraBootCode
69 jmp BadBoot ; Reset failed...
70
71 LoadExtraBootCode:
72 ; First we have to load our extra boot code at
73 ; sector 14 into memory at [0000:7e00h]
74 xor dx,dx
75 mov ax,0eh
76 add ax,WORD [HiddenSectors]
77 adc dx,WORD [HiddenSectors+2] ; Add the number of hidden sectors
78 mov cx,1
79 mov bx,7e0h
80 mov es,bx ; Read sector to [0000:7e00h]
81 xor bx,bx
82 call ReadSectors
83 jmp StartSearch
84
85
86
87
88 ; Reads logical sectors into [ES:BX]
89 ; DX:AX has logical sector number to read
90 ; CX has number of sectors to read
91 ; CarryFlag set on error
92 ReadSectors:
93 push ax
94 push dx
95 push cx
96 xchg ax,cx
97 xchg ax,dx
98 xor dx,dx
99 div WORD [SectorsPerTrack]
100 xchg ax,cx
101 div WORD [SectorsPerTrack] ; Divide logical by SectorsPerTrack
102 inc dx ; Sectors numbering starts at 1 not 0
103 xchg cx,dx
104 div WORD [NumberOfHeads] ; Number of heads
105 mov dh,dl ; Head to DH, drive to DL
106 mov dl,[BootDrive] ; Drive number
107 mov ch,al ; Cylinder in CX
108 ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits
109 ror ah,1 ; in CL shifted to bits 6 & 7
110 or cl,ah ; Or with sector number
111 mov ax,0201h
112 int 13h ; DISK - READ SECTORS INTO MEMORY
113 ; AL = number of sectors to read, CH = track, CL = sector
114 ; DH = head, DL = drive, ES:BX -> buffer to fill
115 ; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
116
117 jc BadBoot
118
119 pop cx
120 pop dx
121 pop ax
122 inc ax ;Increment Sector to Read
123 jnz NoCarry
124 inc dx
125
126
127 NoCarry:
128 push bx
129 mov bx,es
130 add bx,byte 20h
131 mov es,bx
132 pop bx
133 ; Increment read buffer for next sector
134 loop ReadSectors ; Read next sector
135
136 ret
137
138
139
140
141 ; Displays a bad boot message
142 ; And reboots
143 BadBoot:
144 mov si,msgDiskError ; Bad boot disk message
145 call PutChars ; Display it
146 mov si,msgAnyKey ; Press any key message
147 call PutChars ; Display it
148
149 jmp Reboot
150
151 ; Displays an error message
152 ; And reboots
153 ErrBoot:
154 mov si,msgFreeLdr ; FreeLdr not found message
155 call PutChars ; Display it
156 mov si,msgAnyKey ; Press any key message
157 call PutChars ; Display it
158
159 Reboot:
160 xor ax,ax
161 int 16h ; Wait for a keypress
162 int 19h ; Reboot
163
164 PutChars:
165 lodsb
166 or al,al
167 jz short Done
168 mov ah,0eh
169 mov bx,07h
170 int 10h
171 jmp short PutChars
172 Done:
173 retn
174
175 msgDiskError db 'Disk error',0dh,0ah,0
176 msgFreeLdr db 'FREELDR.SYS not found',0dh,0ah,0
177 msgAnyKey db 'Press any key to continue.',0dh,0ah,0
178 filename db 'FREELDR SYS'
179
180 times 510-($-$$) db 0 ; Pad to 510 bytes
181 dw 0aa55h ; BootSector signature
182
183
184 ; End of bootsector
185 ;
186 ; Now starts the extra boot code that we will store
187 ; at sector 14 on a FAT32 volume
188 ;
189 ; To remain multi-boot compatible with other operating
190 ; systems we must not overwrite anything other than
191 ; the bootsector which means we will have to use
192 ; a different sector like 14 to store our extra boot code
193 ;
194 ; Note: Win2k uses sector 12 for this purpose
195
196
197
198 StartSearch:
199 ; Now we must get the first cluster of the root directory
200 mov eax,DWORD [RootDirStartCluster]
201 cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
202 jb ContinueSearch ; If not continue, if so BadBoot
203 jmp ErrBoot
204 ContinueSearch:
205 mov bx,800h
206 mov es,bx ; Read cluster to [0000:8000h]
207 call ReadCluster ; Read the cluster
208
209
210 ; Now we have to find our way through the root directory to
211 ; The OSLOADER.SYS file
212 xor bx,bx
213 mov bl,[SectsPerCluster]
214 shl bx,4 ; BX = BX * 512 / 32
215 mov ax,800h ; We loaded at 0800:0000
216 mov es,ax
217 xor di,di
218 mov si,filename
219 mov cx,11
220 rep cmpsb ; Compare filenames
221 jz FoundFile ; If same we found it
222 dec bx
223 jnz FindFile
224 jmp ErrBoot
225
226 FindFile:
227 mov ax,es ; We didn't find it in the previous dir entry
228 add ax,2 ; So lets move to the next one
229 mov es,ax ; And search again
230 xor di,di
231 mov si,filename
232 mov cx,11
233 rep cmpsb ; Compare filenames
234 jz FoundFile ; If same we found it
235 dec bx ; Keep searching till we run out of dir entries
236 jnz FindFile ; Last entry?
237
238 ; Get the next root dir cluster and try again until we run out of clusters
239 mov eax,DWORD [RootDirStartCluster]
240 call GetFatEntry
241 mov [RootDirStartCluster],eax
242 jmp StartSearch
243
244 FoundFile:
245 ; Display "Loading FreeLoader..." message
246 mov si,msgLoading ; Loading message
247 call PutChars ; Display it
248
249 xor di,di ; ES:DI has dir entry
250 xor dx,dx
251 mov ax,WORD [es:di+14h] ; Get start cluster high word
252 shl eax,16
253 mov ax,WORD [es:di+1ah] ; Get start cluster low word
254
255 mov bx,800h
256 mov es,bx
257
258 FoundFile2:
259 cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
260 jae FoundFile3 ; If so continue, if not then read then next one
261 push eax
262 xor bx,bx ; Load ROSLDR starting at 0000:8000h
263 push es
264 call ReadCluster
265 pop es
266
267 xor bx,bx
268 mov bl,[SectsPerCluster]
269 shl bx,5 ; BX = BX * 512 / 16
270 mov ax,es ; Increment the load address by
271 add ax,bx ; The size of a cluster
272 mov es,ax
273
274 pop eax
275 push es
276 call GetFatEntry ; Get the next entry
277 pop es
278
279 jmp FoundFile2 ; Load the next cluster (if any)
280
281 FoundFile3:
282 mov dl,[BootDrive]
283 xor ax,ax
284 push ax
285 mov ax,8000h
286 push ax ; We will do a far return to 0000:8000h
287 retf ; Transfer control to ROSLDR
288
289
290 ; Returns the FAT entry for a given cluster number
291 ; On entry EAX has cluster number
292 ; On return EAX has FAT entry for that cluster
293 GetFatEntry:
294
295 shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes)
296 mov ecx,eax ; Save this for later in ECX
297 xor edx,edx
298 movzx ebx,WORD [BytesPerSector]
299 push ebx
300 div ebx ; FAT Sector Number = EAX / BytesPerSector
301 movzx ebx,WORD [ReservedSectors]
302 add eax,ebx ; FAT Sector Number += ReservedSectors
303 mov ebx,DWORD [HiddenSectors]
304 add eax,ebx ; FAT Sector Number += HiddenSectors
305 pop ebx
306 dec ebx
307 and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector
308 ; EAX holds logical FAT sector number
309 ; ECX holds FAT entry offset
310
311 ; Now we have to check the extended flags
312 ; to see which FAT is the active one
313 ; and use it, or if they are mirrored then
314 ; no worries
315 movzx ebx,WORD [ExtendedFlags] ; Get extended flags and put into ebx
316 and bx,0x0f ; Mask off upper 8 bits
317 jz GetFatEntry2 ; If fat is mirrored then skip fat calcs
318 cmp bl,[NumberOfFats] ; Compare bl to number of fats
319 jc GetFatEntry1
320 jmp ErrBoot ; If bl is bigger than numfats exit with error
321 GetFatEntry1:
322 mov edx,eax ; Put logical FAT sector number in edx
323 mov eax,[SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax
324 mul ebx ; Multiplied by the active FAT index we have in ebx
325 add eax,edx ; Add the current FAT sector offset
326
327 GetFatEntry2:
328 push ecx
329 ror eax,16
330 mov dx,ax
331 ror eax,16
332 ; DX:AX holds logical FAT sector number
333 mov bx,7000h
334 mov es,bx
335 xor bx,bx ; We will load it to [7000:0000h]
336 mov cx,1
337 call ReadSectors
338 jnc GetFatEntry3
339 jmp BadBoot
340 GetFatEntry3:
341 mov bx,7000h
342 mov es,bx
343 pop ecx
344 mov eax,DWORD [es:ecx] ; Get FAT entry
345 and eax,0fffffffh ; Mask off reserved bits
346
347 ret
348
349
350 ; Reads cluster number in EAX into [ES:0000]
351 ReadCluster:
352 ; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
353
354 dec eax
355 dec eax
356 xor edx,edx
357 movzx ebx,BYTE [SectsPerCluster]
358 mul ebx
359 push eax
360 xor edx,edx
361 movzx eax,BYTE [NumberOfFats]
362 mul DWORD [SectorsPerFatBig]
363 movzx ebx,WORD [ReservedSectors]
364 add eax,ebx
365 add eax,DWORD [HiddenSectors]
366 pop ebx
367 add eax,ebx ; EAX now contains the logical sector number of the cluster
368 ror eax,16
369 mov dx,ax
370 ror eax,16
371 xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
372 movzx cx,BYTE [SectsPerCluster]
373 call ReadSectors
374 ret
375
376 times 998-($-$$) db 0 ; Pad to 998 bytes
377
378 msgLoading db 'Loading FreeLoader...',0dh,0ah,0
379
380 dw 0aa55h ; BootSector signature