[FATxxx BOOTSECTORS]: Whitespace changes mainly (makes easier for diffing). No code changes.

svn path=/trunk/; revision=70428
This commit is contained in:
Hermès Bélusca-Maïto 2015-12-26 20:13:27 +00:00
parent 909f7439d0
commit 6a513178c3
5 changed files with 703 additions and 702 deletions

View file

@ -43,15 +43,15 @@
#define BP_REL(x) [bp+x-offset start] #define BP_REL(x) [bp+x-offset start]
DataAreaStartHigh = 2 DataAreaStartHigh = 2
DataAreaStartLow = 4 DataAreaStartLow = 4
BiosCHSDriveSizeHigh = 6 BiosCHSDriveSizeHigh = 6
BiosCHSDriveSizeLow = 8 BiosCHSDriveSizeLow = 8
BiosCHSDriveSize = 8 BiosCHSDriveSize = 8
ReadSectorsOffset = 10 ReadSectorsOffset = 10
ReadClusterOffset = 12 ReadClusterOffset = 12
PutCharsOffset = 14 PutCharsOffset = 14
BootSectorStackTop = HEX(7c00) - 16 BootSectorStackTop = HEX(7c00) - 16
// org 7c00h // org 7c00h
@ -105,21 +105,21 @@ main:
xor ax, ax xor ax, ax
mov ss, ax mov ss, ax
mov bp, HEX(7c00) mov bp, HEX(7c00)
mov sp, BootSectorStackTop // Setup a stack mov sp, BootSectorStackTop // Setup a stack
mov ds, ax // Make DS correct mov ds, ax // Make DS correct
mov es, ax // Make ES correct mov es, ax // Make ES correct
cmp byte ptr BP_REL(BootDrive), HEX(0ff) // If they have specified a boot drive then use it cmp byte ptr BP_REL(BootDrive), HEX(0ff) // If they have specified a boot drive then use it
jne GetDriveParameters jne GetDriveParameters
mov byte ptr BP_REL(BootDrive), dl // Save the boot drive mov byte ptr BP_REL(BootDrive), dl // Save the boot drive
GetDriveParameters: GetDriveParameters:
mov ah, 8 mov ah, 8
mov dl, byte ptr BP_REL(BootDrive) // Get boot drive in dl mov dl, byte ptr BP_REL(BootDrive) // Get boot drive in dl
int HEX(13) // Request drive parameters from the bios int HEX(13) // Request drive parameters from the bios
jnc CalcDriveSize // If the call succeeded then calculate the drive size jnc CalcDriveSize // If the call succeeded then calculate the drive size
// If we get here then the call to the BIOS failed // If we get here then the call to the BIOS failed
// so just set CHS equal to the maximum addressable // so just set CHS equal to the maximum addressable
@ -151,26 +151,26 @@ CalcDriveSize:
// Now we must find our way to the first sector of the root directory // Now we must find our way to the first sector of the root directory
xor ax, ax xor ax, ax
xor cx, cx xor cx, cx
mov al, byte ptr BP_REL(NumberOfFats) // Number of fats mov al, byte ptr BP_REL(NumberOfFats) // Number of fats
mul word ptr BP_REL(SectorsPerFat) // Times sectors per fat mul word ptr BP_REL(SectorsPerFat) // Times sectors per fat
add ax, word ptr BP_REL(HiddenSectors) add ax, word ptr BP_REL(HiddenSectors)
adc dx, word ptr BP_REL(HiddenSectors+2) // Add the number of hidden sectors adc dx, word ptr BP_REL(HiddenSectors+2) // Add the number of hidden sectors
add ax, word ptr BP_REL(ReservedSectors) // Add the number of reserved sectors add ax, word ptr BP_REL(ReservedSectors) // Add the number of reserved sectors
adc dx, cx // Add carry bit adc dx, cx // Add carry bit
mov word ptr [bp - DataAreaStartLow], ax // Save the starting sector of the root directory mov word ptr [bp - DataAreaStartLow], ax // Save the starting sector of the root directory
mov word ptr [bp - DataAreaStartHigh], dx // Save it in the first 4 bytes before the boot sector mov word ptr [bp - DataAreaStartHigh], dx // Save it in the first 4 bytes before the boot sector
mov si, word ptr BP_REL(MaxRootEntries) // Get number of root dir entries in SI mov si, word ptr BP_REL(MaxRootEntries) // Get number of root dir entries in SI
pusha // Save 32-bit logical start sector of root dir pusha // Save 32-bit logical start sector of root dir
// DX:AX now has the number of the starting sector of the root directory // DX:AX now has the number of the starting sector of the root directory
// Now calculate the size of the root directory // Now calculate the size of the root directory
xor dx, dx xor dx, dx
mov ax, 32 // Size of dir entry mov ax, 32 // Size of dir entry
mul si // Times the number of entries mul si // Times the number of entries
mov bx, word ptr BP_REL(BytesPerSector) mov bx, word ptr BP_REL(BytesPerSector)
add ax, bx add ax, bx
dec ax dec ax
div bx // Divided by the size of a sector div bx // Divided by the size of a sector
// AX now has the number of root directory sectors // AX now has the number of root directory sectors
add word ptr [bp - DataAreaStartLow], ax // Add the number of sectors of the root directory to our other value add word ptr [bp - DataAreaStartLow], ax // Add the number of sectors of the root directory to our other value
@ -178,49 +178,49 @@ CalcDriveSize:
popa // Restore root dir logical sector start to DX:AX popa // Restore root dir logical sector start to DX:AX
LoadRootDirSector: LoadRootDirSector:
mov bx, HEX(7e0) // We will load the root directory sector mov bx, HEX(7e0) // We will load the root directory sector
mov es, bx // Right after the boot sector in memory mov es, bx // Right after the boot sector in memory
xor bx, bx // We will load it to [0000:7e00h] xor bx, bx // We will load it to [0000:7e00h]
xor cx, cx // Zero out CX xor cx, cx // Zero out CX
inc cx // Now increment it to 1, we are reading one sector inc cx // Now increment it to 1, we are reading one sector
xor di, di // Zero out di xor di, di // Zero out di
push es // Save ES because it will get incremented by 20h push es // Save ES because it will get incremented by 20h
call ReadSectors // Read the first sector of the root directory call ReadSectors // Read the first sector of the root directory
pop es // Restore ES (ES:DI = 07E0:0000) pop es // Restore ES (ES:DI = 07E0:0000)
SearchRootDirSector: SearchRootDirSector:
cmp byte ptr es:[di], ch // If the first byte of the directory entry is zero then we have cmp byte ptr es:[di], ch // If the first byte of the directory entry is zero then we have
jz ErrBoot // reached the end of the directory and FREELDR.SYS is not here so reboot jz ErrBoot // reached the end of the directory and FREELDR.SYS is not here so reboot
pusha // Save all registers pusha // Save all registers
mov cl, 11 // Put 11 in cl (length of filename in directory entry) mov cl, 11 // Put 11 in cl (length of filename in directory entry)
mov si, offset filename // Put offset of filename string in DS:SI mov si, offset filename // Put offset of filename string in DS:SI
repe cmpsb // Compare this directory entry against 'FREELDR SYS' repe cmpsb // Compare this directory entry against 'FREELDR SYS'
popa // Restore all the registers popa // Restore all the registers
jz FoundFreeLoader // If we found it then jump jz FoundFreeLoader // If we found it then jump
dec si // SI holds MaxRootEntries, subtract one dec si // SI holds MaxRootEntries, subtract one
jz ErrBoot // If we are out of root dir entries then reboot jz ErrBoot // If we are out of root dir entries then reboot
add di, 32 // Increment DI by the size of a directory entry add di, 32 // Increment DI by the size of a directory entry
cmp di, HEX(0200) // Compare DI to 512 (DI has offset to next dir entry, make sure we haven't gone over one sector) cmp di, HEX(0200) // Compare DI to 512 (DI has offset to next dir entry, make sure we haven't gone over one sector)
jc SearchRootDirSector // If DI is less than 512 loop again jc SearchRootDirSector // If DI is less than 512 loop again
jmp short LoadRootDirSector // Didn't find FREELDR.SYS in this directory sector, try again jmp short LoadRootDirSector // Didn't find FREELDR.SYS in this directory sector, try again
FoundFreeLoader: FoundFreeLoader:
// We found freeldr.sys on the disk // We found freeldr.sys on the disk
// so we need to load the first 512 // so we need to load the first 512
// bytes of it to 0000:F800 // bytes of it to 0000:F800
// ES:DI has dir entry (ES:DI == 07E0:XXXX) // ES:DI has dir entry (ES:DI == 07E0:XXXX)
mov ax, word ptr es:[di + HEX(1a)] // Get start cluster mov ax, word ptr es:[di + HEX(1a)] // Get start cluster
push ax // Save start cluster push ax // Save start cluster
push FREELDR_BASE / 16 // Put load segment on the stack and load it push FREELDR_BASE / 16 // Put load segment on the stack and load it
pop es // Into ES so that we load the cluster at 0000:F800 pop es // Into ES so that we load the cluster at 0000:F800
call ReadCluster // Read the cluster call ReadCluster // Read the cluster
pop ax // Restore start cluster of FreeLoader pop ax // Restore start cluster of FreeLoader
// Save the addresses of needed functions so // Save the addresses of needed functions so
// the helper code will know where to call them. // the helper code will know where to call them.
mov word ptr [bp-ReadSectorsOffset], offset ReadSectors // Save the address of ReadSectors mov word ptr [bp-ReadSectorsOffset], offset ReadSectors // Save the address of ReadSectors
mov word ptr [bp-ReadClusterOffset], offset ReadCluster // Save the address of ReadCluster mov word ptr [bp-ReadClusterOffset], offset ReadCluster // Save the address of ReadCluster
mov word ptr [bp-PutCharsOffset], offset PutChars // Save the address of PutChars mov word ptr [bp-PutCharsOffset], offset PutChars // Save the address of PutChars
// Now AX has start cluster of FreeLoader and we // Now AX has start cluster of FreeLoader and we
// have loaded the helper code in the first 512 bytes // have loaded the helper code in the first 512 bytes
@ -236,12 +236,12 @@ FoundFreeLoader:
// Displays an error message // Displays an error message
// And reboots // And reboots
ErrBoot: ErrBoot:
mov si, offset msgFreeLdr // FreeLdr not found message mov si, offset msgFreeLdr // FreeLdr not found message
call PutChars // Display it call PutChars // Display it
Reboot: Reboot:
// mov si, offset msgAnyKey // Press any key message // mov si, offset msgAnyKey // Press any key message
// call PutChars // Display it // call PutChars // Display it
xor ax, ax xor ax, ax
int HEX(16) // Wait for a keypress int HEX(16) // Wait for a keypress
int HEX(19) // Reboot int HEX(19) // Reboot
@ -260,8 +260,8 @@ Done:
// Displays a bad boot message // Displays a bad boot message
// And reboots // And reboots
BadBoot: BadBoot:
mov si, offset msgDiskError // Bad boot disk message mov si, offset msgDiskError // Bad boot disk message
call PutChars // Display it call PutChars // Display it
jmp short Reboot jmp short Reboot
@ -269,17 +269,17 @@ BadBoot:
// Reads cluster number in AX into [ES:0000] // Reads cluster number in AX into [ES:0000]
ReadCluster: ReadCluster:
// StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors; // StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
dec ax // Adjust start cluster by 2 dec ax // Adjust start cluster by 2
dec ax // Because the data area starts on cluster 2 dec ax // Because the data area starts on cluster 2
xor ch, ch xor ch, ch
mov cl, byte ptr BP_REL(SectsPerCluster) mov cl, byte ptr BP_REL(SectsPerCluster)
mul cx // Times sectors per cluster mul cx // Times sectors per cluster
add ax, [bp-DataAreaStartLow] // Add start of data area add ax, [bp-DataAreaStartLow] // Add start of data area
adc dx, [bp-DataAreaStartHigh] // Now we have DX:AX with the logical start sector of OSLOADER.SYS adc dx, [bp-DataAreaStartHigh] // Now we have DX:AX with the logical start sector of FREELDR.SYS
xor bx, bx // We will load it to [ES:0000], ES loaded before function call xor bx, bx // We will load it to [ES:0000], ES loaded before function call
//mov cl,BYTE [BYTE bp+SectsPerCluster]// Sectors per cluster still in CX // mov cl,BYTE [BYTE bp+SectsPerCluster]// Sectors per cluster still in CX
//call ReadSectors // call ReadSectors
//ret // ret
@ -296,63 +296,63 @@ ReadSectors:
add ax, cx add ax, cx
adc dx, 0 adc dx, 0
cmp dx, word ptr [bp-BiosCHSDriveSizeHigh] // Check if they are reading a sector within CHS range cmp dx, word ptr [bp-BiosCHSDriveSizeHigh] // Check if they are reading a sector within CHS range
ja ReadSectorsLBA // No - go to the LBA routine ja ReadSectorsLBA // No - go to the LBA routine
jb ReadSectorsCHS // Yes - go to the old CHS routine jb ReadSectorsCHS // Yes - go to the old CHS routine
cmp ax, word ptr [bp-BiosCHSDriveSizeLow] // Check if they are reading a sector within CHS range cmp ax, word ptr [bp-BiosCHSDriveSizeLow] // Check if they are reading a sector within CHS range
jbe ReadSectorsCHS // Yes - go to the old CHS routine jbe ReadSectorsCHS // Yes - go to the old CHS routine
ReadSectorsLBA: ReadSectorsLBA:
popa popa
ReadSectorsLBALoop: ReadSectorsLBALoop:
pusha // Save logical sector number & sector count pusha // Save logical sector number & sector count
push 0 push 0
push 0 push 0
push dx // Put 64-bit logical push dx // Put 64-bit logical
push ax // block address on stack push ax // block address on stack
push es // Put transfer segment on stack push es // Put transfer segment on stack
push bx // Put transfer offset on stack push bx // Put transfer offset on stack
push 1 // Set transfer count to 1 sector push 1 // Set transfer count to 1 sector
push HEX(10) // Set size of packet to 10h push HEX(10) // Set size of packet to 10h
mov si,sp // Setup disk address packet on stack mov si,sp // Setup disk address packet on stack
// We are so totally out of space here that I am forced to // We are so totally out of space here that I am forced to
// comment out this very beautifully written piece of code // comment out this very beautifully written piece of code
// It would have been nice to have had this check... // It would have been nice to have had this check...
//CheckInt13hExtensions: // Now make sure this computer supports extended reads //CheckInt13hExtensions: // Now make sure this computer supports extended reads
// mov ah,0x41 // AH = 41h // mov ah,0x41 // AH = 41h
// mov bx,0x55aa // BX = 55AAh // mov bx,0x55aa // BX = 55AAh
// mov dl,[BYTE bp+BootDrive] // DL = drive (80h-FFh) // mov dl,[BYTE bp+BootDrive] // DL = drive (80h-FFh)
// int 13h // IBM/MS INT 13 Extensions - INSTALLATION CHECK // int 13h // IBM/MS INT 13 Extensions - INSTALLATION CHECK
// jc PrintDiskError // CF set on error (extensions not supported) // jc PrintDiskError // CF set on error (extensions not supported)
// cmp bx,0xaa55 // BX = AA55h if installed // cmp bx,0xaa55 // BX = AA55h if installed
// jne PrintDiskError // jne PrintDiskError
// test cl,1 // CX = API subset support bitmap // test cl,1 // CX = API subset support bitmap
// jz PrintDiskError // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported // jz PrintDiskError // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
// Good, we're here so the computer supports LBA disk access // Good, we're here so the computer supports LBA disk access
// So finish the extended read // So finish the extended read
mov dl, byte ptr BP_REL(BootDrive) // Drive number mov dl, byte ptr BP_REL(BootDrive) // Drive number
mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read
int HEX(13) // Call BIOS int HEX(13) // Call BIOS
jc BadBoot // If the read failed then abort jc BadBoot // If the read failed then abort
add sp, 16 // Remove disk address packet from stack add sp, 16 // Remove disk address packet from stack
popa // Restore sector count & logical sector number popa // Restore sector count & logical sector number
inc ax // Increment Sector to Read inc ax // Increment Sector to Read
adc dx, 0 adc dx, 0
push bx push bx
mov bx, es mov bx, es
add bx, HEX(20) // Increment read buffer for next sector add bx, HEX(20) // Increment read buffer for next sector
mov es, bx mov es, bx
pop bx pop bx
loop ReadSectorsLBALoop // Read next sector loop ReadSectorsLBALoop // Read next sector
ret ret
@ -370,26 +370,26 @@ ReadSectorsCHSLoop:
xor dx, dx xor dx, dx
div word ptr BP_REL(SectorsPerTrack) div word ptr BP_REL(SectorsPerTrack)
xchg ax, cx xchg ax, cx
div word ptr BP_REL(SectorsPerTrack) // Divide logical by SectorsPerTrack div word ptr BP_REL(SectorsPerTrack) // Divide logical by SectorsPerTrack
inc dx // Sectors numbering starts at 1 not 0 inc dx // Sectors numbering starts at 1 not 0
xchg cx, dx xchg cx, dx
div word ptr BP_REL(NumberOfHeads) // Number of heads div word ptr BP_REL(NumberOfHeads) // Number of heads
mov dh, dl // Head to DH, drive to DL mov dh, dl // Head to DH, drive to DL
mov dl, byte ptr BP_REL(BootDrive) // Drive number mov dl, byte ptr BP_REL(BootDrive) // Drive number
mov ch, al // Cylinder in CX mov ch, al // Cylinder in CX
ror ah, 2 // Low 8 bits of cylinder in CH, high 2 bits ror ah, 2 // Low 8 bits of cylinder in CH, high 2 bits
// in CL shifted to bits 6 & 7 // in CL shifted to bits 6 & 7
or cl, ah // Or with sector number or cl, ah // Or with sector number
mov ax, HEX(0201) mov ax, HEX(0201)
int HEX(13) // DISK - READ SECTORS INTO MEMORY int HEX(13) // DISK - READ SECTORS INTO MEMORY
// AL = number of sectors to read, CH = track, CL = sector // AL = number of sectors to read, CH = track, CL = sector
// DH = head, DL = drive, ES:BX -> buffer to fill // DH = head, DL = drive, ES:BX -> buffer to fill
// Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read // Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
jc BadBoot jc BadBoot
popa popa
inc ax //Increment Sector to Read inc ax // Increment Sector to Read
jnz NoCarryCHS jnz NoCarryCHS
inc dx inc dx
@ -400,8 +400,8 @@ NoCarryCHS:
add bx, HEX(20) add bx, HEX(20)
mov es, bx mov es, bx
pop bx pop bx
// Increment read buffer for next sector // Increment read buffer for next sector
loop ReadSectorsCHSLoop // Read next sector loop ReadSectorsCHSLoop // Read next sector
ret ret
@ -409,10 +409,11 @@ NoCarryCHS:
msgDiskError: msgDiskError:
.ascii "Disk error", CR, LF, NUL .ascii "Disk error", CR, LF, NUL
msgFreeLdr: msgFreeLdr:
.ascii "ldr not found", CR, LF, NUL .ascii "Ldr not found", CR, LF, NUL
// Sorry, need the space... // Sorry, need the space...
//msgAnyKey: // msgAnyKey:
// .ascii "Press any key to restart", CR, LF, NUL // .ascii "Press any key to restart", CR, LF, NUL
// .ascii "Press a key", CR, LF, NUL
filename: filename:
.ascii "FREELDR SYS" .ascii "FREELDR SYS"
@ -422,7 +423,7 @@ BootPartition:
.byte 0 .byte 0
BootSignature: BootSignature:
.word HEX(0aa55) // BootSector signature .word HEX(0aa55) // BootSector signature
.endcode16 .endcode16

