On Thu, Jul 31, 2008 at 5:20 AM, Bean <[EMAIL PROTECTED]> wrote:
> 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.

Hi,

I make some adjustment for the patch. First, I don't try to remap
blocks anymore, it's not so reliable. and anyway, the real stub area
is 0x8000 long, which is more than enough for the assembly code. If
the area would ever overflow, I just halt grub2. This makes the code
much simpler, and also, there is no need for an extra field to store
the mapped address, we just replace the original address with the
mapped one.

I also add a grub_alloc_real_stub function, which can be used to
allocate memory from the stub area that can be used to to  communicate
with real mode service. Please note that once allocated, the space
can't be released, so remember to save the pointer for later use.

Some real mode service need some kind of alignment for the input data,
so I add two more function grub_call_real_stub_align and
grub_alloc_real_stub_align, which have a alignment parameter. 1 means
no alignment, 2 word alignment, 4 dword alignment, etc. Don't use 0,
it will cause problem for the function.

2008-07-31  Bean  <[EMAIL PROTECTED]>

        * conf/i386-pc.rmk (biosdisk_mod_SOURCES): Add
        disk/i386/pc/biosdisk_stub.S.

        * disk/i386/pc/biosdisk_stub.S: New file.

        * include/grub/i386/pc/biosdisk.h (grub_biosdisk_rw_int13_extensions):
        Remove EXPORT_FUNC, as we have moved it out of the kernel.
        (grub_biosdisk_rw_standard): Likewise.
        (grub_biosdisk_check_int13_extensions): Likewise.
        (grub_biosdisk_get_diskinfo_int13_extensions): Likewise.
        (grub_biosdisk_get_cdinfo_int13_extensions): Likewise.
        (grub_biosdisk_get_diskinfo_standard): Likewise.
        (grub_biosdisk_get_num_floppies): Likewise.

        * include/grub/i386/pc/kernel.h (grub_real_stub): New structure.
        (grub_alloc_real_stub): New function.
        (grub_alloc_real_stub_align): Likewise.
        (grub_call_real_stub): Likewise.
        (grub_call_real_stub_align): Likewise.

        * include/grub/i386/pc/memory.h (GRUB_MEMORY_MACHINE_REAL_STUB_START):
        New macro.
        (GRUB_MEMORY_MACHINE_REAL_STUB_SIZE): Likewise.
        (GRUB_MEMORY_MACHINE_REAL_STUB_END): Likewise.
        (GRUB_MEMORY_MACHINE_RESERVED_END): Change value.

        * include/symbol.h (REAL_STUB_START): New macro.
        (REAL_STUB_END): Likewise.

        * kern/i386/pc/startup.S (real_stub_addr): New variable.
        (grub_alloc_real_stub): New function.
        (grub_alloc_real_stub_align): Likewise.
        (grub_call_real_stub): Likewise.
        (grub_call_real_stub_align): Likewise.
        (grub_biosdisk_rw_int13_extensions): Moved to biosdisk_stub.S.
        (grub_biosdisk_rw_standard): Likewise.
        (grub_biosdisk_check_int13_extensions): Likewise.
        (grub_biosdisk_get_diskinfo_int13_extensions): Likewise.
        (grub_biosdisk_get_cdinfo_int13_extensions): Likewise.
        (grub_biosdisk_get_diskinfo_standard): Likewise.
        (grub_biosdisk_get_num_floppies): Likewise.

-- 
Bean
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 59fc6a3..f779414 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -162,7 +162,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \
 	aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod
 
 # For biosdisk.mod.
-biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
+biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c disk/i386/pc/biosdisk_stub.S
 biosdisk_mod_CFLAGS = $(COMMON_CFLAGS)
 biosdisk_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
diff --git a/disk/i386/pc/biosdisk_stub.S b/disk/i386/pc/biosdisk_stub.S
new file mode 100644
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 a00117b..fde9525 100644
--- a/include/grub/i386/pc/kernel.h
+++ b/include/grub/i386/pc/kernel.h
@@ -86,6 +86,19 @@ 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);
 
+struct grub_real_stub
+{
+  void *address;
+  grub_uint32_t length;
+};
+
+void* EXPORT_FUNC(grub_alloc_real_stub) (int size);
+void* EXPORT_FUNC(grub_alloc_real_stub_align) (int size, int align);
+
+void EXPORT_FUNC(grub_call_real_stub) (struct grub_real_stub *stub);
+void EXPORT_FUNC(grub_call_real_stub_align) (struct grub_real_stub *stub,
+                                             int align);
+
 #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..eef966f 100644
--- a/include/grub/symbol.h
+++ b/include/grub/symbol.h
@@ -43,4 +43,13 @@
 # define EXPORT_VAR(x)	x
 #endif /* ! GRUB_SYMBOL_GENERATOR */
 
+#define REAL_STUB_START(x)	x ## _stub: ; \
+	.long	x ## _start ; \
+	.long	x ## _end - x ## _start ; \
+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..8e7c68d 100644
--- a/kern/i386/pc/startup.S
+++ b/kern/i386/pc/startup.S
@@ -618,357 +618,157 @@ 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/data to address below 1M.
  *
