mirror of
https://github.com/reactos/reactos.git
synced 2024-11-03 21:34:00 +00:00
495 lines
14 KiB
NASM
495 lines
14 KiB
NASM
|
; FAT.ASM
|
||
|
; FAT12/16 Boot Sector
|
||
|
; Copyright (c) 1998, 2001 Brian Palmer
|
||
|
|
||
|
|
||
|
|
||
|
; This is a FAT12/16 file system boot sector
|
||
|
; that searches the entire root directory
|
||
|
; for the file freeldr.sys and loads it into
|
||
|
; memory.
|
||
|
;
|
||
|
; The stack is set to 0000:7C00 so that the first
|
||
|
; DWORD pushed will be placed at 0000:7BFC
|
||
|
;
|
||
|
; When it locates freeldr.sys on the disk it will
|
||
|
; load the first sector of the file to 0000:7E00
|
||
|
; With the help of this sector we should be able
|
||
|
; to load the entire file off the disk, no matter
|
||
|
; how fragmented it is.
|
||
|
;
|
||
|
; We load the entire FAT table into memory at
|
||
|
; 7000:0000. This improves the speed of floppy disk
|
||
|
; boots dramatically.
|
||
|
|
||
|
|
||
|
|
||
|
org 7c00h
|
||
|
|
||
|
segment .text
|
||
|
|
||
|
bits 16
|
||
|
|
||
|
start:
|
||
|
jmp short main
|
||
|
nop
|
||
|
|
||
|
OEMName db 'FrLdr1.0'
|
||
|
BytesPerSector dw 512
|
||
|
SectsPerCluster db 1
|
||
|
ReservedSectors dw 1
|
||
|
NumberOfFats db 2
|
||
|
MaxRootEntries dw 224
|
||
|
TotalSectors dw 2880
|
||
|
MediaDescriptor db 0f0h
|
||
|
SectorsPerFat dw 9
|
||
|
SectorsPerTrack dw 18
|
||
|
NumberOfHeads dw 2
|
||
|
HiddenSectors dd 0
|
||
|
TotalSectorsBig dd 0
|
||
|
BootDrive db 0
|
||
|
Reserved db 0
|
||
|
ExtendSig db 29h
|
||
|
SerialNumber dd 00000000h
|
||
|
VolumeLabel db 'NO NAME '
|
||
|
FileSystem db 'FAT12 '
|
||
|
|
||
|
main:
|
||
|
cli
|
||
|
cld
|
||
|
xor ax,ax
|
||
|
mov ss,ax
|
||
|
mov bp,7c00h
|
||
|
mov sp,bp ; Setup a stack
|
||
|
mov ax,cs ; Setup segment registers
|
||
|
mov ds,ax ; Make DS correct
|
||
|
mov es,ax ; Make ES correct
|
||
|
|
||
|
|
||
|
sti ; Enable ints now
|
||
|
mov [BYTE bp+BootDrive],dl ; Save the boot drive
|
||
|
xor ax,ax ; Zero out AX
|
||
|
|
||
|
; Reset disk controller
|
||
|
int 13h
|
||
|
jnc Continue1
|
||
|
jmp BadBoot ; Reset failed...
|
||
|
|
||
|
Continue1:
|
||
|
; Now we must find our way to the first sector of the root directory
|
||
|
xor ax,ax
|
||
|
xor dx,dx
|
||
|
mov al,[BYTE bp+NumberOfFats] ; Number of fats
|
||
|
mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat
|
||
|
add ax,WORD [BYTE bp+HiddenSectors]
|
||
|
adc dx,WORD [BYTE bp+HiddenSectors+2] ; Add the number of hidden sectors
|
||
|
add ax,WORD [BYTE bp+ReservedSectors] ; Add the number of reserved sectors
|
||
|
adc dx,byte 0 ; Add carry bit
|
||
|
push ax ; Store it on the stack
|
||
|
push dx ; Save 32-bit logical start sector
|
||
|
push ax
|
||
|
push dx ; Save it for later use also
|
||
|
; DX:AX now has the number of the starting sector of the root directory
|
||
|
|
||
|
; Now calculate the size of the root directory
|
||
|
mov ax,0020h ; Size of dir entry
|
||
|
mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
|
||
|
mov bx,[BYTE bp+BytesPerSector]
|
||
|
add ax,bx
|
||
|
dec ax
|
||
|
div bx ; Divided by the size of a sector
|
||
|
; AX now has the number of root directory sectors
|
||
|
|
||
|
xchg ax,cx ; Now CX has number of sectors
|
||
|
pop dx
|
||
|
pop ax ; Restore logical sector start
|
||
|
push cx ; Save number of root dir sectors for later use
|
||
|
mov bx,7c0h ; We will load the root directory
|
||
|
add bx,byte 20h ; Right after the boot sector in memory
|
||
|
mov es,bx
|
||
|
xor bx,bx ; We will load it to [0000:7e00h]
|
||
|
call ReadSectors ; Read the sectors
|
||
|
|
||
|
|
||
|
; Now we have to find our way through the root directory to
|
||
|
; The OSLOADER.SYS file
|
||
|
mov bx,[BYTE bp+MaxRootEntries]; Search entire root directory
|
||
|
mov ax,7e0h ; We loaded at 07e0:0000
|
||
|
mov es,ax
|
||
|
xor di,di
|
||
|
mov si,filename
|
||
|
mov cx,11
|
||
|
rep cmpsb ; Compare filenames
|
||
|
jz FoundFile ; If same we found it
|
||
|
dec bx
|
||
|
jnz FindFile
|
||
|
jmp ErrBoot
|
||
|
|
||
|
FindFile:
|
||
|
mov ax,es ; We didn't find it in the previous dir entry
|
||
|
add ax,byte 2 ; So lets move to the next one
|
||
|
mov es,ax ; And search again
|
||
|
xor di,di
|
||
|
mov si,filename
|
||
|
mov cx,11
|
||
|
rep cmpsb ; Compare filenames
|
||
|
jz FoundFile ; If same we found it
|
||
|
dec bx ; Keep searching till we run out of dir entries
|
||
|
jnz FindFile ; Last entry?
|
||
|
jmp ErrBoot
|
||
|
|
||
|
FoundFile:
|
||
|
; We found freeldr.sys on the disk
|
||
|
; so we need to load the first 512
|
||
|
; bytes of it to 0000:7E00
|
||
|
xor di,di ; ES:DI has dir entry
|
||
|
xor dx,dx
|
||
|
mov ax,WORD [es:di+1ah]; Get start cluster
|
||
|
dec ax ; Adjust start cluster by 2
|
||
|
dec ax ; Because the data area starts on cluster 2
|
||
|
xor ch,ch
|
||
|
mov cl,BYTE [BYTE bp+SectsPerCluster] ; Times sectors per cluster
|
||
|
mul cx
|
||
|
pop cx ; Get number of sectors for root dir
|
||
|
add ax,cx ; Add it to the start sector of freeldr.sys
|
||
|
adc dx,byte 0
|
||
|
pop cx ; Get logical start sector of
|
||
|
pop bx ; Root directory
|
||
|
add ax,bx ; Now we have DX:AX with the logical start
|
||
|
adc dx,cx ; Sector of OSLOADER.SYS
|
||
|
mov cx,1 ; We will load 1 sector
|
||
|
push WORD [es:di+1ah] ; Save start cluster
|
||
|
mov bx,7e0h
|
||
|
mov es,bx
|
||
|
xor bx,bx
|
||
|
call ReadSectors ; Load it
|
||
|
pop ax ; Restore start cluster
|
||
|
jmp LoadFile
|
||
|
|
||
|
|
||
|
|
||
|
; Reads logical sectors into [ES:BX]
|
||
|
; DX:AX has logical sector number to read
|
||
|
; CX has number of sectors to read
|
||
|
; CarryFlag set on error
|
||
|
ReadSectors:
|
||
|
push ax
|
||
|
push dx
|
||
|
push cx
|
||
|
xchg ax,cx
|
||
|
xchg ax,dx
|
||
|
xor dx,dx
|
||
|
div WORD [BYTE bp+SectorsPerTrack]
|
||
|
xchg ax,cx
|
||
|
div WORD [BYTE bp+SectorsPerTrack] ; Divide logical by SectorsPerTrack
|
||
|
inc dx ; Sectors numbering starts at 1 not 0
|
||
|
xchg cx,dx
|
||
|
div WORD [BYTE bp+NumberOfHeads] ; Number of heads
|
||
|
mov dh,dl ; Head to DH, drive to DL
|
||
|
mov dl,[BYTE bp+BootDrive] ; Drive number
|
||
|
mov ch,al ; Cylinder in CX
|
||
|
ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits
|
||
|
ror ah,1 ; in CL shifted to bits 6 & 7
|
||
|
or cl,ah ; Or with sector number
|
||
|
mov ax,0201h
|
||
|
int 13h ; DISK - READ SECTORS INTO MEMORY
|
||
|
; AL = number of sectors to read, CH = track, CL = sector
|
||
|
; DH = head, DL = drive, ES:BX -> buffer to fill
|
||
|
; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
|
||
|
|
||
|
jc BadBoot
|
||
|
|
||
|
pop cx
|
||
|
pop dx
|
||
|
pop ax
|
||
|
inc ax ;Increment Sector to Read
|
||
|
jnz NoCarry
|
||
|
inc dx
|
||
|
|
||
|
|
||
|
NoCarry:
|
||
|
push bx
|
||
|
mov bx,es
|
||
|
add bx,byte 20h
|
||
|
mov es,bx
|
||
|
pop bx
|
||
|
; Increment read buffer for next sector
|
||
|
loop ReadSectors ; Read next sector
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
|
||
|
; Displays a bad boot message
|
||
|
; And reboots
|
||
|
BadBoot:
|
||
|
mov si,msgDiskError ; Bad boot disk message
|
||
|
call PutChars ; Display it
|
||
|
mov si,msgAnyKey ; Press any key message
|
||
|
call PutChars ; Display it
|
||
|
|
||
|
jmp Reboot
|
||
|
|
||
|
; Displays an error message
|
||
|
; And reboots
|
||
|
ErrBoot:
|
||
|
mov si,msgFreeLdr ; FreeLdr not found message
|
||
|
call PutChars ; Display it
|
||
|
mov si,msgAnyKey ; Press any key message
|
||
|
call PutChars ; Display it
|
||
|
|
||
|
Reboot:
|
||
|
xor ax,ax
|
||
|
int 16h ; Wait for a keypress
|
||
|
int 19h ; Reboot
|
||
|
|
||
|
PutChars:
|
||
|
lodsb
|
||
|
or al,al
|
||
|
jz short Done
|
||
|
mov ah,0eh
|
||
|
mov bx,07h
|
||
|
int 10h
|
||
|
jmp short PutChars
|
||
|
Done:
|
||
|
retn
|
||
|
|
||
|
msgDiskError db 'Disk error',0dh,0ah,0
|
||
|
msgFreeLdr db 'FREELDR.SYS not found',0dh,0ah,0
|
||
|
msgAnyKey db 'Press any key to continue.',0dh,0ah,0
|
||
|
filename db 'FREELDR SYS'
|
||
|
|
||
|
times 510-($-$$) db 0 ; Pad to 510 bytes
|
||
|
dw 0aa55h ; BootSector signature
|
||
|
|
||
|
|
||
|
|
||
|
; End of bootsector
|
||
|
;
|
||
|
; Now starts the extra boot code that we will store
|
||
|
; in the first 512 bytes of freeldr.sys
|
||
|
|
||
|
|
||
|
|
||
|
LoadFile:
|
||
|
; Display "Loading FreeLoader..." message
|
||
|
push ax
|
||
|
mov si,msgLoading ; Loading message
|
||
|
call PutChars ; Display it
|
||
|
pop ax
|
||
|
|
||
|
; AX has start cluster of freeldr.sys
|
||
|
push ax
|
||
|
call ReadFatIntoMemory
|
||
|
pop ax
|
||
|
|
||
|
mov bx,7e0h
|
||
|
mov es,bx
|
||
|
|
||
|
LoadFile2:
|
||
|
push ax
|
||
|
call IsFat12
|
||
|
pop ax
|
||
|
jnc LoadFile3
|
||
|
cmp ax,0ff8h ; Check to see if this is the last cluster in the chain
|
||
|
jmp LoadFile4
|
||
|
LoadFile3:
|
||
|
cmp ax,0fff8h
|
||
|
LoadFile4:
|
||
|
jae LoadFile_Done ; If so continue, if not then read then next one
|
||
|
push ax
|
||
|
xor bx,bx ; Load ROSLDR starting at 0000:8000h
|
||
|
push es
|
||
|
call ReadCluster
|
||
|
pop es
|
||
|
|
||
|
xor bx,bx
|
||
|
mov bl,BYTE [BYTE bp+SectsPerCluster]
|
||
|
shl bx,5 ; BX = BX * 512 / 16
|
||
|
mov ax,es ; Increment the load address by
|
||
|
add ax,bx ; The size of a cluster
|
||
|
mov es,ax
|
||
|
|
||
|
call IsFat12
|
||
|
pop ax
|
||
|
push es
|
||
|
jnc LoadFile5
|
||
|
call GetFatEntry12 ; Get the next entry
|
||
|
jmp LoadFile6
|
||
|
LoadFile5:
|
||
|
call GetFatEntry16
|
||
|
LoadFile6:
|
||
|
pop es
|
||
|
|
||
|
jmp LoadFile2 ; Load the next cluster (if any)
|
||
|
|
||
|
LoadFile_Done:
|
||
|
mov dl,BYTE [BYTE bp+BootDrive]
|
||
|
xor ax,ax
|
||
|
push ax
|
||
|
mov ax,8000h
|
||
|
push ax ; We will do a far return to 0000:8000h
|
||
|
retf ; Transfer control to ROSLDR
|
||
|
|
||
|
|
||
|
; Reads the entire FAT into memory at 7000:0000
|
||
|
ReadFatIntoMemory:
|
||
|
mov ax,WORD [BYTE bp+HiddenSectors]
|
||
|
mov dx,WORD [BYTE bp+HiddenSectors+2]
|
||
|
add ax,WORD [BYTE bp+ReservedSectors]
|
||
|
adc dx,byte 0
|
||
|
mov cx,WORD [BYTE bp+SectorsPerFat]
|
||
|
mov bx,7000h
|
||
|
mov es,bx
|
||
|
xor bx,bx
|
||
|
call ReadSectors
|
||
|
ret
|
||
|
|
||
|
|
||
|
; Returns the FAT entry for a given cluster number for 16-bit FAT
|
||
|
; On entry AX has cluster number
|
||
|
; On return AX has FAT entry for that cluster
|
||
|
GetFatEntry16:
|
||
|
|
||
|
xor dx,dx
|
||
|
mov cx,2 ; AX = AX * 2 (since FAT16 entries are 2 bytes)
|
||
|
mul cx
|
||
|
shl dx,0fh
|
||
|
|
||
|
mov bx,7000h
|
||
|
add bx,dx
|
||
|
mov es,bx
|
||
|
mov bx,ax ; Restore FAT entry offset
|
||
|
mov ax,WORD [es:bx] ; Get FAT entry
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
; Returns the FAT entry for a given cluster number for 12-bit FAT
|
||
|
; On entry AX has cluster number
|
||
|
; On return AX has FAT entry for that cluster
|
||
|
GetFatEntry12:
|
||
|
|
||
|
push ax
|
||
|
mov cx,ax
|
||
|
shr ax,1
|
||
|
add ax,cx ; AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits)
|
||
|
|
||
|
mov bx,7000h
|
||
|
mov es,bx
|
||
|
mov bx,ax ; Put FAT entry offset into BX
|
||
|
mov ax,WORD [es:bx] ; Get FAT entry
|
||
|
pop cx ; Get cluster number from stack
|
||
|
and cx,1
|
||
|
jz UseLow12Bits
|
||
|
and ax,0fff0h
|
||
|
shr ax,4
|
||
|
jmp GetFatEntry12_Done
|
||
|
|
||
|
UseLow12Bits:
|
||
|
and ax,0fffh
|
||
|
|
||
|
GetFatEntry12_Done:
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
; Reads cluster number in AX into [ES:0000]
|
||
|
ReadCluster:
|
||
|
; StartSector = ((Cluster - 2) * SectorsPerCluster) + + ReservedSectors + HiddenSectors;
|
||
|
|
||
|
dec ax
|
||
|
dec ax
|
||
|
xor dx,dx
|
||
|
movzx bx,BYTE [BYTE bp+SectsPerCluster]
|
||
|
mul bx
|
||
|
push ax
|
||
|
push dx
|
||
|
; Now calculate the size of the root directory
|
||
|
mov ax,0020h ; Size of dir entry
|
||
|
mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
|
||
|
mov bx,WORD [BYTE bp+BytesPerSector]
|
||
|
add ax,bx
|
||
|
dec ax
|
||
|
div bx ; Divided by the size of a sector
|
||
|
mov cx,ax
|
||
|
; CX now has the number of root directory sectors
|
||
|
xor dx,dx
|
||
|
movzx ax,BYTE [BYTE bp+NumberOfFats]
|
||
|
mul WORD [BYTE bp+SectorsPerFat]
|
||
|
add ax,WORD [BYTE bp+ReservedSectors]
|
||
|
adc dx,byte 0
|
||
|
add ax,WORD [BYTE bp+HiddenSectors]
|
||
|
adc dx,WORD [BYTE bp+HiddenSectors+2]
|
||
|
add ax,cx
|
||
|
adc dx,byte 0
|
||
|
pop cx
|
||
|
pop bx
|
||
|
add ax,bx
|
||
|
adc dx,cx
|
||
|
xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
|
||
|
movzx cx,BYTE [BYTE bp+SectsPerCluster]
|
||
|
call ReadSectors
|
||
|
ret
|
||
|
|
||
|
; Returns CF = 1 if this is a FAT12 file system
|
||
|
; Otherwise CF = 0 for FAT16
|
||
|
IsFat12:
|
||
|
|
||
|
; Now calculate the size of the root directory
|
||
|
mov ax,0020h ; Size of dir entry
|
||
|
mul WORD [BYTE bp+MaxRootEntries] ; Times the number of entries
|
||
|
mov bx,WORD [BYTE bp+BytesPerSector]
|
||
|
add ax,bx ; Plus (BytesPerSector - 1)
|
||
|
dec ax
|
||
|
div bx ; Divided by the size of a sector
|
||
|
; AX now has the number of root directory sectors
|
||
|
|
||
|
mov bx,ax
|
||
|
; Now we must find our way to the first sector of the root directory
|
||
|
xor ax,ax
|
||
|
xor dx,dx
|
||
|
mov al,BYTE [BYTE bp+NumberOfFats] ; Number of fats
|
||
|
mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat
|
||
|
add ax,WORD [BYTE bp+HiddenSectors]
|
||
|
adc dx,WORD [BYTE bp+HiddenSectors+2] ; Add the number of hidden sectors
|
||
|
add ax,[BYTE bp+ReservedSectors] ; Add the number of reserved sectors
|
||
|
adc dx,byte 0 ; Add carry bit
|
||
|
add ax,bx
|
||
|
adc dx,byte 0 ; Add carry bit
|
||
|
; DX:AX now has the number of the starting sector of the data area
|
||
|
|
||
|
xor cx,cx
|
||
|
mov bx,WORD [BYTE bp+TotalSectors]
|
||
|
cmp bx,byte 0
|
||
|
jnz IsFat12_2
|
||
|
mov bx,WORD [BYTE bp+TotalSectorsBig]
|
||
|
mov cx,WORD [BYTE bp+TotalSectorsBig+2]
|
||
|
|
||
|
; CX:BX now contains the number of sectors on the volume
|
||
|
IsFat12_2:
|
||
|
sub bx,ax ; Subtract data area start sector
|
||
|
sub cx,dx ; from total sectors of volume
|
||
|
mov ax,bx
|
||
|
mov dx,cx
|
||
|
|
||
|
; DX:AX now contains the number of data sectors on the volume
|
||
|
movzx bx,BYTE [BYTE bp+SectsPerCluster]
|
||
|
div bx
|
||
|
; AX now has the number of clusters on the volume
|
||
|
stc
|
||
|
cmp ax,4085
|
||
|
jb IsFat12_Done
|
||
|
clc
|
||
|
|
||
|
IsFat12_Done:
|
||
|
ret
|
||
|
|
||
|
|
||
|
|
||
|
times 998-($-$$) db 0 ; Pad to 998 bytes
|
||
|
|
||
|
msgLoading db 'Loading FreeLoader...',0dh,0ah,0
|
||
|
|
||
|
dw 0aa55h ; BootSector signature
|