mirror of
https://github.com/reactos/reactos.git
synced 2025-04-21 12:40:33 +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)
|
* 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
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
* PROGRAMMERS: H. Peter Anvin
|
* PURPOSE: Booting ReactOS off a CD-ROM using the El Torito boot standard in "no emulation mode"
|
||||||
* Michael K. Ter Louw
|
* COPYRIGHT: Copyright 1994-2009 H. Peter Anvin
|
||||||
* Eric Kohl
|
* Copyright 2002 Michael K. Ter Louw
|
||||||
* Timo Kreuzer <timo.kreuzer@reactos.org>
|
* Copyright 2002 Eric Kohl
|
||||||
* Colin Finck <colin@reactos.org>
|
* Copyright 2009 Intel Corporation *author: H. Peter Anvin
|
||||||
*
|
* Copyright 2011 Timo Kreuzer (timo.kreuzer@reactos.org)
|
||||||
*****************************************************************************
|
* Copyright 2017 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.
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* INCLUDES ******************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
#include <asm.inc>
|
#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")
|
* 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
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
* COPYRIGHT: Copyright 2017 Colin Finck <colin@reactos.org>
|
* 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>
|
#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