Convert comments to preprocessor format

svn path=/trunk/; revision=53928
This commit is contained in:
Timo Kreuzer 2011-10-02 15:33:39 +00:00
parent a4bc1ebf2b
commit 58e525b4b8

View file

@ -1,11 +1,11 @@
; EXT2.ASM // EXT2.ASM
; EXT2 Boot Sector // EXT2 Boot Sector
; Copyright (c) 2002, 2003 Brian Palmer // Copyright (c) 2002, 2003 Brian Palmer
; [bp-0x04] Here we will store the number of sectors per track // [bp-0x04] Here we will store the number of sectors per track
; [bp-0x08] Here we will store the number of heads // [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-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 // [bp-0x10] Here we will store the number of LBA sectors read
SECTORS_PER_TRACK equ 0x04 SECTORS_PER_TRACK equ 0x04
NUMBER_OF_HEADS equ 0x08 NUMBER_OF_HEADS equ 0x08
@ -29,20 +29,20 @@ start:
nop nop
BootDrive db 0x80 BootDrive db 0x80
;BootPartition db 0 ; Moved to end of boot sector to have a standard format across all boot sectors //BootPartition db 0 // Moved to end of boot sector to have a standard format across all boot sectors
;SectorsPerTrack db 63 ; Moved to [bp-SECTORS_PER_TRACK] //SectorsPerTrack db 63 // Moved to [bp-SECTORS_PER_TRACK]
;NumberOfHeads dw 16 ; Moved to [bp-NUMBER_OF_HEADS] //NumberOfHeads dw 16 // Moved to [bp-NUMBER_OF_HEADS]
;BiosCHSDriveSize dd (1024 * 1024 * 63) ; Moved to [bp-BIOS_CHS_DRIVE_SIZE] //BiosCHSDriveSize dd (1024 * 1024 * 63) // Moved to [bp-BIOS_CHS_DRIVE_SIZE]
;LBASectorsRead dd 0 ; Moved to [bp-LBA_SECTORS_READ] //LBASectorsRead dd 0 // Moved to [bp-LBA_SECTORS_READ]
Ext2VolumeStartSector dd 263088 ; Start sector of the ext2 volume Ext2VolumeStartSector dd 263088 // Start sector of the ext2 volume
Ext2BlockSize dd 2 ; Block size in sectors Ext2BlockSize dd 2 // Block size in sectors
Ext2BlockSizeInBytes dd 1024 ; Block size in bytes Ext2BlockSizeInBytes dd 1024 // Block size in bytes
Ext2PointersPerBlock dd 256 ; Number of block pointers that can be contained in one block Ext2PointersPerBlock dd 256 // Number of block pointers that can be contained in one block
Ext2GroupDescPerBlock dd 32 ; Number of group descriptors per 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) Ext2FirstDataBlock dd 1 // First data block (1 for 1024-byte blocks, 0 for bigger sizes)
Ext2InodesPerGroup dd 2048 ; Number of inodes per group Ext2InodesPerGroup dd 2048 // Number of inodes per group
Ext2InodesPerBlock dd 8 ; Number of inodes per block Ext2InodesPerBlock dd 8 // Number of inodes per block
Ext2ReadEntireFileLoadSegment: Ext2ReadEntireFileLoadSegment:
dw 0 dw 0
@ -54,83 +54,83 @@ Ext2BlocksLeftToRead:
dd 0 dd 0
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,7b00h ; Setup a stack mov sp,7b00h // 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 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
mov [BYTE bp-NUMBER_OF_HEADS],eax ; Save number of heads mov [BYTE bp-NUMBER_OF_HEADS],eax // Save number of heads
mov [BYTE bp-SECTORS_PER_TRACK],ecx ; Save number of sectors per track mov [BYTE bp-SECTORS_PER_TRACK],ecx // Save number of sectors per track
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-BIOS_CHS_DRIVE_SIZE],eax mov [BYTE bp-BIOS_CHS_DRIVE_SIZE],eax
LoadExtraBootCode: LoadExtraBootCode:
; First we have to load our extra boot code at // First we have to load our extra boot code at
; sector 1 into memory at [0000:7e00h] // sector 1 into memory at [0000:7e00h]
;mov eax,01h //mov eax,01h
xor eax,eax xor eax,eax
inc eax ; Read logical sector 1, EAX now = 1 inc eax // Read logical sector 1, EAX now = 1
mov cx,1 ; Read one sector mov cx,1 // Read one sector
mov bx,7e00h ; Read sector to [0000:7e00h] mov bx,7e00h // Read sector to [0000:7e00h]
call ReadSectors call ReadSectors
jmp LoadRootDirectory jmp LoadRootDirectory
; Reads ext2 group descriptor into [7000:8000] // Reads ext2 group descriptor into [7000:8000]
; We read it to this arbitrary location so // We read it to this arbitrary location so
; it will not cross a 64k boundary // it will not cross a 64k boundary
; EAX has group descriptor number to read // EAX has group descriptor number to read
Ext2ReadGroupDesc: Ext2ReadGroupDesc:
shl eax,5 ; Group = (Group * sizeof(GROUP_DESCRIPTOR) /* 32 */) shl eax,5 // Group = (Group * sizeof(GROUP_DESCRIPTOR) /* 32 */)
xor edx,edx xor edx,edx
div DWORD [BYTE bp+Ext2GroupDescPerBlock] ; Group = (Group / Ext2GroupDescPerBlock) div DWORD [BYTE bp+Ext2GroupDescPerBlock] // Group = (Group / Ext2GroupDescPerBlock)
add eax,DWORD [BYTE bp+Ext2FirstDataBlock] ; Group = Group + Ext2FirstDataBlock + 1 add eax,DWORD [BYTE bp+Ext2FirstDataBlock] // Group = Group + Ext2FirstDataBlock + 1
inc eax ; EAX now has the group descriptor block number inc eax // EAX now has the group descriptor block number
; EDX now has the group descriptor offset in the block // EDX now has the group descriptor offset in the block
; Adjust the read offset so that the // Adjust the read offset so that the
; group descriptor is read to 7000:8000 // group descriptor is read to 7000:8000
mov ebx,78000h mov ebx,78000h
sub ebx,edx sub ebx,edx
shr ebx,4 shr ebx,4
@ -138,51 +138,51 @@ Ext2ReadGroupDesc:
xor bx,bx xor bx,bx
; Everything is now setup to call Ext2ReadBlock // Everything is now setup to call Ext2ReadBlock
; Instead of using the call instruction we will // Instead of using the call instruction we will
; just put Ext2ReadBlock right after this routine // just put Ext2ReadBlock right after this routine
; Reads ext2 block into [ES:BX] // Reads ext2 block into [ES:BX]
; EAX has logical block number to read // EAX has logical block number to read
Ext2ReadBlock: Ext2ReadBlock:
mov ecx,DWORD [BYTE bp+Ext2BlockSize] mov ecx,DWORD [BYTE bp+Ext2BlockSize]
mul ecx mul ecx
jmp ReadSectors jmp ReadSectors
; Reads ext2 inode into [6000:8000] // Reads ext2 inode into [6000:8000]
; We read it to this arbitrary location so // We read it to this arbitrary location so
; it will not cross a 64k boundary // it will not cross a 64k boundary
; EAX has inode number to read // EAX has inode number to read
Ext2ReadInode: Ext2ReadInode:
dec eax ; Inode = Inode - 1 dec eax // Inode = Inode - 1
xor edx,edx xor edx,edx
div DWORD [BYTE bp+Ext2InodesPerGroup] ; Inode = (Inode / Ext2InodesPerGroup) div DWORD [BYTE bp+Ext2InodesPerGroup] // Inode = (Inode / Ext2InodesPerGroup)
mov ebx,eax ; EBX now has the inode group number mov ebx,eax // EBX now has the inode group number
mov eax,edx mov eax,edx
xor edx,edx xor edx,edx
div DWORD [BYTE bp+Ext2InodesPerBlock] ; Inode = (Inode / Ext2InodesPerBlock) div DWORD [BYTE bp+Ext2InodesPerBlock] // Inode = (Inode / Ext2InodesPerBlock)
shl edx,7 ; FIXME: InodeOffset *= 128 (make the array index a byte offset) shl edx,7 // FIXME: InodeOffset *= 128 (make the array index a byte offset)
; EAX now has the inode offset block number from inode table // EAX now has the inode offset block number from inode table
; EDX now has the inode offset in the block // EDX now has the inode offset in the block
; Save the inode values and put the group // Save the inode values and put the group
; descriptor number in EAX and read it in // descriptor number in EAX and read it in
push edx push edx
push eax push eax
mov eax,ebx mov eax,ebx
call Ext2ReadGroupDesc call Ext2ReadGroupDesc
; Group descriptor has been read, now // Group descriptor has been read, now
; grab the inode table block number from it // grab the inode table block number from it
push WORD 7000h push WORD 7000h
pop es pop es
mov di,8008h mov di,8008h
pop eax ; Restore inode offset block number from stack pop eax // Restore inode offset block number from stack
add eax,DWORD [es:di] ; Add the inode table start block add eax,DWORD [es:di] // Add the inode table start block
; Adjust the read offset so that the // Adjust the read offset so that the
; inode we want is read to 6000:8000 // inode we want is read to 6000:8000
pop edx ; Restore inode offset in the block from stack pop edx // Restore inode offset in the block from stack
mov ebx,68000h mov ebx,68000h
sub ebx,edx sub ebx,edx
shr ebx,4 shr ebx,4
@ -193,131 +193,131 @@ Ext2ReadInode:
ret ret
; 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
ReadSectors: ReadSectors:
add eax,DWORD [BYTE bp+Ext2VolumeStartSector] ; Add the start of the volume 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 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 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,byte 64 ; Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64 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 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 [BYTE bp-LBA_SECTORS_READ],cx mov [BYTE bp-LBA_SECTORS_READ],cx
mov WORD [BYTE bp-LBA_SECTORS_READ+2],0 mov WORD [BYTE bp-LBA_SECTORS_READ+2],0
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 [BYTE bp-LBA_SECTORS_READ] mov ebx,DWORD [BYTE bp-LBA_SECTORS_READ]
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,[BYTE bp-LBA_SECTORS_READ] sub cx,[BYTE bp-LBA_SECTORS_READ]
jnz ReadSectorsLBA ; Read next sector jnz ReadSectorsLBA // Read next sector
ret ret
; 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
mov ecx,DWORD [BYTE bp-SECTORS_PER_TRACK] mov ecx,DWORD [BYTE bp-SECTORS_PER_TRACK]
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-NUMBER_OF_HEADS] ; Divide logical by number of heads div WORD [BYTE bp-NUMBER_OF_HEADS] // 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,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,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
; 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
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
@ -340,318 +340,318 @@ Done:
msgDiskError db 'Disk error',0 msgDiskError db 'Disk error',0
; Sorry, need the space... // Sorry, need the space...
;msgAnyKey db 'Press any key to restart',0 //msgAnyKey db 'Press any key to restart',0
msgAnyKey db 'Press any key',0 msgAnyKey db 'Press any key',0
times 509-($-$$) db 0 ; Pad to 509 bytes times 509-($-$$) db 0 // Pad to 509 bytes
BootPartition db 0 BootPartition db 0
dw 0aa55h ; BootSector signature dw 0aa55h // BootSector signature
; End of bootsector
; // End of bootsector
; Now starts the extra boot code that we will store //
; at sector 1 on a EXT2 volume // Now starts the extra boot code that we will store
// at sector 1 on a EXT2 volume
LoadRootDirectory: LoadRootDirectory:
mov eax,EXT2_ROOT_INO ; Put the root directory inode number in EAX mov eax,EXT2_ROOT_INO // Put the root directory inode number in EAX
call Ext2ReadInode ; Read in the inode call Ext2ReadInode // Read in the inode
; Point ES:DI to the inode structure at 6000:8000 // Point ES:DI to the inode structure at 6000:8000
push WORD 6000h push WORD 6000h
pop es pop es
mov di,8000h mov di,8000h
push di push di
push es ; Save these for later push es // Save these for later
; Get root directory size from inode structure // Get root directory size from inode structure
mov eax,DWORD [es:di+4] mov eax,DWORD [es:di+4]
push eax push eax
; Now that the inode has been read in load // Now that the inode has been read in load
; the root directory file data to 0000:8000 // the root directory file data to 0000:8000
call Ext2ReadEntireFile call Ext2ReadEntireFile
; Since the root directory was loaded to 0000:8000 // Since the root directory was loaded to 0000:8000
; then add 8000h to the root directory's size // then add 8000h to the root directory's size
pop eax pop eax
mov edx,8000h ; Set EDX to the current offset in the root directory 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 add eax,edx // Initially add 8000h to the size of the root directory
SearchRootDirectory: SearchRootDirectory:
push edx ; Save current offset in root directory push edx // Save current offset in root directory
push eax ; Save the size of the root directory push eax // Save the size of the root directory
; Now we have to convert the current offset // Now we have to convert the current offset
; in the root directory to a SEGMENT:OFFSET pair // in the root directory to a SEGMENT:OFFSET pair
mov eax,edx mov eax,edx
xor edx,edx xor edx,edx
mov ecx,16 mov ecx,16
div ecx ; Now AX:DX has segment & offset div ecx // Now AX:DX has segment & offset
mov es,ax mov es,ax
mov di,dx mov di,dx
push di ; Save the start of the directory entry push di // Save the start of the directory entry
add di,byte 8 ; Add the offset to the filename add di,byte 8 // Add the offset to the filename
mov si,filename mov si,filename
mov cl,11 mov cl,11
rep cmpsb ; Compare the file names rep cmpsb // Compare the file names
pop di pop di
pop eax pop eax
pop edx pop edx
jz FoundFile jz FoundFile
; Nope, didn't find it in this entry, keep looking // Nope, didn't find it in this entry, keep looking
movzx ecx,WORD [es:di+4] movzx ecx,WORD [es:di+4]
add edx,ecx add edx,ecx
; Check to see if we have reached the // Check to see if we have reached the
; end of the root directory // end of the root directory
cmp edx,eax cmp edx,eax
jb SearchRootDirectory jb SearchRootDirectory
jmp PrintFileNotFound jmp PrintFileNotFound
FoundFile: FoundFile:
mov eax,[es:di] ; Get inode number from directory entry mov eax,[es:di] // Get inode number from directory entry
call Ext2ReadInode ; Read in the inode call Ext2ReadInode // Read in the inode
; Point ES:DI to the inode structure at 6000:8000 // Point ES:DI to the inode structure at 6000:8000
pop es pop es
pop di ; These were saved earlier pop di // These were saved earlier
mov cx,[es:di] ; Get the file mode so we can make sure it's a regular file 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 and ch,EXT2_S_IFMT // Mask off everything but the file type
cmp ch,EXT2_S_IFREG ; Make sure it's a regular file cmp ch,EXT2_S_IFREG // Make sure it's a regular file
je LoadFreeLoader je LoadFreeLoader
jmp PrintRegFileError jmp PrintRegFileError
LoadFreeLoader: LoadFreeLoader:
mov si,msgLoading ; "Loading FreeLoader..." message mov si,msgLoading // "Loading FreeLoader..." message
call PutChars ; Display it call PutChars // Display it
call Ext2ReadEntireFile ; Read freeldr.sys to 0000:8000 call Ext2ReadEntireFile // Read freeldr.sys to 0000:8000
mov dl,[BYTE bp+BootDrive] mov dl,[BYTE bp+BootDrive]
mov dh,[BYTE bp+BootPartition] mov dh,[BYTE bp+BootPartition]
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
; Reads ext2 file data into [0000:8000] // Reads ext2 file data into [0000:8000]
; This function assumes that the file's // This function assumes that the file's
; inode has been read in to 6000:8000 *and* // inode has been read in to 6000:8000 *and*
; ES:DI points to 6000:8000 // ES:DI points to 6000:8000
; This will load all the blocks up to // This will load all the blocks up to
; and including the double-indirect pointers. // and including the double-indirect pointers.
; This should be sufficient because it // This should be sufficient because it
; allows for ~64MB which is much bigger // allows for ~64MB which is much bigger
; than we need for a boot loader. // than we need for a boot loader.
Ext2ReadEntireFile: Ext2ReadEntireFile:
; Reset the load segment // Reset the load segment
mov WORD [BYTE bp+Ext2ReadEntireFileLoadSegment],800h mov WORD [BYTE bp+Ext2ReadEntireFileLoadSegment],800h
; Now we must calculate how // Now we must calculate how
; many blocks to read in // many blocks to read in
; We will do this by rounding the // We will do this by rounding the
; file size up to the next block // file size up to the next block
; size and then dividing by the block size // size and then dividing by the block size
mov eax,DWORD [BYTE bp+Ext2BlockSizeInBytes] ; Get the block size in bytes mov eax,DWORD [BYTE bp+Ext2BlockSizeInBytes] // Get the block size in bytes
push eax push eax
dec eax ; Ext2BlockSizeInBytes -= 1 dec eax // Ext2BlockSizeInBytes -= 1
add eax,DWORD [es:di+4] ; Add the file size add eax,DWORD [es:di+4] // Add the file size
xor edx,edx xor edx,edx
pop ecx ; Divide by the block size in bytes pop ecx // Divide by the block size in bytes
div ecx ; EAX now contains the number of blocks to load div ecx // EAX now contains the number of blocks to load
push eax push eax
; Make sure the file size isn't zero // Make sure the file size isn't zero
cmp eax,byte 0 cmp eax,byte 0
jnz Ext2ReadEntireFile2 jnz Ext2ReadEntireFile2
jmp PrintFileSizeError jmp PrintFileSizeError
Ext2ReadEntireFile2: Ext2ReadEntireFile2:
; Save the indirect & double indirect pointers // Save the indirect & double indirect pointers
mov edx,DWORD [es:di+0x58] ; Get indirect pointer mov edx,DWORD [es:di+0x58] // Get indirect pointer
mov [BYTE bp+Ext2InodeIndirectPointer],edx ; Save indirect pointer mov [BYTE bp+Ext2InodeIndirectPointer],edx // Save indirect pointer
mov edx,DWORD [es:di+0x5c] ; Get double indirect pointer mov edx,DWORD [es:di+0x5c] // Get double indirect pointer
mov [BYTE bp+Ext2InodeDoubleIndirectPointer],edx ; Save double indirect pointer mov [BYTE bp+Ext2InodeDoubleIndirectPointer],edx // Save double indirect pointer
; Now copy the direct pointers to 7000:0000 // Now copy the direct pointers to 7000:0000
; so that we can call Ext2ReadDirectBlocks // so that we can call Ext2ReadDirectBlocks
push ds ; Save DS push ds // Save DS
push es push es
push WORD 7000h push WORD 7000h
pop es pop es
pop ds pop ds
mov si,8028h mov si,8028h
xor di,di ; DS:SI = 6000:8028 ES:DI = 7000:0000 xor di,di // DS:SI = 6000:8028 ES:DI = 7000:0000
mov cx,24 ; Moving 24 words of data mov cx,24 // Moving 24 words of data
rep movsw rep movsw
pop ds ; Restore DS pop ds // Restore DS
; Now we have all the block pointers in the // Now we have all the block pointers in the
; right location so read them in // right location so read them in
pop eax ; Restore the total number of blocks in this file pop eax // Restore the total number of blocks in this file
xor ecx,ecx ; Set the max count of blocks to read to 12 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 mov cl,12 // which is the number of direct block pointers in the inode
call Ext2ReadDirectBlockList call Ext2ReadDirectBlockList
; Check to see if we actually have // Check to see if we actually have
; blocks left to read // blocks left to read
cmp eax,byte 0 cmp eax,byte 0
jz Ext2ReadEntireFileDone jz Ext2ReadEntireFileDone
; Now we have read all the direct blocks in // Now we have read all the direct blocks in
; the inode. So now we have to read the indirect // the inode. So now we have to read the indirect
; block and read all it's direct blocks // block and read all it's direct blocks
push eax ; Save the total block count push eax // Save the total block count
mov eax,DWORD [BYTE bp+Ext2InodeIndirectPointer] ; Get the indirect block pointer mov eax,DWORD [BYTE bp+Ext2InodeIndirectPointer] // Get the indirect block pointer
push WORD 7000h push WORD 7000h
pop es pop es
xor bx,bx ; Set the load address to 7000:0000 xor bx,bx // Set the load address to 7000:0000
call Ext2ReadBlock ; Read the block call Ext2ReadBlock // Read the block
; Now we have all the block pointers from the // Now we have all the block pointers from the
; indirect block in the right location so read them in // indirect block in the right location so read them in
pop eax ; Restore the total block count pop eax // Restore the total block count
mov ecx,DWORD [BYTE bp+Ext2PointersPerBlock] ; Get the number of block pointers that one block contains mov ecx,DWORD [BYTE bp+Ext2PointersPerBlock] // Get the number of block pointers that one block contains
call Ext2ReadDirectBlockList call Ext2ReadDirectBlockList
; Check to see if we actually have // Check to see if we actually have
; blocks left to read // blocks left to read
cmp eax,byte 0 cmp eax,byte 0
jz Ext2ReadEntireFileDone jz Ext2ReadEntireFileDone
; Now we have read all the direct blocks from // Now we have read all the direct blocks from
; the inode's indirect block pointer. So now // the inode's indirect block pointer. So now
; we have to read the double indirect block // we have to read the double indirect block
; and read all it's indirect blocks // and read all it's indirect blocks
; (whew, it's a good thing I don't support triple 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 [BYTE bp+Ext2BlocksLeftToRead],eax // Save the total block count
mov eax,DWORD [BYTE bp+Ext2InodeDoubleIndirectPointer] ; Get the double indirect block pointer mov eax,DWORD [BYTE bp+Ext2InodeDoubleIndirectPointer] // Get the double indirect block pointer
push WORD 7800h push WORD 7800h
pop es pop es
push es ; Save an extra copy of this value on the stack push es // Save an extra copy of this value on the stack
xor bx,bx ; Set the load address to 7000:8000 xor bx,bx // Set the load address to 7000:8000
call Ext2ReadBlock ; Read the block call Ext2ReadBlock // Read the block
pop es ; Put 7800h into ES (saved on the stack already) pop es // Put 7800h into ES (saved on the stack already)
xor di,di xor di,di
Ext2ReadIndirectBlock: Ext2ReadIndirectBlock:
mov eax,DWORD [es:di] ; Get indirect block pointer mov eax,DWORD [es:di] // Get indirect block pointer
add di,BYTE 4 ; Update DI for next array index add di,BYTE 4 // Update DI for next array index
push es push es
push di push di
push WORD 7000h push WORD 7000h
pop es pop es
xor bx,bx ; Set the load address to 7000:0000 xor bx,bx // Set the load address to 7000:0000
call Ext2ReadBlock ; Read the indirect block call Ext2ReadBlock // Read the indirect block
; Now we have all the block pointers from the // Now we have all the block pointers from the
; indirect block in the right location so read them in // indirect block in the right location so read them in
mov eax,DWORD [BYTE bp+Ext2BlocksLeftToRead] ; Restore the total block count 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 mov ecx,DWORD [BYTE bp+Ext2PointersPerBlock] // Get the number of block pointers that one block contains
call Ext2ReadDirectBlockList call Ext2ReadDirectBlockList
mov [BYTE bp+Ext2BlocksLeftToRead],eax ; Save the total block count mov [BYTE bp+Ext2BlocksLeftToRead],eax // Save the total block count
pop di pop di
pop es pop es
; Check to see if we actually have // Check to see if we actually have
; blocks left to read // blocks left to read
cmp eax,byte 0 cmp eax,byte 0
jnz Ext2ReadIndirectBlock jnz Ext2ReadIndirectBlock
Ext2ReadEntireFileDone: Ext2ReadEntireFileDone:
ret ret
; Reads a maximum number of blocks // Reads a maximum number of blocks
; from an array at 7000:0000 // from an array at 7000:0000
; and updates the total count // and updates the total count
; ECX contains the max number of blocks to read // ECX contains the max number of blocks to read
; EAX contains the number of blocks left to read // EAX contains the number of blocks left to read
; On return: // On return:
; EAX contians the new number of blocks left to read // EAX contians the new number of blocks left to read
Ext2ReadDirectBlockList: Ext2ReadDirectBlockList:
cmp eax,ecx ; Compare it to the maximum number of blocks to read 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 ja CallExt2ReadDirectBlocks // If it will take more blocks then just read all of the blocks
mov cx,ax ; Otherwise adjust the block count accordingly mov cx,ax // Otherwise adjust the block count accordingly
CallExt2ReadDirectBlocks: CallExt2ReadDirectBlocks:
sub eax,ecx ; Subtract the number of blocks being read from the total count sub eax,ecx // Subtract the number of blocks being read from the total count
push eax ; Save the new total count push eax // Save the new total count
call Ext2ReadDirectBlocks call Ext2ReadDirectBlocks
pop eax ; Restore the total count pop eax // Restore the total count
ret ret
; Reads a specified number of blocks // Reads a specified number of blocks
; from an array at 7000:0000 // from an array at 7000:0000
; CX contains the number of blocks to read // CX contains the number of blocks to read
Ext2ReadDirectBlocks: Ext2ReadDirectBlocks:
push WORD 7000h push WORD 7000h
pop es pop es
xor di,di ; Set ES:DI = 7000:0000 xor di,di // Set ES:DI = 7000:0000
Ext2ReadDirectBlocksLoop: Ext2ReadDirectBlocksLoop:
mov eax,[es:di] ; Get direct block pointer from array mov eax,[es:di] // Get direct block pointer from array
add di,BYTE 4 ; Update DI for next array index add di,BYTE 4 // Update DI for next array index
push cx ; Save number of direct blocks left push cx // Save number of direct blocks left
push es ; Save array segment push es // Save array segment
push di ; Save array offset push di // Save array offset
mov es,[BYTE bp+Ext2ReadEntireFileLoadSegment] mov es,[BYTE bp+Ext2ReadEntireFileLoadSegment]
xor bx,bx ; Setup load address for next read xor bx,bx // Setup load address for next read
call Ext2ReadBlock ; Read the block (this updates ES for the next read) call Ext2ReadBlock // Read the block (this updates ES for the next read)
mov [BYTE bp+Ext2ReadEntireFileLoadSegment],es ; Save updated ES mov [BYTE bp+Ext2ReadEntireFileLoadSegment],es // Save updated ES
pop di ; Restore the array offset pop di // Restore the array offset
pop es ; Restore the array segment pop es // Restore the array segment
pop cx ; Restore the number of blocks left pop cx // Restore the number of blocks left
loop Ext2ReadDirectBlocksLoop loop Ext2ReadDirectBlocksLoop
; At this point all the direct blocks should // At this point all the direct blocks should
; be loaded and ES (Ext2ReadEntireFileLoadSegment) // be loaded and ES (Ext2ReadEntireFileLoadSegment)
; should be ready for the next read. // should be ready for the next read.
ret ret
; Displays a file not found error message // Displays a file not found error message
; And reboots // And reboots
PrintFileNotFound: PrintFileNotFound:
mov si,msgFreeLdr ; FreeLdr not found message mov si,msgFreeLdr // FreeLdr not found message
jmp short DisplayItAndReboot jmp short DisplayItAndReboot
; Displays a file size is 0 error // Displays a file size is 0 error
; And reboots // And reboots
PrintFileSizeError: PrintFileSizeError:
mov si,msgFileSize ; Error message mov si,msgFileSize // Error message
jmp short DisplayItAndReboot jmp short DisplayItAndReboot
; Displays a file is not a regular file error // Displays a file is not a regular file error
; And reboots // And reboots
PrintRegFileError: PrintRegFileError:
mov si,msgRegFile ; Error message mov si,msgRegFile // Error message
DisplayItAndReboot: DisplayItAndReboot:
call PutChars ; Display it call PutChars // Display it
jmp Reboot jmp Reboot
msgFreeLdr db 'freeldr.sys not found',0 msgFreeLdr db 'freeldr.sys not found',0
@ -660,6 +660,6 @@ msgRegFile db 'freeldr.sys isnt a regular file',0
filename db 'freeldr.sys' filename db 'freeldr.sys'
msgLoading db 'Loading FreeLoader...',0 msgLoading db 'Loading FreeLoader...',0
times 1022-($-$$) db 0 ; Pad to 1022 bytes times 1022-($-$$) db 0 // Pad to 1022 bytes
dw 0aa55h ; BootSector signature dw 0aa55h // BootSector signature