View file

@ -39,15 +39,15 @@
; boots dramatically. ; boots dramatically.
BootSectorStackTop equ 0x7bf2 BootSectorStackTop equ 0x7bf2
DataAreaStartHigh equ 0x2 DataAreaStartHigh equ 0x2
DataAreaStartLow equ 0x4 DataAreaStartLow equ 0x4
BiosCHSDriveSizeHigh equ 0x6 BiosCHSDriveSizeHigh equ 0x6
BiosCHSDriveSizeLow equ 0x8 BiosCHSDriveSizeLow equ 0x8
BiosCHSDriveSize equ 0x8 BiosCHSDriveSize equ 0x8
ReadSectorsOffset equ 0xa ReadSectorsOffset equ 0xa
ReadClusterOffset equ 0xc ReadClusterOffset equ 0xc
PutCharsOffset equ 0xe PutCharsOffset equ 0xe
org 7c00h org 7c00h
@ -84,136 +84,136 @@ main:
xor ax,ax xor ax,ax
mov ss,ax mov ss,ax
mov bp,7c00h mov bp,7c00h
mov sp,BootSectorStackTop ; Setup a stack mov sp,BootSectorStackTop ; Setup a stack
mov ds,ax ; Make DS correct mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct mov es,ax ; Make ES correct
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
jne GetDriveParameters jne GetDriveParameters
mov [BYTE bp+BootDrive],dl ; Save the boot drive mov [BYTE bp+BootDrive],dl ; Save the boot drive
GetDriveParameters: GetDriveParameters:
mov ah,08h mov ah,08h
mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl
int 13h ; Request drive parameters from the bios int 13h ; Request drive parameters from the bios
jnc CalcDriveSize ; If the call succeeded then calculate the drive size jnc CalcDriveSize ; If the call succeeded then calculate the drive size
; If we get here then the call to the BIOS failed ; If we get here then the call to the BIOS failed
; so just set CHS equal to the maximum addressable ; so just set CHS equal to the maximum addressable
; size ; size
mov cx,0ffffh mov cx,0ffffh
mov dh,cl mov dh,cl
CalcDriveSize: CalcDriveSize:
; Now that we have the drive geometry ; Now that we have the drive geometry
; lets calculate the drive size ; lets calculate the drive size
mov bl,ch ; Put the low 8-bits of the cylinder count into BL mov bl,ch ; Put the low 8-bits of the cylinder count into BL
mov bh,cl ; Put the high 2-bits in BH mov bh,cl ; Put the high 2-bits in BH
shr bh,6 ; Shift them into position, now BX contains the cylinder count shr bh,6 ; Shift them into position, now BX contains the cylinder count
and cl,3fh ; Mask off cylinder bits from sector count and cl,3fh ; Mask off cylinder bits from sector count
; CL now contains sectors per track and DH contains head count ; CL now contains sectors per track and DH contains head count
movzx eax,dh ; Move the heads into EAX movzx eax,dh ; Move the heads into EAX
movzx ebx,bx ; Move the cylinders into EBX movzx ebx,bx ; Move the cylinders into EBX
movzx ecx,cl ; Move the sectors per track into ECX movzx ecx,cl ; Move the sectors per track into ECX
inc eax ; Make it one based because the bios returns it zero based inc eax ; Make it one based because the bios returns it zero based
inc ebx ; Make the cylinder count one based also inc ebx ; Make the cylinder count one based also
mul ecx ; Multiply heads with the sectors per track, result in edx:eax mul ecx ; Multiply heads with the sectors per track, result in edx:eax
mul ebx ; Multiply the cylinders with (heads * sectors) [stored in edx:eax already] mul ebx ; Multiply the cylinders with (heads * sectors) [stored in edx:eax already]
; We now have the total number of sectors as reported ; We now have the total number of sectors as reported
; by the bios in eax, so store it in our variable ; by the bios in eax, so store it in our variable
mov [BYTE bp-BiosCHSDriveSize],eax mov [BYTE bp-BiosCHSDriveSize],eax
; Now we must find our way to the first sector of the root directory ; Now we must find our way to the first sector of the root directory
xor ax,ax xor ax,ax
xor cx,cx xor cx,cx
mov al,[BYTE bp+NumberOfFats] ; Number of fats mov al,[BYTE bp+NumberOfFats] ; Number of fats
mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat
add ax,WORD [BYTE bp+HiddenSectors] add ax,WORD [BYTE bp+HiddenSectors]
adc dx,WORD [BYTE bp+HiddenSectors+2] ; Add the number of hidden sectors 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 add ax,WORD [BYTE bp+ReservedSectors] ; Add the number of reserved sectors
adc dx,cx ; Add carry bit adc dx,cx ; Add carry bit
mov WORD [BYTE bp-DataAreaStartLow],ax ; Save the starting sector of the root directory mov WORD [BYTE bp-DataAreaStartLow],ax ; Save the starting sector of the root directory
mov WORD [BYTE bp-DataAreaStartHigh],dx ; Save it in the first 4 bytes before the boot sector mov WORD [BYTE bp-DataAreaStartHigh],dx ; Save it in the first 4 bytes before the boot sector
mov si,WORD [BYTE bp+MaxRootEntries] ; Get number of root dir entries in SI mov si,WORD [BYTE bp+MaxRootEntries] ; Get number of root dir entries in SI
pusha ; Save 32-bit logical start sector of root dir pusha ; Save 32-bit logical start sector of root dir
; DX:AX now has the number of the starting sector of the root directory ; DX:AX now has the number of the starting sector of the root directory
; Now calculate the size of the root directory ; Now calculate the size of the root directory
xor dx,dx xor dx,dx
mov ax,0020h ; Size of dir entry mov ax,0020h ; Size of dir entry
mul si ; Times the number of entries mul si ; Times the number of entries
mov bx,[BYTE bp+BytesPerSector] mov bx,[BYTE bp+BytesPerSector]
add ax,bx add ax,bx
dec ax dec ax
div bx ; Divided by the size of a sector div bx ; Divided by the size of a sector
; AX now has the number of root directory sectors ; AX now has the number of root directory sectors
add [BYTE bp-DataAreaStartLow],ax ; Add the number of sectors of the root directory to our other value add [BYTE bp-DataAreaStartLow],ax ; Add the number of sectors of the root directory to our other value
adc [BYTE bp-DataAreaStartHigh],cx ; Now the first 4 bytes before the boot sector contain the starting sector of the data area adc [BYTE bp-DataAreaStartHigh],cx ; Now the first 4 bytes before the boot sector contain the starting sector of the data area
popa ; Restore root dir logical sector start to DX:AX popa ; Restore root dir logical sector start to DX:AX
LoadRootDirSector: LoadRootDirSector:
mov bx,7e0h ; We will load the root directory sector mov bx,7e0h ; We will load the root directory sector
mov es,bx ; Right after the boot sector in memory mov es,bx ; Right after the boot sector in memory
xor bx,bx ; We will load it to [0000:7e00h] xor bx,bx ; We will load it to [0000:7e00h]
xor cx,cx ; Zero out CX xor cx,cx ; Zero out CX
inc cx ; Now increment it to 1, we are reading one sector inc cx ; Now increment it to 1, we are reading one sector
xor di,di ; Zero out di xor di,di ; Zero out di
push es ; Save ES because it will get incremented by 20h push es ; Save ES because it will get incremented by 20h
call ReadSectors ; Read the first sector of the root directory call ReadSectors ; Read the first sector of the root directory
pop es ; Restore ES (ES:DI = 07E0:0000) pop es ; Restore ES (ES:DI = 07E0:0000)
SearchRootDirSector: SearchRootDirSector:
cmp [es:di],ch ; If the first byte of the directory entry is zero then we have cmp [es:di],ch ; If the first byte of the directory entry is zero then we have
jz ErrBoot ; reached the end of the directory and FREELDR.SYS is not here so reboot jz ErrBoot ; reached the end of the directory and FREELDR.SYS is not here so reboot
pusha ; Save all registers pusha ; Save all registers
mov cl,0xb ; Put 11 in cl (length of filename in directory entry) mov cl,0xb ; Put 11 in cl (length of filename in directory entry)
mov si,filename ; Put offset of filename string in DS:SI mov si,filename ; Put offset of filename string in DS:SI
repe cmpsb ; Compare this directory entry against 'FREELDR SYS' repe cmpsb ; Compare this directory entry against 'FREELDR SYS'
popa ; Restore all the registers popa ; Restore all the registers
jz FoundFreeLoader ; If we found it then jump jz FoundFreeLoader ; If we found it then jump
dec si ; SI holds MaxRootEntries, subtract one dec si ; SI holds MaxRootEntries, subtract one
jz ErrBoot ; If we are out of root dir entries then reboot jz ErrBoot ; If we are out of root dir entries then reboot
add di,BYTE +0x20 ; Increment DI by the size of a directory entry add di,BYTE +0x20 ; Increment DI by the size of a directory entry
cmp di,0200h ; Compare DI to 512 (DI has offset to next dir entry, make sure we haven't gone over one sector) cmp di,0200h ; Compare DI to 512 (DI has offset to next dir entry, make sure we haven't gone over one sector)
jc SearchRootDirSector ; If DI is less than 512 loop again jc SearchRootDirSector ; If DI is less than 512 loop again
jmp short LoadRootDirSector ; Didn't find FREELDR.SYS in this directory sector, try again jmp short LoadRootDirSector ; Didn't find FREELDR.SYS in this directory sector, try again
FoundFreeLoader: FoundFreeLoader:
; We found freeldr.sys on the disk ; We found freeldr.sys on the disk
; so we need to load the first 512 ; so we need to load the first 512
; bytes of it to 0000:8000 ; bytes of it to 0000:8000
; ES:DI has dir entry (ES:DI == 07E0:XXXX) ; ES:DI has dir entry (ES:DI == 07E0:XXXX)
mov ax,WORD [es:di+1ah] ; Get start cluster mov ax,WORD [es:di+1ah] ; Get start cluster
push ax ; Save start cluster push ax ; Save start cluster
push WORD 800h ; Put 800h on the stack and load it push WORD 800h ; Put 800h on the stack and load it
pop es ; Into ES so that we load the cluster at 0000:8000 pop es ; Into ES so that we load the cluster at 0000:8000
call ReadCluster ; Read the cluster call ReadCluster ; Read the cluster
pop ax ; Restore start cluster of FreeLoader pop ax ; Restore start cluster of FreeLoader
; Save the addresses of needed functions so ; Save the addresses of needed functions so
; the helper code will know where to call them. ; the helper code will know where to call them.
mov WORD [BYTE bp-ReadSectorsOffset],ReadSectors ; Save the address of ReadSectors mov WORD [BYTE bp-ReadSectorsOffset],ReadSectors ; Save the address of ReadSectors
mov WORD [BYTE bp-ReadClusterOffset],ReadCluster ; Save the address of ReadCluster mov WORD [BYTE bp-ReadClusterOffset],ReadCluster ; Save the address of ReadCluster
mov WORD [BYTE bp-PutCharsOffset],PutChars ; Save the address of PutChars mov WORD [BYTE bp-PutCharsOffset],PutChars ; Save the address of PutChars
; Now AX has start cluster of FreeLoader and we ; Now AX has start cluster of FreeLoader and we
; have loaded the helper code in the first 512 bytes ; have loaded the helper code in the first 512 bytes
; of FreeLoader to 0000:8000. Now transfer control ; of FreeLoader to 0000:8000. Now transfer control
; to the helper code. Skip the first three bytes ; to the helper code. Skip the first three bytes
; because they contain a jump instruction to skip ; because they contain a jump instruction to skip
; over the helper code in the FreeLoader image. ; over the helper code in the FreeLoader image.
;jmp 0000:9003h ;jmp 0000:9003h
push 0 ; push segment (0x0000) push 0 ; push segment (0x0000)
mov bx, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax mov bx, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax
add bx, 0x8003 ; RVA -> VA and skip 3 bytes (jump to fathelper code) add bx, 0x8003 ; RVA -> VA and skip 3 bytes (jump to fathelper code)
push bx ; push offset push bx ; push offset
retf ; Transfer control to FreeLoader retf ; Transfer control to FreeLoader
@ -248,23 +248,23 @@ BadBoot:
mov si,msgDiskError ; Bad boot disk message mov si,msgDiskError ; Bad boot disk message
call PutChars ; Display it call PutChars ; Display it
jmp short Reboot jmp short Reboot
; Reads cluster number in AX into [ES:0000] ; Reads cluster number in AX into [ES:0000]
ReadCluster: ReadCluster:
; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors; ; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
dec ax ; Adjust start cluster by 2 dec ax ; Adjust start cluster by 2
dec ax ; Because the data area starts on cluster 2 dec ax ; Because the data area starts on cluster 2
xor ch,ch xor ch,ch
mov cl,BYTE [BYTE bp+SectsPerCluster] mov cl,BYTE [BYTE bp+SectsPerCluster]
mul cx ; Times sectors per cluster mul cx ; Times sectors per cluster
add ax,[BYTE bp-DataAreaStartLow] ; Add start of data area add ax,[BYTE bp-DataAreaStartLow] ; Add start of data area
adc dx,[BYTE bp-DataAreaStartHigh] ; Now we have DX:AX with the logical start sector of OSLOADER.SYS adc dx,[BYTE bp-DataAreaStartHigh] ; Now we have DX:AX with the logical start sector of FREELDR.SYS
xor bx,bx ; We will load it to [ES:0000], ES loaded before function call xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
;mov cl,BYTE [BYTE bp+SectsPerCluster]; Sectors per cluster still in CX ;mov cl,BYTE [BYTE bp+SectsPerCluster]; Sectors per cluster still in CX
;call ReadSectors ;call ReadSectors
;ret ;ret
@ -273,70 +273,70 @@ ReadCluster:
; CX has number of sectors to read ; CX has number of sectors to read
ReadSectors: ReadSectors:
; We can't just check if the start sector is ; We can't just check if the start sector is
; in the BIOS CHS range. We have to check if ; in the BIOS CHS range. We have to check if
; the start sector + length is in that range. ; the start sector + length is in that range.
pusha pusha
dec cx dec cx
add ax,cx add ax,cx
adc dx,byte 0 adc dx,byte 0
cmp dx,WORD [BYTE bp-BiosCHSDriveSizeHigh] ; Check if they are reading a sector within CHS range cmp dx,WORD [BYTE bp-BiosCHSDriveSizeHigh] ; Check if they are reading a sector within CHS range
ja ReadSectorsLBA ; No - go to the LBA routine ja ReadSectorsLBA ; No - go to the LBA routine
jb ReadSectorsCHS ; Yes - go to the old CHS routine jb ReadSectorsCHS ; Yes - go to the old CHS routine
cmp ax,WORD [BYTE bp-BiosCHSDriveSizeLow] ; Check if they are reading a sector within CHS range cmp ax,WORD [BYTE bp-BiosCHSDriveSizeLow] ; Check if they are reading a sector within CHS range
jbe ReadSectorsCHS ; Yes - go to the old CHS routine jbe ReadSectorsCHS ; Yes - go to the old CHS routine
ReadSectorsLBA: ReadSectorsLBA:
popa popa
ReadSectorsLBALoop: ReadSectorsLBALoop:
pusha ; Save logical sector number & sector count pusha ; Save logical sector number & sector count
o32 push byte 0 o32 push byte 0
push dx ; Put 64-bit logical push dx ; Put 64-bit logical
push ax ; block address on stack push ax ; block address on stack
push es ; Put transfer segment on stack push es ; Put transfer segment on stack
push bx ; Put transfer offset on stack push bx ; Put transfer offset on stack
push byte 1 ; Set transfer count to 1 sector push byte 1 ; Set transfer count to 1 sector
push byte 0x10 ; Set size of packet to 10h push byte 0x10 ; Set size of packet to 10h
mov si,sp ; Setup disk address packet on stack mov si,sp ; Setup disk address packet on stack
; We are so totally out of space here that I am forced to ; We are so totally out of space here that I am forced to
; comment out this very beautifully written piece of code ; comment out this very beautifully written piece of code
; It would have been nice to have had this check... ; It would have been nice to have had this check...
;CheckInt13hExtensions: ; Now make sure this computer supports extended reads ;CheckInt13hExtensions: ; Now make sure this computer supports extended reads
; mov ah,0x41 ; AH = 41h ; mov ah,0x41 ; AH = 41h
; mov bx,0x55aa ; BX = 55AAh ; mov bx,0x55aa ; BX = 55AAh
; mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh) ; mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh)
; int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK ; int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK
; jc PrintDiskError ; CF set on error (extensions not supported) ; jc PrintDiskError ; CF set on error (extensions not supported)
; cmp bx,0xaa55 ; BX = AA55h if installed ; cmp bx,0xaa55 ; BX = AA55h if installed
; jne PrintDiskError ; jne PrintDiskError
; test cl,1 ; CX = API subset support bitmap ; test cl,1 ; CX = API subset support bitmap
; jz PrintDiskError ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported ; jz PrintDiskError ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
; Good, we're here so the computer supports LBA disk access ; Good, we're here so the computer supports LBA disk access
; So finish the extended read ; So finish the extended read
mov dl,[BYTE bp+BootDrive] ; Drive number mov dl,[BYTE bp+BootDrive] ; Drive number
mov ah,42h ; Int 13h, AH = 42h - Extended Read mov ah,42h ; Int 13h, AH = 42h - Extended Read
int 13h ; Call BIOS int 13h ; Call BIOS
jc BadBoot ; If the read failed then abort jc BadBoot ; If the read failed then abort
add sp,byte 0x10 ; Remove disk address packet from stack add sp,byte 0x10 ; Remove disk address packet from stack
popa ; Restore sector count & logical sector number popa ; Restore sector count & logical sector number
inc ax ; Increment Sector to Read inc ax ; Increment Sector to Read
adc dx,byte 0 adc dx,byte 0
push bx push bx
mov bx,es mov bx,es
add bx,byte 20h ; Increment read buffer for next sector add bx,byte 20h ; Increment read buffer for next sector
mov es,bx mov es,bx
pop bx pop bx
loop ReadSectorsLBALoop ; Read next sector loop ReadSectorsLBALoop ; Read next sector
ret ret
@ -346,7 +346,7 @@ ReadSectorsLBALoop:
; CX has number of sectors to read ; CX has number of sectors to read
; CarryFlag set on error ; CarryFlag set on error
ReadSectorsCHS: ReadSectorsCHS:
popa popa
ReadSectorsCHSLoop: ReadSectorsCHSLoop:
pusha pusha
xchg ax,cx xchg ax,cx
@ -367,8 +367,8 @@ ReadSectorsCHSLoop:
mov ax,0201h mov ax,0201h
int 13h ; DISK - READ SECTORS INTO MEMORY int 13h ; DISK - READ SECTORS INTO MEMORY
; AL = number of sectors to read, CH = track, CL = sector ; AL = number of sectors to read, CH = track, CL = sector
; DH = head, DL = drive, ES:BX -> buffer to fill ; DH = head, DL = drive, ES:BX -> buffer to fill
; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read ; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
jc BadBoot jc BadBoot
@ -391,16 +391,16 @@ NoCarryCHS:
msgDiskError db 'Disk error',0dh,0ah,0 msgDiskError db 'Disk error',0dh,0ah,0
msgFreeLdr db 'ldr not found',0dh,0ah,0 msgFreeLdr db 'Ldr not found',0dh,0ah,0
; Sorry, need the space... ; Sorry, need the space...
;msgAnyKey db 'Press any key to restart',0dh,0ah,0 ;msgAnyKey db 'Press any key to restart',0dh,0ah,0
msgAnyKey db 'Press a key',0dh,0ah,0 ;msgAnyKey db 'Press a key',0dh,0ah,0
filename db 'FREELDR SYS' filename db 'FREELDR SYS'
times 509-($-$$) db 0 ; Pad to 509 bytes times 509-($-$$) db 0 ; Pad to 509 bytes
BootPartition: BootPartition:
db 0 db 0
BootSignature: BootSignature:
dw 0aa55h ; BootSector signature dw 0aa55h ; BootSector signature

