// fathelp.S // FAT12/16 Boot Sector Helper Code // Copyright (c) 1998, 2001, 2002, 2003 Brian Palmer //#include //org 8000h //.text #define BootSectorStackTop HEX(7bf2) #define DataAreaStartHigh 2 #define DataAreaStartLow 4 #define BiosCHSDriveSizeHigh 6 #define BiosCHSDriveSizeLow 8 #define BiosCHSDriveSize 8 #define ReadSectorsOffset 10 #define ReadClusterOffset 12 #define PutCharsOffset 14 #define OEMName 3 #define BytesPerSector 11 #define SectsPerCluster 13 #define ReservedSectors 14 #define NumberOfFats 16 #define MaxRootEntries 17 #define TotalSectors 19 #define MediaDescriptor 21 #define SectorsPerFat 22 #define SectorsPerTrack 24 #define NumberOfHeads 26 #define HiddenSectors 28 #define TotalSectorsBig 32 #define BootDrive 36 #define Reserved 37 #define ExtendSig 38 #define SerialNumber 39 #define VolumeLabel 43 #define FileSystem 54 #define BootPartition HEX(7dfd) // This code will be stored in the first 512 bytes // of freeldr.sys. The first 3 bytes will be a jmp // instruction to skip past the FAT helper code // that is stored in the rest of the 512 bytes. // PUBLIC start start: // This code is loaded at 0000:F800 so we have to // encode a jmp instruction to jump to 0000:FA00 .byte HEX(e9), HEX(fd), HEX(01) // Now starts the extra boot code that we will store // in the first 512 bytes of freeldr.sys. This code // allows the FAT12/16 bootsector to navigate the // FAT table so that we can still load freeldr.sys // even if it is fragmented. FatHelperEntryPoint: /* First save AX - the start cluster of freeldr.sys */ push ax /* Display "Loading FreeLoader..." message */ mov si, offset msgLoading call word ptr [bp-PutCharsOffset] call ReadFatIntoMemory /* Restore AX (start cluster) */ pop ax // AX has start cluster of freeldr.sys mov bx, FREELDR_BASE / 16 mov es,bx LoadFile: push ax call IsFat12 pop ax jnc LoadFile2 cmp ax, HEX(0ff8) // Check to see if this is the last cluster in the chain jmp LoadFile3 LoadFile2: cmp ax, HEX(0fff8) LoadFile3: jae LoadFile_Done // If so continue, if not then read then next one push ax xor bx,bx // Load ROSLDR starting at 0000:8000h push es call word ptr [bp-ReadClusterOffset] pop es xor bx,bx mov bl, [bp+SectsPerCluster] shl bx,5 // BX = BX * 512 / 16 mov ax,es // Increment the load address by add ax,bx // The size of a cluster mov es,ax call IsFat12 pop ax push es jnc LoadFile4 call GetFatEntry12 // Get the next entry jmp LoadFile5 LoadFile4: call GetFatEntry16 LoadFile5: pop es jmp LoadFile // Load the next cluster (if any) LoadFile_Done: mov dl, byte ptr [bp+BootDrive] // Load the boot drive into DL mov dh, byte ptr ds:[BootPartition] // Load the boot partition into DH /* continue where other bootsectors start */ jmp start // Reads the entire FAT into memory at 7000:0000 ReadFatIntoMemory: mov ax, [bp+HiddenSectors] mov dx, [bp+HiddenSectors+2] add ax, [bp+ReservedSectors] adc dx, 0 mov cx, [bp+SectorsPerFat] mov bx, HEX(7000) mov es,bx xor bx,bx call word ptr [bp-ReadSectorsOffset] ret // Returns the FAT entry for a given cluster number for 16-bit FAT // On entry AX has cluster number // On return AX has FAT entry for that cluster GetFatEntry16: mov cx,2 // AX = AX * 2 (since FAT16 entries are 2 bytes) mul cx shl dx,12 mov bx, HEX(7000) add bx,dx mov es,bx mov bx,ax // Restore FAT entry offset mov ax, es:[bx] // Get FAT entry ret // Returns the FAT entry for a given cluster number for 12-bit FAT // On entry AX has cluster number // On return AX has FAT entry for that cluster GetFatEntry12: push ax mov cx,ax shr ax,1 add ax,cx // AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits) mov bx, HEX(7000) mov es,bx mov bx,ax // Put FAT entry offset into BX mov ax, es:[bx] // Get FAT entry pop cx // Get cluster number from stack and cx,1 jz UseLow12Bits and ax, HEX(0fff0) shr ax,4 jmp GetFatEntry12_Done UseLow12Bits: and ax, HEX(0fff) GetFatEntry12_Done: ret // Returns CF = 1 if this is a FAT12 file system // Otherwise CF = 0 for FAT16 IsFat12: mov ebx, dword ptr [bp-DataAreaStartLow] // EBX now has the number of the starting sector of the data area // starting from the beginning of the disk, so subtrace hidden sectors sub ebx, dword ptr [bp+HiddenSectors] xor eax,eax mov ax, word ptr [bp+TotalSectors] cmp ax, 0 jnz IsFat12_2 mov eax, dword ptr [bp+TotalSectorsBig] // EAX now contains the number of sectors on the volume IsFat12_2: sub eax,ebx // Subtract data area start sector xor edx,edx // from total sectors of volume // EDX:EAX now contains the number of data sectors on the volume movzx ebx, byte ptr [bp+SectsPerCluster] div ebx // EAX now has the number of clusters on the volume stc cmp eax,4085 jb IsFat12_Done clc IsFat12_Done: ret msgLoading: .ascii "Loading FreeLoader...", CR, LF, NUL .org 510 // Pad to 510 bytes .word HEX(0aa55) // BootSector signature