blob: c1a342c0f3ec8fe5298bf4e896c8821baaa56a2b [file] [log] [blame] [raw]
/*
* bootlace.inc -- code shared by 16-bit DOS and 32-bit Linux
* Copyright (C) 2005,2006,2007 Tinybit(tinybit@tom.com)
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
.file "bootlace.inc"
#ifdef __DOS_16
#undef ABS
#define ABS(x) (x - _start + 0x100)
#undef iBX
#define iBX %bx
#undef iSI
#define iSI %si
#undef iDI
#define iDI %di
#undef iDX
#define iDX %dx
#undef LEAL
#define LEAL ADDR32 leal
#undef MOVZWL
#define MOVZWL ADDR32 movzwl
#undef MOVL
#define MOVL ADDR32 movl
#undef MOVW
#define MOVW ADDR32 movw
#undef CMPL
#define CMPL ADDR32 cmpl
#undef CMPW
#define CMPW ADDR32 cmpw
#undef SUBL
#define SUBL ADDR32 subl
#undef SBBL
#define SBBL ADDR32 sbbl
#undef NEGL
#define NEGL ADDR32 negl
#undef NOTL
#define NOTL ADDR32 notl
#undef ADCL
#define ADCL ADDR32 adcl
#undef ADDL
#define ADDL ADDR32 addl
#undef DIVL
#define DIVL ADDR32 divl
. = _start + 0x34 // dos entry point invalid_dos_exec
#if 0
movl $ABS(msg_invalid_dos), %ecx
call 8f
movw $0x4c01, %ax // EXIT - TERMINATE WITH RETURN CODE 1
int $0x21 // call DOS
#else
jmp 1f
#endif
//////////////////////////////////////////////////////////////////////
. = _start + 0x47 // dos entry point
1:
/* dos entry point */
movl $0x81, %esi
movl %esi, %edi
movl $0x7f, %ecx
movb $0x0d, %al /* CR */
cld
repnz scasb
decl %edi /* points to CR */
std
movb $0, %al
stosb
movl %edi, %esi
xorl %ecx, %ecx
pushl %ecx /* 0 is the end of argv */
xorl %edx, %edx /* find spaces */
3:
cmpl $0x81, %edi
jb 3f
lodsb
cmpb $0x20, %al
je 1f
cmpb $0x09, %al
jne 2f
1:
testl %edx, %edx
jz 1f
notl %edx
incl %edi
pushl %edi /* argv */
decl %edi
1:
movb $0, %al
stosb
jmp 3b
2:
testl %edx, %edx
jnz 1f
incl %ecx
notl %edx
1:
stosb
jmp 3b
3:
testl %edx, %edx
jz 1f
incl %edi
pushl %edi
1:
pushl %esi /* dummy for program name */
incl %ecx
pushl %ecx /* argc */
cld
#else
#undef ABS
#define ABS(x) (x)
#undef iBX
#define iBX %ebx
#undef iSI
#define iSI %esi
#undef iDI
#define iDI %edi
#undef iDX
#define iDX %edx
#undef LEAL
#define LEAL leal
#undef MOVZWL
#define MOVZWL movzwl
#undef MOVL
#define MOVL movl
#undef MOVW
#define MOVW movw
#undef CMPL
#define CMPL cmpl
#undef CMPW
#define CMPW cmpw
#undef SUBL
#define SUBL subl
#undef SBBL
#define SBBL sbbl
#undef NEGL
#define NEGL negl
#undef NOTL
#define NOTL notl
#undef ADCL
#define ADCL adcl
#undef ADDL
#define ADDL addl
#undef DIVL
#define DIVL divl
#endif
popl %ecx # argc
/* argc must be > 1 */
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $1, %ecx
movl $ABS(msg_no_args), %ecx
jbe 4f /* error */
/* Note: ECX does not hold the argc now. */
xorl %eax, %eax # EAX will point to file name
//movl %ebx, ABS(filename) # save 0 to filename
popl %ecx # discard argv[0], the program name
1:
popl %ecx # argv
movl %ecx, %ebx
test %ecx, %ecx
jz 1f /* end of arguments */
/* check if it is an option */
cmpb $0x2D, (iBX) # "-"
jz 2f
/* it is a filename */
testl %eax, %eax # filename already specified?
//cmpl $0, ABS(filename)
jz 3f
/* error: only one file should be specified. */
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_too_many_files), %ecx
jmp 4f /* error */
3:
/* not yet, this is the first filename */
movl %ecx, %eax # save ECX to EAX
//movl %ecx, ABS(filename) # save ECX to filename
jmp 1b # continue
2:
/* it is an option */
/* check --restore-mbr */
movl $14, %ecx
movl $ABS(option_restore_mbr), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
testl $0x80000000, ABS(restore_mbr)
movl $ABS(msg_option_restore_mbr_with_other), %ecx
jnz 4f /* error */
testb $1, ABS(restore_mbr)
movl $ABS(msg_option_restore_mbr), %ecx
jnz 4f /* error */
orb $1, ABS(restore_mbr)
jmp 1b
3:
/* check --read-only */
movl $12, %ecx
movl $ABS(option_read_only), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $2, ABS(read_only)
movl $ABS(msg_option_read_only), %ecx
jnz 4f /* error */
movl $0, ABS(read_only)
jmp 1b
3:
orl $0x80000000, ABS(restore_mbr) # first option is not --restore-mbr/--read-only
testb $1, ABS(restore_mbr)
movl $ABS(msg_option_restore_mbr_with_other), %ecx
jnz 4f /* error */
/* check --no-backup-mbr */
movl $16, %ecx
movl $ABS(option_no_backup_mbr), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $1, ABS(backup_mbr)
movl $ABS(msg_option_backup_mbr), %ecx
jnz 4f /* error */
movl $0, ABS(backup_mbr)
jmp 1b
3:
/* check --force-backup-mbr */
movl $19, %ecx
movl $ABS(option_force_backup_mbr), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $1, ABS(backup_mbr)
movl $ABS(msg_option_backup_mbr), %ecx
jnz 4f /* error */
movl $2, ABS(backup_mbr)
jmp 1b
3:
/* check --mbr-enable-floppy */
movl $20, %ecx
movl $ABS(option_mbr_enable_floppy), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(mbr_floppy)
movl $ABS(msg_option_mbr_floppy), %ecx
jnz 4f /* error */
movl $2, ABS(mbr_floppy)
jmp 1b
3:
/* check --mbr-disable-floppy */
movl $21, %ecx
movl $ABS(option_mbr_disable_floppy), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(mbr_floppy)
movl $ABS(msg_option_mbr_floppy), %ecx
jnz 4f /* error */
movl $1, ABS(mbr_floppy)
jmp 1b
3:
/* check --mbr-enable-osbr */
movl $18, %ecx
movl $ABS(option_mbr_enable_osbr), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(mbr_osbr)
movl $ABS(msg_option_mbr_osbr), %ecx
jnz 4f /* error */
movl $2, ABS(mbr_osbr)
jmp 1b
3:
/* check --mbr-disable-osbr */
movl $19, %ecx
movl $ABS(option_mbr_disable_osbr), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(mbr_osbr)
movl $ABS(msg_option_mbr_osbr), %ecx
jnz 4f /* error */
movl $1, ABS(mbr_osbr)
jmp 1b
3:
/* check --mbr-no-bpb */
movl $13, %ecx
movl $ABS(option_mbr_no_bpb), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(mbr_bpb)
movl $ABS(msg_option_mbr_bpb), %ecx
jnz 4f /* error */
movl $1, ABS(mbr_bpb)
jmp 1b
3:
/* check --duce */
movl $7, %ecx
movl $ABS(option_duce), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(duce)
movl $ABS(msg_option_duce), %ecx
jnz 4f /* error */
movl $1, ABS(duce)
jmp 1b
3:
/* check --boot-prevmbr-first */
movl $21, %ecx
movl $ABS(option_boot_prevmbr_first), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(boot_prevmbr)
movl $ABS(msg_option_boot_prevmbr), %ecx
jnz 4f /* error */
movl $1, ABS(boot_prevmbr)
jmp 1b
3:
/* check --boot-prevmbr-last */
movl $20, %ecx
movl $ABS(option_boot_prevmbr_last), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(boot_prevmbr)
movl $ABS(msg_option_boot_prevmbr), %ecx
jnz 4f /* error */
movl $2, ABS(boot_prevmbr)
jmp 1b
3:
/* check --preferred-drive= */
movl $18, %ecx
movl $ABS(option_preferred_drive), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xff, ABS(preferred_drive)
movl $ABS(msg_option_preferred_drive), %ecx
jnz 4f /* error */
movl $0xfe, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
movl %edi, ABS(preferred_drive)
jmp 1b
3:
/* check --preferred-partition= */
movl $22, %ecx
movl $ABS(option_preferred_partition), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xff, ABS(preferred_partition)
movl $ABS(msg_option_preferred_partition), %ecx
jnz 4f /* error */
movl $0xfe, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
movl %edi, ABS(preferred_partition)
jmp 1b
3:
/* check --serial-number= */
movl $16, %ecx
movl $ABS(option_serial_number), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(serial_number)
movl $ABS(msg_option_serial_number), %ecx
jnz 4f /* error */
movl $0xffffffff, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
cmpl $0, %edi
je 4f /* error */
movl %edi, ABS(serial_number)
jmp 1b
3:
/* check --time-out= */
movl $11, %ecx
movl $ABS(option_time_out), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffff05, ABS(time_out)
movl $ABS(msg_option_time_out), %ecx
jnz 4f /* error */
movl $0xff, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
movl %edi, ABS(time_out)
jmp 1b
3:
/* check --hot-key= */
movl $10, %ecx
movl $ABS(option_hot_key), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffff3920, ABS(hot_key)
movl $ABS(msg_option_hot_key), %ecx
jnz 4f /* error */
movl $0xffff, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
movl %edi, ABS(hot_key)
jmp 1b
3:
/* check --install-partition= */
movl $20, %ecx
movl $ABS(option_install_partition), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffffff, ABS(install_partition)
movl $ABS(msg_option_install_partition), %ecx
jnz 4f /* error */
movl $0xffff, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
movl %edi, ABS(install_partition)
jmp 1b
3:
/* check --sectors-per-track= */
movl $20, %ecx
movl $ABS(option_sectors_per_track), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffff3f, ABS(sectors_per_track)
movl $ABS(msg_option_sectors_per_track), %ecx
jnz 4f /* error */
movl $0x3f, %ebx # maximum is 63
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
cmpl $0, %edi
je 4f /* error */
movl %edi, ABS(sectors_per_track)
jmp 1b
3:
/* check --heads= */
movl $8, %ecx
movl $ABS(option_heads), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffff00ff, ABS(heads)
movl $ABS(msg_option_heads), %ecx
jnz 4f /* error */
movl $0x100, %ebx # maximum is 256
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
cmpl $0, %edi
je 4f /* error */
movl %edi, ABS(heads)
jmp 1b
3:
/* check --start-sector= */
movl $15, %ecx
movl $ABS(option_start_sector), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffffff, ABS(start_sector)
movl $ABS(msg_option_start_sector), %ecx
jnz 4f /* error */
movl $0xfffffffe, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
movl %edi, ABS(start_sector)
jmp 1b
3:
/* check --total-sectors= */
movl $16, %ecx
movl $ABS(option_total_sectors), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0, ABS(total_sectors)
movl $ABS(msg_option_total_sectors), %ecx
jnz 4f /* error */
movl $0xffffffff, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
cmpl $0, %edi
je 4f /* error */
movl %edi, ABS(total_sectors)
jmp 1b
3:
/* check --floppy= */
movl $9, %ecx
movl $ABS(option_floppy_partition), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffffff, ABS(floppy)
movl $ABS(msg_option_floppy), %ecx
jnz 4f /* error */
movl $0xfe, %ebx
call 7f /* parse_number */
movl %ebx, %edi # save EBX to EDI
movl $0, %ebx # invalid file descriptor for CLOSE below
movl $ABS(msg_invalid_number), %ecx
jc 4f /* error */
movl %edi, ABS(floppy)
jmp 1b
3:
/* check --floppy */
movl $9, %ecx
movl $ABS(option_floppy), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffffff, ABS(floppy)
movl $ABS(msg_option_floppy), %ecx
jnz 4f /* error */
movl $0xff, ABS(floppy)
jmp 1b
3:
/* check --lba */
movl $6, %ecx
movl $ABS(option_lba), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffffff, ABS(lba)
movl $ABS(msg_option_lba), %ecx
jnz 4f /* error */
movl $1, ABS(lba)
jmp 1b
3:
/* check --chs */
movl $6, %ecx
movl $ABS(option_chs), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffffff, ABS(lba)
movl $ABS(msg_option_lba), %ecx
jnz 4f /* error */
movl $0, ABS(lba)
jmp 1b
3:
/* check --fat12 */
movl $8, %ecx
movl $ABS(option_fat12), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xfffffff7, ABS(fstypes)
jnz 2f
movl $0, ABS(fstypes)
2:
orb $1, ABS(fstypes)
jmp 1b
3:
/* check --fat16 */
movl $8, %ecx
movl $ABS(option_fat16), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xfffffff7, ABS(fstypes)
jnz 2f
movl $0, ABS(fstypes)
2:
orb $2, ABS(fstypes)
jmp 1b
3:
/* check --fat32 */
movl $8, %ecx
movl $ABS(option_fat32), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xfffffff7, ABS(fstypes)
jnz 2f
movl $0, ABS(fstypes)
2:
orb $4, ABS(fstypes)
jmp 1b
3:
/* check --ntfs */
movl $7, %ecx
movl $ABS(option_ntfs), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xfffffff7, ABS(fstypes)
jnz 2f
movl $0, ABS(fstypes)
2:
orb $8, ABS(fstypes)
jmp 1b
3:
/* check --ext2 */
movl $7, %ecx
movl $ABS(option_ext2), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xfffffff7, ABS(fstypes)
jnz 2f
movl $0, ABS(fstypes)
2:
orb $0x10, ABS(fstypes)
jmp 1b
3:
/* check --vfat */
movl $7, %ecx
movl $ABS(option_vfat), %esi
movl %ebx, %edi
cld
repz cmpsb
jnz 3f
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xfffffff7, ABS(fstypes)
jnz 2f
movl $0, ABS(fstypes)
2:
orb $7, ABS(fstypes)
jmp 1b
3:
movl $ABS(msg_invalid_option), %ecx
jmp 4f /* error */
1:
//----------------------------------------------------------------------------
/* end of arguments */
/* ECX=EBX=0 */
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
testl %eax, %eax # filename already specified?
//cmpl $0, ABS(filename) # filename already specified?
movl $ABS(msg_no_file), %ecx
jz 4f /* error */
xchgl %eax, %ebx # move EAX to EBX
//movl ABS(filename), %ebx # move filename to EBX
/* EBX points to the pathname of the file. */
/* check if preferred_partition matches preferred_drive */
movb ABS(preferred_drive), %al
movb ABS(preferred_partition), %ah
cmpb $0xff, %al
jne 1f
movl %ebx, %edi # save EBX to EDI
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpb $0xff, %ah
movl $ABS(msg_partition_without_drive), %ecx
jne 4f /* error */
movl %edi, %ebx # restore EBX from EDI
1:
/* EBX points to the pathname of the file. */
movl %ebx, %edi # save EBX to EDI
xorl %ebx, %ebx # invalid file descriptor for CLOSE below
cmpl $0xffffffff, ABS(floppy)
je 1f # --floppy is not specified
/* if --floppy is specified, should not specify the options for MBR. */
cmpl $1, ABS(backup_mbr)
movl $ABS(msg_option_backup_mbr_with_floppy), %ecx
jnz 4f /* error */
cmpl $0, ABS(mbr_floppy)
movl $ABS(msg_option_mbr_floppy_with_floppy), %ecx
jnz 4f /* error */
cmpl $0, ABS(mbr_osbr)
movl $ABS(msg_option_mbr_osbr_with_floppy), %ecx
jnz 4f /* error */
cmpl $0, ABS(mbr_bpb)
movl $ABS(msg_option_mbr_bpb_with_floppy), %ecx
jnz 4f /* error */
cmpl $0, ABS(duce)
movl $ABS(msg_option_duce_with_floppy), %ecx
jnz 4f /* error */
cmpl $0, ABS(boot_prevmbr)
movl $ABS(msg_option_boot_prevmbr_with_floppy), %ecx
jnz 4f /* error */
cmpl $0xff, ABS(preferred_drive)
movl $ABS(msg_option_preferred_drive_with_floppy), %ecx
jnz 4f /* error */
cmpl $0xff, ABS(preferred_partition)
movl $ABS(msg_option_preferred_partition_with_floppy), %ecx
jnz 4f /* error */
cmpl $0, ABS(serial_number)
movl $ABS(msg_option_serial_number_with_floppy), %ecx
jnz 4f /* error */
cmpl $0xffffffff, ABS(install_partition)
movl $ABS(msg_option_install_partition_with_floppy), %ecx
jnz 4f /* error */
cmpl $0xffffff05, ABS(time_out)
movl $ABS(msg_option_time_out_with_floppy), %ecx
jnz 4f /* error */
cmpl $0xffff3920, ABS(hot_key)
movl $ABS(msg_option_hot_key_with_floppy), %ecx
jnz 4f /* error */
/* for a floppy, start_sector should be 0, and
* for a partition, start_sector should be non-zero
*/
cmpl $0xff, ABS(floppy)
je 2f # a real floppy
/* a single partition */
cmpl $0, ABS(start_sector)
movl $ABS(msg_partition_start), %ecx
jz 4f /* error */
jmp 3f
2:
/* a real floppy */
/* */
cmpl $0xffffffff, ABS(start_sector)
je 3f
cmpl $0, ABS(start_sector)
movl $ABS(msg_floppy_start), %ecx
jnz 4f /* error */
3:
jmp 2f
1:
/* EBX=0 */
cmpl $0xffffffff, ABS(install_partition)
je 1f # --install-partition is not specified
/* should not specify --install-partition with options for MBR. */
cmpl $1, ABS(backup_mbr)
movl $ABS(msg_option_backup_mbr_with_partition), %ecx
jnz 4f /* error */
cmpl $0, ABS(mbr_floppy)
movl $ABS(msg_option_mbr_floppy_with_partition), %ecx
jnz 4f /* error */
cmpl $0, ABS(mbr_osbr)
movl $ABS(msg_option_mbr_osbr_with_partition), %ecx
jnz 4f /* error */
cmpl $0, ABS(mbr_bpb)
movl $ABS(msg_option_mbr_bpb_with_partition), %ecx
jnz 4f /* error */
cmpl $0, ABS(duce)
movl $ABS(msg_option_duce_with_partition), %ecx
jnz 4f /* error */
cmpl $0, ABS(boot_prevmbr)
movl $ABS(msg_option_boot_prevmbr_with_partition), %ecx
jnz 4f /* error */
cmpl $0xff, ABS(preferred_drive)
movl $ABS(msg_option_preferred_drive_with_partition), %ecx
jnz 4f /* error */
cmpl $0xff, ABS(preferred_partition)
movl $ABS(msg_option_preferred_partition_with_partition), %ecx
jnz 4f /* error */
cmpl $0, ABS(serial_number)
movl $ABS(msg_option_serial_number_with_partition), %ecx
jnz 4f /* error */
cmpl $0xffffff05, ABS(time_out)
movl $ABS(msg_option_time_out_with_partition), %ecx
jnz 4f /* error */
cmpl $0xffff3920, ABS(hot_key)
movl $ABS(msg_option_hot_key_with_partition), %ecx
jnz 4f /* error */
cmpl $0xffffff3f, ABS(sectors_per_track)
movl $ABS(msg_option_sectors_per_track_with_partition), %ecx
jnz 4f /* error */
cmpl $0xffff00ff, ABS(heads)
movl $ABS(msg_option_heads_with_partition), %ecx
jnz 4f /* error */
cmpl $0xffffffff, ABS(start_sector)
movl $ABS(msg_option_start_sector_with_partition), %ecx
jnz 4f /* error */
cmpl $0, ABS(total_sectors)
movl $ABS(msg_option_total_sectors_with_partition), %ecx
jnz 4f /* error */
jmp 2f
1:
/* EBX=0 */
/* this is an MBR device. Should not specify floppy-specific options. */
// testl $1, ABS(boot_prevmbr) /* --boot-prevmbr-first specified? */
// jnz 2f /* Yes, specified. Continue */
// /* No, not specified. */
// /* Should not specify --time-out without --boot-prevmbr-first. */
// cmpl $0xffffff05, ABS(time_out)
// movl $ABS(msg_option_time_out_without_prevmbr), %ecx
// jne 4f /* error */
//
// /* Should not specify --hot-key without --boot-prevmbr-first. */
// cmpl $0xffff3920, ABS(hot_key)
// movl $ABS(msg_option_hot_key_without_prevmbr), %ecx
// jne 4f /* error */
2:
/* EBX=0, EDI points to the pathname of the file. */
//----------------------------------------------------------------------------
movl %edi, %ebx # restore EBX from EDI
/* EBX=EDI points to the pathname of the file. */
#ifdef __DOS_16
xorl %eax, %eax
//movl %ebx, %edi /* EBX points to the pathname of the file. */
movl $0xfe, %ebx
call 7f /* parse_number */
jc 2f /* invalid number */
/* EBX holds the bios drive number */
movl %ebx, ABS(bios_drive_number)
jmp 1f
2:
//AH = 3Dh //OPEN EXISTING FILE
//AL = access and sharing modes (see #01402)
//DS:DX -> ASCIZ filename
//CL = attribute mask of files to look for (server call only)
//Return:
//CF clear if successful AX = file handle
//CF set on error AX = error code (01h,02h,03h,04h,05h,0Ch,56h)
movzbl ABS(read_only), %eax
movb $0x3d, %ah // open file for read/write
movl %edi, %edx // DS:DX points to ASCIZ filename
int $0x21
jnc 1f
negl %eax /* EAX < 0 */
1:
#else
/* int open(const char *pathname, int flags, mode_t mode) */
movl $5, %eax // sys_open
movzbl ABS(read_only), %ecx // O_RDWR = 02
int $0x80
#endif
xorl %ebx, %ebx // invalid file descriptor for CLOSE below
movl $ABS(msg_open_file_rw), %ecx
cmpw $2, ABS(read_only)
je 1f
movl $ABS(msg_open_file_ro), %ecx
1:
testl %eax, %eax
js 4f /* error */
//----------------------------------------------------------------------------
/* open file succeeded */
#ifdef __DOS_16
#undef PRE
#define PRE(x) %x:
#undef ABS
#define ABS(x) (x - _start + 0x100)
#undef MBR
#define MBR(x) (x)
#else
#undef PRE
#define PRE(x)
#undef ABS
#define ABS(x) (x)
#undef MBR
#define MBR(x) (mbr_63_sectors + x)
#endif
pushl %eax // file descriptor, or 0 for BIOS drive
movl %eax, %ebx
/* EBX and the stack holds the file descriptor number or 0 */
#ifdef __DOS_16
/* check if there is 64K available for mbr_63_sectors and stack. */
xorw %ax, %ax
movw %ax, %ds
movw 0x413, %ax /* low memory in KBytes */
shlw $6, %ax /* low memory in paragraphs */
movw %cs, %cx
movw %cx, %ds
addw $0x2000, %cx
cmpw %ax, %cx
movl $ABS(msg_no_enough_memory), %ecx
ja 4f
/* move stack to next 64K to avoid memory conflict. */
movw %cs, %ax
addw $0x1000, %ax
movw %ax, %ss
movw %ax, %ds
movw %ax, %es
popl %eax // dummy pop
pushl %ebx // file descriptor, or 0 for BIOS drive
xorl %eax, %eax
cmpl $0xff, PRE(cs)ABS(bios_drive_number)
je 1f
xchgw %ax, %bx // BX=0
movw $0x204, %ax // read 4 sectors of the MBR
movw $1, %cx
movb PRE(cs)ABS(bios_drive_number), %dl
movb $0, %dh
int $0x13
movzwl %ax, %eax
movw %ss, %cx
movw %cx, %ds
movw %cx, %es
jc 2f // stop on error
movw %ss, %ax
movw %ax, %ds
movw %ax, %es
movw $0x7E00, %bx
movw $1, %cx
movb PRE(cs)ABS(bios_drive_number), %dl
movb $1, %dh
movw $0x201, %ax // read 1 sector of track 1(the 2nd track)
int $0x13
movzwl %ax, %eax
movw %ss, %cx
movw %cx, %ds
movw %cx, %es
clc // ignore error
jmp 2f
1:
//READ FROM FILE OR DEVICE
//AH = 3Fh
//BX = file handle
//CX = number of bytes to read
//DS:DX -> buffer for data
//Return:
//CF clear if successful AX = number of bytes actually read (0 if at EOF before call)
//CF set on error AX = error code (05h,06h)
xchgw %ax, %dx // DX=0
movw $0x3f00, %ax
movw $((63+1)*512), %cx
//movl $MBR(0), %edx
int $0x21
2:
jnc 1f
negl %eax
1:
#else
/* ssize_t read(int fd, void *buf, size_t count) */
movl $3, %eax // sys_read
movl $MBR(0), %ecx
movl $((63+1)*512), %edx // read 63+1 sectors
int $0x80
#endif
popl %ebx // file descriptor, or 0 for BIOS drive
testl %eax, %eax
movl $ABS(msg_read_file), %ecx
js 4f /* error */
//----------------------------------------------------------------------------
/* rewind the file for write! important! */
pushl %ebx // file descriptor, or 0 for BIOS drive
#ifdef __DOS_16
xorl %eax, %eax
cmpl $0xff, PRE(cs)ABS(bios_drive_number)
jne 1f
//LSEEK - SET CURRENT FILE POSITION
//AH = 42h
//AL = origin of move
// 00h start of file
// 01h current file position
// 02h end of file
//BX = file handle
//CX:DX = (signed) offset from origin of new file position
//Return:
//CF clear if successful DX:AX = new file position in bytes from start of file
//CF set on error AX = error code (01h,06h)
movl $0x4200, %eax
movl $0, %ecx
movl $0, %edx
int $0x21
jnc 1f
negl %eax
1:
#else
/* off_t lseek(int fildes, off_t offset, int whence) */
movl $19, %eax // sys_lseek
movl $0, %ecx
movl $0, %edx // SEEK_SET = 0
int $0x80
#endif
popl %ebx // file descriptor, or 0 for BIOS drive
testl %eax, %eax
movl $ABS(msg_lseek_file), %ecx
js 4f /* error */
//----------------------------------------------------------------------------
/* remember EBX holds file descriptor number, and don't touch it */
/* check if the partition table is valid. */
#ifdef __DOS_16
xorl %esi, %esi
#else
movl $MBR(0), %esi
#endif
cmpw $0xAA55, 0x1fe(iSI)
movl $ABS(msg_boot_signature_mbr), %ecx
//jne 4f /* error */
clc
jne 2f
call 9f /* probe_geometry */
jnc 1f
2:
/* should be floppy since no partition table or no boot signature. */
/* CF=0 means no boot signature, CF=1 means no partition table. */
jnc 2f
movl $ABS(msg_invalid_partition_table), %ecx
2:
cmpl $0xffffffff, PRE(cs)ABS(floppy) /* Is --floppy specified? */
je 4f /* error */
/* Yes, --floppy is specified */
/* ESI points to MBR(0) */
call 5f /* floppy routine */
movl $0, %ecx
jc 4f /* error */
jmp 2f /* write file */
1:
//----------------------------------------------------------------------------
/* the image type is MBR. So, should not specify --floppy */
cmpl $0xffffffff, PRE(cs)ABS(floppy) /* Is --floppy specified? */
movl $ABS(msg_floppy_partition_table), %ecx
jne 4f /* error */
cmpl $0xffffff3f, PRE(cs)ABS(sectors_per_track)
movl $ABS(msg_option_sectors_per_track_for_mbr), %ecx
jnz 4f /* error */
cmpl $0xffff00ff, PRE(cs)ABS(heads)
movl $ABS(msg_option_heads_for_mbr), %ecx
jnz 4f /* error */
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
movl $ABS(msg_option_start_sector_for_mbr), %ecx
jnz 4f /* error */
cmpl $0, PRE(cs)ABS(total_sectors)
movl $ABS(msg_option_total_sectors_for_mbr), %ecx
jnz 4f /* error */
cmpl $0xffffffff, PRE(cs)ABS(lba)
movl $ABS(msg_option_lba_for_mbr), %ecx
jnz 4f /* error */
cmpl $0xfffffff7, PRE(cs)ABS(fstypes)
movl $ABS(msg_option_fstypes_for_mbr), %ecx
jnz 4f /* error */
cmpl $((pre_stage2_start - _start1) / 512), PRE(cs)ABS(mbr_free_sectors)
movl $ABS(msg_sectors_per_track), %ecx
jb 4f /* error */
cmpl $0xffffffff, PRE(cs)ABS(install_partition)
movl $ABS(msg_option_install_partition_not_implemented), %ecx
je 1f
jmp 4f /* error */
/* EBX holds the file descriptor number or 0 if it is BIOS drive */
/* move partition table forward to the beginning of the 17th sector */
movl $MBR(0x01be), %esi
movl $MBR(0x2000), %edi
movl $0x10, %ecx # 0x10 dwords = 0x40 bytes
cld
repz movsl
/* initialize the current_partition number */
movzbl PRE(cs)ABS(install_partition), %eax
movl %eax, PRE(cs)ABS(current_partition)
3:
/* load the next partition and modify the boot record */
call 0f /* partition */
jc 3f /* done */
call 2f /* write to file */
incl PRE(cs)ABS(current_partition)
movw PRE(cs)ABS(install_partition), %ax
addb %ah, %al /* Max partition number for install */
cmpb %al, PRE(cs)ABS(current_partition)
jbe 3b
3:
/* all partitions have been installed. */
xorl %eax, %eax # exit code = 0
#ifdef __DOS_16
movb $0x4c, %ah // EXIT - TERMINATE WITH RETURN CODE in AL
int $0x21 // call DOS
#else
xchgl %eax, %ebx # move exit code in EAX to EBX
movl $1, %eax # sys_exit
int $0x80
#endif
ret
1:
//----------------------------------------------------------------------------
/* restore mbr */
testb $1, PRE(cs)ABS(restore_mbr)
jz 1f
/* check if previous mbr is valid. */
#ifdef __DOS_16
xorl %esi, %esi
movw $0x200, %si
#else
movl $MBR(0x200), %esi /* point to 2nd sector */
#endif
cmpw $0xAA55, 0x1fe(iSI)
movl $ABS(msg_invalid_prev_mbr), %ecx
jnz 4f /* error */
call 9f /* probe_geometry */
movl $ABS(msg_invalid_prev_mbr), %ecx
jc 4f /* error */
/* check if previous mbr is grldr */
/* 2nd is not empty. if it is grldr, consider it is empty */
movb $0xBB, %al
#ifdef __DOS_16
xorl %edi, %edi
movw $0x260, %di
#else
movl $MBR(0x260), %edi // in 2nd sector
#endif
movl $0x150, %ecx
cld
repnz scasb
jnz 3f // 2nd is not grldr, restore it
cmpl $0xB8661FFC, (%edi)
movl $ABS(msg_invalid_prev_mbr), %ecx
jz 4f /* error */
3:
/* copy byte 0000 to 01b7 in 2nd sector to 1st sector */
#ifdef __DOS_16
movl $0x200, %esi /* point to 2nd sector */
xorl %edi, %edi
#else
movl $MBR(0x200), %esi /* point to 2nd sector */
movl $MBR(0), %edi
#endif
movl $0x6e, %ecx // 0x6e dwords = 0x1b8 bytes
cld
repz movsl
movl $1, PRE(cs)ABS(sectors_to_write)
/* completed. write file. */
jmp 2f
1:
/* backup mbr */
/* auto backup */
cmpl $1, PRE(cs)ABS(backup_mbr)
jnz 1f
/* check if the second sector begins in 106 dups of one byte */
#ifdef __DOS_16
movb 0x200, %al
movl $0x200, %edi
#else
movb MBR(0x200), %al
movl $MBR(0x200), %edi
#endif
movl $0x6A, %ecx // 0x6A=106
cld
repz scasb
jz 10f // the second sector is empty.
/* 2nd is not empty. if it is grldr, consider it is empty */
movb $0xBB, %al
#ifdef __DOS_16
xorl %edi, %edi
movw $0x260, %di
#else
movl $MBR(0x260), %edi // in 2nd sector
#endif
movl $0x150, %ecx
cld
repnz scasb
jnz 3f # 2nd is not grldr, do not overwrite it
cmpl $0xB8661FFC, (%edi)
jnz 3f # 2nd is not grldr, do not overwrite it
10:
/* 2nd is empty. but if MBR is grldr, we still skip the backup. */
movb $0xBB, %al
movl $MBR(0x60), %edi // in 1st sector
movl $0x150, %ecx
cld
repnz scasb
jnz 1f # MBR is not grldr, enable backup
cmpl $0xB8661FFC, (%edi)
jz 3f # MBR is grldr, do not backup
1:
//----------------------------------------------------------------------------
cmpl $0, PRE(cs)ABS(backup_mbr)
jz 3f # will not backup
#ifdef __DOS_16
xorl %esi, %esi
movl $0x200, %edi
#else
movl $MBR(0), %esi
movl $MBR(0x200), %edi
#endif
movl $0x80, %ecx # 0x80 dwords = 0x200 bytes
cld
repz movsl
3:
//----------------------------------------------------------------------------
/* copy byte 0000 to 01b7 of grldr.mbr to MBR(0) */
movl $ABS(_start1), %esi
#ifdef __DOS_16
xorl %edi, %edi
#else
movl $MBR(0), %edi
#endif
movl $0x6e, %ecx # 0x6e dwords = 0x1b8 bytes
cld
#ifdef __DOS_16
cs repz movsl
#else
repz movsl
#endif
/* locate the BPB sector */
#ifdef __DOS_16
testb $1, PRE(cs)ABS(mbr_bpb)
jnz 1f /* mbr disable bpb */
testl %ebx, %ebx
jnz 1f
/* BIOS drive. Need to load all 64 sectors. */
/* first, try EBIOS */
movb $0x41, %ah
movw $0x55AA, %bx
int $0x13
movw %ss, %ax
movw %ax, %ds
movw %ax, %es
jc 3f /* No EBIOS */
cmpw $0xAA55, %bx
jne 3f /* No EBIOS */
testb $1, %cl
jz 3f /* No EBIOS */
/* EBIOS supported */
pushl $0 // hi 32bit of startLBA
pushl $4 // startLBA=4
pushw %es // buffer segment
pushw $0x800 // buffer offset
pushw $0x003C // sectors=60
pushw $0x0010 // packet length
movw %sp, %si
int $0x13
movw %ss, %ax
movw %ax, %ds
movw %ax, %es
addw $16, %sp
movl $0, %ebx
jnc 1f
3:
/* second, try BIOS with a single cross-track read. */
movw $0x23C, %ax // read 60 sectors in the MBR track
movw $0x800, %bx // skip 4 sectors
movw $5, %cx // skip 4 sectors to load sector 5
movb PRE(cs)ABS(bios_drive_number), %dl
movb $0, %dh
int $0x13
movw %ss, %ax
movw %ax, %ds
movw %ax, %es
movl $0, %ebx
jnc 1f
/* third, try normal BIOS read track by track */
movl $0x3B, %ecx
3:
pushl %ecx
movw $0x200, %ax // read sectors
addw %cx, %ax
movw $0x800, %bx // skip 4 sectors
movw $5, %cx // skip 4 sectors to load sector 5
movb PRE(cs)ABS(bios_drive_number), %dl
movb $0, %dh
int $0x13
movw %ss, %ax
movw %ax, %ds
movw %ax, %es
popl %ecx
jnc 3f
loop 3b
3:
/* CX + 4 = sectors per track */
addw $4, %cx
cmpw $32, %cx
movl $0, %ebx
jb 1f
movw $0x240, %ax // read sectors
subw %cx, %ax
movw %cx, %bx
shlw $9, %bx
movw $1, %cx // load sector 1
movb PRE(cs)ABS(bios_drive_number), %dl
movb $1, %dh // head 1
int $0x13
movw %ss, %ax
movw %ax, %ds
movw %ax, %es
movl $0, %ebx
/* ignore error */
1:
#endif
/* find a minimum StartLBA in the partition table. */
#if 0
movl $MBR(0x1c6), %esi
movl $64, %eax
movl (iSI), %ecx
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
movl 16(iSI), %ecx
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
movl 32(iSI), %ecx
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
movl 48(iSI), %ecx
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
#endif
testb $1, PRE(cs)ABS(mbr_bpb)
jnz 1f /* mbr disable bpb */
movl PRE(cs)ABS(mbr_free_sectors), %eax
movl %eax, %esi
cmpl $63, %eax
ja 1f /* too many sectors before partition */
cmpl $18, %eax
jb 1f /* too few sectors before partition */
shll $9, %esi
#ifndef __DOS_16
addl $MBR(0), %esi
#endif
/* ESI points to BPB sector */
/* check if it has a valid FAT BPB */
cmpw $512, 0x0B(iSI) // bytes per sector
jne 1f
cmpl %eax, 0x1C(iSI) // hidden sectors
jne 1f
movw 0x18(iSI), %ax // sectors per track
decw %ax
cmpw $62, %ax
ja 1f
movw 0x1A(iSI), %ax // heads
decw %ax
cmpw $255, %ax
ja 1f
movb 0x0D(iSI), %cl // sectors per cluster
testb %cl, %cl
jz 1f
movw $128, %ax
divb %cl
testb %ah, %ah
jnz 1f
movw 0x0E(iSI), %cx // reserved sectors
jcxz 1f
movb 0x10(iSI), %al // number of FATs
decw %ax
cmpb $1, %al
ja 1f
movb 0x15(iSI), %al // media descriptor
cmpb $0xF0, %al
jb 1f
/* copy the BPB to MBR(0) */
addl $0x0B, %esi
#ifdef __DOS_16
pushw %ss
popw %es
movl $0x0B, %edi
#else
movl $MBR(0x0B), %edi
#endif
movl $(0x5A - 0x0B), %ecx
cld
repz movsb
/* modify reserved sectors */
#ifdef __DOS_16
xorl %esi, %esi
#else
movl $MBR(0), %esi
#endif
movl 0x1C(iSI), %eax #; EAX=sectors per track
addw %ax, 0x0E(iSI)
/* modify total sectors word */
movw 0x13(iSI), %ax #; EAX hi word = 0
testw %ax, %ax
jz 3f
addw 0x1C(iSI), %ax
movw %ax, 0x13(iSI)
3:
/* modify total sectors dword */
movl 0x20(iSI), %eax
testl %eax, %eax
jz 3f
addl 0x1C(iSI), %eax
movl %eax, 0x20(iSI)
3:
/* clear the hidden sectors */
xorl %eax, %eax
movl %eax, 0x1C(iSI)
1:
/* modify PRE(cs)ABS(mbr_floppy) bit */
movb PRE(cs)ABS(mbr_floppy), %al
andb $0x01, %al
movb %al, MBR(2)
/* modify PRE(cs)ABS(mbr_osbr) bit */
movb PRE(cs)ABS(mbr_osbr), %al
andb $0x01, %al
shlb $1, %al
orb %al, MBR(2)
/* modify PRE(cs)ABS(duce) bit */
movb PRE(cs)ABS(duce), %al
andb $0x01, %al
shlb $2, %al
orb %al, MBR(2)
/* modify PRE(cs)ABS(boot_prevmbr) bit */
movb PRE(cs)ABS(boot_prevmbr), %al
notb %al
andb $0x01, %al
rorb $1, %al
orb %al, MBR(2)
/* modify PRE(cs)ABS(time_out) byte */
movb PRE(cs)ABS(time_out), %al
movb %al, MBR(3)
/* modify PRE(cs)ABS(hot_key) byte */
movw PRE(cs)ABS(hot_key), %ax
movw %ax, MBR(4)
/* modify PRE(cs)ABS(preferred_drive) byte */
movb PRE(cs)ABS(preferred_drive), %al
movb %al, MBR(6)
/* modify PRE(cs)ABS(preferred_partition) byte */
movb PRE(cs)ABS(preferred_partition), %al
movb %al, MBR(7)
/* modify disk serial number */
movl PRE(cs)ABS(serial_number), %eax
testl %eax, %eax
jz 1f
xorl %edi, %edi
movw PRE(cs)ABS(_start1 + 0x1FF8), %di
#ifndef __DOS_16
addl $MBR(0), %edi /* in the 1st sector */
#endif
stosl
movl %eax, PRE(cs)ABS(_start1 + 0x1FFC) /* in the 16th sector */
1:
/* copy byte 0400 and the rest of grldr.mbr to MBR(0) */
movl $ABS(_start1 + 0x400), %esi
movl $MBR(0x400), %edi
movl $((pre_stage2_start - _start1 - 0x400) / 4), %ecx
cld
#ifdef __DOS_16
cs repz movsl
#else
repz movsl
#endif
//----------------------------------------------------------------------------
2: /* label for the above floppy code to jump */
/* OK. Now write file! */
xorl %eax, %eax
cmpw $2, PRE(cs)ABS(read_only)
jne 3f
pushl %ebx # file descriptor, or 0 if specified BIOS drive
/* for safety, don't write too many sectors */
cmpl $0xffffffff, PRE(cs)ABS(install_partition)
jne 1f
cmpl $0xffffffff, PRE(cs)ABS(floppy)
je 2f
1:
cmpl $4, PRE(cs)ABS(sectors_to_write)
jbe 1f
movl $4, PRE(cs)ABS(sectors_to_write)
jmp 1f
2:
cmpl $((pre_stage2_start - _start1) / 512), PRE(cs)ABS(sectors_to_write)
jbe 1f
movl $((pre_stage2_start - _start1) / 512), PRE(cs)ABS(sectors_to_write)
1:
#ifdef __DOS_16
xorl %eax, %eax
cmpl $0xff, PRE(cs)ABS(bios_drive_number)
je 1f
movb $0x03, %ah // write to disk
movb PRE(cs)ABS(sectors_to_write), %al
// cmpl $0xffffffff, PRE(cs)ABS(floppy)
// je 2f
// movb $4, %al # write 4 sectors if it is floppy
//2:
movw $0, %bx
movw $1, %cx
movw PRE(cs)ABS(bios_drive_number), %dx
int $0x13
movzwl %ax, %eax
movw %ss, %cx
movw %cx, %ds
movw %cx, %es
jmp 2f
1:
//WRITE TO FILE OR DEVICE
//AH = 40h
//BX = file handle
//CX = number of bytes to write
//DS:DX -> data to write
//Return:
//CF clear if successful AX = number of bytes actually written
//CF set on error AX = error code (05h,06h)
movl $0x4000, %eax
movl PRE(cs)ABS(sectors_to_write), %ecx
shll $9, %ecx
//movl $(pre_stage2_start - _start1), %ecx
// cmpl $0xffffffff, PRE(cs)ABS(floppy)
// je 1f
// movl $0x800, %ecx # write 4 sectors if it is floppy
//1:
movl $0, %edx
int $0x21
2:
jnc 1f
negl %eax
1:
#else
/* ssize_t write(int fd, const void *buf, size_t count) */
movl $4, %eax # sys_write
movl $MBR(0), %ecx
movl PRE(cs)ABS(sectors_to_write), %edx
shll $9, %edx
//movl $(pre_stage2_start - _start1), %edx # length of grldr.mbr
// cmpl $0xffffffff, PRE(cs)ABS(floppy)
// je 1f
// movl $0x800, %edx # write 4 sectors if it is floppy
//1:
int $0x80
#endif
popl %ebx # file descriptor, or 0 if specified BIOS drive
3:
cmpl $0xffffffff, PRE(cs)ABS(install_partition)
je 3f
/* for install_partition, SF=0 when success, SF=1 when failure */
testl %eax, %eax
ret
3:
testl %eax, %eax
movl $ABS(msg_write_file), %ecx
js 4f /* error */
//----------------------------------------------------------------------------
cmpl $0xffffffff, PRE(cs)ABS(floppy)
jne 3f
cmpl $0, PRE(cs)ABS(probed_sectors_per_track)
je 2f
cmpl $0, PRE(cs)ABS(probed_heads)
je 2f
movl $ABS(msg_geometry_S), %ecx
call 8f /* linux_print */
movl PRE(cs)ABS(probed_sectors_per_track), %eax
call 6f /* print decimal number */
movl $ABS(msg_geometry_H), %ecx
call 8f /* linux_print */
movl PRE(cs)ABS(probed_heads), %eax
call 6f /* print decimal number */
2:
movl $ABS(msg_success), %ecx
call 8f /* linux_print */
3:
//success:
# EBX=file descriptor, or 0 if specified BIOS drive
xorl %eax, %eax # exit code = 0
jmp 1f
//error:
4:
# EBX=file descriptor, or 0 if specified BIOS drive
testl %ecx, %ecx
jz 2f
call 8f /* linux_print */
2:
movl $ABS(msg_usage), %ecx
call 8f /* linux_print */
movl $1, %eax # exit code = 1
1:
testl %ebx, %ebx
jz 1f
pushl %eax # exit code
#ifdef __DOS_16
movb $0x3e, %ah // close file (BX = file handle)
int $0x21
jnc 2f
negl %eax /* EAX < 0 */
2:
#else
/* int close(int fd); */
movl $6, %eax # sys_close
int $0x80
#endif
movl $ABS(msg_close_file), %ecx
testl %eax, %eax
popl %eax # exit code
jns 1f
call 8f /* linux_print */
//exit:
1:
#ifdef __DOS_16
movb $0x4c, %ah // EXIT - TERMINATE WITH RETURN CODE in AL
int $0x21 // call DOS
#else
xchgl %eax, %ebx # move exit code in EAX to EBX
movl $1, %eax # sys_exit
int $0x80
#endif
ret
//----------------------------------------------------------------------------
//floppy:
5:
pushal
/* Beforehand, try MBR */
/* ESI=$MBR(0) */
cld
cmpw $0xAA55, 0x1fe(iSI)
jne 1f
pushl %esi
pushl %edi
pushl %ebx
/* has a valid partition table ? */
movb $0, %bl /* count valid partition entries */
addl $0x1be, %esi
3:
cmpl $MBR(0x1fe), %esi
jnb 3f /* partition table is OK */
movl $4, %ecx
movl %esi, %edi
2:
lodsl
negl %eax
jc 2f
loop 2b
/* empty entry, check next */
jmp 3b
2:
/* non-empty entry */
movl %edi, %esi
lodsw
shlb $1, %al /* boot indicator */
jnz 2f
lodsw
andb $63, %al
jz 2f
lodsw
lodsw
andb $63, %al
jz 2f
lodsl
negl %eax
jnc 2f
lodsl
negl %eax
jnc 2f
incb %bl
jmp 3b
2:
stc /* invalid partition table */
3:
popl %eax
popl %edi
popl %esi
xchgl %eax, %ebx
jc 1f
testb %al, %al
jz 1f
/* MBR write not allowed */
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_mbr_deny), %ecx
call 8f /* linux_print */
stc
popal
ret
1:
/* First, try ext2 */
cmpw $0xEF53, 0x438(iSI) /* Magic signature */
jnz 1f
xorl %eax, %eax
cmpl %eax, 0x400(iSI) /* s_inodes_count */
jz 1f
cmpl %eax, 0x404(iSI) /* s_blocks_count */
jz 1f
// cmpw %ax, 0x458(iSI) /* s_inode_size, usually 0x80 */
// jz 1f
cmpl %eax, 0x420(iSI) /* s_blocks_per_group */
jz 1f
cmpl %eax, 0x428(iSI) /* s_inodes_per_group */
jz 1f
movl 0x414(iSI), %eax /* s_first_data_block */
movw %ax, %bx /* BX=1 for 1K block, 0 otherwise */
shrl $1, %eax /* must be 0 */
jnz 1f
movl 0x418(iSI), %ecx /* s_log_block_size */
cmpl $4, %ecx /* max size of block is 16K */
ja 1f
negw %cx /* CF=0 for 1K block, CF=1 otherwise */
adcw %ax, %bx /* EAX=0 */
decw %bx
jnz 1f
/* BX = 0 */
movl $ABS(_start1 + 0x826), %edi /* inode size in the 5th sector */
movw $0x80, %ax /* EXT2_GOOD_OLD_INODE_SIZE */
movw %ax, PRE(cs)(iDI) /* inode size */
movl 0x44C(iSI), %ecx /* ECX=s_rev_level */
jecxz 3f /* EXT2_GOOD_OLD_REV */
movw 0x458(iSI), %ax /* AX=s_inode_size */
testw %ax, %ax
jz 1f /* invalid inode size */
pushw %ax
pushw %dx
movb 0x418(iSI), %cl /* s_log_block_size */
addb $10, %cl
xorw %dx, %dx /* DX=0 */
incw %dx /* DX=1 */
shlw %cl, %dx /* DX=block size in bytes */
xchgw %ax, %cx /* CX=s_inode_size */
xchgw %ax, %dx /* AX=block size in bytes */
xorw %dx, %dx /* DX:AX=block size in bytes */
divw %cx /* quo=AX, rem=DX */
testw %dx, %dx
popw %dx
popw %ax
jnz 1f /* invalid inode size */
movw %ax, PRE(cs)(iDI) /* inode size */
3:
/* BX = 0 */
/* super block is sane */
/* is EXT2 allowed write? */
testl $0x10, PRE(cs)ABS(fstypes)
jnz 2f
/* EXT2 write not allowed */
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_ext2_deny), %ecx
call 8f /* linux_print */
stc
popal
ret
2:
/* write to ext2 boot area */
cld
movl $ABS(_start1 + 0x800), %esi /* points to the 5th sector */
#ifdef __DOS_16
xorl %edi, %edi
cs lodsw
#else
movl $MBR(0), %edi
lodsw PRE(cs)(iSI), %ax /* The first 2 byte: short jmp */
#endif
LEAL 0x400(%edi), %esi /* ESI points to super block */
stosw
/* lba indicator byte is not used. so we shouldn't touch it. */
/* check lba-chs-mode specified, 1 byte */
cmpl $-1, PRE(cs)ABS(lba) /* lba-chs-mode not specified? */
je 2f /* yes, do nothing. */
#if 0
movb $0x42, %al /* initialize to lba mode. */
cmpl $0, PRE(cs)ABS(lba) /* chs ? */
jnz 10f /* no, it is not chs.*/
movb $0x02, %al /* yes, it is chs. */
10:
#else
/* if specified lba or chs, we simply place a 0x90. */
movb $0x90, %al
#endif
stosb
decl %edi
2:
addl $(1+10), %edi /* skip 10-byte OEM name */
/* Sectors per block, byte */
movb 0x18(iSI), %cl /* s_log_block_size */
movl $2, %eax
shlw %cl, %ax
stosb
/* Bytes per block, word */
shlw $9, %ax /* block size is word wide */
stosw
/* Pointers covered by an indirect block, dword */
/* Pointers per block, dword */
shrw $2, %ax
pushl %eax /* Pointers per block */
addb $8, %cl
shll %cl, %eax
stosl /* Pointers covered by an indirect block */
popl %eax
stosl /* Pointers per block */
/* Sectors per track, word */
cmpl $0xFFFFFF3F, PRE(cs)ABS(sectors_per_track)
je 10f
movb PRE(cs)ABS(sectors_per_track), %al
cbw
stosw
subl $2, %edi
10:
addl $2, %edi
/* Number of heads, word */
cmpl $0xFFFF00FF, PRE(cs)ABS(heads)
je 10f
movw PRE(cs)ABS(heads), %ax
stosw
subl $2, %edi
10:
addl $2, %edi
/* hidden sectors(i.e., partition start), dword */
movb PRE(cs)ABS(floppy), %al /* partition number(0xFF for floppy) */
cmpb $0xff, %al
jne 10f
/* real floppy */
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
sete %al
movzbl %al, %eax
addl PRE(cs)ABS(start_sector), %eax
stosl
jmp 11f
10:
/* hard drive partition */
addl $4, %edi
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
je 11f
movl PRE(cs)ABS(start_sector), %eax
subl $4, %edi
stosl
11:
/* total sectors, dword */
movl %es:(iDI), %eax
cmpl %eax, PRE(cs)ABS(total_sectors)
jbe 10f
movl PRE(cs)ABS(total_sectors), %eax
10:
stosl
/* drive number, byte */
//this byte is not used.
incl %edi
/* partition number, byte */
movb PRE(cs)ABS(floppy), %al
stosb
/* reserved, word */
incl %edi
incl %edi
/* Number of inodes per group, dword */
movl 0x28(iSI), %eax /* s_inodes_per_group */
stosl
/* block number for group descriptors, dword */
movl 0x14(iSI), %eax /* s_first_data_block */
incw %ax
stosl
/* Machine code begins at offset 0x30, 462 bytes plus
* 2 bytes of boot signature */
movl $ABS(_start1 + 0x830), %esi
lodsl PRE(cs)(iSI), %eax
movb PRE(cs)ABS(floppy), %cl /* partition number(0xFF for floppy) */
cmpb $0xff, %cl
jne 10f
/* real floppy */
cmpl $0x90C031FC, %eax /* FC=cld; 31 C0=xor ax,ax; 90=nop */
jne 10f
movl $0x99C031FC, %eax /* FC=cld; 31 C0=xor ax,ax; 99=cwd */
10:
stosl
movl $((464 / 4) - 1), %ecx
repz movsl PRE(cs)(iSI), %es:(iDI)
movl $1, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_ext2_allow), %ecx
call 8f /* linux_print */
clc
popal
ret
1:
/* Secondly, try FAT12/16/32/NTFS */
cld
cmpw $0xAA55, 0x1fe(iSI) /* boot signature */
jne 1f /* not a normal BPB */
cmpw $0x200, 0x0b(iSI) /* bytes per sector */
jne 1f /* not a normal BPB */
movb 0x0d(iSI), %al /* sectors per cluster */
testb %al, %al
jz 1f /* invalid if = 0 */
movb %al, %cl
movw $128, %ax
divb %cl /* quo=AL, rem=AH */
testb %ah, %ah
jnz 1f /* invalid if not 2^n */
movw 0x18(iSI), %ax /* sectors per track */
testw %ax, %ax
jz 1f /* invalid if = 0 */
cmpw $63, %ax
ja 1f /* invalid if > 63 */
movw 0x1a(iSI), %ax /* number of heads */
decw %ax /* Max head number, should be a byte */
testb %ah, %ah /* should be 0 */
jnz 1f /* invalid if number of heads > 256 */
cmpb $0xf0, 0x15(iSI) /* media descriptor */
jb 1f
// movw $0x0600, %bx /* FAT12/FAT16 */
// movw $0x003c, %cx /* FAT12/FAT16 */
movb 0x10(iSI), %al /* number of FATs(NTFS:0, FAT:1,2) */
cmpb $2, %al
ja 1f /* abnormal FAT */
movw 0x11(iSI), %ax /* max root entries */
testw %ax, %ax
jnz 2f /* FAT12/FAT16 */
/* FAT32 or NTFS */
movw 0x13(iSI), %ax /* total sectors(small) */
testw %ax, %ax
jnz 1f /* invalid FAT32 BPB */
movw 0x16(iSI), %ax /* sectors per FAT(small) */
testw %ax, %ax
jnz 1f /* invalid FAT32 BPB */
movb 0x10(iSI), %al /* number of FATs(NTFS:0, FAT:1,2) */
testb %al, %al
jz 4f /* NTFS */
/* FAT32 */
movl 0x20(iSI), %eax /* FAT32 total sectors */
testl %eax, %eax
jz 1f
movl 0x24(iSI), %eax /* FAT32 sectors per FAT */
testl %eax, %eax
jz 1f
/* sure it is FAT32 */
/* is FAT32 allowed write? */
testl $0x04, PRE(cs)ABS(fstypes)
jnz 3f
/* FAT32 write not allowed */
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_fat32_deny), %ecx
call 8f /* linux_print */
stc
popal
ret
3:
/* write to FAT32 boot area */
cld
movl $ABS(_start1 + 0x400), %esi /* points to the 3rd sector */
#ifdef __DOS_16
xorl %edi, %edi
cs lodsw
#else
movl $MBR(0), %edi
lodsw PRE(cs)(iSI), %ax /* The first 2 byte: short jmp */
#endif
//leal 0x400(%edi), %esi /* ESI points to super block */
stosw
/* check lba-chs-mode specified, 1 byte */
cmpl $-1, PRE(cs)ABS(lba) /* lba-chs-mode not specified? */
je 3f /* yes, do nothing. */
movb $0x0e, %al /* initialize to lba mode. */
cmpl $0, PRE(cs)ABS(lba) /* chs ? */
jnz 10f /* no, it is not chs.*/
movb $0x90, %al /* yes, it is chs. */
10:
stosb
decl %edi
3:
addl $(1+8+2+1+2+1+2+2+1+2), %edi
addl $(1+8+2+1+2+1+2+2+1+2), %esi
/* skip 8-byte OEM name and Bytes per sector */
/* and Sectors per cluster, byte */
/* and Reserved sectors, word */
/* and Number of FATs, byte */
/* (Max root dir entries)Must be 0, word */
/* (Total sectors small)Must be 0, word */
/* Media descriptor, byte */
/* (Sectors per FAT)Must be 0, word */
/* sectors per track, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffffff3f, PRE(cs)ABS(sectors_per_track)
je 3f
movb PRE(cs)ABS(sectors_per_track), %al
cbw
subl $2, %edi
stosw
3:
/* number of heads, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffff00ff, PRE(cs)ABS(heads)
je 3f
movw PRE(cs)ABS(heads), %ax
subl $2, %edi
stosw
3:
/* hidden sectors(i.e., partition start), dword */
lodsl PRE(cs)(iSI), %eax
addl $4, %edi
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
je 3f
movl PRE(cs)ABS(start_sector), %eax
subl $4, %edi
stosl
3:
/* total sectors, dword */
lodsl PRE(cs)(iSI), %eax
addl $4, %edi
cmpl $0, PRE(cs)ABS(total_sectors)
je 3f
movl PRE(cs)ABS(total_sectors), %eax
subl $4, %edi
stosl
3:
/* FAT32 sectors per FAT, dword, etc... */
addl $(4+2+2+4+2+2+12+1+1+1+4+11+8), %esi
addl $(4+2+2+4+2+2+12+1+1+1+4+11+8), %edi
//movl $0xFFB6FCFA, %eax /* CLI, CLD, MOV DH,FF */
lodsw PRE(cs)(iSI), %ax
stosw
lodsb PRE(cs)(iSI), %al
stosb
lodsb PRE(cs)(iSI), %al
//decl %edi
/* partition number, byte */
movb PRE(cs)ABS(floppy), %al
stosb
/* Machine code begins at offset 0x5e, 416 bytes without
* the ending 2 bytes of boot signature */
//movl $ABS(_start1 + 0x45e), %esi
movl $(416 / 4), %ecx
repz movsl PRE(cs)(iSI), %es:(iDI)
movl $1, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_fat32_allow), %ecx
call 8f /* linux_print */
clc
popal
ret
4:
/* NTFS */
movl 0x20(iSI), %eax /* FAT32 total sectors */
testl %eax, %eax
jnz 1f
//movw 0x11(%si), %ax /* max root entries */
//testw %ax, %ax
//jnz 1f
movw 0x0e(iSI), %ax /* reserved sectors */
testw %ax, %ax
jnz 1f
/* sure it is NTFS */
/* is NTFS allowed write? */
testl $0x08, PRE(cs)ABS(fstypes)
jnz 3f
/* NTFS write not allowed */
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_ntfs_deny), %ecx
call 8f /* linux_print */
stc
popal
ret
3:
#if 1
/* write to NTFS boot area */
cld
movl $ABS(_start1 + 0xA00), %esi /* points to the 6th sector */
#ifdef __DOS_16
xorl %edi, %edi
cs lodsw
#else
movl $MBR(0), %edi
lodsw PRE(cs)(iSI), %ax /* The first 2 byte: short jmp */
#endif
stosw
/* check lba-chs-mode specified, 1 byte */
cmpl $-1, PRE(cs)ABS(lba) /* lba-chs-mode not specified? */
je 3f /* yes, do nothing. */
movb $0x0e, %al /* initialize to lba mode. */
cmpl $0, PRE(cs)ABS(lba) /* chs ? */
jnz 10f /* no, it is not chs.*/
movb $0x90, %al /* yes, it is chs. */
10:
stosb
decl %edi
3:
addl $(1+8+2+1+2+1+2+2+1+2), %edi
addl $(1+8+2+1+2+1+2+2+1+2), %esi
/* skip 8-byte OEM name and Bytes per sector */
/* and Sectors per cluster, byte */
/* and Reserved sectors, word */
/* and Number of FATs, byte */
/* (Max root dir entries)Must be 0, word */
/* (Total sectors small)Must be 0, word */
/* Media descriptor, byte */
/* (Sectors per FAT)Must be 0, word */
/* sectors per track, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffffff3f, PRE(cs)ABS(sectors_per_track)
je 3f
movb PRE(cs)ABS(sectors_per_track), %al
cbw
subl $2, %edi
stosw
3:
/* number of heads, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffff00ff, PRE(cs)ABS(heads)
je 3f
movw PRE(cs)ABS(heads), %ax
subl $2, %edi
stosw
3:
/* hidden sectors(i.e., partition start), dword */
lodsl PRE(cs)(iSI), %eax
addl $4, %edi
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
je 3f
movl PRE(cs)ABS(start_sector), %eax
subl $4, %edi
stosl
3:
addl $(4+1+1+1+1+8), %esi
addl $(4+1+1+1+1+8), %edi
/* total sectors, unused, dword */
/* drive number, byte, and another 3 bytes; Usually 80 00 80 00 */
/* Number of sectors in the volume, qword */
//lodsl
//lodsl
//addl $8, %edi
cmpl $0, PRE(cs)ABS(total_sectors)
je 3f
movl PRE(cs)ABS(total_sectors), %eax
subl $8, %edi
stosl
xorl %eax, %eax /* high 32 bits */
stosl
3:
addl $(8+8+4+4+8+4), %esi
addl $(8+8+4+4+8+4), %edi
/* 30 - LCN of VCN 0 of the $MFT, qword */
/* 38 - LCN of VCN 0 of the $MFTMirr, qword */
/* 40 - Clusters per MFT Record, dword */
/* 44 - Clusters per Index Record, dword */
/* 48 - Volume serial number, qword */
/* 50 - Checksum, usually 0, dword */
//movl $0xFFB6FCFA, %eax /* CLI, CLD, MOV DH,FF */
lodsw PRE(cs)(iSI), %ax
stosw
lodsb PRE(cs)(iSI), %al
stosb
lodsb PRE(cs)(iSI), %al
//decl %edi
/* partition number, byte */
movb PRE(cs)ABS(floppy), %al
stosb
/* Machine code begins at offset 0x58, ending at 0x7FF, where
* we assume that NTFS boot record takes up 4 sectors. */
movl $((0x800 - 0x58)/ 4), %ecx
repz movsl PRE(cs)(iSI), %es:(iDI)
movl $4, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_ntfs_allow), %ecx
call 8f /* linux_print */
clc
popal
ret
#else
/* write to NTFS boot area */
movl $MBR(0), %edi
LEAL 0x400(%edi), %esi /* ESI points to super block */
/* hidden sectors(i.e., partition start), dword */
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
je 3f
movl PRE(cs)ABS(start_sector), %eax
movl %eax, 0x1c(iDI)
3:
/* drive number needn't touch */
/* partition number */
call 4f
jc 5f
movl 0x06(iSI), %eax /* NT 4 */
cmpl $0x03E8B800, %eax /* MOV ES,AX */
jnz 3f
cmpl $0x680007E8, 0x84(iDI) /* call 008e; push (0D00) */
jnz 3f
movb $0xB6, %al /* 0xB6="MOV DH,imm8" */
movb PRE(cs)ABS(floppy), %ah /* partition number */
movw %ax, 0x0a(iSI)
movl $4, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_ntfs_allow), %ecx
call 8f /* linux_print */
clc
popal
ret
3:
/* NT 5.0 */
cmpl $0x680053E8, 0x71(iDI) /* call 00C7; push (0D00) */
jnz 5f
movl $0x4b, %ebx
movl (iBX, iSI), %eax /* NT 5 */
cmpl $0x03E8B800, %eax /* MOV ES,AX */
jz 3f
movl $0x79, %ebx
movl (iBX, iSI), %eax /* NT 5p */
cmpl $0x03E8B800, %eax /* MOV ES,AX */
jnz 5f
3:
movb $0xB6, %al /* 0xB6="MOV DH,imm8" */
movb PRE(cs)ABS(floppy), %ah /* partition number */
movw %ax, 4(iBX, iSI)
movl $4, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_ntfs_allow), %ecx
call 8f /* linux_print */
clc
popal
ret
5:
/* No NTFS boot record present */
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_no_ntfs_boot_record), %ecx
call 8f /* linux_print */
stc
popal
ret
4: /* change NT to GR */
pushal
cld
movl $0x00520047, 0x202(iDI) /* G R L D R */
addl $0x0100, %edi
movl $0x00fa, %ecx
movw $0x014e, %ax /* AL="N", AH=Carry for SAHF below */
movl $0x52444c54, %ebx /* "TLDR" */
3:
repnz scasb /* find "N" */
jcxz 4f /* gets the end, exit */
cmpl %ebx, (iDI) /* is it "NTLDR"? */
jnz 3b /* no, continue to find */
/* "NTLDR" is found, so we believe it is NT boot sector. */
movw $0x5247, -1(iDI) /* change "NT" to "GR" */
/* CF=0 for now */
lahf /* Load Flags into AH */
/* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
/* AH = binary xxxxxxx0 */
jmp 3b
4:
sahf /* Store AH into flags SF ZF xx AF xx PF xx CF */
/* CF=0 means "NTLDR" is found, CF=1 means "NTLDR" is not found. */
popal
ret
#endif
2:
/* FAT12/FAT16 */
movb 0x10(iSI), %al /* number of FATs(NTFS:0, FAT:1,2) */
testb %al, %al
jz 1f
movw 0x16(iSI), %ax /* sectors per FAT(small) */
testw %ax, %ax
jz 1f
// movw $(FAT16_message - _start1), %si
cmpw $12, %ax
ja 4f /* FAT16 */
/* sure it is FAT12 */
/* is FAT12 allowed write? */
testl $0x01, PRE(cs)ABS(fstypes)
jnz 2f
/* FAT12 write not allowed */
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_fat12_deny), %ecx
call 8f /* linux_print */
stc
popal
ret
2:
/* write to FAT12 boot area */
cld
movl $ABS(_start1 + 0x600), %esi /* points to the 4th sector */
#ifdef __DOS_16
xorl %edi, %edi
cs lodsw
#else
movl $MBR(0), %edi
lodsw PRE(cs)(iSI), %ax /* The first 2 byte: short jmp */
#endif
//leal 0x400(%edi), %esi /* ESI points to super block */
stosw
/* check lba-chs-mode specified, 1 byte */
cmpl $-1, PRE(cs)ABS(lba) /* lba-chs-mode not specified? */
je 2f /* yes, do nothing. */
movb $0x0e, %al /* initialize to lba mode. */
cmpl $0, PRE(cs)ABS(lba) /* chs ? */
jnz 10f /* no, it is not chs.*/
movb $0x90, %al /* yes, it is chs. */
10:
stosb
decl %edi
2:
addl $(1+8+2+1+2+1+2+2+1+2), %edi
addl $(1+8+2+1+2+1+2+2+1+2), %esi
/* skip 8-byte OEM name and Bytes per sector */
/* and Sectors per cluster, byte */
/* and Reserved sectors, word */
/* and Number of FATs, byte */
/* (Max root dir entries)Must be 0, word */
/* (Total sectors small)Must be 0, word */
/* Media descriptor, byte */
/* (Sectors per FAT)Must be 0, word */
/* sectors per track, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffffff3f, PRE(cs)ABS(sectors_per_track)
je 2f
movb PRE(cs)ABS(sectors_per_track), %al
cbw
subl $2, %edi
stosw
2:
/* number of heads, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffff00ff, PRE(cs)ABS(heads)
je 2f
movw PRE(cs)ABS(heads), %ax
subl $2, %edi
stosw
2:
/* hidden sectors(i.e., partition start), dword */
lodsl PRE(cs)(iSI), %eax
addl $4, %edi
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
je 2f
movl PRE(cs)ABS(start_sector), %eax
subl $4, %edi
stosl
2:
/* total sectors, dword */
lodsl PRE(cs)(iSI), %eax
addl $4, %edi
cmpl $0, PRE(cs)ABS(total_sectors)
je 2f
movl PRE(cs)ABS(total_sectors), %eax
subl $4, %edi
stosl
2:
/* drive number, byte, etc... */
addl $(1+1+1+4+11+8), %esi
addl $(1+1+1+4+11+8), %edi
//movl $0xFFB6FCFA, %eax /* CLI, CLD, MOV DH,FF */
lodsw PRE(cs)(iSI), %ax
stosw
lodsb PRE(cs)(iSI), %al
stosb
lodsb PRE(cs)(iSI), %al
//decl %edi
/* partition number, byte */
movb PRE(cs)ABS(floppy), %al
stosb
/* Machine code begins at offset 0x42, 444 bytes without
* the ending 2 bytes of boot signature */
//movl $ABS(_start1 + 0x642), %esi
movl $(444 / 4), %ecx
repz movsl PRE(cs)(iSI), %es:(iDI)
movl $1, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_fat12_allow), %ecx
call 8f /* linux_print */
clc
popal
ret
4:
/* sure it is FAT16 */
/* is FAT16 allowed write? */
testl $0x02, PRE(cs)ABS(fstypes)
jnz 2f
/* FAT16 write not allowed */
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_fat16_deny), %ecx
call 8f /* linux_print */
stc
popal
ret
2:
/* write to FAT16 boot area */
cld
movl $ABS(_start1 + 0x600), %esi /* points to the 4th sector */
#ifdef __DOS_16
xorl %edi, %edi
cs lodsw
#else
movl $MBR(0), %edi
lodsw PRE(cs)(iSI), %ax /* The first 2 byte: short jmp */
#endif
//leal 0x400(%edi), %esi /* ESI points to super block */
stosw
/* check lba-chs-mode specified, 1 byte */
cmpl $-1, PRE(cs)ABS(lba) /* lba-chs-mode not specified? */
je 2f /* yes, do nothing. */
movb $0x0e, %al /* initialize to lba mode. */
cmpl $0, PRE(cs)ABS(lba) /* chs ? */
jnz 10f /* no, it is not chs.*/
movb $0x90, %al /* yes, it is chs. */
10:
stosb
decl %edi
2:
addl $(1+8+2+1+2+1+2+2+1+2), %edi
addl $(1+8+2+1+2+1+2+2+1+2), %esi
/* skip 8-byte OEM name and Bytes per sector */
/* and Sectors per cluster, byte */
/* and Reserved sectors, word */
/* and Number of FATs, byte */
/* (Max root dir entries)Must be 0, word */
/* (Total sectors small)Must be 0, word */
/* Media descriptor, byte */
/* (Sectors per FAT)Must be 0, word */
/* sectors per track, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffffff3f, PRE(cs)ABS(sectors_per_track)
je 2f
movb PRE(cs)ABS(sectors_per_track), %al
cbw
subl $2, %edi
stosw
2:
/* number of heads, word */
lodsw PRE(cs)(iSI), %ax
addl $2, %edi
cmpl $0xffff00ff, PRE(cs)ABS(heads)
je 2f
movw PRE(cs)ABS(heads), %ax
subl $2, %edi
stosw
2:
/* hidden sectors(i.e., partition start), dword */
lodsl PRE(cs)(iSI), %eax
addl $4, %edi
cmpl $0xffffffff, PRE(cs)ABS(start_sector)
je 2f
movl PRE(cs)ABS(start_sector), %eax
subl $4, %edi
stosl
2:
/* total sectors, dword */
lodsl PRE(cs)(iSI), %eax
addl $4, %edi
cmpl $0, PRE(cs)ABS(total_sectors)
je 2f
movl PRE(cs)ABS(total_sectors), %eax
subl $4, %edi
stosl
2:
/* drive number, byte, etc... */
addl $(1+1+1+4+11+8), %esi
addl $(1+1+1+4+11+8), %edi
//movl $0xFFB6FCFA, %eax /* CLI, CLD, MOV DH,FF */
lodsw PRE(cs)(iSI), %ax
stosw
lodsb PRE(cs)(iSI), %al
stosb
lodsb PRE(cs)(iSI), %al
//decl %edi
/* partition number, byte */
movb PRE(cs)ABS(floppy), %al
stosb
/* Machine code begins at offset 0x42, 444 bytes without
* the ending 2 bytes of boot signature */
//movl $ABS(_start1 + 0x642), %esi
movl $(444 / 4), %ecx
repz movsl PRE(cs)(iSI), %es:(iDI)
movl $1, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_fstype_fat16_allow), %ecx
call 8f /* linux_print */
clc
popal
ret
1:
movl $0, PRE(cs)ABS(sectors_to_write)
movl $ABS(msg_unsupported_fstype), %ecx
call 8f /* linux_print */
stc
popal
ret
//----------------------------------------------------------------------------
//print decimal number in EAX
6:
/* print EAX value in decimal format */
pushal
#ifdef __DOS_16
pushw %cs
popw %es
#endif
#if 0
cld
movl $ABS(number_digits), %edi
xchgl %eax, %edx // save EAX to EDX
movw $0x2020, %ax // two spaces
stosw
stosw
stosw
stosw
stosw
decl %edi // EDI points to the last digit
xchgl %eax, %edx // restore EAX from EDX
#endif
std
movl $ABS(number_digits + 9), %edi
movl $10, %ebp
1:
xorl %edx, %edx
divl %ebp // quo=EAX, rem=EDX
xchgl %eax, %edx
orb $0x30, %al
stosb
xchgl %eax, %edx
testl %eax, %eax
jnz 1b
/* all digits are stored */
incl %edi // points to the digit string
movl %edi, %ecx
call 8f /* linux_print */
cld
#ifdef __DOS_16
pushw %ss
popw %es
#endif
popal
ret
//----------------------------------------------------------------------------
//parse_number:
7:
/* input: EDI points to the number
* EBX upper limit of the number
* output: EBX the value of the number
* EDX changed
* ESI changed
* EBP changed
* CF=1 failure
* CF=0 success
*/
pushl %eax
pushl %ebx /* upper limit */
cld
movl %edi, %esi
movl $0xffffffff, %edx
xorl %ebx, %ebx
lodsw
cmpw $0x5830, %ax /* 0X */
je 1f
cmpw $0x7830, %ax /* 0x */
je 1f
/* decimal */
decl %esi
decl %esi
movl $10, %ebp
2:
xorl %eax, %eax
lodsb
cmpb $0, %al
je 4f /* CF=0 */
cmpb $0x30, %al
jb 3f
cmpb $0x39, %al
ja 3f
subb $0x30, %al
pushl %eax
movl %ebx, %eax
mull %ebp
movl %eax, %ebx
popl %eax
jc 3f
addl %eax, %ebx
jc 3f
popl %eax
pushl %eax /* upper limit */
cmpl %eax, %ebx
ja 3f
jmp 2b
1:
/* hex */
movl $16, %ebp
2:
xorl %eax, %eax
lodsb
cmpb $0, %al
je 4f /* CF=0 */
cmpb $0x30, %al
jb 3f
cmpb $0x39, %al
jbe 1f
orb $0x20, %al
cmpb $0x61, %al
jb 3f
cmpb $0x66, %al
ja 3f
subb $0x27, %al
1:
subb $0x30, %al
pushl %eax
movl %ebx, %eax
mull %ebp
movl %eax, %ebx
popl %eax
jc 3f
addl %eax, %ebx
jc 3f
popl %eax
pushl %eax /* upper limit */
cmpl %eax, %ebx
ja 3f
jmp 2b
3:
stc
popl %eax /* upper limit */
popl %eax
ret
4:
testl %edx, %edx /* CF=0 */
jnz 3b
popl %eax /* upper limit */
popl %eax
ret
//----------------------------------------------------------------------------
//linux_print:
8:
/* print a message.
* input: ECX points to message string
* output: message is displayed on the stdout device
*/
/* ssize_t write(int fd, const void *buf, size_t count) */
pushal
#ifdef __DOS_16
cld
movl %ecx, %esi
// movw %si, %dx
// movb $0x09, %ah // WRITE STRING TO STANDARD OUTPUT
// int $0x21 // call DOS
// ret
1:
lodsb %cs:(%si), %al // get token
cmpb $0, %al // end of string?
je 1f
#if 0
/* use BIOS independent of DOS */
xorw %bx, %bx // video page 0
movb $0x0e, %ah // print it
int $0x10 // via TTY mode
#else
/* use stdout for redirection of the output */
movb %al, %dl // character to write
movb $0x02, %ah // WRITE CHARACTER TO STANDARD OUTPUT
int $0x21 // call DOS
#endif
jmp 1b // until done
1:
#else
pushl %ecx
movl %ecx, %edi # scan the message string ...
movl $(msg_end - msg_start), %ecx
movb $0, %al # ... find the ending zero byte
cld
repnz scasb
movl %edi, %edx
popl %ecx # ECX points to the message
subl %ecx, %edx # EDX=message length
decl %edx # discard the ending zero byte
movl $4, %eax # sys_write
movl $1, %ebx # file descriptor = stdout
int $0x80
#endif
popal
ret
//----------------------------------------------------------------------------
//probe_geometry:
9:
pushal
addl $0x200, %esi
movl $0, PRE(cs)ABS(mbr_free_sectors) # geometry ok
movw $0, PRE(cs)ABS(Cmax)
movl $0, PRE(cs)ABS(Hmax)
movw $0, PRE(cs)ABS(Smax)
movl $0, PRE(cs)ABS(i) # partition number
1:
cmpl $4, PRE(cs)ABS(i)
jae 1f
/* the boot indicator must be 0x80(bootable) or 0(non-bootable) */
movl PRE(cs)ABS(i), %ebx
movl PRE(cs)ABS(i), %edi
shll $4, %ebx # EBX = i * 16
movb -66(iBX, iSI), %al # boot_indicator
shlb $1, %al
jnz 6f /* geometry_probe_failed */
/* check if the entry is empty, i.e., all the 16 bytes are 0 */
movl -66(iBX, iSI), %eax
orl -62(iBX, iSI), %eax
orl -58(iBX, iSI), %eax
orl -54(iBX, iSI), %eax
jz 2f # empty partition entry
/* valid partitions never start at 0, because this is where the MBR
* lives; and more, the number of total sectors should be non-zero.
*/
cmpl $0, -58(iBX, iSI) # start_lba
jz 6f /* geometry_probe_failed */
cmpl $0, -54(iBX, iSI) # total_sectors
jz 6f /* geometry_probe_failed */
/* the partitions should not overlap each other */
movl $-1, PRE(cs)ABS(j) // j = -1
3:
// for (j = 0; j < i; j++)
incl PRE(cs)ABS(j) // j++
cmpl %edi, PRE(cs)ABS(j) # i = EDI
jae 3f // j >= i, break.
movl -58(iBX, iSI), %ecx # ECX=P[i].start_lba
movl PRE(cs)ABS(j), %edx
shll $4, %edx # EDX = j * 16
MOVL -58(%edx, %esi), %eax # EAX=P[j].start_lba
// if ((P[j].start_lba <= P[i].start_lba) && (P[j].start_lba + P[j].total_sectors >= P[i].start_lba + P[i].total_sectors))
cmpl %ecx, %eax
ja 4f
pushl %ecx
pushl %eax
addl -54(iBX, iSI), %ecx // ECX = P[i].start_lba + P[i].total_sectors
ADDL -54(%edx, %esi), %eax // EAX = P[j].start_lba + P[j].total_sectors
cmpl %ecx, %eax
popl %eax
popl %ecx
jb 4f
jmp 3b //continue
4:
// if ((P[j].start_lba >= P[i].start_lba) && (P[j].start_lba + P[j].total_sectors <= P[i].start_lba + P[i].total_sectors))
cmpl %ecx, %eax
jb 4f
pushl %ecx
pushl %eax
addl -54(iBX, iSI), %ecx // ECX = P[i].start_lba + P[i].total_sectors
ADDL -54(%edx, %esi), %eax // EAX = P[j].start_lba + P[j].total_sectors
cmpl %ecx, %eax
popl %eax
popl %ecx
ja 4f
jmp 3b //continue
4:
cmpl %ecx, %eax
jae 4f
// P[j].start_lba < P[i].start_lba
subl %eax, %ecx // ECX = P[i].start_lba - P[j].start_lba
CMPL -54(%edx, %esi), %ecx # ECX < P[j].total_sectors
jmp 5f
4:
// P[j].start_lba >= P[i].start_lba
subl %ecx, %eax // EAX = P[j].start_lba - P[i].start_lba
cmpl -54(iBX, iSI), %eax # EAX < P[i].total_sectors
5:
jb 6f /* geometry_probe_failed */
jmp 3b //continue
3:
/* the start cylinder number */
movzwl -64(iBX, iSI), %eax # start_sector_cylinder
movl %eax, %edx
andw $0x003f, %dx
jz 6f /* geometry_probe_failed */
movw %dx, PRE(cs)ABS(X) # the sector number
cmpw %dx, PRE(cs)ABS(Smax)
jae 3f
movw %dx, PRE(cs)ABS(Smax)
3:
movl -58(iBX, iSI), %ecx # start_lba
incl %ecx
subl %edx, %ecx
movl $ABS(L), %edx
MOVL %ecx, PRE(cs)(%edx, %edi, 8) # L[i]
///* partitions should not start at the first track, the MBR-track */
//movw PRE(cs)ABS(Smax), %dx
//cmpw %dx, -58(%ebx, %esi) # start_lba
//jb 6f /* geometry_probe_failed */
shrb $6, %al
xchgb %al, %ah
movl $ABS(C), %edx
MOVW %ax, PRE(cs)(%edx, %edi, 4) # C[i]
cmpw %ax, PRE(cs)ABS(Cmax)
jae 3f
movw %ax, PRE(cs)ABS(Cmax)
3:
//movl PRE(cs)ABS(i), %ebx
//shll $4, %ebx # EBX = PRE(cs)ABS(i) * 16
movzbl -65(iBX, iSI), %eax # start_head
movl $ABS(H), %edx
MOVL %eax, PRE(cs)(%edx, %edi, 4) # H[i]
cmpl %eax, PRE(cs)ABS(Hmax)
jae 3f
movl %eax, PRE(cs)ABS(Hmax)
3:
/* the end cylinder number */
movzwl -60(iBX, iSI), %eax # end_sector_cylinder
movl %eax, %edx
andw $0x003f, %dx
jz 6f /* geometry_probe_failed */
movw %dx, PRE(cs)ABS(Y) # the sector number
cmpw %dx, PRE(cs)ABS(Smax)
jae 3f
movw %dx, PRE(cs)ABS(Smax)
3:
movl -58(iBX, iSI), %ecx # start_lba
addl -54(iBX, iSI), %ecx # total_sectors
# XXX: possible overflow!
subl %edx, %ecx
jb 6f /* geometry_probe_failed */
addl $4, %edi # EDI=i+4
movl $ABS(L), %edx
MOVL %ecx, PRE(cs)(%edx, %edi, 8) # L[i+4]
movl %ecx, %ebp # save ECX to EBP
// /* partitions should not start at the first track, the MBR-track */
// movzbl PRE(cs)ABS(Smax), %edx
// cmpl %edx, -58(iBX, iSI) # start_lba
// jb 6f /* geometry_probe_failed */
shrb $6, %al
xchgb %al, %ah
movl $ABS(C), %edx
MOVW %ax, PRE(cs)(%edx, %edi, 4) # C[i+4]
cmpw %ax, PRE(cs)ABS(Cmax)
jae 3f
movw %ax, PRE(cs)ABS(Cmax)
3:
xchgl %eax, %ecx # save AX to CX
//movl PRE(cs)ABS(i), %ebx
//shll $4, %ebx # EBX = PRE(cs)ABS(i) * 16
movzbl -61(iBX, iSI), %eax # end_head
movl $ABS(H), %edx
MOVL %eax, PRE(cs)(%edx, %edi, 4) # H[i+4]
cmpl %eax, PRE(cs)ABS(Hmax)
jae 3f
movl %eax, PRE(cs)ABS(Hmax)
3:
/* Check the large disk partition -- Win98 */
cmpw $63, PRE(cs)ABS(Y)
jne 3f
cmpl %eax, PRE(cs)ABS(Hmax) # EAX=H[i+4]
jne 3f
cmpw %cx, PRE(cs)ABS(Cmax) # ECX=C[i+4]
jne 3f
cmpl $254, %eax # EAX=PRE(cs)ABS(Hmax)
jnb 4f
cmpw $1022, %cx # CX=PRE(cs)ABS(Cmax)
jb 3f
4:
movl $63, %edx # EDX=PRE(cs)ABS(Y)
addl %edx, %ebp
incl %eax
mull %edx # EDX:EAX=product
# EDX=0
# EAX high word = 0
# AX=(Hmax+1)*63
pushl %eax # EAX=(Hmax+1)*63
incl %ecx
mull %ecx # EDX:EAX=product
# EDX=0
cmpl %ebp, %eax
popl %eax # EAX=(Hmax+1)*63
jnb 3f
/* EDI=i+4 at this moment */
pushl %eax # EAX=(Hmax+1)*63
subl $4, %edi # EDI=i
movl $ABS(C), %ebx
MOVZWL PRE(cs)(%ebx, %edi, 4), %eax # C[i]
movl PRE(cs)ABS(Hmax), %ebp # Hmax
incl %ebp
pushl %eax # EAX=C[i]
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %ecx # H[i]
mull %ebp # EDX=0, EAX=product
addl %ecx, %eax
movl $63, %edx
mull %edx # EDX=0, EAX=product
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edi, 8), %ebp # L[i]
cmpl %ebp, %eax
popl %eax # EAX=C[i]
jae 4f
/* calculate CHS numbers from start LBA */
//pushl %eax # EAX=C[i]
xorl %edx, %edx
xchgl %eax, %ebp # EBP=C[i], EDX:EAX=L[i]
divl PRE(cs)ABS(Y) # Y=63
# quo=EAX, rem=EDX
incl %edx # sector number
cmpw %dx, PRE(cs)ABS(X)
je 15f
cmpw $63, PRE(cs)ABS(X)
jne 4f
15:
xorl %edx, %edx
movl PRE(cs)ABS(Hmax), %ebx
incl %ebx # EBX=Hmax+1
divl %ebx # quo=EAX=cylinder number
# rem=EDX=head number
cmpl %edx, %ecx # ECX=H[i]
je 15f
decl %ebx # EBX=Hmax
cmpl %ebx, %ecx
jne 4f
15:
/* EAX=calculated cylinder number, EBP=C[i] */
cmpl PRE(cs)ABS(Cmax), %ebp
je 4f
andw $0x3ff, %ax # low 10 bit of calculated cylinder
cmpw %ax, %bp
//5:
// cmpw PRE(cs)ABS(Cmax), %ax
// jne 4f
// cmpl PRE(cs)ABS(Hmax), %ecx
// jne 4f
// cmpw $63, PRE(cs)ABS(X)
4:
popl %eax
//##jne 6f /* geometry_probe_failed */
jmp 5f
3:
/* Check the large disk partition -- Win2K */
/* EDI=i+4 at this moment */
cmpw $63, PRE(cs)ABS(Y)
jne 3f
movl $ABS(H), %edx
MOVL PRE(cs)(%edx, %edi, 4), %eax # H[i+4]
cmpl %eax, PRE(cs)ABS(Hmax) # EAX=H[i+4]
jne 3f
movl $ABS(L), %edx
MOVL PRE(cs)(%edx, %edi, 8), %ebp # L[i+4]
movl $ABS(C), %edx
MOVZWL PRE(cs)(%edx, %edi, 4), %ecx # C[i+4]
incl %ecx
incl %eax
mull %ecx # EDX=0, EAX=product
mull PRE(cs)ABS(Y) # Y=63, EDX=0, EAX=product
addl PRE(cs)ABS(Y), %ebp
cmpl %ebp, %eax
jnb 3f
movl PRE(cs)ABS(Hmax), %eax
incl %eax
mull PRE(cs)ABS(Y) # Y=63, EDX=0, EAX=product
xorl %edx, %edx
xchgl %eax, %ebp # EBP=(Hmax+1)*63
# EAX=L[i+4]+Y
divl %ebp # EAX=quo, EDX=rem
testl %edx, %edx
jnz 3f
decl %eax
andl $0x3ff, %eax
decl %ecx
cmpl %eax, %ecx
jne 3f
/* EDI=i+4 at this moment */
subl $4, %edi # EDI=i
movl $ABS(C), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # C[i]
pushl %eax
mull %ebp # EBP=(Hmax+1)*63
# EDX=0, EAX=product
pushl %ebp # EBP=(Hmax+1)*63
xchgl %eax, %ebp # EBP=product
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # H[i]
mull PRE(cs)ABS(Y) # Y=63, EDX=0, EAX=H[i]*63
pushl %eax
addl %eax, %ebp
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edi, 8), %eax # L[i]
cmpl %eax, %ebp
popl %ebx # EBX=H[i]*63
popl %ebp # EBP=(Hmax+1)*63
popl %ecx # ECX=C[i]
xchgl %eax, %ebp
//##ja 6f /* geometry_probe_failed */
//##je 5f
jae 5f
xchgl %eax, %ebp
subl %ebx, %eax
xorl %edx, %edx
divl %ebp # EAX=quo, EDX=rem
testl %edx, %edx
//##jnz 6f /* geometry_probe_failed */
jnz 5f /* geometry_probe_failed */
andl $0x3ff, %eax
cmpl %eax, %ecx
//##jne 6f /* geometry_probe_failed */
jne 5f /* geometry_probe_failed */
xchgl %eax, %ebp
jmp 5f
3:
/* Maximum of C[n] * (H * S) + H[n] * S = 1023 * 255 * 63 + 254 * 63 = 0xFB03C1 */
/* EDI=i+4 at this moment */
movl $ABS(L), %edx
MOVL PRE(cs)(%edx, %edi, 8), %ebp # L[i+4]
cmpl $0xFB03C1, %ebp
jbe 3f
/* set H/S to max */
cmpl $254, PRE(cs)ABS(Hmax)
jae 4f
movl $254, PRE(cs)ABS(Hmax)
4:
movw $63, PRE(cs)ABS(Smax)
xorl %edx, %edx
movl %ebp, %eax
divl PRE(cs)ABS(Smax)
testl %edx, %edx
//##jnz 6f /* geometry_probe_failed */
jnz 5f /* geometry_probe_failed */
/* EAX=L[i+4]/63, EDX=0 */
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %ebx # EBX=H[i+4]
movl PRE(cs)ABS(Hmax), %ecx
incl %ecx # ECX=Hmax+1
divl %ecx
cmpl %edx, %ebx
je 15f
cmpl PRE(cs)ABS(Hmax), %ebx
//##jne 6f /* geometry_probe_failed */
jne 5f /* geometry_probe_failed */
15:
/* EAX=L[i+4]/63/(Hmax+1) */
andl $0x3FF, %eax
movl $ABS(C), %edx
MOVZWL PRE(cs)(%edx, %edi, 4), %ebx # C[i+4]
cmpl %eax, %ebx
je 15f
cmpl PRE(cs)ABS(Cmax), %ebx
//##jne 6f /* geometry_probe_failed */
jne 5f /* geometry_probe_failed */
15:
movl $63, %eax
mull %ecx
/* EDI=i+4 at this moment */
pushl %eax # EAX=(Hmax+1)*63
subl $4, %edi # EDI=i
movl $ABS(C), %ebx
MOVZWL PRE(cs)(%ebx, %edi, 4), %eax # C[i]
movl PRE(cs)ABS(Hmax), %ebp # Hmax
incl %ebp
pushl %eax # EAX=C[i]
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %ecx # H[i]
mull %ebp # EDX=0, EAX=product
addl %ecx, %eax
movl $63, %edx
mull %edx # EDX=0, EAX=product
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edi, 8), %ebp # L[i]
cmpl %ebp, %eax
popl %eax # EAX=C[i]
jae 4f
/* calculate CHS numbers from start LBA */
//pushl %eax # EAX=C[i]
xorl %edx, %edx
xchgl %eax, %ebp # EBP=C[i], EDX:EAX=L[i]
divl PRE(cs)ABS(Y) # Y=63
# quo=EAX, rem=EDX
incl %edx # sector number
cmpw %dx, PRE(cs)ABS(X)
je 15f
cmpw $63, PRE(cs)ABS(X)
jne 4f
15:
xorl %edx, %edx
movl PRE(cs)ABS(Hmax), %ebx
incl %ebx # EBX=Hmax+1
divl %ebx # quo=EAX=cylinder number
# rem=EDX=head number
cmpl %edx, %ecx # ECX=H[i]
je 15f
decl %ebx # EBX=Hmax
cmpl %ebx, %ecx
jne 4f
15:
/* EAX=calculated cylinder number, EBP=C[i] */
cmpl PRE(cs)ABS(Cmax), %ebp
je 4f
andw $0x3ff, %ax # low 10 bit of calculated cylinder
cmpw %ax, %bp
//5:
// cmpw PRE(cs)ABS(Cmax), %ax
// jne 4f
// cmpl PRE(cs)ABS(Hmax), %ecx
// jne 4f
// cmpw $63, PRE(cs)ABS(X)
4:
popl %eax
//##jne 6f /* geometry_probe_failed */
//jmp 5f
5:
je 5f
movl $-1, PRE(cs)ABS(mbr_free_sectors) # geometry fail
jmp 3f
5:
/* EAX = (Hmax+1)*63 */
movl $ABS(C), %ebx
MOVW $0, PRE(cs)(%ebx, %edi, 4) # C[i]=0
movl $ABS(H), %ebx
MOVL $1, PRE(cs)(%ebx, %edi, 4) # H[i]=1
movl $ABS(L), %ebx
MOVL $63, PRE(cs)(%ebx, %edi, 8) # L[i]=63
addl $4, %edi # EDI=i+4
movl $ABS(C), %ebx
MOVW $1, PRE(cs)(%ebx, %edi, 4) # C[i+4]=1
movl $ABS(H), %ebx
MOVL $0, PRE(cs)(%ebx, %edi, 4) # H[i+4]=0
movl $ABS(L), %ebx
MOVL %eax, PRE(cs)(%ebx, %edi, 8) # L[i+4]=(Hmax+1)*63
//##3:
jmp 3f
2: /* else */
/* empty entry, zero all the coefficients */
movl $ABS(C), %ebx
MOVW $0, PRE(cs)(%ebx, %edi, 4) # C[i]=0
movl $ABS(H), %ebx
MOVW $0, PRE(cs)(%ebx, %edi, 4) # H[i]=0
movl $ABS(L), %ebx
MOVL $0, PRE(cs)(%ebx, %edi, 8) # L[i]=0
addl $4, %edi
movl $ABS(C), %ebx
MOVW $0, PRE(cs)(%ebx, %edi, 4) # C[i+4]=0
movl $ABS(H), %ebx
MOVW $0, PRE(cs)(%ebx, %edi, 4) # H[i+4]=0
movl $ABS(L), %ebx
MOVL $0, PRE(cs)(%ebx, %edi, 8) # L[i+4]=0
3:
incl PRE(cs)ABS(i)
jmp 1b
1:
/* all coefficients are generated ok */
# --------------------------------------------------------------------
#if 0
/* print the coefficients */
xorl %edi, %edi
1:
cmpl $4, %edi
jae 1f
/* print C[i] */
movl $ABS(C), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # C[i]
call 6b //print decimal number
/* print spaces */
movl $ABS(delimit_space), %ecx
call 8b /* linux_print */
/* print H[i] */
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # H[i]
call 6b //print decimal number
/* print spaces */
movl $ABS(delimit_space), %ecx
call 8b /* linux_print */
/* print L[i] */
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edi, 8), %eax # L[i]
call 6b //print decimal number
/* print spaces */
movl $ABS(delimit_space), %ecx
call 8b /* linux_print */
addl $4, %edi
/* print C[i] */
movl $ABS(C), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # C[i+4]
call 6b //print decimal number
/* print spaces */
movl $ABS(delimit_space), %ecx
call 8b /* linux_print */
/* print H[i] */
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # H[i+4]
call 6b //print decimal number
/* print spaces */
movl $ABS(delimit_space), %ecx
call 8b /* linux_print */
/* print L[i] */
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edi, 8), %eax # L[i+4]
call 6b //print decimal number
/* print spaces */
movl $ABS(delimit_newline), %ecx
call 8b /* linux_print */
subl $4, %edi
incl %edi
jmp 1b
1:
#endif
# --------------------------------------------------------------------
/* mbr_free_sectors = 0 for geometry ok, -1 for failure */
cmpl $0, PRE(cs)ABS(mbr_free_sectors)
movl $1, PRE(cs)ABS(mbr_free_sectors) # partition table ok
jne 6f /* -1 for failed geometry probing */
//movl $1, PRE(cs)ABS(mbr_free_sectors) # partition table ok
xorl %edi, %edi # equation number PRE(cs)ABS(i)
1:
cmpl $8, %edi
jae 1f
movl $ABS(C), %ebx
CMPW $0, PRE(cs)(%ebx, %edi, 4) # C[i]
jne 1f
incl %edi
jmp 1b
1:
cmpl $8, %edi
jb 1f
/* all C[i] == 0 */
xorl %edi, %edi # equation number PRE(cs)ABS(i)
movl $ABS(H), %ebx
2:
cmpl $8, %edi
jae 2f
MOVL PRE(cs)(%ebx, %edi, 4), %ecx # H[i]
testl %ecx, %ecx
jne 2f
incl %edi
jmp 2b
2:
cmpl $8, %edi
je 6f /* geometry_probe_failed */ # all H[i] == 0
movl $1, PRE(cs)ABS(mbr_free_sectors) # partition table ok
xorl %edx, %edx # equation number j
movl $ABS(L), %ebx
2:
cmpl %edi, %edx
jae 2f
CMPW $0, PRE(cs)(%ebx, %edx, 8) # L[j]
jne 6f /* geometry_probe_failed */
incl %edx
jmp 2b
2:
/* j == i */
MOVL PRE(cs)(%ebx, %edi, 8), %eax # L[i]
testl %eax, %eax
jle 6f /* geometry_probe_failed */
# OF=0; jmp if SF=1 or ZF=1
cdq # EDX=0
divl %ecx # ECX=H[i]
# EAX=quo=sectors_per_track
# EDX=rem
testl %edx, %edx
jnz 6f /* geometry_probe_failed */
movl %eax, PRE(cs)ABS(probed_sectors_per_track)
cmpl $63, %eax
ja 6f /* geometry_probe_failed */
cmpw PRE(cs)ABS(Smax), %ax
jb 6f /* geometry_probe_failed */
movw %ax, PRE(cs)ABS(Smax)
movl %edi, %edx
incl %edx # equation number j=i+1
2:
cmpl $8, %edx
jae 2f
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edx, 4), %ecx # H[j]
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edx, 8), %eax # L[j]
jecxz 3f
pushl %edx
xchgl %eax, %ecx # EAX=H[j], ECX=L[j]
mull PRE(cs)ABS(probed_sectors_per_track) # EAX=product
# EDX=0
popl %edx
cmpl %eax, %ecx
jnz 6f /* geometry_probe_failed */
jmp 4f
3:
testl %eax, %eax
jnz 6f /* geometry_probe_failed */
4:
incl %edx
jmp 2b
2:
movl PRE(cs)ABS(Hmax), %eax
incl %eax
movl %eax, PRE(cs)ABS(probed_heads)
jmp 2f
1:
movl $1, PRE(cs)ABS(mbr_free_sectors) # partition table ok
testl %edi, %edi
jz 1f
/* xchgw C[i], C[0] */
movl $ABS(C), %ebx
MOVW PRE(cs)(%ebx, %edi, 4), %ax # C[i]
movw PRE(cs)(iBX), %cx # C[0]
movw %ax, PRE(cs)(iBX)
MOVW %cx, PRE(cs)(%ebx, %edi, 4)
/* xchgw H[i], H[0] */
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # H[i]
movl PRE(cs)(iBX), %ecx # H[0]
movl %eax, PRE(cs)(iBX)
MOVL %ecx, PRE(cs)(%ebx, %edi, 4)
/* xchgw L[i], L[0] */
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edi, 8), %eax # L[i]
movl PRE(cs)(iBX), %ecx # L[0]
movl %eax, PRE(cs)(iBX)
MOVL %ecx, PRE(cs)(%ebx, %edi, 8)
1:
movl $0, PRE(cs)ABS(H8) # will store sectors per track
/* for (i = 1; i < 8; i++) */
movl $1, %edi
1:
cmpl $8, %edi
jae 1f
movl $ABS(L), %ebx
MOVL PRE(cs)(%ebx, %edi, 8), %eax # L[i]
movzwl PRE(cs)ABS(C), %edx # C[0]
mull %edx # EDX:EAX=product
MOVL %eax, PRE(cs)(%ebx, %edi, 8) # L[i] low
MOVL %edx, PRE(cs)4(%ebx, %edi, 8) # L[i] high
movl $ABS(C), %ebx
MOVZWL PRE(cs)(%ebx, %edi, 4), %eax # C[i]
mull PRE(cs)ABS(L) # L[0]
movl $ABS(L), %ebx
SUBL %eax, PRE(cs)(%ebx, %edi, 8) # L[i] low
SBBL %edx, PRE(cs)4(%ebx, %edi, 8) # L[i] high
movl $ABS(H), %ebx
MOVL PRE(cs)(%ebx, %edi, 4), %eax # H[i]
movzwl PRE(cs)ABS(C), %edx # C[0]
mull %edx # EDX:EAX=product
# EDX=0
MOVL %eax, PRE(cs)(%ebx, %edi, 4) # H[i]
movl $ABS(C), %ebx
MOVZWL PRE(cs)(%ebx, %edi, 4), %eax # C[i]
mull PRE(cs)ABS(H) # H[0]
movl $ABS(H), %ebx
SUBL %eax, PRE(cs)(%ebx, %edi, 4) # H[i]
/* if (H[i]) */
jz 3f
ja 4f
movl $ABS(H), %ebx
NEGL PRE(cs)(%ebx, %edi, 4) # H[i]
movl $ABS(L), %ebx
xorl %eax, %eax
NEGL PRE(cs)(%ebx, %edi, 8) # L[i] low
cmc
NOTL PRE(cs)4(%ebx, %edi, 8) # L[i] high
ADCL %eax, PRE(cs)4(%ebx, %edi, 8)
4:
movl $ABS(L), %ebx
CMPL $0, PRE(cs)4(%ebx, %edi, 8) # L[i] high
jne 6f /* geometry_probe_failed */
MOVL PRE(cs)(%ebx, %edi, 8), %eax # L[i] low
testl %eax, %eax
jle 6f /* geometry_probe_failed */
# OF=0; jmp if SF=1 or ZF=1
cdq # EDX=0
movl $ABS(H), %ebx
DIVL PRE(cs)(%ebx, %edi, 4) # H[i]
# EAX=sectors per track
testl %edx, %edx
jnz 6f /* geometry_probe_failed */
movl %eax, PRE(cs)ABS(L8)
cmpl $63, %eax
ja 6f /* geometry_probe_failed */
cmpw PRE(cs)ABS(Smax), %ax
jb 6f /* geometry_probe_failed */
movw %ax, PRE(cs)ABS(Smax)
cmpl $0, PRE(cs)ABS(H8)
je 4f
cmpl %eax, PRE(cs)ABS(H8) # EAX=L[8]
jne 6f /* geometry_probe_failed */
jmp 5f
4:
movl %eax, PRE(cs)ABS(H8) # EAX=L[8]
5:
jmp 4f
3: /* else */
movl $ABS(L), %ebx
CMPL $0, PRE(cs)(%ebx, %edi, 8) # L[i] low
jne 6f /* geometry_probe_failed */
CMPL $0, PRE(cs)4(%ebx, %edi, 8) # L[i] high
jne 6f /* geometry_probe_failed */
4: /* end if (H[i]) */
incl %edi
jmp 1b
1: /* end for (i = 1; i < 8; i++) */
/* if (PRE(cs)ABS(H)[8]) */
cmpl $0, PRE(cs)ABS(H8)
je 3f
/* PRE(cs)ABS(H)[8] is sectors per track */
movl PRE(cs)ABS(H), %eax # H[0]
mull PRE(cs)ABS(H8)
//movl $ABS(L), %ebx
subl %eax, PRE(cs)ABS(L) # L[0] low
sbbl %edx, PRE(cs)ABS(L) + 4 # L[0] high
jnz 6f /* geometry_probe_failed */
movl PRE(cs)ABS(L), %eax
testl %eax, %eax
jle 6f /* geometry_probe_failed */
# OF=0; jmp if SF=1 or ZF=1
cdq # EDX=0
divl PRE(cs)ABS(H8)
testl %edx, %edx
jnz 6f /* geometry_probe_failed */
movzwl PRE(cs)ABS(C), %ecx # C[0]
divl %ecx
testl %edx, %edx
jnz 6f /* geometry_probe_failed */
movl %eax, PRE(cs)ABS(L8) # L[8] is number of heads
cmpl $256, %eax
ja 6f /* geometry_probe_failed */
cmpl PRE(cs)ABS(Hmax), %eax
jbe 6f /* geometry_probe_failed */
movl PRE(cs)ABS(H8), %eax
movl %eax, PRE(cs)ABS(probed_sectors_per_track)
jmp 4f
3: /* else */
/* fail to set L[8], this means all H[i]==0, i=1,2,3,4,5,6,7 */
/* Now the only equation is: C[0] * H * S + H[0] * S = L[0] */
/* for (i = 63; i >= Smax; i--) */
movl PRE(cs)ABS(L), %ebx # EBX=L[0]
movl $63, %edi
3:
cmpl PRE(cs)ABS(Smax), %edi
jb 3f
movl PRE(cs)ABS(H), %eax # H[0]
mull %edi # EDX=0
# EAX=product
//movl %ebx, PRE(cs)ABS(L8)
//subl %eax, PRE(cs)ABS(L8)
subl %ebx, %eax
negl %eax
jz 5f # continue
js 5f # continue
cdq # EDX=0
divl %edi
testl %edx, %edx
jnz 5f
movzwl PRE(cs)ABS(C), %ecx # C[0]
divl %ecx
testl %edx, %edx
jnz 5f
movl %eax, PRE(cs)ABS(L8) # L[8] is number of heads
cmpl $256, %eax
ja 5f
cmpl PRE(cs)ABS(Hmax), %eax
ja 3f
5:
decl %edi
jmp 3b
3: /* end for (i = 63; i >= Smax; i--) */
cmpl PRE(cs)ABS(Smax), %edi
jb 6f /* geometry_probe_failed */
movl %edi, PRE(cs)ABS(probed_sectors_per_track)
4: /* end if (PRE(cs)ABS(H)[8]) */
movl PRE(cs)ABS(L8), %eax
movl %eax, PRE(cs)ABS(probed_heads)
2: /* end if (PRE(cs)ABS(i) == 8) */
/* geometry_probe_ok */
clc
jmp 2f
//geometry_probe_failed:
6:
stc
movl $0, PRE(cs)ABS(probed_sectors_per_track)
movl $0, PRE(cs)ABS(probed_heads)
2:
/* try to get mbr_free_sectors */
cmpl $1, PRE(cs)ABS(mbr_free_sectors) # partition table ok
jl 2f # failure
/* find a minimum StartLBA in the partition table. */
movl $64, %eax
movl -58(iSI), %ecx # start_lba
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
movl -42(iSI), %ecx # start_lba
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
movl -26(iSI), %ecx # start_lba
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
movl -10(iSI), %ecx # start_lba
jecxz 1f
cmpl %ecx, %eax
jbe 1f
movl %ecx, %eax
1:
movl %eax, PRE(cs)ABS(mbr_free_sectors)
clc /* success */
popal
ret
2:
movl $0, PRE(cs)ABS(mbr_free_sectors) # partition table fail
stc
popal
ret
//partition:
0:
#if 0
/* load the next partition and modify the boot record */
/* EBX holds the file descriptor number or 0 if it is BIOS drive */
/* partition table is at MBR(0x2000) */
/* current partition number is PRE(cs)ABS(current_partition) */
pushal
/* enumerate all partitions */
/* initialize the partition table, move start_LBA(the 3rd dword)
* to the total_sectors field(the 4th dword) and clear the 3rd dword.
* The sum of the 3rd and 4th dwords gives the absolute start_LBA.
*/
movl $MBR(0x2000), %ebp
xorl %eax, %eax
xchgl %eax, 0x08(%ebp)
movl %eax, 0x0c(%ebp)
xorl %eax, %eax
xchgl %eax, 0x18(%ebp)
movl %eax, 0x1c(%ebp)
xorl %eax, %eax
xchgl %eax, 0x28(%ebp)
movl %eax, 0x2c(%ebp)
xorl %eax, %eax
xchgl %eax, 0x38(%ebp)
movl %eax, 0x3c(%ebp)
movl $0x04, PRE(cs)ABS(total_partition_entries)
/* copy extended partition entries to the end of the partition table */
xorl %esi, %esi
1:
movb 4(%ebp, %esi), %al # partition id
cmpb $0x05, %al
je 2f
cmpb $0x0f, %al
je 2f
cmpb $0x15, %al
je 2f
cmpb $0x1f, %al
je 2f
cmpb $0x85, %al
jne 4f
2:
/* extended partition */
/* read one sector of the partition to MBR(0) */
........
/* check if the partition table is valid */
j_invalid 3f
/* approve the partition entries and move onto the free entries */
movl PRE(cs)ABS(total_partition_entries), %edi
shll $4, %edi
addl %ebp, %edi # EDI points to the first free entry
/* move the extended partition entry onto the first free entry */
movl (%ebp, %esi), %eax
stosl
movl 4(%ebp, %esi), %eax
stosl
xorl %eax, %eax
stosl
movl 8(%ebp, %esi), %eax
stosl
incl PRE(cs)ABS(total_partition_entries)
3:
///* disable the original extended partition entry by clearing its id */
//movb $0, 4(%ebp, %esi)
cmpl $0x40, %esi # Is it in the main partition table?
jb 4f # yes, keep the entry in its place.
# no, remove the entry.
pushl %esi
addl %ebp, %esi
movl %esi, %edi
addl $0x10, %esi
movl PRE(cs)ABS(total_partition_entries), %ecx
shll $4, %ecx
subl %esi, %ecx
shrl $2, %ecx
cld
repz movsl
popl %esi
decl PRE(cs)ABS(total_partition_entries)
subl $0x10, %esi # go back one entry and redo
4:
addl $0x10, %esi
movl PRE(cs)ABS(total_partition_entries), %edi
shll $4, %edi
cmpl %edi, %esi
jb 1b
/* end of partition enumeration */
/* recursively resolve extended partition entries */
//xorl %esi, %esi
//movl $4, %esi
//cmpl PRE(cs)ABS(total_partition_entries), %esi
cmpl $3, PRE(cs)ABS(current_partition)
ja 1f
/* it is primary partition */
movl PRE(cs)ABS(current_partition), %esi
shll $4, %esi
movl 8(%ebp, %esi), %eax # start LBA
movl $ABS(msg_no_such_partition), PRE(cs)ABS(error_message_pointer)
testl %eax, %eax
stc
jz 2f
/* read 4 sectors at start LBA to MBR(0) */
movl $4, %ecx
clc /* read */
call 6f
movl $ABS(msg_read_file), PRE(cs)ABS(error_message_pointer)
jc 2f
/* modify the boot record */
call 7f
movl $ABS(msg_unsupported_fstype), PRE(cs)ABS(error_message_pointer)
jc 2f
/* write sectors to start LBA at MBR(0) */
movl PRE(cs)ABS(sectors_to_write), %ecx
stc /* write */
call 6f
movl $ABS(msg_write_file), PRE(cs)ABS(error_message_pointer)
2:
popal
ret
1:
/* it is logical partition */
movl $ABS(msg_end_of_partition_chain), PRE(cs)ABS(error_message_pointer)
popal
ret
6:
/* before the call: */
/* EAX=start LBA */
/* EBX=file descriptor or 0 for BIOS drive */
/* ECX=sectors */
/* CF=0 for read; CF=1 for write */
/* on return: */
/* CF=0 for success; CF=1 for failure */
pushal
popal
ret
7:
pushal
popal
ret
/* EBX holds the file descriptor number or 0 if it is BIOS drive */
/* move partition table forward to the beginning of the 17th sector */
movl $MBR(0x01be), %esi
movl $MBR(0x2000), %edi
movl $0x10, %ecx # 0x10 dwords = 0x40 bytes
cld
repz movsl
/* initialize the current_partition number */
movzbl PRE(cs)ABS(install_partition), %eax
movl %eax, PRE(cs)ABS(current_partition)
3:
/* load the next partition and modify the boot record */
call 0f /* partition */
jc 3f /* done */
call 2f /* write to file */
incl PRE(cs)ABS(current_partition)
movw PRE(cs)ABS(install_partition), %ax
addb %ah, %al /* Max partition number for install */
cmpb %al, PRE(cs)ABS(current_partition)
jbe 3b
3:
/* all partitions have been installed. */
xorl %eax, %eax # exit code = 0
#ifdef __DOS_16
movb $0x4c, %ah // EXIT - TERMINATE WITH RETURN CODE in AL
int $0x21 // call DOS
#else
xchgl %eax, %ebx # move exit code in EAX to EBX
movl $1, %eax # sys_exit
int $0x80
#endif
#endif
ret