Hi,

Currently, most assembly code are in startup.S. This is normally used
to ensure that the function address are below 1m, which is required if
it would switch to real mode and call bios services. However, this
make the kernel larger. For example, the biosdisk functions are only
used by biodisk module, they should not be placed inside the kernel.

This patch support splitting such code from startup.S. For example, we
create a new module biosdisk_stub.mod for assembly code of biosdisk.
Instead of call prot_to_real and real_to_prot, we call
grub_call_real_stub to enter real mode. grub_call_real_stub would copy
the code to real mode and do the mode switch.

To avoid unnecessary memory transfer, grub_call_real_stub would not
erase the real mode stub when it's done, so that it can be used
directly next time. When the stub area is full, it zero it out and
start anew. The area uses a simple verification method so that the old
mapping is invalidated, the code would need be copied again on their
next use.

The patch shows how to do it for the biosdisk module, here is the new
grub_biosdisk_rw_int13_extensions function.

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

Real mode code is enclosed between REAL_STUB_START and REAL_STUB_END,
no need to use .code16 and .code32 as it's handled by the macro. In
the main function, use

        leal    grub_biosdisk_rw_int13_extensions_stub, %eax
        call    EXT_C(grub_call_real_stub)

to invoke grub_call_real_stub. grub_biosdisk_rw_int13_extensions_stub
is defined in the REAL_STUB_START macro.

This same method can be applied to loaders, vbe, etc. In fact, almost
all function behind grub_call_real_stub can be moved out of startup.S.

-- 
Bean
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 <http://www.gnu.org/licenses/>.
+ */
+
+#define ASM_FILE	1
+
+#include <grub/symbol.h>
+#include <grub/machine/memory.h>
+
+/*
+ *   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"
 
 /*
  *
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to