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