View file

@ -3,7 +3,7 @@
* PROJECT: ReactOS Bootsector * PROJECT: ReactOS Bootsector
* FILE: boot/freeldr/bootsect/fat32.S * FILE: boot/freeldr/bootsect/fat32.S
* PURPOSE: * PURPOSE:
* PROGRAMMERS: ? * PROGRAMMERS: Brian Palmer
*/ */
/* INCLUDES ******************************************************************/ /* INCLUDES ******************************************************************/
@ -32,13 +32,13 @@ ReservedSectors:
NumberOfFats: NumberOfFats:
.byte 2 .byte 2
MaxRootEntries: MaxRootEntries:
.word 0 // Always zero for FAT32 volumes .word 0 // Always zero for FAT32 volumes
TotalSectors: TotalSectors:
.word 0 // Always zero for FAT32 volumes .word 0 // Always zero for FAT32 volumes
MediaDescriptor: MediaDescriptor:
.byte HEX(0f8) .byte HEX(0f8)
SectorsPerFat: SectorsPerFat:
.word 0 // Always zero for FAT32 volumes .word 0 // Always zero for FAT32 volumes
SectorsPerTrack: SectorsPerTrack:
.word 0 .word 0
NumberOfHeads: NumberOfHeads:
@ -82,33 +82,33 @@ main:
xor ax,ax // Setup segment registers xor ax,ax // Setup segment registers
mov ds,ax // Make DS correct mov ds,ax // Make DS correct
mov es,ax // Make ES correct mov es,ax // Make ES correct
mov ss,ax // Make SS correct mov ss,ax // Make SS correct
mov bp, HEX(7c00) mov bp, HEX(7c00)
mov sp, HEX(7c00) // Setup a stack mov sp, HEX(7c00) // Setup a stack
cmp byte ptr BP_REL(BootDrive), HEX(0ff) // If they have specified a boot drive then use it cmp byte ptr BP_REL(BootDrive), HEX(0ff) // If they have specified a boot drive then use it
jne CheckSectorsPerFat jne CheckSectorsPerFat
mov byte ptr BP_REL(BootDrive), dl // Save the boot drive mov byte ptr BP_REL(BootDrive), dl // Save the boot drive
CheckSectorsPerFat: CheckSectorsPerFat:
cmp word ptr BP_REL(SectorsPerFat), 0 // Check the old 16-bit value of SectorsPerFat cmp word ptr BP_REL(SectorsPerFat), 0 // Check the old 16-bit value of SectorsPerFat
jnz CheckFailed // If it is non-zero then exit with an error jnz CheckFailed // If it is non-zero then exit with an error
CheckTotalSectors: // Check the old 16-bit value of TotalSectors & MaxRootEntries CheckTotalSectors: // Check the old 16-bit value of TotalSectors & MaxRootEntries
cmp dword ptr BP_REL(MaxRootEntries), 0// by comparing the DWORD at offset MaxRootEntries to zero cmp dword ptr BP_REL(MaxRootEntries), 0 // by comparing the DWORD at offset MaxRootEntries to zero
jnz CheckFailed // If it is non-zero then exit with an error jnz CheckFailed // If it is non-zero then exit with an error
CheckFileSystemVersion: CheckFileSystemVersion:
cmp word ptr BP_REL(FSVersion), 0 // Check the file system version word cmp word ptr BP_REL(FSVersion), 0 // Check the file system version word
jna GetDriveParameters // It is zero, so continue jna GetDriveParameters // It is zero, so continue
CheckFailed: CheckFailed:
jmp PrintFileSystemError // If it is not zero then exit with an error jmp PrintFileSystemError // If it is not zero then exit with an error
GetDriveParameters: GetDriveParameters:
mov ax, HEX(0800) mov ax, HEX(0800)
mov dl, byte ptr BP_REL(BootDrive) // Get boot drive in dl mov dl, byte ptr BP_REL(BootDrive) // Get boot drive in dl
int HEX(13) // Request drive parameters from the bios int HEX(13) // Request drive parameters from the bios
jnc CalcDriveSize // If the call succeeded then calculate the drive size jnc CalcDriveSize // If the call succeeded then calculate the drive size
// If we get here then the call to the BIOS failed // If we get here then the call to the BIOS failed
// so just set CHS equal to the maximum addressable // so just set CHS equal to the maximum addressable
@ -119,18 +119,18 @@ GetDriveParameters:
CalcDriveSize: CalcDriveSize:
// Now that we have the drive geometry // Now that we have the drive geometry
// lets calculate the drive size // lets calculate the drive size
mov bl, ch // Put the low 8-bits of the cylinder count into BL mov bl, ch // Put the low 8-bits of the cylinder count into BL
mov bh, cl // Put the high 2-bits in BH mov bh, cl // Put the high 2-bits in BH
shr bh, 6 // Shift them into position, now BX contains the cylinder count shr bh, 6 // Shift them into position, now BX contains the cylinder count
and cl, HEX(3f) // Mask off cylinder bits from sector count and cl, HEX(3f) // Mask off cylinder bits from sector count
// CL now contains sectors per track and DH contains head count // CL now contains sectors per track and DH contains head count
movzx eax, dh // Move the heads into EAX movzx eax, dh // Move the heads into EAX
movzx ebx, bx // Move the cylinders into EBX movzx ebx, bx // Move the cylinders into EBX
movzx ecx, cl // Move the sectors per track into ECX movzx ecx, cl // Move the sectors per track into ECX
inc eax // Make it one based because the bios returns it zero based inc eax // Make it one based because the bios returns it zero based
inc ebx // Make the cylinder count one based also inc ebx // Make the cylinder count one based also
mul ecx // Multiply heads with the sectors per track, result in edx:eax mul ecx // Multiply heads with the sectors per track, result in edx:eax
mul ebx // Multiply the cylinders with (heads * sectors) [stored in edx:eax already] mul ebx // Multiply the cylinders with (heads * sectors) [stored in edx:eax already]
// We now have the total number of sectors as reported // We now have the total number of sectors as reported
// by the bios in eax, so store it in our variable // by the bios in eax, so store it in our variable
@ -140,10 +140,10 @@ LoadExtraBootCode:
// First we have to load our extra boot code at // First we have to load our extra boot code at
// sector 14 into memory at [0000:7e00h] // sector 14 into memory at [0000:7e00h]
mov eax, HEX(0e) mov eax, HEX(0e)
add eax, dword ptr BP_REL(HiddenSectors) // Add the number of hidden sectors add eax, dword ptr BP_REL(HiddenSectors) // Add the number of hidden sectors
mov cx, 1 mov cx, 1
xor bx, bx xor bx, bx
mov es, bx // Read sector to [0000:7e00h] mov es, bx // Read sector to [0000:7e00h]
mov bx, HEX(7e00) mov bx, HEX(7e00)
call ReadSectors call ReadSectors
jmp StartSearch jmp StartSearch
@ -154,64 +154,64 @@ LoadExtraBootCode:
// CX has number of sectors to read // CX has number of sectors to read
ReadSectors: ReadSectors:
push es push es
cmp eax, dword ptr ds:[BiosCHSDriveSize] // Check if they are reading a sector outside CHS range cmp eax, dword ptr ds:[BiosCHSDriveSize] // Check if they are reading a sector outside CHS range
jae ReadSectorsLBA // Yes - go to the LBA routine jae ReadSectorsLBA // Yes - go to the LBA routine
// If at all possible we want to use LBA routines because // If at all possible we want to use LBA routines because
// They are optimized to read more than 1 sector per read // They are optimized to read more than 1 sector per read
pushad // Save logical sector number & sector count pushad // Save logical sector number & sector count
CheckInt13hExtensions: // Now check if this computer supports extended reads CheckInt13hExtensions: // Now check if this computer supports extended reads
mov ah, HEX(41) // AH = 41h mov ah, HEX(41) // AH = 41h
mov bx, HEX(55aa) // BX = 55AAh mov bx, HEX(55aa) // BX = 55AAh
mov dl, byte ptr BP_REL(BootDrive) // DL = drive (80h-FFh) mov dl, byte ptr BP_REL(BootDrive) // DL = drive (80h-FFh)
int HEX(13) // IBM/MS INT 13 Extensions - INSTALLATION CHECK int HEX(13) // IBM/MS INT 13 Extensions - INSTALLATION CHECK
jc ReadSectorsCHS // CF set on error (extensions not supported) jc ReadSectorsCHS // CF set on error (extensions not supported)
cmp bx, HEX(0aa55) // BX = AA55h if installed cmp bx, HEX(0aa55) // BX = AA55h if installed
jne ReadSectorsCHS jne ReadSectorsCHS
test cl,1 // CX = API subset support bitmap test cl,1 // CX = API subset support bitmap
jz ReadSectorsCHS // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported jz ReadSectorsCHS // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
popad // Restore sector count & logical sector number popad // Restore sector count & logical sector number
ReadSectorsLBA: ReadSectorsLBA:
pushad // Save logical sector number & sector count pushad // Save logical sector number & sector count
cmp cx, 64 // Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64 cmp cx, 64 // Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64
jbe ReadSectorsSetupDiskAddressPacket // If we are reading less than 65 sectors then just do the read jbe ReadSectorsSetupDiskAddressPacket // If we are reading less than 65 sectors then just do the read
mov cx, 64 // Otherwise read only 64 sectors on this loop iteration mov cx, 64 // Otherwise read only 64 sectors on this loop iteration
ReadSectorsSetupDiskAddressPacket: ReadSectorsSetupDiskAddressPacket:
mov word ptr ds:[LBASectorsRead],cx mov word ptr ds:[LBASectorsRead],cx
push 0 push 0
push 0 push 0
push eax // Put 64-bit logical block address on stack push eax // Put 64-bit logical block address on stack
push es // Put transfer segment on stack push es // Put transfer segment on stack
push bx // Put transfer offset on stack push bx // Put transfer offset on stack
push cx // Set transfer count push cx // Set transfer count
push 16 // Set size of packet to 10h push 16 // Set size of packet to 10h
mov si, sp // Setup disk address packet on stack mov si, sp // Setup disk address packet on stack
mov dl, byte ptr BP_REL(BootDrive) // Drive number mov dl, byte ptr BP_REL(BootDrive) // Drive number
mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read
int HEX(13) // Call BIOS int HEX(13) // Call BIOS
jc PrintDiskError // If the read failed then abort jc PrintDiskError // If the read failed then abort
add sp, 16 // Remove disk address packet from stack add sp, 16 // Remove disk address packet from stack
popad // Restore sector count & logical sector number popad // Restore sector count & logical sector number
push bx push bx
mov ebx, dword ptr ds:[LBASectorsRead] mov ebx, dword ptr ds:[LBASectorsRead]
add eax, ebx // Increment sector to read add eax, ebx // Increment sector to read
shl ebx, 5 shl ebx, 5
mov dx, es mov dx, es
add dx, bx // Setup read buffer for next sector add dx, bx // Setup read buffer for next sector
mov es, dx mov es, dx
pop bx pop bx
sub cx, word ptr ds:[LBASectorsRead] sub cx, word ptr ds:[LBASectorsRead]
jnz ReadSectorsLBA // Read next sector jnz ReadSectorsLBA // Read next sector
pop es pop es
ret ret
@ -231,57 +231,57 @@ ReadSectorsCHSLoop:
xor edx, edx xor edx, edx
movzx ecx, word ptr BP_REL(SectorsPerTrack) movzx ecx, word ptr BP_REL(SectorsPerTrack)
div ecx // Divide logical by SectorsPerTrack div ecx // Divide logical by SectorsPerTrack
inc dl // Sectors numbering starts at 1 not 0 inc dl // Sectors numbering starts at 1 not 0
mov cl, dl // Sector in CL mov cl, dl // Sector in CL
mov edx, eax mov edx, eax
shr edx, 16 shr edx, 16
div word ptr BP_REL(NumberOfHeads) // Divide logical by number of heads div word ptr BP_REL(NumberOfHeads) // Divide logical by number of heads
mov dh, dl // Head in DH mov dh, dl // Head in DH
mov dl, byte ptr BP_REL(BootDrive) // Drive number in DL mov dl, byte ptr BP_REL(BootDrive) // Drive number in DL
mov ch, al // Cylinder in CX mov ch, al // Cylinder in CX
ror ah, 1 // Low 8 bits of cylinder in CH, high 2 bits ror ah, 1 // Low 8 bits of cylinder in CH, high 2 bits
ror ah, 1 // in CL shifted to bits 6 & 7 ror ah, 1 // in CL shifted to bits 6 & 7
or cl, ah // Or with sector number or cl, ah // Or with sector number
mov ax, HEX(0201) mov ax, HEX(0201)
int HEX(13) // DISK - READ SECTORS INTO MEMORY int HEX(13) // DISK - READ SECTORS INTO MEMORY
// AL = number of sectors to read, CH = track, CL = sector // AL = number of sectors to read, CH = track, CL = sector
// DH = head, DL = drive, ES:BX -> buffer to fill // DH = head, DL = drive, ES:BX -> buffer to fill
// Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read // Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
jc PrintDiskError // If the read failed then abort jc PrintDiskError // If the read failed then abort
popad popad
inc eax // Increment Sector to Read inc eax // Increment Sector to Read
mov dx, es mov dx, es
add dx, 32 // Increment read buffer for next sector add dx, 32 // Increment read buffer for next sector
mov es, dx mov es, dx
loop ReadSectorsCHSLoop // Read next sector loop ReadSectorsCHSLoop // Read next sector
ret ret
// Displays a disk error message // Displays a disk error message
// And reboots // And reboots
PrintDiskError: PrintDiskError:
mov si, offset msgDiskError // Bad boot disk message mov si, offset msgDiskError // Bad boot disk message
call PutChars // Display it call PutChars // Display it
jmp Reboot jmp Reboot
// Displays a file system error message // Displays a file system error message
// And reboots // And reboots
PrintFileSystemError: PrintFileSystemError:
mov si, offset msgFileSystemError // FreeLdr not found message mov si, offset msgFileSystemError // FreeLdr not found message
call PutChars // Display it call PutChars // Display it
Reboot: Reboot:
mov si, offset msgAnyKey // Press any key message mov si, offset msgAnyKey // Press any key message
call PutChars // Display it call PutChars // Display it
xor ax, ax xor ax, ax
int HEX(16) // Wait for a keypress int HEX(16) // Wait for a keypress
int HEX(19) // Reboot int HEX(19) // Reboot
PutChars: PutChars:
lodsb lodsb
@ -311,7 +311,7 @@ BootPartition:
.byte 0 .byte 0
BootSignature: BootSignature:
.word HEX(0aa55) // BootSector signature .word HEX(0aa55) // BootSector signature
// End of bootsector // End of bootsector
// //
@ -330,7 +330,7 @@ StartSearch:
// Now we must get the first cluster of the root directory // Now we must get the first cluster of the root directory
mov eax, dword ptr BP_REL(RootDirStartCluster) mov eax, dword ptr BP_REL(RootDirStartCluster)
cmp eax, HEX(0ffffff8) // Check to see if this is the last cluster in the chain cmp eax, HEX(0ffffff8) // Check to see if this is the last cluster in the chain
jb ContinueSearch // If not continue, if so then we didn't find freeldr.sys jb ContinueSearch // If not continue, if so then we didn't find freeldr.sys
jmp PrintFileNotFound jmp PrintFileNotFound
ContinueSearch: ContinueSearch:
@ -339,16 +339,16 @@ ContinueSearch:
call ReadCluster // Read the cluster call ReadCluster // Read the cluster
// Now we have to find our way through the root directory to // Now we have to find our way through the root directory to
// The OSLOADER.SYS file // The FREELDR.SYS file
xor bx,bx xor bx,bx
mov bl, byte ptr BP_REL(SectsPerCluster) mov bl, byte ptr BP_REL(SectsPerCluster)
shl bx, 4 // BX = BX * 512 / 32 shl bx, 4 // BX = BX * 512 / 32
mov ax, HEX(2000) // We loaded at 2000:0000 mov ax, HEX(2000) // We loaded at 2000:0000
mov es, ax mov es, ax
xor di, di xor di, di
mov si, offset filename mov si, offset filename
mov cx, 11 mov cx, 11
repe cmpsb // Compare filenames repe cmpsb // Compare filenames
jz FoundFile // If same we found it jz FoundFile // If same we found it
dec bx dec bx
jnz FindFile jnz FindFile
@ -357,11 +357,11 @@ ContinueSearch:
FindFile: FindFile:
mov ax, es // We didn't find it in the previous dir entry mov ax, es // We didn't find it in the previous dir entry
add ax, 2 // So lets move to the next one add ax, 2 // So lets move to the next one
mov es, ax // And search again mov es, ax // And search again
xor di, di xor di, di
mov si, offset filename mov si, offset filename
mov cx, 11 mov cx, 11
repe cmpsb // Compare filenames repe cmpsb // Compare filenames
jz FoundFile // If same we found it jz FoundFile // If same we found it
dec bx // Keep searching till we run out of dir entries dec bx // Keep searching till we run out of dir entries
jnz FindFile // Last entry? jnz FindFile // Last entry?
@ -377,51 +377,51 @@ FoundFile:
mov si, offset msgLoading // Loading message mov si, offset msgLoading // Loading message
call PutChars // Display it call PutChars // Display it
xor di, di // ES:DI has dir entry xor di, di // ES:DI has dir entry
xor dx, dx xor dx, dx
mov ax, word ptr es:[di+20] // Get start cluster high word mov ax, word ptr es:[di+20] // Get start cluster high word
shl eax, 16 shl eax, 16
mov ax, word ptr es:[di+26] // Get start cluster low word mov ax, word ptr es:[di+26] // Get start cluster low word
CheckStartCluster: CheckStartCluster:
cmp eax, 2 // Check and see if the start cluster starts at cluster 2 or above cmp eax, 2 // Check and see if the start cluster starts at cluster 2 or above
jnb CheckEndCluster // If so then continue jnb CheckEndCluster // If so then continue
jmp PrintFileSystemError // If not exit with error jmp PrintFileSystemError // If not exit with error
CheckEndCluster: CheckEndCluster:
cmp eax, HEX(0ffffff8) // Check and see if the start cluster is and end of cluster chain indicator cmp eax, HEX(0ffffff8) // Check and see if the start cluster is and end of cluster chain indicator
jb InitializeLoadSegment // If not then continue jb InitializeLoadSegment // If not then continue
jmp PrintFileSystemError // If so exit with error jmp PrintFileSystemError // If so exit with error
InitializeLoadSegment: InitializeLoadSegment:
mov bx, FREELDR_BASE / 16 mov bx, FREELDR_BASE / 16
mov es, bx mov es, bx
LoadFile: LoadFile:
cmp eax, HEX(0ffffff8) // Check to see if this is the last cluster in the chain cmp eax, HEX(0ffffff8) // Check to see if this is the last cluster in the chain
jae LoadFileDone // If so continue, if not then read the next one jae LoadFileDone // If so continue, if not then read the next one
push eax push eax
xor bx, bx // Load ROSLDR starting at 0000:8000h xor bx, bx // Load ROSLDR starting at 0000:8000h
push es push es
call ReadCluster call ReadCluster
pop es pop es
xor bx, bx xor bx, bx
mov bl, byte ptr BP_REL(SectsPerCluster) mov bl, byte ptr BP_REL(SectsPerCluster)
shl bx, 5 // BX = BX * 512 / 16 shl bx, 5 // BX = BX * 512 / 16
mov ax, es // Increment the load address by mov ax, es // Increment the load address by
add ax, bx // The size of a cluster add ax, bx // The size of a cluster
mov es, ax mov es, ax
pop eax pop eax
push es push es
call GetFatEntry // Get the next entry call GetFatEntry // Get the next entry
pop es pop es
jmp LoadFile // Load the next cluster (if any) jmp LoadFile // Load the next cluster (if any)
LoadFileDone: LoadFileDone:
mov dl, byte ptr BP_REL(BootDrive) // Load boot drive into DL mov dl, byte ptr BP_REL(BootDrive) // Load boot drive into DL
mov dh, byte ptr ds:[BootPartition] // Load boot partition into DH mov dh, byte ptr ds:[BootPartition] // Load boot partition into DH
/* Transfer execution to the bootloader */ /* Transfer execution to the bootloader */
ljmp16 0, FREELDR_BASE ljmp16 0, FREELDR_BASE
@ -431,43 +431,43 @@ LoadFileDone:
// On return EAX has FAT entry for that cluster // On return EAX has FAT entry for that cluster
GetFatEntry: GetFatEntry:
shl eax, 2 // EAX = EAX * 4 (since FAT32 entries are 4 bytes) shl eax, 2 // EAX = EAX * 4 (since FAT32 entries are 4 bytes)
mov ecx, eax // Save this for later in ECX mov ecx, eax // Save this for later in ECX
xor edx, edx xor edx, edx
movzx ebx, word ptr BP_REL(BytesPerSector) movzx ebx, word ptr BP_REL(BytesPerSector)
push ebx push ebx
div ebx // FAT Sector Number = EAX / BytesPerSector div ebx // FAT Sector Number = EAX / BytesPerSector
movzx ebx, word ptr BP_REL(ReservedSectors) movzx ebx, word ptr BP_REL(ReservedSectors)
add eax, ebx // FAT Sector Number += ReservedSectors add eax, ebx // FAT Sector Number += ReservedSectors
mov ebx, dword ptr BP_REL(HiddenSectors) mov ebx, dword ptr BP_REL(HiddenSectors)
add eax, ebx // FAT Sector Number += HiddenSectors add eax, ebx // FAT Sector Number += HiddenSectors
pop ebx pop ebx
dec ebx dec ebx
and ecx,ebx // FAT Offset Within Sector = ECX % BytesPerSector and ecx,ebx // FAT Offset Within Sector = ECX % BytesPerSector
// EAX holds logical FAT sector number // EAX holds logical FAT sector number
// ECX holds FAT entry offset // ECX holds FAT entry offset
// Now we have to check the extended flags // Now we have to check the extended flags
// to see which FAT is the active one // to see which FAT is the active one
// and use it, or if they are mirrored then // and use it, or if they are mirrored then
// no worries // no worries
movzx ebx, word ptr BP_REL(ExtendedFlags) // Get extended flags and put into ebx movzx ebx, word ptr BP_REL(ExtendedFlags) // Get extended flags and put into ebx
and bx, HEX(0f) // Mask off upper 8 bits, now we have active fat in bl and bx, HEX(0f) // Mask off upper 8 bits, now we have active fat in bl
jz LoadFatSector // If fat is mirrored then skip fat calcs jz LoadFatSector // If fat is mirrored then skip fat calcs
cmp bl, byte ptr BP_REL(NumberOfFats) // Compare bl to number of fats cmp bl, byte ptr BP_REL(NumberOfFats) // Compare bl to number of fats
jb GetActiveFatOffset jb GetActiveFatOffset
jmp PrintFileSystemError // If bl is bigger than numfats exit with error jmp PrintFileSystemError // If bl is bigger than numfats exit with error
GetActiveFatOffset: GetActiveFatOffset:
push eax // Save logical FAT sector number push eax // Save logical FAT sector number
mov eax, dword ptr BP_REL(SectorsPerFatBig) // Get the number of sectors occupied by one fat in eax mov eax, dword ptr BP_REL(SectorsPerFatBig) // Get the number of sectors occupied by one fat in eax
mul ebx // Multiplied by the active FAT index we have in ebx mul ebx // Multiplied by the active FAT index we have in ebx
pop edx // Get logical FAT sector number pop edx // Get logical FAT sector number
add eax, edx // Add the current FAT sector offset add eax, edx // Add the current FAT sector offset
LoadFatSector: LoadFatSector:
push ecx push ecx
mov bx, HEX(9000) // We will load it to [9000:0000h] mov bx, HEX(9000) // We will load it to [9000:0000h]
mov es, bx mov es, bx
// EAX holds logical FAT sector number // EAX holds logical FAT sector number
@ -482,18 +482,18 @@ LoadFatSector:
LoadFatSectorAlreadyLoaded: LoadFatSectorAlreadyLoaded:
pop ecx pop ecx
mov eax, dword ptr es:[ecx] // Get FAT entry mov eax, dword ptr es:[ecx] // Get FAT entry
and eax, HEX(0fffffff) // Mask off reserved bits and eax, HEX(0fffffff) // Mask off reserved bits
ret ret
FatSectorInCache: // This variable tells us which sector we currently have in memory FatSectorInCache: // This variable tells us which sector we currently have in memory
.long HEX(0ffffffff) // There is no need to re-read the same sector if we don't have to .long HEX(0ffffffff) // There is no need to re-read the same sector if we don't have to
// Reads cluster number in EAX into [ES:0000] // Reads cluster number in EAX into [ES:0000]
ReadCluster: ReadCluster:
// StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors// // StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
dec eax dec eax
dec eax dec eax
@ -508,7 +508,7 @@ ReadCluster:
add eax, ebx add eax, ebx
add eax, dword ptr BP_REL(HiddenSectors) add eax, dword ptr BP_REL(HiddenSectors)
pop ebx pop ebx
add eax, ebx // EAX now contains the logical sector number of the cluster add eax, ebx // EAX now contains the logical sector number of the cluster
xor bx, bx // We will load it to [ES:0000], ES loaded before function call xor bx, bx // We will load it to [ES:0000], ES loaded before function call
movzx cx, byte ptr BP_REL(SectsPerCluster) movzx cx, byte ptr BP_REL(SectsPerCluster)
call ReadSectors call ReadSectors
@ -517,10 +517,10 @@ ReadCluster:
// Displays a file not found error message // Displays a file not found error message
// And reboots // And reboots
PrintFileNotFound: PrintFileNotFound:
mov si, offset msgFreeLdr // FreeLdr not found message mov si, offset msgFreeLdr // FreeLdr not found message
call PutChars // Display it call PutChars // Display it
mov si, offset msgAnyKey // Press any key message mov si, offset msgAnyKey // Press any key message
call PutChars // Display it call PutChars // Display it
jmp Reboot jmp Reboot

