diff --git a/reactos/boot/freeldr/bootsect/CMakeLists.txt b/reactos/boot/freeldr/bootsect/CMakeLists.txt index 5612d9a3b94..dcd44e3d0bf 100644 --- a/reactos/boot/freeldr/bootsect/CMakeLists.txt +++ b/reactos/boot/freeldr/bootsect/CMakeLists.txt @@ -4,13 +4,12 @@ if(ARCH MATCHES i386 OR ARCH MATCHES amd64) CreateBootSectorTarget2(dosmbr ${CMAKE_CURRENT_SOURCE_DIR}/dosmbr.S ${CMAKE_CURRENT_BINARY_DIR}/dosmbr.bin 7c00) #CreateBootSectorTarget2(ext2 ${CMAKE_CURRENT_SOURCE_DIR}/ext2.S ${CMAKE_CURRENT_BINARY_DIR}/ext2.bin 0) CreateBootSectorTarget2(fat32 ${CMAKE_CURRENT_SOURCE_DIR}/fat32.S ${CMAKE_CURRENT_BINARY_DIR}/fat32.bin 7c00) -#CreateBootSectorTarget2(fat ${CMAKE_CURRENT_SOURCE_DIR}/fat.S ${CMAKE_CURRENT_BINARY_DIR}/fat.bin 0) +CreateBootSectorTarget2(fat ${CMAKE_CURRENT_SOURCE_DIR}/fat.S ${CMAKE_CURRENT_BINARY_DIR}/fat.bin 7c00) CreateBootSectorTarget2(isoboot ${CMAKE_CURRENT_SOURCE_DIR}/isoboot.S ${CMAKE_CURRENT_BINARY_DIR}/isoboot.bin 7000) CreateBootSectorTarget2(isobtrt ${CMAKE_CURRENT_SOURCE_DIR}/isobtrt.S ${CMAKE_CURRENT_BINARY_DIR}/isobtrt.bin 7000) if(NOT MSVC) CreateBootSectorTarget(ext2 ${CMAKE_CURRENT_SOURCE_DIR}/ext2.asm ${CMAKE_CURRENT_BINARY_DIR}/ext2.bin 0) -CreateBootSectorTarget(fat ${CMAKE_CURRENT_SOURCE_DIR}/fat.asm ${CMAKE_CURRENT_BINARY_DIR}/fat.bin 0) endif() add_cd_file(TARGET dosmbr DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/dosmbr.bin FOR all) diff --git a/reactos/boot/freeldr/bootsect/fat.S b/reactos/boot/freeldr/bootsect/fat.S new file mode 100644 index 00000000000..22b1b2d7d17 --- /dev/null +++ b/reactos/boot/freeldr/bootsect/fat.S @@ -0,0 +1,433 @@ +// FAT.ASM +// FAT12/16 Boot Sector +// Copyright (c) 1998, 2001, 2002 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:7BF2 so that the first +// WORD pushed will be placed at 0000:7BF0 +// +// The DWORD at 0000:7BFC or BP-04h is the logical +// sector number of the start of the data area. +// +// The DWORD at 0000:7BF8 or BP-08h is the total +// sector count of the boot drive as reported by +// the computers bios. +// +// The WORD at 0000:7BF6 or BP-0ah is the offset +// of the ReadSectors function in the boot sector. +// +// The WORD at 0000:7BF4 or BP-0ch is the offset +// of the ReadCluster function in the boot sector. +// +// The WORD at 0000:7BF2 or BP-0eh is the offset +// of the PutChars function in the boot sector. +// +// When it locates freeldr.sys on the disk it will +// load the first sector of the file to 0000:8000 +// 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. + +#include + +#define BP_REL(x) [bp+x-offset start] + +DataAreaStartHigh = 2 +DataAreaStartLow = 4 +BiosCHSDriveSizeHigh = 6 +BiosCHSDriveSizeLow = 8 +BiosCHSDriveSize = 8 +ReadSectorsOffset = 10 +ReadClusterOffset = 12 +PutCharsOffset = 14 +BootSectorStackTop = HEX(7c00) - 16 + + +// org 7c00h + +.code16 + +start: + jmp main + nop + +OEMName: + .ascii "FrLdr1.0" +BytesPerSector: + .word 512 +SectsPerCluster: + .byte 1 +ReservedSectors: + .word 1 +NumberOfFats: + .byte 2 +MaxRootEntries: + .word 224 +TotalSectors: + .word 2880 +MediaDescriptor: + .byte HEX(0f0) +SectorsPerFat: + .word 9 +SectorsPerTrack: + .word 18 +NumberOfHeads: + .word 2 +HiddenSectors: + .long 0 +TotalSectorsBig: + .long 0 +BootDrive: + .byte HEX(0ff) +Reserved: + .byte 0 +ExtendSig: + .byte HEX(29) +SerialNumber: + .long 00000000 +VolumeLabel: + .ascii "NO NAME " +FileSystem: + .ascii "FAT12 " + +main: + xor ax, ax + mov ss, ax + mov bp, HEX(7c00) + mov sp, BootSectorStackTop // Setup a stack + mov ds, ax // Make DS 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 + jne GetDriveParameters + + mov byte ptr BP_REL(BootDrive), dl // Save the boot drive + + +GetDriveParameters: + mov ah, 8 + mov dl, byte ptr BP_REL(BootDrive) // Get boot drive in dl + int HEX(13) // Request drive parameters from the bios + jnc CalcDriveSize // If the call succeeded then calculate the drive size + + // If we get here then the call to the BIOS failed + // so just set CHS equal to the maximum addressable + // size + mov cx, HEX(0ffff) + mov dh, cl + +CalcDriveSize: + // Now that we have the drive geometry + // lets calculate the drive size + mov bl, ch // Put the low 8-bits of the cylinder count into BL + mov bh, cl // Put the high 2-bits in BH + shr bh, 6 // Shift them into position, now BX contains the cylinder count + and cl, HEX(3f) // Mask off cylinder bits from sector count + // CL now contains sectors per track and DH contains head count + movzx eax, dh // Move the heads into EAX + movzx ebx, bx // Move the cylinders into EBX + movzx ecx, cl // Move the sectors per track into ECX + inc eax // Make it one based because the bios returns it zero based + inc ebx // Make the cylinder count one based also + 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] + + // We now have the total number of sectors as reported + // by the bios in eax, so store it in our variable + mov dword ptr [bp - BiosCHSDriveSize], eax + + + // Now we must find our way to the first sector of the root directory + xor ax, ax + xor cx, cx + mov al, byte ptr BP_REL(NumberOfFats) // Number of fats + mul word ptr BP_REL(SectorsPerFat) // Times sectors per fat + add ax, word ptr BP_REL(HiddenSectors) + 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 + adc dx, cx // Add carry bit + 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 si, word ptr BP_REL(MaxRootEntries) // Get number of root dir entries in SI + pusha // Save 32-bit logical start sector of root dir + // DX:AX now has the number of the starting sector of the root directory + + // Now calculate the size of the root directory + xor dx, dx + mov ax, 32 // Size of dir entry + mul si // Times the number of entries + mov bx, word ptr BP_REL(BytesPerSector) + add ax, bx + dec ax + div bx // Divided by the size of a sector + // 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 + adc word ptr [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 + +LoadRootDirSector: + mov bx, HEX(7e0) // We will load the root directory sector + mov es, bx // Right after the boot sector in memory + xor bx, bx // We will load it to [0000:7e00h] + xor cx, cx // Zero out CX + inc cx // Now increment it to 1, we are reading one sector + xor di, di // Zero out di + push es // Save ES because it will get incremented by 20h + call ReadSectors // Read the first sector of the root directory + pop es // Restore ES (ES:DI = 07E0:0000) + +SearchRootDirSector: + 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 + pusha // Save all registers + 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 + repe cmpsb // Compare this directory entry against 'FREELDR SYS' + popa // Restore all the registers + jz FoundFreeLoader // If we found it then jump + dec si // SI holds MaxRootEntries, subtract one + jz ErrBoot // If we are out of root dir entries then reboot + 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) + jc SearchRootDirSector // If DI is less than 512 loop again + jmp short LoadRootDirSector // Didn't find FREELDR.SYS in this directory sector, try again + +FoundFreeLoader: + // We found freeldr.sys on the disk + // so we need to load the first 512 + // bytes of it to 0000:8000 + // ES:DI has dir entry (ES:DI == 07E0:XXXX) + mov ax, word ptr es:[di + HEX(1a)] // Get start cluster + push ax // Save start cluster + push HEX(800) // Put 800h on the stack and load it + pop es // Into ES so that we load the cluster at 0000:8000 + call ReadCluster // Read the cluster + pop ax // Restore start cluster of FreeLoader + + // Save the addresses of needed functions so + // 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-ReadClusterOffset], offset ReadCluster // Save the address of ReadCluster + mov word ptr [bp-PutCharsOffset], offset PutChars // Save the address of PutChars + + // Now AX has start cluster of FreeLoader and we + // have loaded the helper code in the first 512 bytes + // of FreeLoader to 0000:8000. Now transfer control + // to the helper code. Skip the first three bytes + // because they contain a jump instruction to skip + // over the helper code in the FreeLoader image. + //jmp 0000:9003h + push 0 // push segment (0x0000) + mov bx, [HEX(8000) + HEX(0A8)] // load the RVA of the EntryPoint into eax + add bx, HEX(8003) // RVA -> VA and skip 3 bytes (jump to fathelper code) + push bx // push offset + retf // Transfer control to FreeLoader + + + + +// Displays an error message +// And reboots +ErrBoot: + mov si, offset msgFreeLdr // FreeLdr not found message + call PutChars // Display it + +Reboot: +// mov si, offset msgAnyKey // Press any key message +// call PutChars // Display it + xor ax, ax + int HEX(16) // Wait for a keypress + int HEX(19) // Reboot + +PutChars: + lodsb + or al,al + jz short Done + mov ah, HEX(0e) + mov bx, 7 + int HEX(10) + jmp short PutChars +Done: + ret + +// Displays a bad boot message +// And reboots +BadBoot: + mov si, offset msgDiskError // Bad boot disk message + call PutChars // Display it + + jmp short Reboot + + +// Reads cluster number in AX into [ES:0000] +ReadCluster: + // StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors; + dec ax // Adjust start cluster by 2 + dec ax // Because the data area starts on cluster 2 + xor ch, ch + mov cl, byte ptr BP_REL(SectsPerCluster) + mul cx // Times sectors per cluster + 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 + 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 + //call ReadSectors + //ret + + + +// Reads logical sectors into [ES:BX] +// DX:AX has logical sector number to read +// CX has number of sectors to read +ReadSectors: + + // We can't just check if the start sector is + // in the BIOS CHS range. We have to check if + // the start sector + length is in that range. + pusha + dec cx + add ax, cx + adc dx, 0 + + cmp dx, word ptr [bp-BiosCHSDriveSizeHigh] // Check if they are reading a sector within CHS range + ja ReadSectorsLBA // No - go to the LBA 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 + jbe ReadSectorsCHS // Yes - go to the old CHS routine + +ReadSectorsLBA: + popa +ReadSectorsLBALoop: + pusha // Save logical sector number & sector count + + push 0 + push 0 + push dx // Put 64-bit logical + push ax // block address on stack + push es // Put transfer segment on stack + push bx // Put transfer offset on stack + push 1 // Set transfer count to 1 sector + push HEX(10) // Set size of packet to 10h + mov si,sp // Setup disk address packet on stack + +// We are so totally out of space here that I am forced to +// comment out this very beautifully written piece of code +// It would have been nice to have had this check... +//CheckInt13hExtensions: // Now make sure this computer supports extended reads +// mov ah,0x41 // AH = 41h +// mov bx,0x55aa // BX = 55AAh +// mov dl,[BYTE bp+BootDrive] // DL = drive (80h-FFh) +// int 13h // IBM/MS INT 13 Extensions - INSTALLATION CHECK +// jc PrintDiskError // CF set on error (extensions not supported) +// cmp bx,0xaa55 // BX = AA55h if installed +// jne PrintDiskError +// test cl,1 // CX = API subset support bitmap +// 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 + // So finish the extended read + mov dl, byte ptr BP_REL(BootDrive) // Drive number + mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read + int HEX(13) // Call BIOS + jc BadBoot // If the read failed then abort + + add sp, 16 // Remove disk address packet from stack + + popa // Restore sector count & logical sector number + + inc ax // Increment Sector to Read + adc dx, 0 + + push bx + mov bx, es + add bx, HEX(20) // Increment read buffer for next sector + mov es, bx + pop bx + + loop ReadSectorsLBALoop // Read next sector + + ret + + +// 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 +ReadSectorsCHS: + popa +ReadSectorsCHSLoop: + pusha + xchg ax, cx + xchg ax, dx + xor dx, dx + div word ptr BP_REL(SectorsPerTrack) + xchg ax, cx + div word ptr BP_REL(SectorsPerTrack) // Divide logical by SectorsPerTrack + inc dx // Sectors numbering starts at 1 not 0 + xchg cx, dx + div word ptr BP_REL(NumberOfHeads) // Number of heads + mov dh, dl // Head to DH, drive to DL + mov dl, byte ptr BP_REL(BootDrive) // Drive number + mov ch, al // Cylinder in CX + ror ah, 2 // Low 8 bits of cylinder in CH, high 2 bits + // in CL shifted to bits 6 & 7 + or cl, ah // Or with sector number + mov ax, HEX(0201) + int HEX(13) // 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 + + popa + inc ax //Increment Sector to Read + jnz NoCarryCHS + inc dx + + +NoCarryCHS: + push bx + mov bx, es + add bx, HEX(20) + mov es, bx + pop bx + // Increment read buffer for next sector + loop ReadSectorsCHSLoop // Read next sector + + ret + + +msgDiskError: + .asciz "Disk error\r\n" +msgFreeLdr: + .asciz "ldr not found\r\n" +// Sorry, need the space... +//msgAnyKey: +// .asciz "Press any key to restart\r\n" +filename: + .ascii "FREELDR SYS" + + .org 509 // Pad to 509 bytes + +BootPartition: + .byte 0 + +BootSignature: + .word HEX(0aa55) // BootSector signature + +.endcode16 + +END