summaryrefslogtreecommitdiffstats
path: root/debian/grub-extras/ntldr-img/grldrstart.S
diff options
context:
space:
mode:
Diffstat (limited to 'debian/grub-extras/ntldr-img/grldrstart.S')
-rw-r--r--debian/grub-extras/ntldr-img/grldrstart.S5793
1 files changed, 5793 insertions, 0 deletions
diff --git a/debian/grub-extras/ntldr-img/grldrstart.S b/debian/grub-extras/ntldr-img/grldrstart.S
new file mode 100644
index 0000000..1751338
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/grldrstart.S
@@ -0,0 +1,5793 @@
+/*
+ * grldrstart.S -- Startup code for GRLDR
+ * Copyright (C) 2004-2007 Tinybit(tinybit@tom.com)
+ * Copyright (C) 2007 Bean(bean@windrv.net)
+ *
+ * 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.
+ */
+
+/*
+ * This program is used to generate the GRLDR file.
+ *
+ * Use the following shell command to generate the GRLDR file:
+ *
+ * cat grldrstart pre_stage2 > grldr
+ *
+ */
+
+#ifndef STAGE1_5
+//#include <stage2_size.h>
+#else
+#error cannot compile with STAGE1_5
+#endif
+
+#ifdef GRLDR_MBR
+ .file "mbrstart.S"
+#elif defined(GRLDR_INSTALL)
+ .file "bootlacestart.S"
+#else
+ .file "grldrstart.S"
+#endif
+
+#ifdef GRLDR_INSTALL
+ //.data
+#else
+ .text
+
+ .globl start, _start
+
+start:
+_start:
+#endif
+
+_start1:
+
+ /* Tell GAS to generate 16-bit real mode instructions */
+
+ .code16
+
+ . = _start1 + 0x00
+
+ /* 1 byte at offset 0x00 will be overwritten for the EBIOS indicator
+ * later. This is safe because the jmp instruction only get executed
+ * once. The write happens after the jmp instruction have got
+ * executed.
+ *
+ * The value written would be 0x42 for EBIOS present(LBA) and 0x02
+ * for non-present(CHS).
+ *
+ */
+
+ /* No cli, we use stack! BIOS or caller usually sets SS:SP=0000:0400 */
+
+ jmp 1f /* FAT32/NTFS routine comes to offset 0 */
+
+ . = _start1 + 0x02
+
+ .byte 0x80 /* bit0=1: disable GRLDR search on floppy */
+ /* bit1=1: disable the boot of the previous MBR with
+ * invalid partition table */
+ /* bit2=1: disable the feature of unconditional
+ * entrance to the command-line */
+ /* bit7=1: disable the boot of the previous MBR prior
+ to the search for GRLDR */
+
+ /* GRLDR.MBR uses offset 0x03 to indicate a timer counter. */
+
+ /* 0xff indicates waiting forever,
+ * other value specifies the time in seconds to wait */
+
+ . = _start1 + 0x03
+
+ .byte 5
+
+ /* a key press to wait. if AX returned from int16 equals this word,
+ * the desired action will occur. */
+
+ . = _start1 + 0x04
+
+ .word 0x3920 /* the space bar */
+
+ . = _start1 + 0x06
+
+ .byte 0xff /* preferred boot drive number, 0xff for no-drive(i.e., drive not defined) */
+ .byte 0xff /* preferred partition number, 0xff for whole drive(a floppy that has no partition table) */
+
+ . = _start1 + 8
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* filled in by mkisofs using the -boot-info-table option */
+
+#;bi_pvd: .long 0xDEADBEEF /* LBA of primary volume descript */
+#;bi_file: .long 0xDEADBEEF /* LBA of boot file */
+#;bi_length: .long 0xDEADBEEF /* Length of boot file */
+#;bi_csum: .long 0xDEADBEEF /* Checksum of boot file */
+#;bi_reserved: .space (10*4) /* Reserved */
+
+ . = _start1 + 0x40
+
+#else
+
+ /* filled in with BPB in case the drive(typically USB) is treated as floppy by buggy BIOSes */
+
+ . = _start1 + 0x60
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+1:
+ call 1f
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ . = _start1 + 0x43
+
+#else
+
+ . = _start1 + 0x63
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+1:
+ popw %bx /* Instruction Pointer of 1b */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ subw $(1b - _start1), %bx /* CS:BX=_start1 */
+
+#else
+
+ subw $(1b - _start1), %bx /* CS:BX=_start1 */
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+ shrw $4, %bx
+ movw %cs, %ax
+ addw %ax, %bx /* BX:0000=_start1 */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* we are booted from BOOT.INI, or whole GRLDR image already loaded */
+
+ pushw %bx /* BX:0000=_start1 */
+ addw $((grldr_signature - _start1 + 4 + STAGE2_SIZE - 4) >> 4), %bx
+ movw %bx, %ds
+
+ cmpl $0xCE1A02B0, ((STAGE2_SIZE - 4) & 0x0F)
+ popw %ds /* DS:0000=_start1 */
+ je grldr_real_start /* whole image loaded. boot it! */
+
+ /* bad! we might be loaded by a buggy BIOS with a no-emulation-mode
+ * bootable CD. The buggy BIOS might load only 1 CD-ROM sector(2048
+ * bytes) of our grldr image. So we need this check.
+ */
+
+ /* Our cdrom_check code begins at 0x1BE and overlaps the partition
+ * table. Just in case someone replace it with a partition table and
+ * use this sector as an MBR, we do this additional test for safety.
+ */
+
+ /* We should avoid using opcode 0x00 and 0x80 at cdrom_check. */
+
+ /* Note that if cdrom_check code is present, then we are booting from
+ * no-emulation mode cdrom.
+ */
+
+ testb $0x7F, cdrom_check - _start1 /* is it 0x00 or 0x80? */
+ jz 1f /* yes, cdrom_check not found */
+ call cdrom_check /* no, cdrom_check is present */
+1:
+ /* DS:0000=_start1 */
+
+ /* Let CS:0000=_start1 */
+ pushw %ds
+
+ #;pushw $(1f - _start1)
+ .byte 0x6A, (1f - _start1)
+
+ lret
+ . = . - (. - _start1) / 0x80
+1:
+#else
+ /* BX:0000=_start1 */
+
+ movw %bx, %ds
+
+ /* Let CS:0000=_start1 */
+ pushw %bx
+
+ #;pushw $(1f - _start1)
+ .byte 0x6A, (1f - _start1)
+
+ lret
+ . = . - (. - _start1) / 0x80
+1:
+ testb $0x04, 0x02
+ jz 1f
+
+ /* set the DUCE indicator */
+ xorw %ax, %ax
+ movw %ax, %es
+ movw $0x5FC, %di
+ movl $0x45435544, %eax
+ stosl
+1:
+#endif
+
+ /* CS:0000=DS:0000=_start1 */
+
+ /* we are loaded by BIOS or another boot loader */
+
+#define GRLDR_CS 0x2000 /* grldr code segment */
+ /* hope this segment never be used by all */
+ /* subsequent partition boot records */
+#if 0
+ /* for single sector boot record */
+#define MONITOR 0x7e10
+#else
+ /* for 4-sector NTFS boot record */
+#define MONITOR 0x8410
+#endif
+
+// cli
+ pushw $GRLDR_CS
+ popw %ss
+ movw $0x9000, %sp /* SS:SP=0x9d000, keep away from EBDA data */
+// sti
+
+ /* Extended BIOS Data Area should not take up space below 0x9d000 */
+
+ /*
+ * 0x07c00-0x07dff This sector. Another boot loader load us here
+ * 0x0d000-0x14dff partition/floppy boot track(bootsector,etc)
+ * 0x94000-0x9bdff master boot track(MBR,etc,usually 63 sectors)
+ * 0x9be00-0x9c3ff 3 sectors for temp extended partition entries
+ * 0x9c400-0x9cfff 6 sectors for stack
+ */
+
+#define FS_BOOT 0xd00 /* segment of partition boot track */
+
+ xorw %cx, %cx
+ pushw %cx /* CX=0 */
+ movw $0x0080, %dx
+ pushw %dx
+ movb $8, %ah /* read drive parameters changes DX,ES,DI */
+ stc
+ int $0x13
+ popw %dx
+ popw %ax /* AX=0 */
+
+ pushw %ss /* SS=0x9400 */
+ popw %es /* ES=0x9400 */
+
+ jc Error1
+
+ andb $63, %cl /* AL=sectors per track, CF cleared */
+
+ stc
+ jz Error1
+
+ xchgw %ax, %cx /* this moves CL to AL, and CX=0 */
+ movb $0x02, %ah
+ movw %ax, %bp /* save AX to BP: read 1 track */
+ xorw %bx, %bx /* ES already has a known value of 0x9400 */
+ incw %cx
+ pushw %dx
+ stc
+ int $0x13 /* read master boot track to ES:0000 */
+ popw %dx
+ jc Error1
+ negb %ah /* set CF=1 if non-zero */
+Error1:
+ pushw %cs /* DS=0 */
+ popw %ds /* DS=CS */
+ pushfw /* CF=1 on error */
+
+ /* CS=DS=old segment. ES=SS=new segment. */
+
+ /* Move the code and error messages from DS:0000 to 9400:0000, do not
+ * touch the partition table
+ */
+ xorw %si, %si
+ xorw %di, %di
+ movw $223, %cx /* 223 words = 446 bytes = 0x1be bytes */
+ cld
+ repz movsw /* SI=DI=0x1be, CX=0 */
+
+ movw $(grldr_signature - _start1), %bx
+
+ /* if the boot loader has loaded more than one sector, we use them */
+ movl $0xAA555247, %eax /* "GR" 0x55 0xAA */
+//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ cmpl %eax, (%bx) /* DS=old segment! */
+ jne 1f
+
+ /* The MOVE_HELPER code is in the old segment! */
+
+ call move_helper /* SI=0x1be, CX=0 */
+1:
+//#endif
+
+ /* Jump to new segment! */
+#if 1
+ ljmp $GRLDR_CS, $(1f - _start1)
+#else
+ pushw %ss /* 0x9400 */
+
+ //pushw $(1f - _start1)
+ .byte 0x6A, (1f - _start1)
+
+ lret
+ . = . - (. - _start1) / 0x80
+#endif
+1:
+
+ /* We are at the new segment. CS=ES=SS=new segment. */
+
+ /* But DS is still old segment. */
+
+ pushw %ss
+ popw %ds
+
+ /* CS=DS=ES=SS=new segment. */
+
+ //movw $0x01be, %si
+
+ /* check the existence of helper */
+ cmpl %eax, (%bx)
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ jne Error_or_prev_MBR /* Missing helper */
+
+#else
+
+ je 1f
+
+ /* try to load helper from floppy */
+
+ pushal
+
+ movw 0x18, %ax /* BPB sectors per track at offset 0x18 */
+
+ cmpw $0x3F, %ax
+ ja 3f
+
+ cmpb $((pre_stage2_start - _start1) >> 9), %al
+ jb 3f
+
+ decw %ax /* skip the first sector already loaded */
+
+ movw $3, %di /* retry 3 times on read failure */
+2:
+ movb $2, %ah /* BIOS disk read */
+ cwd /* DX=0 for floppy head 0 */
+ movw $0x200, %bx /* ES:BX immediately follow this sector */
+ movw $2, %cx /* skip the first sector already loaded */
+
+ pushaw
+ int $0x13
+ popaw
+
+ jnc 3f
+
+ pushaw
+ xorw %ax, %ax
+ int $0x13
+ popaw
+
+ decw %di
+ jnz 2b
+3:
+ popal
+ cmpl %eax, (%bx) /* helper loaded? */
+
+ jne Error_or_prev_MBR /* Missing helper */
+
+1:
+#endif
+
+ popfw /* CF=1 on error */
+ jc try_floppy /* harddisk (hd0) failed, try floppy (fd0) */
+1:
+ pushw %cs
+ popw %ds
+ lodsw
+ movb %ah, %dh /* head number */
+ lodsw
+ movw %ax, %cx /* sector and cylinder number */
+ andb $63, %al
+ //stc
+ jz helper_call_c
+
+ /* use BP to calculate the sectors to read within 1 track */
+ subw %bp, %ax
+ decw %ax /* decb %al */
+ negb %al /* AL=sectors upto the end of the track */
+7:
+ movw $3, %di /* retry 3 times on read failure */
+2:
+ movb $2, %ah
+ pushw $FS_BOOT
+ popw %es /* ES=FS_BOOT */
+ xorw %bx, %bx
+
+ pushaw
+ int $0x13 /* read partition boot track to FS_BOOT:0000 */
+ popaw
+
+ jnc helper_call
+
+ pushaw
+ xorw %ax, %ax
+ int $0x13
+ popaw
+
+ decw %di
+ jnz 2b
+
+helper_call_c:
+
+ stc
+
+helper_call:
+ /* find GRLDR in this partition
+ * before the call:
+ * CF=1 : indicates an invalid or corrupt entry
+ * CF=0 : indicates a valid entry
+ *
+ * on return:
+ * CF=1 : means "below", try next entry
+ * CF=0,ZF=1 : means "equal", helper did nothing, so we need
+ * a further try to boot via NT bootsector
+ * CF=0,ZF=0 : means "above", helper succeeded, boot it now
+ */
+ call helper_start /* change to jmp 6f if helper not present */
+ ja filesystem_boot /* helper succeeded, directly boot it */
+6:
+
+add_sub_si:
+
+ /* extended partition check routine will adjust this to
+ *
+ * 0x83, 0xEE, 0x04 for "subw $4, %si"
+ *
+ * or
+ *
+ * 0x83, 0xC6, 0xFC for "addw $-4, %si"
+ *
+ * so that SI keeps the value 0x1fe.
+ */
+ addw $12, %si /* 0x83, 0xC6, 0x0C */
+
+ . = add_sub_si + 3
+
+ /* extended partition check routine will adjust the word 0x1fe at
+ * (add_sub_si + 5). The value 0x1ff or greater indicates there are
+ * entries need to be treated. The value 0x1fe indicates no entries
+ * left, and the floppy should be checked.
+ */
+
+ cmpw $0x01fe, %si /* 0x81, 0xFE, 0xfe, 0x01 */
+ /* All entries checked done? */
+ jb 1b /* No, check the next entry */
+ ja 5f /* floppy already checked. Fail and hang */
+
+try_floppy:
+
+ movw $0x31b2, %si /* a value big enough */
+ movb $0x08, %ah /* read drive parameters changes DX,ES,DI */
+ cwd /* DL=0 for floppy */
+ pushw %dx /* DX=0 */
+ int $0x13
+ popw %ax /* AX=0 */
+ jc 5f /* floppy failure, issue "Error" and hang */
+ cwd /* DX=0 */
+ xchgw %ax, %cx /* this moves CL to AL, and CX=0 */
+ andb $63, %al /* AL=sectors per track */
+ jz 5f /* invalid value. floppy failure. hangs */
+ //movw $1, %cx
+ incw %cx
+ jmp 7b
+
+5:
+Error_or_prev_MBR:
+
+ /* GRLDR not found, print "Error" or launch previous MBR */
+ movw $(message_string - _start1), %si
+Error2:
+ call print_message /* CS:SI points to message string */
+3: jmp 3b
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+filesystem_boot:
+ /* The partition boot record successfully modified, just boot it */
+
+ /*
+ * The boot might fail, but we want to take back the control.
+ * So we save the registers now.
+ */
+ pushw %ds
+ pushw %es
+ pushal
+
+ /* DS=CS=GRLDR_CS, ES=FS_BOOT */
+
+ /* save GRLDR_CS */
+
+ movw %es, %bx # save old ES to BX
+
+ cli
+ lgdt gdt - _start1
+ movl %cr0, %eax
+ orb $1, %al
+ movl %eax, %cr0
+
+ movw $8, %si
+ movw %si, %es
+
+ xorl %esi, %esi
+ xorl %edi, %edi
+ movl $(0x9000 / 4), %ecx
+
+ cld
+ repz movsl
+
+ movw $16, %si
+ movw %si, %es
+
+ andb $0xfe, %al
+ movl %eax, %cr0
+
+ movw %bx, %es # restore ES from BX
+
+ /* move FS_BOOT:0000 to 0:7c00 */
+#if 0
+ /* for single sector boot record */
+ movw $0x0200, %cx /* move 2 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#else
+ /* for 4-sector NTFS boot record */
+ movw $0x0400, %cx /* move 4 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#endif
+ xorw %si, %si
+ pushw %si /* SI=0, for the segment of 0000:7c00 */
+ movw $0x7c00, %di
+ pushw %di /* DI=0x7c00, for the offset of 0000:7c00 */
+ pushw %es /* ES=FS_BOOT */
+ popw %ds /* DS=FS_BOOT */
+ pushw %si /* SI=0 */
+ popw %es /* ES=0 */
+ cld
+ repz movsw
+
+ movw $MONITOR, %di
+ movw $(restore_GRLDR_CS - _start1), %si
+ movw $((gdt_end - restore_GRLDR_CS) / 4), %cx
+ cld
+ repz cs movsl /* CS segment override prefix(=0x2E) */
+
+ pushw %es /* ES=0 */
+ popw %ds /* DS=0 */
+ sti
+ lret //ljmp $0, $0x7c00
+#endif
+
+try_next_partition:
+
+ cli
+ movw $GRLDR_CS, %ax
+ movw %ax, %ss
+ movw $(0x9000-36), %sp
+ sti
+
+ /* restore the registers and continue */
+ popal
+ popw %es
+ popw %ds
+ jmp add_sub_si
+
+ /* prints string CS:SI (modifies AX BX SI) */
+3:
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print char in AL */
+ int $0x10 /* via TTY mode */
+
+print_message:
+
+ lodsb %cs:(%si), %al /* get token */
+ cmpb $0, %al /* end of string? */
+ jne 3b
+ ret
+
+message_string:
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ .ascii "\r\nMissing helper.\0"
+#else
+ .ascii "\r\nMissing MBR-helper.\0"
+#endif
+
+#;buggy_bios_string:
+#;
+#; .ascii "\r\nBuggy BIOS!\0"
+
+ /* Make sure the above code does not occupy the partition table */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ /* offset value here must be less than or equal to 0x1be */
+ . = . - ((. - _start1) / 0x1bf)
+#else
+ /* offset value here must be less than or equal to 0x1b8 */
+ . = . - ((. - _start1) / 0x1b9)
+#endif
+
+ /* The following code may occupy the same area as the partition table */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* we are not booted from MBR. So we can reuse the area of partition
+ * table for our code.
+ */
+
+ . = _start1 + 0x1be
+
+cdrom_check:
+
+ /* DS points to the sector start, but CS does not. */
+
+ /* BX segment points to near the end of GRLDR image. */
+
+ popw %ax /* old return IP */
+
+ /* set BX as the new safe stack. */
+ movw %bx, %ss
+ movw $0xFFF0, %sp
+
+ pushw %ax /* old return IP */
+
+ /* check if DL is no-emulation-mode bootable CDROM. */
+ pushw %ds
+
+ cmpb $0x80, %dl
+ jb 1f /* not a valid no-emulation-mode cdrom drive number */
+
+ cmpw $0xAA55, 0x7FE /* 2048 bytes loaded? */
+ jne 1f
+
+// cmpw $0xAA55, 0x5FE /* 2048 bytes loaded? */
+// jne 1f
+
+ movw $0x0180, %si
+ movw $0x4B01, %ax
+ pushw $0x0040
+ //.byte 0x6A, 0x40
+ popw %ds
+ pushw %ds
+ popw %es
+ movb $0x13, (%si)
+ int $0x13
+
+ /* ignore CF */
+#; jc 2f /* not in emulation mode */
+ xorl %eax, %eax
+ xorw %bp, %bp
+ testb $0x0F, 1(%si) /* boot media type is No Emulation? */
+ jnz 2f /* no, it simulates floppy or hard disk. */
+ cmpb %dl, 2(%si) /* drive number */
+ jnz 2f /* invalid drive */
+
+ /* OK! it is no-emulation-mode cdrom drive. */
+ movl 4(%si), %eax /* LBA of GRLDR */
+ incw %bp
+
+2:
+ jmp cdrom_helper
+1:
+ popw %ds
+ ret
+
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+ . = _start1 + 0x1fe /* boot signature */
+
+/* partition entries in the extended partitions will overwrite code here upto
+ * 0x3fd.
+ *
+ * the extended partition entries will occupy a temp area at 0x9be00-0x9c3ff
+ */
+
+#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
+ .word 0xaa55
+#endif
+
+ . = _start1 + 0x200
+
+/* if it is in the Master Boot Track, the second sector can be used to backup
+ * the previously working MBR, typically, the MS MBR. if the backup copy of
+ * the MBR cannot boot(because, e.g., it depends on another sector of code
+ * that does not exist for now), then please do not set the ending signature
+ * to 0xAA55, that is to say, if the signature is already 0xAA55, you should
+ * change it to another value(for example, 0x0000).
+ */
+
+#if (! defined(GRLDR_INSTALL))
+#if 0
+print_cl:
+ pushaw
+
+ movw %cx, %ax
+ movb $16, %cl
+ divb %cl # quo=AL, rem=AH
+ orw $0x3030, %ax
+
+ cmpb $0x39, %ah
+ jbe 1f
+ addb $7, %ah
+1:
+ cmpb $0x39, %al
+ jbe 1f
+ addb $7, %al
+1:
+ movb %ah, %cl
+
+ xorw %bx, %bx
+
+ movb $0x0e, %ah
+ int $0x10
+
+ movb $0x0e, %ah
+ movb %cl, %al
+ int $0x10
+
+ movw $0x0e20, %ax
+ int $0x10
+
+ popaw
+ ret
+#else
+#if 0
+ .word 5, 0x47, 0x52, 0x4c, 0x44, 0x52, 4, 0x24
+ .word 0x49, 0x33, 0x30, 0xe000, 0, 0x3000, 0, 0
+#else
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+#endif
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+#endif
+ . = _start1 + 0x256 /* cmdcons comes here */
+
+#if 0
+ jmp 1f
+#else
+ .byte 0x90, 0x90
+#endif
+
+ . = _start1 + 0x258
+
+ .byte 0x90, 0x90
+
+ . = _start1 + 0x25a
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ . = _start1 + 0x26a
+1:
+ //movw %cs, %ax
+ //movw %ax, %ds
+ //jmp single_boot_sector
+
+ /* a value < 0x80 here means we are not booted from no-emulation-mode
+ * bootable CD.
+ */
+ movb $0x7F, %dl
+ jmp _start1
+
+#endif /* (! defined(GRLDR_INSTALL)) */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+cdrom_helper:
+
+ /* IP and old_DS is on the stack. */
+
+ /* DS=ES=40h */
+
+ /* Stack is high and safe. */
+
+ /* EAX is LBA. if EAX==0, LBA is unknown. */
+
+ /* check if the first sector is the same as the current one */
+
+ /* load the first sector onto the sector immediately follows */
+1:
+ popw %bx /* BX = old_DS = load_segment */
+ pushw %bx
+ movw %bx, %es
+ addw $0x0080, %bx /* buffer segment */
+ call load_cd_sector
+
+ /* compare the two sectors */
+ movw $0x200, %cx
+ movw %bx, %ds
+ xorw %si, %si
+ xorw %di, %di
+ cld
+ repz cmpsl
+ je load_the_rest /* 1st sector is ok, continue */
+not_grldr:
+ testw %bp, %bp
+ jz 2f
+ xorw %bp, %bp
+ xorl %eax, %eax
+2:
+ incl %eax
+ jnz 1b /* try next */
+
+cd_no_grldr:
+
+ popw %ds /* DS=load_segment */
+
+ # Here we use error message and routine in FAT32 boot sector
+ # which is also inside the 2048-byte CD sector.
+
+ movw $(msg_BootError_32 - _start1), %si
+ jmp boot_error_32
+
+load_cd_sector:
+ /* input: EAX LBA
+ * BX buffer segment(buffer offset=0)
+ * DS 0x40 (or another safe one)
+ */
+
+ movw $0x1A0, %si
+
+ /* disk address packet */
+ movl $0x00010010, (%si) /* load 1 sector each time. */
+ movw $0, 4(%si) /* buffer offset=0 */
+ movw %bx, 6(%si) /* buffer segment */
+ movl %eax, 8(%si) /* LBA lo 32 bits */
+ movl $0, 12(%si) /* LBA hi 32 bits */
+
+ pushal
+ movb $0x42, %ah
+ int $0x13
+ popal
+ ret
+
+load_the_rest:
+
+ /* load all sectors (except the first one) */
+
+ /* EAX = first sector(LBA) of GRLDR */
+
+ popw %bx /* BX = old_DS = load_segment */
+ pushw %bx
+ movw %bx, %es
+ /* 6144 = 0x1800 = 3 sectors > 4KB, this is for the additional 4KB-preset-menu at the end of grldr */
+ movw $((grldr_signature - _start1 + 4 + STAGE2_SIZE - 1 + 6144) / 2048), %cx /* sectors to load */
+1:
+ incl %eax /* next sector */
+ addw $0x0080, %bx /* buffer segment */
+
+ call load_cd_sector
+
+ loop 1b
+
+ /* loading is completed. BX=segment of the last sector. */
+
+ subw $0x0181, %bx /* decw %bx */
+ movw %bx, %ds
+
+ /* check the ending signature */
+ cmpl $0xCE1A02B0, ((grldr_signature - _start1 + 4 + STAGE2_SIZE - 1) % 2048) + 13
+ jne not_grldr
+#; je grldr_real_start /* yes. boot it! */
+
+#; /* it is not our grldr image, return and use MBR-helper. */
+#;
+#;4:
+#; //jmp grldr_real_start
+#; popw %ds
+#; ret
+
+grldr_real_start:
+
+ #; FAT_12_16 no longer be used. So comment out.
+ #;je 1f /* jc 1f */
+ #;//ZF=0 /* CF cleared, so we are coming from FAT_12_16 */
+ #;popw %dx /* discard the cluster number */
+ #;popw %dx /* this is our boot_drive/boot_partition */
+ #;1:
+
+ #; The partition number for no-emulation-mode bootable CDROM will be
+ #; set to 0xFF later(in common.c). So comment out.
+ #;cli
+ #;movw %cs, %ax
+ #;cmpw $0x1000, %ax
+ #;jne 1f
+ #;
+ #;/* CS=0x1000, may be booted from ext2 or no-emulation-mode CDROM */
+ #;
+ #;cmpw $0x1000, %di
+ #;jne 2f
+ #;cmpw $0x7c00, %bp
+ #;jne 2f
+ #;movw %es, %ax
+ #;cmpw $0x1000, %ax
+ #;jbe 2f
+ #;cmpw $0x7c00, %si
+ #;jbe 2f
+ #;movl %edx, %eax
+ #;shrl $16, %eax
+ #;jnz 2f
+ #;jecxz 1f // booted from ext2 partition
+ #;2:
+ #;// booted from no-emulation-mode bootable CDROM
+ #;movb $0xff, %dh // partition 0xff means whole drive(for CDROM)
+ #; #; if needed, 0xfe can be used as an indicator
+ #; #; here for the bootable CDROM and changed to
+ #; #; 0xff later.
+ #;1:
+ #;
+ #;//if not booted from CDROM, don't touch the boot partition number(dh)
+
+ cli
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $0x0400, %sp /* tmp use real-mode IDT as stack */
+ movw %cs, %bp /* save CS to BP */
+ call 1f
+1:
+ popw %bx /* BX=Instruction Pointer of 1b */
+ subw $(1b - _start1), %bx
+ movw %bx, %cx
+ shrw $4, %bx
+ addw %bp, %bx
+ pushw %bx /* new CS */
+ andw $0x000f, %cx
+ addw $(1f - _start1), %cx
+ pushw %cx /* new IP */
+ lret
+1:
+ pushw %cs
+ popw %ds
+
+ /* CS=DS=BX, CS:0000 = _start1 */
+
+ addw $((pre_stage2_start - _start1) >> 4), %bx
+
+ /* BX:0000 = pre_stage2_start */
+
+ cmpw $0x820, %bx
+ jb 2f
+
+ movw $((0x8200 - (pre_stage2_start - _start1) - 0x400) >> 4), %cx
+
+ /* Now CS(=DS) >= CX+0x40 */
+
+ movw %cx, %es
+ xorw %di, %di
+ xorw %si, %si
+
+ /////////////////////////////////////////////////////////////
+ //
+ // CS
+ // DS 0x820 BX
+ // _start1---------------pre_stage2_start
+ // CX+0x40---------------0x820
+ // CX
+ // ES
+ //
+ /////////////////////////////////////////////////////////////
+
+ movw $0x200, %cx /* move 2 sectors */
+ cld
+ repz movsw
+
+ pushw %es /* ES:0000 = _start */
+ pushw $(1f - _start)
+ lret /* CS=ES, CS:0000 = _start1 */
+1:
+
+ /* move BX:0000 to 0820:0000 upward since BX >= 0x820 */
+
+ cld
+
+ movw %bx, %ds
+ movw $0x820, %bx
+ movw %bx, %es
+
+ xorw %si, %si
+ xorw %di, %di
+
+ movw $6, %bx /* 64K pages: 0x20000 - 0x7ffff */
+1:
+ movw $0x8000, %cx
+ repz movsw
+ movw %ds, %ax
+ addw $0x1000, %ax
+ movw %ax, %ds
+ movw %es, %ax
+ addw $0x1000, %ax
+ movw %ax, %es
+ decw %bx
+ jnz 1b
+
+ jmp 3f
+2:
+
+ /* move BX:0000 to 0820:0000 downward since BX < 0x820 */
+
+ std
+
+ addw $0x7000, %bx
+ movw %bx, %ds
+ movw $0x7820, %bx
+ movw %bx, %es
+
+ movw $0xfffe, %si
+ movw %si, %di
+
+ movw $8, %bx /* 64K pages: 0x08200 - 0x881ff */
+1:
+ movw $0x8000, %cx
+ repz movsw
+ movw %ds, %ax
+ subw $0x1000, %ax
+ movw %ax, %ds
+ movw %es, %ax
+ subw $0x1000, %ax
+ movw %ax, %es
+ decw %bx
+ jnz 1b
+
+ cld
+
+3:
+
+ /* put the config file name */
+ xorw %ax, %ax
+ movw %ax, %es
+ movw %ax, %ds
+
+ xorl %ebp, %ebp
+
+ movb %dh, 0x820A /* this is the boot partition number */
+
+ #; clear saved_entryno so that force_cdrom_as_boot_device be cleared
+ #; later in common.c
+
+ movl %ebp, 0x820C /* EBP=0, clear saved_entryno */
+
+ movw $0x0010, %cx /* set max length of grub version string */
+ movw $0x8212, %di /* version string */
+ cld
+ /* AL is already 0. Locate the end of version string */
+ repnz scasb /* find the location of the default config file name */
+
+ jcxz 1f /* failed, will not use the default config file name */
+
+ movw $0x4e, %cx /* max length of config file name */
+
+ movw %cs, %si /* CS:0000 = _start1 */
+ shlw $4, %si /* 0000:SI = _start1 */
+
+ addw $(default_config_file - _start1), %si
+
+ //movw $(default_config_file + 0x8200 - pre_stage2_start), %si
+ cld
+ repz movsb /* move file name to the config-file field of stage2 */
+1:
+
+ movw $0x0003, %ax /* set display mode: 80*25 color text */
+ int $0x10
+
+ xorw %bx, %bx
+ movw $(launch_pre_stage2 - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $0x2000, %sp
+
+ sti
+
+ ljmp $0, $0x8200
+
+launch_pre_stage2:
+ .ascii "\r\n\r\nBooting GRLDR...\r\n"
+
+ .byte 0 /* mark the end of ascii zero string */
+
+default_config_file:
+//#ifndef PRESET_MENU_STRING
+ .ascii "/menu.lst"
+//#else
+// .ascii "[default menu is disabled]"
+//#endif
+
+ .byte 0 /* mark the end of ascii zero string */
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+ . = _start1 + 0x400
+
+#define ALTERNATIVE_KERNEL
+
+
+/*
+ * The following is based on FreeDOS, modified heavily by Tinybit in Feb, 2004
+ *
+ * Merges LBA and CHS boot sectors to ONE FAT32 boot sector!
+ *
+ * Memory layout for GRLDR FAT32 single stage boot process:
+ *
+ * ...
+ * |-------| 1FE0:7E00
+ * |BOOTSEC| (GRUB does not use this relocation area)
+ * |RELOC. | (overwritten by kernel loaded)
+ * |-------| 1FE0:7C00
+ * ...
+ * |-------|
+ * |KERNEL | (overwrites bootsec reloc.)
+ * |LOADED | (holds 1 sector directory buffer before kernel load)
+ * |-------| 2000:0000
+ * ...
+ * |-------| 0000:7E00
+ * |BOOTSEC| GRUB always run inside this sector,
+ * |ORIGIN | no relocation.
+ * |-------| 0000:7C00
+ * ...
+ * |-------| 0060:0200
+ * | FAT | (only 1 sector buffered)
+ * |-------| 0060:0000
+ * ...
+ *
+ */
+
+/*
+; This is an LBA-enabled FreeDOS FAT32 boot sector (single sector!).
+; You can use and copy source code and binaries under the terms of the
+; GNU Public License (GPL), version 2 or newer. See www.gnu.org for more.
+
+; Based on earlier work by FreeDOS kernel hackers, modified heavily by
+; Eric Auer and Jon Gentle in 7 / 2003.
+;
+; Features: Uses LBA and calculates all variables from BPB/EBPB data,
+; thus making partition move / resize / image-restore easier. FreeDOS
+; can boot from FAT32 partitions which start > 8 GB boundary with this
+; boot sector. Disk geometry knowledge is not needed for booting.
+;
+; Windows uses 2-3 sectors for booting (sector stage, statistics sector,
+; filesystem stage). Only using 1 sector for FreeDOS makes multi-booting
+; of FreeDOS and Windows on the same filesystem easier.
+;
+; Requirements: LBA BIOS and 386 or better CPU. Use the older CHS-only
+; boot sector if you want FAT32 on really old PCs (problems: you cannot
+; boot from > 8 GB boundary, cannot move / resize / ... without applying
+; SYS again if you use the CHS-only FAT32 boot sector).
+;
+; FAT12 / FAT16 hints: Use the older CHS-only boot sector unless you
+; have to boot from > 8 GB. The LBA-and-CHS FAT12 / FAT16 boot sector
+; needs applying SYS again after move / resize / ... a variant of that
+; boot sector without CHS support but with better move / resize / ...
+; support would be good for use on LBA harddisks.
+
+
+; Memory layout for the FreeDOS FAT32 single stage boot process:
+
+; ...
+; |-------| 1FE0:7E00
+; |BOOTSEC|
+; |RELOC. |
+; |-------| 1FE0:7C00
+; ...
+; |-------| 2000:0200
+; | FAT | (only 1 sector buffered)
+; |-------| 2000:0000
+; ...
+; |-------| 0000:7E00
+; |BOOTSEC| overwritten by the kernel, so the
+; |ORIGIN | bootsector relocates itself up...
+; |-------| 0000:7C00
+; ...
+; |-------|
+; |KERNEL | maximum size 134k (overwrites bootsec origin)
+; |LOADED | (holds 1 sector directory buffer before kernel load)
+; |-------| 0060:0000
+; ...
+*/
+
+#define BOOTGRUB /* undef this if compiled for loading FreeDOS */
+//#undef BOOTGRUB
+
+#ifdef BOOTGRUB
+#define LOADSEG 0x2000
+#define FATSEG 0x0060
+#else
+#define LOADSEG 0x0060
+#define FATSEG 0x2000
+#endif
+
+Entry_32:
+ jmp 1f
+
+ . = Entry_32 + 0x02
+
+ /* The default mode is CHS. This is for maximum compatiblity with
+ * small-sized disks, e.g., floppies.
+ *
+ * Valid values are 0x90 for CHS mode, or 0x0e for LBA mode.
+ *
+ * If the BIOS int13 supports LBA, this byte can be safely set to 0x0e.
+ *
+ * Some USB BIOSes might have bugs when using CHS mode, so the format
+ * program should set this byte to 0x0e. It seems that (generally) all
+ * USB BIOSes have LBA support.
+ *
+ * If the format program does not know whether the BIOS has LBA
+ * support, it may operate this way:
+ *
+ * if (partition_start + total_sectors_in_partition) exceeds the CHS
+ * addressing ability(especially when it is greater than 1024*256*63),
+ * the caller should set this byte to 0x0e, otherwise, set to 0x90.
+ */
+
+ .byte 0x90 /* for CHS. Another possible value is 0x0e for LBA */
+
+
+ . = Entry_32 + 0x03
+
+#ifdef BOOTGRUB
+ .ascii "GRLDR " /* OEM name string (of OS which formatted the disk). */
+#endif
+
+ . = Entry_32 + 0x0b
+
+ .word 0x200 /* bytes per sector. Must be 512 */
+
+ . = Entry_32 + 0x0d
+
+ /* Sectors per cluster. Valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
+ * But a cluster size larger than 32K should not occur.
+ */
+
+ .byte 1 /* sectors per cluster */
+
+ . = Entry_32 + 0x0e
+
+ /* Reserved sectors(number of sectors before the first FAT,
+ * including the boot sector), usually 1.
+ */
+
+ .word 1 /* reserved sectors */
+
+ . = Entry_32 + 0x10
+
+ /* Number of FATs(nearly always 2). */
+
+ .byte 2 /* number of FATs */
+
+ . = Entry_32 + 0x11
+
+ /* (Maximum number of root directory entries)Must be 0. */
+
+ .word 0 /* Max dir entries for FAT12/FAT16 */
+
+ . = Entry_32 + 0x13
+
+ /* (Total number of sectors for small disks only)Must be 0. */
+
+ .word 0 /* total sectors for FAT12/FAT16 */
+
+ . = Entry_32 + 0x15
+
+ /* Media descriptor byte, pretty meaningless now. */
+
+ .byte 0xf8 /* media descriptor */
+
+ . = Entry_32 + 0x16
+
+ /* (Sectors per FAT)Must be 0. */
+
+ .word 0 /* sectors per FAT for FAT12/FAT16 */
+
+ . = Entry_32 + 0x18
+
+ .word 18 /* sectors per track */
+
+ . = Entry_32 + 0x1a
+
+ .word 2 /* number of heads */
+
+ . = Entry_32 + 0x1c
+
+ /* Number of hidden sectors (those preceding the boot sector).
+ * Also referred to as the starting sector of the partition.
+ * For floppies, it should be 0.
+ */
+
+ .long 0 /* hidden sectors */
+
+ . = Entry_32 + 0x20
+
+ /* Total number of sectors in the filesystem. */
+
+ .long 0 /* total sectors for FAT32 */
+
+ . = Entry_32 + 0x24
+
+ /* FAT32 sectors per FAT. */
+
+ .long 0
+
+ . = Entry_32 + 0x28
+
+ /* If bit 7 is clear then all FATs are updated, otherwise bits 0-3
+ * give the current active FAT, all other bits are reserved.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 0
+
+ . = Entry_32 + 0x2a
+
+ /* High byte is major revision number, low byte is minor revision
+ * number, currently both are 0.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 0
+
+ . = Entry_32 + 0x2c
+
+ /* Root directory starting cluster. */
+
+ .long 0
+
+ . = Entry_32 + 0x30
+
+ /* File system information sector number.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 0
+
+ . = Entry_32 + 0x32
+
+ /* If non-zero this gives the sector which holds a copy of the
+ * boot record, usually 6.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 6
+
+ . = Entry_32 + 0x34
+
+ /* Reserved, 12 bytes, set to 0. */
+
+ .long 0
+ .long 0
+ .long 0
+
+ . = Entry_32 + 0x40
+
+ /* drive number of the boot device.
+ * This byte is ignored for read. The program will write DL onto
+ * this byte. The caller should set drive number in DL.
+ * We assume all BIOSes pass correct drive number in DL.
+ * That is to say, buggy BIOSes are not supported!!
+ */
+
+ .byte 0
+
+ . = Entry_32 + 0x41
+
+ /* partition number of this filesystem in the boot drive.
+ * This byte is ignored for read. The boot code will write partition
+ * number onto this byte. See Entry + 0x5d below.
+ */
+
+ .byte 0
+
+ . = Entry_32 + 0x42
+
+ /* Signature (must be 28h or 29h to be recognised by NT). */
+
+ .byte 0x29 /* extended boot signature for FAT12/FAT16 */
+
+ . = Entry_32 + 0x43
+
+ .long 0x0AC4AF63 /* volume serial number */
+
+ . = Entry_32 + 0x47
+
+ .ascii "NO NAME " /* volume label, 11 bytes. */
+
+ . = Entry_32 + 0x52
+
+ .ascii "FAT32 " /* filesystem ID, 8 bytes. */
+
+/*
+; bp is initialized to 7c00h
+; %define bsOemName bp+0x03 ; OEM label (8)
+%define bsBytesPerSec bp+0x0b ; bytes/sector (dw)
+%define bsSecPerClust bp+0x0d ; sectors/allocation unit (db)
+%define bsResSectors bp+0x0e ; # reserved sectors (dw)
+%define bsFATs bp+0x10 ; # of fats (db)
+; %define bsRootDirEnts bp+0x11 ; # of root dir entries (dw, 0 for FAT32)
+ ; (FAT32 has root dir in a cluster chain)
+; %define bsSectors bp+0x13 ; # sectors total in image (dw, 0 for FAT32)
+ ; (if 0 use nSectorHuge even if FAT16)
+; %define bsMedia bp+0x15 ; media descriptor: fd=2side9sec, etc... (db)
+; %define sectPerFat bp+0x16 ; # sectors in a fat (dw, 0 for FAT32)
+ ; (FAT32 always uses xsectPerFat)
+%define sectPerTrack bp+0x18 ; # sectors/track
+; %define nHeads bp+0x1a ; # heads (dw)
+%define nHidden bp+0x1c ; # hidden sectors (dd)
+; %define nSectorHuge bp+0x20 ; # sectors if > 65536 (dd)
+%define xsectPerFat bp+0x24 ; Sectors/Fat (dd)
+ ; +0x28 dw flags (for fat mirroring)
+ ; +0x2a dw filesystem version (usually 0)
+%define xrootClst bp+0x2c ; Starting cluster of root directory (dd)
+ ; +0x30 dw -1 or sector number of fs.-info sector
+ ; +0x32 dw -1 or sector number of boot sector backup
+ ; (+0x34 .. +0x3f reserved)
+%define drive bp+0x40 ; Drive number
+ bp+0x41 ; partition number for GRLDR
+
+%define fat_sector bp+0x44 ; last accessed FAT sector (dd)
+ ; (overwriting unused bytes)
+%define fat_start bp+0x48 ; first FAT sector (dd)
+ ; (overwriting unused bytes)
+%define data_start bp+0x4c ; first data sector (dd)
+ ; (overwriting unused bytes)
+
+*/
+ /* not used: [0x42] = byte 0x29 (ext boot param flag)
+ * [0x43] = dword serial
+ * [0x47] = label (padded with 00, 11 bytes)
+ * [0x52] = "FAT32",32,32,32 (not used by Windows)
+ * ([0x5a] is where FreeDOS parts start)
+ */
+
+ . = Entry_32 + 0x5a
+1:
+ cli
+ cld
+
+#ifdef BOOTGRUB
+
+ . = Entry_32 + 0x5c
+
+ /* the byte at offset 0x5d stores the real partition number for read.
+ * the format program or the caller should set it to a correct value.
+ * For floppies, it should be 0xff, which stands for whole drive.
+ */
+
+ movb $0xff, %dh /* boot partition number */
+
+ cmpb $0xff, %dh /* is floppy? */
+ jne 1f
+ movb $0, %dl /* yes, let drive number = 0 */
+1:
+#endif
+
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw $0x7c00, %bp
+
+#ifdef BOOTGRUB
+ movw %ax, %es
+#else
+ movw $0x1fe0, %ax
+ movw %ax, %es
+ movw %bp, %si /* move from 0000:7c00 */
+ movw %bp, %di /* move to 1fe0:7c00 */
+ movw $0x0100, %cx /* one sector to move */
+ repz movsw
+ ljmp $0x1fe0, $(1f - Entry_32 + 0x7c00)
+1:
+ movw %ax, %ds
+#endif
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+ movw %dx, 0x40(%bp) /* BIOS passes drive number in DL */
+
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xAA55, %bx
+ jne 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ /* EBIOS supported */
+ movb $0x42, (ebios_32 - 1 - Entry_32 + 0x7c00)
+1:
+
+/* figure out where FAT and DATA area starts
+ * (modifies EAX EDX, sets fat_start and data_start variables)
+ */
+ xorl %eax, %eax
+ movl %eax, 0x44(%bp) /* init buffer status */
+
+ /* first, find fat_start */
+ movw 0x0e(%bp), %ax /* reserved sectors */
+ addl 0x1c(%bp), %eax /* hidden sectors */
+ movl %eax, 0x48(%bp) /* first FAT sector */
+ movl %eax, 0x4c(%bp) /* first data sector, initial value */
+
+ /* next, find data_start */
+ movl 0x10(%bp), %eax /* number of fats, no movzbl needed: the
+ 2 words after 0x10(%bp) are 0 for fat32 */
+ mull 0x24(%bp) /* sectors per fat (EDX=0) */
+ addl %eax, 0x4c(%bp) /* first DATA sector */
+
+/* Searches for the file in the root directory.
+ * Returns: EAX = first cluster of file
+ */
+
+ movl 0x2c(%bp), %eax /* root dir cluster */
+
+1:
+ pushl %eax /* save cluster */
+ call cluster_to_lba_32
+ /* EDX is sectors per cluster, EAX is sector number */
+ movw $(msg_BootError_32 - Entry_32 + 0x7c00), %si
+ jc boot_error_32 /* EOC encountered */
+
+2:
+ lesw (loadseg_off_32 - Entry_32)(%bp), %bx /* load to loadseg:0 */
+ call readDisk_32
+
+ xorw %di, %di
+
+ /* Search for kernel file name, and find start cluster */
+3:
+ movw $11, %cx
+ movw $(filename_32 - Entry_32 + 0x7c00), %si
+ repz cmpsb
+ jz 1f /* note that di now is at dirent+11 */
+
+ addw $0x20, %di
+ andw $-0x20, %di /* 0xffe0 */
+ cmp 0x0b(%bp), %di /* bytes per sector */
+ jnz 3b /* next directory entry */
+
+ decw %dx /* initially DX holds sectors per cluster */
+ jnz 2b /* loop over sectors in cluster */
+
+ popl %eax /* restore current cluster */
+ call next_cluster_32
+ jmp 1b /* read next cluster */
+
+#ifndef ALTERNATIVE_KERNEL
+loadseg_off_32:
+ .word 0
+ .word LOADSEG
+#endif
+
+1:
+ /* kernel directory entry is found */
+ pushw %es:(0x14-11)(%di) /* get cluster number HI */
+ pushw %es:(0x1a-11)(%di) /* get cluster number LO */
+ popl %eax /* convert to 32bit */
+
+ xorw %bx, %bx /* read kernel at ES:BX=LOADSEG:0 */
+
+/* read kernel */
+
+2:
+ pushl %eax
+ call cluster_to_lba_32
+ /* EDX is sectors per cluster, EAX is sector number */
+ jnc 1f
+
+ /* EOC encountered - done */
+#ifdef BOOTGRUB
+ movw 0x40(%bp), %dx /* boot_drive and boot_partition */
+#else
+ movb 0x40(%bp), %bl /* FreeDOS kernel uses BL, not DL, for drive */
+#endif
+ ljmp *(loadseg_off_32 - Entry_32)(%bp)
+
+1:
+ call readDisk_32
+ decw %dx /* initially DX holds sectors per cluster */
+ jnz 1b /* loop over sectors in cluster */
+
+ popl %eax
+ call next_cluster_32
+ jmp 2b
+
+/* given a cluster number, find the number of the next cluster in
+ * the FAT chain. Needs fat_start.
+ * input: EAX - cluster
+ * EDX = 0
+ * output: EAX - next cluster
+ * EDX = undefined
+ */
+
+next_cluster_32:
+ pushw %es
+ /* pushw %di */
+ pushw %bx /* hi word of EBX never used */
+
+#if 1
+ /* xorl %edx, %edx */
+ shll $2, %eax /* 32bit FAT */
+ movzwl 0x0b(%bp), %ebx /* bytes per sector */
+ divl %ebx /* residue is in EDX */
+ /* movw %dx, %di */
+#else
+ shll $2, %eax /* 32bit FAT */
+ ;xchgw %ax, %di /* movw %ax, %di */
+ movw %ax, %di
+ ;shlw $2, %di /* 32bit FAT */
+
+ pushw %cx
+ movw 0x0b(%bp), %bx /* bytes per sector */
+ bsfw %bx, %cx
+ ;decw %cx
+ ;decw %cx
+ decw %bx
+ andw %bx, %di /* mask to sector size */
+ shrl %cl, %eax
+ popw %cx
+#endif
+ addl 0x48(%bp), %eax /* add the first FAT sector number.
+ EAX is absolute sector number now */
+ movw $FATSEG, %bx
+ movw %bx, %es
+ xorw %bx, %bx
+
+ cmpl 0x44(%bp), %eax /* is it the last accessed and already buffered
+ FAT sector? */
+ jz 1f
+ movl %eax, 0x44(%bp) /* mark sector EAX as buffered */
+ call readDisk_32 /* read sector EAX to buffer */
+1:
+#if 1
+ //.byte 0x67, 0x26, 0x80, 0x62, 0x03, 0x0f
+ addr32 andb $0x0f, %es:3(%edx) /* mask out top 4 bits */
+
+ //.byte 0x67, 0x66, 0x26, 0x8b, 0x02
+ addr32 movl %es:(%edx), %eax /* read next cluster number */
+#else
+ andb $0x0f, %es:3(%di) /* mask out top 4 bits */
+ movl %es:(%di), %eax /* read next cluster number */
+#endif
+ popw %bx
+ /* popw %di */
+ popw %es
+ ret
+
+/* Convert cluster number to the absolute sector number
+ * ... or return carry if EndOfChain! Needs data_start.
+ * input: EAX - target cluster
+ * output: EAX - absolute sector
+ * EDX - [bsSectPerClust] (byte)
+ * carry clear
+ * (if carry set, EAX/EDX unchanged, end of chain)
+ */
+
+cluster_to_lba_32:
+ cmpl $0x0ffffff8, %eax /* check End Of Chain */
+ cmc
+ jb 1f /* carry is stored if EOC */
+
+ /* sector = (cluster-2) * clustersize + data_start */
+ decl %eax
+ decl %eax
+
+ movzbl 0x0d(%bp), %edx /* sectors per cluster */
+ pushw %dx /* only DX would change */
+ mull %edx /* EDX = 0 */
+ popw %dx
+ addl 0x4c(%bp), %eax /* data_start */
+ /* here, carry is cleared (unless parameters are wrong) */
+1:
+ ret
+
+/* Read a sector from disk, using LBA or CHS
+ * input: EAX - 32-bit DOS sector number
+ * ES:BX - destination buffer
+ * (will be filled with 1 sector of data)
+ * output: ES:BX points one byte after the last byte read.
+ * EAX - next sector
+ */
+
+readDisk_32:
+ pushal
+ xorl %edx, %edx /* EDX:EAX = LBA */
+ pushl %edx /* hi 32bit of sector number */
+ pushl %eax /* lo 32bit of sector number */
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ pushw $1 /* 1 sector to read */
+ pushw $16 /* size of this parameter block */
+
+ xorl %ecx, %ecx
+ pushl 0x18(%bp) /* lo:sectors per track, hi:number of heads */
+ popw %cx /* ECX = sectors per track */
+ divl %ecx /* residue is in EDX */
+ /* quotient is in EAX */
+ incw %dx /* sector number in DL */
+ popw %cx /* ECX = number of heads */
+ pushw %dx /* push sector number into stack */
+ xorw %dx, %dx /* EDX:EAX = cylinder * TotalHeads + head */
+ divl %ecx /* residue is in EDX, head number */
+ /* quotient is in EAX, cylinder number */
+ xchgb %dl, %dh /* head number should be in DH */
+ /* DL = 0 */
+ popw %cx /* pop sector number from stack */
+ xchgb %al, %ch /* lo 8bit cylinder should be in CH */
+ /* AL = 0 */
+ shlb $6, %ah /* hi 2bit cylinder ... */
+ orb %ah, %cl /* ... should be in CL */
+
+ movw $0x201, %ax /* read 1 sector */
+ebios_32: /* ebios_32 - 1 points to 0x02 that can be changed to 0x42 */
+
+// cmpb $0x0e, 2(%bp) /* force LBA? */
+// jnz 1f /* no, continue */
+// movb $0x42, %ah /* yes, use extended disk read */
+//1:
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb 0x40(%bp), %dl /* hard disk drive number */
+ int $0x13
+ popaw /* remove parameter block from stack */
+ popal
+ jc disk_error_32 /* disk read error, jc 1f if caller handles */
+ incl %eax /* next sector */
+ addw 0x0b(%bp), %bx /* bytes per sector */
+ jnc 1f /* 64K bound check */
+ pushw %dx
+ movw %es, %dx
+ addb $0x10, %dh /* add 1000h to ES */
+ /* here, carry is cleared */
+ movw %dx, %es
+ popw %dx
+1:
+ /* carry stored on disk read error */
+ ret
+
+ . = . - (. - readDisk_32)/91
+
+msg_DiskReadError_32:
+
+ .ascii "disk error\0"
+
+msg_BootError_32:
+
+ .ascii "No "
+
+filename_32:
+
+#ifdef BOOTGRUB2
+ .ascii "G2LDR \0"
+#elif defined (BOOTGRUB)
+ .ascii "GRLDR \0"
+#else
+ .ascii "KERNEL SYS\0"
+#endif
+
+#ifdef ALTERNATIVE_KERNEL
+filename_end_32:
+
+ . = Entry_32 + 0x1e8
+
+loadseg_off_32:
+ .word 0
+ .word LOADSEG
+
+ . = Entry_32 + 0x1ec
+
+boot_image_ofs_32:
+
+ .word (filename_32 - Entry_32)+(filename_end_32 - filename_32 - 1)*2048
+#endif
+
+ . = Entry_32 + 0x1ee
+
+disk_error_32:
+
+ movw $(msg_DiskReadError_32 - Entry_32 + 0x7c00), %si
+
+boot_error_32:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_32:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+ . = Entry_32 + 0x1fc
+
+ .word 0, 0xAA55 /* Win9x uses all 4 bytes as magic value here */
+
+ . = Entry_32 + 0x200
+
+ . = _start1 + 0x600
+
+ //.arch i8086, nojumps
+ .arch i186, nojumps
+/*
+ * The following is based on FreeDOS, modified heavily by Tinybit in Feb, 2004
+ *
+ * Merges FAT12 and FAT16 boot sectors to ONE FAT boot sector!
+ *
+ * Memory layout for GRLDR FAT single stage boot process:
+ *
+ * +--------+
+ * | |
+ * |GRLDR | also used as max 128k FAT buffer
+ * |LOADED | before GRLDR loading starts
+ * |--------| 2000:0000
+ * | |
+ * |--------| 0000:7E00
+ * |BOOTSECT|
+ * |ORIGIN |
+ * |--------| 0000:7C00
+ * | |
+ * |--------| 0000:3000
+ * |CLUSTER |
+ * |LIST |
+ * |--------| 0000:2000
+ * | |
+ * +--------+
+ */
+
+/*
+;
+; File:
+; boot.asm
+; Description:
+; DOS-C boot
+;
+; Copyright (c) 1997;
+; Svante Frey
+; All Rights Reserved
+;
+; This file is part of DOS-C.
+;
+; DOS-C 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, or (at your option) any later version.
+;
+; DOS-C 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 DOS-C; see the file COPYING. If not,
+; write to the Free Software Foundation, 675 Mass Ave,
+; Cambridge, MA 02139, USA.
+;
+;
+; +--------+ 1FE0:7E00
+; |BOOT SEC|
+; |RELOCATE|
+; |--------| 1FE0:7C00
+; | |
+; |--------| 1FE0:3000
+; | CLUSTER|
+; | LIST |
+; |--------| 1FE0:2000
+; | |
+; |--------| 0000:7E00
+; |BOOT SEC| overwritten by max 128k FAT buffer
+; |ORIGIN | and later by max 134k loaded kernel
+; |--------| 0000:7C00
+; | |
+; |--------|
+; |KERNEL | also used as max 128k FAT buffer
+; |LOADED | before kernel loading starts
+; |--------| 0060:0000
+; | |
+; +--------+
+*/
+
+#ifdef BOOTGRUB
+#define LOADSEG_12_16 0x2000
+#define FATBUF 0x2000 /* offset of temp buffer for FAT chain */
+#else
+#define LOADSEG_12_16 0x0060
+#define FATBUF 0x2000 /* offset of temp buffer for FAT chain */
+#endif
+
+Entry_12_16:
+ jmp 1f
+
+ . = Entry_12_16 + 0x02
+
+ /* The default mode is CHS. This is for maximum compatiblity with
+ * small-sized disks, e.g., floppies.
+ *
+ * Valid values are 0x90 for CHS mode, or 0x0e for LBA mode.
+ *
+ * If the BIOS int13 supports LBA, this byte can be safely set to 0x0e.
+ *
+ * Some USB BIOSes might have bugs when using CHS mode, so the format
+ * program should set this byte to 0x0e. It seems that (generally) all
+ * USB BIOSes have LBA support.
+ *
+ * If the format program does not know whether the BIOS has LBA
+ * support, it may operate this way:
+ *
+ * if (partition_start + total_sectors_in_partition) exceeds the CHS
+ * addressing ability(especially when it is greater than 1024*256*63),
+ * the caller should set this byte to 0x0e, otherwise, set to 0x90.
+ */
+
+ .byte 0x90 /* for CHS. Another possible value is 0x0e for LBA */
+
+
+ . = Entry_12_16 + 0x03
+
+#ifdef BOOTGRUB
+ .ascii "GRLDR "
+#endif
+
+ . = Entry_12_16 + 0x0b
+
+ .word 0x200 /* bytes per sector */
+
+ . = Entry_12_16 + 0x0d
+
+ .byte 1 /* sectors per cluster */
+
+ . = Entry_12_16 + 0x0e
+
+ .word 1 /* reserved sectors */
+
+ . = Entry_12_16 + 0x10
+
+ .byte 2 /* number of FATs */
+
+ . = Entry_12_16 + 0x11
+
+ .word 224 /* Max dir entries */
+
+ . = Entry_12_16 + 0x13
+
+ .word 2880 /* total sectors in the filesystem */
+
+ . = Entry_12_16 + 0x15
+
+ .byte 0xf0 /* media descriptor */
+
+ . = Entry_12_16 + 0x16
+
+ .word 9 /* sectors per FAT */
+
+ . = Entry_12_16 + 0x18
+
+ .word 18 /* sectors per track */
+
+ . = Entry_12_16 + 0x1a
+
+ .word 2 /* number of heads */
+
+ . = Entry_12_16 + 0x1c
+
+ .long 0 /* hidden sectors */
+
+ . = Entry_12_16 + 0x20
+
+ .long 0 /* total sectors for large partitions */
+
+ . = Entry_12_16 + 0x24
+
+ /* drive number of the boot device.
+ * This byte is ignored for read. The program will write DL onto
+ * this byte. The caller should set drive number in DL.
+ * We assume all BIOSes pass correct drive number in DL.
+ * That is to say, buggy BIOSes are not supported!!
+ */
+
+ .byte 0
+
+ . = Entry_12_16 + 0x25
+
+ /* partition number of this filesystem in the boot drive.
+ * This byte is ignored for read. The boot code will write partition
+ * number onto this byte. See Entry_12_16 + 0x41 below.
+ */
+
+ .byte 0
+
+ . = Entry_12_16 + 0x26
+
+ .byte 0x29 /* extended boot signature */
+
+ . = Entry_12_16 + 0x27
+
+ .long 0x0AC4AF63 /* volume serial number */
+
+ . = Entry_12_16 + 0x2b
+
+ .ascii "NO NAME " /* volume label */
+
+ . = Entry_12_16 + 0x36
+
+ .ascii "FAT12 " /* filesystem ID */
+
+/*
+; bp is initialized to 7c00h
+%define bsOemName bp+0x03 ; OEM label
+%define bsBytesPerSec bp+0x0b ; bytes/sector
+%define bsSecPerClust bp+0x0d ; sectors/allocation unit
+%define bsResSectors bp+0x0e ; # reserved sectors
+%define bsFATs bp+0x10 ; # of fats
+%define bsRootDirEnts bp+0x11 ; # of root dir entries
+%define bsSectors bp+0x13 ; # sectors total in image
+%define bsMedia bp+0x15 ; media descrip: fd=2side9sec, etc...
+%define sectPerFat bp+0x16 ; # sectors in a fat
+%define sectPerTrack bp+0x18 ; # sectors/track
+%define nHeads bp+0x1a ; # heads
+%define nHidden bp+0x1c ; # hidden sectors
+%define nSectorHuge bp+0x20 ; # sectors if > 65536
+%define drive bp+0x24 ; drive number
+ bp+0x25 ; partition number for GRLDR
+%define extBoot bp+0x26 ; extended boot signature
+%define volid bp+0x27
+%define vollabel bp+0x2b
+%define filesys bp+0x36
+
+%define RootDirSecs bp+0x26 ; # of sectors root dir uses
+ ; (overwriting unused bytes)
+%define fat_start bp+0x28 ; first FAT sector
+ ; (overwriting unused bytes)
+%define root_dir_start bp+0x2c ; first root directory sector
+ ; (overwriting unused bytes)
+%define data_start bp+0x30 ; first data sector
+ ; (overwriting unused bytes)
+%define data_clusters bp+0x34 ; # of clusters in data area
+ ; (overwriting unused bytes)
+ bp+0x36 ; bytes per FAT( > 0x1800 means FAT16)
+ ; (overwriting unused bytes)
+*/
+ /* not used: [0x26] = byte 0x29 (ext boot param flag)
+ * [0x27] = dword serial
+ * [0x2b] = label (padded with 00, 11 bytes)
+ * [0x36] = "FAT12" or "FAT16",32,32,32 (not used by Windows)
+ * ([0x3e] is where FreeDOS parts start)
+ */
+
+ . = Entry_12_16 + 0x3e
+1:
+ cli
+ cld
+
+#ifdef BOOTGRUB
+
+ . = Entry_12_16 + 0x40
+
+ /* the byte at offset 0x41 stores the real partition number for read.
+ * the format program or the caller should set it to a correct value.
+ * For floppies, it should be 0xff, which stands for whole drive.
+ */
+
+ movb $0xff, %dh /* boot partition number */
+
+ cmpb $0xff, %dh /* is floppy? */
+ jne 1f
+ movb $0, %dl /* yes, let drive number = 0 */
+1:
+#endif
+
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw $0x7c00, %bp
+
+#ifdef BOOTGRUB
+ movw %ax, %es
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+ movw %dx, 0x24(%bp) /* BIOS passes drive number in DL */
+ /* AX=0 */
+// xchgw %ax, %dx /* let DX = 0 */
+// xorw %cx, %cx /* CX = 0 */
+#else
+ movw %bp, %si /* move from 0000:7c00 */
+ movw %bp, %di /* move to 1fe0:7c00 */
+ movb %dl, 0x24(%si) /* BIOS passes drive number in DL */
+// xchgw %ax, %dx /* let DX = 0 */
+ movw $0x1fe0, %ax
+ movw %ax, %es
+ movw $0x0100, %cx /* one sector to move */
+ repz movsw
+ /* CX = 0 */
+ ljmp $0x1fe0, $(1f - Entry_12_16 + 0x7c00)
+1:
+ movw %ax, %ds
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+ /* AX=0x1fe0 */
+#endif
+
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xAA55, %bx
+ jne 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ /* EBIOS supported */
+ movb $0x42, (ebios_12_16 - 1 - Entry_12_16 + 0x7c00)
+1:
+// xorw %cx, %cx
+ xorw %ax, %ax
+
+ /* GET DRIVE PARMS: Calculate start of some disk areas */
+
+ movw 0x1c(%bp), %si /* number of hidden sectors(lo) */
+ movw 0x1e(%bp), %di /* number of hidden sectors(hi) */
+ addw 0x0e(%bp), %si /* number of reserved sectors */
+ adcw %ax, %di /* DI:SI = first FAT sector */
+ /* AX = 0 */
+
+ movw %si, 0x28(%bp) /* FAT start sector(lo) */
+ movw %di, 0x2a(%bp) /* FAT start sector(hi) */
+
+ //xchgw %ax, %dx /* let AX = 0 */
+ movb 0x10(%bp), %al /* number of FATs */
+ /* cbw */
+ mulw 0x16(%bp) /* sectors per FAT */
+ /* DX:AX = total number of FAT sectors */
+ /* DX = 0 since no too many FAT sectors */
+ addw %ax, %si
+ adcw %dx, %di /* DI:SI = root directory start sector */
+ movw %si, 0x2c(%bp) /* root directory starting sector(lo) */
+ movw %di, 0x2e(%bp) /* root directory starting sector(hi) */
+
+ /* Calculate how many sectors the root directory occupies */
+
+ movw 0x0b(%bp), %bx /* bytes per sector */
+ movb $5, %cl /* divide BX by 32 */
+ shrw %cl, %bx /* BX = directory entries per sector */
+
+ movw 0x11(%bp), %ax /* max number of root dir entries */
+ /* xorw %dx, %dx */ /* assuming DX = 0 */
+ divw %bx /* AX = sectors per root directory */
+ /* DX = 0 since normally no residue */
+
+ movw %ax, 0x26(%bp) /* number of sectors the root dir occupies */
+
+ addw %ax, %si /* DI:SI = first data sector */
+ adcw %dx, %di /* assuming DX = 0 */
+
+ movw %si, 0x30(%bp) /* data starting sector(lo) */
+ movw %di, 0x32(%bp) /* data starting sector(hi) */
+#ifdef USE_TOTAL_CLUSTERS
+ movw 0x13(%bp), %cx /* total sectors(small) */
+ jcxz 1f
+ movw %cx, 0x20(%bp) /* total sectors(large)(lo) */
+ movw %dx, 0x22(%bp) /* total sectors(large)(hi), assuming DX = 0 */
+1:
+ movw 0x20(%bp), %ax /* total sectors(large) */
+ movw 0x22(%bp), %bx
+ addw 0x1c(%bp), %ax /* number of hidden sectors */
+ adcw 0x1e(%bp), %bx
+ subw %si, %ax /* data starting sector */
+ sbbw %di, %bx /* BX:AX = total sectors in the data area */
+ movb 0x0d(%bp), %dl /* sectors per cluster(DH=0) */
+ xchgw %bx, %dx /* DX:AX = total sectors in the data area */
+ /* BX = sectors per cluster */
+ divw %bx /* AX = total clusters in the data area */
+ movw %ax, 0x34(%bp) /* total clusters in the data area */
+#else
+ movw $0xffff, 0x36(%bp)
+ movw 0x16(%bp), %ax /* sectors per FAT */
+ mulw 0x0b(%bp) /* bytes per sector */
+ jc 1f
+ movw %ax, 0x36(%bp)
+1:
+#endif
+ /* Searches for the file in the root directory
+ *
+ * Returns:
+ * AX = first cluster of file
+ */
+
+ /* First, read the whole root directory into the temporary buffer */
+
+ movw 0x2c(%bp), %ax /* root directory starting sector(lo) */
+ movw 0x2e(%bp), %dx /* root directory starting sector(hi) */
+ movw 0x26(%bp), %di /* number of sectors the root dir occupies */
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
+ /* ES:BX = loadseg:0 */
+ call readDisk_12_16
+
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %di
+ /* ES:DI = loadseg:0 */
+
+
+ /* Search for kernel file name, and find start cluster */
+
+1:
+ movw $11, %cx
+ movw $(filename_12_16 - Entry_12_16 + 0x7c00), %si
+ pushw %di
+ repz cmpsb
+ popw %di
+ movw %es:0x1a(%di), %ax /* get cluster number from dir entry */
+ jz 1f
+
+ addw $0x20, %di /* go to next directory entry */
+ cmpb %ch, %es:(%di) /* if the first byte of the name is 0, */
+ /* there is no more files in the directory */
+ /* assuming CH = 0 */
+ jnz 1b
+ movw $(msg_BootError_12_16 - Entry_12_16 + 0x7c00), %si
+ jmp boot_error_12_16 /* fail if not found */
+
+#ifndef ALTERNATIVE_KERNEL
+loadseg_off_12_16: .word 0
+loadseg_seg_12_16: .word LOADSEG_12_16
+#endif
+
+1:
+ pushw %ax /* store first cluster number */
+ /* CX = 0 */
+
+
+ /* Reads the FAT chain and stores it in a temporary buffer in the first
+ * 64KB. The FAT chain is stored an array of 16-bit cluster numbers,
+ * ending with 0.
+ *
+ * The file must fit in conventional memory, so it can't be larger than
+ * 640KB. The sector size must be at least 512 bytes, so the FAT chain
+ * can't be larger than around 3KB.
+ *
+ * Call with: AX = first cluster in chain
+ */
+
+ /* Load the complete FAT into memory. The FAT can't be larger
+ * than 128 kb, so it should fit in the temporary buffer.
+ */
+
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
+ /* ES:BX = loadseg:0 */
+ movw 0x16(%bp), %di /* sectors per FAT */
+ movw 0x28(%bp), %ax /* FAT start sector(lo) */
+ movw 0x2a(%bp), %dx /* FAT start sector(hi) */
+ call readDisk_12_16
+ popw %ax /* restore first cluster number */
+
+ /* Set ES:DI to the temporary storage for the FAT chain */
+ pushw %ds
+ popw %es
+ movw (loadseg_seg_12_16 - Entry_12_16)(%bp), %ds
+ movw $FATBUF, %di
+
+2:
+ stosw /* store cluster number */
+ movw %ax, %si /* SI = cluster number */
+ addw %si, %si /* multiply cluster number by two */
+ movw (loadseg_seg_12_16 - Entry_12_16)(%bp), %dx
+ /* segment for FAT16 */
+ jnc 1f
+ addb $0x10, %dh /* overflow. Add 0x1000 to segment value */
+1:
+
+#ifdef USE_TOTAL_CLUSTERS
+ cmpw $0x0ff7, 0x34(%bp) /* total clusters in the data area */
+#else
+ cmpw $0x1801, 0x36(%bp) /* bytes per FAT */
+#endif
+ jnb 3f
+
+ /* This is a FAT12 disk */
+
+ addw %ax, %si /* multiply cluster number by 3 ... */
+ shrw $1, %si /* ... and divide by 2 */
+ lodsw
+
+ /* If the cluster number was even, the cluster value is now in
+ * bits 0-11 of AX. If the cluster number was odd, the cluster
+ * value is in bits 4-15, and must be shifted right 4 bits. If
+ * the number was odd, CF was set in the last shift instruction.
+ */
+
+ jnc 1f
+ movb $4, %cl
+ shrw %cl, %ax
+1:
+ andb $0x0f, %ah /* mask off the highest 4 bits */
+ cmpw $0x0ff7, %ax /* check for EOF */
+ jmp 4f
+
+3:
+ /* This is a FAT16 disk. The maximal size of a 16bit FAT
+ * is 128KB, so it may not fit within a single 64KB segment
+ */
+
+ movw %dx, %ds /* DS:SI points to next cluster */
+ lodsw /* AX = next cluster */
+
+ cmpw $0xfff7, %ax /* check for EOF */
+4:
+ jbe 2b /* continue if not EOF */
+
+ /* Mark end of FAT chain with 0, so we have a single
+ * EOF marker for both FAT12 and FAT16 systems.
+ */
+
+ xorw %ax, %ax
+ stosw
+
+ pushw %cs
+ popw %ds
+
+ /* Loads the file into memory, one cluster at a time */
+
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
+ /* ES:BX = loadseg:0 */
+ movw $FATBUF, %si /* set DS:SI to the FAT chain */
+
+2:
+ lodsw /* AX = next cluster to read */
+ orw %ax, %ax
+ jnz 1f
+
+ /* EOC encountered - done */
+#ifdef BOOTGRUB
+ movw 0x24(%bp), %dx /* boot_drive and boot_partition */
+#else
+ movb 0x24(%bp), %bl /* FreeDOS kernel uses BL, not DL, for drive */
+#endif
+ ljmp *(loadseg_off_12_16 - Entry_12_16)(%bp) /* boot it! */
+
+1:
+ decw %ax /* cluster numbers start with 2 */
+ decw %ax
+
+ movw 0x0d(%bp), %di /* sectors per cluster */
+ andw $0xff, %di /* DI = sectors per cluster */
+ mulw %di
+ addw 0x30(%bp), %ax /* data starting sector(lo) */
+ adcw 0x32(%bp), %dx /* data starting sector(hi) */
+ /* DX:AX = first sector to read */
+ call readDisk_12_16
+ jmp 2b /* read next cluster */
+
+/* Reads a number of sectors into memory.
+ *
+ * Call with: DX:AX = 32-bit DOS sector number
+ * DI = number of sectors to read
+ * ES:BX = destination buffer
+ *
+ * Returns: CF set on error
+ * ES:BX points one byte after the last byte read.
+ * DX:AX = next sector number after read
+ */
+
+readDisk_12_16:
+2:
+ pushaw
+ xorw %cx, %cx
+ pushw %cx
+ pushw %cx
+ pushw %dx
+ pushw %ax
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ incw %cx
+ pushw %cx /* 1 sector to read */
+ movb $16, %cl
+ pushw %cx /* size of this parameter block */
+
+ xchgw %ax, %cx /* save AX to CX */
+
+ /*
+ * translate sector number to BIOS parameters
+ *
+ * LBA = sector-1 offset in track
+ * + head * sectPerTrack offset in cylinder
+ * + cyl * sectPerTrack * nHeads offset in platter
+ *
+ */
+ pushw %bx
+ movw 0x18(%bp), %ax /* sectors per track */
+ movw %ax, %bx
+ mulb 0x1a(%bp) /* nHeads, but maybe a word value 0x100 */
+ jnz 1f
+ movb %bl, %ah /* nHeads=0x100, so AX=sectPerTrack*0x100 */
+1:
+ xchgw %ax, %cx /* restore AX from CX, and save AX to CX */
+ /* DX:AX = LBA, CX = nHeads * sectPerTrack <= 256*63 */
+ divw %cx /* AX = cyl, DX = sector-1 + head * sectPerTrack */
+ xchgw %ax, %dx /* DX = cyl, AX = sector-1 + head * sectPerTrack */
+ divb %bl /* sectors per track */
+ /* DX = cyl, AL = head, AH = sector-1 */
+#if 1
+ xchgb %al, %ah /* DX = cyl, AH = head, AL = sector-1 */
+ incw %ax /* DX = cyl, AH = head, AL = sector */
+ xchgw %ax, %dx /* AX = cyl, DH = head, DL = sector */
+ xchgw %ax, %cx /* CX = cyl, DH = head, DL = sector */
+ xchgb %cl, %ch /* set cyl number low 8 bits in CH */
+ rorb $1, %cl /* move cyl high bits into bits 7-6 */
+ rorb $1, %cl /* (assumes top = 0) */
+ orb %dl, %cl /* merge sector into cylinder */
+#else
+ movw %dx, %cx /* CX = cyl, AL = head, AH = sector-1 */
+
+ /*
+ * the following manipulations are necessary in order to properly place
+ * parameters into registers.
+ * CH = cylinder number low 8 bits
+ * CL<7-6> = cylinder high two bits
+ * CL<5-0> = sector
+ */
+ movb %al, %dh /* save head into DH for BIOS */
+ xchgb %cl, %ch /* set cyl number low 8 bits in CH */
+ rorb $1, %cl /* move cyl high bits into bits 7-6 */
+ rorb $1, %cl /* (assumes top = 0) */
+ incb %ah /* AH = sector number */
+ orb %ah, %cl /* merge sector into cylinder */
+#endif
+ popw %bx
+
+ movw $0x0201, %ax /* read 1 sector */
+ebios_12_16: /* ebios_12_16 - 1 points to 0x02 that can be changed to 0x42 */
+
+// cmpb $0x0e, 2(%bp) /* force LBA? */
+// jnz 1f /* no, continue */
+// movb $0x42, %ah /* yes, use extended disk read */
+//1:
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb 0x24(%bp), %dl /* drive number */
+ int $0x13
+// stc #; only for testing the buggy Virtual PC
+ popaw /* remove parameter block from stack */
+ popaw
+ jc disk_error_12_16 /* disk read error, jc 1f if caller handles */
+ incw %ax /* next sector */
+ jnz 1f
+ incw %dx
+1:
+ addw 0x0b(%bp), %bx /* bytes per sector */
+ jnc 1f /* 64K bound check */
+ pushw %dx
+ movw %es, %dx
+ addb $0x10, %dh /* add 1000h to ES */
+ /* here, carry is cleared */
+ movw %dx, %es
+ popw %dx
+1:
+ decw %di
+ jnz 2b
+
+ /* carry stored on disk read error */
+ ret
+
+ . = . - (. - readDisk_12_16)/99
+
+msg_DiskReadError_12_16:
+
+ .ascii "disk error\0"
+
+msg_BootError_12_16:
+
+ .ascii "No "
+
+filename_12_16:
+
+#ifdef BOOTGRUB2
+ .ascii "G2LDR \0"
+#elif defined (BOOTGRUB)
+ .ascii "GRLDR \0"
+#else
+ .ascii "KERNEL SYS\0"
+#endif
+
+#ifdef ALTERNATIVE_KERNEL
+filename_end_12_16:
+
+ . = Entry_12_16 + 0x1e8
+
+loadseg_off_12_16: .word 0
+loadseg_seg_12_16: .word LOADSEG_12_16
+
+ . = Entry_12_16 + 0x1ec
+
+boot_image_ofs_12_16:
+
+ .word (filename_12_16 - Entry_12_16)+(filename_end_12_16 - filename_12_16 - 1)*2048
+#endif
+
+ . = Entry_12_16 + 0x1ee
+
+disk_error_12_16:
+
+ movw $(msg_DiskReadError_12_16 - Entry_12_16 + 0x7c00), %si
+
+boot_error_12_16:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_12_16:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+ . = Entry_12_16 + 0x1fc
+
+ .word 0, 0xAA55 /* Win9x uses all 4 bytes as magic value here */
+
+ . = Entry_12_16 + 0x200
+
+ . = _start1 + 0x800
+
+
+
+
+ .arch i486, nojumps
+
+/*
+ #; Ext2 boot sector for GRLDR
+ */
+
+
+#define DEBUG call debug_print
+#undef DEBUG
+
+ //. = _start1 + 0x800
+
+Entry_ext2:
+
+ jmp 1f
+
+ . = Entry_ext2 + 0x02
+
+ /* The default mode is CHS. This is for maximum compatiblity with
+ * small-sized disks, e.g., floppies.
+ *
+ * Valid values are 0x02 for CHS mode, or 0x42 for LBA mode.
+ *
+ * If the BIOS int13 supports LBA, this byte can be safely set to 0x42.
+ *
+ * Some USB BIOSes might have bugs when using CHS mode, so the format
+ * program should set this byte to 0x42. It seems that (generally) all
+ * USB BIOSes have LBA support.
+ *
+ * If the format program does not know whether the BIOS has LBA
+ * support, it may operate this way:
+ *
+ * if (partition_start + total_sectors_in_partition) exceeds the CHS
+ * addressing ability(especially when it is greater than 1024*256*63),
+ * the caller should set this byte to 0x42, otherwise, set to 0x02.
+ */
+
+ .byte 0x02 /* for CHS. Another possible value is 0x42 for LBA */
+
+ . = Entry_ext2 + 0x03
+
+#if 0
+
+ .ascii "ext2 grldr"
+
+#else
+
+msg_DiskReadError_ext2:
+
+ .ascii "I/O error\0"
+
+#endif
+
+ . = Entry_ext2 + 0x0d
+
+ /* sectors per block. Valid values are 2, 4, 8, 16, 32. */
+
+ .byte 2
+
+ . = Entry_ext2 + 0x0e
+
+ /* bytes per block.
+ * Valid values are 0x400, 0x800, 0x1000, 0x2000, 0x4000.
+ */
+
+ .word 1024 /* bytes per block, at most 16K */
+
+ . = Entry_ext2 + 0x10
+
+ /* pointers in pointers-per-block blocks, that is, number of blocks
+ * covered by a double-indirect block.
+ * Valid values are 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000.
+ */
+
+ .long 0x10000 /* number of blocks covered by double-indirect block */
+ /* low word=0 */
+
+ . = Entry_ext2 + 0x14
+
+ /* pointers per block, that is, number of blocks covered by an indirect
+ * block. Valid values are 0x100, 0x200, 0x400, 0x800, 0x1000.
+ */
+
+ .long 0x100 /* high word=0, low byte=0 */
+
+ . = Entry_ext2 + 0x18
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .word 18 /* sectors per track */
+
+ . = Entry_ext2 + 0x1a
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .word 2 /* number of heads */
+
+ . = Entry_ext2 + 0x1c
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 0 /* hidden sectors */
+
+ . = Entry_ext2 + 0x20
+
+ /* total sectors in the filesystem(or in the partition).
+ * This value is informative. The code does not use it.
+ */
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 2880
+
+ . = Entry_ext2 + 0x24
+
+ /* This byte is ignored for read. The program will write DL onto
+ * this byte. The caller should set drive number in DL.
+ * We assume all BIOSes pass correct drive number in DL.
+ * That is to say, buggy BIOSes are not supported!!
+ */
+
+ .byte 0 /* drive number */
+
+ . = Entry_ext2 + 0x25
+
+ /* this is default for floppies, the caller should set it to
+ * a correct value for hard-drive partitions */
+
+ .byte 0xff /* partition number, 0xff for whole drive */
+
+ . = Entry_ext2 + 0x26
+
+ .word 0x80 /* inode size */
+
+ . = Entry_ext2 + 0x28
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 2048 /* s_inodes_per_group */
+
+ . = Entry_ext2 + 0x2c
+
+ /* block number for group descriptors = s_first_data_block + 1.
+ * Valid values are 2 for 1024-byte blocks, and 1 for otherwise.
+ */
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 2 /* block number for group descriptors */
+
+ . = Entry_ext2 + 0x30
+1:
+ cld /* 0xFC */
+
+ xorw %ax, %ax /* 0x31, 0xC0; CF=0, ZF=1 */
+
+ /* this byte `nop' will be changed to `cwd' by bootlace for floppy */
+ nop /* 0x90=nop, 0x99=cwd */
+ /* cwd will set DL=0 forcibly for floppy A: */
+
+ movw %ax, %ss /* constant SS=0 */
+ movw $0x7c00, %sp
+
+ movw %sp, %bp /* constant BP=0x7c00 */
+ movw %ax, %ds /* constant DS=0 */
+
+ pushw %ax /* 0x0000 at 0000:7bfe */
+ movw $0x1000, %bx
+ pushw %bx /* 0x1000 at 0000:7bfc */
+ pushw %ax /* 0x0000 at 0000:7bfa */
+ /* SP=0x7bfa */
+
+ /* the 6 bytes in the stack are used by read_block():
+ * 0000 ---- -2(%bp)
+ * 1000 ---- -4(%bp)
+ * 0000 ---- -6(%bp)
+ * Don't touch them!
+ */
+
+ movb %dl, 0x24(%bp) /* BIOS passes drive number in DL */
+
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+#if 0
+ jnc 1f
+ /* No EBIOS */
+ movb $0x02, (ebios_ext2 - 1 - Entry_ext2 + 0x7c00)
+#else
+ jc 1f #; No EBIOS
+
+ //testb $1, %cl
+ //jz 1f #; No EBIOS
+#if 0
+ /* gcc-4.0.1 does not generate 2-byte code. */
+ rcrb $1, %cl #; also can be rorb $1, %cl
+#else
+ .byte 0xD0, 0xD9 #; ror cl: D0 C9
+#endif
+ jnc 1f #; No EBIOS
+
+ movb $0x42, (ebios_ext2 - 1 - Entry_ext2 + 0x7c00)
+#endif
+1:
+ xorl %eax, %eax /* CF=0, ZF=1 */
+
+#if 0
+ /* the INC touches ZF flag, so use MOV instead */
+
+ incw %ax
+ incw %ax /* EAX=2=inode number for root dir */
+#else
+
+ /* MOV keeps all flags untouched, so it is better than INC */
+
+ movb $2, %al /* EAX=2=inode number for root dir */
+#endif
+
+ /* CF=0, ZF=1 because MOV and PUSH do not touch Flags */
+
+ /* read root dir to 0000:1000, and grldr to 1000:0000 */
+
+4:
+ /* EAX holds the inode number: for root dir or grldr */
+
+ /* These 3 PUSHes is intended to place 1000:0000 onto the stack for
+ * grldr. For root dir, the stack is not used since CF is cleared.
+ * Although there is no corresponding POPs, this is safe enough
+ * because the program comes here only twice: the first is for
+ * the root dir, and the second is for grldr.
+ *
+ * For root dir, CF=0 and ZF=1. For grldr, CF=1.
+ */
+
+ pushw %di /* 0x1000, see "jz 4b" below. */
+ pushw %ss /* 0x0000 */
+ pushfw
+
+ /* SP=0x7bf4 for root dir, or 0x7bee for grldr */
+
+ decl %eax /* EAX=(inode - 1) */
+
+ /* inode numbers are far less than 0x7fffffff, so it is safe to
+ * initialise EDX with CDQ */
+
+ cdq /* let EDX=0 */
+
+ divl 0x28(%bp) /* s_inodes_per_group */
+ /* EAX=group number */
+ pushl %edx /* EDX=inode number in the group */
+
+ /* group numbers are far less than 0x7fffffff, so it is safe to
+ * initialise EDX with CDQ */
+
+ cdq /* let EDX=0 */
+ shll $5, %eax /* EAX=relative displacement of the group descriptor */
+ divl 0x0e(%bp) /* bytes per block */
+ /* EAX=relative block number for the group descriptor */
+ /* DX=displacement in the block */
+ /* EDX high=0 */
+
+ pushw %dx /* we don't care about EDX high word, because it is 0 */
+
+ addl 0x2c(%bp), %eax /* EAX=absolute block number for the group descriptor */
+ /* CF=0, ZF=0 */
+
+ call read_block /* 0000:1000 points to the block data containing the group descriptor */
+ /* ES changed and > 0, BX=0x1000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+
+ popw %si /* DS:[BX+SI] points to the group descriptor */
+ /* DS:[BX+SI+8] points to the starting block number of the group inode table */
+
+ popl %eax /* inode number in the group */
+// shll $7, %eax /* inode struct size = 0x80 */
+// /* EAX=relative displacement of the inode struct */
+// /* EDX=0 */
+ movw 0x26(%bp), %dx /* EDX=inode size */
+ mull %edx /* EDX:EAX=relative displacement of the inode struct */
+
+ divl 0x0e(%bp) /* bytes per block */
+ /* EAX=relative block number for the inode struct */
+ pushw %dx /* DX=displacement of the inode struct in the block */
+ /* EDX high=0 */
+
+ addl 8(%bx, %si), %eax /* EAX=absolute block number for the inode struct */
+ /* CF=0, ZF=0 */
+
+ call read_block /* 0000:1000 points to the block data containing the inode struct */
+ /* ES changed and > 0, BX=0x1000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+
+ popw %si /* DS:[BX+SI] points to the inode struct */
+
+ addw %bx, %si /* DS:SI points to the inode struct */
+
+ /* Move the inode struct to a known safe area(0000:0fa8 - 0000:0fff),
+ * that is, 0x58 bytes immediately before 0000:1000. We care about only
+ * the beginning 0x58 bytes of the 0x80-byte inode struct, the last
+ * 0x28 bytes are ignored. The area from 0xfa8+0x28 to 0xfa8+0x57
+ * stores 12 direct block pointers.
+ *
+ *
+ * At address Initial value Stores what?
+ * ========== ============= ======================================
+ * 0xfa8+0x04 (const) the size of the file in bytes
+ *
+ * 0xfa8+0x08 total blocks blocks left to read
+ *
+ * 0xfa8+0x0c 0 serial number of the block to read
+ *
+ */
+
+ pushw %ss
+ popw %es /* ES=0 */
+
+ leaw -0x58(%bx), %di /* BX=0x1000, so DI=0x0fa8 */
+ //movw $0x0fa8, %di
+ movb $0x2c, %cl /* 0x2c words = 0x58 bytes */
+
+ repz movsw /* now ECX=0, BX=0x1000=DI */
+
+ movl %ecx, (0x0c - 0x58)(%di) /* block serial number of the file */
+ /* ECX=0 means first block */
+ /* DI=0x1000 */
+
+ movl (0x04 - 0x58)(%di), %eax /* i_size, the file size */
+ decl %eax
+
+ divl 0x0e(%bp) /* bytes per block */
+ /* EDX=various */
+ incl %eax
+ movl %eax, (0x08 - 0x58)(%di) /* total blocks for file data */
+
+ /*
+ * 0000:1000 trebly indirect block
+ * 0000:8000 indirect block
+ * 0000:c000 double indirect block
+ * 1000:0000 the file data
+ */
+
+ /* now DS:SI points to indirect block number */
+
+ lodsl /* indirect block number */
+ testl %eax, %eax
+ jz 1f
+
+ //pushw %ss
+ //popw %es /* ES=0 */
+ movb $0x80, %bh /* ES:BX=0000:8000 */
+#if 0
+ stc
+ call read_block
+#else
+ call read_block_c
+#endif
+ /* ES changed and > 0, BX=0x8000 */
+ /* ECX=EDX=0 */
+ /* ZF=0, CF=0 */
+
+ /* now DS:SI points to double indirect block number */
+
+ lodsl /* double indirect block number */
+ testl %eax, %eax
+ jz 1f
+
+#if 0
+ pushw %ss
+ popw %es /* ES=0 */
+ movb $0xc0, %bh /* ES:BX=0000:c000 */
+ stc
+ call read_block
+#else
+ movb $0xc0, %bh /* ES:BX=0000:c000 */
+ call read_block_c
+#endif
+ /* ES changed and > 0, BX=0xc000 */
+ /* ECX=EDX=0 */
+ /* ZF=0, CF=0 */
+
+ /* now DS:SI points to trebly indirect block number */
+
+ lodsl /* trebly indirect block number */
+ testl %eax, %eax /* CF=0, TEST always clears CF */
+ jz 1f
+ /* ZF=0 */
+ //pushw %ss
+ //popw %es /* ES=0 */
+ //movb $0x10, %bh /* ES:BX=0000:1000 */
+ //stc
+ call read_block /* 0000:1000 points to the block data */
+ /* ES changed and > 0, BX=0x1000 */
+ /* ECX=EDX=0 */
+ /* ZF=0, CF=0 */
+
+ /* the block at 0000:1000, which contains the indirect block numbers,
+ * is just overwritten by the trebly indirect block */
+
+1:
+ /* get absolute block number by block serial number */
+
+ movl (0x0c - 0x58)(%di), %ebx /* block serial number of the file */
+ subl $12, %ebx
+ jc 3f /* direct block: block serial number < 12 */
+
+ pushw %bx
+ subl 0x14(%bp), %ebx
+ popw %ax
+ jnc 2f
+
+ /* indirect block: 12 <= block serial number < 12 + 0x14(%bp) */
+
+ //addw 0x14(%bp), %bx
+ addb $(0x70 / 4), %ah
+ //xchgw %ax, %bx
+ jmp 8f
+
+2:
+ pushl %ebx
+ subl 0x10(%bp), %ebx
+ jc 7f /* EBX on the stack is < 0x10(%bp). double indirect block:
+ * 12 + 0x14(%bp) <= block serial number < 12 + 0x14(%bp) + 0x10(%bp)
+ */
+
+ /* trebly indirect block: block serial number >= 12 + 0x14(%bp) + 0x10(%bp) */
+
+ popl %eax /* discard the stack */
+ xchgl %eax, %ebx /* move EBX to EAX */
+ /* EDX=0 */
+ divl 0x10(%bp)
+ /* EAX=indirect block number, < 0x14(%bp) */
+ /* EDX=block number, < 0x10(%bp) */
+
+ pushl %edx /* EDX < 0x10(%bp) */
+ testl %edx, %edx
+ jnz 7f
+
+ /* EDX=0, so we need to load the double indirect block */
+
+ shlw $2, %ax
+ xchgw %ax, %bx
+
+ /* get the double indirect block number from the trebly indirect
+ * block data */
+
+ movl (%bx, %di), %eax
+
+//6:
+ movw $0xc000, %bx /* ES:BX=0000:c000 */
+
+ //pushw %ss
+ //popw %es /* ES=0 */
+ //stc
+ call read_block_c /* 0000:c000 points to the block data */
+ /* ES changed and > 0, BX=0xc000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+7:
+ popl %eax /* EAX < 0x10(%bp) */
+ cdq /* let EDX=0 (notice the above jc 7f and jnz 7f) */
+ divl 0x14(%bp)
+ /* EAX=indirect block number, < 0x14(%bp) */
+ /* EDX=block number, < 0x14(%bp) */
+
+ pushw %dx /* EDX < 0x14(%bp) */
+ testw %dx, %dx
+ jnz 7f
+
+ /* if DX=0, we need to load the indirect block */
+
+ //addb $(0xb0 / 4), %ah
+ shlw $2, %ax
+ xchgw %ax, %bx
+
+ /* get the indirect block number from the double indirect block data */
+
+ movl 0xb000(%bx, %di), %eax
+ //movl (%bx, %di), %eax
+//5:
+ movw $0x8000, %bx /* ES:BX=0000:8000 */
+
+ //pushw %ss
+ //popw %es /* ES=0 */
+ //stc
+ call read_block_c /* 0000:8000 points to the block data */
+ /* ES changed and > 0, BX=0x8000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+7:
+ popw %ax /* AX < 0x14(%bp) */
+8:
+ xchgw %ax, %bx
+3:
+ shlw $2, %bx
+ movl (%bx, %di), %eax
+
+ /* got it! EAX=absolute block number */
+
+ /* read block data to 1000:0000. For root dir, read each block to
+ * 1000:0000(overwrite the previous read). For grldr, read blocks
+ * one by one to the area starting at 1000:0000.
+ */
+
+ popfw
+ popw %bx
+ popw %es
+ pushfw
+
+ /* CF=0 and ZF=1 for reading root dir, CF=1 for reading grldr */
+
+ call read_block /* 1000:0000 points to the block data */
+ /* ES changed and > 0x1000, BX=0 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+
+ popfw
+ pushw %es
+ pushw %bx
+ pushfw
+
+ jc 3f /* CF=1, we are reading grldr */
+
+ /* We have just read a block of the root dir to 1000:0000.
+ * So we check all dir entries in the block to see if anyone
+ * matches grldr.
+ */
+
+ xorw %si, %si
+ pushw %ss
+ popw %es /* ES=0 */
+
+2:
+ pushw %ds /* DS=0 */
+ movw %di, %ds /* DS=0x1000 */
+ movw $(filename_ext2 - Entry_ext2 + 0x7c00), %di
+
+ pushw %si
+ lodsl /* This is possible inode number for grldr */
+ pushl %eax /* This is possible inode number for grldr */
+ lodsw
+ xchgw %ax, %dx /* rec_len */
+ lodsw /* AL=name_len, should be 5 for grldr */
+ /* AH=file_type(1 for regular file) */
+#if 0
+ cmpw $0x0105, %ax
+ jnz 5f
+ movb %al, %cl /* CH is already 0 */
+ repz cmpsb
+#else
+ decb %ah
+ //jnz 5f
+ xchgw %ax, %cx /* CX=name_len */
+ repz cmpsb
+ jnz 5f
+ xchgw %ax, %cx /* movb $0, %al */
+ scasb
+#endif
+5:
+ popl %eax /* This is possible inode number for grldr */
+ popw %si
+
+ /* DS=0x1000, EAX=inode number */
+
+ movw %ds, %di /* DI=0x1000 */
+ popw %ds /* DS=0 */
+
+ stc /* indicates the new inode is for grldr */
+
+ jz 4b /* grldr is found with EAX=inode number */
+
+ addw %dx, %si
+ cmpw 0x0e(%bp), %si /* bytes per block */
+ jb 2b
+
+ /* file not found in this block, continue */
+
+ /* We are lucky that CF=0, which indicates we are dealing with
+ * the root dir.
+ */
+
+3:
+
+ /* CF=1 for grldr, CF=0 for root dir. */
+
+ incl (0x0c - 0x58)(%di)
+ decl (0x08 - 0x58)(%di)
+ jnz 1b
+
+#if 0
+ /* The above 2 instructions INC and DEC do not touch CF, so we
+ * can omit this POP-PUSH pair.
+ */
+
+ popfw
+ pushfw
+#endif
+
+ movw $(msg_No_grldr_ext2 - Entry_ext2 + 0x7c00), %si
+
+ jnc boot_error_ext2 /* grldr not found in the root dir */
+
+ /* All grldr blocks have been loaded to memory starting at 1000:0000,
+ * Before the boot, we pass boot_drive and boot_partition to grldr.
+ */
+
+ /* ES>0x1000, BX=0, ECX=EDX=0, DI=0x1000, SS=0, SI>0x7c00, DS=0
+ * BP=0x7c00, SP<=0x7c00
+ */
+
+ movw 0x24(%bp), %dx
+
+ /* boot it now! */
+
+ pushw %di /* 0x1000 */
+ pushw %ss /* 0x0000 */
+ lret
+
+read_block_c:
+
+ pushw %ss
+ popw %es /* ES=0 */
+ stc
+
+/* read_block - read a block
+ * input: CF - indicator for overlap or consecution
+ * EAX = block number
+ * ES:BX - buffer
+ *
+ * output: if CF is cleared on input, ES:BX is initialized to 0000:1000
+ * ES:BX - buffer filled with data
+ * ES, EAX - Changed
+ * ECX = 0
+ * EDX = 0
+ * ZF = 0
+ * CF = 0
+ */
+
+read_block:
+
+ jc 1f
+
+ .byte 0xC4, 0x5E, 0xFC /* lesw -4(%bp), %bx */
+ /* ES:BX=0000:1000 */
+ jnz 1f
+
+ //at this time, the gcc cannot generate 3 byte code
+ .byte 0xC4, 0x5E, 0xFA /* lesw -6(%bp), %bx */
+ /* ES:BX=1000:0000 */
+ //. = . - (. - read_block) / 6
+1:
+ movzbl 0x0d(%bp), %ecx /* CX=sectors per block */
+ /* ECX high=0 */
+ . = . - (. - 1b) / 6
+ mull %ecx /* EAX=relative sector number */
+ /* EDX=0 */
+ . = . - (. - 1b) / 9
+ addl 0x1c(%bp), %eax /* EAX=absolute sector number */
+
+#if 1
+ /* pass through, saving 4 bytes(call and ret) */
+#else
+ call readDisk_ext2
+ ret
+#endif
+
+/* Read sectors from disk, using LBA or CHS
+ * input: EAX = 32-bit LBA sector number
+ * CX = number of sectors to read
+ * ECX high word = 0
+ * ES:BX = destination buffer
+ *
+ * output: No return on error
+ * BX not changed
+ * ES = ES + 0x20 * CX
+ * EAX = EAX + CX
+ * ZF = 0
+ * CF = 0
+ */
+
+readDisk_ext2:
+2:
+ pushal
+ //xorl %edx, %edx /* EDX:EAX = LBA */
+ pushl %edx /* hi 32bit of sector number */
+ pushl %eax /* lo 32bit of sector number */
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ pushw $1 /* 1 sector to read */
+ pushw $16 /* size of this parameter block */
+
+ //xorl %ecx, %ecx
+ pushl 0x18(%bp) /* lo:sectors per track, hi:number of heads */
+ popw %cx /* ECX = sectors per track */
+ divl %ecx /* residue is in EDX */
+ /* quotient is in EAX */
+ /* EDX high=0, DH=0 */
+ incw %dx /* DL=sector number */
+ popw %cx /* ECX = number of heads */
+ pushw %dx /* push sector number into stack */
+ xorw %dx, %dx /* EDX:EAX = cylinder * TotalHeads + head */
+ divl %ecx /* residue is in EDX, head number */
+ /* quotient is in EAX, cylinder number */
+ /* EDX high=0, EAX high=0 */
+
+
+ xchgb %dl, %dh /* head number should be in DH */
+ /* DL = 0 */
+ popw %cx /* pop sector number from stack */
+ xchgb %al, %ch /* lo 8bit cylinder should be in CH */
+ /* AL = 0 */
+ shlb $6, %ah /* hi 2bit cylinder ... */
+ orb %ah, %cl /* ... should be in CL */
+
+ incw %ax /* AL=1, read 1 sector */
+
+ /* Instead of 0x0e, the LBA indicator at 2(%bp) is
+ *
+ * 0x42 for LBA
+ *
+ * and
+ *
+ * 0x02 for CHS
+ */
+#if 0
+ movb $0x42, %ah
+ /* ebios_ext2 - 1 points to 0x42 that can be changed to 0x02 */
+#else
+ movb $0x02, %ah
+ /* ebios_ext2 - 1 points to 0x02 that can be changed to 0x42 */
+#endif
+ebios_ext2:
+
+ //andb 2(%bp), %ah
+
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb 0x24(%bp), %dl /* drive number */
+ int $0x13
+ jc disk_error_ext2
+ movw %es, %ax
+ addw $0x20, %ax /* here, carry is cleared */
+ movw %ax, %es
+ popaw /* remove parameter block from stack */
+ popal
+ incl %eax /* next sector, here ZF=0 */
+ loop 2b
+ ret
+
+ //. = . - (. - readDisk_ext2)/74
+
+//msg_DiskReadError_ext2:
+//
+// .ascii "disk error\0"
+
+msg_No_grldr_ext2:
+
+ .ascii "No "
+
+filename_ext2:
+#ifdef BOOTGRUB2
+ .ascii "g2ldr\0"
+#else
+ .ascii "grldr\0"
+#endif
+ . = Entry_ext2 + 0x1ee
+
+filename_end_ext2:
+
+ .word (filename_ext2 - Entry_ext2)+(filename_end_ext2 - filename_ext2 - 1)*2048
+
+ . = Entry_ext2 + 0x1f0
+
+disk_error_ext2:
+
+ movw $(msg_DiskReadError_ext2 - Entry_ext2 + 0x7c00), %si
+
+boot_error_ext2:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_ext2:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+#if 1
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+#else
+ /* boot failed, try to hand over the control to supervisor */
+ ldsw (1f + 3 - Entry_ext2)(%bp), %si
+ lodsl
+ cmpl $0x9400b8fa, %eax
+1: jnz 1b /* no supervisor, hang up. */
+ ljmp $0x9400, $(try_next_partition - _start1)
+
+ //. = . - (. - disk_error_ext2) / 30
+#endif
+
+ . = Entry_ext2 + 0x1fe
+
+ .word 0xAA55
+
+ . = _start1 + 0xA00
+
+#define INSIDE_GRLDR
+
+#include "ntfsbs.S"
+
+ . = _start1 + 0x1200
+
+ .arch i586, jumps
+
+#ifdef DEBUG
+
+ . = Entry_ext2 + 0x201
+
+debug_print:
+
+ pushfl
+ pushal
+ movl %eax, %ebp
+ call 2f
+#if 0
+ popal
+ pushal
+ movl %ebx, %ebp
+ call 2f
+ popal
+ pushal
+ movl %ecx, %ebp
+ call 2f
+ popal
+ pushal
+ movl %edx, %ebp
+ call 2f
+ popal
+ pushal
+ movl %esi, %ebp
+ call 2f
+ popal
+ pushal
+ movl %edi, %ebp
+ call 2f
+ popal
+ popfl
+ pushfl
+ pushal
+ pushfl
+ popl %ebp /* flags */
+ call 2f
+ movw %ds, %bp
+ shll $16, %ebp
+ movw %es, %bp
+ call 2f
+ movw $0x0e0d, %ax /* print CR */
+ int $0x10 /* via TTY mode */
+ movw $0x0e0a, %ax /* print LF */
+ int $0x10 /* via TTY mode */
+#endif
+ popal
+ popfl
+ ret
+2:
+ movw $7, %cx
+1:
+ xorw %bx, %bx /* video page 0 */
+ movl %ebp, %eax
+ shrl %cl, %eax
+ shrl %cl, %eax
+ shrl %cl, %eax
+ shrl %cl, %eax
+ andb $0x0f, %al
+ addb $0x30, %al
+ movb $0x0e, %ah /* print char in AL */
+ int $0x10 /* via TTY mode */
+
+ decw %cx
+ testw %cx, %cx
+ jns 1b
+
+ movw $0x0e20, %ax /* print space */
+ int $0x10 /* via TTY mode */
+ ret
+#endif
+
+#if 1
+ /* restore GRLDR_CS */
+
+ /* this code is executed at 0000:MONITOR, which must be a 16-byte
+ * aligned address. The address 0000:MONITOR should be designed in
+ * a way that could avoid memory confliction with volume boot records
+ * (currently FAT12/16/32/NTFS/EXT2/3 are built in).
+ */
+
+ /* CS=code */
+
+ .align 16
+
+restore_GRLDR_CS:
+2:
+ call 1f
+1:
+ popw %bx # instruction pointer of 1b
+ movw %cs, %ax
+ shrw $4, %bx
+ addw %ax, %bx # BX=segment value of this code
+ pushw %bx
+ pushw $(1f - 2b)
+ lret
+1:
+ /* modify gdt base */
+ xorl %eax, %eax
+ movw %bx, %ax
+ shll $4, %eax
+ addl $(gdt -2b), %eax
+ movl %eax, %cs:(gdt - 2b + 2)
+
+ movw $GRLDR_CS, %bx
+ movw %bx, %es
+ movw %ds, %bx # save old DS to BX
+
+ cli
+ lgdt %cs:(gdt - 2b)
+ movl %cr0, %eax
+ orb $1, %al
+ movl %eax, %cr0
+
+ movw $8, %si
+ movw %si, %ds
+
+ xorl %esi, %esi
+ xorl %edi, %edi
+ movl $(0x9000 / 4), %ecx
+
+ cld
+ repz movsl
+
+ movw $16, %si
+ movw %si, %ds
+
+ andb $0xfe, %al
+ movl %eax, %cr0
+
+ movw %bx, %ds # restore DS from BX
+
+ ljmp $GRLDR_CS, $(try_next_partition - _start1)
+
+#endif
+
+# Descriptor tables
+#
+# NOTE: The intel manual says gdt should be sixteen bytes aligned for
+# efficiency reasons. However, there are machines which are known not
+# to boot with misaligned GDTs, so alter this at your peril! If you alter
+# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
+# empty GDT entries (one for NULL and one reserved).
+#
+# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
+# true for the Voyager Quad CPU card which will not boot without
+# This directive. 16 byte aligment is recommended by intel.
+#
+ .align 16
+gdt:
+ /* this is the default null entry in GDT */
+ .word gdt_end - gdt - 1 # gdt limit
+ .long (GRLDR_CS * 16 + gdt - _start1) # linear address of gdt
+ .word 0 # pad 2 bytes
+
+ /* real mode data segment base=0x200000 */
+ .word 0xFFFF, 0
+ .byte 0x20, 0x92, 0, 0
+
+ /* real mode data segment base=0 */
+ .word 0xFFFF, 0
+ .byte 0, 0x92, 0, 0
+
+gdt_end:
+
+helper_start:
+
+ /* helper function begins here
+ * before the call:
+ * CF=1 : indicates an invalid or corrupt entry
+ * CF=0 : indicates a valid entry
+ *
+ * on return:
+ * CF=1 : means "below", try next entry
+ * CF=0,ZF=1 : means "equal", helper did nothing, so we need
+ * a further try to boot via NT bootsector
+ * CF=0,ZF=0 : means "above", helper succeeded, boot it now
+ */
+
+ sti
+
+ /* DS=SS=0x9400 */
+ pushw %cs
+ popw %ds
+
+ pushw $FS_BOOT
+ popw %es
+
+ /* ES=FS_BOOT */
+
+ /* Format of partition information blocks.
+ *
+ * Offset Length in bytes Field
+ * 00h 1 Set to 80h if this partition is active.
+ * 01h 1 Partition's starting head.
+ * 02h 2 Partition's starting sector and track.
+ * 04h(SI) 1 Partition's ID number.
+ * 05h 1 Partition's ending head.
+ * 06h 2 Partition's ending sector and track.
+ * 08h 4 Starting LBA.
+ * 0Ch 4 Partition's length in sectors.
+ */
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ //pushw %si
+ //stc
+ //jc invalid_or_null /* invalid or null entry */
+#if 0
+ /* backup 63 sectors at FS_BOOT:0 to 63 sectors at FS_BOOT:8000
+ * this piece of code is no longer useful.
+ */
+ pushw %es
+ popw %ds
+ xorw %si, %si
+ movw $0x8000, %di
+ movw $0x3f00, %cx
+ cld
+ repz movsw
+#endif
+
+#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
+ testb $0x80, %cs:0x02 /* boot previous MBR first? */
+ jnz 2f /* no, continue to find GRLDR */
+
+ /* yes, call the routine for booting the previous MBR.
+ * it will not return on success.
+ * on failure, it will return here
+ */
+
+ /* before we call the routine, we will check if the user want to
+ * skip this step and continue to find the GRLDR
+ */
+#if 0
+ movw $(press_space_bar_string - _start1), %si
+ cmpw $0x3920, %cs:0x04
+ je 1f
+ movw $(press_hot_key_string - _start1), %si
+1:
+ /* if timeout==0, don't display the message */
+
+ cmpb $0, %cs:0x03
+ je 1f
+ call print_message /* CS:SI points to message string */
+ movw $(press_any_key_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+#else
+ cmpb $0, %cs:0x03
+ je 1f
+ movw $(press_hot_key_pre - _start1), %si
+ call print_message
+ movw $(press_hot_key_name - _start1), %si
+ call print_message
+ movw $(press_hot_key_sub - _start1), %si
+ call print_message
+#endif
+1:
+ call sleep_5_seconds
+ jc 1f /* desired hot-key pressed */
+ call boot_prev_mbr //Error_modify
+1:
+ orb $0x80, %cs:0x02
+2:
+#endif
+ popfw
+ popal
+ popw %es
+ popw %ds
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ //cmpb $0x0e, 0x00 /* EBIOS previously checked OK? */
+ //jbe 1f /* yes, skip the check */
+ movb $0x02, 0x00 /* initialise this byte to 0x02 */
+ movb $0x41, %ah /* EBIOS check existence */
+ movw $0x55aa, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xaa55, %bx
+ jnz 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ movb $0x42, 0x00 /* LBA supported, save 0x42 to 9400:0000 */
+1:
+ popfw
+ popal
+ popw %es
+ popw %ds
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ pushaw
+ cmpw $0x1c2, %si
+ jne 1f
+ /* initialize partition number and partition entries end */
+ movw $0xffff, 0x1bc /* hd partition number */
+ movw $0x01fe, 0x1ba /* partition entries end */
+1:
+ pushw %dx
+ testb %dl, %dl
+ jns 1f /* floppy, use normal CHS mode */
+ cmpw $0x1f2, %si /* is it a primary partition? */
+ ja 2f /* no, it is an extended partition */
+ movl 4(%si), %eax
+ movl %eax, 8(%si) /* parent part_start saved here */
+ xorl %eax, %eax
+ movl %eax, 4(%si) /* current part_start(0) saved here */
+2:
+ //movl -4(%si), %eax
+ //cmpl $0xfffffe00, %eax /* check the starting CHS */
+ //jb 1f /* use normal CHS mode */
+
+ /* get CHS total number of sectors */
+ pushw %es
+ pushw %ds
+ movb $8, %ah /* read drive parameters changes DX,ES,DI */
+ //movb $0x80, %dl /* BIOS drive number is in DL */
+ int $0x13
+ popw %ds
+ popw %es
+ jc 3f
+ testb $63, %cl
+ jnz 2f
+3:
+ /* failed to get drive parameters, use maximum value */
+#if 0
+ popw %dx
+ pushw %dx
+ cmpb $0x80, %dl
+ jne 3f
+ pushw %ds
+ xorw %ax, %ax
+ movw %ax, %ds
+ cmpb $0, 0x475
+ popw %ds
+ je 3f
+
+3:
+#endif
+ movw $0xffff, %cx
+ movw %cx, %dx
+2:
+ //xorl %eax, %eax
+ movzbl %dh, %eax
+ incw %ax
+ movzbl %cl, %edx
+ andb $63, %dl
+ mulw %dx /* DX=0, AX=product */
+ shrb $6, %cl
+ xchgb %cl, %dh
+ xchgb %ch, %dl
+ incw %dx /* DX=total cylinders */
+ mull %edx /* EDX=0, EAX=product */
+
+ /* check the partition's starting LBA */
+ movl 4(%si), %ebx
+ addl 8(%si), %ebx /* EBX=start_LBA */
+
+ testl %ebx, %ebx
+ je 1f
+
+ ///* we always use LBA mode */
+ ////cmpl %eax, %ebx
+ ////jb 1f /* use normal CHS mode */
+ cmpb $0x42, 0x00 /* EBIOS present? */
+ jne 1f /* no, skip the LBA mode int13 call */
+
+ /* load partition boot track to FS_BOOT using LBA mode */
+ popw %ax /* AX=orig DX which holds drive number DL */
+ pushw %ax
+ pushl %edx /* EDX=0, higher 4 bytes of starting LBA */
+ pushl %ebx /* lower 4 bytes of starting LBA */
+ pushw %es /* ES=FS_BOOT */
+ pushw %dx /* DX=0, ES:0 is the buffer */
+ //pushl $0x003f0010 /* transfer 63 sectors */
+ pushw $0x3f /* transfer 63 sectors */
+ pushw $0x10 /* size of disk address packet */
+ xchgw %ax, %dx /* restore drive number DL from AL */
+ movb $0x42, %ah /* extended read */
+ movw %sp, %si /* DS:SI points to disk address packet */
+ int $0x13 /* ignore the read failure */
+ popaw /* adjust the stack */
+ jc 1f
+ popw %dx
+ popaw
+
+ //popw %ax /* discard flags in the stack */
+ popfw
+ clc
+
+ pushfw /* push new flags with CF=0 */
+ pushaw
+ pushw %dx
+1:
+ popw %dx
+ popaw
+
+ popfw
+ popal
+ popw %es
+ popw %ds
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ pushw %si
+
+ pushfw
+ pushw %es
+//---------------------------------------------------------
+ /* print "Try (hd0,n): " or "Try (fd0): "*/
+ pushw %ds
+ popw %es /* ES=DS=CS=0x9400 */
+
+ cld /* for stosb */
+ xorw %ax, %ax
+ testb %dl, %dl
+ jns 1f /* floppy */
+ /* hard drive */
+#if 0
+ movw %si, %ax
+ subw $0x1c2, %ax
+ shrw $4, %ax
+ cmpw $0x1fe, %si /* is in MBR? */
+ jb 1f /* yes */
+ /* no, it is an entry in an extended partition */
+ movb $0xFC, (add_sub_si + 2 - _start1) /* addw $-4, %si */
+ incw 0x1bc /* logical partition number */
+ movb 0x1bc, %al
+#else
+ incw 0x1bc /* logical partition number */
+ movw 0x1bc, %ax
+ cmpb $4, %al
+ jb 1f
+ movb $0xFC, (add_sub_si + 2 - _start1) /* addw $-4, %si */
+#endif
+1:
+ /* AL=partition number, AH=0 */
+ pushw %ax
+
+ movw $(partition_message - _start1 + 7), %di /* drive type */
+ movb %dl, %al
+ shrb $7, %al /* drive type: floppy=0, harddrive=1 */
+ shlb $1, %al
+ addw $0x6466, %ax /* "fd" or "hd" */
+ stosw
+ movb %dl, %al
+ andb $0x7f, %al /* drive number */
+ aam /* convert binary to decimal, AH=high, AL=low */
+ testb %ah, %ah
+ jz 1f
+ addb $0x30, %ah
+ movb %ah, (%di)
+ incw %di
+1:
+ addb $0x30, %al
+ stosb
+
+ popw %ax
+
+ testb %dl, %dl
+ jns 2f /* floppy */
+ /* this is a hard drive, the partition number is in AL */
+ movb $0x2c, (%di) /* "," */
+ incw %di
+ aam /* convert binary to decimal, AH=high, AL=low */
+ testb %ah, %ah
+ jz 1f
+ addb $0x30, %ah
+ movb %ah, (%di)
+ incw %di
+1:
+ addb $0x30, %al
+ stosb
+2:
+ movl $0x00203a29, (%di) /* "): \0" */
+
+ movw $(partition_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+//---------------------------------------------------------
+ popw %es
+ popfw
+ //stc
+ jc invalid_or_null /* invalid or null entry */
+
+ xorw %si, %si
+ pushw %es
+ popw %ds
+
+ /* DS=ES=FS_BOOT */
+
+ /* First, check for ext2 filesystem */
+
+ cmpw $0xEF53, 0x438 /* Magic signature */
+ jnz 1f
+ xorl %eax, %eax
+ cmpl %eax, 0x400 /* s_inodes_count */
+ jz 1f
+ cmpl %eax, 0x404 /* s_blocks_count */
+ jz 1f
+// cmpw %ax, 0x458 /* s_inode_size, usually 0x80 */
+// jz 1f
+ cmpl %eax, 0x420 /* s_blocks_per_group */
+ jz 1f
+ cmpl %eax, 0x428 /* s_inodes_per_group */
+ jz 1f
+ movl 0x414, %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, %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 */
+ /* EAX= 0 */
+
+ movw $0x80, %ax /* EXT2_GOOD_OLD_INODE_SIZE */
+ movw %ax, %cs:0x826 /* inode size */
+ movl 0x44C, %ecx /* ECX=s_rev_level */
+ jecxz 3f /* EXT2_GOOD_OLD_REV */
+ movw 0x458, %ax /* AX=s_inode_size */
+ testw %ax, %ax
+ jz 1f /* invalid inode size */
+ pushw %ax
+ pushw %dx
+ movb 0x418, %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, %cs:0x826 /* inode size */
+3:
+ /* BX = 0 */
+
+ /* super block is sane */
+
+ //pushw %cs
+ //popw %ds
+ ///* DS=SS=0x9400 */
+ ///* ES=FS_BOOT */
+ cld
+ movw $0x800, %si
+ xorw %di, %di
+ movw $0x0200, %cx /* yes, we need 2 sectors if enable debug */
+
+ repz cs movsw /* CS segment override prefix(=0x2E) */
+
+ /* modify the boot partition number */
+
+ /* the boot partition number is at offset 0x25 for ext2 */
+
+ testb %dl, %dl
+ jns 3f /* no modification for floppy */
+ movw $0x25, %di
+ movw %cs:0x1bc, %ax /* partition number */
+ stosb
+3:
+ /* fix for ext2 partition: hidden_sectors, offset 0x1c */
+ popw %si /* DI points to old entry in MBR */
+ pushw %si
+ xorl %eax, %eax /* let hidden_sectors=0 for floppy */
+ testb %dl, %dl
+ jns 3f /* floppy */
+ movl %cs:4(%si), %eax
+ addl %cs:8(%si), %eax
+3:
+ /* BX = 0 */
+
+ movl %eax, %es:0x1c(%bx) /* adjust hidden_sectors for EXT2 */
+
+ /* fix for ext2 partition: EBIOS indicator, offset 0x02 */
+
+ movb %cs:0x00(%bx), %al
+ movb %al, %es:0x02(%bx)
+
+ /* fix for ext2 partition: sectors per block, offset 0x0d */
+ /* fix for ext2 partition: bytes per block, offset 0x0e */
+ /* fix for ext2 partition: dwords per block(dpb), offset 0x14 */
+ /* fix for ext2 partition: square of dpb, offset 0x10 */
+
+ movb %es:0x418, %cl /* s_log_block_size */
+ //incw %cx
+ movl $2, %eax
+ shlw %cl, %ax
+ movb %al, %es:0x0d(%bx)
+ shlw $9, %ax /* block size is word wide */
+ movw %ax, %es:0x0e(%bx)
+ shrw $2, %ax
+ movl %eax, %es:0x14(%bx)
+ addb $8, %cl
+ shll %cl, %eax
+ movl %eax, %es:0x10(%bx)
+
+
+ /* fix for ext2 partition: sectors per track, offset 0x18 */
+ /* fix for ext2 partition: number of heads, offset 0x1a */
+#if 1
+ pushw %ds
+ pushw %es
+ pushw %bx
+ pushw %dx
+ movb $8, %ah /* read drive parameters changes DX,ES,DI,BX */
+ movb $0x80, %dl /* BIOS drive number is in DL */
+ int $0x13
+ movw %dx, %ax
+ popw %dx
+ popw %bx
+ popw %es
+ popw %ds
+ jc 3f
+ andb $63, %cl
+ jz 3f
+ movb %cl, %es:0x18(%bx)
+ shrw $8, %ax
+ incw %ax
+ movw %ax, %es:0x1a(%bx)
+3:
+#else
+ testb %dl, %dl
+ jns 3f /* floppy */
+ popw %di /* DI points to old entry in MBR */
+ pushw %di
+ movw %cs:1(%di), %ax
+ andb $63, %ah
+ movb %ah, %es:0x18
+ xorb %ah, %ah
+ incw %ax
+ movw %ax, %es:0x1a
+3:
+#endif
+
+ /* fix for ext2 partition: s_inodes_per_group, offset 0x28 */
+ movl %es:0x428, %eax /* s_inodes_per_group */
+ movl %eax, %es:0x28(%bx)
+
+ /* fix for ext2 partition: block number for group descriptors, offset 0x2c */
+ /* At which block the group descriptors begin? */
+ movl %es:0x414, %eax /* s_first_data_block */
+ incw %ax
+ movl %eax, %es:0x2c(%bx)
+
+ /* fix for ext2 partition: on error go back to supervisor, offset 0x01fc */
+ movw $0x01fc, %si
+ movw %si, %di
+ lodsw
+ cmpw $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
+ jnz 3f
+ decw %ax /* AL=0xEA, ljmp */
+ stosb
+ //movw $(try_next_partition - _start1), %ax
+ movw $MONITOR, %ax
+ stosw
+ //movw %cs, %ax /* AX=0x9400 */
+ xorw %ax, %ax
+ stosw /* the last byte 0x00 is in the next sector! */
+// addw $0x0f, %di
+// movw $(restore_GRLDR_CS - _start1), %si
+// movw $((gdt_end - restore_GRLDR_CS) / 4), %cx
+// .byte 0x2e /* %cs: prefix */
+// repz movsl
+3:
+
+ movw $(EXT2_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ clc
+ jmp move_entries_and_return
+
+1:
+ #; It is not EXT2. Check for FAT12/16/32/NTFS.
+
+ /* DS=ES=FS_BOOT */
+
+ cmpw $0x200, 0x0b(%si) /* bytes per sector */
+ jne 1f /* not a normal BPB */
+ movb 0x0d(%si), %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(%si), %ax /* sectors per track */
+ testw %ax, %ax
+ jz 1f /* invalid if = 0 */
+ cmpw $63, %ax
+ ja 1f /* invalid if > 63 */
+ movw 0x1a(%si), %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(%si) /* media descriptor */
+ jb 1f
+
+ cmpb $0x42, %cs:0x00 /* EBIOS present? */
+ jne 3f
+ //movb $0x41, %ah /* EBIOS check existence */
+ //movw $0x55aa, %bx
+ //int $0x13
+ //jc 3f /* No EBIOS */
+ //cmpw $0xaa55, %bx
+ //jnz 3f /* No EBIOS */
+ //testb $1, %cl
+ //jz 3f /* No EBIOS */
+ movb $0x0e, 0x02(%si) /* force LBA */
+3:
+ cld
+ movw $0x0600, %bx /* FAT12/FAT16 */
+ movw $0x003c, %cx /* FAT12/FAT16 */
+
+ movb 0x10(%si), %al /* number of FATs(NTFS:0, FAT:1,2) */
+ cmpb $2, %al
+ ja 1f /* abnormal FAT */
+ movw 0x11(%si), %ax /* max root entries */
+ testw %ax, %ax
+ jnz 2f /* FAT12/FAT16 */
+
+ /* FAT32 or NTFS */
+ movw 0x13(%si), %ax /* total sectors(small) */
+ testw %ax, %ax
+ jnz 1f /* invalid FAT32 BPB */
+ movw 0x16(%si), %ax /* sectors per FAT(small) */
+ testw %ax, %ax
+ jnz 1f /* invalid FAT32 BPB */
+ movb 0x10(%si), %al /* number of FATs(NTFS:0, FAT:1,2) */
+ testb %al, %al
+ jz 8f
+
+ /* FAT32 */
+ movl 0x20(%si), %eax /* FAT32 total sectors */
+ testl %eax, %eax
+ jz 1f
+ movl 0x24(%si), %eax /* FAT32 sectors per FAT */
+ testl %eax, %eax
+ jz 1f
+ movw $0x0400, %bx /* FAT32 */
+ movw $0x0058, %cx /* FAT32 */
+ movw $(FAT32_message - _start1), %si
+ jmp 7f
+8:
+ /* NTFS */
+ movl 0x20(%si), %eax /* FAT32 total sectors */
+ testl %eax, %eax
+ jnz 1f
+ //movw 0x11(%si), %ax /* max root entries */
+ //testw %ax, %ax
+ //jnz 1f
+ movw 0x0e(%si), %ax /* reserved sectors */
+ testw %ax, %ax
+ jnz 1f
+
+ /* BUG fix for extended NTFS partition */
+ popw %si /* SI points to old entry in MBR */
+ pushw %si
+ xorl %eax, %eax /* let hidden_sectors=0 for floppy */
+ testb %dl, %dl
+ jns 3f /* floppy */
+ movl %cs:4(%si), %eax
+ addl %cs:8(%si), %eax
+3:
+ movl %eax, 0x1c /* adjust hidden_sectors for NTFS */
+
+ movb %dl, 0x24 /* adjust drive number for NTFS */
+
+#if 1
+ // Load NTFS using internal boot sector at 0xA00
+
+ movw $(NTFS5_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ movw $0xA00, %bx
+ movw $0x52, %cx
+
+ pushw %cs
+ popw %ds
+
+ /* DS=SS=0x9400 */
+ /* ES=FS_BOOT */
+
+ movw %bx, %si
+ xorw %di, %di
+ lodsw
+ stosw
+ addw %cx, %si
+ addw %cx, %di
+ movw $0x800, %cx
+ subw %di, %cx
+
+ repz movsb
+
+ /* modify the boot partition number */
+ movb %es:1, %al
+ addb $5, %al /* AL is less than 0x80 */
+ cbw /* AH=0 */
+ xchgw %ax, %di /* move AX to DI */
+ movb $0xff, %al /* partition=whole drive for floppy */
+ testb %dl, %dl
+ jns 3f /* no modification for floppy */
+ movb 0x1bc, %al /* partition number */
+3:
+ stosb
+
+ /* fix for NTFS partition: on error go back to supervisor, offset 0x01fa */
+
+ movw $0x01fa, %di
+ movw %es:(%di), %ax
+ cmpw $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
+ jnz 3f
+ decw %ax /* AL=0xEA, ljmp */
+ stosb
+ //movw $(try_next_partition - _start1), %ax
+ movw $MONITOR, %ax
+ stosw
+
+ //movw %cs, %ax /* AX=0x9400 */
+ xorw %ax, %ax
+ stosw /* DI=0x01ff */
+3:
+ clc
+ jmp move_entries_and_return
+
+#else
+
+ /* modify the boot partition number */
+ movb $0xB6, %al /* 0xB6="MOV DH,imm8" */
+ movb %cs:0x1bc, %ah
+ testb %dl, %dl
+ js 3f
+ movb $0xff, %ah /* partition number for floppy is whole drive */
+3:
+ /* before the call:
+ * AH= partition number
+ * AL= 0xB6 ; 0xB6 is opcode of "MOV DH,imm8"
+ * DL= drive number
+ *
+ * on return: CF=0 if there is NTFS boot record;
+ * CF=1 otherwise.
+ * CF of flags_orig on the stack will set if CF=1
+ */
+
+ call modify_NTFS_boot_record
+ //jnc move_entries_and_return
+ //movw $(NTFS5_message - _start1), %si
+ ////jmp 4f
+ //call print_message /* CS:SI points to message string */
+ //stc
+ jmp move_entries_and_return
+
+#endif
+
+2:
+ /* FAT12/FAT16 */
+ movb 0x10(%si), %al /* number of FATs(NTFS:0, FAT:1,2) */
+ testb %al, %al
+ jz 1f
+ movw 0x16(%si), %ax /* sectors per FAT(small) */
+ testw %ax, %ax
+ jz 1f
+ movw $(FAT16_message - _start1), %si
+ cmpw $12, %ax
+ ja 7f
+ movw $(FAT12_message - _start1), %si
+7:
+ /* BUG fix for extended FAT12/16/32 partition */
+ popw %di /* DI points to old entry in MBR */
+ pushw %di
+ xorl %eax, %eax /* let hidden_sectors=0 for floppy */
+ testb %dl, %dl
+ jns 3f /* floppy */
+ movl %cs:4(%di), %eax
+ addl %cs:8(%di), %eax
+3:
+ movl %eax, 0x1c /* adjust hidden_sectors for FAT */
+
+ call print_message /* CS:SI points to message string */
+ pushw %cs
+ popw %ds
+ /* DS=SS=0x9400 */
+ /* ES=FS_BOOT */
+ movw %bx, %si
+ xorw %di, %di
+ lodsw
+ stosw
+ addw %cx, %si
+ addw %cx, %di
+ movw $0x0200, %cx
+ subw %di, %cx
+ repz movsb
+ /* modify the boot partition number */
+ movb %es:1, %al
+ addb $5, %al /* AL is less than 0x80 */
+ cbw /* AH=0 */
+ xchgw %ax, %di /* move AX to DI */
+ movb $0xff, %al /* partition=whole drive for floppy */
+ testb %dl, %dl
+ jns 3f /* no modification for floppy */
+ movb 0x1bc, %al /* partition number */
+3:
+ stosb
+
+ /* fix for FAT12/16/32 partition: on error go back to supervisor, offset 0x01fa */
+ //pushw %es
+ //popw %ds
+ movw $0x01fa, %di
+ //movw %di, %si
+ //lodsw
+ movw %es:(%di), %ax
+ cmpw $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
+ jnz 3f
+ decw %ax /* AL=0xEA, ljmp */
+ stosb
+ //movw $(try_next_partition - _start1), %ax
+ movw $MONITOR, %ax
+ stosw
+ //movw %cs, %ax /* AX=0x9400 */
+ xorw %ax, %ax
+ stosw /* DI=0x01ff */
+3:
+
+ clc
+ jmp move_entries_and_return
+1:
+ #; It is not FAT12/16/32/NTFS. Check for extended partition.
+
+ /* DS=ES=FS_BOOT */
+
+ pushw %cs
+ popw %es
+
+ /* ES=SS=0x9400 */
+ /* DS=FS_BOOT */
+
+ popw %si
+ pushw %si
+ cmpb $0x05, %es:(%si) /* extended */
+ je 1f
+ cmpb $0x0f, %es:(%si) /* Win95 extended (LBA) */
+ je 1f
+ cmpb $0x15, %es:(%si) /* hidden extended */
+ je 1f
+ cmpb $0x1f, %es:(%si) /* hidden win95 extended (LBA) */
+ je 1f
+ cmpb $0x85, %es:(%si) /* Linux extended */
+ je 1f
+ movw $(non_MS_message - _start1), %si
+4:
+ call print_message /* CS:SI points to message string */
+ stc
+ jmp move_entries_and_return
+1:
+ /* extended partition entry */
+ cmpw $0x1fe, %si
+ jb 1f
+ decw %es:0x1bc /* count the partitions in extended zone */
+1:
+ movw $(extended_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+ movw $0x1be, %si
+ movw $4, %cx
+5:
+ //xorl %eax, %eax
+ //cmpl %eax, (%si)
+ //jnz 2f
+ movl (%si), %eax
+ cmpw 2(%si), %ax /* Is EAX high word equal to AX? */
+ jnz 2f
+ cmpb %al, %ah /* Is AL=AH? */
+ jnz 2f
+
+ /* now all 4 bytes in EAX are equal to each other. */
+ cmpl %eax, 4(%si)
+ jnz 2f
+ cmpl %eax, 8(%si)
+ jnz 2f
+ cmpl %eax, 12(%si)
+ jz 3f /* entry with 16 dups of a byte means empty entry */
+2:
+ movb (%si), %al
+ shlb $1, %al
+ jnz 1f
+ //jnz 3f /* invalid entry is treated as empty entry */
+ movb 2(%si), %al
+ and $63, %al /* starting sector number */
+ jz 1f
+ //jz 3f /* invalid entry is treated as empty entry */
+ movb 6(%si), %al
+ and $63, %al /* ending sector number */
+ jz 1f
+ //jz 3f /* invalid entry is treated as empty entry */
+ movl 8(%si), %eax /* starting LBA */
+ testl %eax, %eax
+ jz 1f
+ //jz 3f /* invalid entry is treated as empty entry */
+ movl 12(%si), %eax /* total number of sectors in partition */
+ testl %eax, %eax
+ jz 1f
+3:
+ addw $16, %si
+ loop 5b
+ cmpw $0xaa55, (%si)
+ jnz 1f
+
+ movw $0x1be, %si
+ movw $4, %cx
+ popw %bx /* the old SI points to extended partition ID in MBR */
+ pushw %bx
+5:
+#if 1
+ //xorl %eax, %eax
+ //cmpl %eax, (%si)
+ //jnz 2f
+ movl (%si), %eax
+ cmpw 2(%si), %ax /* Is EAX high word equal to AX? */
+ jnz 2f
+ cmpb %al, %ah /* Is AL=AH? */
+ jnz 2f
+
+ /* now all 4 bytes in EAX are equal to each other. */
+ cmpl %eax, 4(%si)
+ jnz 2f
+ cmpl %eax, 8(%si)
+ jnz 2f
+ cmpl %eax, 12(%si)
+ jz 3f /* entry with 16 dups of a byte means empty entry */
+2:
+ /* now it is an acceptable entry */
+ movw %es:0x1ba, %di /* partition entries end */
+ /* ensure our stack not to be overwritten by the partition entries */
+ cmpw $0x83f0, %di
+ ja 3f /* try next */
+ /* ensure our code not to be overwritten by the partition entries */
+ cmpw $0x3fe, %di
+ jne 6f
+ /* more entries stores at 0x9be00-0x9c3ff */
+ movw $0x7e00, %di
+ movw %di, %es:0x1ba
+6:
+ addw $16, %es:0x1ba /* increment partition entries end */
+
+ lodsl
+ stosl
+ lodsl
+ stosl
+
+ xchgw %ax, %dx /* save AL(the partition ID)to DL */
+
+ lodsl
+ xchgl %eax, %edx /* restore AL from DL(the partition ID)
+ * and save EAX to EDX */
+ cmpb $0x05, %al
+ je 6f
+ cmpb $0x0f, %al
+ je 6f
+ cmpb $0x15, %al
+ je 6f
+ cmpb $0x1f, %al
+ je 6f
+ cmpb $0x85, %al
+ je 6f
+ /* normal partition, copied to 0x941fe-0x943fb */
+ addl %es:4(%bx), %edx /* current partition start */
+6:
+ /* extended partition, copied to 0x941fe-0x943fb */
+ xchgl %eax, %edx /* restore or update EAX from EDX */
+ stosl
+ lodsl /* adjust SI only */
+ movl %es:8(%bx), %eax /* parent partition start ... */
+ stosl /* ... stored here */
+ jmp 2f
+3:
+ addw $16, %si
+#endif
+ //. = 5b + 0x7c
+2:
+ loop 5b
+
+ /* extended partition is not a normal one, so set carry to try next */
+ stc
+ jmp move_entries_and_return
+
+invalid_or_null:
+1:
+ movw $(invalid_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+ stc
+
+move_entries_and_return:
+ popw %si
+ pushfw
+ pushw %cs
+ popw %ds
+ pushw %cs
+ popw %es
+ pushw %si
+ cmpw $0x202, %si
+ jne 1f
+ /* move entries backward 1 entry */
+ movw $0x1fe, %di
+ movw $0x20e, %si
+ movw $0xf8, %cx /* 0x1f0 bytes = 0xf8 words */
+ cld /* move upward */
+ repz movsw
+ movw $0x3ee, %di
+ movw $0x7e00, %si
+ movw $0x8, %cx /* 0x10 bytes = 0x8 words */
+ cld /* move upward */
+ repz movsw
+ movw $0x7e00, %di
+ movw $0x7e10, %si
+ movw $0x2f8, %cx /* 0x5f0 bytes = 0x2f8 words */
+ cld /* move upward */
+ repz movsw
+ cmpw $0x7e10, 0x1ba
+ jne 2f
+ movw $0x40e, 0x1ba
+2:
+ subw $0x10, 0x1ba
+
+1:
+ popw %si
+ movw $0x1ff, (add_sub_si + 5 - _start1)
+ cmpw $0x1fe, 0x1ba
+ jne 1f
+ decw (add_sub_si + 5 - _start1)
+ cmpw $0x31b2, %si /* floppy? */
+ je 1f /* yes */
+ cmpw $0x1f2, %si
+ ja 2f /* logical partition */
+ jb 1f /* primary partition 0, 1, 2 */
+ /* primary partition 3 */
+ cmpw $0x0003, 0x1bc /* are there any logical partitions? */
+ ja 1f /* yes */
+2:
+inc_hard_drive:
+
+ /* all partitions on the drive have been checked, try next drive.
+ *
+ * the current stack is:
+ *
+ * SP + 38 : DS
+ * SP + 36 : ES
+ * SP + 32 : EAX
+ * SP + 28 : ECX
+ * SP + 24 : EDX
+ * SP + 20 : EBX
+ * SP + 16 : ESP_temp
+ * SP + 12 : EBP
+ * SP + 8 : ESI
+ * SP + 4 : EDI
+ * SP + 2 : flags_orig
+ * SP : flags
+ *
+ */
+
+ /* get total hard drives */
+ xorw %ax, %ax
+ movw %ax, %ds
+ movb 0x475, %dh
+ pushw %cs
+ popw %ds
+// cmpb $16, %dh
+// jnb 2f
+// movb $16, %dh
+//2:
+ orb $0x80, %dh /* CF=0, DH=Max harddrive number + 1 */
+ //xchgw %ax, %cx /* CL=Max harddrive number + 1, CH=0 */
+ movw %sp, %bp
+ movb 24(%bp), %dl /* BIOS drive number is in DL */
+2:
+ jnc 3f
+ call print_message /* CS:SI points to message string */
+ movw $(drive_number_string - _start1), %si
+ movb %dl, %al
+ andb $0x7f, %al
+ aam /* AH=high decimal, AL=low decimal */
+ addw $0x3030, %ax
+ xchgb %al, %ah
+ movw %ax, 9(%si)
+ call print_message /* CS:SI points to message string */
+3:
+ incw %dx
+ cmpb %dh, %dl
+ jnb 2f /* all drives checked, try floppy finally */
+
+ pushw %bx
+ pushw %dx
+ pushw %es
+ movb $8, %ah /* read drive parameters changes DX, ES, DI */
+ int $0x13
+ popw %es
+ jc 3f /* try next hard drive */
+ //xchgw %ax, %cx /* this moves CL to AL */
+ andb $63, %cl /* CL=sectors per track, CF cleared */
+ stc
+ jz 3f /* try next hard drive */
+ popw %dx /* get DL */
+ popw %bx
+ movb %dl, %ch /* DL saved at BP high byte in the stack */
+ pushw %cx /* push new BX onto stack */
+ pushw %dx
+ //movb $0x02, %ah
+ //movw %ax, %si /* save AX to SI: read 1 track */
+ movw $0x201, %ax /* read 1 sector */
+ movw $0x7e00, %bx /* read MBR to 9400:7e00 */
+ movw $1, %cx
+ //popw %dx
+ //pushw %dx
+ xorb %dh, %dh
+ stc
+ int $0x13
+ sti
+3:
+ popw %dx
+ popw %bx /* BL=sectors per track, BH=DL */
+
+ //movw %si, %bx /* BL=sectors per track */
+
+ movw $(Error_while_reading_string - _start1), %si
+ jc 2b /* read failure, try next hard drive */
+
+ /* on seccessful return, should be: ah=0 for OK, al=1 for 1 sector */
+ //decw %ax /* some BIOSes return incorrect AL */
+ testb %ah, %ah
+ stc
+ jnz 2b
+
+ /* The new partition table might be empty or invalid.
+ * Move the new partition table onto the old one while checking
+ */
+
+ //movb %dl, %bh /* DL saved at BP high byte in the stack */
+
+ movw $0x7fbe, %si
+ movw $0x01be, %di
+
+3:
+ cmpw $0x1fe, %di
+ jnb 3f
+
+ xorl %ecx, %ecx
+
+ lodsl
+ stosl
+ orl %eax, %ecx
+ lodsl
+ stosl
+ orl %eax, %ecx
+ lodsl
+ stosl
+ orl %eax, %ecx
+ lodsl
+ stosl
+ orl %eax, %ecx
+ jecxz 3b /* null entry, check next */
+
+ //lodsw
+ //stosw
+ movb -16(%si), %al
+ shlb $1, %al
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_boot_indicator_string - _start1), %si
+ jnz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsw
+ //stosw
+ movb -14(%si), %al
+ andb $63, %al
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_sectors_per_track_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsw
+ //stosw
+ //lodsw
+ //stosw
+ movb -10(%si), %al
+ andb $63, %al
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_sectors_per_track_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsl
+ //stosl
+ movl -8(%si), %eax
+ testl %eax, %eax
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_start_sector_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+
+ //lodsl
+ //stosl
+ movl -4(%si), %eax
+ testl %eax, %eax
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_end_sector_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+
+ jmp 3b
+3:
+ cmpw $0xAA55, (%si)
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(no_boot_signature_string - _start1), %si
+ jnz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsw
+ //stosw /* store boot signature */
+
+ /* Now the partition table is OK */
+
+ movw %bx, 12(%bp) /* adjust BP in the stack */
+
+ movw $0x1b2, 8(%bp) /* adjust SI in the stack */
+
+ /* temp change the code: call self_modify_once
+ *
+ * "call self_modify_once" at add_sub_si is:
+ *
+ * .byte 0xE8
+ * .word (self_modify_once - add_sub_si - 3)
+ *
+ */
+ movb $0xE8, (add_sub_si - _start1)
+ movw $(self_modify_once - add_sub_si - 3), (add_sub_si + 1 - _start1)
+
+ /* initialize partition number and partition entries end */
+ movw $0xffff, 0x1bc /* hd partition number */
+ movw $0x01fe, 0x1ba /* partition entries end */
+
+ jmp 1f
+2:
+ /* get here if all drives have been checked */
+#if 0
+ movw $0x202, 8(%bp) /* adjust SI in the stack */
+
+ /* restore the original code: addw $-4, %si */
+ movw $0xC683, (add_sub_si - _start1) /* 0x83, 0xC6 */
+ movb $0xFC, (add_sub_si + 2 - _start1) /* 0xFC */
+#endif
+ //--------------------------------------------------------------------
+ /* change the code: jmp Error_modify
+ *
+ * "jmp Error_modify" at Error_or_prev_MBR:
+ *
+ * .byte 0xE9
+ * .word (Error_modify - Error_or_prev_MBR - 3)
+ *
+ */
+ movb $0xE9, (Error_or_prev_MBR - _start1)
+ movw $(Error_modify - Error_or_prev_MBR - 3), (Error_or_prev_MBR + 1 - _start1)
+ //--------------------------------------------------------------------
+
+ //--------------------------------------------------------------------
+ /* floppy search disabled ? */
+#if 0
+ testb $1, 0x02 /* test bit0 of the third byte */
+ jz 1f /* zero means floppy search enabled */
+ /* 0x1fd or below means disable floppy search */
+ decw (add_sub_si + 5 - _start1)
+#else
+ movb 0x02, %al
+ andb $0x01, %al
+ subb %al, (add_sub_si + 5 - _start1)
+#endif
+ //--------------------------------------------------------------------
+
+1:
+#if 0
+ popfw
+ lahf /* Load Flags into AH Register. */
+ /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
+ /* CF will be moved to ZF */
+ movb %ah, %al
+ andb $1, %al /* CF=0 */
+ shlb $6, %al /* move CF to ZF */
+ popfw
+ lahf /* Load Flags into AH Register. */
+ /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
+ andb $0xbf, %ah /* 0xbf= binary 1011 1111. It clears ZF */
+ orb %al, %ah
+#else
+ popw %ax /* AX=Flags */
+ popfw /* Flags_orig */
+ lahf /* Load Flags_orig into AH Register. */
+ /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
+ shlb $2, %ah
+ rorw $2, %ax /* move CF of Flags to ZF of Flags_orig */
+#endif
+
+ sahf /* update flags */
+ /* current CF is the CF of Flags_orig */
+ /* current ZF is the CF of Flags */
+ jc 1f /* CF=1 means failed in loading bootsector */
+ popal /* get drive number DL */
+ pushal
+ pushfw
+ cmpb $0xff, %cs:0x06
+ jz 2f
+ movb %cs:0x1bc, %dh
+ testb %dl, %dl
+ js 3f
+ movb $0xff, %dh /* partition # for floppy is "whole drive" */
+3:
+ cmpw %cs:0x06, %dx
+ jz 2f
+ popfw
+ stc
+ pushfw
+2:
+ popfw
+1:
+ popal
+ popw %es
+ popw %ds
+ ret
+
+self_modify_once:
+ /* when we get here, SI should be 0x1b2, and BP high holds DL */
+ addw $12, %si /* 0x83, 0xC6, 0x0C */
+ movw %bp, %ax
+ movb %ah, %dl
+
+ /* note: DS=0x9400 */
+
+ /* restore the original code: addw $12, %si */
+ movw $0xC683, (add_sub_si - _start1) /* 0x83, 0xC6 */
+ movb $0x0C, (add_sub_si + 2 - _start1) /* 0x0C */
+ ret
+
+Error_modify:
+ cmpb $0xff, %cs:0x06 /* preferred drive? */
+ jz 1f /* not active. Turn to the final step. */
+
+ /* preferred drive is already handled, so de-activate it now. */
+ movb $0xff, %cs:0x06
+
+ /* we will do the second pass, from drive 0x80. */
+ movb $0x7f, %dl /* this will become 0x80 after inc. */
+
+ /* pass "error" to PUSHF, simulating a load failure, in order
+ * to try the first entry after return from the helper function.
+ */
+
+ stc
+
+ pushw $(helper_call + 3 - _start1) /* return address */
+ pushw %cs /* 0x9400, it is for DS. */
+ pushw $FS_BOOT /* 0x0d00, it is for ES. */
+ pushal
+ //pushl %eax
+ //pushl %ecx
+ //pushl %edx
+ //pushl %ebx
+ //pushl %esp
+ //pushl %ebp
+ //pushl %esi
+ //pushl %edi
+ pushfw /* CF=1 */
+ pushfw
+
+ pushw %cs
+ popw %es /* ES=0x9400 */
+
+ /* redo from start: DL will be 0x80 after inc. */
+ jmp inc_hard_drive
+1:
+boot_prev_mbr:
+
+ /* prepare to boot the previous MBR */
+
+ /* at this moment DS=0x9400, ES=$FS_BOOT or ES=0x9400 */
+ xorw %ax, %ax
+ //pushw %ax /* AX=0, for the segment of 0000:7c00 */
+ movw %ax, %es /* ES=0x0000 */
+ movw %ax, %ds /* DS=0x0000 */
+ pushw %ds
+ pushw %es
+ movw $0x0202, %ax /* read 2 sectors ... */
+ movw $0x7A00, %bx /* ... to 0000:7A00 */
+ //pushw %bx /* BX=0x7c00, for the offset of 0000:7c00 */
+ movw $0x0001, %cx /* from the first sector ... */
+ movw $0x0080, %dx /* ... of the first hard drive */
+ stc
+ int $0x13
+ sti
+ popw %es
+ popw %ds
+ jc 1f
+ testb %ah, %ah
+ jnz 1f
+ cmpw $0xAA55, 0x7dfe
+ jne 1f
+ cmpw $0xAA55, 0x7bfe
+ jne 1f
+
+ /* has a valid partition table ? */
+ movw $0x7dbe, %si
+3:
+ cmpw $0x7dfe, %si
+ jnb 3f /* partition table is OK */
+ movw $4, %cx
+
+ movw %si, %di
+2:
+ lodsl
+ negl %eax
+ jc 2f
+ loop 2b
+ /* empty entry, check next */
+ jmp 3b
+2:
+ /* non-empty entry */
+ movw %di, %si
+
+ lodsw
+ shlb $1, %al
+ jnz 2f
+ lodsw
+ andb $63, %al
+ jz 2f
+ lodsw
+ lodsw
+ andb $63, %al
+ jz 2f
+ lodsl
+ negl %eax
+ jnc 2f
+ lodsl
+ negl %eax
+ jc 3b
+2:
+ stc /* invalid partition table */
+3:
+ pushfw
+
+ /* disable the boot of non-MBR bootsector ? */
+ testb $2, %cs:0x02 /* test bit1 of the third byte */
+ jz 2f /* zero means non-MBR enabled */
+ popfw
+ jc 1f /* invalid partition table, print "Error" */
+
+ /* the partition table is valid */
+ pushfw
+
+2:
+ /* the check passed, and the boot is permitted */
+ popfw
+
+ jc 2f /* invalid partition table */
+
+ /* use partition table in MBR instead */
+
+ /* copy 72 bytes at 0000:7bb8 to 0000:7db8 */
+
+ movw $0x7bb8, %si
+ movw $0x7db8, %di
+ movw $36, %cx
+ cld
+ repz movsw
+
+2:
+ testb $0x80, %cs:0x02 /* test bit 7 of the third byte */
+ jz 2f /* zero means boot prev-MBR first */
+
+ movw $(Cannot_find_GRLDR_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ movw $(press_space_bar_string - _start1), %si
+ cmpw $0x3920, %cs:0x04
+ je 3f
+ movw $0x3920, %cs:0x04
+ #;movw $(press_hot_key_string - _start1), %si
+3:
+ call print_message /* CS:SI points to message string */
+ movw $(prev_MBR_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+//#else
+// movw $(press_hot_key_pre - _start1), %si
+// call print_message
+// movw $(press_hot_key_name - _start1), %si
+// call print_message
+// movw $(press_hot_key_sub - _start1), %si
+// call print_message
+//#endif
+3:
+ call sleep_5_seconds
+ /* if hot-key is pressed, wait forever until another key is pressed. */
+ movb $0xff, %cs:0x03
+ jc 3b /* desired hot-key is pressed */
+2:
+ /* boot the previous MBR */
+
+ /* clear the DUCE indicator */
+ movl $0, 0x5FC /* DS=ES=0 */
+
+ //movb $0x80, %dl
+ ljmp $0, $0x7c00
+1:
+ /* no previous MBR, print "Error" */
+ ///* Note the 0000:7C00 is on the stack */
+ //popw %ax /* AX=0x0000 */
+ //popw %ax /* AX=0x7C00 */
+
+ testb $0x80, %cs:0x02 /* are we called prior to the GRLDR search? */
+ jnz 1f /* no, it is a failure at last */
+ /* yes, so return to the caller */
+ movw $(continue_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+ call sleep_5_seconds
+ ret
+1:
+ movw $(message_string_helper - _start1), %si
+ call print_message /* CS:SI points to message string */
+1: jmp 1b /* hang */
+
+sleep_5_seconds:
+ /* sleep 5 seconds */
+
+ /* sleep forever if %cs:0x03 is 0xff */
+
+ /* calculate the timeout ticks */
+
+ pushw %ds
+ pushl %esi
+ pushl %edx
+
+ movl $0xffffffff, %edx
+ movzbl %cs:0x03, %eax
+ cmpb $0xff, %al
+ je 1f
+ movl $18, %edx /* 18.2 ticks per second. We simply use 18. */
+ mulw %dx /* EDX=0, EAX=ticks */
+ xchgw %ax, %dx /* EAX=0, EDX=ticks */
+1:
+ xorw %ax, %ax
+ movw %ax, %ds
+ movl 0x46c, %eax /* initial tick */
+ movl %eax, %ecx /* ECX=initial tick */
+ testl %edx, %edx
+ js 1f
+ addl %edx, %eax /* EAX=timeout tick */
+ pushl %eax
+
+ movzbl %cs:0x03, %eax
+ orl %eax, %eax
+ jz 3f
+
+ movw $(hot_key_timeout_pre - _start1), %si
+ pushl %eax
+ call print_message
+ popl %eax
+
+ movw $(hot_key_timeout_num - _start1), %si
+ call print_decimal
+3:
+ movl %ecx, %esi
+ addl $18, %esi
+
+ popl %eax
+ jmp 3f
+1:
+ movl %edx, %eax /* EAX=0xffffffff */
+ movl %edx, %esi
+3:
+ movl 0x46c, %ebx /* EBX=current tick */
+ cmpl %ecx, %ebx
+ jnb 2f
+
+ /* current tick is less than initial tick, this means the ticks have
+ * overflowed to the next day, and EBX is rather small. */
+ xorl %ecx, %ecx
+ movl %edx, %eax
+ movl $18, %esi
+2:
+ /* check if there is any key press. */
+ pushl %eax
+ movb $1, %ah
+ int $0x16
+ pushw %ax
+ pushfw
+
+ movb $0x11, %ah
+ int $0x16
+ jnz 1f
+ popfw
+ jnz 2f
+
+ /* no, there is no key press. */
+
+ popw %ax
+ popl %eax
+
+ cmpl %esi, %ebx
+ jb 4f
+ pushl %esi
+ pushl %eax
+ pushl %edx
+
+
+ subl %esi, %eax
+ xorl %edx, %edx
+ movl $18, %esi
+ divl %esi
+
+ movw $(hot_key_timeout_num - _start1), %si
+ pushl %ebx
+ call print_decimal
+ popl %ebx
+
+ popl %edx
+ popl %eax
+ popl %esi
+ addl $18, %esi
+4:
+ cmpl %eax, %ebx /* timeout? */
+ jbe 3b /* no, continue to wait */
+
+ /* timeout reached, CF=0, no key pressed. */
+ popl %edx
+ popl %esi
+ popw %ds
+ ret
+1:
+ popfw
+2:
+ /* yes, there is a key press. */
+#if 0
+ /* clear the keyboard buffer */
+ movb $1, %ah
+ int $0x16
+ jz 1f /* no keys, end */
+ movb $0, %ah
+ int $0x16 /* discard the key */
+ jmp 1b
+1:
+#endif
+
+ /* check if it is the desired key. */
+
+ xorw %cs:0x04, %ax /* CF=0 */
+ popw %ax
+ je 1f
+ xorw %cs:0x04, %ax /* CF=0 */
+ jne 2f /* not desired, return CF=0 */
+
+ /* remove the desired key from the keyboard buffer. */
+
+ movb $0, %ah
+ int $0x16 /* discard the key */
+ jmp 3f
+1:
+ /* remove the desired key from the keyboard buffer. */
+
+ movb $0x10, %ah
+ int $0x16 /* discard the key */
+3:
+ stc /* CF=1, the desired key pressed */
+2:
+ popl %eax
+ popl %edx
+ popl %esi
+ popw %ds
+ ret
+
+out_decimal:
+ /*
+ * input: EAX = number, CS:SI = buffer
+ */
+
+ pushl %edx
+ pushl %ecx
+ pushw %bx
+
+ movl $10, %ecx
+ movw %si, %bx
+
+1:
+ xorl %edx, %edx
+ divl %ecx
+ addb $'0', %dl
+ movb %dl, %cs:(%si)
+ incw %si
+ orl %eax, %eax
+ jnz 1b
+
+ pushw %si
+
+1:
+ decw %si
+ cmpw %bx, %si
+ jbe 1f
+ movb %cs:(%si), %al
+ xchgb %al, %cs:(%bx)
+ movb %al, %cs:(%si)
+ incw %bx
+ jmp 1b
+1:
+
+ popw %si
+
+ popw %bx
+ popl %ecx
+ popl %edx
+ ret
+
+print_decimal:
+ pushw %si
+ call out_decimal
+
+1:
+ cmpb $'\b', %cs:(%si)
+ jz 2f
+ movb $' ', %cs:(%si)
+ incw %si
+ jmp 1b
+2:
+ popw %si
+ call print_message
+ ret
+
+#if 0
+modify_NTFS_boot_record:
+
+ /* before the call:
+ * AH= partition number
+ * AL= 0xB6 ; 0xB6 is opcode of "MOV DH,imm8"
+ * DL= drive number
+ *
+ * on return: CF=0 if there is NTFS boot record;
+ * CF=1 otherwise.
+ * CF of flags_orig on the stack will set if CF=1
+ */
+
+ /*
+ *
+ * the current stack is:
+ *
+ * SP + 40 : DS
+ * SP + 38 : ES
+ * SP + 34 : EAX
+ * SP + 30 : ECX
+ * SP + 26 : EDX
+ * SP + 22 : EBX
+ * SP + 18 : ESP_temp
+ * SP + 14 : EBP
+ * SP + 10 : ESI
+ * SP + 6 : EDI
+ * SP + 4 : flags_orig
+ * SP + 2 : SI ; SI points to old entry in MBR
+ * SP : return_IP
+ *
+ */
+
+ /* DS=ES=FS_BOOT */
+
+ /* change NTLDR to GRLDR */
+
+ /* check GR or NT or anything else */
+
+ pushw %ax
+
+ movw $0x200, %si
+ lodsw
+ cmpw $5, %ax
+ jne 1f /* failure */
+ lodsw
+ testb %ah, %ah /* high byte of unicode ASCII should be 0 */
+ jne 1f /* failure */
+
+ /* 'N' should be a capital letter */
+
+ cmpb $0x41, %al /* Less than 'A' */
+ jb 1f /* failure */
+ cmpb $0x5A, %al /* Greater than 'Z'*/
+ ja 1f /* failure */
+
+ xchgw %ax, %cx /* save AX to CX. CL='N' */
+
+ lodsw
+ testb %ah, %ah /* high byte of unicode ASCII should be 0 */
+ jne 1f /* failure */
+
+ /* 'T' should be a capital letter */
+
+ cmpb $0x41, %al /* Less than 'A' */
+ jb 1f /* failure */
+ cmpb $0x5A, %al /* Greater than 'Z'*/
+ ja 1f /* failure */
+
+ movb %al, %ch /* save AL to CH. CH='T' */
+
+ lodsw
+ cmpw $0x4C, %ax /* 'L' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x44, %ax /* 'D' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x52, %ax /* 'R' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x04, %ax /* length of "$I30" */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x24, %ax /* '$' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x49, %ax /* 'I' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x33, %ax /* '3' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x30, %ax /* '0' */
+ jne 1f /* failure */
+
+
+ /* assume it is NT bootsector. first, find "NTLDR". CX holds "NT" */
+ movw $0x0100, %di
+ movb %cl, %al /* AL="N" */
+ movb $1, %ah /* AH=Carry for SAHF below */
+ movl $0x52444c00, %ebx /* "LDR" */
+ movb %ch, %bl /* 'T' */
+ movw $0x00fa, %cx
+
+ /* now AL holds 'N' and BL holds 'T' */
+
+ //cld /* already upward */
+3:
+ repnz scasb /* find "N" */
+ jcxz 4f /* gets the end, exit */
+ cmpl %ebx, (%di) /* is it "NTLDR"? */
+ jnz 3b /* no, continue to find */
+
+ /* "NTLDR" is found, so we believe it is NT boot sector. */
+
+ movw $0x5247, -1(%di) /* 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. */
+
+ jc 1f /* failure */
+
+ movl $0x00520047, 0x202 /* change to "G R L D R" */
+
+ /* check NT 4.0 */
+
+ movw $0x406, %si
+ movl (%si), %ebx /* NT 4.0 */
+ cmpl $0x03E8B800, %ebx /* MOV AX, 03E8 */
+ jnz 3f
+
+ movl 0x84, %ebx
+ cmpl $0x680007E8, %ebx /* call 008e; push (0D00) */
+ jnz 3f
+
+// movw 0x154, %bx /* CR LF at end of "A disk read error occurred." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+// movw 0x180, %bx /* CR LF at end of "A kernel file is missing from the disk." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+// movw 0x1A8, %bx /* CR LF at end of "A kernel file is too discontiguous." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+// movw 0x1F8, %bx /* CR LF at end of "NTLDR is compressed." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+
+ movl 0xE8, %ebx
+ cmpl $0x13CD80B2, %ebx /* "B2 80"="mov DL, 80", "CD 13"="int 13" */
+ jnz 3f
+
+ popw %ax
+ movw %ax, 4(%si)
+
+ movl $0x68909090, %ebx /* nop;nop;nop;push (0D00) */
+ movl %ebx, 0x84
+
+// /* change CRLF in NTFS error messages to spaces */
+// movw $0x2020, %bx /* change CRLF to 2 spaces */
+// movw %bx, 0x154
+// movw %bx, 0x180
+// movw %bx, 0x1A8
+// movw %bx, 0x1F8
+
+ movb %dl, 0xE9 /* modify drive number */
+
+ /* modify NTFS boot record */
+ movb $0xea, %al /* ljmp, hand over the control to supervisor */
+ movb %al, 0x122
+ //movw $(try_next_partition - _start1), %ax /* offset for ljmp */
+ movw $MONITOR, %ax /* offset for ljmp */
+ movw %ax, 0x123
+ //movw %cs, %ax /* AX=0x9400, segment for ljmp */
+ xorw %ax, %ax
+ movw %ax, 0x125
+
+ movw $(NTFS4_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+ clc
+ ret
+3:
+ /* check NT 5.0 */
+
+ movw $0x44b, %si
+ movl (%si), %ebx /* NT 5.0 */
+ cmpl $0x03E8B800, %ebx /* MOV AX, 03E8 */
+ jz 2f
+
+ movw $0x479, %si
+ movl (%si), %ebx /* NT 5.1 SP2 */
+ cmpl $0x03E8B800, %ebx /* MOV AX, 03E8 */
+ jnz 1f
+2:
+ movl 0x71, %ebx
+ cmpl $0x680053E8, %ebx /* call 00C7; push (0D00) */
+ jnz 1f
+
+ //movw 0x183, %bx /* CR LF at begin of "A disk read error occurred." */
+ movb 0x1F8, %bl
+ movb $1, %bh
+ movw (%bx), %bx
+ cmpw $0x0A0D, %bx /* CR LF */
+ jnz 1f
+ //movw 0x1A0, %bx /* CR LF at begin of "NTLDR is missing." */
+ movb 0x1F9, %bl
+ movb $1, %bh
+ movw (%bx), %bx
+ cmpw $0x0A0D, %bx /* CR LF */
+ jnz 1f
+ //movw 0x1B3, %bx /* CR LF at begin of "NTLDR is compressed." */
+ movb 0x1FA, %bl
+ movb $1, %bh
+ movw (%bx), %bx
+ cmpw $0x0A0D, %bx /* CR LF */
+ jnz 1f
+
+ popw %ax
+ movw %ax, 4(%si)
+
+ movl $0x68909090, %ebx /* nop;nop;nop;push (0D00) */
+ movl %ebx, 0x71
+
+ /* change CRLF in NTFS error messages to spaces */
+ movw $0x2020, %ax
+ movb 0x1F8, %bl
+ movb $1, %bh
+ movw %ax, (%bx) // 0x183
+ movb 0x1F9, %bl
+ movb $1, %bh
+ movw %ax, (%bx) // 0x1A0
+ movb 0x1FA, %bl
+ movb $1, %bh
+ movw %ax, (%bx) // 0x1B3
+
+ /* modify NTFS boot record */
+ movb $0xEA, %al /* ljmp, hand over the control to supervisor */
+ movb %al, 0x167
+ //movw $(try_next_partition - _start1), %ax /* offset for ljmp */
+ movw $MONITOR, %ax /* offset for ljmp */
+ movw %ax, 0x168
+ //movw %cs, %ax /* AX=0x9400, segment for ljmp */
+ xorw %ax, %ax
+ movw %ax, 0x16A
+
+ cmpw $0x44b, %si
+ jne 2f
+ movw $(NTFS5_message - _start1), %si
+ jmp 3f
+2:
+ movw $(NTFS5p_message - _start1), %si
+3:
+ call print_message /* CS:SI points to message string */
+ clc
+ ret
+1:
+ /* NTFS boot record not found. */
+
+ movw $(NTFS_no_boot_record_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ popw %ax
+ popl %eax /* return_IP and SI */
+ popfw
+ stc
+ pushfw
+ pushl %eax /* return_IP and SI */
+ ret
+#endif
+
+//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+move_helper:
+
+ /* called only once and only when the boot loader loaded this code */
+ pushw %si
+ pushw %bx
+ pushl %eax
+
+ movw $0x0003, %ax /* set display mode: 80*25 color text */
+ int $0x10
+
+ movw $0x200, %si
+ movw %si, %di
+ movw $0xf00, %cx
+ cld
+ repz movsw
+
+ popl %eax
+ popw %bx
+ popw %si
+ ret
+//#endif
+
+#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
+filesystem_boot:
+ /* The partition boot record successfully modified, just boot it */
+
+ /*
+ * The boot might fail, but we want to take back the control.
+ * So we save the registers now.
+ */
+ pushw %ds
+ pushw %es
+ pushal
+
+ /* DS=CS=GRLDR_CS, ES=FS_BOOT */
+
+ /* save GRLDR_CS */
+
+ movw %es, %bx # save old ES to BX
+
+ cli
+ lgdt gdt - _start1
+ movl %cr0, %eax
+ orb $1, %al
+ movl %eax, %cr0
+
+ movw $8, %si
+ movw %si, %es
+
+ xorl %esi, %esi
+ xorl %edi, %edi
+ movl $(0x9000 / 4), %ecx
+
+ cld
+ repz movsl
+
+ movw $16, %si
+ movw %si, %es
+
+ andb $0xfe, %al
+ movl %eax, %cr0
+
+ movw %bx, %es # restore ES from BX
+
+ /* move FS_BOOT:0000 to 0:7c00 */
+#if 0
+ /* for single sector boot record */
+ movw $0x0200, %cx /* move 2 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#else
+ /* for 4-sector NTFS boot record */
+ movw $0x0400, %cx /* move 4 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#endif
+ xorw %si, %si
+ pushw %si /* SI=0, for the segment of 0000:7c00 */
+ movw $0x7c00, %di
+ pushw %di /* DI=0x7c00, for the offset of 0000:7c00 */
+ pushw %es /* ES=FS_BOOT */
+ popw %ds /* DS=FS_BOOT */
+ pushw %si /* SI=0 */
+ popw %es /* ES=0 */
+ cld
+ repz movsw
+
+ movw $MONITOR, %di
+ movw $(restore_GRLDR_CS - _start1), %si
+ movw $((gdt_end - restore_GRLDR_CS) / 4), %cx
+ cld
+ repz cs movsl /* CS segment override prefix(=0x2E) */
+
+ pushw %es /* ES=0 */
+ popw %ds /* DS=0 */
+ sti
+ lret //ljmp $0, $0x7c00
+#endif
+
+press_space_bar_string:
+ .ascii "\r\nPress space bar\0"
+
+press_hot_key_pre:
+ .ascii "\r\nPress \0"
+
+press_hot_key_sub:
+ .ascii " to start GRUB, any other key to boot previous MBR ...\0"
+
+hot_key_timeout_pre:
+ .ascii "\r\nTimeout : \0"
+
+hot_key_timeout_num:
+ .ascii " \b\b\b\0"
+
+continue_string:
+ .ascii "\r\nInvalid previous MBR. Press any key to start GRUB ...\0"
+
+Cannot_find_GRLDR_string:
+ .ascii "\r\nCannot find GRLDR.\0"
+
+prev_MBR_string:
+ .ascii " to hold the screen, any other key to boot previous MBR ...\0"
+
+Error_while_reading_string:
+ .ascii "\r\nError while reading MBR of \0"
+
+drive_number_string:
+ .ascii "drive (hd0 ) \0"
+
+partition_boot_indicator_string:
+ .ascii "\r\nInvalid boot indicator in partition table of \0"
+
+partition_sectors_per_track_string:
+ .ascii "\r\nInvalid sectors_per_track in partition table of \0"
+
+partition_start_sector_string:
+ .ascii "\r\nInvalid start_sector in partition table of \0"
+
+partition_end_sector_string:
+ .ascii "\r\nInvalid end_sector in partition table of \0"
+
+no_boot_signature_string:
+ .ascii "\r\nNo boot signature in partition table of \0"
+
+message_string_helper:
+ .ascii "\r\nError: Cannot find GRLDR in all devices. Press Ctrl+Alt+Del to restart.\0"
+
+partition_message:
+ .ascii "\r\nTry (hd0,0 ) : \0"
+
+EXT2_message:
+ .ascii "EXT2: \0"
+NTFS4_message:
+ .ascii "NTFS4: \0"
+NTFS5_message:
+ .ascii "NTFS5: \0"
+NTFS5p_message:
+ .ascii "NTFS5p: \0"
+FAT32_message:
+ .ascii "FAT32: \0"
+FAT16_message:
+ .ascii "FAT16: \0"
+FAT12_message:
+ .ascii "FAT12: \0"
+non_MS_message:
+ .ascii "non-MS: skip \0"
+extended_message:
+ .ascii "Extended: \0"
+invalid_message:
+ .ascii "invalid or null \0"
+#if 0
+NTFS_no_boot_record_message:
+ .ascii "This partition is NTFS but with unknown boot record. Please\r\ninstall Microsoft NTFS boot sectors to this partition correctly, or create an\r\nFAT12/16/32 partition and place the same copy of GRLDR and MENU.LST there.\0"
+#endif
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ . = _start1 + 0x1ffa
+#else
+ . = . + (0x3ec - ((. - _start1) % 0x200)) % 0x200
+
+press_hot_key_name:
+
+ /* hot key name, the address is (grldr_signature - 16) */
+
+ .ascii "hot-key\0"
+
+ . = press_hot_key_name + 14
+
+ //. = . + (0x3fa - ((. - _start1) % 0x200)) % 0x200
+#endif
+
+ /* version word of grldr.mbr, the address is (grldr_signature - 2) */
+
+ .word 2
+
+grldr_signature:
+ .byte 0x47, 0x52, 0x55, 0xaa /* signature for helper */
+
+ .align 0x200
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* pre_stage2 start at 0x2000 for grldr */
+
+ . = _start1 + 0x2000
+
+#endif
+
+#if defined(GRLDR_MBR)
+ /* if the size is less than 8192, let it be 8192 */
+ . = . + (0x2000 - (. - _start1)) * (0x4000 / (. - _start1 + 0x2001))
+#endif
+
+pre_stage2_start:
+
+