3 ; Copyright (c) 1998, 2001 Brian Palmer
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
12 ; The stack is set to 0000:7C00 so that the first
13 ; DWORD pushed will be placed at 0000:7BFC
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.
21 ; We load the entire FAT table into memory at
22 ; 7000:0000. This improves the speed of floppy disk
44 MediaDescriptor db 0f0h
53 SerialNumber dd 00000000h
54 VolumeLabel db 'NO NAME '
55 FileSystem db 'FAT12 '
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
70 mov [BYTE bp+BootDrive],dl ; Save the boot drive
71 xor ax,ax ; Zero out AX
73 ; Reset disk controller
76 jmp BadBoot ; Reset failed...
79 ; Now we must find our way to the first sector of the root directory
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
91 push dx ; Save it for later use also
92 ; DX:AX now has the number of the starting sector of the root directory
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]
100 div bx ; Divided by the size of a sector
101 ; AX now has the number of root directory sectors
103 xchg ax,cx ; Now CX has number of sectors
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
110 xor bx,bx ; We will load it to [0000:7e00h]
111 call ReadSectors ; Read the sectors
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
122 rep cmpsb ; Compare filenames
123 jz FoundFile ; If same we found it
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
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?
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
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
151 mov cl,BYTE [BYTE bp+SectsPerCluster] ; Times sectors per cluster
153 pop cx ; Get number of sectors for root dir
154 add ax,cx ; Add it to the start sector of freeldr.sys
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
165 call ReadSectors ; Load it
166 pop ax ; Restore start cluster
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
182 div WORD [BYTE bp+SectorsPerTrack]
184 div WORD [BYTE bp+SectorsPerTrack] ; Divide logical by SectorsPerTrack
185 inc dx ; Sectors numbering starts at 1 not 0
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
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
205 inc ax ;Increment Sector to Read
216 ; Increment read buffer for next sector
217 loop ReadSectors ; Read next sector
223 ; Displays a bad boot message
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
233 ; Displays an error message
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
243 int 16h ; Wait for a keypress
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 restart',0dh,0ah,0
260 filename db 'FREELDR SYS'
262 times 510-($-$$) db 0 ; Pad to 510 bytes
263 dw 0aa55h ; BootSector signature
269 ; Now starts the extra boot code that we will store
270 ; in the first 512 bytes of freeldr.sys
276 push ax ; First save AX - the start cluster of freeldr.sys
279 ; Lets save the contents of the screen
280 ; from B800:0000 to 9000:8000
288 mov cx,2000 ; Copy 2000 characters [words] (screen is 80x25)
289 rep movsw ; 2 bytes a character (one is the attribute byte)
292 mov ah,03h ; AH = 03h
293 xor bx,bx ; BH = video page
294 int 10h ; BIOS Int 10h Func 3 - Read Cursor Position and Size
295 mov [es:di],dx ; DH = row, DL = column
297 ; Display "Loading FreeLoader..." message
298 mov si,msgLoading ; Loading message
299 call PutChars ; Display it
304 ; AX has start cluster of freeldr.sys
306 call ReadFatIntoMemory
317 cmp ax,0ff8h ; Check to see if this is the last cluster in the chain
322 jae LoadFile_Done ; If so continue, if not then read then next one
324 xor bx,bx ; Load ROSLDR starting at 0000:8000h
330 mov bl,BYTE [BYTE bp+SectsPerCluster]
331 shl bx,5 ; BX = BX * 512 / 16
332 mov ax,es ; Increment the load address by
333 add ax,bx ; The size of a cluster
340 call GetFatEntry12 ; Get the next entry
347 jmp LoadFile2 ; Load the next cluster (if any)
350 mov dl,BYTE [BYTE bp+BootDrive]
354 push ax ; We will do a far return to 0000:8000h
355 retf ; Transfer control to ROSLDR
358 ; Reads the entire FAT into memory at 7000:0000
360 mov ax,WORD [BYTE bp+HiddenSectors]
361 mov dx,WORD [BYTE bp+HiddenSectors+2]
362 add ax,WORD [BYTE bp+ReservedSectors]
364 mov cx,WORD [BYTE bp+SectorsPerFat]
372 ; Returns the FAT entry for a given cluster number for 16-bit FAT
373 ; On entry AX has cluster number
374 ; On return AX has FAT entry for that cluster
378 mov cx,2 ; AX = AX * 2 (since FAT16 entries are 2 bytes)
385 mov bx,ax ; Restore FAT entry offset
386 mov ax,WORD [es:bx] ; Get FAT entry
391 ; Returns the FAT entry for a given cluster number for 12-bit FAT
392 ; On entry AX has cluster number
393 ; On return AX has FAT entry for that cluster
399 add ax,cx ; AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits)
403 mov bx,ax ; Put FAT entry offset into BX
404 mov ax,WORD [es:bx] ; Get FAT entry
405 pop cx ; Get cluster number from stack
410 jmp GetFatEntry12_Done
420 ; Reads cluster number in AX into [ES:0000]
422 ; StartSector = ((Cluster - 2) * SectorsPerCluster) + + ReservedSectors + HiddenSectors;
427 movzx bx,BYTE [BYTE bp+SectsPerCluster]
431 ; Now calculate the size of the root directory
432 mov ax,0020h ; Size of dir entry
433 mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
434 mov bx,WORD [BYTE bp+BytesPerSector]
437 div bx ; Divided by the size of a sector
439 ; CX now has the number of root directory sectors
441 movzx ax,BYTE [BYTE bp+NumberOfFats]
442 mul WORD [BYTE bp+SectorsPerFat]
443 add ax,WORD [BYTE bp+ReservedSectors]
445 add ax,WORD [BYTE bp+HiddenSectors]
446 adc dx,WORD [BYTE bp+HiddenSectors+2]
453 xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
454 movzx cx,BYTE [BYTE bp+SectsPerCluster]
458 ; Returns CF = 1 if this is a FAT12 file system
459 ; Otherwise CF = 0 for FAT16
462 ; Now calculate the size of the root directory
463 mov ax,0020h ; Size of dir entry
464 mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
465 mov bx,WORD [BYTE bp+BytesPerSector]
466 add ax,bx ; Plus (BytesPerSector - 1)
468 div bx ; Divided by the size of a sector
469 ; AX now has the number of root directory sectors
472 ; Now we must find our way to the first sector of the root directory
475 mov al,BYTE [BYTE bp+NumberOfFats] ; Number of fats
476 mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat
477 add ax,WORD [BYTE bp+HiddenSectors]
478 adc dx,WORD [BYTE bp+HiddenSectors+2] ; Add the number of hidden sectors
479 add ax,[BYTE bp+ReservedSectors] ; Add the number of reserved sectors
480 adc dx,byte 0 ; Add carry bit
482 adc dx,byte 0 ; Add carry bit
483 ; DX:AX now has the number of the starting sector of the data area
486 mov bx,WORD [BYTE bp+TotalSectors]
489 mov bx,WORD [BYTE bp+TotalSectorsBig]
490 mov cx,WORD [BYTE bp+TotalSectorsBig+2]
492 ; CX:BX now contains the number of sectors on the volume
494 sub bx,ax ; Subtract data area start sector
495 sub cx,dx ; from total sectors of volume
499 ; DX:AX now contains the number of data sectors on the volume
500 movzx bx,BYTE [BYTE bp+SectsPerCluster]
502 ; AX now has the number of clusters on the volume
513 times 998-($-$$) db 0 ; Pad to 998 bytes
515 msgLoading db 'Loading FreeLoader...',0dh,0ah,0
517 dw 0aa55h ; BootSector signature