mirror of
https://git.proxmox.com/git/grub2
synced 2025-08-18 17:07:29 +00:00

git-subtree-dir: debian/grub-extras git-subtree-mainline:955d61226a
git-subtree-split:f2a0794419
5794 lines
128 KiB
ArmAsm
5794 lines
128 KiB
ArmAsm
/*
|
|
* 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:
|
|
|
|
|