mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 17:44:45 +00:00
367cfa7085
- Boot sector code now reports to freeldr.sys the partition that it was installed on. This is specified by a byte value in the boot sector code. By default the boot partition is set to zero which indicates the active (bootable) partition, unless the installer sets the value to non-zero. If FreeLoader is installed on a partition other than the active (bootable) partition then the installer must set this byte to that partition number. Otherwise FreeLoader will not be able to find freeldr.ini. - i386trap.S: Added debug macros BREAKPOINT(), INSTRUCTION_BREAKPOINTX(), MEMORY_READWRITE_BREAKPOINTX(), & MEMORY_WRITE_BREAKPOINTX(). - partition.c (DiskGetPartitionEntry): Add the relative offset of the extended partition to the partitions start sector. - ext2.c (Ext2ReadBlockPointerList, Ext2CopyIndirectBlockPointers, Ext2CopyDoubleIndirectBlockPointers, Ext2CopyTripleIndirectBlockPointers): Rewrote the block pointer functions so they actually work. - ini_init.c (IniFileInitialize, IniOpenIniFile): Looks for freeldr.ini on both the active (bootable) partition and the partition passed in from the boot sector code. - meminit.c (MmInitializeMemoryManager, MmFixupSystemMemoryMap, MmGetEndAddressOfAnyMemory, MmGetAddressablePageCountIncludingHoles, MmInitPageLookupTable): Fixed bug that would cause FreeLoader to have an off-by-one error when accessing the last entry in the page lookup table on systems with 4GB of memory (or memory mapped at the end of the address space). svn path=/trunk/; revision=3372
652 lines
21 KiB
NASM
652 lines
21 KiB
NASM
; EXT2.ASM
|
|
; EXT2 Boot Sector
|
|
; Copyright (c) 2002 Brian Palmer
|
|
|
|
; [bp-0x04] Here we will store the number of sectors per track
|
|
; [bp-0x08] Here we will store the number of heads
|
|
; [bp-0x0c] Here we will store the size of the disk as the BIOS reports in CHS form
|
|
; [bp-0x10] Here we will store the number of LBA sectors read
|
|
|
|
SECTORS_PER_TRACK equ 0x04
|
|
NUMBER_OF_HEADS equ 0x08
|
|
BIOS_CHS_DRIVE_SIZE equ 0x0C
|
|
LBA_SECTORS_READ equ 0x10
|
|
|
|
|
|
EXT2_ROOT_INO equ 2
|
|
EXT2_S_IFMT equ 0f0h
|
|
EXT2_S_IFREG equ 080h
|
|
|
|
|
|
org 7c00h
|
|
|
|
segment .text
|
|
|
|
bits 16
|
|
|
|
start:
|
|
jmp short main
|
|
nop
|
|
|
|
BootDrive db 0x80
|
|
BootPartition db 0
|
|
;SectorsPerTrack db 63 ; Moved to [bp-SECTORS_PER_TRACK]
|
|
;NumberOfHeads dw 16 ; Moved to [bp-NUMBER_OF_HEADS]
|
|
;BiosCHSDriveSize dd (1024 * 1024 * 63) ; Moved to [bp-BIOS_CHS_DRIVE_SIZE]
|
|
;LBASectorsRead dd 0 ; Moved to [bp-LBA_SECTORS_READ]
|
|
|
|
Ext2VolumeStartSector dd 263088 ; Start sector of the ext2 volume
|
|
Ext2BlockSize dd 2 ; Block size in sectors
|
|
Ext2BlockSizeInBytes dd 1024 ; Block size in bytes
|
|
Ext2PointersPerBlock dd 256 ; Number of block pointers that can be contained in one block
|
|
Ext2GroupDescPerBlock dd 32 ; Number of group descriptors per block
|
|
Ext2FirstDataBlock dd 1 ; First data block (1 for 1024-byte blocks, 0 for bigger sizes)
|
|
Ext2InodesPerGroup dd 2048 ; Number of inodes per group
|
|
Ext2InodesPerBlock dd 8 ; Number of inodes per block
|
|
|
|
Ext2ReadEntireFileLoadSegment:
|
|
dw 0
|
|
Ext2InodeIndirectPointer:
|
|
dd 0
|
|
Ext2InodeDoubleIndirectPointer:
|
|
dd 0
|
|
Ext2BlocksLeftToRead:
|
|
dd 0
|
|
|
|
main:
|
|
xor ax,ax ; Setup segment registers
|
|
mov ds,ax ; Make DS correct
|
|
mov es,ax ; Make ES correct
|
|
mov ss,ax ; Make SS correct
|
|
mov bp,7c00h
|
|
mov sp,7b00h ; Setup a stack
|
|
|
|
|
|
GetDriveParameters:
|
|
mov ax,0800h
|
|
mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl
|
|
int 13h ; 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,0ffffh
|
|
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,3fh ; 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
|
|
mov [BYTE bp-NUMBER_OF_HEADS],eax ; Save number of heads
|
|
mov [BYTE bp-SECTORS_PER_TRACK],ecx ; Save number of sectors per track
|
|
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 [BYTE bp-BIOS_CHS_DRIVE_SIZE],eax
|
|
|
|
|
|
LoadExtraBootCode:
|
|
; First we have to load our extra boot code at
|
|
; sector 1 into memory at [0000:7e00h]
|
|
;mov eax,01h
|
|
xor eax,eax
|
|
inc eax ; Read logical sector 1, EAX now = 1
|
|
mov cx,1 ; Read one sector
|
|
mov bx,7e00h ; Read sector to [0000:7e00h]
|
|
call ReadSectors
|
|
|
|
jmp LoadRootDirectory
|
|
|
|
|
|
|
|
; Reads ext2 group descriptor into [7000:8000]
|
|
; We read it to this arbitrary location so
|
|
; it will not cross a 64k boundary
|
|
; EAX has group descriptor number to read
|
|
Ext2ReadGroupDesc:
|
|
shl eax,5 ; Group = (Group * sizeof(GROUP_DESCRIPTOR) /* 32 */)
|
|
xor edx,edx
|
|
div DWORD [BYTE bp+Ext2GroupDescPerBlock] ; Group = (Group / Ext2GroupDescPerBlock)
|
|
add eax,DWORD [BYTE bp+Ext2FirstDataBlock] ; Group = Group + Ext2FirstDataBlock + 1
|
|
inc eax ; EAX now has the group descriptor block number
|
|
; EDX now has the group descriptor offset in the block
|
|
|
|
; Adjust the read offset so that the
|
|
; group descriptor is read to 7000:8000
|
|
mov ebx,78000h
|
|
sub ebx,edx
|
|
shr ebx,4
|
|
mov es,bx
|
|
xor bx,bx
|
|
|
|
|
|
; Everything is now setup to call Ext2ReadBlock
|
|
; Instead of using the call instruction we will
|
|
; just put Ext2ReadBlock right after this routine
|
|
|
|
; Reads ext2 block into [ES:BX]
|
|
; EAX has logical block number to read
|
|
Ext2ReadBlock:
|
|
mov ecx,DWORD [BYTE bp+Ext2BlockSize]
|
|
mul ecx
|
|
jmp ReadSectors
|
|
|
|
; Reads ext2 inode into [6000:8000]
|
|
; We read it to this arbitrary location so
|
|
; it will not cross a 64k boundary
|
|
; EAX has inode number to read
|
|
Ext2ReadInode:
|
|
dec eax ; Inode = Inode - 1
|
|
xor edx,edx
|
|
div DWORD [BYTE bp+Ext2InodesPerGroup] ; Inode = (Inode / Ext2InodesPerGroup)
|
|
mov ebx,eax ; EBX now has the inode group number
|
|
mov eax,edx
|
|
xor edx,edx
|
|
div DWORD [BYTE bp+Ext2InodesPerBlock] ; Inode = (Inode / Ext2InodesPerBlock)
|
|
shl edx,7 ; FIXME: InodeOffset *= 128 (make the array index a byte offset)
|
|
; EAX now has the inode offset block number from inode table
|
|
; EDX now has the inode offset in the block
|
|
|
|
; Save the inode values and put the group
|
|
; descriptor number in EAX and read it in
|
|
push edx
|
|
push eax
|
|
mov eax,ebx
|
|
call Ext2ReadGroupDesc
|
|
|
|
; Group descriptor has been read, now
|
|
; grab the inode table block number from it
|
|
push WORD 7000h
|
|
pop es
|
|
mov di,8008h
|
|
pop eax ; Restore inode offset block number from stack
|
|
add eax,DWORD [es:di] ; Add the inode table start block
|
|
|
|
; Adjust the read offset so that the
|
|
; inode we want is read to 6000:8000
|
|
pop edx ; Restore inode offset in the block from stack
|
|
mov ebx,68000h
|
|
sub ebx,edx
|
|
shr ebx,4
|
|
mov es,bx
|
|
xor bx,bx
|
|
|
|
call Ext2ReadBlock
|
|
ret
|
|
|
|
|
|
; Reads logical sectors into [ES:BX]
|
|
; EAX has logical sector number to read
|
|
; CX has number of sectors to read
|
|
ReadSectors:
|
|
add eax,DWORD [BYTE bp+Ext2VolumeStartSector] ; Add the start of the volume
|
|
cmp eax,DWORD [BYTE bp-BIOS_CHS_DRIVE_SIZE] ; Check if they are reading a sector outside CHS range
|
|
jae ReadSectorsLBA ; Yes - go to the LBA routine
|
|
; If at all possible we want to use LBA routines because
|
|
; They are optimized to read more than 1 sector per read
|
|
|
|
pushad ; Save logical sector number & sector count
|
|
|
|
CheckInt13hExtensions: ; Now check if 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 ReadSectorsCHS ; CF set on error (extensions not supported)
|
|
cmp bx,0xaa55 ; BX = AA55h if installed
|
|
jne ReadSectorsCHS
|
|
test cl,1 ; CX = API subset support bitmap
|
|
jz ReadSectorsCHS ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
|
|
|
|
popad ; Restore sector count & logical sector number
|
|
|
|
ReadSectorsLBA:
|
|
pushad ; Save logical sector number & sector count
|
|
|
|
cmp cx,byte 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
|
|
mov cx,64 ; Otherwise read only 64 sectors on this loop iteration
|
|
|
|
ReadSectorsSetupDiskAddressPacket:
|
|
mov [BYTE bp-LBA_SECTORS_READ],cx
|
|
mov WORD [BYTE bp-LBA_SECTORS_READ+2],0
|
|
o32 push byte 0
|
|
push eax ; Put 64-bit logical block address on stack
|
|
push es ; Put transfer segment on stack
|
|
push bx ; Put transfer offset on stack
|
|
push cx ; Set transfer count
|
|
push byte 0x10 ; Set size of packet to 10h
|
|
mov si,sp ; Setup disk address packet on stack
|
|
|
|
|
|
mov dl,[BYTE bp+BootDrive] ; Drive number
|
|
mov ah,42h ; Int 13h, AH = 42h - Extended Read
|
|
int 13h ; Call BIOS
|
|
jc PrintDiskError ; If the read failed then abort
|
|
|
|
add sp,byte 0x10 ; Remove disk address packet from stack
|
|
|
|
popad ; Restore sector count & logical sector number
|
|
|
|
push bx
|
|
mov ebx,DWORD [BYTE bp-LBA_SECTORS_READ]
|
|
add eax,ebx ; Increment sector to read
|
|
shl ebx,5
|
|
mov dx,es
|
|
add dx,bx ; Setup read buffer for next sector
|
|
mov es,dx
|
|
pop bx
|
|
|
|
sub cx,[BYTE bp-LBA_SECTORS_READ]
|
|
jnz ReadSectorsLBA ; Read next sector
|
|
|
|
ret
|
|
|
|
|
|
; Reads logical sectors into [ES:BX]
|
|
; EAX has logical sector number to read
|
|
; CX has number of sectors to read
|
|
ReadSectorsCHS:
|
|
popad ; Get logical sector number & sector count off stack
|
|
|
|
ReadSectorsCHSLoop:
|
|
pushad
|
|
xor edx,edx
|
|
mov ecx,DWORD [BYTE bp-SECTORS_PER_TRACK]
|
|
div ecx ; Divide logical by SectorsPerTrack
|
|
inc dl ; Sectors numbering starts at 1 not 0
|
|
mov cl,dl ; Sector in CL
|
|
mov edx,eax
|
|
shr edx,16
|
|
div WORD [BYTE bp-NUMBER_OF_HEADS] ; Divide logical by number of heads
|
|
mov dh,dl ; Head in DH
|
|
mov dl,[BYTE bp+BootDrive] ; Drive number in DL
|
|
mov ch,al ; Cylinder in CX
|
|
ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits
|
|
ror ah,1 ; in CL shifted to bits 6 & 7
|
|
or cl,ah ; Or with sector number
|
|
mov ax,0201h
|
|
int 13h ; DISK - READ SECTORS INTO MEMORY
|
|
; AL = number of sectors to read, CH = track, CL = sector
|
|
; DH = head, DL = drive, ES:BX -> buffer to fill
|
|
; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
|
|
|
|
jc PrintDiskError ; If the read failed then abort
|
|
|
|
popad
|
|
|
|
inc eax ; Increment Sector to Read
|
|
|
|
mov dx,es
|
|
add dx,byte 20h ; Increment read buffer for next sector
|
|
mov es,dx
|
|
|
|
loop ReadSectorsCHSLoop ; Read next sector
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
; Displays a disk error message
|
|
; And reboots
|
|
PrintDiskError:
|
|
mov si,msgDiskError ; Bad boot disk message
|
|
call PutChars ; Display it
|
|
|
|
Reboot:
|
|
mov si,msgAnyKey ; Press any key message
|
|
call PutChars ; Display it
|
|
xor ax,ax
|
|
int 16h ; Wait for a keypress
|
|
int 19h ; Reboot
|
|
|
|
PutChars:
|
|
lodsb
|
|
or al,al
|
|
jz short Done
|
|
call PutCharsCallBios
|
|
jmp short PutChars
|
|
PutCharsCallBios:
|
|
mov ah,0eh
|
|
mov bx,07h
|
|
int 10h
|
|
retn
|
|
Done:
|
|
mov al,0dh
|
|
call PutCharsCallBios
|
|
mov al,0ah
|
|
call PutCharsCallBios
|
|
retn
|
|
|
|
|
|
|
|
msgDiskError db 'Disk error',0
|
|
msgAnyKey db 'Press any key to restart',0
|
|
|
|
times 510-($-$$) db 0 ; Pad to 510 bytes
|
|
dw 0aa55h ; BootSector signature
|
|
|
|
|
|
; End of bootsector
|
|
;
|
|
; Now starts the extra boot code that we will store
|
|
; at sector 1 on a EXT2 volume
|
|
|
|
|
|
|
|
LoadRootDirectory:
|
|
|
|
mov eax,EXT2_ROOT_INO ; Put the root directory inode number in EAX
|
|
call Ext2ReadInode ; Read in the inode
|
|
|
|
; Point ES:DI to the inode structure at 6000:8000
|
|
push WORD 6000h
|
|
pop es
|
|
mov di,8000h
|
|
push di
|
|
push es ; Save these for later
|
|
|
|
; Get root directory size from inode structure
|
|
mov eax,DWORD [es:di+4]
|
|
push eax
|
|
|
|
; Now that the inode has been read in load
|
|
; the root directory file data to 0000:8000
|
|
call Ext2ReadEntireFile
|
|
|
|
; Since the root directory was loaded to 0000:8000
|
|
; then add 8000h to the root directory's size
|
|
pop eax
|
|
mov edx,8000h ; Set EDX to the current offset in the root directory
|
|
add eax,edx ; Initially add 8000h to the size of the root directory
|
|
|
|
SearchRootDirectory:
|
|
push edx ; Save current offset in root directory
|
|
push eax ; Save the size of the root directory
|
|
|
|
; Now we have to convert the current offset
|
|
; in the root directory to a SEGMENT:OFFSET pair
|
|
mov eax,edx
|
|
xor edx,edx
|
|
mov ecx,16
|
|
div ecx ; Now AX:DX has segment & offset
|
|
mov es,ax
|
|
mov di,dx
|
|
push di ; Save the start of the directory entry
|
|
add di,byte 8 ; Add the offset to the filename
|
|
mov si,filename
|
|
mov cl,11
|
|
rep cmpsb ; Compare the file names
|
|
pop di
|
|
pop eax
|
|
pop edx
|
|
jz FoundFile
|
|
|
|
; Nope, didn't find it in this entry, keep looking
|
|
movzx ecx,WORD [es:di+4]
|
|
add edx,ecx
|
|
|
|
; Check to see if we have reached the
|
|
; end of the root directory
|
|
cmp edx,eax
|
|
jb SearchRootDirectory
|
|
jmp PrintFileNotFound
|
|
|
|
FoundFile:
|
|
mov eax,[es:di] ; Get inode number from directory entry
|
|
call Ext2ReadInode ; Read in the inode
|
|
|
|
; Point ES:DI to the inode structure at 6000:8000
|
|
pop es
|
|
pop di ; These were saved earlier
|
|
|
|
mov cx,[es:di] ; Get the file mode so we can make sure it's a regular file
|
|
and ch,EXT2_S_IFMT ; Mask off everything but the file type
|
|
cmp ch,EXT2_S_IFREG ; Make sure it's a regular file
|
|
je LoadFreeLoader
|
|
jmp PrintRegFileError
|
|
|
|
LoadFreeLoader:
|
|
mov si,msgLoading ; "Loading FreeLoader..." message
|
|
call PutChars ; Display it
|
|
|
|
call Ext2ReadEntireFile ; Read freeldr.sys to 0000:8000
|
|
|
|
mov dl,[BYTE bp+BootDrive]
|
|
mov dh,[BYTE bp+BootPartition]
|
|
push byte 0 ; We loaded at 0000:8000
|
|
push WORD 8000h ; We will do a far return to 0000:8000h
|
|
retf ; Transfer control to FreeLoader
|
|
|
|
|
|
|
|
|
|
|
|
; Reads ext2 file data into [0000:8000]
|
|
; This function assumes that the file's
|
|
; inode has been read in to 6000:8000 *and*
|
|
; ES:DI points to 6000:8000
|
|
; This will load all the blocks up to
|
|
; and including the double-indirect pointers.
|
|
; This should be sufficient because it
|
|
; allows for ~64MB which is much bigger
|
|
; than we need for a boot loader.
|
|
Ext2ReadEntireFile:
|
|
|
|
; Reset the load segment
|
|
mov WORD [BYTE bp+Ext2ReadEntireFileLoadSegment],800h
|
|
|
|
; Now we must calculate how
|
|
; many blocks to read in
|
|
; We will do this by rounding the
|
|
; file size up to the next block
|
|
; size and then dividing by the block size
|
|
mov eax,DWORD [BYTE bp+Ext2BlockSizeInBytes] ; Get the block size in bytes
|
|
push eax
|
|
dec eax ; Ext2BlockSizeInBytes -= 1
|
|
add eax,DWORD [es:di+4] ; Add the file size
|
|
xor edx,edx
|
|
pop ecx ; Divide by the block size in bytes
|
|
div ecx ; EAX now contains the number of blocks to load
|
|
push eax
|
|
|
|
; Make sure the file size isn't zero
|
|
cmp eax,byte 0
|
|
jnz Ext2ReadEntireFile2
|
|
jmp PrintFileSizeError
|
|
|
|
Ext2ReadEntireFile2:
|
|
; Save the indirect & double indirect pointers
|
|
mov edx,DWORD [es:di+0x58] ; Get indirect pointer
|
|
mov [BYTE bp+Ext2InodeIndirectPointer],edx ; Save indirect pointer
|
|
mov edx,DWORD [es:di+0x5c] ; Get double indirect pointer
|
|
mov [BYTE bp+Ext2InodeDoubleIndirectPointer],edx ; Save double indirect pointer
|
|
|
|
; Now copy the direct pointers to 7000:0000
|
|
; so that we can call Ext2ReadDirectBlocks
|
|
push ds ; Save DS
|
|
push es
|
|
push WORD 7000h
|
|
pop es
|
|
pop ds
|
|
mov si,8028h
|
|
xor di,di ; DS:SI = 6000:8028 ES:DI = 7000:0000
|
|
mov cx,24 ; Moving 24 words of data
|
|
rep movsw
|
|
pop ds ; Restore DS
|
|
|
|
; Now we have all the block pointers in the
|
|
; right location so read them in
|
|
pop eax ; Restore the total number of blocks in this file
|
|
xor ecx,ecx ; Set the max count of blocks to read to 12
|
|
mov cl,12 ; which is the number of direct block pointers in the inode
|
|
call Ext2ReadDirectBlockList
|
|
|
|
; Check to see if we actually have
|
|
; blocks left to read
|
|
cmp eax,byte 0
|
|
jz Ext2ReadEntireFileDone
|
|
|
|
; Now we have read all the direct blocks in
|
|
; the inode. So now we have to read the indirect
|
|
; block and read all it's direct blocks
|
|
push eax ; Save the total block count
|
|
mov eax,DWORD [BYTE bp+Ext2InodeIndirectPointer] ; Get the indirect block pointer
|
|
push WORD 7000h
|
|
pop es
|
|
xor bx,bx ; Set the load address to 7000:0000
|
|
call Ext2ReadBlock ; Read the block
|
|
|
|
; Now we have all the block pointers from the
|
|
; indirect block in the right location so read them in
|
|
pop eax ; Restore the total block count
|
|
mov ecx,DWORD [BYTE bp+Ext2PointersPerBlock] ; Get the number of block pointers that one block contains
|
|
call Ext2ReadDirectBlockList
|
|
|
|
; Check to see if we actually have
|
|
; blocks left to read
|
|
cmp eax,byte 0
|
|
jz Ext2ReadEntireFileDone
|
|
|
|
; Now we have read all the direct blocks from
|
|
; the inode's indirect block pointer. So now
|
|
; we have to read the double indirect block
|
|
; and read all it's indirect blocks
|
|
; (whew, it's a good thing I don't support triple indirect blocks)
|
|
mov [BYTE bp+Ext2BlocksLeftToRead],eax ; Save the total block count
|
|
mov eax,DWORD [BYTE bp+Ext2InodeDoubleIndirectPointer] ; Get the double indirect block pointer
|
|
push WORD 7800h
|
|
pop es
|
|
push es ; Save an extra copy of this value on the stack
|
|
xor bx,bx ; Set the load address to 7000:8000
|
|
call Ext2ReadBlock ; Read the block
|
|
|
|
pop es ; Put 7800h into ES (saved on the stack already)
|
|
xor di,di
|
|
|
|
Ext2ReadIndirectBlock:
|
|
mov eax,DWORD [es:di] ; Get indirect block pointer
|
|
add di,BYTE 4 ; Update DI for next array index
|
|
push es
|
|
push di
|
|
|
|
push WORD 7000h
|
|
pop es
|
|
xor bx,bx ; Set the load address to 7000:0000
|
|
call Ext2ReadBlock ; Read the indirect block
|
|
|
|
; Now we have all the block pointers from the
|
|
; indirect block in the right location so read them in
|
|
mov eax,DWORD [BYTE bp+Ext2BlocksLeftToRead] ; Restore the total block count
|
|
mov ecx,DWORD [BYTE bp+Ext2PointersPerBlock] ; Get the number of block pointers that one block contains
|
|
call Ext2ReadDirectBlockList
|
|
mov [BYTE bp+Ext2BlocksLeftToRead],eax ; Save the total block count
|
|
pop di
|
|
pop es
|
|
|
|
; Check to see if we actually have
|
|
; blocks left to read
|
|
cmp eax,byte 0
|
|
jnz Ext2ReadIndirectBlock
|
|
|
|
Ext2ReadEntireFileDone:
|
|
ret
|
|
|
|
; Reads a maximum number of blocks
|
|
; from an array at 7000:0000
|
|
; and updates the total count
|
|
; ECX contains the max number of blocks to read
|
|
; EAX contains the number of blocks left to read
|
|
; On return:
|
|
; EAX contians the new number of blocks left to read
|
|
Ext2ReadDirectBlockList:
|
|
cmp eax,ecx ; Compare it to the maximum number of blocks to read
|
|
ja CallExt2ReadDirectBlocks ; If it will take more blocks then just read all of the blocks
|
|
mov cx,ax ; Otherwise adjust the block count accordingly
|
|
|
|
CallExt2ReadDirectBlocks:
|
|
sub eax,ecx ; Subtract the number of blocks being read from the total count
|
|
push eax ; Save the new total count
|
|
call Ext2ReadDirectBlocks
|
|
pop eax ; Restore the total count
|
|
ret
|
|
|
|
|
|
; Reads a specified number of blocks
|
|
; from an array at 7000:0000
|
|
; CX contains the number of blocks to read
|
|
Ext2ReadDirectBlocks:
|
|
|
|
push WORD 7000h
|
|
pop es
|
|
xor di,di ; Set ES:DI = 7000:0000
|
|
|
|
Ext2ReadDirectBlocksLoop:
|
|
mov eax,[es:di] ; Get direct block pointer from array
|
|
add di,BYTE 4 ; Update DI for next array index
|
|
|
|
push cx ; Save number of direct blocks left
|
|
push es ; Save array segment
|
|
push di ; Save array offset
|
|
mov es,[BYTE bp+Ext2ReadEntireFileLoadSegment]
|
|
xor bx,bx ; Setup load address for next read
|
|
|
|
call Ext2ReadBlock ; Read the block (this updates ES for the next read)
|
|
|
|
mov [BYTE bp+Ext2ReadEntireFileLoadSegment],es ; Save updated ES
|
|
|
|
pop di ; Restore the array offset
|
|
pop es ; Restore the array segment
|
|
pop cx ; Restore the number of blocks left
|
|
|
|
loop Ext2ReadDirectBlocksLoop
|
|
|
|
; At this point all the direct blocks should
|
|
; be loaded and ES (Ext2ReadEntireFileLoadSegment)
|
|
; should be ready for the next read.
|
|
ret
|
|
|
|
|
|
|
|
; Displays a file not found error message
|
|
; And reboots
|
|
PrintFileNotFound:
|
|
mov si,msgFreeLdr ; FreeLdr not found message
|
|
jmp short DisplayAndRebootIt
|
|
|
|
; Displays a file size is 0 error
|
|
; And reboots
|
|
PrintFileSizeError:
|
|
mov si,msgFileSize ; Error message
|
|
jmp short DisplayAndRebootIt
|
|
|
|
; Displays a file is not a regular file error
|
|
; And reboots
|
|
PrintRegFileError:
|
|
mov si,msgRegFile ; Error message
|
|
DisplayAndRebootIt:
|
|
call PutChars ; Display it
|
|
jmp Reboot
|
|
|
|
msgFreeLdr db 'freeldr.sys not found',0
|
|
msgFileSize db 'File size is 0',0
|
|
msgRegFile db 'freeldr.sys isnt a regular file',0
|
|
filename db 'freeldr.sys'
|
|
msgLoading db 'Loading FreeLoader...',0
|
|
|
|
times 1022-($-$$) db 0 ; Pad to 1022 bytes
|
|
|
|
dw 0aa55h ; BootSector signature
|