- *  This starts another boot loader.
+ * On entry, %eax should points to a structure that specifies the code/data to
+ * be copied:
+ *
+ *   offset 0: address of code/data
+ *   offset 4: size of code/data
+ *
+ * grub_copy_real_stub fetches the address from offset 0, if it's not below 1M or
+ * properly aligned, it copies it to a reserved area and updates the address at
+ * offset 0, so that it don't need to do it again the next time.
+ *
+ * Currently, the reserved area for stub code/data is 0x80000 - 0x88000. It
+ * should be big enough for assembly code.
  */
 
-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)
+ * Allocate memory from the stub area.
  *
- *   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.
+ * void* grub_alloc_real_stub (int size);
+ * void* grub_alloc_real_stub_align (int size, int align);
  */
 
-FUNCTION(grub_biosdisk_rw_int13_extensions)
-	pushl	%ebp
-	pushl	%esi
+FUNCTION(grub_alloc_real_stub)
+	movl	$1, %edx
 
-	/* compute the address of disk_address_packet */
-	movw	%cx, %si
-	xorw	%cx, %cx
-	shrl	$4, %ecx	/* save the segment to cx */
+FUNCTION(grub_alloc_real_stub_align)
+	decl	%edx
 
-	/* ah */
-	movb	%al, %dh
-	/* enter real mode */
-	call	prot_to_real
+grub_alloc_real_stub_1:
+	movl	%eax, %ecx
+	movl	real_stub_addr, %eax
 
-	.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
+	addl	%edx, %eax
+	notl	%edx
+	andl	%edx, %eax
 
-	movb	%dl, %al	/* return value in %eax */
+	leal	(%eax, %ecx), %edx
+	cmpl	$GRUB_MEMORY_MACHINE_REAL_STUB_END, %edx
+	ja	EXT_C(grub_stop)
 
-	popl	%esi
-	popl	%ebp
+	movl	%edx, real_stub_addr
 
 	ret
 
 /*
- *   int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
- *                                  int soff, int nsec, int segment)
+ * Test the address in stub, if it's above 1M or not properly aligned,
+ * allocate memory from the stub area and copy the code. Then, it switches
+ * to real mode and execute.
  *
- *   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.
+ * void grub_call_real_stub (struct grub_real_stub *stub);
+ * void grub_call_real_stub_align (struct grub_real_stub *stub,
+ *                                 int align);
  */
 
-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
-
-	/* enter real mode */
-	call	prot_to_real
+FUNCTION(grub_call_real_stub)
+	pushl	%edx
+	xorl	%edx, %edx
+	jmp	1f
 
-	.code16
-	movw	%bx, %es
-	xorw	%bx, %bx
-	movw	$3, %si		/* attempt at least three times */
+FUNCTION(grub_call_real_stub_align)
+	pushl	%edx
+	decl	%edx
 
 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:
-	/* back to protected mode */
-	DATA32	call	real_to_prot
-	.code32
-
-	movb	%bl, %al	/* return value in %eax */
-
-	popl	%esi
-	popl	%edi
-	popl	%ebx
-	popl	%ebp
+	pushl	%ecx
 
-	ret	$(4 * 4)
+	/* Test if it's below 1M.  */
+	movl	(%eax), %ecx
+	cmpl	$GRUB_MEMORY_MACHINE_UPPER, %ecx
+	jae	1f
 
+	/* Test if it's aligned properly.  */
+	testl	%edx, %ecx
+	jz	2f
 
-/*
- *   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.
- */
+1:
+	pushl	%esi
+	pushl	%edi
+	pushl	%eax
 
-FUNCTION(grub_biosdisk_check_int13_extensions)
-	pushl	%ebp
-	pushl	%ebx
+	movl	%ecx, %esi
+	movl	4(%eax), %eax
 
-	/* drive */
-	movb	%al, %dl
-	/* enter real mode */
-	call	prot_to_real
+	call	grub_alloc_real_stub_1
 
-	.code16
-	movb	$0x41, %ah
-	movw	$0x55aa, %bx
-	int	$0x13		/* do the operation */
+	/* On return, %ecx will contain the length.  */
 
-	/* check the result */
-	jc	1f
-	cmpw	$0xaa55, %bx
-	jne	1f
+	movl	%eax, %edi
+	xchgl	%eax, (%esp)
+	movl	%edi, (%eax)
 
-	movb	%ah, %bl	/* save the major version into %bl */
+	cld
+	rep	movsb
 
-	/* check if AH=0x42 is supported */
-	andw	$1, %cx
-	jnz	2f
+	popl	%ecx
+	popl	%edi
+	popl	%esi
 
-1:
-	xorb	%bl, %bl
 2:
-	/* back to protected mode */
-	DATA32	call	real_to_prot
-	.code32
+	shll	$12, %ecx
+	shrw	$12, %cx
 
-	movb	%bl, %al	/* return value in %eax */
+	movl	%ecx, GRUB_MEMORY_MACHINE_REAL_STACK + 0x10
 
-	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
+	popl	%ecx
+	popl	%edx
 
-	/* 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 */
+	lcall	*(GRUB_MEMORY_MACHINE_REAL_STACK + 0x10)
 
-	popl	%esi
-	popl	%ebx
-	popl	%ebp
+	DATA32	call	real_to_prot
+	.code32
 
 	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