View file

@ -12,109 +12,109 @@ start:
jmp short main jmp short main
nop nop
OEMName db 'FrLdr1.0' OEMName db 'FrLdr1.0'
BytesPerSector dw 512 BytesPerSector dw 512
SectsPerCluster db 0 SectsPerCluster db 0
ReservedSectors dw 32 ReservedSectors dw 32
NumberOfFats db 2 NumberOfFats db 2
MaxRootEntries dw 0 ; Always zero for FAT32 volumes MaxRootEntries dw 0 ; Always zero for FAT32 volumes
TotalSectors dw 0 ; Always zero for FAT32 volumes TotalSectors dw 0 ; Always zero for FAT32 volumes
MediaDescriptor db 0f8h MediaDescriptor db 0f8h
SectorsPerFat dw 0 ; Always zero for FAT32 volumes SectorsPerFat dw 0 ; Always zero for FAT32 volumes
SectorsPerTrack dw 0 SectorsPerTrack dw 0
NumberOfHeads dw 0 NumberOfHeads dw 0
HiddenSectors dd 0 HiddenSectors dd 0
TotalSectorsBig dd 0 TotalSectorsBig dd 0
; FAT32 Inserted Info ; FAT32 Inserted Info
SectorsPerFatBig dd 0 SectorsPerFatBig dd 0
ExtendedFlags dw 0 ExtendedFlags dw 0
FSVersion dw 0 FSVersion dw 0
RootDirStartCluster dd 0 RootDirStartCluster dd 0
FSInfoSector dw 0 FSInfoSector dw 0
BackupBootSector dw 6 BackupBootSector dw 6
Reserved1 times 12 db 0 Reserved1 times 12 db 0
; End FAT32 Inserted Info ; End FAT32 Inserted Info
BootDrive db 0 BootDrive db 0
Reserved db 0 Reserved db 0
ExtendSig db 29h ExtendSig db 29h
SerialNumber dd 00000000h SerialNumber dd 00000000h
VolumeLabel db 'NO NAME ' VolumeLabel db 'NO NAME '
FileSystem db 'FAT32 ' FileSystem db 'FAT32 '
main: main:
xor ax,ax ; Setup segment registers xor ax,ax ; Setup segment registers
mov ds,ax ; Make DS correct mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct mov es,ax ; Make ES correct
mov ss,ax ; Make SS correct mov ss,ax ; Make SS correct
mov bp,7c00h mov bp,7c00h
mov sp,7c00h ; Setup a stack mov sp,7c00h ; Setup a stack
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
jne CheckSectorsPerFat jne CheckSectorsPerFat
mov [BYTE bp+BootDrive],dl ; Save the boot drive mov [BYTE bp+BootDrive],dl ; Save the boot drive
CheckSectorsPerFat: CheckSectorsPerFat:
cmp WORD [BYTE bp+SectorsPerFat],byte 0x00 ; Check the old 16-bit value of SectorsPerFat cmp WORD [BYTE bp+SectorsPerFat],byte 0x00 ; Check the old 16-bit value of SectorsPerFat
jnz CheckFailed ; If it is non-zero then exit with an error jnz CheckFailed ; If it is non-zero then exit with an error
CheckTotalSectors: ; Check the old 16-bit value of TotalSectors & MaxRootEntries CheckTotalSectors: ; Check the old 16-bit value of TotalSectors & MaxRootEntries
cmp DWORD [BYTE bp+MaxRootEntries],byte 0x00; by comparing the DWORD at offset MaxRootEntries to zero cmp DWORD [BYTE bp+MaxRootEntries],byte 0x00; by comparing the DWORD at offset MaxRootEntries to zero
jnz CheckFailed ; If it is non-zero then exit with an error jnz CheckFailed ; If it is non-zero then exit with an error
CheckFileSystemVersion: CheckFileSystemVersion:
cmp WORD [BYTE bp+FSVersion],byte 0x00 ; Check the file system version word cmp WORD [BYTE bp+FSVersion],byte 0x00 ; Check the file system version word
jna GetDriveParameters ; It is zero, so continue jna GetDriveParameters ; It is zero, so continue
CheckFailed: CheckFailed:
jmp PrintFileSystemError ; If it is not zero then exit with an error jmp PrintFileSystemError ; If it is not zero then exit with an error
GetDriveParameters: GetDriveParameters:
mov ax,0800h mov ax,0800h
mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl
int 13h ; Request drive parameters from the bios int 13h ; Request drive parameters from the bios
jnc CalcDriveSize ; If the call succeeded then calculate the drive size jnc CalcDriveSize ; If the call succeeded then calculate the drive size
; If we get here then the call to the BIOS failed ; If we get here then the call to the BIOS failed
; so just set CHS equal to the maximum addressable ; so just set CHS equal to the maximum addressable
; size ; size
mov cx,0ffffh mov cx,0ffffh
mov dh,cl mov dh,cl
CalcDriveSize: CalcDriveSize:
; Now that we have the drive geometry ; Now that we have the drive geometry
; lets calculate the drive size ; lets calculate the drive size
mov bl,ch ; Put the low 8-bits of the cylinder count into BL mov bl,ch ; Put the low 8-bits of the cylinder count into BL
mov bh,cl ; Put the high 2-bits in BH mov bh,cl ; Put the high 2-bits in BH
shr bh,6 ; Shift them into position, now BX contains the cylinder count shr bh,6 ; Shift them into position, now BX contains the cylinder count
and cl,3fh ; Mask off cylinder bits from sector count and cl,3fh ; Mask off cylinder bits from sector count
; CL now contains sectors per track and DH contains head count ; CL now contains sectors per track and DH contains head count
movzx eax,dh ; Move the heads into EAX movzx eax,dh ; Move the heads into EAX
movzx ebx,bx ; Move the cylinders into EBX movzx ebx,bx ; Move the cylinders into EBX
movzx ecx,cl ; Move the sectors per track into ECX movzx ecx,cl ; Move the sectors per track into ECX
inc eax ; Make it one based because the bios returns it zero based inc eax ; Make it one based because the bios returns it zero based
inc ebx ; Make the cylinder count one based also inc ebx ; Make the cylinder count one based also
mul ecx ; Multiply heads with the sectors per track, result in edx:eax mul ecx ; Multiply heads with the sectors per track, result in edx:eax
mul ebx ; Multiply the cylinders with (heads * sectors) [stored in edx:eax already] mul ebx ; Multiply the cylinders with (heads * sectors) [stored in edx:eax already]
; We now have the total number of sectors as reported ; We now have the total number of sectors as reported
; by the bios in eax, so store it in our variable ; by the bios in eax, so store it in our variable
mov [BiosCHSDriveSize],eax mov [BiosCHSDriveSize],eax
LoadExtraBootCode: LoadExtraBootCode:
; First we have to load our extra boot code at ; First we have to load our extra boot code at
; sector 14 into memory at [0000:7e00h] ; sector 14 into memory at [0000:7e00h]
mov eax,0eh mov eax,0eh
add eax,DWORD [BYTE bp+HiddenSectors] ; Add the number of hidden sectors add eax,DWORD [BYTE bp+HiddenSectors] ; Add the number of hidden sectors
mov cx,1 mov cx,1
xor bx,bx xor bx,bx
mov es,bx ; Read sector to [0000:7e00h] mov es,bx ; Read sector to [0000:7e00h]
mov bx,7e00h mov bx,7e00h
call ReadSectors call ReadSectors
jmp StartSearch jmp StartSearch
@ -122,110 +122,110 @@ LoadExtraBootCode:
; EAX has logical sector number to read ; EAX has logical sector number to read
; CX has number of sectors to read ; CX has number of sectors to read
ReadSectors: ReadSectors:
cmp eax,DWORD [BiosCHSDriveSize] ; Check if they are reading a sector outside CHS range cmp eax,DWORD [BiosCHSDriveSize] ; Check if they are reading a sector outside CHS range
jae ReadSectorsLBA ; Yes - go to the LBA routine jae ReadSectorsLBA ; Yes - go to the LBA routine
; If at all possible we want to use LBA routines because ; If at all possible we want to use LBA routines because
; They are optimized to read more than 1 sector per read ; They are optimized to read more than 1 sector per read
pushad ; Save logical sector number & sector count pushad ; Save logical sector number & sector count
CheckInt13hExtensions: ; Now check if this computer supports extended reads CheckInt13hExtensions: ; Now check if this computer supports extended reads
mov ah,0x41 ; AH = 41h mov ah,0x41 ; AH = 41h
mov bx,0x55aa ; BX = 55AAh mov bx,0x55aa ; BX = 55AAh
mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh) mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh)
int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK
jc ReadSectorsCHS ; CF set on error (extensions not supported) jc ReadSectorsCHS ; CF set on error (extensions not supported)
cmp bx,0xaa55 ; BX = AA55h if installed cmp bx,0xaa55 ; BX = AA55h if installed
jne ReadSectorsCHS jne ReadSectorsCHS
test cl,1 ; CX = API subset support bitmap test cl,1 ; CX = API subset support bitmap
jz ReadSectorsCHS ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported jz ReadSectorsCHS ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
popad ; Restore sector count & logical sector number popad ; Restore sector count & logical sector number
ReadSectorsLBA: ReadSectorsLBA:
pushad ; Save logical sector number & sector count pushad ; Save logical sector number & sector count
cmp cx,64 ; Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64 cmp cx,64 ; Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64
jbe ReadSectorsSetupDiskAddressPacket ; If we are reading less than 65 sectors then just do the read jbe ReadSectorsSetupDiskAddressPacket ; If we are reading less than 65 sectors then just do the read
mov cx,64 ; Otherwise read only 64 sectors on this loop iteration mov cx,64 ; Otherwise read only 64 sectors on this loop iteration
ReadSectorsSetupDiskAddressPacket: ReadSectorsSetupDiskAddressPacket:
mov [LBASectorsRead],cx mov [LBASectorsRead],cx
o32 push byte 0 o32 push byte 0
push eax ; Put 64-bit logical block address on stack push eax ; Put 64-bit logical block address on stack
push es ; Put transfer segment on stack push es ; Put transfer segment on stack
push bx ; Put transfer offset on stack push bx ; Put transfer offset on stack
push cx ; Set transfer count push cx ; Set transfer count
push byte 0x10 ; Set size of packet to 10h push byte 0x10 ; Set size of packet to 10h
mov si,sp ; Setup disk address packet on stack mov si,sp ; Setup disk address packet on stack
mov dl,[BYTE bp+BootDrive] ; Drive number mov dl,[BYTE bp+BootDrive] ; Drive number
mov ah,42h ; Int 13h, AH = 42h - Extended Read mov ah,42h ; Int 13h, AH = 42h - Extended Read
int 13h ; Call BIOS int 13h ; Call BIOS
jc PrintDiskError ; If the read failed then abort jc PrintDiskError ; If the read failed then abort
add sp,byte 0x10 ; Remove disk address packet from stack add sp,byte 0x10 ; Remove disk address packet from stack
popad ; Restore sector count & logical sector number popad ; Restore sector count & logical sector number
push bx push bx
mov ebx,DWORD [LBASectorsRead] mov ebx,DWORD [LBASectorsRead]
add eax,ebx ; Increment sector to read add eax,ebx ; Increment sector to read
shl ebx,5 shl ebx,5
mov dx,es mov dx,es
add dx,bx ; Setup read buffer for next sector add dx,bx ; Setup read buffer for next sector
mov es,dx mov es,dx
pop bx pop bx
sub cx,[LBASectorsRead] sub cx,[LBASectorsRead]
jnz ReadSectorsLBA ; Read next sector jnz ReadSectorsLBA ; Read next sector
ret ret
LBASectorsRead: LBASectorsRead:
dd 0 dd 0
; Reads logical sectors into [ES:BX] ; Reads logical sectors into [ES:BX]
; EAX has logical sector number to read ; EAX has logical sector number to read
; CX has number of sectors to read ; CX has number of sectors to read
ReadSectorsCHS: ReadSectorsCHS:
popad ; Get logical sector number & sector count off stack popad ; Get logical sector number & sector count off stack
ReadSectorsCHSLoop: ReadSectorsCHSLoop:
pushad pushad
xor edx,edx xor edx,edx
movzx ecx,WORD [BYTE bp+SectorsPerTrack] movzx ecx,WORD [BYTE bp+SectorsPerTrack]
div ecx ; Divide logical by SectorsPerTrack div ecx ; Divide logical by SectorsPerTrack
inc dl ; Sectors numbering starts at 1 not 0 inc dl ; Sectors numbering starts at 1 not 0
mov cl,dl ; Sector in CL mov cl,dl ; Sector in CL
mov edx,eax mov edx,eax
shr edx,16 shr edx,16
div WORD [BYTE bp+NumberOfHeads] ; Divide logical by number of heads div WORD [BYTE bp+NumberOfHeads] ; Divide logical by number of heads
mov dh,dl ; Head in DH mov dh,dl ; Head in DH
mov dl,[BYTE bp+BootDrive] ; Drive number in DL mov dl,[BYTE bp+BootDrive] ; Drive number in DL
mov ch,al ; Cylinder in CX mov ch,al ; Cylinder in CX
ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits
ror ah,1 ; in CL shifted to bits 6 & 7 ror ah,1 ; in CL shifted to bits 6 & 7
or cl,ah ; Or with sector number or cl,ah ; Or with sector number
mov ax,0201h mov ax,0201h
int 13h ; DISK - READ SECTORS INTO MEMORY int 13h ; DISK - READ SECTORS INTO MEMORY
; AL = number of sectors to read, CH = track, CL = sector ; AL = number of sectors to read, CH = track, CL = sector
; DH = head, DL = drive, ES:BX -> buffer to fill ; DH = head, DL = drive, ES:BX -> buffer to fill
; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read ; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
jc PrintDiskError ; If the read failed then abort jc PrintDiskError ; If the read failed then abort
popad popad
inc eax ; Increment Sector to Read inc eax ; Increment Sector to Read
mov dx,es mov dx,es
add dx,byte 20h ; Increment read buffer for next sector add dx,byte 20h ; Increment read buffer for next sector
mov es,dx mov es,dx
loop ReadSectorsCHSLoop ; Read next sector loop ReadSectorsCHSLoop ; Read next sector
ret ret
@ -235,23 +235,23 @@ ReadSectorsCHSLoop:
; Displays a disk error message ; Displays a disk error message
; And reboots ; And reboots
PrintDiskError: PrintDiskError:
mov si,msgDiskError ; Bad boot disk message mov si,msgDiskError ; Bad boot disk message
call PutChars ; Display it call PutChars ; Display it
jmp Reboot jmp Reboot
; Displays a file system error message ; Displays a file system error message
; And reboots ; And reboots
PrintFileSystemError: PrintFileSystemError:
mov si,msgFileSystemError ; FreeLdr not found message mov si,msgFileSystemError ; FreeLdr not found message
call PutChars ; Display it call PutChars ; Display it
Reboot: Reboot:
mov si,msgAnyKey ; Press any key message mov si,msgAnyKey ; Press any key message
call PutChars ; Display it call PutChars ; Display it
xor ax,ax xor ax,ax
int 16h ; Wait for a keypress int 16h ; Wait for a keypress
int 19h ; Reboot int 19h ; Reboot
PutChars: PutChars:
lodsb lodsb
@ -268,14 +268,14 @@ Done:
BiosCHSDriveSize dd 0 BiosCHSDriveSize dd 0
msgDiskError db 'Disk error',0dh,0ah,0 msgDiskError db 'Disk error',0dh,0ah,0
msgFileSystemError db 'File system error',0dh,0ah,0 msgFileSystemError db 'File system error',0dh,0ah,0
msgAnyKey db 'Press any key to restart',0dh,0ah,0 msgAnyKey db 'Press any key to restart',0dh,0ah,0
times 509-($-$$) db 0 ; Pad to 509 bytes times 509-($-$$) db 0 ; Pad to 509 bytes
BootPartition: BootPartition:
db 0 db 0
BootSignature: BootSignature:
dw 0aa55h ; BootSector signature dw 0aa55h ; BootSector signature
@ -295,22 +295,22 @@ BootSignature:
StartSearch: StartSearch:
; Now we must get the first cluster of the root directory ; Now we must get the first cluster of the root directory
mov eax,DWORD [BYTE bp+RootDirStartCluster] mov eax,DWORD [BYTE bp+RootDirStartCluster]
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
jb ContinueSearch ; If not continue, if so then we didn't find freeldr.sys jb ContinueSearch ; If not continue, if so then we didn't find freeldr.sys
jmp PrintFileNotFound jmp PrintFileNotFound
ContinueSearch: ContinueSearch:
mov bx,2000h mov bx,2000h
mov es,bx ; Read cluster to [2000:0000h] mov es,bx ; Read cluster to [2000:0000h]
call ReadCluster ; Read the cluster call ReadCluster ; Read the cluster
; Now we have to find our way through the root directory to ; Now we have to find our way through the root directory to
; The OSLOADER.SYS file ; The FREELDR.SYS file
xor bx,bx xor bx,bx
mov bl,[BYTE bp+SectsPerCluster] mov bl,[BYTE bp+SectsPerCluster]
shl bx,4 ; BX = BX * 512 / 32 shl bx,4 ; BX = BX * 512 / 32
mov ax,2000h ; We loaded at 2000:0000 mov ax,2000h ; We loaded at 2000:0000
mov es,ax mov es,ax
xor di,di xor di,di
mov si,filename mov si,filename
@ -333,157 +333,157 @@ FindFile:
dec bx ; Keep searching till we run out of dir entries dec bx ; Keep searching till we run out of dir entries
jnz FindFile ; Last entry? jnz FindFile ; Last entry?
; Get the next root dir cluster and try again until we run out of clusters ; Get the next root dir cluster and try again until we run out of clusters
mov eax,DWORD [BYTE bp+RootDirStartCluster] mov eax,DWORD [BYTE bp+RootDirStartCluster]
call GetFatEntry call GetFatEntry
mov [BYTE bp+RootDirStartCluster],eax mov [BYTE bp+RootDirStartCluster],eax
jmp StartSearch jmp StartSearch
FoundFile: FoundFile:
; Display "Loading FreeLoader..." message ; Display "Loading FreeLoader..." message
mov si,msgLoading ; Loading message mov si,msgLoading ; Loading message
call PutChars ; Display it call PutChars ; Display it
xor di,di ; ES:DI has dir entry xor di,di ; ES:DI has dir entry
xor dx,dx xor dx,dx
mov ax,WORD [es:di+14h] ; Get start cluster high word mov ax,WORD [es:di+14h] ; Get start cluster high word
shl eax,16 shl eax,16
mov ax,WORD [es:di+1ah] ; Get start cluster low word mov ax,WORD [es:di+1ah] ; Get start cluster low word
CheckStartCluster: CheckStartCluster:
cmp eax,2 ; Check and see if the start cluster starts at cluster 2 or above cmp eax,2 ; Check and see if the start cluster starts at cluster 2 or above
jnb CheckEndCluster ; If so then continue jnb CheckEndCluster ; If so then continue
jmp PrintFileSystemError ; If not exit with error jmp PrintFileSystemError ; If not exit with error
CheckEndCluster: CheckEndCluster:
cmp eax,0ffffff8h ; Check and see if the start cluster is and end of cluster chain indicator cmp eax,0ffffff8h ; Check and see if the start cluster is and end of cluster chain indicator
jb InitializeLoadSegment ; If not then continue jb InitializeLoadSegment ; If not then continue
jmp PrintFileSystemError ; If so exit with error jmp PrintFileSystemError ; If so exit with error
InitializeLoadSegment: InitializeLoadSegment:
mov bx,800h mov bx,800h
mov es,bx mov es,bx
LoadFile: LoadFile:
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
jae LoadFileDone ; If so continue, if not then read the next one jae LoadFileDone ; If so continue, if not then read the next one
push eax push eax
xor bx,bx ; Load ROSLDR starting at 0000:8000h xor bx,bx ; Load ROSLDR starting at 0000:8000h
push es push es
call ReadCluster call ReadCluster
pop es pop es
xor bx,bx xor bx,bx
mov bl,[BYTE bp+SectsPerCluster] mov bl,[BYTE bp+SectsPerCluster]
shl bx,5 ; BX = BX * 512 / 16 shl bx,5 ; BX = BX * 512 / 16
mov ax,es ; Increment the load address by mov ax,es ; Increment the load address by
add ax,bx ; The size of a cluster add ax,bx ; The size of a cluster
mov es,ax mov es,ax
pop eax pop eax
push es push es
call GetFatEntry ; Get the next entry call GetFatEntry ; Get the next entry
pop es pop es
jmp LoadFile ; Load the next cluster (if any) jmp LoadFile ; Load the next cluster (if any)
LoadFileDone: LoadFileDone:
mov dl,[BYTE bp+BootDrive] ; Load boot drive into DL mov dl,[BYTE bp+BootDrive] ; Load boot drive into DL
mov dh,[BootPartition] ; Load boot partition into DH mov dh,[BootPartition] ; Load boot partition into DH
push 0 ; push segment (0x0000) push 0 ; push segment (0x0000)
mov eax, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax mov eax, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax
add eax, 0x8000 ; RVA -> VA add eax, 0x8000 ; RVA -> VA
push ax ; push offset push ax ; push offset
retf ; Transfer control to FreeLoader retf ; Transfer control to FreeLoader
; Returns the FAT entry for a given cluster number ; Returns the FAT entry for a given cluster number
; On entry EAX has cluster number ; On entry EAX has cluster number
; On return EAX has FAT entry for that cluster ; On return EAX has FAT entry for that cluster
GetFatEntry: GetFatEntry:
shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes) shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes)
mov ecx,eax ; Save this for later in ECX mov ecx,eax ; Save this for later in ECX
xor edx,edx xor edx,edx
movzx ebx,WORD [BYTE bp+BytesPerSector] movzx ebx,WORD [BYTE bp+BytesPerSector]
push ebx push ebx
div ebx ; FAT Sector Number = EAX / BytesPerSector div ebx ; FAT Sector Number = EAX / BytesPerSector
movzx ebx,WORD [BYTE bp+ReservedSectors] movzx ebx,WORD [BYTE bp+ReservedSectors]
add eax,ebx ; FAT Sector Number += ReservedSectors add eax,ebx ; FAT Sector Number += ReservedSectors
mov ebx,DWORD [BYTE bp+HiddenSectors] mov ebx,DWORD [BYTE bp+HiddenSectors]
add eax,ebx ; FAT Sector Number += HiddenSectors add eax,ebx ; FAT Sector Number += HiddenSectors
pop ebx pop ebx
dec ebx dec ebx
and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector
; EAX holds logical FAT sector number ; EAX holds logical FAT sector number
; ECX holds FAT entry offset ; ECX holds FAT entry offset
; Now we have to check the extended flags ; Now we have to check the extended flags
; to see which FAT is the active one ; to see which FAT is the active one
; and use it, or if they are mirrored then ; and use it, or if they are mirrored then
; no worries ; no worries
movzx ebx,WORD [BYTE bp+ExtendedFlags] ; Get extended flags and put into ebx movzx ebx,WORD [BYTE bp+ExtendedFlags] ; Get extended flags and put into ebx
and bx,0x0f ; Mask off upper 8 bits, now we have active fat in bl and bx,0x0f ; Mask off upper 8 bits, now we have active fat in bl
jz LoadFatSector ; If fat is mirrored then skip fat calcs jz LoadFatSector ; If fat is mirrored then skip fat calcs
cmp bl,[BYTE bp+NumberOfFats] ; Compare bl to number of fats cmp bl,[BYTE bp+NumberOfFats] ; Compare bl to number of fats
jb GetActiveFatOffset jb GetActiveFatOffset
jmp PrintFileSystemError ; If bl is bigger than numfats exit with error jmp PrintFileSystemError ; If bl is bigger than numfats exit with error
GetActiveFatOffset: GetActiveFatOffset:
push eax ; Save logical FAT sector number push eax ; Save logical FAT sector number
mov eax,[BYTE bp+SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax mov eax,[BYTE bp+SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax
mul ebx ; Multiplied by the active FAT index we have in ebx mul ebx ; Multiplied by the active FAT index we have in ebx
pop edx ; Get logical FAT sector number pop edx ; Get logical FAT sector number
add eax,edx ; Add the current FAT sector offset add eax,edx ; Add the current FAT sector offset
LoadFatSector: LoadFatSector:
push ecx push ecx
; EAX holds logical FAT sector number ; EAX holds logical FAT sector number
; Check if we have already loaded it ; Check if we have already loaded it
cmp eax,DWORD [FatSectorInCache] cmp eax,DWORD [FatSectorInCache]
je LoadFatSectorAlreadyLoaded je LoadFatSectorAlreadyLoaded
mov DWORD [FatSectorInCache],eax mov DWORD [FatSectorInCache],eax
mov bx,9000h mov bx,9000h
mov es,bx mov es,bx
xor bx,bx ; We will load it to [9000:0000h] xor bx,bx ; We will load it to [9000:0000h]
mov cx,1 mov cx,1
call ReadSectors call ReadSectors
LoadFatSectorAlreadyLoaded: LoadFatSectorAlreadyLoaded:
mov bx,9000h mov bx,9000h
mov es,bx mov es,bx
pop ecx pop ecx
mov eax,DWORD [es:ecx] ; Get FAT entry mov eax,DWORD [es:ecx] ; Get FAT entry
and eax,0fffffffh ; Mask off reserved bits and eax,0fffffffh ; Mask off reserved bits
ret ret
FatSectorInCache: ; This variable tells us which sector we currently have in memory FatSectorInCache: ; This variable tells us which sector we currently have in memory
dd 0ffffffffh ; There is no need to re-read the same sector if we don't have to dd 0ffffffffh ; There is no need to re-read the same sector if we don't have to
; Reads cluster number in EAX into [ES:0000] ; Reads cluster number in EAX into [ES:0000]
ReadCluster: ReadCluster:
; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors; ; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
dec eax dec eax
dec eax dec eax
xor edx,edx xor edx,edx
movzx ebx,BYTE [BYTE bp+SectsPerCluster] movzx ebx,BYTE [BYTE bp+SectsPerCluster]
mul ebx mul ebx
push eax push eax
xor edx,edx xor edx,edx
movzx eax,BYTE [BYTE bp+NumberOfFats] movzx eax,BYTE [BYTE bp+NumberOfFats]
mul DWORD [BYTE bp+SectorsPerFatBig] mul DWORD [BYTE bp+SectorsPerFatBig]
movzx ebx,WORD [BYTE bp+ReservedSectors] movzx ebx,WORD [BYTE bp+ReservedSectors]
add eax,ebx add eax,ebx
add eax,DWORD [BYTE bp+HiddenSectors] add eax,DWORD [BYTE bp+HiddenSectors]
pop ebx pop ebx
add eax,ebx ; EAX now contains the logical sector number of the cluster add eax,ebx ; EAX now contains the logical sector number of the cluster
xor bx,bx ; We will load it to [ES:0000], ES loaded before function call xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
movzx cx,BYTE [BYTE bp+SectsPerCluster] movzx cx,BYTE [BYTE bp+SectsPerCluster]
call ReadSectors call ReadSectors
ret ret
; Displays a file not found error message ; Displays a file not found error message
@ -494,7 +494,7 @@ PrintFileNotFound:
mov si,msgAnyKey ; Press any key message mov si,msgAnyKey ; Press any key message
call PutChars ; Display it call PutChars ; Display it
jmp Reboot jmp Reboot
msgFreeLdr db 'freeldr.sys not found',0dh,0ah,0 msgFreeLdr db 'freeldr.sys not found',0dh,0ah,0
filename db 'FREELDR SYS' filename db 'FREELDR SYS'

View file

@ -1,8 +1,8 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Bootsector * PROJECT: ReactOS Bootsector
* FILE: boot/freeldr/bootsect/fatx.S * FILE: boot/freeldr/bootsect/faty.S
* PURPOSE: Combined FAT16 and FAT32 boot sector * PURPOSE: Combined FAT12, FAT16 and FAT32 boot sector
* PROGRAMMERS: Brian Palmer * PROGRAMMERS: Brian Palmer
* Timo Kreuzer * Timo Kreuzer
*/ */