1*f0d73e0fSSylvain Deverre/* 2*f0d73e0fSSylvain Deverre * PROJECT: ReactOS Bootsector 3*f0d73e0fSSylvain Deverre * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4*f0d73e0fSSylvain Deverre * FILE: boot/freeldr/bootsect/fat32.S 5*f0d73e0fSSylvain Deverre * PURPOSE: Implementing boot sector for NTFS 6*f0d73e0fSSylvain Deverre * COPYRIGHT: Copyright 2020 Sylvain Deverre (deverre.sylv@gmail.com) 7*f0d73e0fSSylvain Deverre */ 8*f0d73e0fSSylvain Deverre 9*f0d73e0fSSylvain Deverre/* INCLUDES ******************************************************************/ 10*f0d73e0fSSylvain Deverre 11*f0d73e0fSSylvain Deverre#include <asm.inc> 12*f0d73e0fSSylvain Deverre#include <freeldr/include/arch/pc/x86common.h> 13*f0d73e0fSSylvain Deverre 14*f0d73e0fSSylvain Deverre.code16 15*f0d73e0fSSylvain Deverre 16*f0d73e0fSSylvain Deverre//ORG HEX(7c00) 17*f0d73e0fSSylvain Deverre 18*f0d73e0fSSylvain Deverrestart: 19*f0d73e0fSSylvain Deverre jmp short main 20*f0d73e0fSSylvain Deverre nop 21*f0d73e0fSSylvain DeverreOEMName: 22*f0d73e0fSSylvain Deverre .ASCII "NTFS " // NTFS signature 23*f0d73e0fSSylvain DeverreBytesPerSector: 24*f0d73e0fSSylvain Deverre .word 512 25*f0d73e0fSSylvain DeverreSectsPerCluster: 26*f0d73e0fSSylvain Deverre .byte 8 27*f0d73e0fSSylvain DeverreReservedSectors: 28*f0d73e0fSSylvain Deverre .word 0 // Unused by NTFS 29*f0d73e0fSSylvain DeverreNumberOfFats: 30*f0d73e0fSSylvain Deverre .byte 0 // Unused by NTFS 31*f0d73e0fSSylvain DeverreMaxRootEntries: 32*f0d73e0fSSylvain Deverre .word 0 // Unused by NTFS 33*f0d73e0fSSylvain DeverreTotalSectors: 34*f0d73e0fSSylvain Deverre .word 0 // Unused by NTFS 35*f0d73e0fSSylvain DeverreMediaDescriptor: 36*f0d73e0fSSylvain Deverre .byte HEX(0f8) 37*f0d73e0fSSylvain DeverreSectorsPerFat: 38*f0d73e0fSSylvain Deverre .word 0 // Unused by NTFS 39*f0d73e0fSSylvain DeverreSectorsPerTrack: 40*f0d73e0fSSylvain Deverre .word 0 // Should contain disk geometry 41*f0d73e0fSSylvain DeverreNumberOfHeads: 42*f0d73e0fSSylvain Deverre .word 0 // Should contain disk geometry 43*f0d73e0fSSylvain DeverreHiddenSectors: 44*f0d73e0fSSylvain Deverre .long 0 // Filled by format program 45*f0d73e0fSSylvain DeverreTotalSectorsBig: 46*f0d73e0fSSylvain Deverre .long 0 // Unused by NTFS 47*f0d73e0fSSylvain Deverre// NTFS inserted info 48*f0d73e0fSSylvain DeverreBootDrive: 49*f0d73e0fSSylvain Deverre .byte HEX(80) 50*f0d73e0fSSylvain DeverreCurrentHead: 51*f0d73e0fSSylvain Deverre .byte 0 52*f0d73e0fSSylvain DeverreBootSignature: 53*f0d73e0fSSylvain Deverre .byte HEX(80) 54*f0d73e0fSSylvain DeverreUnused: 55*f0d73e0fSSylvain Deverre .byte 0 56*f0d73e0fSSylvain DeverreVolumeSectorCount: 57*f0d73e0fSSylvain Deverre .quad 0 // Must be patched by format program ! 58*f0d73e0fSSylvain DeverreMftLocation: 59*f0d73e0fSSylvain Deverre .quad 0 // Must be patched by format program ! 60*f0d73e0fSSylvain DeverreMftMirrorLocation: 61*f0d73e0fSSylvain Deverre .quad 0 // Must be patched by format program ! 62*f0d73e0fSSylvain DeverreClustersPerMftRecord: 63*f0d73e0fSSylvain Deverre .long 0 64*f0d73e0fSSylvain DeverreClustersPerIndexRecord: 65*f0d73e0fSSylvain Deverre .long 0 66*f0d73e0fSSylvain DeverreVolumeSerialNumber: 67*f0d73e0fSSylvain Deverre .quad 0 68*f0d73e0fSSylvain DeverreChecksum: 69*f0d73e0fSSylvain Deverre .long 0 70*f0d73e0fSSylvain Deverre 71*f0d73e0fSSylvain Deverremain: 72*f0d73e0fSSylvain Deverre xor ax,ax // Setup segment registers 73*f0d73e0fSSylvain Deverre mov ds,ax // Make DS correct 74*f0d73e0fSSylvain Deverre mov es,ax // Make ES correct 75*f0d73e0fSSylvain Deverre mov ss,ax // Make SS correct 76*f0d73e0fSSylvain Deverre mov sp, HEX(7c00) 77*f0d73e0fSSylvain Deverre mov bp, sp // Setup a stack 78*f0d73e0fSSylvain Deverre 79*f0d73e0fSSylvain Deverre cmp byte ptr [BootDrive], HEX(0ff) // If they have specified a boot drive then use it 80*f0d73e0fSSylvain Deverre jne GetDriveParameters 81*f0d73e0fSSylvain Deverre 82*f0d73e0fSSylvain Deverre mov byte ptr [BootDrive], dl // Save the boot drive 83*f0d73e0fSSylvain Deverre 84*f0d73e0fSSylvain DeverreGetDriveParameters: 85*f0d73e0fSSylvain Deverre mov ah, 8 86*f0d73e0fSSylvain Deverre mov dl, byte ptr [BootDrive] // Get boot drive in dl 87*f0d73e0fSSylvain Deverre int HEX(13) // Request drive parameters from the bios 88*f0d73e0fSSylvain Deverre jnc CalcDriveSize // If the call succeeded then calculate the drive size 89*f0d73e0fSSylvain Deverre 90*f0d73e0fSSylvain Deverre // If we get here then the call to the BIOS failed 91*f0d73e0fSSylvain Deverre // so just set CHS equal to the maximum addressable 92*f0d73e0fSSylvain Deverre // size 93*f0d73e0fSSylvain Deverre mov cx, HEX(0ffff) 94*f0d73e0fSSylvain Deverre mov dh, cl 95*f0d73e0fSSylvain Deverre 96*f0d73e0fSSylvain DeverreCalcDriveSize: 97*f0d73e0fSSylvain Deverre // Now that we have the drive geometry 98*f0d73e0fSSylvain Deverre // lets calculate the drive size 99*f0d73e0fSSylvain Deverre mov bl, ch // Put the low 8-bits of the cylinder count into BL 100*f0d73e0fSSylvain Deverre mov bh, cl // Put the high 2-bits in BH 101*f0d73e0fSSylvain Deverre shr bh, 6 // Shift them into position, now BX contains the cylinder count 102*f0d73e0fSSylvain Deverre and cl, HEX(3f) // Mask off cylinder bits from sector count 103*f0d73e0fSSylvain Deverre // CL now contains sectors per track and DH contains head count 104*f0d73e0fSSylvain Deverre movzx eax, dh // Move the heads into EAX 105*f0d73e0fSSylvain Deverre movzx ebx, bx // Move the cylinders into EBX 106*f0d73e0fSSylvain Deverre movzx ecx, cl // Move the sectors per track into ECX 107*f0d73e0fSSylvain Deverre inc eax // Make it one based because the bios returns it zero based 108*f0d73e0fSSylvain Deverre inc ebx // Make the cylinder count one based also 109*f0d73e0fSSylvain Deverre mul ecx // Multiply heads with the sectors per track, result in edx:eax 110*f0d73e0fSSylvain Deverre mul ebx // Multiply the cylinders with (heads * sectors) [stored in edx:eax already] 111*f0d73e0fSSylvain Deverre 112*f0d73e0fSSylvain Deverre // We now have the total number of sectors as reported 113*f0d73e0fSSylvain Deverre // by the bios in eax, so store it in our variable 114*f0d73e0fSSylvain Deverre mov dword ptr ds:[BiosCHSDriveSize], eax 115*f0d73e0fSSylvain Deverre 116*f0d73e0fSSylvain DeverreLoadExtraBootCode: 117*f0d73e0fSSylvain Deverre // First we have to load our extra boot code at 118*f0d73e0fSSylvain Deverre // next sector into memory at [0000:7e00h] 119*f0d73e0fSSylvain Deverre mov eax, HEX(1) 120*f0d73e0fSSylvain Deverre xor edx, edx 121*f0d73e0fSSylvain Deverre mov cx, 4 122*f0d73e0fSSylvain Deverre xor bx, bx 123*f0d73e0fSSylvain Deverre mov es, bx // Read sector to [0000:7e00h] 124*f0d73e0fSSylvain Deverre mov bx, HEX(7e00) 125*f0d73e0fSSylvain Deverre call ReadSectors 126*f0d73e0fSSylvain Deverre jmp StartSearch 127*f0d73e0fSSylvain Deverre 128*f0d73e0fSSylvain Deverre 129*f0d73e0fSSylvain Deverre// Reads logical sectors into [ES:BX] 130*f0d73e0fSSylvain Deverre// EDX:EAX has logical sector number to read 131*f0d73e0fSSylvain Deverre// CX has number of sectors to read 132*f0d73e0fSSylvain DeverreReadSectors: 133*f0d73e0fSSylvain Deverre push es 134*f0d73e0fSSylvain Deverre add eax, dword ptr [HiddenSectors] // Add offset from the disk beginning 135*f0d73e0fSSylvain Deverre test edx, edx 136*f0d73e0fSSylvain Deverre jnz ReadSectorsLBA 137*f0d73e0fSSylvain Deverre cmp eax, dword ptr ds:[BiosCHSDriveSize] // Check if they are reading a sector outside CHS range 138*f0d73e0fSSylvain Deverre jae ReadSectorsLBA // Yes - go to the LBA routine 139*f0d73e0fSSylvain Deverre // If at all possible we want to use LBA routines because 140*f0d73e0fSSylvain Deverre // They are optimized to read more than 1 sector per read 141*f0d73e0fSSylvain Deverre 142*f0d73e0fSSylvain Deverre pushad // Save logical sector number & sector count 143*f0d73e0fSSylvain Deverre 144*f0d73e0fSSylvain DeverreCheckInt13hExtensions: // Now check if this computer supports extended reads 145*f0d73e0fSSylvain Deverre mov ah, HEX(41) // AH = 41h 146*f0d73e0fSSylvain Deverre mov bx, HEX(55aa) // BX = 55AAh 147*f0d73e0fSSylvain Deverre mov dl, byte ptr [BootDrive] // DL = drive (80h-FFh) 148*f0d73e0fSSylvain Deverre int HEX(13) // IBM/MS INT 13 Extensions - INSTALLATION CHECK 149*f0d73e0fSSylvain Deverre jc ReadSectorsCHS // CF set on error (extensions not supported) 150*f0d73e0fSSylvain Deverre cmp bx, HEX(0aa55) // BX = AA55h if installed 151*f0d73e0fSSylvain Deverre jne ReadSectorsCHS 152*f0d73e0fSSylvain Deverre test cl,1 // CX = API subset support bitmap 153*f0d73e0fSSylvain Deverre jz ReadSectorsCHS // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported 154*f0d73e0fSSylvain Deverre 155*f0d73e0fSSylvain Deverre popad // Restore sector count & logical sector number 156*f0d73e0fSSylvain Deverre 157*f0d73e0fSSylvain DeverreReadSectorsLBA: 158*f0d73e0fSSylvain Deverre pushad // Save logical sector number & sector count 159*f0d73e0fSSylvain Deverre 160*f0d73e0fSSylvain Deverre cmp cx, 64 // Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64 161*f0d73e0fSSylvain Deverre jbe ReadSectorsSetupDiskAddressPacket // If we are reading less than 65 sectors then just do the read 162*f0d73e0fSSylvain Deverre mov cx, 64 // Otherwise read only 64 sectors on this loop iteration 163*f0d73e0fSSylvain Deverre 164*f0d73e0fSSylvain DeverreReadSectorsSetupDiskAddressPacket: 165*f0d73e0fSSylvain Deverre mov word ptr ds:[LBASectorsRead],cx 166*f0d73e0fSSylvain Deverre push edx 167*f0d73e0fSSylvain Deverre push eax // Put 64-bit logical block address on stack 168*f0d73e0fSSylvain Deverre push es // Put transfer segment on stack 169*f0d73e0fSSylvain Deverre push bx // Put transfer offset on stack 170*f0d73e0fSSylvain Deverre push cx // Set transfer count 171*f0d73e0fSSylvain Deverre push 16 // Set size of packet to 10h 172*f0d73e0fSSylvain Deverre mov si, sp // Setup disk address packet on stack 173*f0d73e0fSSylvain Deverre 174*f0d73e0fSSylvain Deverre mov dl, byte ptr [BootDrive] // Drive number 175*f0d73e0fSSylvain Deverre mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read 176*f0d73e0fSSylvain Deverre int HEX(13) // Call BIOS 177*f0d73e0fSSylvain Deverre jc PrintDiskError // If the read failed then abort 178*f0d73e0fSSylvain Deverre 179*f0d73e0fSSylvain Deverre add sp, 16 // Remove disk address packet from stack 180*f0d73e0fSSylvain Deverre 181*f0d73e0fSSylvain Deverre popad // Restore sector count & logical sector number 182*f0d73e0fSSylvain Deverre 183*f0d73e0fSSylvain Deverre push bx 184*f0d73e0fSSylvain Deverre mov ebx, dword ptr ds:[LBASectorsRead] 185*f0d73e0fSSylvain Deverre add eax, ebx // Increment sector to read 186*f0d73e0fSSylvain Deverre adc edx, 0 187*f0d73e0fSSylvain Deverre shl ebx, 5 188*f0d73e0fSSylvain Deverre mov dx, es 189*f0d73e0fSSylvain Deverre add dx, bx // Setup read buffer for next sector 190*f0d73e0fSSylvain Deverre mov es, dx 191*f0d73e0fSSylvain Deverre pop bx 192*f0d73e0fSSylvain Deverre 193*f0d73e0fSSylvain Deverre sub cx, word ptr ds:[LBASectorsRead] 194*f0d73e0fSSylvain Deverre jnz ReadSectorsLBA // Read next sector 195*f0d73e0fSSylvain Deverre 196*f0d73e0fSSylvain Deverre pop es 197*f0d73e0fSSylvain Deverre ret 198*f0d73e0fSSylvain Deverre 199*f0d73e0fSSylvain DeverreLBASectorsRead: 200*f0d73e0fSSylvain Deverre .long 0 201*f0d73e0fSSylvain Deverre 202*f0d73e0fSSylvain Deverre 203*f0d73e0fSSylvain Deverre// Reads logical sectors into [ES:BX] 204*f0d73e0fSSylvain Deverre// EAX has logical sector number to read 205*f0d73e0fSSylvain Deverre// CX has number of sectors to read 206*f0d73e0fSSylvain DeverreReadSectorsCHS: 207*f0d73e0fSSylvain Deverre popad // Get logical sector number & sector count off stack 208*f0d73e0fSSylvain Deverre 209*f0d73e0fSSylvain DeverreReadSectorsCHSLoop: 210*f0d73e0fSSylvain Deverre pushad 211*f0d73e0fSSylvain Deverre xor edx, edx 212*f0d73e0fSSylvain Deverre movzx ecx, word ptr [SectorsPerTrack] 213*f0d73e0fSSylvain Deverre div ecx // Divide logical by SectorsPerTrack 214*f0d73e0fSSylvain Deverre inc dl // Sectors numbering starts at 1 not 0 215*f0d73e0fSSylvain Deverre mov cl, dl // Sector in CL 216*f0d73e0fSSylvain Deverre mov edx, eax 217*f0d73e0fSSylvain Deverre shr edx, 16 218*f0d73e0fSSylvain Deverre div word ptr [NumberOfHeads] // Divide logical by number of heads 219*f0d73e0fSSylvain Deverre mov dh, dl // Head in DH 220*f0d73e0fSSylvain Deverre mov dl, byte ptr [BootDrive] // Drive number in DL 221*f0d73e0fSSylvain Deverre mov ch, al // Cylinder in CX 222*f0d73e0fSSylvain Deverre ror ah, 2 // Low 8 bits of cylinder in CH, high 2 bits 223*f0d73e0fSSylvain Deverre // in CL shifted to bits 6 & 7 224*f0d73e0fSSylvain Deverre or cl, ah // Or with sector number 225*f0d73e0fSSylvain Deverre mov ax, HEX(0201) 226*f0d73e0fSSylvain Deverre int HEX(13) // DISK - READ SECTORS INTO MEMORY 227*f0d73e0fSSylvain Deverre // AL = number of sectors to read, CH = track, CL = sector 228*f0d73e0fSSylvain Deverre // DH = head, DL = drive, ES:BX -> buffer to fill 229*f0d73e0fSSylvain Deverre // Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read 230*f0d73e0fSSylvain Deverre 231*f0d73e0fSSylvain Deverre jc PrintDiskError // If the read failed then abort 232*f0d73e0fSSylvain Deverre 233*f0d73e0fSSylvain Deverre popad 234*f0d73e0fSSylvain Deverre 235*f0d73e0fSSylvain Deverre inc eax // Increment Sector to Read 236*f0d73e0fSSylvain Deverre 237*f0d73e0fSSylvain Deverre mov dx, es 238*f0d73e0fSSylvain Deverre add dx, 32 // Increment read buffer for next sector 239*f0d73e0fSSylvain Deverre mov es, dx 240*f0d73e0fSSylvain Deverre 241*f0d73e0fSSylvain Deverre loop ReadSectorsCHSLoop // Read next sector 242*f0d73e0fSSylvain Deverre 243*f0d73e0fSSylvain Deverre pop es 244*f0d73e0fSSylvain Deverre ret 245*f0d73e0fSSylvain Deverre 246*f0d73e0fSSylvain Deverre// Displays a disk error message 247*f0d73e0fSSylvain Deverre// And reboots 248*f0d73e0fSSylvain DeverrePrintDiskError: 249*f0d73e0fSSylvain Deverre mov si, offset msgDiskError // Bad boot disk message 250*f0d73e0fSSylvain Deverre call PutChars // Display it 251*f0d73e0fSSylvain Deverre 252*f0d73e0fSSylvain Deverre jmp Reboot 253*f0d73e0fSSylvain Deverre 254*f0d73e0fSSylvain Deverre// Displays a file system error message 255*f0d73e0fSSylvain Deverre// And reboots 256*f0d73e0fSSylvain DeverrePrintFileSystemError: 257*f0d73e0fSSylvain Deverre mov si, offset msgFileSystemError // FreeLdr not found message 258*f0d73e0fSSylvain Deverre call PutChars // Display it 259*f0d73e0fSSylvain Deverre 260*f0d73e0fSSylvain DeverreReboot: 261*f0d73e0fSSylvain Deverre mov si, offset msgAnyKey // Press any key message 262*f0d73e0fSSylvain Deverre call PutChars // Display it 263*f0d73e0fSSylvain Deverre xor ax, ax 264*f0d73e0fSSylvain Deverre int HEX(16) // Wait for a keypress 265*f0d73e0fSSylvain Deverre int HEX(19) // Reboot 266*f0d73e0fSSylvain Deverre 267*f0d73e0fSSylvain DeverrePutChars: 268*f0d73e0fSSylvain Deverre lodsb 269*f0d73e0fSSylvain Deverre or al, al 270*f0d73e0fSSylvain Deverre jz short Done 271*f0d73e0fSSylvain Deverre mov ah, HEX(0e) 272*f0d73e0fSSylvain Deverre mov bx, 7 273*f0d73e0fSSylvain Deverre int HEX(10) 274*f0d73e0fSSylvain Deverre jmp short PutChars 275*f0d73e0fSSylvain DeverreDone: 276*f0d73e0fSSylvain Deverre ret 277*f0d73e0fSSylvain Deverre 278*f0d73e0fSSylvain DeverremsgDiskError: 279*f0d73e0fSSylvain Deverre .ascii "Disk error", CR, LF, NUL 280*f0d73e0fSSylvain DeverremsgFileSystemError: 281*f0d73e0fSSylvain Deverre .ascii "File system error", CR, LF, NUL 282*f0d73e0fSSylvain DeverremsgAnyKey: 283*f0d73e0fSSylvain Deverre .ascii "Press any key to restart", CR, LF, NUL 284*f0d73e0fSSylvain Deverre 285*f0d73e0fSSylvain DeverreSectsPerMFT: 286*f0d73e0fSSylvain Deverre .word 0 287*f0d73e0fSSylvain Deverre 288*f0d73e0fSSylvain DeverreMFTStartSector: 289*f0d73e0fSSylvain Deverre .quad 0 290*f0d73e0fSSylvain Deverre 291*f0d73e0fSSylvain DeverreBiosCHSDriveSize: 292*f0d73e0fSSylvain Deverre .long 0 293*f0d73e0fSSylvain Deverre 294*f0d73e0fSSylvain Deverre.org 509 // Pad to 509 bytes 295*f0d73e0fSSylvain DeverreBootPartition: 296*f0d73e0fSSylvain Deverre .byte 1 297*f0d73e0fSSylvain Deverre 298*f0d73e0fSSylvain DeverreBootFlagSignature: 299*f0d73e0fSSylvain Deverre .word HEX(0aa55) // BootSector signature 300*f0d73e0fSSylvain Deverre 301*f0d73e0fSSylvain Deverre// End of Bootsector 302*f0d73e0fSSylvain Deverre// Next sector starts as sector 2, since boot sector is 303*f0d73e0fSSylvain Deverre// as a file under NTFS ($Boot, which has inode number 7) 304*f0d73e0fSSylvain Deverre// and takes the two first clusters of the volume (which means 305*f0d73e0fSSylvain Deverre// 16 sectors, checked on Windows and mkfs.ntfs from ntfsutils) 306*f0d73e0fSSylvain Deverre 307*f0d73e0fSSylvain Deverre#define ATTRIBUTE_DATA HEX(80) 308*f0d73e0fSSylvain Deverre#define ATTRIBUTE_INDEX_ROOT HEX(90) 309*f0d73e0fSSylvain Deverre#define ATTRIBUTE_INDEX_ALLOCATION HEX(A0) 310*f0d73e0fSSylvain Deverre#define FILE_MAGIC HEX(454c4946) 311*f0d73e0fSSylvain Deverre#define INDX_MAGIC HEX(58444e49) 312*f0d73e0fSSylvain Deverre#define NTFS_FILE_ROOT 5 313*f0d73e0fSSylvain DeverreStartSearch: 314*f0d73e0fSSylvain Deverre // Compute MFT start sector 315*f0d73e0fSSylvain Deverre mov eax, dword ptr [MftLocation] 316*f0d73e0fSSylvain Deverre mov cl, byte ptr [SectsPerCluster] 317*f0d73e0fSSylvain Deverre movzx ecx, cx 318*f0d73e0fSSylvain Deverre mul ecx 319*f0d73e0fSSylvain Deverre mov dword ptr [MFTStartSector], eax 320*f0d73e0fSSylvain Deverre 321*f0d73e0fSSylvain Deverre // Compute size of MFT entry in sectors 322*f0d73e0fSSylvain Deverre xor ax, ax 323*f0d73e0fSSylvain Deverre mov al, byte ptr [ClustersPerMftRecord] 324*f0d73e0fSSylvain Deverre test al, al 325*f0d73e0fSSylvain Deverre js NegativeOffset 326*f0d73e0fSSylvain Deverre mov cx, word ptr [SectsPerCluster] 327*f0d73e0fSSylvain Deverre mul cx 328*f0d73e0fSSylvain Deverre mov word ptr [SectsPerMFT], cx 329*f0d73e0fSSylvain Deverre jmp SearchNext 330*f0d73e0fSSylvain Deverre NegativeOffset: 331*f0d73e0fSSylvain Deverre // ClustersPerMftRecord is negative, so we need to perform 1 << (-ClustersPerMftRecord) 332*f0d73e0fSSylvain Deverre // to get the number of bytes needed for a MFT entry 333*f0d73e0fSSylvain Deverre not al 334*f0d73e0fSSylvain Deverre inc al 335*f0d73e0fSSylvain Deverre mov cl, al 336*f0d73e0fSSylvain Deverre xor ax, ax 337*f0d73e0fSSylvain Deverre inc ax 338*f0d73e0fSSylvain Deverre shl ax, cl 339*f0d73e0fSSylvain Deverre 340*f0d73e0fSSylvain Deverre // But here want to store sectors, so we need to divide by BytesPerSector 341*f0d73e0fSSylvain Deverre xor dx, dx 342*f0d73e0fSSylvain Deverre mov cx, word ptr [BytesPerSector] 343*f0d73e0fSSylvain Deverre div cx 344*f0d73e0fSSylvain Deverre mov word ptr [SectsPerMFT], ax 345*f0d73e0fSSylvain Deverre 346*f0d73e0fSSylvain Deverre SearchNext: 347*f0d73e0fSSylvain Deverre mov bp, sp 348*f0d73e0fSSylvain Deverre sub sp, HEX(10) 349*f0d73e0fSSylvain Deverre 350*f0d73e0fSSylvain Deverre // Read Root Directory MFT into [2000:0] 351*f0d73e0fSSylvain Deverre mov ax, HEX(2000) 352*f0d73e0fSSylvain Deverre mov es, ax 353*f0d73e0fSSylvain Deverre xor bx, bx 354*f0d73e0fSSylvain Deverre xor edx, edx 355*f0d73e0fSSylvain Deverre mov eax, NTFS_FILE_ROOT 356*f0d73e0fSSylvain Deverre call ReadInode 357*f0d73e0fSSylvain Deverre 358*f0d73e0fSSylvain Deverre // Finds freeldr.sys into index root's B-Tree 359*f0d73e0fSSylvain Deverre // and return its MFT index 360*f0d73e0fSSylvain Deverre xor ax, ax 361*f0d73e0fSSylvain Deverre call ExploreIndexRoot 362*f0d73e0fSSylvain Deverre 363*f0d73e0fSSylvain Deverre // Read the MFT entry of freeldr.sys into [A00:0] 364*f0d73e0fSSylvain Deverre push eax 365*f0d73e0fSSylvain Deverre mov ax, HEX(A00) 366*f0d73e0fSSylvain Deverre mov es, ax 367*f0d73e0fSSylvain Deverre pop eax 368*f0d73e0fSSylvain Deverre call ReadInode 369*f0d73e0fSSylvain Deverre 370*f0d73e0fSSylvain Deverre xor ax, ax 371*f0d73e0fSSylvain Deverre mov ebx, HEX(30) 372*f0d73e0fSSylvain Deverre call FindAttributeHdr 373*f0d73e0fSSylvain Deverre mov si, ax 374*f0d73e0fSSylvain Deverre // Move to the attribute data 375*f0d73e0fSSylvain Deverre add si, word ptr es:[si + HEX(14)] 376*f0d73e0fSSylvain Deverre 377*f0d73e0fSSylvain Deverre // We don't support compressed, sparse or encrypted Freeldr 378*f0d73e0fSSylvain Deverre test dword ptr es:[si + HEX(38)], HEX(4a00) 379*f0d73e0fSSylvain Deverre jnz CompressedFreeldr 380*f0d73e0fSSylvain Deverre 381*f0d73e0fSSylvain Deverre // Compute size in clusters 382*f0d73e0fSSylvain Deverre mov eax, dword ptr es:[si + HEX(28)] 383*f0d73e0fSSylvain Deverre mov cl, byte ptr [SectsPerCluster] 384*f0d73e0fSSylvain Deverre xor edx, edx 385*f0d73e0fSSylvain Deverre div ecx 386*f0d73e0fSSylvain Deverre mov cx, word ptr [BytesPerSector] 387*f0d73e0fSSylvain Deverre movzx ecx, cx 388*f0d73e0fSSylvain Deverre xor edx, edx 389*f0d73e0fSSylvain Deverre div ecx 390*f0d73e0fSSylvain Deverre mov edx, eax 391*f0d73e0fSSylvain Deverre 392*f0d73e0fSSylvain Deverre push ax 393*f0d73e0fSSylvain Deverre mov si, offset msgLoading 394*f0d73e0fSSylvain Deverre call PutChars 395*f0d73e0fSSylvain Deverre pop ax 396*f0d73e0fSSylvain Deverre 397*f0d73e0fSSylvain Deverre xor ax, ax 398*f0d73e0fSSylvain Deverre mov ebx, HEX(80) 399*f0d73e0fSSylvain Deverre call FindAttributeHdr 400*f0d73e0fSSylvain Deverre mov si, ax 401*f0d73e0fSSylvain Deverre add ax, word ptr es:[si + HEX(20)] 402*f0d73e0fSSylvain Deverre xor ecx, ecx 403*f0d73e0fSSylvain Deverre xor bx, bx 404*f0d73e0fSSylvain Deverre push FREELDR_BASE / 16 405*f0d73e0fSSylvain Deverre pop fs 406*f0d73e0fSSylvain Deverre FreeLdrLoad: 407*f0d73e0fSSylvain Deverre pushad 408*f0d73e0fSSylvain Deverre call ReadNonResidentAttribute 409*f0d73e0fSSylvain Deverre popad 410*f0d73e0fSSylvain Deverre mov bx, fs 411*f0d73e0fSSylvain Deverre add bx, HEX(100) 412*f0d73e0fSSylvain Deverre mov fs, bx 413*f0d73e0fSSylvain Deverre xor bx, bx 414*f0d73e0fSSylvain Deverre inc ecx 415*f0d73e0fSSylvain Deverre cmp ecx, edx 416*f0d73e0fSSylvain Deverre jbe FreeLdrLoad 417*f0d73e0fSSylvain Deverre 418*f0d73e0fSSylvain Deverre mov dl, byte ptr [BootDrive] 419*f0d73e0fSSylvain Deverre mov dh, byte ptr [BootPartition] 420*f0d73e0fSSylvain Deverre ljmp16 0, FREELDR_BASE 421*f0d73e0fSSylvain Deverre 422*f0d73e0fSSylvain Deverre// Error message if Freeldr is compressed, encrypted or sparse 423*f0d73e0fSSylvain DeverreCompressedFreeldr: 424*f0d73e0fSSylvain Deverre mov si, offset msgFreeldrCompressed 425*f0d73e0fSSylvain Deverre call PutChars 426*f0d73e0fSSylvain Deverre jmp Reboot 427*f0d73e0fSSylvain Deverre 428*f0d73e0fSSylvain Deverre// Finds Freeldr.sys into the directory tree and returns the 429*f0d73e0fSSylvain Deverre// inode index 430*f0d73e0fSSylvain Deverre// INPUT: 431*f0d73e0fSSylvain Deverre// - ES:[AX] address of the MFT record 432*f0d73e0fSSylvain Deverre// OUTPUT: 433*f0d73e0fSSylvain Deverre// - EDX:EAX MFT number of the found file 434*f0d73e0fSSylvain DeverreExploreIndexRoot: 435*f0d73e0fSSylvain Deverre #define fileRecordBase 2 436*f0d73e0fSSylvain Deverre #define fileRecord 4 437*f0d73e0fSSylvain Deverre #define indexRootData 6 438*f0d73e0fSSylvain Deverre #define allocationRunList 8 439*f0d73e0fSSylvain Deverre 440*f0d73e0fSSylvain Deverre push bp 441*f0d73e0fSSylvain Deverre mov bp, sp 442*f0d73e0fSSylvain Deverre push bx 443*f0d73e0fSSylvain Deverre push si 444*f0d73e0fSSylvain Deverre push di 445*f0d73e0fSSylvain Deverre sub sp, HEX(10) 446*f0d73e0fSSylvain Deverre mov word ptr [bp - fileRecordBase], es 447*f0d73e0fSSylvain Deverre mov word ptr [bp - fileRecord], ax 448*f0d73e0fSSylvain Deverre 449*f0d73e0fSSylvain Deverre mov ebx, ATTRIBUTE_INDEX_ROOT 450*f0d73e0fSSylvain Deverre call FindAttributeHdr 451*f0d73e0fSSylvain Deverre test ax, ax 452*f0d73e0fSSylvain Deverre jz PrintFileSystemError // fail if no INDEX_ROOT 453*f0d73e0fSSylvain Deverre 454*f0d73e0fSSylvain Deverre mov si, ax 455*f0d73e0fSSylvain Deverre cmp byte ptr es:[si + 8], HEX(0) 456*f0d73e0fSSylvain Deverre jnz PrintFileSystemError // fail if attribute is non-resident 457*f0d73e0fSSylvain Deverre 458*f0d73e0fSSylvain Deverre add si, word ptr es:[si + HEX(14)] 459*f0d73e0fSSylvain Deverre cmp dword ptr es:[si], HEX(30) 460*f0d73e0fSSylvain Deverre jnz PrintFileSystemError // fail if FILE_NAME attribute isn't indexed 461*f0d73e0fSSylvain Deverre 462*f0d73e0fSSylvain Deverre mov word ptr [bp - indexRootData], si 463*f0d73e0fSSylvain Deverre mov ax, word ptr [bp - fileRecord] 464*f0d73e0fSSylvain Deverre 465*f0d73e0fSSylvain Deverre test byte ptr es:[si + HEX(0c)], 1 466*f0d73e0fSSylvain Deverre jz ExploreNext // Skip index allocation lookup if we don't have children 467*f0d73e0fSSylvain Deverre 468*f0d73e0fSSylvain Deverre mov ebx, ATTRIBUTE_INDEX_ALLOCATION 469*f0d73e0fSSylvain Deverre call FindAttributeHdr 470*f0d73e0fSSylvain Deverre test ax, ax 471*f0d73e0fSSylvain Deverre jz PrintFileSystemError // No INDEX_ALLOCATION found 472*f0d73e0fSSylvain Deverre 473*f0d73e0fSSylvain Deverre mov si, ax 474*f0d73e0fSSylvain Deverre cmp byte ptr es:[si + 8], 1 475*f0d73e0fSSylvain Deverre jnz PrintFileSystemError // Fail if attribute is resident (shouldn't be) 476*f0d73e0fSSylvain Deverre 477*f0d73e0fSSylvain Deverre add si, word ptr es:[si + HEX(20)] 478*f0d73e0fSSylvain Deverre mov word ptr [bp - allocationRunList], si // save run list 479*f0d73e0fSSylvain Deverre 480*f0d73e0fSSylvain Deverre ExploreNext: 481*f0d73e0fSSylvain Deverre mov si, word ptr [bp - indexRootData] 482*f0d73e0fSSylvain Deverre lea si, [si + 32] // get the first INDEX_ENTRY 483*f0d73e0fSSylvain Deverre 484*f0d73e0fSSylvain Deverre // Main search loop. We browse the B-Tree which contains directory entries 485*f0d73e0fSSylvain Deverre // SI contains the current index entry. 486*f0d73e0fSSylvain Deverre NodeCheck: 487*f0d73e0fSSylvain Deverre test word ptr es:[si + HEX(0C)], 2 488*f0d73e0fSSylvain Deverre jnz NodeCheckLastNode 489*f0d73e0fSSylvain Deverre 490*f0d73e0fSSylvain Deverre mov cl, byte ptr es:[si + HEX(50)] 491*f0d73e0fSSylvain Deverre movzx cx, cl 492*f0d73e0fSSylvain Deverre lea si, [si + HEX(52)] 493*f0d73e0fSSylvain Deverre mov di, offset FreeLdr 494*f0d73e0fSSylvain Deverre call CompareWideStrInsensitive 495*f0d73e0fSSylvain Deverre lea si, [si - HEX(52)] 496*f0d73e0fSSylvain Deverre test ax, ax 497*f0d73e0fSSylvain Deverre jz RootIndexFound 498*f0d73e0fSSylvain Deverre test word ptr es:[si + HEX(0C)], 1 499*f0d73e0fSSylvain Deverre jz ContinueSearch 500*f0d73e0fSSylvain Deverre 501*f0d73e0fSSylvain Deverre test ax, HEX(f000) 502*f0d73e0fSSylvain Deverre jnz LookupChildNode // if result < 0 then explore child node 503*f0d73e0fSSylvain Deverre 504*f0d73e0fSSylvain Deverre ContinueSearch: 505*f0d73e0fSSylvain Deverre add si, word ptr es:[si + 8] 506*f0d73e0fSSylvain Deverre jmp NodeCheck 507*f0d73e0fSSylvain Deverre 508*f0d73e0fSSylvain Deverre RootIndexFound: 509*f0d73e0fSSylvain Deverre mov eax, dword ptr es:[si] // We found root entry, return with its MFT number 510*f0d73e0fSSylvain Deverre mov dx, word ptr es:[si + 4] // Return high part into edx. 511*f0d73e0fSSylvain Deverre // We take only the first word, the high word contains the 512*f0d73e0fSSylvain Deverre // sequence number 513*f0d73e0fSSylvain Deverre movzx edx, dx 514*f0d73e0fSSylvain Deverre jmp ExitIndexTree 515*f0d73e0fSSylvain Deverre 516*f0d73e0fSSylvain Deverre NodeCheckLastNode: 517*f0d73e0fSSylvain Deverre test word ptr es:[si + HEX(0C)], 1 518*f0d73e0fSSylvain Deverre jz PrintFreeldrError 519*f0d73e0fSSylvain Deverre 520*f0d73e0fSSylvain Deverre LookupChildNode: 521*f0d73e0fSSylvain Deverre // Take the right LCN at the end of the index record 522*f0d73e0fSSylvain Deverre add si, word ptr es:[si + 8] 523*f0d73e0fSSylvain Deverre mov ecx, dword ptr es:[si - 8] 524*f0d73e0fSSylvain Deverre 525*f0d73e0fSSylvain Deverre // Read the fixed up LCN 526*f0d73e0fSSylvain Deverre mov bx, word ptr [bp - allocationRunList] 527*f0d73e0fSSylvain Deverre mov ax, word ptr [bp - fileRecordBase] 528*f0d73e0fSSylvain Deverre mov es, ax 529*f0d73e0fSSylvain Deverre mov ax, HEX(9000) 530*f0d73e0fSSylvain Deverre mov fs, ax 531*f0d73e0fSSylvain Deverre mov ax, bx 532*f0d73e0fSSylvain Deverre xor bx, bx 533*f0d73e0fSSylvain Deverre call ReadINDX 534*f0d73e0fSSylvain Deverre 535*f0d73e0fSSylvain Deverre // Go again to the loop but with the child node list 536*f0d73e0fSSylvain Deverre mov ax, HEX(9000) 537*f0d73e0fSSylvain Deverre mov es, ax 538*f0d73e0fSSylvain Deverre mov si, 0 539*f0d73e0fSSylvain Deverre add si, es:[si + HEX(18)] // Go to the first node 540*f0d73e0fSSylvain Deverre lea si, [si + HEX(18)] 541*f0d73e0fSSylvain Deverre jmp NodeCheck 542*f0d73e0fSSylvain Deverre 543*f0d73e0fSSylvain Deverre ExitIndexTree: 544*f0d73e0fSSylvain Deverre pop di 545*f0d73e0fSSylvain Deverre pop si 546*f0d73e0fSSylvain Deverre mov sp, bp 547*f0d73e0fSSylvain Deverre pop bp 548*f0d73e0fSSylvain Deverre ret 549*f0d73e0fSSylvain Deverre 550*f0d73e0fSSylvain Deverre// 64-bit multiplication 551*f0d73e0fSSylvain Deverre// EDX:EAX operand 552*f0d73e0fSSylvain Deverre// ECX operator 553*f0d73e0fSSylvain DeverreMultiply64: 554*f0d73e0fSSylvain Deverre push bp 555*f0d73e0fSSylvain Deverre mov bp, sp 556*f0d73e0fSSylvain Deverre sub sp, 12 557*f0d73e0fSSylvain Deverre // Save the high part of the multiplication 558*f0d73e0fSSylvain Deverre mov dword ptr [bp - 4], edx 559*f0d73e0fSSylvain Deverre 560*f0d73e0fSSylvain Deverre // Multiply the low part and save the result 561*f0d73e0fSSylvain Deverre mul ecx 562*f0d73e0fSSylvain Deverre mov dword ptr[bp - 8], eax 563*f0d73e0fSSylvain Deverre mov dword ptr[bp - 12], edx 564*f0d73e0fSSylvain Deverre 565*f0d73e0fSSylvain Deverre // Multiply the high part and add the carry 566*f0d73e0fSSylvain Deverre mov eax, dword ptr [bp - 4] 567*f0d73e0fSSylvain Deverre mul ecx 568*f0d73e0fSSylvain Deverre add eax, dword ptr [bp - 12] 569*f0d73e0fSSylvain Deverre 570*f0d73e0fSSylvain Deverre // Format correctly the number 571*f0d73e0fSSylvain Deverre mov edx, eax 572*f0d73e0fSSylvain Deverre mov eax, dword ptr [bp - 8] 573*f0d73e0fSSylvain Deverre mov sp, bp 574*f0d73e0fSSylvain Deverre pop bp 575*f0d73e0fSSylvain Deverre ret 576*f0d73e0fSSylvain Deverre 577*f0d73e0fSSylvain Deverre// Compare case-insensitive strings 578*f0d73e0fSSylvain Deverre// [ES:SI] - the source file name 579*f0d73e0fSSylvain Deverre// [DS:DI] - the destination file name 580*f0d73e0fSSylvain Deverre// CX - compare length 581*f0d73e0fSSylvain DeverreCompareWideStrInsensitive: 582*f0d73e0fSSylvain Deverre push bx 583*f0d73e0fSSylvain Deverre push si 584*f0d73e0fSSylvain Deverre push di 585*f0d73e0fSSylvain Deverre movzx cx, cl 586*f0d73e0fSSylvain Deverre CmpLoop: 587*f0d73e0fSSylvain Deverre mov ax, word ptr es:[si] 588*f0d73e0fSSylvain Deverre cmp ax, 'a' 589*f0d73e0fSSylvain Deverre jl NoUpper 590*f0d73e0fSSylvain Deverre cmp ax, 'z' 591*f0d73e0fSSylvain Deverre jg NoUpper 592*f0d73e0fSSylvain Deverre sub ax, HEX(20) 593*f0d73e0fSSylvain Deverre NoUpper: 594*f0d73e0fSSylvain Deverre mov bx, word ptr ds:[di] 595*f0d73e0fSSylvain Deverre sub bx, ax 596*f0d73e0fSSylvain Deverre test bx, bx 597*f0d73e0fSSylvain Deverre jnz CompareFail 598*f0d73e0fSSylvain Deverre add si, 2 599*f0d73e0fSSylvain Deverre add di, 2 600*f0d73e0fSSylvain Deverre dec cx 601*f0d73e0fSSylvain Deverre jnz CmpLoop 602*f0d73e0fSSylvain Deverre CompareFail: 603*f0d73e0fSSylvain Deverre mov ax, bx 604*f0d73e0fSSylvain Deverre pop di 605*f0d73e0fSSylvain Deverre pop si 606*f0d73e0fSSylvain Deverre pop bx 607*f0d73e0fSSylvain Deverre ret 608*f0d73e0fSSylvain Deverre 609*f0d73e0fSSylvain Deverre// Reads a NTFS cluster 610*f0d73e0fSSylvain Deverre// INPUT: 611*f0d73e0fSSylvain Deverre// - EDX:EAX : cluster number to read 612*f0d73e0fSSylvain Deverre// OUTPUT: 613*f0d73e0fSSylvain Deverre// - ES:BX : address to read 614*f0d73e0fSSylvain DeverreReadCluster: 615*f0d73e0fSSylvain Deverre push ecx 616*f0d73e0fSSylvain Deverre mov cl, byte ptr [SectsPerCluster] // Convert clusters to sectors 617*f0d73e0fSSylvain Deverre movzx ecx, cx 618*f0d73e0fSSylvain Deverre call Multiply64 619*f0d73e0fSSylvain Deverre call ReadSectors 620*f0d73e0fSSylvain Deverre pop ecx 621*f0d73e0fSSylvain Deverre ret 622*f0d73e0fSSylvain Deverre 623*f0d73e0fSSylvain Deverre// Reads a MFT entry 624*f0d73e0fSSylvain Deverre// INPUT: 625*f0d73e0fSSylvain Deverre// - EDX:EAX : MFT inode 626*f0d73e0fSSylvain Deverre// OUTPUT: 627*f0d73e0fSSylvain Deverre// - ES:[BX] : address to read 628*f0d73e0fSSylvain DeverreReadInode: 629*f0d73e0fSSylvain Deverre push ecx 630*f0d73e0fSSylvain Deverre push si 631*f0d73e0fSSylvain Deverre push di 632*f0d73e0fSSylvain Deverre 633*f0d73e0fSSylvain Deverre push edx 634*f0d73e0fSSylvain Deverre mov cx, word ptr [SectsPerMFT] // Get the correct number of sectors for the FILE entry 635*f0d73e0fSSylvain Deverre movzx ecx, cx 636*f0d73e0fSSylvain Deverre mul ecx 637*f0d73e0fSSylvain Deverre movzx eax, ax 638*f0d73e0fSSylvain Deverre add eax, dword ptr [MFTStartSector] // Add it to the start of the MFT 639*f0d73e0fSSylvain Deverre mov cx, word ptr [SectsPerMFT] 640*f0d73e0fSSylvain Deverre movzx ecx, cx 641*f0d73e0fSSylvain Deverre pop edx 642*f0d73e0fSSylvain Deverre call ReadSectors 643*f0d73e0fSSylvain Deverre 644*f0d73e0fSSylvain Deverre cmp dword ptr es:[bx], FILE_MAGIC // Ensure we get a valid FILE record 645*f0d73e0fSSylvain Deverre jnz PrintFileSystemError 646*f0d73e0fSSylvain Deverre 647*f0d73e0fSSylvain Deverre call ApplyFixups 648*f0d73e0fSSylvain Deverre 649*f0d73e0fSSylvain Deverre pop di 650*f0d73e0fSSylvain Deverre pop si 651*f0d73e0fSSylvain Deverre pop ecx 652*f0d73e0fSSylvain Deverre ret 653*f0d73e0fSSylvain Deverre 654*f0d73e0fSSylvain Deverre#define UpdateSequenceOffset 4 655*f0d73e0fSSylvain Deverre#define UpdateSequenceLen 6 656*f0d73e0fSSylvain Deverre// Apply fixups to INDX and FILE records 657*f0d73e0fSSylvain Deverre// INPUT: 658*f0d73e0fSSylvain Deverre// - ES:[BX] - pointer to the record to fixup 659*f0d73e0fSSylvain DeverreApplyFixups: 660*f0d73e0fSSylvain Deverre push si 661*f0d73e0fSSylvain Deverre push di 662*f0d73e0fSSylvain Deverre mov si, bx 663*f0d73e0fSSylvain Deverre add si, word ptr es:[bx + UpdateSequenceOffset] 664*f0d73e0fSSylvain Deverre xor cx, cx 665*f0d73e0fSSylvain Deverre inc cx 666*f0d73e0fSSylvain Deverre FixupLoop: 667*f0d73e0fSSylvain Deverre cmp cx, word ptr es:[bx + UpdateSequenceLen] 668*f0d73e0fSSylvain Deverre jz EndFixupLoop 669*f0d73e0fSSylvain Deverre mov si, bx 670*f0d73e0fSSylvain Deverre add si, word ptr es:[bx + UpdateSequenceOffset] 671*f0d73e0fSSylvain Deverre mov ax, word ptr es:[si] // Get first fixup value 672*f0d73e0fSSylvain Deverre 673*f0d73e0fSSylvain Deverre mov di, cx 674*f0d73e0fSSylvain Deverre shl di, 9 675*f0d73e0fSSylvain Deverre add di, bx 676*f0d73e0fSSylvain Deverre sub di, 2 677*f0d73e0fSSylvain Deverre cmp ax, word ptr es:[di] // Check fixup value 678*f0d73e0fSSylvain Deverre jnz PrintFileSystemError // Fixup is corrupted, so print error 679*f0d73e0fSSylvain Deverre inc cx 680*f0d73e0fSSylvain Deverre add si, cx 681*f0d73e0fSSylvain Deverre mov ax, word ptr es:[si] // Apply fixup 682*f0d73e0fSSylvain Deverre mov word ptr es:[di], ax 683*f0d73e0fSSylvain Deverre 684*f0d73e0fSSylvain Deverre jmp FixupLoop 685*f0d73e0fSSylvain Deverre EndFixupLoop: 686*f0d73e0fSSylvain Deverre 687*f0d73e0fSSylvain Deverre pop di 688*f0d73e0fSSylvain Deverre pop si 689*f0d73e0fSSylvain Deverre ret 690*f0d73e0fSSylvain Deverre 691*f0d73e0fSSylvain Deverre// Reads a non-resident attribute 692*f0d73e0fSSylvain Deverre// INPUT: 693*f0d73e0fSSylvain Deverre// - ES:[AX] : Address of the data runs 694*f0d73e0fSSylvain Deverre// - ECX : LCN to read 695*f0d73e0fSSylvain Deverre// OUTPUT: 696*f0d73e0fSSylvain Deverre// - FS:[BX] : Address to write to 697*f0d73e0fSSylvain DeverreReadNonResidentAttribute: 698*f0d73e0fSSylvain Deverre #define currentLCN 4 699*f0d73e0fSSylvain Deverre #define offsetWrite 8 700*f0d73e0fSSylvain Deverre #define startReadLCN HEX(0C) 701*f0d73e0fSSylvain Deverre push bp 702*f0d73e0fSSylvain Deverre mov bp, sp 703*f0d73e0fSSylvain Deverre sub sp, HEX(10) 704*f0d73e0fSSylvain Deverre push edx 705*f0d73e0fSSylvain Deverre push si 706*f0d73e0fSSylvain Deverre mov dword ptr [bp - currentLCN], 0 // Store the current LCN 707*f0d73e0fSSylvain Deverre mov word ptr [bp - offsetWrite], bx 708*f0d73e0fSSylvain Deverre mov dword ptr [bp - startReadLCN], ecx 709*f0d73e0fSSylvain Deverre mov si, ax 710*f0d73e0fSSylvain Deverre xor edx, edx 711*f0d73e0fSSylvain Deverre RunLoop: 712*f0d73e0fSSylvain Deverre mov al, byte ptr es:[si] 713*f0d73e0fSSylvain Deverre test al, al 714*f0d73e0fSSylvain Deverre jz NotFound 715*f0d73e0fSSylvain Deverre call UnpackRun 716*f0d73e0fSSylvain Deverre add dword ptr [bp - currentLCN], eax 717*f0d73e0fSSylvain Deverre cmp dword ptr [bp - startReadLCN], ecx 718*f0d73e0fSSylvain Deverre jb FoundRun 719*f0d73e0fSSylvain Deverre sub dword ptr [bp - startReadLCN], ecx // Decrement the cluster 720*f0d73e0fSSylvain Deverre jmp RunLoop 721*f0d73e0fSSylvain Deverre FoundRun: 722*f0d73e0fSSylvain Deverre mov ebx, dword ptr [bp - currentLCN] 723*f0d73e0fSSylvain Deverre mov ecx, dword ptr [bp - startReadLCN] 724*f0d73e0fSSylvain Deverre add ebx, ecx 725*f0d73e0fSSylvain Deverre 726*f0d73e0fSSylvain Deverre push es 727*f0d73e0fSSylvain Deverre mov ax, fs 728*f0d73e0fSSylvain Deverre mov es, ax 729*f0d73e0fSSylvain Deverre mov eax, ebx 730*f0d73e0fSSylvain Deverre mov bx, word ptr [bp - offsetWrite] 731*f0d73e0fSSylvain Deverre call ReadCluster 732*f0d73e0fSSylvain Deverre pop es 733*f0d73e0fSSylvain Deverre jmp RunSearchEnd 734*f0d73e0fSSylvain Deverre NotFound: 735*f0d73e0fSSylvain Deverre xor ax, ax 736*f0d73e0fSSylvain Deverre RunSearchEnd: 737*f0d73e0fSSylvain Deverre pop si 738*f0d73e0fSSylvain Deverre pop edx 739*f0d73e0fSSylvain Deverre mov sp, bp 740*f0d73e0fSSylvain Deverre pop bp 741*f0d73e0fSSylvain Deverre ret 742*f0d73e0fSSylvain Deverre 743*f0d73e0fSSylvain Deverre// Decodes a run in the runlist 744*f0d73e0fSSylvain Deverre// INPUT: 745*f0d73e0fSSylvain Deverre// - ES:[SI] : address of the run 746*f0d73e0fSSylvain Deverre// OUTPUT: 747*f0d73e0fSSylvain Deverre// - EAX : Unpacked LCN 748*f0d73e0fSSylvain Deverre// - ECX : Unpacked run length (in sectors) 749*f0d73e0fSSylvain Deverre// - SI : Next run in the run list 750*f0d73e0fSSylvain DeverreUnpackRun: 751*f0d73e0fSSylvain Deverre push bp 752*f0d73e0fSSylvain Deverre mov bp, sp 753*f0d73e0fSSylvain Deverre sub sp, HEX(10) 754*f0d73e0fSSylvain Deverre push ebx 755*f0d73e0fSSylvain Deverre 756*f0d73e0fSSylvain Deverre // Unpack run header 757*f0d73e0fSSylvain Deverre mov bl, byte ptr es:[si] 758*f0d73e0fSSylvain Deverre inc si 759*f0d73e0fSSylvain Deverre 760*f0d73e0fSSylvain Deverre mov bh, bl 761*f0d73e0fSSylvain Deverre shr bh, 4 762*f0d73e0fSSylvain Deverre and bl, 7 763*f0d73e0fSSylvain Deverre mov byte ptr [bp-2], bh // BH contains the LCN length 764*f0d73e0fSSylvain Deverre mov byte ptr [bp-1], bl // BL contains the number of cluster length 765*f0d73e0fSSylvain Deverre 766*f0d73e0fSSylvain Deverre mov al, bl 767*f0d73e0fSSylvain Deverre call UnpackLen 768*f0d73e0fSSylvain Deverre mov dword ptr [bp - 8], ebx 769*f0d73e0fSSylvain Deverre 770*f0d73e0fSSylvain Deverre mov al, byte ptr [bp-2] 771*f0d73e0fSSylvain Deverre call UnpackLen 772*f0d73e0fSSylvain Deverre mov cl, byte ptr es:[si-1] // Fixup sign if last byte is > 255 773*f0d73e0fSSylvain Deverre test cl, HEX(80) 774*f0d73e0fSSylvain Deverre jz NoSign 775*f0d73e0fSSylvain Deverre not eax 776*f0d73e0fSSylvain Deverre add ebx, eax 777*f0d73e0fSSylvain Deverre 778*f0d73e0fSSylvain Deverre NoSign: 779*f0d73e0fSSylvain Deverre mov eax, ebx 780*f0d73e0fSSylvain Deverre mov ecx, dword ptr [bp - 8] 781*f0d73e0fSSylvain Deverre pop ebx 782*f0d73e0fSSylvain Deverre mov sp, bp 783*f0d73e0fSSylvain Deverre pop bp 784*f0d73e0fSSylvain Deverre ret 785*f0d73e0fSSylvain Deverre 786*f0d73e0fSSylvain Deverre 787*f0d73e0fSSylvain Deverre// Auxiliary function that unpacks n bytes in the memory 788*f0d73e0fSSylvain Deverre// INPUT: 789*f0d73e0fSSylvain Deverre// - AL : size to unpack (max 4 bytes) 790*f0d73e0fSSylvain Deverre// OUTPUT: 791*f0d73e0fSSylvain Deverre// - EAX : the mask used to unpack (for negative number fixup) 792*f0d73e0fSSylvain Deverre// - EBX : the unpacked number 793*f0d73e0fSSylvain Deverre// - SI : Next byte to read 794*f0d73e0fSSylvain DeverreUnpackLen: 795*f0d73e0fSSylvain Deverre push cx 796*f0d73e0fSSylvain Deverre movzx ax, al 797*f0d73e0fSSylvain Deverre 798*f0d73e0fSSylvain Deverre // Read the whole DWORD and then compute a mask to remove 799*f0d73e0fSSylvain Deverre // unneeded bytes to get correct size 800*f0d73e0fSSylvain Deverre xor ebx, ebx 801*f0d73e0fSSylvain Deverre mov ebx, dword ptr es:[si] 802*f0d73e0fSSylvain Deverre add si, ax 803*f0d73e0fSSylvain Deverre 804*f0d73e0fSSylvain Deverre cmp al, 4 805*f0d73e0fSSylvain Deverre jnz UnpackLen_not4 806*f0d73e0fSSylvain Deverre xor eax, eax 807*f0d73e0fSSylvain Deverre dec eax 808*f0d73e0fSSylvain Deverre jmp UnpackLen_mask 809*f0d73e0fSSylvain Deverre 810*f0d73e0fSSylvain DeverreUnpackLen_not4: 811*f0d73e0fSSylvain Deverre mov cl, al // Compute mask (2^(8*len) - 1) 812*f0d73e0fSSylvain Deverre shl cl, 3 813*f0d73e0fSSylvain Deverre xor eax, eax 814*f0d73e0fSSylvain Deverre inc eax 815*f0d73e0fSSylvain Deverre shl eax, cl 816*f0d73e0fSSylvain Deverre dec eax 817*f0d73e0fSSylvain Deverre 818*f0d73e0fSSylvain DeverreUnpackLen_mask: 819*f0d73e0fSSylvain Deverre and ebx, eax // Apply mask 820*f0d73e0fSSylvain Deverre pop cx 821*f0d73e0fSSylvain Deverre ret 822*f0d73e0fSSylvain Deverre 823*f0d73e0fSSylvain Deverre// Reads an INDX sector and applies fixups 824*f0d73e0fSSylvain Deverre// INPUT: 825*f0d73e0fSSylvain Deverre// - ES:[AX] : Address of the data runs 826*f0d73e0fSSylvain Deverre// - ECX : LCN to read 827*f0d73e0fSSylvain Deverre// OUTPUT: 828*f0d73e0fSSylvain Deverre// - FS:[BX] : Address to write to 829*f0d73e0fSSylvain DeverreReadINDX: 830*f0d73e0fSSylvain Deverre push es 831*f0d73e0fSSylvain Deverre push bx 832*f0d73e0fSSylvain Deverre call ReadNonResidentAttribute 833*f0d73e0fSSylvain Deverre test ax, ax 834*f0d73e0fSSylvain Deverre jz PrintFileSystemError 835*f0d73e0fSSylvain Deverre cmp dword ptr fs:[0], INDX_MAGIC 836*f0d73e0fSSylvain Deverre jnz PrintFileSystemError // jump if not valid 837*f0d73e0fSSylvain Deverre pop bx 838*f0d73e0fSSylvain Deverre 839*f0d73e0fSSylvain Deverre mov ax, fs 840*f0d73e0fSSylvain Deverre mov es, ax 841*f0d73e0fSSylvain Deverre call ApplyFixups 842*f0d73e0fSSylvain Deverre pop es 843*f0d73e0fSSylvain Deverre ret 844*f0d73e0fSSylvain Deverre 845*f0d73e0fSSylvain Deverre// Finds an attribute header into the MFT 846*f0d73e0fSSylvain Deverre// INPUT: 847*f0d73e0fSSylvain Deverre// - ES:[AX] : pointer to the MFT entry 848*f0d73e0fSSylvain Deverre// - EBX : type to find 849*f0d73e0fSSylvain Deverre// OUTPUT: 850*f0d73e0fSSylvain Deverre// - ES:[AX] : Pointer to the attribute header in the MFT entry 851*f0d73e0fSSylvain DeverreFindAttributeHdr: 852*f0d73e0fSSylvain Deverre push cx 853*f0d73e0fSSylvain Deverre push si 854*f0d73e0fSSylvain Deverre push edx 855*f0d73e0fSSylvain Deverre mov si, ax 856*f0d73e0fSSylvain Deverre mov cx, word ptr es:[si+HEX(14)] // Get offset attribute 857*f0d73e0fSSylvain Deverre add si, cx 858*f0d73e0fSSylvain Deverre FindAttributeHdrLoop: 859*f0d73e0fSSylvain Deverre mov edx, dword ptr es:[si] // Get attribute type 860*f0d73e0fSSylvain Deverre cmp edx, ebx 861*f0d73e0fSSylvain Deverre jz AttrFound 862*f0d73e0fSSylvain Deverre cmp edx, HEX(ffffffff) 863*f0d73e0fSSylvain Deverre jz AttrNotFound 864*f0d73e0fSSylvain Deverre add cx, word ptr es:[si + 4] // Add size of the attribute 865*f0d73e0fSSylvain Deverre add si, word ptr es:[si + 4] 866*f0d73e0fSSylvain Deverre jmp FindAttributeHdrLoop 867*f0d73e0fSSylvain Deverre 868*f0d73e0fSSylvain Deverre AttrNotFound: 869*f0d73e0fSSylvain Deverre // Attribute not found, reset the offset 870*f0d73e0fSSylvain Deverre xor cx, cx 871*f0d73e0fSSylvain Deverre AttrFound: 872*f0d73e0fSSylvain Deverre mov ax, cx 873*f0d73e0fSSylvain Deverre pop edx 874*f0d73e0fSSylvain Deverre pop si 875*f0d73e0fSSylvain Deverre pop cx 876*f0d73e0fSSylvain Deverre ret 877*f0d73e0fSSylvain Deverre 878*f0d73e0fSSylvain DeverrePrintFreeldrError: 879*f0d73e0fSSylvain Deverre mov si, offset msgFreeldr 880*f0d73e0fSSylvain Deverre call PutChars 881*f0d73e0fSSylvain Deverre jmp Reboot 882*f0d73e0fSSylvain Deverre 883*f0d73e0fSSylvain DeverreFreeLdr: 884*f0d73e0fSSylvain Deverre .word 'F', 'R', 'E', 'E', 'L', 'D', 'R', '.', 'S', 'Y', 'S' 885*f0d73e0fSSylvain DeverremsgFreeldr: 886*f0d73e0fSSylvain Deverre .ascii "FreeLdr not found, cannot boot", CR, LF, NUL 887*f0d73e0fSSylvain DeverremsgLoading: 888*f0d73e0fSSylvain Deverre .ascii "Loading FreeLoader...", CR, LF, NUL 889*f0d73e0fSSylvain DeverremsgFreeldrCompressed: 890*f0d73e0fSSylvain Deverre .ascii "freeldr.sys is a sparse, compressed or encrypted file, cannot boot", CR, LF, NUL 891*f0d73e0fSSylvain Deverre.endcode16 892*f0d73e0fSSylvain Deverre 893*f0d73e0fSSylvain DeverreEND 894