mirror of
https://github.com/reactos/reactos.git
synced 2025-04-20 20:36:35 +00:00
[BOOTSECTORS] Use the new header with SPDX license identifier for the ISO boot sector files I contributed to.
Remove the unmaintained .asm files. svn path=/trunk/; revision=75984
This commit is contained in:
parent
d20eaaf8ca
commit
ea2806e13c
10 changed files with 13 additions and 4501 deletions
|
@ -1,179 +0,0 @@
|
|||
;
|
||||
; Normal DOS boot sector
|
||||
;
|
||||
; Ported to NASM from FreeDOS fdisk 1.2.0 by:
|
||||
; Casper Hornstrup (chorns@users.sourceforge.net)
|
||||
;
|
||||
|
||||
align 2, db 0
|
||||
|
||||
global _bootnormal_code
|
||||
_bootnormal_code:
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
; ENTRY (copied from freedos bootsector)
|
||||
;
|
||||
; IN: DL = boot drive
|
||||
;OUT: DL = boot drive
|
||||
;
|
||||
;-----------------------------------------------------------------------
|
||||
|
||||
real_start: cli
|
||||
cld
|
||||
xor ax, ax
|
||||
mov ss, ax ; initialize stack
|
||||
mov ds, ax
|
||||
mov bp, 0x7c00
|
||||
lea sp, [bp-0x20]
|
||||
sti
|
||||
|
||||
mov ax, 0x1FE0
|
||||
mov es, ax
|
||||
mov si, bp
|
||||
mov di, bp
|
||||
mov cx, 0x0100
|
||||
rep movsw
|
||||
|
||||
jmp word 0x1FE0:0x7c00+ cont-real_start
|
||||
|
||||
cont: mov ds, ax
|
||||
mov ss, ax
|
||||
xor ax,ax
|
||||
mov es,ax
|
||||
|
||||
|
||||
; search for active partition
|
||||
lea di, [bp+0x1be] ; start of partition table
|
||||
test_next_for_active:
|
||||
test byte [di],0x80
|
||||
jne active_partition_found
|
||||
add di,0x10 ; next table
|
||||
cmp di, 07c00h+0x1fe; scanned beyond end of table ??
|
||||
jb test_next_for_active
|
||||
|
||||
;*****************************************************************
|
||||
call print
|
||||
db 'No active partition found',0
|
||||
|
||||
WAIT_FOR_REBOOT:
|
||||
jmp $
|
||||
|
||||
|
||||
;*****************************************************************
|
||||
trouble_reading_drive:
|
||||
call print
|
||||
db 'Read error while reading drive',0
|
||||
jmp WAIT_FOR_REBOOT
|
||||
|
||||
;*****************************************************************
|
||||
|
||||
invalid_partition_code:
|
||||
call print
|
||||
db 'Partition signature != 55AA',0
|
||||
|
||||
jmp WAIT_FOR_REBOOT
|
||||
|
||||
|
||||
;*****************************************************************
|
||||
|
||||
active_partition_found:
|
||||
; call print
|
||||
; db 'Loading active partition',0
|
||||
|
||||
call read_boot_sector
|
||||
|
||||
jc trouble_reading_drive
|
||||
|
||||
cmp word [es:0x7c00+0x1fe],0xaa55
|
||||
jne invalid_partition_code
|
||||
|
||||
jmp word 0x0:0x7c00 ; and jump to boot sector code
|
||||
|
||||
|
||||
;*****************************
|
||||
; read_boot_sector
|
||||
;
|
||||
; IN: DI--> partition info
|
||||
;OUT:CARRY
|
||||
;*****************************
|
||||
|
||||
read_boot_sector:
|
||||
; /* check for LBA support */
|
||||
mov bx,0x55aa
|
||||
mov ah,0x41
|
||||
int 0x13
|
||||
|
||||
jc StandardBios ; if (regs.b.x != 0xaa55 || (regs.flags & 0x01))
|
||||
cmp bx,0xaa55 ; goto StandardBios;
|
||||
jne StandardBios
|
||||
|
||||
; /* if DAP cannot be used, don't use LBA */
|
||||
; if ((regs.c.x & 1) == 0)
|
||||
; goto StandardBios;
|
||||
test cl,1
|
||||
jz StandardBios
|
||||
|
||||
jmp short LBABios
|
||||
|
||||
|
||||
_bios_LBA_address_packet:
|
||||
db 0x10
|
||||
db 0
|
||||
db 4 ; read four sectors - why not
|
||||
db 0
|
||||
dw 0x7c00 ; fixed boot address for DOS sector
|
||||
dw 0x0000
|
||||
_bios_LBA_low dw 0
|
||||
_bios_LBA_high dw 0
|
||||
dw 0,0
|
||||
|
||||
|
||||
LBABios:
|
||||
; copy start address of partition to DAP
|
||||
mov ax,[di+8]
|
||||
mov [0x7c00+ (_bios_LBA_low-real_start)],ax
|
||||
mov ax,[di+8+2]
|
||||
mov [0x7c00+ (_bios_LBA_high-real_start)],ax
|
||||
|
||||
mov ax,0x4200 ; regs.a.x = LBA_READ;
|
||||
mov si,0x7c00+ (_bios_LBA_address_packet-real_start); regs.si = FP_OFF(&dap);
|
||||
|
||||
int 0x13
|
||||
ret
|
||||
|
||||
;*****************************************************************
|
||||
; read disk, using standard BIOS
|
||||
;
|
||||
StandardBios:
|
||||
mov ax,0x0204 ; regs.a.x = 0x0201;
|
||||
mov bx,0x7c00 ; regs.b.x = FP_OFF(buffer);
|
||||
mov cx,[di+2] ; regs.c.x =
|
||||
; ((chs.Cylinder & 0xff) << 8) + ((chs.Cylinder & 0x300) >> 2) +
|
||||
; chs.Sector;
|
||||
; that was easy ;-)
|
||||
mov dh,[di+1] ; regs.d.b.h = chs.Head;
|
||||
; regs.es = FP_SEG(buffer);
|
||||
int 0x13
|
||||
ret
|
||||
|
||||
|
||||
|
||||
;****** PRINT
|
||||
; prints text after call to this function.
|
||||
|
||||
print_1char:
|
||||
xor bx, bx ; video page 0
|
||||
mov ah, 0x0E ; else print it
|
||||
int 0x10 ; via TTY mode
|
||||
print: pop si ; this is the first character
|
||||
print1: lodsb ; get token
|
||||
push si ; stack up potential return address
|
||||
cmp al, 0 ; end of string?
|
||||
jne print_1char ; until done
|
||||
ret ; and jump to it
|
||||
|
||||
|
||||
|
||||
times 0x1fe-$+$$ db 0
|
||||
db 0x55,0xaa
|
||||
|
|
@ -1,665 +0,0 @@
|
|||
; EXT2.ASM
|
||||
; EXT2 Boot Sector
|
||||
; Copyright (c) 2002, 2003 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 ; Moved to end of boot sector to have a standard format across all boot sectors
|
||||
;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
|
||||
|
||||
|
||||
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
|
||||
jne GetDriveParameters
|
||||
|
||||
mov [BYTE bp+BootDrive],dl ; Save the boot drive
|
||||
|
||||
|
||||
GetDriveParameters:
|
||||
mov ah,08h
|
||||
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,2 ; Low 8 bits of cylinder in CH, high 2 bits
|
||||
; in CL shifted to bits 6 & 7
|
||||
or cl,ah ; Or with sector number
|
||||
mov ax,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
|
||||
; Sorry, need the space...
|
||||
;msgAnyKey db 'Press any key to restart',0
|
||||
msgAnyKey db 'Press any key',0
|
||||
|
||||
times 509-($-$$) db 0 ; Pad to 509 bytes
|
||||
|
||||
BootPartition db 0
|
||||
|
||||
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 0 ; push segment (0x0000)
|
||||
mov eax, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax
|
||||
add eax, 0x8000 ; RVA -> VA
|
||||
push ax ; push offset
|
||||
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 contains 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 DisplayItAndReboot
|
||||
|
||||
; Displays a file size is 0 error
|
||||
; And reboots
|
||||
PrintFileSizeError:
|
||||
mov si,msgFileSize ; Error message
|
||||
jmp short DisplayItAndReboot
|
||||
|
||||
; Displays a file is not a regular file error
|
||||
; And reboots
|
||||
PrintRegFileError:
|
||||
mov si,msgRegFile ; Error message
|
||||
DisplayItAndReboot:
|
||||
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
|
|
@ -1,404 +0,0 @@
|
|||
; FAT.ASM
|
||||
; FAT12/16 Boot Sector
|
||||
; Copyright (c) 1998, 2001, 2002 Brian Palmer
|
||||
|
||||
|
||||
|
||||
; This is a FAT12/16 file system boot sector
|
||||
; that searches the entire root directory
|
||||
; for the file freeldr.sys and loads it into
|
||||
; memory.
|
||||
;
|
||||
; The stack is set to 0000:7BF2 so that the first
|
||||
; WORD pushed will be placed at 0000:7BF0
|
||||
;
|
||||
; The DWORD at 0000:7BFC or BP-04h is the logical
|
||||
; sector number of the start of the data area.
|
||||
;
|
||||
; The DWORD at 0000:7BF8 or BP-08h is the total
|
||||
; sector count of the boot drive as reported by
|
||||
; the computers bios.
|
||||
;
|
||||
; The WORD at 0000:7BF6 or BP-0ah is the offset
|
||||
; of the ReadSectors function in the boot sector.
|
||||
;
|
||||
; The WORD at 0000:7BF4 or BP-0ch is the offset
|
||||
; of the ReadCluster function in the boot sector.
|
||||
;
|
||||
; The WORD at 0000:7BF2 or BP-0eh is the offset
|
||||
; of the PutChars function in the boot sector.
|
||||
;
|
||||
; When it locates freeldr.sys on the disk it will
|
||||
; load the first sector of the file to 0000:F800
|
||||
; With the help of this sector we should be able
|
||||
; to load the entire file off the disk, no matter
|
||||
; how fragmented it is.
|
||||
;
|
||||
; We load the entire FAT table into memory at
|
||||
; 7000:0000. This improves the speed of floppy disk
|
||||
; boots dramatically.
|
||||
|
||||
|
||||
BootSectorStackTop equ 0x7bf2
|
||||
DataAreaStartHigh equ 0x2
|
||||
DataAreaStartLow equ 0x4
|
||||
BiosCHSDriveSizeHigh equ 0x6
|
||||
BiosCHSDriveSizeLow equ 0x8
|
||||
BiosCHSDriveSize equ 0x8
|
||||
ReadSectorsOffset equ 0xa
|
||||
ReadClusterOffset equ 0xc
|
||||
PutCharsOffset equ 0xe
|
||||
|
||||
|
||||
org 7c00h
|
||||
|
||||
segment .text
|
||||
|
||||
bits 16
|
||||
|
||||
start:
|
||||
jmp short main
|
||||
nop
|
||||
|
||||
OEMName db 'FrLdr1.0'
|
||||
BytesPerSector dw 512
|
||||
SectsPerCluster db 1
|
||||
ReservedSectors dw 1
|
||||
NumberOfFats db 2
|
||||
MaxRootEntries dw 224
|
||||
TotalSectors dw 2880
|
||||
MediaDescriptor db 0f0h
|
||||
SectorsPerFat dw 9
|
||||
SectorsPerTrack dw 18
|
||||
NumberOfHeads dw 2
|
||||
HiddenSectors dd 0
|
||||
TotalSectorsBig dd 0
|
||||
BootDrive db 0xff
|
||||
Reserved db 0
|
||||
ExtendSig db 29h
|
||||
SerialNumber dd 00000000h
|
||||
VolumeLabel db 'NO NAME '
|
||||
FileSystem db 'FAT12 '
|
||||
|
||||
main:
|
||||
xor ax,ax
|
||||
mov ss,ax
|
||||
mov bp,7c00h
|
||||
mov sp,BootSectorStackTop ; Setup a stack
|
||||
mov ds,ax ; Make DS correct
|
||||
mov es,ax ; Make ES correct
|
||||
|
||||
|
||||
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
|
||||
jne GetDriveParameters
|
||||
|
||||
mov [BYTE bp+BootDrive],dl ; Save the boot drive
|
||||
|
||||
|
||||
GetDriveParameters:
|
||||
mov ah,08h
|
||||
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
|
||||
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-BiosCHSDriveSize],eax
|
||||
|
||||
|
||||
; Now we must find our way to the first sector of the root directory
|
||||
xor ax,ax
|
||||
xor cx,cx
|
||||
mov al,[BYTE bp+NumberOfFats] ; Number of fats
|
||||
mul WORD [BYTE bp+SectorsPerFat] ; Times sectors per fat
|
||||
add ax,WORD [BYTE bp+HiddenSectors]
|
||||
adc dx,WORD [BYTE bp+HiddenSectors+2] ; Add the number of hidden sectors
|
||||
add ax,WORD [BYTE bp+ReservedSectors] ; Add the number of reserved sectors
|
||||
adc dx,cx ; Add carry bit
|
||||
mov WORD [BYTE bp-DataAreaStartLow],ax ; Save the starting sector of the root directory
|
||||
mov WORD [BYTE bp-DataAreaStartHigh],dx ; Save it in the first 4 bytes before the boot sector
|
||||
mov si,WORD [BYTE bp+MaxRootEntries] ; Get number of root dir entries in SI
|
||||
pusha ; Save 32-bit logical start sector of root dir
|
||||
; DX:AX now has the number of the starting sector of the root directory
|
||||
|
||||
; Now calculate the size of the root directory
|
||||
xor dx,dx
|
||||
mov ax,0020h ; Size of dir entry
|
||||
mul si ; Times the number of entries
|
||||
mov bx,[BYTE bp+BytesPerSector]
|
||||
add ax,bx
|
||||
dec ax
|
||||
div bx ; Divided by the size of a sector
|
||||
; AX now has the number of root directory sectors
|
||||
|
||||
add [BYTE bp-DataAreaStartLow],ax ; Add the number of sectors of the root directory to our other value
|
||||
adc [BYTE bp-DataAreaStartHigh],cx ; Now the first 4 bytes before the boot sector contain the starting sector of the data area
|
||||
popa ; Restore root dir logical sector start to DX:AX
|
||||
|
||||
LoadRootDirSector:
|
||||
mov bx,7e0h ; We will load the root directory sector
|
||||
mov es,bx ; Right after the boot sector in memory
|
||||
xor bx,bx ; We will load it to [0000:7e00h]
|
||||
xor cx,cx ; Zero out CX
|
||||
inc cx ; Now increment it to 1, we are reading one sector
|
||||
xor di,di ; Zero out di
|
||||
push es ; Save ES because it will get incremented by 20h
|
||||
call ReadSectors ; Read the first sector of the root directory
|
||||
pop es ; Restore ES (ES:DI = 07E0:0000)
|
||||
|
||||
SearchRootDirSector:
|
||||
cmp [es:di],ch ; If the first byte of the directory entry is zero then we have
|
||||
jz ErrBoot ; reached the end of the directory and FREELDR.SYS is not here so reboot
|
||||
pusha ; Save all registers
|
||||
mov cl,0xb ; Put 11 in cl (length of filename in directory entry)
|
||||
mov si,filename ; Put offset of filename string in DS:SI
|
||||
repe cmpsb ; Compare this directory entry against 'FREELDR SYS'
|
||||
popa ; Restore all the registers
|
||||
jz FoundFreeLoader ; If we found it then jump
|
||||
dec si ; SI holds MaxRootEntries, subtract one
|
||||
jz ErrBoot ; If we are out of root dir entries then reboot
|
||||
add di,BYTE +0x20 ; Increment DI by the size of a directory entry
|
||||
cmp di,0200h ; Compare DI to 512 (DI has offset to next dir entry, make sure we haven't gone over one sector)
|
||||
jc SearchRootDirSector ; If DI is less than 512 loop again
|
||||
jmp short LoadRootDirSector ; Didn't find FREELDR.SYS in this directory sector, try again
|
||||
|
||||
FoundFreeLoader:
|
||||
; We found freeldr.sys on the disk
|
||||
; so we need to load the first 512
|
||||
; bytes of it to 0000:F800
|
||||
; ES:DI has dir entry (ES:DI == 07E0:XXXX)
|
||||
mov ax,WORD [es:di+1ah] ; Get start cluster
|
||||
push ax ; Save start cluster
|
||||
push WORD 0F80h ; FREELDR_BASE / 16 ; Put load segment on the stack and load it
|
||||
pop es ; Into ES so that we load the cluster at 0000:F800
|
||||
call ReadCluster ; Read the cluster
|
||||
pop ax ; Restore start cluster of FreeLoader
|
||||
|
||||
; Save the addresses of needed functions so
|
||||
; the helper code will know where to call them.
|
||||
mov WORD [BYTE bp-ReadSectorsOffset],ReadSectors ; Save the address of ReadSectors
|
||||
mov WORD [BYTE bp-ReadClusterOffset],ReadCluster ; Save the address of ReadCluster
|
||||
mov WORD [BYTE bp-PutCharsOffset],PutChars ; Save the address of PutChars
|
||||
|
||||
; Now AX has start cluster of FreeLoader and we
|
||||
; have loaded the helper code in the first 512 bytes
|
||||
; of FreeLoader to 0000:F800. Now transfer control
|
||||
; to the helper code. Skip the first three bytes
|
||||
; because they contain a jump instruction to skip
|
||||
; over the helper code in the FreeLoader image.
|
||||
;ljmp16 0, FREELDR_BASE + 3
|
||||
db 0EAh
|
||||
dw 0F803h
|
||||
dw 0
|
||||
|
||||
|
||||
|
||||
|
||||
; Displays an error message
|
||||
; And reboots
|
||||
ErrBoot:
|
||||
mov si,msgFreeLdr ; FreeLdr not found 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
|
||||
mov ah,0eh
|
||||
mov bx,07h
|
||||
int 10h
|
||||
jmp short PutChars
|
||||
Done:
|
||||
retn
|
||||
|
||||
; Displays a bad boot message
|
||||
; And reboots
|
||||
BadBoot:
|
||||
mov si,msgDiskError ; Bad boot disk message
|
||||
call PutChars ; Display it
|
||||
|
||||
jmp short Reboot
|
||||
|
||||
|
||||
; Reads cluster number in AX into [ES:0000]
|
||||
ReadCluster:
|
||||
; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
|
||||
dec ax ; Adjust start cluster by 2
|
||||
dec ax ; Because the data area starts on cluster 2
|
||||
xor ch,ch
|
||||
mov cl,BYTE [BYTE bp+SectsPerCluster]
|
||||
mul cx ; Times sectors per cluster
|
||||
add ax,[BYTE bp-DataAreaStartLow] ; Add start of data area
|
||||
adc dx,[BYTE bp-DataAreaStartHigh] ; Now we have DX:AX with the logical start sector of FREELDR.SYS
|
||||
xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
|
||||
;mov cl,BYTE [BYTE bp+SectsPerCluster]; Sectors per cluster still in CX
|
||||
;call ReadSectors
|
||||
;ret
|
||||
|
||||
|
||||
|
||||
; Reads logical sectors into [ES:BX]
|
||||
; DX:AX has logical sector number to read
|
||||
; CX has number of sectors to read
|
||||
ReadSectors:
|
||||
|
||||
; We can't just check if the start sector is
|
||||
; in the BIOS CHS range. We have to check if
|
||||
; the start sector + length is in that range.
|
||||
pusha
|
||||
dec cx
|
||||
add ax,cx
|
||||
adc dx,byte 0
|
||||
|
||||
cmp dx,WORD [BYTE bp-BiosCHSDriveSizeHigh] ; Check if they are reading a sector within CHS range
|
||||
ja ReadSectorsLBA ; No - go to the LBA routine
|
||||
jb ReadSectorsCHS ; Yes - go to the old CHS routine
|
||||
cmp ax,WORD [BYTE bp-BiosCHSDriveSizeLow] ; Check if they are reading a sector within CHS range
|
||||
jbe ReadSectorsCHS ; Yes - go to the old CHS routine
|
||||
|
||||
ReadSectorsLBA:
|
||||
popa
|
||||
ReadSectorsLBALoop:
|
||||
pusha ; Save logical sector number & sector count
|
||||
|
||||
o32 push byte 0
|
||||
push dx ; Put 64-bit logical
|
||||
push ax ; block address on stack
|
||||
push es ; Put transfer segment on stack
|
||||
push bx ; Put transfer offset on stack
|
||||
push byte 1 ; Set transfer count to 1 sector
|
||||
push byte 0x10 ; Set size of packet to 10h
|
||||
mov si,sp ; Setup disk address packet on stack
|
||||
|
||||
; We are so totally out of space here that I am forced to
|
||||
; comment out this very beautifully written piece of code
|
||||
; It would have been nice to have had this check...
|
||||
;CheckInt13hExtensions: ; Now make sure this computer supports extended reads
|
||||
; mov ah,0x41 ; AH = 41h
|
||||
; mov bx,0x55aa ; BX = 55AAh
|
||||
; mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh)
|
||||
; int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK
|
||||
; jc PrintDiskError ; CF set on error (extensions not supported)
|
||||
; cmp bx,0xaa55 ; BX = AA55h if installed
|
||||
; jne PrintDiskError
|
||||
; test cl,1 ; CX = API subset support bitmap
|
||||
; jz PrintDiskError ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
|
||||
|
||||
|
||||
; Good, we're here so the computer supports LBA disk access
|
||||
; So finish the extended read
|
||||
mov dl,[BYTE bp+BootDrive] ; Drive number
|
||||
mov ah,42h ; Int 13h, AH = 42h - Extended Read
|
||||
int 13h ; Call BIOS
|
||||
jc BadBoot ; If the read failed then abort
|
||||
|
||||
add sp,byte 0x10 ; Remove disk address packet from stack
|
||||
|
||||
popa ; Restore sector count & logical sector number
|
||||
|
||||
inc ax ; Increment Sector to Read
|
||||
adc dx,byte 0
|
||||
|
||||
push bx
|
||||
mov bx,es
|
||||
add bx,byte 20h ; Increment read buffer for next sector
|
||||
mov es,bx
|
||||
pop bx
|
||||
|
||||
loop ReadSectorsLBALoop ; Read next sector
|
||||
|
||||
ret
|
||||
|
||||
|
||||
; Reads logical sectors into [ES:BX]
|
||||
; DX:AX has logical sector number to read
|
||||
; CX has number of sectors to read
|
||||
; CarryFlag set on error
|
||||
ReadSectorsCHS:
|
||||
popa
|
||||
ReadSectorsCHSLoop:
|
||||
pusha
|
||||
xchg ax,cx
|
||||
xchg ax,dx
|
||||
xor dx,dx
|
||||
div WORD [BYTE bp+SectorsPerTrack]
|
||||
xchg ax,cx
|
||||
div WORD [BYTE bp+SectorsPerTrack] ; Divide logical by SectorsPerTrack
|
||||
inc dx ; Sectors numbering starts at 1 not 0
|
||||
xchg cx,dx
|
||||
div WORD [BYTE bp+NumberOfHeads] ; Number of heads
|
||||
mov dh,dl ; Head to DH, drive to DL
|
||||
mov dl,[BYTE bp+BootDrive] ; Drive number
|
||||
mov ch,al ; Cylinder in CX
|
||||
ror ah,2 ; Low 8 bits of cylinder in CH, high 2 bits
|
||||
; in CL shifted to bits 6 & 7
|
||||
or cl,ah ; Or with sector number
|
||||
mov ax,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 BadBoot
|
||||
|
||||
popa
|
||||
inc ax ;Increment Sector to Read
|
||||
jnz NoCarryCHS
|
||||
inc dx
|
||||
|
||||
|
||||
NoCarryCHS:
|
||||
push bx
|
||||
mov bx,es
|
||||
add bx,byte 20h
|
||||
mov es,bx
|
||||
pop bx
|
||||
; Increment read buffer for next sector
|
||||
loop ReadSectorsCHSLoop ; Read next sector
|
||||
|
||||
ret
|
||||
|
||||
|
||||
msgDiskError db 'Disk error',0dh,0ah,0
|
||||
msgFreeLdr db 'Ldr not found',0dh,0ah,0
|
||||
; Sorry, need the space...
|
||||
;msgAnyKey db 'Press any key to restart',0dh,0ah,0
|
||||
;msgAnyKey db 'Press a key',0dh,0ah,0
|
||||
filename db 'FREELDR SYS'
|
||||
|
||||
times 509-($-$$) db 0 ; Pad to 509 bytes
|
||||
|
||||
BootPartition:
|
||||
db 0
|
||||
|
||||
BootSignature:
|
||||
dw 0aa55h ; BootSector signature
|
|
@ -1,507 +0,0 @@
|
|||
; FAT32.ASM
|
||||
; FAT32 Boot Sector
|
||||
; Copyright (c) 1998, 2000, 2001, 2002 Brian Palmer
|
||||
|
||||
org 7c00h
|
||||
|
||||
segment .text
|
||||
|
||||
bits 16
|
||||
|
||||
start:
|
||||
jmp short main
|
||||
nop
|
||||
|
||||
OEMName db 'FrLdr1.0'
|
||||
BytesPerSector dw 512
|
||||
SectsPerCluster db 0
|
||||
ReservedSectors dw 32
|
||||
NumberOfFats db 2
|
||||
MaxRootEntries dw 0 ; Always zero for FAT32 volumes
|
||||
TotalSectors dw 0 ; Always zero for FAT32 volumes
|
||||
MediaDescriptor db 0f8h
|
||||
SectorsPerFat dw 0 ; Always zero for FAT32 volumes
|
||||
SectorsPerTrack dw 0
|
||||
NumberOfHeads dw 0
|
||||
HiddenSectors dd 0
|
||||
TotalSectorsBig dd 0
|
||||
; FAT32 Inserted Info
|
||||
SectorsPerFatBig dd 0
|
||||
ExtendedFlags dw 0
|
||||
FSVersion dw 0
|
||||
RootDirStartCluster dd 0
|
||||
FSInfoSector dw 0
|
||||
BackupBootSector dw 6
|
||||
Reserved1 times 12 db 0
|
||||
; End FAT32 Inserted Info
|
||||
BootDrive db 0
|
||||
Reserved db 0
|
||||
ExtendSig db 29h
|
||||
SerialNumber dd 00000000h
|
||||
VolumeLabel db 'NO NAME '
|
||||
FileSystem db 'FAT32 '
|
||||
|
||||
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,7c00h ; Setup a stack
|
||||
|
||||
|
||||
|
||||
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
|
||||
jne CheckSectorsPerFat
|
||||
|
||||
mov [BYTE bp+BootDrive],dl ; Save the boot drive
|
||||
|
||||
|
||||
|
||||
CheckSectorsPerFat:
|
||||
cmp WORD [BYTE bp+SectorsPerFat],byte 0x00 ; Check the old 16-bit value of SectorsPerFat
|
||||
jnz CheckFailed ; If it is non-zero then exit with an error
|
||||
CheckTotalSectors: ; Check the old 16-bit value of TotalSectors & MaxRootEntries
|
||||
cmp DWORD [BYTE bp+MaxRootEntries],byte 0x00; by comparing the DWORD at offset MaxRootEntries to zero
|
||||
jnz CheckFailed ; If it is non-zero then exit with an error
|
||||
CheckFileSystemVersion:
|
||||
cmp WORD [BYTE bp+FSVersion],byte 0x00 ; Check the file system version word
|
||||
jna GetDriveParameters ; It is zero, so continue
|
||||
CheckFailed:
|
||||
jmp PrintFileSystemError ; If it is not zero then exit with an error
|
||||
|
||||
|
||||
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
|
||||
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 [BiosCHSDriveSize],eax
|
||||
|
||||
|
||||
LoadExtraBootCode:
|
||||
; First we have to load our extra boot code at
|
||||
; sector 14 into memory at [0000:7e00h]
|
||||
mov eax,0eh
|
||||
add eax,DWORD [BYTE bp+HiddenSectors] ; Add the number of hidden sectors
|
||||
mov cx,1
|
||||
xor bx,bx
|
||||
mov es,bx ; Read sector to [0000:7e00h]
|
||||
mov bx,7e00h
|
||||
call ReadSectors
|
||||
jmp StartSearch
|
||||
|
||||
|
||||
|
||||
; Reads logical sectors into [ES:BX]
|
||||
; EAX has logical sector number to read
|
||||
; CX has number of sectors to read
|
||||
ReadSectors:
|
||||
push es
|
||||
cmp eax,DWORD [BiosCHSDriveSize] ; 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,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 [LBASectorsRead],cx
|
||||
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 [LBASectorsRead]
|
||||
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,[LBASectorsRead]
|
||||
jnz ReadSectorsLBA ; Read next sector
|
||||
|
||||
pop es
|
||||
ret
|
||||
|
||||
LBASectorsRead:
|
||||
dd 0
|
||||
|
||||
|
||||
; 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
|
||||
movzx ecx,WORD [BYTE bp+SectorsPerTrack]
|
||||
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+NumberOfHeads] ; 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
|
||||
|
||||
jmp Reboot
|
||||
|
||||
; Displays a file system error message
|
||||
; And reboots
|
||||
PrintFileSystemError:
|
||||
mov si,msgFileSystemError ; FreeLdr not found 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
|
||||
mov ah,0eh
|
||||
mov bx,07h
|
||||
int 10h
|
||||
jmp short PutChars
|
||||
Done:
|
||||
retn
|
||||
|
||||
|
||||
|
||||
BiosCHSDriveSize dd 0
|
||||
|
||||
msgDiskError db 'Disk error',0dh,0ah,0
|
||||
msgFileSystemError db 'File system error',0dh,0ah,0
|
||||
msgAnyKey db 'Press any key to restart',0dh,0ah,0
|
||||
|
||||
times 509-($-$$) db 0 ; Pad to 509 bytes
|
||||
|
||||
BootPartition:
|
||||
db 0
|
||||
|
||||
BootSignature:
|
||||
dw 0aa55h ; BootSector signature
|
||||
|
||||
|
||||
; End of bootsector
|
||||
;
|
||||
; Now starts the extra boot code that we will store
|
||||
; at sector 14 on a FAT32 volume
|
||||
;
|
||||
; To remain multi-boot compatible with other operating
|
||||
; systems we must not overwrite anything other than
|
||||
; the bootsector which means we will have to use
|
||||
; a different sector like 14 to store our extra boot code
|
||||
|
||||
|
||||
|
||||
StartSearch:
|
||||
; Now we must get the first cluster of the root directory
|
||||
mov eax,DWORD [BYTE bp+RootDirStartCluster]
|
||||
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
|
||||
jb ContinueSearch ; If not continue, if so then we didn't find freeldr.sys
|
||||
jmp PrintFileNotFound
|
||||
ContinueSearch:
|
||||
mov bx,2000h
|
||||
mov es,bx ; Read cluster to [2000:0000h]
|
||||
call ReadCluster ; Read the cluster
|
||||
|
||||
|
||||
; Now we have to find our way through the root directory to
|
||||
; The FREELDR.SYS file
|
||||
xor bx,bx
|
||||
mov bl,[BYTE bp+SectsPerCluster]
|
||||
shl bx,4 ; BX = BX * 512 / 32
|
||||
mov ax,2000h ; We loaded at 2000:0000
|
||||
mov es,ax
|
||||
xor di,di
|
||||
mov si,filename
|
||||
mov cx,11
|
||||
rep cmpsb ; Compare filenames
|
||||
jz FoundFile ; If same we found it
|
||||
dec bx
|
||||
jnz FindFile
|
||||
jmp PrintFileNotFound
|
||||
|
||||
FindFile:
|
||||
mov ax,es ; We didn't find it in the previous dir entry
|
||||
add ax,2 ; So lets move to the next one
|
||||
mov es,ax ; And search again
|
||||
xor di,di
|
||||
mov si,filename
|
||||
mov cx,11
|
||||
rep cmpsb ; Compare filenames
|
||||
jz FoundFile ; If same we found it
|
||||
dec bx ; Keep searching till we run out of dir entries
|
||||
jnz FindFile ; Last entry?
|
||||
|
||||
; Get the next root dir cluster and try again until we run out of clusters
|
||||
mov eax,DWORD [BYTE bp+RootDirStartCluster]
|
||||
call GetFatEntry
|
||||
mov [BYTE bp+RootDirStartCluster],eax
|
||||
jmp StartSearch
|
||||
|
||||
FoundFile:
|
||||
; Display "Loading FreeLoader..." message
|
||||
mov si,msgLoading ; Loading message
|
||||
call PutChars ; Display it
|
||||
|
||||
xor di,di ; ES:DI has dir entry
|
||||
xor dx,dx
|
||||
mov ax,WORD [es:di+14h] ; Get start cluster high word
|
||||
shl eax,16
|
||||
mov ax,WORD [es:di+1ah] ; Get start cluster low word
|
||||
|
||||
CheckStartCluster:
|
||||
cmp eax,2 ; Check and see if the start cluster starts at cluster 2 or above
|
||||
jnb CheckEndCluster ; If so then continue
|
||||
jmp PrintFileSystemError ; If not exit with error
|
||||
CheckEndCluster:
|
||||
cmp eax,0ffffff8h ; Check and see if the start cluster is and end of cluster chain indicator
|
||||
jb InitializeLoadSegment ; If not then continue
|
||||
jmp PrintFileSystemError ; If so exit with error
|
||||
|
||||
InitializeLoadSegment:
|
||||
mov bx,0F80h ; FREELDR_BASE / 16
|
||||
mov es,bx
|
||||
|
||||
LoadFile:
|
||||
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
|
||||
jae LoadFileDone ; If so continue, if not then read the next one
|
||||
push eax
|
||||
xor bx,bx ; Load ROSLDR starting at 0000:F800h
|
||||
push es
|
||||
call ReadCluster
|
||||
pop es
|
||||
|
||||
xor bx,bx
|
||||
mov bl,[BYTE bp+SectsPerCluster]
|
||||
shl bx,5 ; BX = BX * 512 / 16
|
||||
mov ax,es ; Increment the load address by
|
||||
add ax,bx ; The size of a cluster
|
||||
mov es,ax
|
||||
|
||||
pop eax
|
||||
push es
|
||||
call GetFatEntry ; Get the next entry
|
||||
pop es
|
||||
|
||||
jmp LoadFile ; Load the next cluster (if any)
|
||||
|
||||
LoadFileDone:
|
||||
mov dl,[BYTE bp+BootDrive] ; Load boot drive into DL
|
||||
mov dh,[BootPartition] ; Load boot partition into DH
|
||||
|
||||
; Transfer execution to the bootloader
|
||||
;ljmp16 0, FREELDR_BASE
|
||||
db 0EAh
|
||||
dw 0F800h
|
||||
dw 0
|
||||
|
||||
; Returns the FAT entry for a given cluster number
|
||||
; On entry EAX has cluster number
|
||||
; On return EAX has FAT entry for that cluster
|
||||
GetFatEntry:
|
||||
|
||||
shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes)
|
||||
mov ecx,eax ; Save this for later in ECX
|
||||
xor edx,edx
|
||||
movzx ebx,WORD [BYTE bp+BytesPerSector]
|
||||
push ebx
|
||||
div ebx ; FAT Sector Number = EAX / BytesPerSector
|
||||
movzx ebx,WORD [BYTE bp+ReservedSectors]
|
||||
add eax,ebx ; FAT Sector Number += ReservedSectors
|
||||
mov ebx,DWORD [BYTE bp+HiddenSectors]
|
||||
add eax,ebx ; FAT Sector Number += HiddenSectors
|
||||
pop ebx
|
||||
dec ebx
|
||||
and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector
|
||||
; EAX holds logical FAT sector number
|
||||
; ECX holds FAT entry offset
|
||||
|
||||
; Now we have to check the extended flags
|
||||
; to see which FAT is the active one
|
||||
; and use it, or if they are mirrored then
|
||||
; no worries
|
||||
movzx ebx,WORD [BYTE bp+ExtendedFlags] ; Get extended flags and put into ebx
|
||||
and bx,0x0f ; Mask off upper 8 bits, now we have active fat in bl
|
||||
jz LoadFatSector ; If fat is mirrored then skip fat calcs
|
||||
cmp bl,[BYTE bp+NumberOfFats] ; Compare bl to number of fats
|
||||
jb GetActiveFatOffset
|
||||
jmp PrintFileSystemError ; If bl is bigger than numfats exit with error
|
||||
GetActiveFatOffset:
|
||||
push eax ; Save logical FAT sector number
|
||||
mov eax,[BYTE bp+SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax
|
||||
mul ebx ; Multiplied by the active FAT index we have in ebx
|
||||
pop edx ; Get logical FAT sector number
|
||||
add eax,edx ; Add the current FAT sector offset
|
||||
|
||||
LoadFatSector:
|
||||
push ecx
|
||||
|
||||
mov bx, 9000h ; We will load it to [9000:0000h]
|
||||
mov es, bx
|
||||
|
||||
; EAX holds logical FAT sector number
|
||||
; Check if we have already loaded it
|
||||
cmp eax,DWORD [FatSectorInCache]
|
||||
je LoadFatSectorAlreadyLoaded
|
||||
|
||||
mov DWORD [FatSectorInCache],eax
|
||||
xor bx,bx
|
||||
mov cx,1
|
||||
call ReadSectors
|
||||
|
||||
LoadFatSectorAlreadyLoaded:
|
||||
pop ecx
|
||||
mov eax,DWORD [es:ecx] ; Get FAT entry
|
||||
and eax,0fffffffh ; Mask off reserved bits
|
||||
|
||||
ret
|
||||
|
||||
FatSectorInCache: ; This variable tells us which sector we currently have in memory
|
||||
dd 0ffffffffh ; There is no need to re-read the same sector if we don't have to
|
||||
|
||||
|
||||
; Reads cluster number in EAX into [ES:0000]
|
||||
ReadCluster:
|
||||
; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
|
||||
|
||||
dec eax
|
||||
dec eax
|
||||
xor edx,edx
|
||||
movzx ebx,BYTE [BYTE bp+SectsPerCluster]
|
||||
mul ebx
|
||||
push eax
|
||||
xor edx,edx
|
||||
movzx eax,BYTE [BYTE bp+NumberOfFats]
|
||||
mul DWORD [BYTE bp+SectorsPerFatBig]
|
||||
movzx ebx,WORD [BYTE bp+ReservedSectors]
|
||||
add eax,ebx
|
||||
add eax,DWORD [BYTE bp+HiddenSectors]
|
||||
pop ebx
|
||||
add eax,ebx ; EAX now contains the logical sector number of the cluster
|
||||
xor bx,bx ; We will load it to [ES:0000], ES loaded before function call
|
||||
movzx cx,BYTE [BYTE bp+SectsPerCluster]
|
||||
call ReadSectors
|
||||
ret
|
||||
|
||||
|
||||
; Displays a file not found error message
|
||||
; And reboots
|
||||
PrintFileNotFound:
|
||||
mov si,msgFreeLdr ; FreeLdr not found message
|
||||
call PutChars ; Display it
|
||||
mov si,msgAnyKey ; Press any key message
|
||||
call PutChars ; Display it
|
||||
|
||||
jmp Reboot
|
||||
|
||||
msgFreeLdr db 'freeldr.sys not found',0dh,0ah,0
|
||||
filename db 'FREELDR SYS'
|
||||
msgLoading db 'Loading FreeLoader...',0dh,0ah,0
|
||||
|
||||
|
||||
times 1022-($-$$) db 0 ; Pad to 1022 bytes
|
||||
|
||||
dw 0aa55h ; BootSector signature
|
|
@ -1,31 +1,14 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Boot Sector for ISO file system (based on ISOLINUX)
|
||||
* LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
|
||||
* PROGRAMMERS: H. Peter Anvin
|
||||
* Michael K. Ter Louw
|
||||
* Eric Kohl
|
||||
* Timo Kreuzer <timo.kreuzer@reactos.org>
|
||||
* Colin Finck <colin@reactos.org>
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* isolinux.asm
|
||||
*
|
||||
* A program to boot Linux kernels off a CD-ROM using the El Torito
|
||||
* boot standard in "no emulation" mode, making the entire filesystem
|
||||
* available. It is based on the SYSLINUX boot loader for MS-DOS
|
||||
* floppies.
|
||||
*
|
||||
* Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation *author: H. Peter Anvin
|
||||
*
|
||||
* This program is free software *you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, Inc., 53 Temple Place Ste 330,
|
||||
* Boston MA 02111-1307, USA *either version 2 of the License, or
|
||||
* (at your option) any later version *incorporated herein by reference.
|
||||
*
|
||||
*****************************************************************************/
|
||||
* PROJECT: ReactOS Boot Sector for ISO file system (based on ISOLINUX)
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Booting ReactOS off a CD-ROM using the El Torito boot standard in "no emulation mode"
|
||||
* COPYRIGHT: Copyright 1994-2009 H. Peter Anvin
|
||||
* Copyright 2002 Michael K. Ter Louw
|
||||
* Copyright 2002 Eric Kohl
|
||||
* Copyright 2009 Intel Corporation *author: H. Peter Anvin
|
||||
* Copyright 2011 Timo Kreuzer (timo.kreuzer@reactos.org)
|
||||
* Copyright 2017 Colin Finck (colin@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
#include <asm.inc>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,984 +0,0 @@
|
|||
; ****************************************************************************
|
||||
;
|
||||
; isolinux.asm
|
||||
;
|
||||
; A program to boot Linux kernels off a CD-ROM using the El Torito
|
||||
; boot standard in "no emulation" mode, making the entire filesystem
|
||||
; available. It is based on the SYSLINUX boot loader for MS-DOS
|
||||
; floppies.
|
||||
;
|
||||
; Copyright (C) 1994-2001 H. Peter Anvin
|
||||
;
|
||||
; This program is free software; you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
|
||||
; USA; either version 2 of the License, or (at your option) any later
|
||||
; version; incorporated herein by reference.
|
||||
;
|
||||
; ****************************************************************************
|
||||
;
|
||||
; THIS FILE IS A MODIFIED VERSION OF ISOLINUX.ASM
|
||||
; MODIFICATION DONE BY MICHAEL K TER LOUW
|
||||
; LAST UPDATED 3-9-2002
|
||||
; SEE "COPYING" FOR INFORMATION ABOUT THE LICENSE THAT APPLIES TO THIS RELEASE
|
||||
;
|
||||
; ****************************************************************************
|
||||
;
|
||||
; This file is a modified version of ISOLINUX.ASM.
|
||||
; Modification done by Eric Kohl
|
||||
; Last update 04-25-2002
|
||||
;
|
||||
; ****************************************************************************
|
||||
;
|
||||
; This file is a modified version of ISOLINUX.ASM.
|
||||
; (for ReactOS regression testing)
|
||||
; Modification done by Christoph von Wittich
|
||||
; Last update 08-27-2006
|
||||
;
|
||||
; ****************************************************************************
|
||||
|
||||
|
||||
; Note: The Makefile builds one version with DEBUG_MESSAGES automatically.
|
||||
;%define DEBUG_MESSAGES ; Uncomment to get debugging messages
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; BEGIN THE BIOS/CODE/DATA SEGMENT
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
absolute 0400h
|
||||
serial_base resw 4 ; Base addresses for 4 serial ports
|
||||
absolute 0413h
|
||||
BIOS_fbm resw 1 ; Free Base Memory (kilobytes)
|
||||
absolute 046Ch
|
||||
BIOS_timer resw 1 ; Timer ticks
|
||||
absolute 0472h
|
||||
BIOS_magic resw 1 ; BIOS reset magic
|
||||
absolute 0484h
|
||||
BIOS_vidrows resb 1 ; Number of screen rows
|
||||
|
||||
;
|
||||
; Memory below this point is reserved for the BIOS and the MBR
|
||||
;
|
||||
absolute 1000h
|
||||
trackbuf resb 8192 ; Track buffer goes here
|
||||
trackbufsize equ $-trackbuf
|
||||
; trackbuf ends at 3000h
|
||||
|
||||
struc open_file_t
|
||||
file_sector resd 1 ; Sector pointer (0 = structure free)
|
||||
file_left resd 1 ; Number of sectors left
|
||||
endstruc
|
||||
|
||||
struc dir_t
|
||||
dir_lba resd 1 ; Directory start (LBA)
|
||||
dir_len resd 1 ; Length in bytes
|
||||
dir_clust resd 1 ; Length in clusters
|
||||
endstruc
|
||||
|
||||
|
||||
MAX_OPEN_LG2 equ 2 ; log2(Max number of open files)
|
||||
MAX_OPEN equ (1 << MAX_OPEN_LG2)
|
||||
SECTORSIZE_LG2 equ 11 ; 2048 bytes/sector (El Torito requirement)
|
||||
SECTORSIZE equ (1 << SECTORSIZE_LG2)
|
||||
CR equ 13 ; Carriage Return
|
||||
LF equ 10 ; Line Feed
|
||||
retry_count equ 6 ; How patient are we with the BIOS?
|
||||
|
||||
|
||||
|
||||
absolute 5000h ; Here we keep our BSS stuff
|
||||
|
||||
DriveNo resb 1 ; CD-ROM BIOS drive number
|
||||
DiskError resb 1 ; Error code for disk I/O
|
||||
RetryCount resb 1 ; Used for disk access retries
|
||||
TimeoutCount resb 1 ; Timeout counter
|
||||
ISOFlags resb 1 ; Flags for ISO directory search
|
||||
RootDir resb dir_t_size ; Root directory
|
||||
CurDir resb dir_t_size ; Current directory
|
||||
ISOFileName resb 64 ; ISO filename canonicalization buffer
|
||||
ISOFileNameEnd equ $
|
||||
|
||||
|
||||
alignb open_file_t_size
|
||||
Files resb MAX_OPEN*open_file_t_size
|
||||
|
||||
|
||||
|
||||
section .text
|
||||
org 7000h
|
||||
|
||||
start:
|
||||
cli ; Disable interrupts
|
||||
xor ax, ax ; ax = segment zero
|
||||
mov ss, ax ; Initialize stack segment
|
||||
mov sp, start ; Set up stack
|
||||
mov ds, ax ; Initialize other segment registers
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
sti ; Enable interrupts
|
||||
cld ; Increment pointers
|
||||
|
||||
mov cx, 2048 >> 2 ; Copy the bootsector
|
||||
mov si, 0x7C00 ; from 0000:7C00
|
||||
mov di, 0x7000 ; to 0000:7000
|
||||
rep movsd ; copy the program
|
||||
jmp 0:relocate ; jump into relocated code
|
||||
|
||||
relocate:
|
||||
; Display the banner and copyright
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, isolinux_banner ; si points to hello message
|
||||
call writestr ; display the message
|
||||
mov si,copyright_str
|
||||
call writestr
|
||||
%endif
|
||||
|
||||
; check if there is a mbr on the hdd if so boot from it
|
||||
|
||||
pusha
|
||||
mov ax, 0201h
|
||||
mov dx, 0080h
|
||||
mov cx, 0001h
|
||||
mov bx, trackbuf
|
||||
int 13h
|
||||
popa
|
||||
jc .boot_cdrom ; could not read hdd
|
||||
|
||||
push ax
|
||||
mov ax, word [trackbuf+510]
|
||||
cmp ax, 0
|
||||
je .boot_cdrom ; no boot sector found (hopefully there are no weird bootsectors which begin with 0)
|
||||
pop ax
|
||||
|
||||
.boot_harddisk:
|
||||
call crlf
|
||||
|
||||
; Boot first harddisk (drive 0x80)
|
||||
mov ax, 0201h
|
||||
mov dx, 0080h
|
||||
mov cx, 0001h
|
||||
mov bx, 7C00h
|
||||
int 13h
|
||||
jnc .go_hd
|
||||
jmp kaboom
|
||||
.go_hd:
|
||||
mov ax, cs
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov dx, 0080h
|
||||
|
||||
jmp 0:0x7C00
|
||||
|
||||
.boot_cdrom:
|
||||
; Save and display the boot drive number
|
||||
mov [DriveNo], dl
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, startup_msg
|
||||
call writemsg
|
||||
mov al, dl
|
||||
call writehex2
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
; Now figure out what we're actually doing
|
||||
; Note: use passed-in DL value rather than 7Fh because
|
||||
; at least some BIOSes will get the wrong value otherwise
|
||||
mov ax, 4B01h ; Get disk emulation status
|
||||
mov dl, [DriveNo]
|
||||
mov si, spec_packet
|
||||
int 13h
|
||||
jc near spec_query_failed ; Shouldn't happen (BIOS bug)
|
||||
mov dl, [DriveNo]
|
||||
cmp [sp_drive], dl ; Should contain the drive number
|
||||
jne near spec_query_failed
|
||||
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, spec_ok_msg
|
||||
call writemsg
|
||||
mov al, byte [sp_drive]
|
||||
call writehex2
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
found_drive:
|
||||
; Get drive information
|
||||
mov ah, 48h
|
||||
mov dl, [DriveNo]
|
||||
mov si, drive_params
|
||||
int 13h
|
||||
jnc params_ok
|
||||
|
||||
; mov si, nosecsize_msg No use in reporting this
|
||||
; call writemsg
|
||||
|
||||
params_ok:
|
||||
; Check for the sector size (should be 2048, but
|
||||
; some BIOSes apparently think we're 512-byte media)
|
||||
;
|
||||
; FIX: We need to check what the proper behaviour
|
||||
; is for getlinsec when the BIOS thinks the sector
|
||||
; size is 512!!! For that, we need such a BIOS, though...
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, secsize_msg
|
||||
call writemsg
|
||||
mov ax, [dp_secsize]
|
||||
call writehex4
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
|
||||
;
|
||||
; Clear Files structures
|
||||
;
|
||||
mov di, Files
|
||||
mov cx, (MAX_OPEN*open_file_t_size)/4
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
|
||||
;
|
||||
; Now, we need to sniff out the actual filesystem data structures.
|
||||
; mkisofs gave us a pointer to the primary volume descriptor
|
||||
; (which will be at 16 only for a single-session disk!); from the PVD
|
||||
; we should be able to find the rest of what we need to know.
|
||||
;
|
||||
get_fs_structures:
|
||||
mov eax, 16 ; Primary Volume Descriptor (sector 16)
|
||||
mov bx, trackbuf
|
||||
call getonesec
|
||||
|
||||
mov eax, [trackbuf+156+2]
|
||||
mov [RootDir+dir_lba],eax
|
||||
mov [CurDir+dir_lba],eax
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, rootloc_msg
|
||||
call writemsg
|
||||
call writehex8
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
mov eax,[trackbuf+156+10]
|
||||
mov [RootDir+dir_len],eax
|
||||
mov [CurDir+dir_len],eax
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, rootlen_msg
|
||||
call writemsg
|
||||
call writehex8
|
||||
call crlf
|
||||
%endif
|
||||
add eax,SECTORSIZE-1
|
||||
shr eax,SECTORSIZE_LG2
|
||||
mov [RootDir+dir_clust],eax
|
||||
mov [CurDir+dir_clust],eax
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, rootsect_msg
|
||||
call writemsg
|
||||
call writehex8
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
; Look for the "REACTOS" directory, and if found,
|
||||
; make it the current directory instead of the root
|
||||
; directory.
|
||||
mov di,isolinux_dir
|
||||
mov al,02h ; Search for a directory
|
||||
call searchdir_iso
|
||||
jnz .dir_found
|
||||
mov si,no_dir_msg
|
||||
call writemsg
|
||||
jmp kaboom
|
||||
|
||||
.dir_found:
|
||||
mov [CurDir+dir_len],eax
|
||||
mov eax,[si+file_left]
|
||||
mov [CurDir+dir_clust],eax
|
||||
xor eax,eax ; Free this file pointer entry
|
||||
xchg eax,[si+file_sector]
|
||||
mov [CurDir+dir_lba],eax
|
||||
|
||||
|
||||
mov di, isolinux_bin ; di points to Isolinux filename
|
||||
call searchdir ; look for the file
|
||||
jnz .isolinux_opened ; got the file
|
||||
mov si, no_isolinux_msg ; si points to error message
|
||||
call writemsg ; display the message
|
||||
jmp kaboom ; fail boot
|
||||
|
||||
.isolinux_opened:
|
||||
mov di, si ; save file pointer
|
||||
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, filelen_msg
|
||||
call writemsg
|
||||
call writehex8
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
mov ecx, eax ; calculate sector count
|
||||
shr ecx, 11
|
||||
test eax, 0x7FF
|
||||
jz .full_sector
|
||||
inc ecx
|
||||
.full_sector:
|
||||
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov eax, ecx
|
||||
mov si, filesect_msg
|
||||
call writemsg
|
||||
call writehex8
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
; use high segment, as some bios can fail, when offset is too big
|
||||
mov bx, 0x0F80 ; FREELDR_BASE / 16 ; es = load segment
|
||||
mov es, bx
|
||||
xor ebx, ebx ; bx = load offset
|
||||
mov si, di ; restore file pointer
|
||||
mov cx, 0xFFFF ; load the whole file
|
||||
call getfssec ; get the whole file
|
||||
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, startldr_msg
|
||||
call writemsg
|
||||
call crlf
|
||||
%endif
|
||||
|
||||
mov dl, [DriveNo] ; dl = boot drive
|
||||
mov dh, 0 ; dh = boot partition
|
||||
|
||||
; Transfer execution to the bootloader
|
||||
;ljmp16 0, FREELDR_BASE
|
||||
db 0xEA
|
||||
dw 0xF800
|
||||
dw 0
|
||||
|
||||
;
|
||||
; searchdir:
|
||||
;
|
||||
; Open a file
|
||||
;
|
||||
; On entry:
|
||||
; DS:DI = filename
|
||||
; If successful:
|
||||
; ZF clear
|
||||
; SI = file pointer
|
||||
; DX:AX or EAX = file length in bytes
|
||||
; If unsuccessful
|
||||
; ZF set
|
||||
;
|
||||
|
||||
;
|
||||
; searchdir_iso is a special entry point for ISOLINUX only. In addition
|
||||
; to the above, searchdir_iso passes a file flag mask in AL. This is useful
|
||||
; for searching for directories.
|
||||
;
|
||||
alloc_failure:
|
||||
xor ax,ax ; ZF <- 1
|
||||
ret
|
||||
|
||||
searchdir:
|
||||
xor al,al
|
||||
searchdir_iso:
|
||||
mov [ISOFlags],al
|
||||
call allocate_file ; Temporary file structure for directory
|
||||
jnz alloc_failure
|
||||
push es
|
||||
push ds
|
||||
pop es ; ES = DS
|
||||
mov si,CurDir
|
||||
cmp byte [di],'\' ; If filename begins with slash
|
||||
jne .not_rooted
|
||||
inc di ; Skip leading slash
|
||||
mov si,RootDir ; Reference root directory instead
|
||||
.not_rooted:
|
||||
mov eax,[si+dir_clust]
|
||||
mov [bx+file_left],eax
|
||||
mov eax,[si+dir_lba]
|
||||
mov [bx+file_sector],eax
|
||||
mov edx,[si+dir_len]
|
||||
|
||||
.look_for_slash:
|
||||
mov ax,di
|
||||
.scan:
|
||||
mov cl,[di]
|
||||
inc di
|
||||
and cl,cl
|
||||
jz .isfile
|
||||
cmp cl,'\'
|
||||
jne .scan
|
||||
mov [di-1],byte 0 ; Terminate at directory name
|
||||
mov cl,02h ; Search for directory
|
||||
xchg cl,[ISOFlags]
|
||||
push di
|
||||
push cx
|
||||
push word .resume ; Where to "return" to
|
||||
push es
|
||||
.isfile:
|
||||
xchg ax,di
|
||||
|
||||
.getsome:
|
||||
; Get a chunk of the directory
|
||||
mov si,trackbuf
|
||||
pushad
|
||||
xchg bx,si
|
||||
mov cx,1 ; load one sector
|
||||
call getfssec
|
||||
popad
|
||||
|
||||
.compare:
|
||||
movzx eax, byte [si] ; Length of directory entry
|
||||
cmp al, 33
|
||||
jb .next_sector
|
||||
mov cl, [si+25]
|
||||
xor cl, [ISOFlags]
|
||||
test cl, byte 8Eh ; Unwanted file attributes!
|
||||
jnz .not_file
|
||||
pusha
|
||||
movzx cx, byte [si+32] ; File identifier length
|
||||
add si, byte 33 ; File identifier offset
|
||||
call iso_compare_names
|
||||
popa
|
||||
je .success
|
||||
.not_file:
|
||||
sub edx, eax ; Decrease bytes left
|
||||
jbe .failure
|
||||
add si, ax ; Advance pointer
|
||||
|
||||
.check_overrun:
|
||||
; Did we finish the buffer?
|
||||
cmp si, trackbuf+trackbufsize
|
||||
jb .compare ; No, keep going
|
||||
|
||||
jmp short .getsome ; Get some more directory
|
||||
|
||||
.next_sector:
|
||||
; Advance to the beginning of next sector
|
||||
lea ax, [si+SECTORSIZE-1]
|
||||
and ax, ~(SECTORSIZE-1)
|
||||
sub ax, si
|
||||
jmp short .not_file ; We still need to do length checks
|
||||
|
||||
.failure:
|
||||
%ifdef DEBUG_MESSAGES
|
||||
mov si, findfail_msg
|
||||
call writemsg
|
||||
call crlf
|
||||
%endif
|
||||
xor eax, eax ; ZF = 1
|
||||
mov [bx+file_sector], eax
|
||||
pop es
|
||||
ret
|
||||
|
||||
.success:
|
||||
mov eax, [si+2] ; Location of extent
|
||||
mov [bx+file_sector], eax
|
||||
mov eax, [si+10] ; Data length
|
||||
push eax
|
||||
add eax, SECTORSIZE-1
|
||||
shr eax, SECTORSIZE_LG2
|
||||
mov [bx+file_left], eax
|
||||
pop eax
|
||||
mov edx, eax
|
||||
shr edx, 16
|
||||
and bx, bx ; ZF = 0
|
||||
mov si, bx
|
||||
pop es
|
||||
ret
|
||||
|
||||
.resume:
|
||||
; We get here if we were only doing part of a lookup
|
||||
; This relies on the fact that .success returns bx == si
|
||||
xchg edx, eax ; Directory length in edx
|
||||
pop cx ; Old ISOFlags
|
||||
pop di ; Next filename pointer
|
||||
|
||||
mov byte [di-1], '\' ; restore the backslash in the filename
|
||||
|
||||
mov [ISOFlags], cl ; Restore the flags
|
||||
jz .failure ; Did we fail? If so fail for real!
|
||||
jmp .look_for_slash ; Otherwise, next level
|
||||
|
||||
;
|
||||
; allocate_file: Allocate a file structure
|
||||
;
|
||||
; If successful:
|
||||
; ZF set
|
||||
; BX = file pointer
|
||||
; In unsuccessful:
|
||||
; ZF clear
|
||||
;
|
||||
allocate_file:
|
||||
push cx
|
||||
mov bx, Files
|
||||
mov cx, MAX_OPEN
|
||||
.check:
|
||||
cmp dword [bx], byte 0
|
||||
je .found
|
||||
add bx, open_file_t_size ; ZF = 0
|
||||
loop .check
|
||||
; ZF = 0 if we fell out of the loop
|
||||
.found:
|
||||
pop cx
|
||||
ret
|
||||
|
||||
;
|
||||
; iso_compare_names:
|
||||
; Compare the names DS:SI and DS:DI and report if they are
|
||||
; equal from an ISO 9660 perspective. SI is the name from
|
||||
; the filesystem; CX indicates its length, and ';' terminates.
|
||||
; DI is expected to end with a null.
|
||||
;
|
||||
; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
|
||||
;
|
||||
iso_compare_names:
|
||||
; First, terminate and canonicalize input filename
|
||||
push di
|
||||
mov di, ISOFileName
|
||||
.canon_loop:
|
||||
jcxz .canon_end
|
||||
lodsb
|
||||
dec cx
|
||||
cmp al, ';'
|
||||
je .canon_end
|
||||
and al, al
|
||||
je .canon_end
|
||||
stosb
|
||||
cmp di, ISOFileNameEnd-1 ; Guard against buffer overrun
|
||||
jb .canon_loop
|
||||
.canon_end:
|
||||
cmp di, ISOFileName
|
||||
jbe .canon_done
|
||||
cmp byte [di-1], '.' ; Remove terminal dots
|
||||
jne .canon_done
|
||||
dec di
|
||||
jmp short .canon_end
|
||||
.canon_done:
|
||||
mov [di], byte 0 ; Null-terminate string
|
||||
pop di
|
||||
mov si, ISOFileName
|
||||
.compare:
|
||||
lodsb
|
||||
mov ah, [di]
|
||||
inc di
|
||||
and ax, ax
|
||||
jz .success ; End of string for both
|
||||
and al, al ; Is either one end of string?
|
||||
jz .failure ; If so, failure
|
||||
and ah, ah
|
||||
jz .failure
|
||||
or ax, 2020h ; Convert to lower case
|
||||
cmp al, ah
|
||||
je .compare
|
||||
.failure:
|
||||
and ax, ax ; ZF = 0 (at least one will be nonzero)
|
||||
.success:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;
|
||||
; getfssec: Get multiple clusters from a file, given the file pointer.
|
||||
;
|
||||
; On entry:
|
||||
; ES:BX -> Buffer
|
||||
; SI -> File pointer
|
||||
; CX -> Cluster count; 0FFFFh = until end of file
|
||||
; On exit:
|
||||
; SI -> File pointer (or 0 on EOF)
|
||||
; CF = 1 -> Hit EOF
|
||||
;
|
||||
getfssec:
|
||||
cmp cx, [si+file_left]
|
||||
jna .ok_size
|
||||
mov cx, [si+file_left]
|
||||
|
||||
.ok_size:
|
||||
mov bp, cx
|
||||
push cx
|
||||
push si
|
||||
mov eax, [si+file_sector]
|
||||
call getlinsec
|
||||
xor ecx, ecx
|
||||
pop si
|
||||
pop cx
|
||||
|
||||
add [si+file_sector], ecx
|
||||
sub [si+file_left], ecx
|
||||
ja .not_eof ; CF = 0
|
||||
|
||||
xor ecx, ecx
|
||||
mov [si+file_sector], ecx ; Mark as unused
|
||||
xor si,si
|
||||
stc
|
||||
|
||||
.not_eof:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; INT 13h, AX=4B01h, DL=<passed in value> failed.
|
||||
; Try to scan the entire 80h-FFh from the end.
|
||||
spec_query_failed:
|
||||
mov si,spec_err_msg
|
||||
call writemsg
|
||||
|
||||
mov dl, 0FFh
|
||||
.test_loop:
|
||||
pusha
|
||||
mov ax, 4B01h
|
||||
mov si, spec_packet
|
||||
mov byte [si], 13 ; Size of buffer
|
||||
int 13h
|
||||
popa
|
||||
jc .still_broken
|
||||
|
||||
mov si, maybe_msg
|
||||
call writemsg
|
||||
mov al, dl
|
||||
call writehex2
|
||||
call crlf
|
||||
|
||||
cmp byte [sp_drive], dl
|
||||
jne .maybe_broken
|
||||
|
||||
; Okay, good enough...
|
||||
mov si, alright_msg
|
||||
call writemsg
|
||||
mov [DriveNo], dl
|
||||
.found_drive:
|
||||
jmp found_drive
|
||||
|
||||
; Award BIOS 4.51 apparently passes garbage in sp_drive,
|
||||
; but if this was the drive number originally passed in
|
||||
; DL then consider it "good enough"
|
||||
.maybe_broken:
|
||||
cmp byte [DriveNo], dl
|
||||
je .found_drive
|
||||
|
||||
.still_broken:
|
||||
dec dx
|
||||
cmp dl, 80h
|
||||
jnb .test_loop
|
||||
|
||||
fatal_error:
|
||||
mov si, nothing_msg
|
||||
call writemsg
|
||||
|
||||
.norge:
|
||||
jmp short .norge
|
||||
|
||||
|
||||
|
||||
; Information message (DS:SI) output
|
||||
; Prefix with "isolinux: "
|
||||
;
|
||||
writemsg:
|
||||
push ax
|
||||
push si
|
||||
mov si, isolinux_str
|
||||
call writestr
|
||||
pop si
|
||||
call writestr
|
||||
pop ax
|
||||
ret
|
||||
|
||||
;
|
||||
; crlf: Print a newline
|
||||
;
|
||||
crlf:
|
||||
mov si, crlf_msg
|
||||
; Fall through
|
||||
|
||||
;
|
||||
; writestr: write a null-terminated string to the console, saving
|
||||
; registers on entry.
|
||||
;
|
||||
writestr:
|
||||
pushfd
|
||||
pushad
|
||||
.top:
|
||||
lodsb
|
||||
and al, al
|
||||
jz .end
|
||||
call writechr
|
||||
jmp short .top
|
||||
.end:
|
||||
popad
|
||||
popfd
|
||||
ret
|
||||
|
||||
|
||||
;
|
||||
; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
|
||||
;
|
||||
writehex2:
|
||||
pushfd
|
||||
pushad
|
||||
shl eax, 24
|
||||
mov cx, 2
|
||||
jmp short writehex_common
|
||||
writehex4:
|
||||
pushfd
|
||||
pushad
|
||||
shl eax, 16
|
||||
mov cx, 4
|
||||
jmp short writehex_common
|
||||
writehex8:
|
||||
pushfd
|
||||
pushad
|
||||
mov cx, 8
|
||||
writehex_common:
|
||||
.loop:
|
||||
rol eax, 4
|
||||
push eax
|
||||
and al, 0Fh
|
||||
cmp al, 10
|
||||
jae .high
|
||||
.low:
|
||||
add al, '0'
|
||||
jmp short .ischar
|
||||
.high:
|
||||
add al, 'A'-10
|
||||
.ischar:
|
||||
call writechr
|
||||
pop eax
|
||||
loop .loop
|
||||
popad
|
||||
popfd
|
||||
ret
|
||||
|
||||
;
|
||||
; Write a character to the screen. There is a more "sophisticated"
|
||||
; version of this in the subsequent code, so we patch the pointer
|
||||
; when appropriate.
|
||||
;
|
||||
|
||||
writechr:
|
||||
pushfd
|
||||
pushad
|
||||
mov ah, 0Eh
|
||||
xor bx, bx
|
||||
int 10h
|
||||
popad
|
||||
popfd
|
||||
ret
|
||||
|
||||
;
|
||||
; Get one sector. Convenience entry point.
|
||||
;
|
||||
getonesec:
|
||||
mov bp, 1
|
||||
; Fall through to getlinsec
|
||||
|
||||
;
|
||||
; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
|
||||
;
|
||||
; Note that we can't always do this as a single request, because at least
|
||||
; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
|
||||
; to 32 sectors (64K) per request.
|
||||
;
|
||||
; Input:
|
||||
; EAX - Linear sector number
|
||||
; ES:BX - Target buffer
|
||||
; BP - Sector count
|
||||
;
|
||||
getlinsec:
|
||||
mov si,dapa ; Load up the DAPA
|
||||
mov [si+4],bx
|
||||
mov bx,es
|
||||
mov [si+6],bx
|
||||
mov [si+8],eax
|
||||
.loop2:
|
||||
push bp ; Sectors left
|
||||
cmp bp,[MaxTransfer]
|
||||
jbe .bp_ok
|
||||
mov bp,[MaxTransfer]
|
||||
.bp_ok:
|
||||
mov [si+2],bp
|
||||
push si
|
||||
mov dl,[DriveNo]
|
||||
mov ah,42h ; Extended Read
|
||||
call xint13
|
||||
pop si
|
||||
pop bp
|
||||
movzx eax,word [si+2] ; Sectors we read
|
||||
add [si+8],eax ; Advance sector pointer
|
||||
sub bp,ax ; Sectors left
|
||||
shl ax,SECTORSIZE_LG2-4 ; 2048-byte sectors -> segment
|
||||
add [si+6],ax ; Advance buffer pointer
|
||||
and bp,bp
|
||||
jnz .loop2
|
||||
mov eax,[si+8] ; Next sector
|
||||
ret
|
||||
|
||||
; INT 13h with retry
|
||||
xint13:
|
||||
mov byte [RetryCount], retry_count
|
||||
.try:
|
||||
pushad
|
||||
int 13h
|
||||
jc .error
|
||||
add sp, byte 8*4 ; Clean up stack
|
||||
ret
|
||||
.error:
|
||||
mov [DiskError], ah ; Save error code
|
||||
popad
|
||||
dec byte [RetryCount]
|
||||
jz .real_error
|
||||
push ax
|
||||
mov al,[RetryCount]
|
||||
mov ah,[dapa+2] ; Sector transfer count
|
||||
cmp al,2 ; Only 2 attempts left
|
||||
ja .nodanger
|
||||
mov ah,1 ; Drop transfer size to 1
|
||||
jmp short .setsize
|
||||
.nodanger:
|
||||
cmp al,retry_count-2
|
||||
ja .again ; First time, just try again
|
||||
shr ah,1 ; Otherwise, try to reduce
|
||||
adc ah,0 ; the max transfer size, but not to 0
|
||||
.setsize:
|
||||
mov [MaxTransfer],ah
|
||||
mov [dapa+2],ah
|
||||
.again:
|
||||
pop ax
|
||||
jmp .try
|
||||
|
||||
.real_error:
|
||||
mov si, diskerr_msg
|
||||
call writemsg
|
||||
mov al, [DiskError]
|
||||
call writehex2
|
||||
mov si, ondrive_str
|
||||
call writestr
|
||||
mov al, dl
|
||||
call writehex2
|
||||
call crlf
|
||||
; Fall through to kaboom
|
||||
|
||||
;
|
||||
; kaboom: write a message and bail out. Wait for a user keypress,
|
||||
; then do a hard reboot.
|
||||
;
|
||||
kaboom:
|
||||
mov ax, cs
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
sti
|
||||
mov si, err_bootfailed
|
||||
call writestr
|
||||
call getchar
|
||||
cli
|
||||
mov word [BIOS_magic], 0 ; Cold reboot
|
||||
jmp 0F000h:0FFF0h ; Reset vector address
|
||||
|
||||
getchar:
|
||||
.again:
|
||||
mov ah, 1 ; Poll keyboard
|
||||
int 16h
|
||||
jz .again
|
||||
.kbd:
|
||||
xor ax, ax ; Get keyboard input
|
||||
int 16h
|
||||
.func_key:
|
||||
ret
|
||||
|
||||
|
||||
isolinux_banner db CR, LF, 'Loading IsoBoot...', CR, LF, 0
|
||||
copyright_str db ' (C) 1994-2002 H. Peter Anvin', CR, LF, 0
|
||||
presskey_msg db 'Press any key to boot from CD', 0
|
||||
dot_msg db '.',0
|
||||
|
||||
%ifdef DEBUG_MESSAGES
|
||||
startup_msg: db 'Starting up, DL = ', 0
|
||||
spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
|
||||
secsize_msg: db 'Sector size appears to be ', 0
|
||||
rootloc_msg: db 'Root directory location: ', 0
|
||||
rootlen_msg: db 'Root directory length: ', 0
|
||||
rootsect_msg: db 'Root directory length(sectors): ', 0
|
||||
fileloc_msg: db 'SETUPLDR.SYS location: ', 0
|
||||
filelen_msg: db 'SETUPLDR.SYS length: ', 0
|
||||
filesect_msg: db 'SETUPLDR.SYS length(sectors): ', 0
|
||||
findfail_msg: db 'Failed to find file!', 0
|
||||
startldr_msg: db 'Starting SETUPLDR.SYS', 0
|
||||
%endif
|
||||
|
||||
; nosecsize_msg: db 'Failed to get sector size, assuming 0800', CR, LF, 0
|
||||
spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
|
||||
maybe_msg: db 'Found something at drive = ', 0
|
||||
alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0
|
||||
nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF, 0
|
||||
isolinux_str db 'IsoBoot: ', 0
|
||||
crlf_msg db CR, LF, 0
|
||||
diskerr_msg: db 'Disk error ', 0
|
||||
ondrive_str: db ', drive ', 0
|
||||
err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
|
||||
isolinux_dir db '\LOADER', 0
|
||||
no_dir_msg db 'Could not find the LOADER directory.', CR, LF, 0
|
||||
isolinux_bin db 'SETUPLDR.SYS', 0
|
||||
no_isolinux_msg db 'Could not find SETUPLDR.SYS.', CR, LF, 0
|
||||
|
||||
;
|
||||
; El Torito spec packet
|
||||
;
|
||||
align 8, db 0
|
||||
spec_packet: db 13h ; Size of packet
|
||||
sp_media: db 0 ; Media type
|
||||
sp_drive: db 0 ; Drive number
|
||||
sp_controller: db 0 ; Controller index
|
||||
sp_lba: dd 0 ; LBA for emulated disk image
|
||||
sp_devspec: dw 0 ; IDE/SCSI information
|
||||
sp_buffer: dw 0 ; User-provided buffer
|
||||
sp_loadseg: dw 0 ; Load segment
|
||||
sp_sectors: dw 0 ; Sector count
|
||||
sp_chs: db 0,0,0 ; Simulated CHS geometry
|
||||
sp_dummy: db 0 ; Scratch, safe to overwrite
|
||||
|
||||
;
|
||||
; EBIOS drive parameter packet
|
||||
;
|
||||
align 8, db 0
|
||||
drive_params: dw 30 ; Buffer size
|
||||
dp_flags: dw 0 ; Information flags
|
||||
dp_cyl: dd 0 ; Physical cylinders
|
||||
dp_head: dd 0 ; Physical heads
|
||||
dp_sec: dd 0 ; Physical sectors/track
|
||||
dp_totalsec: dd 0,0 ; Total sectors
|
||||
dp_secsize: dw 0 ; Bytes per sector
|
||||
dp_dpte: dd 0 ; Device Parameter Table
|
||||
dp_dpi_key: dw 0 ; 0BEDDh if rest valid
|
||||
dp_dpi_len: db 0 ; DPI len
|
||||
db 0
|
||||
dw 0
|
||||
dp_bus: times 4 db 0 ; Host bus type
|
||||
dp_interface: times 8 db 0 ; Interface type
|
||||
db_i_path: dd 0,0 ; Interface path
|
||||
db_d_path: dd 0,0 ; Device path
|
||||
db 0
|
||||
db_dpi_csum: db 0 ; Checksum for DPI info
|
||||
|
||||
;
|
||||
; EBIOS disk address packet
|
||||
;
|
||||
align 8, db 0
|
||||
dapa: dw 16 ; Packet size
|
||||
.count: dw 0 ; Block count
|
||||
.off: dw 0 ; Offset of buffer
|
||||
.seg: dw 0 ; Segment of buffer
|
||||
.lba: dd 0 ; LBA (LSW)
|
||||
dd 0 ; LBA (MSW)
|
||||
|
||||
alignb 4, db 0
|
||||
MaxTransfer dw 2 ;32 ; Max sectors per transfer
|
||||
|
||||
times 2046-($-$$) db 0 ; Pad to file offset 2046
|
||||
dw 0aa55h ; BootSector signature
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* PROJECT: ReactOS MBR Boot Sector for ISO file system ("isohybrid mode")
|
||||
* LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
|
||||
* COPYRIGHT: Copyright 2017 Colin Finck <colin@reactos.org>
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Providing an MBR Boot Sector that enables an ISO to be booted from a disk
|
||||
* COPYRIGHT: Copyright 2017 Colin Finck (colin@reactos.org)
|
||||
*/
|
||||
|
||||
#include <asm.inc>
|
||||
|
|
|
@ -1,466 +0,0 @@
|
|||
;
|
||||
; Win2k FAT32 Boot Sector
|
||||
;
|
||||
; Brian Palmer <brianp@sginet.com>
|
||||
;
|
||||
|
||||
;
|
||||
; The BP register is initialized to 0x7c00, the start of
|
||||
; the boot sector. The SP register is initialized to
|
||||
; 0x7bf4, leaving 12 bytes of data storage space above
|
||||
; the stack.
|
||||
;
|
||||
; The DWORD that gets stored at 0x7bf4 is 0xffffffff ??
|
||||
;
|
||||
; The DWORD that gets stored at 0x7bf8 is the count of
|
||||
; total sectors of the volume, calculated from the BPB.
|
||||
;
|
||||
; The DWORD that gets stored at 0x7bfc is the logical
|
||||
; sector number of the start of the data area.
|
||||
;
|
||||
|
||||
org 7c00h
|
||||
|
||||
segment .text
|
||||
|
||||
bits 16
|
||||
|
||||
start:
|
||||
jmp short main
|
||||
nop
|
||||
|
||||
OEMName db 'MSWIN4.0'
|
||||
BytesPerSector dw 512
|
||||
SectsPerCluster db 1
|
||||
ReservedSectors dw 1
|
||||
NumberOfFats db 2
|
||||
MaxRootEntries dw 0 ;512 - Always zero for FAT32 volumes
|
||||
TotalSectors dw 0 ;2880 - Always zero for FAT32 volumes
|
||||
MediaDescriptor db 0f8h
|
||||
SectorsPerFat dw 0 ;9 - Always zero for FAT32 volumes
|
||||
SectorsPerTrack dw 18
|
||||
NumberOfHeads dw 2
|
||||
HiddenSectors dd 0
|
||||
TotalSectorsBig dd 0
|
||||
; FAT32 Inserted Info
|
||||
SectorsPerFatBig dd 0
|
||||
ExtendedFlags dw 0
|
||||
FSVersion dw 0
|
||||
RootDirStartCluster dd 0
|
||||
FSInfoSector dw 0
|
||||
BackupBootSector dw 6
|
||||
Reserved1 times 12 db 0
|
||||
; End FAT32 Inserted Info
|
||||
BootDrive db 80h
|
||||
Reserved db 0
|
||||
ExtendSig db 29h
|
||||
SerialNumber dd 00000000h
|
||||
VolumeLabel db 'NO NAME '
|
||||
FileSystem db 'FAT32 '
|
||||
|
||||
main:
|
||||
00007C5A 33C9 xor cx,cx
|
||||
00007C5C 8ED1 mov ss,cx ; Setup the stack
|
||||
00007C5E BCF47B mov sp,0x7bf4 ; Give us 12 bytes of space above the stack
|
||||
00007C61 8EC1 mov es,cx
|
||||
00007C63 8ED9 mov ds,cx
|
||||
00007C65 BD007C mov bp,0x7c00
|
||||
00007C68 884E02 mov [bp+0x2],cl ; Zero out the nop instruction?? (3rd byte of the boot sector)
|
||||
00007C6B 8A5640 mov dl,[bp+BootDrive]
|
||||
00007C6E B408 mov ah,0x8
|
||||
00007C70 CD13 int 0x13 ; Int 13, func 8 - Get Drive Parameters
|
||||
00007C72 7305 jnc drive_param_ok ; If no error jmp
|
||||
|
||||
drive_param_error:
|
||||
00007C74 B9FFFF mov cx,0xffff ; We couldn't determine the drive parameters
|
||||
00007C77 8AF1 mov dh,cl ; So just set the CHS to 0xff
|
||||
|
||||
drive_param_ok:
|
||||
00007C79 660FB6C6 movzx eax,dh ; Store the number of heads in eax
|
||||
00007C7D 40 inc ax ; Make it one-based because the bios returns it zero-based
|
||||
00007C7E 660FB6D1 movzx edx,cl ; Store the sectors per track in edx
|
||||
00007C82 80E23F and dl,0x3f ; Mask off the cylinder bits
|
||||
00007C85 F7E2 mul dx ; Multiply the sectors per track with the heads, result in dx:ax
|
||||
00007C87 86CD xchg cl,ch ; Switch the cylinder with the sectors
|
||||
00007C89 C0ED06 shr ch,0x6 ; Move the top two cylinder bits down where they should be
|
||||
00007C8C 41 inc cx ; Make it one-based because the bios returns it zero-based
|
||||
00007C8D 660FB7C9 movzx ecx,cx
|
||||
00007C91 66F7E1 mul ecx ; Multiply the cylinders with (heads * sectors) [stored in dx:ax already]
|
||||
00007C94 668946F8 mov [bp-0x8],eax ; This value is the number of total sectors on the disk, so save it for later
|
||||
00007C98 837E1600 cmp word [bp+TotalSectors],byte +0x0 ; Check the old 16-bit value of TotalSectors
|
||||
00007C9C 7538 jnz print_ntldr_error_message ; If it is non-zero then exit with an error
|
||||
|
||||
00007C9E 837E2A00 cmp word [bp+FSVersion],byte +0x0 ; Check the file system version word
|
||||
00007CA2 7732 ja print_ntldr_error_message ; If it is not zero then exit with an error
|
||||
|
||||
|
||||
;
|
||||
; We are now ready to load our second sector of boot code
|
||||
; But first, a bit of undocumented information about how
|
||||
; Win2k stores it's second sector of boot code.
|
||||
;
|
||||
; The FAT32 filesystem was designed so that you can store
|
||||
; multiple sectors of boot code. The boot sector of a FAT32
|
||||
; volume is actually three sectors long. Microsoft extended
|
||||
; the BPB so much that you can't fit enough code in the
|
||||
; boot sector to make it work. So they extended it. Sector 0
|
||||
; is the traditional boot sector, sector 1 is the FSInfo sector,
|
||||
; and sector 2 is used to store extra boot code to make up
|
||||
; for the lost space the BPB takes.
|
||||
;
|
||||
; Now this creates an interesting problem. Suppose for example
|
||||
; that the user has Win98 and Win2k installed. The Win2k
|
||||
; boot sector is stored at sector 0 and the Win98 boot sector is
|
||||
; stored as BOOTSECT.DOS on the file system. Now if Win2k were
|
||||
; to store it's second sector of boot code in sector 2 like
|
||||
; the fat spec says to do then when you try to dual boot back
|
||||
; to Win98 the Win98 boot sector will load Win2k's second
|
||||
; sector of boot code. Understand? ;-)
|
||||
;
|
||||
; To get around this problem Win2k stores it's second sector
|
||||
; of boot code elsewhere. This sector is always stored at sector 13
|
||||
; on the file system. Now don't ask me what happens when you don't
|
||||
; have enough reserved sectors to store it, but I've never seen a
|
||||
; FAT32 volume that didn't have at least 32 reserved sectors.
|
||||
;
|
||||
|
||||
00007CA4 668B461C mov eax,[bp+HiddenSectors] ; Get the count of hidden sectors
|
||||
00007CA8 6683C00C add eax,byte +0xc ; Add 12 to that value so that we are loading the 13th sector of the volume
|
||||
00007CAC BB0080 mov bx,0x8000 ; Read the sector to address 0x8000
|
||||
00007CAF B90100 mov cx,0x1 ; Read just one sector
|
||||
00007CB2 E82B00 call read_sectors ; Read it
|
||||
00007CB5 E94803 jmp 0x8000 ; Jump to the next sector of boot code
|
||||
|
||||
print_disk_error_message:
|
||||
00007CB8 A0FA7D mov al,[DISK_ERR_offset_from_0x7d00]
|
||||
putchars:
|
||||
00007CBB B47D mov ah,0x7d
|
||||
00007CBD 8BF0 mov si,ax
|
||||
get_another_char:
|
||||
00007CBF AC lodsb
|
||||
00007CC0 84C0 test al,al
|
||||
00007CC2 7417 jz reboot
|
||||
00007CC4 3CFF cmp al,0xff
|
||||
00007CC6 7409 jz print_reboot_message
|
||||
00007CC8 B40E mov ah,0xe
|
||||
00007CCA BB0700 mov bx,0x7
|
||||
00007CCD CD10 int 0x10
|
||||
00007CCF EBEE jmp short get_another_char
|
||||
print_reboot_message:
|
||||
00007CD1 A0FB7D mov al,[RESTART_ERR_offset_from_0x7d00]
|
||||
00007CD4 EBE5 jmp short putchars
|
||||
print_ntldr_error_message:
|
||||
00007CD6 A0F97D mov al,[NTLDR_ERR_offset_from_0x7d00]
|
||||
00007CD9 EBE0 jmp short putchars
|
||||
reboot:
|
||||
00007CDB 98 cbw
|
||||
00007CDC CD16 int 0x16
|
||||
00007CDE CD19 int 0x19
|
||||
|
||||
read_sectors:
|
||||
00007CE0 6660 pushad
|
||||
00007CE2 663B46F8 cmp eax,[bp-0x8]
|
||||
00007CE6 0F824A00 jc near 0x7d34
|
||||
00007CEA 666A00 o32 push byte +0x0
|
||||
00007CED 6650 push eax
|
||||
00007CEF 06 push es
|
||||
00007CF0 53 push bx
|
||||
00007CF1 666810000100 push dword 0x10010
|
||||
00007CF7 807E0200 cmp byte [bp+0x2],0x0
|
||||
00007CFB 0F852000 jnz near 0x7d1f
|
||||
00007CFF B441 mov ah,0x41
|
||||
00007D01 BBAA55 mov bx,0x55aa
|
||||
00007D04 8A5640 mov dl,[bp+BootDrive]
|
||||
00007D07 CD13 int 0x13
|
||||
00007D09 0F821C00 jc near 0x7d29
|
||||
00007D0D 81FB55AA cmp bx,0xaa55
|
||||
00007D11 0F851400 jnz near 0x7d29
|
||||
00007D15 F6C101 test cl,0x1
|
||||
00007D18 0F840D00 jz near 0x7d29
|
||||
00007D1C FE4602 inc byte [bp+0x2]
|
||||
00007D1F B442 mov ah,0x42
|
||||
00007D21 8A5640 mov dl,[bp+BootDrive]
|
||||
00007D24 8BF4 mov si,sp
|
||||
00007D26 CD13 int 0x13
|
||||
00007D28 B0F9 mov al,0xf9
|
||||
00007D2A 6658 pop eax
|
||||
00007D2C 6658 pop eax
|
||||
00007D2E 6658 pop eax
|
||||
00007D30 6658 pop eax
|
||||
00007D32 EB2A jmp short 0x7d5e
|
||||
00007D34 6633D2 xor edx,edx
|
||||
00007D37 660FB74E18 movzx ecx,word [bp+SectorsPerTrack]
|
||||
00007D3C 66F7F1 div ecx
|
||||
00007D3F FEC2 inc dl
|
||||
00007D41 8ACA mov cl,dl
|
||||
00007D43 668BD0 mov edx,eax
|
||||
00007D46 66C1EA10 shr edx,0x10
|
||||
00007D4A F7761A div word [bp+NumberOfHeads]
|
||||
00007D4D 86D6 xchg dl,dh
|
||||
00007D4F 8A5640 mov dl,[bp+BootDrive]
|
||||
00007D52 8AE8 mov ch,al
|
||||
00007D54 C0E406 shl ah,0x6
|
||||
00007D57 0ACC or cl,ah
|
||||
00007D59 B80102 mov ax,0x201
|
||||
00007D5C CD13 int 0x13
|
||||
00007D5E 6661 popad
|
||||
00007D60 0F8254FF jc near print_disk_error_message
|
||||
00007D64 81C30002 add bx,0x200
|
||||
00007D68 6640 inc eax
|
||||
00007D6A 49 dec cx
|
||||
00007D6B 0F8571FF jnz near read_sectors
|
||||
00007D6F C3 ret
|
||||
|
||||
NTLDR db 'NTLDR '
|
||||
|
||||
filler times 49 db 0
|
||||
|
||||
NTLDR_ERR db 0dh,0ah,'NTLDR is missing',0ffh
|
||||
DISK_ERR db 0dh,0ah,'Disk error',0ffh
|
||||
RESTART_ERR db 0dh,0ah,'Press any key to restart',0dh,0ah
|
||||
|
||||
more_filler times 16 db 0
|
||||
|
||||
NTLDR_offset_from_0x7d00 db 0
|
||||
NTLDR_ERR_offset_from_0x7d00 db 0ach
|
||||
DISK_ERR_offset_from_0x7d00 db 0bfh
|
||||
RESTART_ERR_offset_from_0x7d00 db 0cch
|
||||
|
||||
dw 0
|
||||
dw 0aa55h
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;
|
||||
; And that ends the code that makes up the traditional boot sector
|
||||
; From here on out is a disassembly of the extra sector of boot
|
||||
; code required for a FAT32 volume. Win2k stores this code at
|
||||
; sector 13 on the file system.
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
00008000 660FB64610 movzx eax,byte [bp+NumberOfFats] ; Put the number of fats into eax
|
||||
00008005 668B4E24 mov ecx,[bp+SectorsPerFatBig] ; Put the count of sectors per fat into ecx
|
||||
00008009 66F7E1 mul ecx ; Multiply them, edx:eax = (eax * ecx)
|
||||
0000800C 6603461C add eax,[bp+HiddenSectors] ; Add the hidden sectors to eax
|
||||
00008010 660FB7560E movzx edx,word [bp+ReservedSectors] ; Put the count of reserved sectors into edx
|
||||
00008015 6603C2 add eax,edx ; Add it to eax
|
||||
00008018 668946FC mov [bp-0x4],eax ; eax now contains the start of the data area, so save it for later
|
||||
0000801C 66C746F4FFFFFFFF mov dword [bp-0xc],0xffffffff ; Save 0xffffffff for later??
|
||||
00008024 668B462C mov eax,[bp+RootDirStartCluster] ; Put the starting cluster of the root directory into eax
|
||||
00008028 6683F802 cmp eax,byte +0x2 ; Check and see if the root directory starts at cluster 2 or above
|
||||
0000802C 0F82A6FC jc near print_ntldr_error_message ; If not exit with error
|
||||
00008030 663DF8FFFF0F cmp eax,0xffffff8 ; Check and see if the root directory start cluster is and end of cluster chain indicator
|
||||
00008036 0F839CFC jnc near print_ntldr_error_message ; If so exit with error
|
||||
|
||||
search_root_directory_cluster:
|
||||
0000803A 6650 push eax ; Save root directory start cluster on stack
|
||||
0000803C 6683E802 sub eax,byte +0x2 ; Adjust it because the first two fat entries are unused so the third entry marks the first data area cluster
|
||||
00008040 660FB65E0D movzx ebx,byte [bp+SectsPerCluster] ; Put the number of sectors per cluster in ebx
|
||||
00008045 8BF3 mov si,bx ; Now store it also in si register
|
||||
00008047 66F7E3 mul ebx ; Multiply sectors per cluster with root directory start cluster
|
||||
0000804A 660346FC add eax,[bp-0x4] ; Add the start sector of the data area
|
||||
|
||||
read_directory_sector:
|
||||
0000804E BB0082 mov bx,0x8200 ; We now have the start sector of the root directory, so load it to 0x8200
|
||||
00008051 8BFB mov di,bx ; Put the address of the root directory sector in di also
|
||||
00008053 B90100 mov cx,0x1 ; Read one sector
|
||||
00008056 E887FC call read_sectors ; Perform the read
|
||||
|
||||
check_entry_for_ntldr:
|
||||
00008059 382D cmp [di],ch ; Check the first byte of the root directory entry for zero
|
||||
0000805B 741E jz ntldr_not_found ; If so then NTLDR is missing so exit with error
|
||||
0000805D B10B mov cl,0xb ; Put the value 11 in cl so we can compare an 11-byte filename
|
||||
0000805F 56 push si ; Save si (which contains the number of sectors per cluster)
|
||||
00008060 BE707D mov si,NTLDR ;0x7d70 ; Check and see if "NTLDR" is the first file entry
|
||||
00008063 F3A6 repe cmpsb ; Do the compare
|
||||
00008065 5E pop si ; Restore sectors per cluster into si
|
||||
00008066 741B jz ntldr_found ; If we found it then continue, else check next entry
|
||||
00008068 03F9 add di,cx ; Add 0 to di? the next entry is 0x15 bytes away
|
||||
0000806A 83C715 add di,byte +0x15 ; Add 0x15 to di
|
||||
0000806D 3BFB cmp di,bx ; Check to see if we have reached the end of our sector we loaded, read_sectors sets bx = end address of data loaded
|
||||
0000806F 72E8 jc check_entry_for_ntldr ; If we haven't reached the end then check the next entry
|
||||
00008071 4E dec si ; decrement si, si holds the number of sectors per cluster
|
||||
00008072 75DA jnz read_directory_sector ; If it's not zero then search the next sector for NTLDR
|
||||
00008074 6658 pop eax ; If we got here that means we didn't find NTLDR in the previous root directory cluster, so restore eax with the start cluster
|
||||
00008076 E86500 call get_fat_entry ; Get the next cluster in the fat chain
|
||||
00008079 72BF jc search_root_directory_cluster ; If we reached end-of-file marker then don't jump, otherwise continue search
|
||||
|
||||
ntldr_not_found:
|
||||
0000807B 83C404 add sp,byte +0x4
|
||||
0000807E E955FC jmp print_ntldr_error_message
|
||||
|
||||
ntldr_load_segment_address dw 0x2000
|
||||
|
||||
ntldr_found:
|
||||
00008083 83C404 add sp,byte +0x4 ; Adjust stack to remove root directory start cluster
|
||||
00008086 8B7509 mov si,[di+0x9] ; Put start cluster high word in si
|
||||
00008089 8B7D0F mov di,[di+0xf] ; Put start cluster low word in di
|
||||
0000808C 8BC6 mov ax,si ; Put high word in ax
|
||||
0000808E 66C1E010 shl eax,0x10 ; Shift it into position
|
||||
00008092 8BC7 mov ax,di ; Put low word in ax, now eax contains start cluster of NTLDR
|
||||
00008094 6683F802 cmp eax,byte +0x2 ; Check and see if the start cluster of NTLDR starts at cluster 2 or above
|
||||
00008098 0F823AFC jc near print_ntldr_error_message ; If not exit with error
|
||||
0000809C 663DF8FFFF0F cmp eax,0xffffff8 ; Check and see if the start cluster of NTLDR is and end of cluster chain indicator
|
||||
000080A2 0F8330FC jnc near print_ntldr_error_message ; If so exit with error
|
||||
|
||||
load_next_ntldr_cluster:
|
||||
000080A6 6650 push eax ; Save NTLDR start cluster for later
|
||||
000080A8 6683E802 sub eax,byte +0x2 ; Adjust it because the first two fat entries are unused so the third entry marks the first data area cluster
|
||||
000080AC 660FB64E0D movzx ecx,byte [bp+SectsPerCluster] ; Put the sectors per cluster into ecx
|
||||
000080B1 66F7E1 mul ecx ; Multiply sectors per cluster by the start cluster, we now have the logical start sector
|
||||
000080B4 660346FC add eax,[bp-0x4] ; Add the start of the data area logical sector
|
||||
000080B8 BB0000 mov bx,0x0 ; Load NTLDR to offset zero
|
||||
000080BB 06 push es ; Save es
|
||||
000080BC 8E068180 mov es,[ntldr_load_segment_address] ; Get the segment address to load NTLDR to
|
||||
000080C0 E81DFC call read_sectors ; Load the first cluster
|
||||
000080C3 07 pop es ; Restore es
|
||||
000080C4 6658 pop eax ; Restore eax to NTLDR start cluster
|
||||
000080C6 C1EB04 shr bx,0x4 ; bx contains the amount of data we transferred, so divide it by 16
|
||||
000080C9 011E8180 add [ntldr_load_segment_address],bx ; Add that value to the segment
|
||||
000080CD E80E00 call get_fat_entry ; Get the next cluster in eax
|
||||
000080D0 0F830200 jnc near jump_to_ntldr ; If we have reached the end of file then lets get to NTLDR
|
||||
000080D4 72D0 jc load_next_ntldr_cluster ; If not, then load another cluster
|
||||
|
||||
jump_to_ntldr:
|
||||
000080D6 8A5640 mov dl,[bp+BootDrive] ; Put the boot drive in dl
|
||||
000080D9 EA00000020 jmp 0x2000:0x0 ; Jump to NTLDR
|
||||
|
||||
get_fat_entry:
|
||||
000080DE 66C1E002 shl eax,0x2 ; Multiply cluster by 4
|
||||
000080E2 E81100 call load_fat_sector ; Load the fat sector
|
||||
000080E5 26668B01 mov eax,[es:bx+di] ; Get the fat entry
|
||||
000080E9 6625FFFFFF0F and eax,0xfffffff ; Mask off the most significant 4 bits
|
||||
000080EF 663DF8FFFF0F cmp eax,0xffffff8 ; Compare it to end of file marker to set the flags correctly
|
||||
000080F5 C3 ret ; Return to caller
|
||||
|
||||
load_fat_sector:
|
||||
000080F6 BF007E mov di,0x7e00 ; We will load the fat sector to 0x7e00
|
||||
000080F9 660FB74E0B movzx ecx,word [bp+SectsPerCluster] ; Get the sectors per cluster
|
||||
000080FE 6633D2 xor edx,edx ; We will divide (cluster * 4) / sectorspercluster
|
||||
00008101 66F7F1 div ecx ; eax is already set before we get to this routine
|
||||
00008104 663B46F4 cmp eax,[bp-0xc] ; Compare eax to 0xffffffff (initially, we set this value later)
|
||||
00008108 743A jz load_fat_sector_end ; If it is the same return
|
||||
0000810A 668946F4 mov [bp-0xc],eax ; Update that value
|
||||
0000810E 6603461C add eax,[bp+HiddenSectors] ; Add the hidden sectors
|
||||
00008112 660FB74E0E movzx ecx,word [bp+ReservedSectors] ; Add the reserved sectors
|
||||
00008117 6603C1 add eax,ecx ; To the hidden sectors + the value we computed earlier
|
||||
0000811A 660FB75E28 movzx ebx,word [bp+ExtendedFlags] ; Get extended flags and put into ebx
|
||||
0000811F 83E30F and bx,byte +0xf ; Mask off upper 8 bits
|
||||
00008122 7416 jz load_fat_sector_into_memory ; If fat is mirrored then skip fat calcs
|
||||
00008124 3A5E10 cmp bl,[bp+NumberOfFats] ; Compare bl to number of fats
|
||||
00008127 0F83ABFB jnc near print_ntldr_error_message ; If bl is bigger than numfats exit with error
|
||||
0000812B 52 push dx ; Save dx
|
||||
0000812C 668BC8 mov ecx,eax ; Put the current fat sector offset into ecx
|
||||
0000812F 668B4624 mov eax,[bp+SectorsPerFatBig] ; Get the number of sectors occupied by one fat
|
||||
00008133 66F7E3 mul ebx ; Multiplied by the active fat index
|
||||
00008136 6603C1 add eax,ecx ; Add the current fat sector offset
|
||||
00008139 5A pop dx ; Restore dx
|
||||
load_fat_sector_into_memory:
|
||||
0000813A 52 push dx ; Save dx, what is so important in dx??
|
||||
0000813B 8BDF mov bx,di ; Put 0x7e00 in bx
|
||||
0000813D B90100 mov cx,0x1 ; Load one sector
|
||||
00008140 E89DFB call read_sectors ; Perform the read
|
||||
00008143 5A pop dx ; Restore dx
|
||||
load_fat_sector_end:
|
||||
00008144 8BDA mov bx,dx ; Put it into bx, what is this value??
|
||||
00008146 C3 ret ; Return
|
||||
|
||||
|
||||
00008147 0000 add [bx+si],al
|
||||
00008149 0000 add [bx+si],al
|
||||
0000814B 0000 add [bx+si],al
|
||||
0000814D 0000 add [bx+si],al
|
||||
0000814F 0000 add [bx+si],al
|
||||
00008151 0000 add [bx+si],al
|
||||
00008153 0000 add [bx+si],al
|
||||
00008155 0000 add [bx+si],al
|
||||
00008157 0000 add [bx+si],al
|
||||
00008159 0000 add [bx+si],al
|
||||
0000815B 0000 add [bx+si],al
|
||||
0000815D 0000 add [bx+si],al
|
||||
0000815F 0000 add [bx+si],al
|
||||
00008161 0000 add [bx+si],al
|
||||
00008163 0000 add [bx+si],al
|
||||
00008165 0000 add [bx+si],al
|
||||
00008167 0000 add [bx+si],al
|
||||
00008169 0000 add [bx+si],al
|
||||
0000816B 0000 add [bx+si],al
|
||||
0000816D 0000 add [bx+si],al
|
||||
0000816F 0000 add [bx+si],al
|
||||
00008171 0000 add [bx+si],al
|
||||
00008173 0000 add [bx+si],al
|
||||
00008175 0000 add [bx+si],al
|
||||
00008177 0000 add [bx+si],al
|
||||
00008179 0000 add [bx+si],al
|
||||
0000817B 0000 add [bx+si],al
|
||||
0000817D 0000 add [bx+si],al
|
||||
0000817F 0000 add [bx+si],al
|
||||
00008181 0000 add [bx+si],al
|
||||
00008183 0000 add [bx+si],al
|
||||
00008185 0000 add [bx+si],al
|
||||
00008187 0000 add [bx+si],al
|
||||
00008189 0000 add [bx+si],al
|
||||
0000818B 0000 add [bx+si],al
|
||||
0000818D 0000 add [bx+si],al
|
||||
0000818F 0000 add [bx+si],al
|
||||
00008191 0000 add [bx+si],al
|
||||
00008193 0000 add [bx+si],al
|
||||
00008195 0000 add [bx+si],al
|
||||
00008197 0000 add [bx+si],al
|
||||
00008199 0000 add [bx+si],al
|
||||
0000819B 0000 add [bx+si],al
|
||||
0000819D 0000 add [bx+si],al
|
||||
0000819F 0000 add [bx+si],al
|
||||
000081A1 0000 add [bx+si],al
|
||||
000081A3 0000 add [bx+si],al
|
||||
000081A5 0000 add [bx+si],al
|
||||
000081A7 0000 add [bx+si],al
|
||||
000081A9 0000 add [bx+si],al
|
||||
000081AB 0000 add [bx+si],al
|
||||
000081AD 0000 add [bx+si],al
|
||||
000081AF 0000 add [bx+si],al
|
||||
000081B1 0000 add [bx+si],al
|
||||
000081B3 0000 add [bx+si],al
|
||||
000081B5 0000 add [bx+si],al
|
||||
000081B7 0000 add [bx+si],al
|
||||
000081B9 0000 add [bx+si],al
|
||||
000081BB 0000 add [bx+si],al
|
||||
000081BD 0000 add [bx+si],al
|
||||
000081BF 0000 add [bx+si],al
|
||||
000081C1 0000 add [bx+si],al
|
||||
000081C3 0000 add [bx+si],al
|
||||
000081C5 0000 add [bx+si],al
|
||||
000081C7 0000 add [bx+si],al
|
||||
000081C9 0000 add [bx+si],al
|
||||
000081CB 0000 add [bx+si],al
|
||||
000081CD 0000 add [bx+si],al
|
||||
000081CF 0000 add [bx+si],al
|
||||
000081D1 0000 add [bx+si],al
|
||||
000081D3 0000 add [bx+si],al
|
||||
000081D5 0000 add [bx+si],al
|
||||
000081D7 0000 add [bx+si],al
|
||||
000081D9 0000 add [bx+si],al
|
||||
000081DB 0000 add [bx+si],al
|
||||
000081DD 0000 add [bx+si],al
|
||||
000081DF 0000 add [bx+si],al
|
||||
000081E1 0000 add [bx+si],al
|
||||
000081E3 0000 add [bx+si],al
|
||||
000081E5 0000 add [bx+si],al
|
||||
000081E7 0000 add [bx+si],al
|
||||
000081E9 0000 add [bx+si],al
|
||||
000081EB 0000 add [bx+si],al
|
||||
000081ED 0000 add [bx+si],al
|
||||
000081EF 0000 add [bx+si],al
|
||||
000081F1 0000 add [bx+si],al
|
||||
000081F3 0000 add [bx+si],al
|
||||
000081F5 0000 add [bx+si],al
|
||||
000081F7 0000 add [bx+si],al
|
||||
000081F9 0000 add [bx+si],al
|
||||
000081FB 0000 add [bx+si],al
|
||||
000081FD 0055AA add [di-0x56],dl ; We can't forget the infamous boot signature
|
|
@ -1,249 +0,0 @@
|
|||
|
||||
;
|
||||
; The BP register is initialized to 0x7c00, the start of
|
||||
; the boot sector. The SP register is initialized to
|
||||
; 0x7bf0, leaving 16 bytes of data storage space above
|
||||
; the stack.
|
||||
;
|
||||
; The DWORD that gets stored at 0x7bfc is the logical
|
||||
; sector number of the start of the data area.
|
||||
;
|
||||
; The DWORD that gets stored at 0x7bf8 is ????????
|
||||
;
|
||||
; The DWORD that gets stored at 0x7bf4 is ????????
|
||||
;
|
||||
; The DWORD that gets stored at 0x7bf0 is ????????
|
||||
;
|
||||
|
||||
|
||||
org 7c00h
|
||||
|
||||
segment .text
|
||||
|
||||
bits 16
|
||||
|
||||
start:
|
||||
jmp short main
|
||||
nop
|
||||
|
||||
OEMName db 'MSWIN4.0'
|
||||
BytesPerSector dw 512
|
||||
SectsPerCluster db 1
|
||||
ReservedSectors dw 1
|
||||
NumberOfFats db 2
|
||||
MaxRootEntries dw 0 ;512 - Always zero for FAT32 volumes
|
||||
TotalSectors dw 0 ;2880 - Always zero for FAT32 volumes
|
||||
MediaDescriptor db 0f8h
|
||||
SectorsPerFat dw 0 ;9 - Always zero for FAT32 volumes
|
||||
SectorsPerTrack dw 18
|
||||
NumberOfHeads dw 2
|
||||
HiddenSectors dd 0
|
||||
TotalSectorsBig dd 0
|
||||
BootDrive db 80h
|
||||
Reserved db 0
|
||||
ExtendSig db 29h
|
||||
SerialNumber dd 00000000h
|
||||
VolumeLabel db 'NO NAME '
|
||||
FileSystem db 'FAT16 '
|
||||
|
||||
main:
|
||||
00007C3E 33C9 xor cx,cx
|
||||
00007C40 8ED1 mov ss,cx ; Setup stack
|
||||
00007C42 BCF07B mov sp,0x7bf0 ; Give us 16 bytes (4 dwords) of space above stack
|
||||
00007C45 8ED9 mov ds,cx
|
||||
00007C47 B80020 mov ax,0x2000
|
||||
00007C4A 8EC0 mov es,ax ; Setup ES:0000 == 2000:0000
|
||||
00007C4C FC cld
|
||||
00007C4D BD007C mov bp,0x7c00
|
||||
00007C50 384E24 cmp [bp+BootDrive],cl ; Compare the boot drive to zero (I think they are testing for a hard disk drive number)
|
||||
00007C53 7D24 jnl floppy_boot ; Nope, it's a floppy, skip partition table tests
|
||||
00007C55 8BC1 mov ax,cx ; Move zero to AX
|
||||
00007C57 99 cwd ; DX:AX now contains zero
|
||||
00007C58 E83C01 call read_one_sector ; Try to read in the MBR sector
|
||||
00007C5B 721C jc floppy_boot ; Read failed, continue
|
||||
00007C5D 83EB3A sub bx,byte +0x3a ; BX comes back with 512, make it equal to 454 (offset of partition table in MBR)
|
||||
00007C60 66A11C7C mov eax,[HiddenSectors] ; Put HiddenSectors in EAX
|
||||
find_our_partition:
|
||||
00007C64 26663B07 cmp eax,[es:bx] ; Compare partition table entry's start sector to HiddenSectors
|
||||
00007C68 268A57FC mov dl,[es:bx-0x4] ; Get partition type byte for this entry
|
||||
00007C6C 7506 jnz next_partition_entry ; If partition start sector != HiddenSectors then skip this entry
|
||||
00007C6E 80CA02 or dl,0x2 ; Set the second bit in partition type?? I guess this makes types 4 & 6 identical
|
||||
00007C71 885602 mov [bp+0x2],dl ; Save it on top of nop instruction (3rd byte of boot sector)
|
||||
next_partition_entry:
|
||||
00007C74 80C310 add bl,0x10 ; Add 16 to bl (offset of next entry in partition table)
|
||||
00007C77 73EB jnc find_our_partition ; Jump back until we hit the end of the partition table
|
||||
|
||||
; We now have our partition type at 0000:7C02
|
||||
; If the type was 4 or 6 then that byte is 6
|
||||
; I can't imagine why the boot sector needs to store
|
||||
; this information, but hopefully I will uncover it
|
||||
; as I further disassemble this boot sector.
|
||||
|
||||
|
||||
floppy_boot:
|
||||
00007C79 33C9 xor cx,cx ; Zero out CX
|
||||
00007C7B 8A4610 mov al,[bp+NumberOfFats] ; Get the number of FATs in AL (usually 2)
|
||||
00007C7E 98 cbw ; Sign extend it into AX (AX == 2)
|
||||
00007C7F F76616 mul word [bp+NumberOfFats] ; Multiply it with NumberOfFats PLUS the low byte of MaxRootEntries!!??
|
||||
00007C82 03461C add ax,[bp+HiddenSectors] ; Result is in DX:AX
|
||||
00007C85 13561E adc dx,[bp+HiddenSectors+2] ; Add HiddenSectors to DX:AX
|
||||
00007C88 03460E add ax,[bp+ReservedSectors] ; Add ReservedSectors to DX:AX
|
||||
00007C8B 13D1 adc dx,cx ; CX still contains zero
|
||||
00007C8D 8B7611 mov si,[bp+MaxRootEntries] ; Get MaxRootEntries in SI
|
||||
00007C90 60 pusha ; Save all registers (right now DX:AX has starting sector of root dir)
|
||||
00007C91 8946FC mov [bp-0x4],ax ; Save the starting sector of the root directory
|
||||
00007C94 8956FE mov [bp-0x2],dx ; Save it in the first 4 bytes before the boot sector
|
||||
00007C97 B82000 mov ax,0x20 ; AX == 32 (size of a directory entry)
|
||||
00007C9A F7E6 mul si ; Multiply it with MaxRootEntries (DX:AX == length in bytes of root directory)
|
||||
00007C9C 8B5E0B mov bx,[bp+BytesPerSector] ; Get the BytesPerSector in BX
|
||||
00007C9F 03C3 add ax,bx ; Add it to AX (what if this addition carries? MS should 'adc dx,0' shouldn't they?)
|
||||
00007CA1 48 dec ax ; Subtract one (basically rounding up)
|
||||
00007CA2 F7F3 div bx ; Divide DX:AX (length of root dir in bytes) by the size of a sector
|
||||
00007CA4 0146FC add [bp-0x4],ax ; Add the number of sectors of the root directory to our other value
|
||||
00007CA7 114EFE adc [bp-0x2],cx ; Now the first 4 bytes before the boot sector contain the starting sector of the data area
|
||||
00007CAA 61 popa ; Restore all registers (DX:AX has start sector of root dir)
|
||||
load_root_dir_sector:
|
||||
00007CAB BF0000 mov di,0x0 ; Zero out di
|
||||
00007CAE E8E600 call read_one_sector ; Read the first sector of the root directory
|
||||
00007CB1 7239 jc print_disk_error_message ; Read failed, print disk error and reboot
|
||||
search_directory:
|
||||
00007CB3 26382D cmp [es:di],ch ; If the first byte of the directory entry is zero then we have reached the end
|
||||
00007CB6 7417 jz print_ntldr_error_message; of the directory and NTLDR is not here so reboot
|
||||
00007CB8 60 pusha ; Save all registers
|
||||
00007CB9 B10B mov cl,0xb ; Put 11 in cl (length of filename in directory entry)
|
||||
00007CBB BEA17D mov si,NTLDR ; Put offset of filename string in DS:SI
|
||||
00007CBE F3A6 repe cmpsb ; Compare this directory entry against 'NTLDR '
|
||||
00007CC0 61 popa ; Restore all the registers
|
||||
00007CC1 7432 jz found_ntldr ; If we found NTLDR then jump
|
||||
00007CC3 4E dec si ; SI holds MaxRootEntries, subtract one
|
||||
00007CC4 7409 jz print_ntldr_error_message; If we are out of root dir entries then reboot
|
||||
00007CC6 83C720 add di,byte +0x20 ; Increment DI by the size of a directory entry
|
||||
00007CC9 3BFB cmp di,bx ; Compare DI to BX (DI has offset to next dir entry, BX has address of end of directory sector in memory)
|
||||
00007CCB 72E6 jc search_directory ; If DI is less than BX loop again
|
||||
00007CCD EBDC jmp short load_root_dir_sector ; Didn't find NTLDR in this directory sector, try again
|
||||
print_ntldr_error_message:
|
||||
00007CCF A0FB7D mov al,[NTLDR_ERR_offset_from_0x7d00]
|
||||
putchars:
|
||||
00007CD2 B47D mov ah,0x7d
|
||||
00007CD4 8BF0 mov si,ax
|
||||
get_another_char:
|
||||
00007CD6 AC lodsb
|
||||
00007CD7 98 cbw
|
||||
00007CD8 40 inc ax
|
||||
00007CD9 740C jz print_reboot_message
|
||||
00007CDB 48 dec ax
|
||||
00007CDC 7413 jz reboot
|
||||
00007CDE B40E mov ah,0xe
|
||||
00007CE0 BB0700 mov bx,0x7
|
||||
00007CE3 CD10 int 0x10
|
||||
00007CE5 EBEF jmp short get_another_char
|
||||
print_reboot_message:
|
||||
00007CE7 A0FD7D mov al,[RESTART_ERR_offset_from_0x7d00]
|
||||
00007CEA EBE6 jmp short putchars
|
||||
print_disk_error_message:
|
||||
00007CEC A0FC7D mov al,[DISK_ERR_offset_from_0x7d00]
|
||||
00007CEF EBE1 jmp short putchars
|
||||
reboot:
|
||||
00007CF1 CD16 int 0x16
|
||||
00007CF3 CD19 int 0x19
|
||||
found_ntldr:
|
||||
00007CF5 268B551A mov dx,[es:di+0x1a] ; Get NTLDR start cluster in DX
|
||||
00007CF9 52 push dx ; Save it on the stack
|
||||
00007CFA B001 mov al,0x1 ; Read 1 cluster? Or is this one sector?
|
||||
00007CFC BB0000 mov bx,0x0 ; ES:BX is the load address (2000:0000)
|
||||
00007CFF E83B00 call read_cluster ; Do the read
|
||||
00007D02 72E8 jc print_disk_error_message ; If it failed then reboot
|
||||
00007D04 5B pop bx ; Get the start cluster of NTLDR in BX
|
||||
00007D05 8A5624 mov dl,[bp+BootDrive] ; Get boot drive in DL
|
||||
00007D08 BE0B7C mov si,0x7c0b
|
||||
00007D0B 8BFC mov di,sp
|
||||
00007D0D C746F03D7D mov word [bp-0x10],read_cluster
|
||||
00007D12 C746F4297D mov word [bp-0xc],0x7d29
|
||||
00007D17 8CD9 mov cx,ds
|
||||
00007D19 894EF2 mov [bp-0xe],cx
|
||||
00007D1C 894EF6 mov [bp-0xa],cx
|
||||
00007D1F C606967DCB mov byte [0x7d96],0xcb
|
||||
00007D24 EA03000020 jmp 0x2000:0x3
|
||||
00007D29 0FB6C8 movzx cx,al
|
||||
00007D2C 668B46F8 mov eax,[bp-0x8]
|
||||
00007D30 6603461C add eax,[bp+HiddenSectors]
|
||||
00007D34 668BD0 mov edx,eax
|
||||
00007D37 66C1EA10 shr edx,0x10
|
||||
00007D3B EB5E jmp short 0x7d9b
|
||||
read_cluster:
|
||||
00007D3D 0FB6C8 movzx cx,al
|
||||
00007D40 4A dec dx
|
||||
00007D41 4A dec dx
|
||||
00007D42 8A460D mov al,[bp+SectsPerCluster]
|
||||
00007D45 32E4 xor ah,ah
|
||||
00007D47 F7E2 mul dx
|
||||
00007D49 0346FC add ax,[bp-0x4]
|
||||
00007D4C 1356FE adc dx,[bp-0x2]
|
||||
00007D4F EB4A jmp short 0x7d9b
|
||||
|
||||
read_sectors:
|
||||
00007D51 52 push dx
|
||||
00007D52 50 push ax
|
||||
00007D53 06 push es
|
||||
00007D54 53 push bx
|
||||
00007D55 6A01 push byte +0x1
|
||||
00007D57 6A10 push byte +0x10
|
||||
00007D59 91 xchg ax,cx
|
||||
00007D5A 8B4618 mov ax,[bp+SectorsPerTrack]
|
||||
00007D5D 96 xchg ax,si
|
||||
00007D5E 92 xchg ax,dx
|
||||
00007D5F 33D2 xor dx,dx
|
||||
00007D61 F7F6 div si
|
||||
00007D63 91 xchg ax,cx
|
||||
00007D64 F7F6 div si
|
||||
00007D66 42 inc dx
|
||||
00007D67 87CA xchg cx,dx
|
||||
00007D69 F7761A div word [bp+NumberOfHeads]
|
||||
00007D6C 8AF2 mov dh,dl
|
||||
00007D6E 8AE8 mov ch,al
|
||||
00007D70 C0CC02 ror ah,0x2
|
||||
00007D73 0ACC or cl,ah
|
||||
00007D75 B80102 mov ax,0x201
|
||||
00007D78 807E020E cmp byte [bp+0x2],0xe
|
||||
00007D7C 7504 jnz 0x7d82
|
||||
00007D7E B442 mov ah,0x42
|
||||
00007D80 8BF4 mov si,sp
|
||||
00007D82 8A5624 mov dl,[bp+BootDrive]
|
||||
00007D85 CD13 int 0x13
|
||||
00007D87 61 popa
|
||||
00007D88 61 popa
|
||||
00007D89 720B jc 0x7d96
|
||||
00007D8B 40 inc ax
|
||||
00007D8C 7501 jnz 0x7d8f
|
||||
00007D8E 42 inc dx
|
||||
00007D8F 035E0B add bx,[bp+BytesPerSector]
|
||||
00007D92 49 dec cx
|
||||
00007D93 7506 jnz 0x7d9b
|
||||
00007D95 F8 clc
|
||||
00007D96 C3 ret
|
||||
|
||||
read_one_sector:
|
||||
00007D97 41 inc cx
|
||||
00007D98 BB0000 mov bx,0x0
|
||||
00007D9B 60 pusha
|
||||
00007D9C 666A00 o32 push byte +0x0
|
||||
00007D9F EBB0 jmp short 0x7d51
|
||||
|
||||
|
||||
NTLDR db 'NTLDR '
|
||||
|
||||
|
||||
NTLDR_ERR db 0dh,0ah,'NTLDR is missing',0ffh
|
||||
DISK_ERR db 0dh,0ah,'Disk error',0ffh
|
||||
RESTART_ERR db 0dh,0ah,'Press any key to restart',0dh,0ah
|
||||
|
||||
filler times 18 db 0
|
||||
|
||||
|
||||
NTLDR_offset_from_0x7d00 db 0
|
||||
NTLDR_ERR_offset_from_0x7d00 db 0ach
|
||||
DISK_ERR_offset_from_0x7d00 db 0bfh
|
||||
RESTART_ERR_offset_from_0x7d00 db 0cch
|
||||
|
||||
dw 0
|
||||
dw 0aa55h
|
Loading…
Reference in a new issue