diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 59fc6a3..fd58e17 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -154,7 +154,7 @@ grub_install_SOURCES = util/i386/pc/grub-install.in
grub_mkrescue_SOURCES = util/i386/pc/grub-mkrescue.in
# Modules.
-pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \
+pkglib_MODULES = biosdisk.mod biosdisk_stub.mod _chain.mod _linux.mod linux.mod normal.mod \
_multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \
vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \
@@ -166,6 +166,16 @@ biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
biosdisk_mod_CFLAGS = $(COMMON_CFLAGS)
biosdisk_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For biosdisk_stub.mod.
+biosdisk_stub_mod_SOURCES = disk/i386/pc/biosdisk_stub.S
+biosdisk_stub_mod_CFLAGS = $(COMMON_CFLAGS)
+biosdisk_stub_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For biosdiskstub.mod.
+biosdiskstub_mod_SOURCES = disk/i386/pc/biosdisk.c
+biosdiskstub_mod_CFLAGS = $(COMMON_CFLAGS)
+biosdisk_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
_chain_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/disk/i386/pc/biosdisk_stub.S b/disk/i386/pc/biosdisk_stub.S
new file mode 100755
index 0000000..05536c6
--- /dev/null
+++ b/disk/i386/pc/biosdisk_stub.S
@@ -0,0 +1,344 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see .
+ */
+
+#define ASM_FILE 1
+
+#include
+#include
+
+/*
+ * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
+ *
+ * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
+ * is passed for disk address packet. If an error occurs, return
+ * non-zero, otherwise zero.
+ */
+
+REAL_STUB_START(grub_biosdisk_rw_int13_extensions)
+ movb %dh, %ah
+ movw %cx, %ds
+ int $0x13 /* do the operation */
+ movb %ah, %dl /* save return value */
+ lret
+REAL_STUB_END(grub_biosdisk_rw_int13_extensions)
+
+FUNCTION(grub_biosdisk_rw_int13_extensions)
+ pushl %ebp
+ pushl %esi
+
+ /* compute the address of disk_address_packet */
+ movw %cx, %si
+ xorw %cx, %cx
+ shrl $4, %ecx /* save the segment to cx */
+
+ /* ah */
+ movb %al, %dh
+
+ leal grub_biosdisk_rw_int13_extensions_stub, %eax
+ call EXT_C(grub_call_real_stub)
+
+ movb %dl, %al /* return value in %eax */
+
+ popl %esi
+ popl %ebp
+
+ ret
+
+/*
+ * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
+ * int soff, int nsec, int segment)
+ *
+ * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
+ * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
+ * return non-zero, otherwise zero.
+ */
+
+REAL_STUB_START(grub_biosdisk_rw_standard)
+ movw %bx, %es
+ xorw %bx, %bx
+ movw $3, %si /* attempt at least three times */
+
+1:
+ movw %di, %ax
+ int $0x13 /* do the operation */
+ jnc 2f /* check if successful */
+
+ movb %ah, %bl /* save return value */
+ /* if fail, reset the disk system */
+ xorw %ax, %ax
+ int $0x13
+
+ decw %si
+ cmpw $0, %si
+ je 2f
+ xorb %bl, %bl
+ jmp 1b /* retry */
+2:
+ lret
+REAL_STUB_END(grub_biosdisk_rw_standard)
+
+FUNCTION(grub_biosdisk_rw_standard)
+ pushl %ebp
+ movl %esp, %ebp
+
+ pushl %ebx
+ pushl %edi
+ pushl %esi
+
+ /* set up CHS information */
+
+ /* set %ch to low eight bits of cylinder */
+ xchgb %cl, %ch
+ /* set bits 6-7 of %cl to high two bits of cylinder */
+ shlb $6, %cl
+ /* set bits 0-5 of %cl to sector */
+ addb 0xc(%ebp), %cl
+ /* set %dh to head */
+ movb 0x8(%ebp), %dh
+ /* set %ah to AH */
+ movb %al, %ah
+ /* set %al to NSEC */
+ movb 0x10(%ebp), %al
+ /* save %ax in %di */
+ movw %ax, %di
+ /* save SEGMENT in %bx */
+ movw 0x14(%ebp), %bx
+
+ leal grub_biosdisk_rw_standard_stub, %eax
+ call EXT_C(grub_call_real_stub)
+
+ movb %bl, %al /* return value in %eax */
+
+ popl %esi
+ popl %edi
+ popl %ebx
+ popl %ebp
+
+ ret $(4 * 4)
+
+
+/*
+ * int grub_biosdisk_check_int13_extensions (int drive)
+ *
+ * Check if LBA is supported for DRIVE. If it is supported, then return
+ * the major version of extensions, otherwise zero.
+ */
+
+REAL_STUB_START(grub_biosdisk_check_int13_extensions)
+ movb $0x41, %ah
+ movw $0x55aa, %bx
+ int $0x13 /* do the operation */
+
+ /* check the result */
+ jc 1f
+ cmpw $0xaa55, %bx
+ jne 1f
+
+ movb %ah, %bl /* save the major version into %bl */
+
+ /* check if AH=0x42 is supported */
+ andw $1, %cx
+ jnz 2f
+
+1:
+ xorb %bl, %bl
+2:
+ lret
+REAL_STUB_END(grub_biosdisk_check_int13_extensions)
+
+FUNCTION(grub_biosdisk_check_int13_extensions)
+ pushl %ebp
+ pushl %ebx
+
+ /* drive */
+ movb %al, %dl
+
+ leal grub_biosdisk_check_int13_extensions_stub, %eax
+ call EXT_C(grub_call_real_stub)
+
+ movb %bl, %al /* return value in %eax */
+
+ popl %ebx
+ popl %ebp
+
+ ret
+
+
+/*
+ * int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
+ *
+ * Return the cdrom information of DRIVE in CDRP. If an error occurs,
+ * then return non-zero, otherwise zero.
+ */
+
+FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions)
+ movw $0x4B01, %cx
+ jmp 1f
+
+/*
+ * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
+ *
+ * Return the geometry of DRIVE in a drive parameters, DRP. If an error
+ * occurs, then return non-zero, otherwise zero.
+ */
+
+REAL_STUB_START(grub_biosdisk_get_diskinfo_int13_extensions)
+ movw %cx, %ax
+ movw %bx, %ds
+ int $0x13 /* do the operation */
+ movb %ah, %bl /* save return value in %bl */
+ lret
+REAL_STUB_END(grub_biosdisk_get_diskinfo_int13_extensions)
+
+FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
+ movb $0x48, %ch
+1:
+ pushl %ebp
+ pushl %ebx
+ pushl %esi
+
+ /* compute the address of drive parameters */
+ movw %dx, %si
+ andl $0xf, %esi
+ shrl $4, %edx
+ movw %dx, %bx /* save the segment into %bx */
+ /* drive */
+ movb %al, %dl
+
+ leal grub_biosdisk_get_diskinfo_int13_extensions_stub, %eax
+ call EXT_C(grub_call_real_stub)
+
+ movb %bl, %al /* return value in %eax */
+
+ popl %esi
+ popl %ebx
+ popl %ebp
+
+ ret
+
+
+/*
+ * int grub_biosdisk_get_diskinfo_standard (int drive,
+ * unsigned long *cylinders,
+ * unsigned long *heads,
+ * unsigned long *sectors)
+ *
+ * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
+ * error occurs, then return non-zero, otherwise zero.
+ */
+REAL_STUB_START(grub_biosdisk_get_diskinfo_standard)
+ movb $0x8, %ah
+ int $0x13 /* do the operation */
+ /* check if successful */
+ testb %ah, %ah
+ jnz 1f
+ /* bogus BIOSes may not return an error number */
+ testb $0x3f, %cl /* 0 sectors means no disk */
+ jnz 1f /* if non-zero, then succeed */
+ /* XXX 0x60 is one of the unused error numbers */
+ movb $0x60, %ah
+1:
+ movb %ah, %bl /* save return value in %bl */
+ lret
+REAL_STUB_END(grub_biosdisk_get_diskinfo_standard)
+
+FUNCTION(grub_biosdisk_get_diskinfo_standard)
+ pushl %ebp
+ pushl %ebx
+ pushl %edi
+
+ /* push CYLINDERS */
+ pushl %edx
+ /* push HEADS */
+ pushl %ecx
+ /* SECTORS is on the stack */
+
+ /* drive */
+ movb %al, %dl
+
+ leal grub_biosdisk_get_diskinfo_standard_stub, %eax
+ call EXT_C(grub_call_real_stub)
+
+ /* pop HEADS */
+ popl %edi
+ movb %dh, %al
+ incl %eax /* the number of heads is counted from zero */
+ movl %eax, (%edi)
+
+ /* pop CYLINDERS */
+ popl %edi
+ movb %ch, %al
+ movb %cl, %ah
+ shrb $6, %ah /* the number of cylinders is counted from zero */
+ incl %eax
+ movl %eax, (%edi)
+
+ /* SECTORS */
+ movl 0x10(%esp), %edi
+ andb $0x3f, %cl
+ movzbl %cl, %eax
+ movl %eax, (%edi)
+
+ xorl %eax, %eax
+ movb %bl, %al /* return value in %eax */
+
+ popl %edi
+ popl %ebx
+ popl %ebp
+
+ ret $4
+
+
+/*
+ * int grub_biosdisk_get_num_floppies (void)
+ */
+
+REAL_STUB_START(grub_biosdisk_get_num_floppies)
+ /* reset the disk system first */
+ int $0x13
+1:
+ stc
+
+ /* call GET DISK TYPE */
+ movb $0x15, %ah
+ int $0x13
+
+ jc 2f
+
+ /* check if this drive exists */
+ testb $0x3, %ah
+ jz 2f
+
+ incb %dl
+ cmpb $2, %dl
+ jne 1b
+2:
+ lret
+REAL_STUB_END(grub_biosdisk_get_num_floppies)
+
+FUNCTION(grub_biosdisk_get_num_floppies)
+ pushl %ebp
+
+ xorl %edx, %edx
+
+ leal grub_biosdisk_get_num_floppies_stub, %eax
+ call EXT_C(grub_call_real_stub)
+
+ movl %edx, %eax
+ popl %ebp
+ ret
diff --git a/include/grub/i386/pc/biosdisk.h b/include/grub/i386/pc/biosdisk.h
index 05d5dc5..da82116 100644
--- a/include/grub/i386/pc/biosdisk.h
+++ b/include/grub/i386/pc/biosdisk.h
@@ -106,19 +106,19 @@ struct grub_biosdisk_dap
grub_uint64_t block;
} __attribute__ ((packed));
-int EXPORT_FUNC(grub_biosdisk_rw_int13_extensions) (int ah, int drive, void *dap);
-int EXPORT_FUNC(grub_biosdisk_rw_standard) (int ah, int drive, int coff, int hoff,
+int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap);
+int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
int soff, int nsec, int segment);
-int EXPORT_FUNC(grub_biosdisk_check_int13_extensions) (int drive);
-int EXPORT_FUNC(grub_biosdisk_get_diskinfo_int13_extensions) (int drive,
+int grub_biosdisk_check_int13_extensions (int drive);
+int grub_biosdisk_get_diskinfo_int13_extensions (int drive,
void *drp);
-int EXPORT_FUNC(grub_biosdisk_get_cdinfo_int13_extensions) (int drive,
+int grub_biosdisk_get_cdinfo_int13_extensions (int drive,
void *cdrp);
-int EXPORT_FUNC(grub_biosdisk_get_diskinfo_standard) (int drive,
+int grub_biosdisk_get_diskinfo_standard (int drive,
unsigned long *cylinders,
unsigned long *heads,
unsigned long *sectors);
-int EXPORT_FUNC(grub_biosdisk_get_num_floppies) (void);
+int grub_biosdisk_get_num_floppies (void);
void grub_biosdisk_init (void);
void grub_biosdisk_fini (void);
diff --git a/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h
index 402faa3..3c205ac 100644
--- a/include/grub/i386/pc/kernel.h
+++ b/include/grub/i386/pc/kernel.h
@@ -86,6 +86,8 @@ extern grub_addr_t grub_end_addr;
extern grub_addr_t EXPORT_FUNC(grub_arch_memdisk_addr) (void);
extern grub_off_t EXPORT_FUNC(grub_arch_memdisk_size) (void);
+void EXPORT_FUNC(grub_call_real_stub) (void);
+
#endif /* ! ASM_FILE */
#endif /* ! KERNEL_MACHINE_HEADER */
diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h
index a3e3ed7..55d5dcb 100644
--- a/include/grub/i386/pc/memory.h
+++ b/include/grub/i386/pc/memory.h
@@ -45,12 +45,17 @@
(GRUB_MEMORY_MACHINE_SCRATCH_ADDR + GRUB_MEMORY_MACHINE_SCRATCH_SIZE \
+ GRUB_MEMORY_MACHINE_PROT_STACK_SIZE - 0x10)
+#define GRUB_MEMORY_MACHINE_REAL_STUB_START (GRUB_MEMORY_MACHINE_PROT_STACK + 0x10)
+#define GRUB_MEMORY_MACHINE_REAL_STUB_SIZE 0x8000
+#define GRUB_MEMORY_MACHINE_REAL_STUB_END \
+ (GRUB_MEMORY_MACHINE_REAL_STUB_START + GRUB_MEMORY_MACHINE_REAL_STUB_SIZE)
+
/* The memory area where GRUB uses its own purpose. This part is not added
into free memory for dynamic allocations. */
#define GRUB_MEMORY_MACHINE_RESERVED_START \
GRUB_MEMORY_MACHINE_SCRATCH_ADDR
#define GRUB_MEMORY_MACHINE_RESERVED_END \
- (GRUB_MEMORY_MACHINE_PROT_STACK + 0x10)
+ GRUB_MEMORY_MACHINE_REAL_STUB_END
/* The area where GRUB is decompressed at early startup. */
#define GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR 0x100000
diff --git a/include/grub/symbol.h b/include/grub/symbol.h
index e951490..6fd161a 100644
--- a/include/grub/symbol.h
+++ b/include/grub/symbol.h
@@ -43,4 +43,14 @@
# define EXPORT_VAR(x) x
#endif /* ! GRUB_SYMBOL_GENERATOR */
+#define REAL_STUB_START(x) x ## _stub: ; \
+ .long x ## _start ; \
+ .long x ## _end - x ## _start ; \
+ .long 0 ; \
+x ## _start: ; \
+ .code16
+
+#define REAL_STUB_END(x) .code32 ; \
+x ## _end:
+
#endif /* ! GRUB_SYMBOL_HEADER */
diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S
index 679ad1f..5b1a2a1 100644
--- a/kern/i386/pc/startup.S
+++ b/kern/i386/pc/startup.S
@@ -618,357 +618,134 @@ FUNCTION(grub_halt)
jmp EXT_C(grub_hard_stop)
.code32
+real_stub_addr:
+ .long GRUB_MEMORY_MACHINE_REAL_STUB_START
/*
- * void grub_chainloader_real_boot (int drive, void *part_addr)
+ * Copy code to address below 1M, switch to real mode and execute.
*
- * This starts another boot loader.
- */
-
-FUNCTION(grub_chainloader_real_boot)
- pushl %edx
- pushl %eax
-
- call EXT_C(grub_dl_unload_all)
-
- /* Turn off Gate A20 */
- xorl %eax, %eax
- call EXT_C(grub_gate_a20)
-
- /* set up to pass boot drive */
- popl %edx
-
- /* ESI must point to a partition table entry */
- popl %esi
-
- call prot_to_real
- .code16
- ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
- .code32
-
-#include "../loader.S"
-
-/*
- * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
+ * On entry, %eax should points to a structure that specifies the code to be
+ * copied:
+ *
+ * offset 0: address of code
+ * offset 4: size of code
+ * offset 8: mapped address
+ *
+ * To avoid unnecessary memory transfer, it replaces the code address with
+ * mapped address, so that it can be used directly the next time.
+ *
+ * The real mode stub also holds the address of the structure directly before
+ * its code. This is used for verification. When the stub area is full, we
+ * zero it and start again. This would invalidate all mapped block so that
+ * they must be copied again when used.
*
- * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
- * is passed for disk address packet. If an error occurs, return
- * non-zero, otherwise zero.
*/
-FUNCTION(grub_biosdisk_rw_int13_extensions)
- pushl %ebp
- pushl %esi
-
- /* compute the address of disk_address_packet */
- movw %cx, %si
- xorw %cx, %cx
- shrl $4, %ecx /* save the segment to cx */
-
- /* ah */
- movb %al, %dh
- /* enter real mode */
- call prot_to_real
+FUNCTION(grub_call_real_stub)
+ pushl %edi
- .code16
- movb %dh, %ah
- movw %cx, %ds
- int $0x13 /* do the operation */
- movb %ah, %dl /* save return value */
- /* back to protected mode */
- DATA32 call real_to_prot
- .code32
+ /* Test if we need to map it. */
+ movl (%eax), %edi
+ cmpl $GRUB_MEMORY_MACHINE_UPPER, %edi
+ jb 3f
- movb %dl, %al /* return value in %eax */
+ /* Test if we already map it. */
+ movl 8(%eax), %edi
+ orl %edi, %edi
+ jz 1f
- popl %esi
- popl %ebp
+ /* Test if the mapped block is valid. */
+ cmpl %eax, -4(%edi)
+ jz 3f
- ret
+1:
+ pushl %esi
+ pushl %ecx
-/*
- * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
- * int soff, int nsec, int segment)
- *
- * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
- * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
- * return non-zero, otherwise zero.
- */
+ cld
-FUNCTION(grub_biosdisk_rw_standard)
- pushl %ebp
- movl %esp, %ebp
+ movl 4(%eax), %ecx
+ movl real_stub_addr, %edi
+ leal 4(%edi, %ecx), %esi
+ cmpl $GRUB_MEMORY_MACHINE_REAL_STUB_END, %esi
+ jbe 2f
- pushl %ebx
+ /* The stub area is full, zero it and start again. */
+ pushl %ecx
+ movl $(GRUB_MEMORY_MACHINE_REAL_STUB_SIZE >> 2), %ecx
+ movl $GRUB_MEMORY_MACHINE_REAL_STUB_START, %edi
pushl %edi
- pushl %esi
+ pushl %eax
- /* set up CHS information */
-
- /* set %ch to low eight bits of cylinder */
- xchgb %cl, %ch
- /* set bits 6-7 of %cl to high two bits of cylinder */
- shlb $6, %cl
- /* set bits 0-5 of %cl to sector */
- addb 0xc(%ebp), %cl
- /* set %dh to head */
- movb 0x8(%ebp), %dh
- /* set %ah to AH */
- movb %al, %ah
- /* set %al to NSEC */
- movb 0x10(%ebp), %al
- /* save %ax in %di */
- movw %ax, %di
- /* save SEGMENT in %bx */
- movw 0x14(%ebp), %bx
-
- /* enter real mode */
- call prot_to_real
+ xorl %eax, %eax
+ rep stosl
- .code16
- movw %bx, %es
- xorw %bx, %bx
- movw $3, %si /* attempt at least three times */
+ popl %edi
+ popl %eax
+ popl %ecx
-1:
- movw %di, %ax
- int $0x13 /* do the operation */
- jnc 2f /* check if successful */
+2:
+ stosl
- movb %ah, %bl /* save return value */
- /* if fail, reset the disk system */
- xorw %ax, %ax
- int $0x13
+ pushl %edi
+ movl %edi, 8(%eax)
- decw %si
- cmpw $0, %si
- je 2f
- xorb %bl, %bl
- jmp 1b /* retry */
-2:
- /* back to protected mode */
- DATA32 call real_to_prot
- .code32
+ movl (%eax), %esi
+ rep movsb
- movb %bl, %al /* return value in %eax */
+ movl %edi, real_stub_addr
- popl %esi
popl %edi
- popl %ebx
- popl %ebp
- ret $(4 * 4)
+ popl %ecx
+ popl %esi
+3:
-/*
- * int grub_biosdisk_check_int13_extensions (int drive)
- *
- * Check if LBA is supported for DRIVE. If it is supported, then return
- * the major version of extensions, otherwise zero.
- */
+ shll $12, %edi
+ shrw $12, %di
-FUNCTION(grub_biosdisk_check_int13_extensions)
- pushl %ebp
- pushl %ebx
+ movl %edi, GRUB_MEMORY_MACHINE_REAL_STACK + 0x10
+ popl %edi
- /* drive */
- movb %al, %dl
- /* enter real mode */
call prot_to_real
-
.code16
- movb $0x41, %ah
- movw $0x55aa, %bx
- int $0x13 /* do the operation */
- /* check the result */
- jc 1f
- cmpw $0xaa55, %bx
- jne 1f
+ lcall *(GRUB_MEMORY_MACHINE_REAL_STACK + 0x10)
- movb %ah, %bl /* save the major version into %bl */
-
- /* check if AH=0x42 is supported */
- andw $1, %cx
- jnz 2f
-
-1:
- xorb %bl, %bl
-2:
- /* back to protected mode */
DATA32 call real_to_prot
.code32
- movb %bl, %al /* return value in %eax */
-
- popl %ebx
- popl %ebp
-
ret
-
-/*
- * int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
- *
- * Return the cdrom information of DRIVE in CDRP. If an error occurs,
- * then return non-zero, otherwise zero.
- */
-
-FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions)
- movw $0x4B01, %cx
- jmp 1f
-
/*
- * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
- *
- * Return the geometry of DRIVE in a drive parameters, DRP. If an error
- * occurs, then return non-zero, otherwise zero.
- */
-
-FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
- movb $0x48, %ch
-1:
- pushl %ebp
- pushl %ebx
- pushl %esi
-
- /* compute the address of drive parameters */
- movw %dx, %si
- andl $0xf, %esi
- shrl $4, %edx
- movw %dx, %bx /* save the segment into %bx */
- /* drive */
- movb %al, %dl
- /* enter real mode */
- call prot_to_real
-
- .code16
- movw %cx, %ax
- movw %bx, %ds
- int $0x13 /* do the operation */
- movb %ah, %bl /* save return value in %bl */
- /* back to protected mode */
- DATA32 call real_to_prot
- .code32
-
- movb %bl, %al /* return value in %eax */
-
- popl %esi
- popl %ebx
- popl %ebp
-
- ret
-
-
-/*
- * int grub_biosdisk_get_diskinfo_standard (int drive,
- * unsigned long *cylinders,
- * unsigned long *heads,
- * unsigned long *sectors)
+ * void grub_chainloader_real_boot (int drive, void *part_addr)
*
- * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
- * error occurs, then return non-zero, otherwise zero.
+ * This starts another boot loader.
*/
-FUNCTION(grub_biosdisk_get_diskinfo_standard)
- pushl %ebp
- pushl %ebx
- pushl %edi
-
- /* push CYLINDERS */
+FUNCTION(grub_chainloader_real_boot)
pushl %edx
- /* push HEADS */
- pushl %ecx
- /* SECTORS is on the stack */
-
- /* drive */
- movb %al, %dl
- /* enter real mode */
- call prot_to_real
-
- .code16
- movb $0x8, %ah
- int $0x13 /* do the operation */
- /* check if successful */
- testb %ah, %ah
- jnz 1f
- /* bogus BIOSes may not return an error number */
- testb $0x3f, %cl /* 0 sectors means no disk */
- jnz 1f /* if non-zero, then succeed */
- /* XXX 0x60 is one of the unused error numbers */
- movb $0x60, %ah
-1:
- movb %ah, %bl /* save return value in %bl */
- /* back to protected mode */
- DATA32 call real_to_prot
- .code32
-
- /* pop HEADS */
- popl %edi
- movb %dh, %al
- incl %eax /* the number of heads is counted from zero */
- movl %eax, (%edi)
-
- /* pop CYLINDERS */
- popl %edi
- movb %ch, %al
- movb %cl, %ah
- shrb $6, %ah /* the number of cylinders is counted from zero */
- incl %eax
- movl %eax, (%edi)
+ pushl %eax
- /* SECTORS */
- movl 0x10(%esp), %edi
- andb $0x3f, %cl
- movzbl %cl, %eax
- movl %eax, (%edi)
+ call EXT_C(grub_dl_unload_all)
+ /* Turn off Gate A20 */
xorl %eax, %eax
- movb %bl, %al /* return value in %eax */
-
- popl %edi
- popl %ebx
- popl %ebp
-
- ret $4
+ call EXT_C(grub_gate_a20)
+ /* set up to pass boot drive */
+ popl %edx
-/*
- * int grub_biosdisk_get_num_floppies (void)
- */
-FUNCTION(grub_biosdisk_get_num_floppies)
- pushl %ebp
+ /* ESI must point to a partition table entry */
+ popl %esi
- xorl %edx, %edx
call prot_to_real
-
.code16
- /* reset the disk system first */
- int $0x13
-1:
- stc
-
- /* call GET DISK TYPE */
- movb $0x15, %ah
- int $0x13
-
- jc 2f
-
- /* check if this drive exists */
- testb $0x3, %ah
- jz 2f
-
- incb %dl
- cmpb $2, %dl
- jne 1b
-2:
- DATA32 call real_to_prot
+ ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
.code32
- movl %edx, %eax
- popl %ebp
- ret
-
+#include "../loader.S"
/*
*