Hi.
Here is a patch for booting GRUB via itself with multiboot module.
Tested on [http://grub.enbug.org/TestingOnX86]-alike floppy image and QEMU.
BTW. When I'm trying to add some code/data before/in multiboot_entry in
startup.S, GRUB hangs with "Loading kernel" message (even if it booted
not via multiboot). How can I avoid it? It would be nice to print some
message about invalid magic value, for example. But I just cannot add
the code.
diff -ru grub2.orig/include/grub/i386/pc/loader.h grub2.multiboot/include/grub/i386/pc/loader.h
--- grub2.orig/include/grub/i386/pc/loader.h 2004-09-12 19:20:52.000000000 +0700
+++ grub2.multiboot/include/grub/i386/pc/loader.h 2007-06-17 18:31:53.000000000 +0700
@@ -28,11 +28,17 @@
extern char *EXPORT_VAR(grub_linux_tmp_addr);
extern char *EXPORT_VAR(grub_linux_real_addr);
+/* Multiboot loader needs to know boot device. */
+extern grub_uint32_t EXPORT_VAR(grub_boot_drive);
+extern grub_int32_t EXPORT_VAR(grub_install_dos_part);
+extern grub_int32_t EXPORT_VAR(grub_install_bsd_part);
+
void EXPORT_FUNC(grub_linux_boot_zimage) (void) __attribute__ ((noreturn));
void EXPORT_FUNC(grub_linux_boot_bzimage) (void) __attribute__ ((noreturn));
/* This is an asm part of the chainloader. */
-void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn));
+void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr)
+ __attribute__ ((noreturn));
/* The asm part of the multiboot loader. */
void EXPORT_FUNC(grub_multiboot_real_boot) (grub_addr_t entry,
diff -ru grub2.orig/loader/i386/pc/multiboot.c grub2.multiboot/loader/i386/pc/multiboot.c
--- grub2.orig/loader/i386/pc/multiboot.c 2006-06-04 22:56:54.000000000 +0700
+++ grub2.multiboot/loader/i386/pc/multiboot.c 2007-06-17 19:02:10.000000000 +0700
@@ -22,8 +22,6 @@
* FIXME: The following features from the Multiboot specification still
* need to be implemented:
* - VBE support
- * - a.out support
- * - boot device
* - symbol table
* - memory map
* - drives table
@@ -236,6 +234,75 @@
return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
}
+/* Load with a.out kludge. */
+static grub_err_t
+grub_multiboot_load_raw (grub_file_t file, grub_off_t header_offset,
+ const struct grub_multiboot_header *header)
+{
+ grub_off_t file_size = grub_file_size (file);
+ grub_off_t load_offset = header_offset
+ - (header->header_addr - header->load_addr);
+ grub_uint32_t load_end_addr = header->load_end_addr;
+ grub_uint32_t bss_end_addr = header->bss_end_addr;
+ grub_uint32_t load_size, total_size;
+
+ if (header->header_addr < header->load_addr)
+ return grub_error (GRUB_ERR_BAD_OS, "Header precedes code");
+
+ if (header_offset < (header->header_addr - header->load_addr)
+ || load_offset > file_size)
+ return grub_error (GRUB_ERR_BAD_OS, "Code and data go out of file");
+
+ if (load_end_addr == 0)
+ {
+ if (file_size - load_offset > 0xFFFFFFFF)
+ return grub_error (GRUB_ERR_BAD_OS, "Code and data size is too big");
+ load_size = file_size - load_offset;
+ load_end_addr = header->load_addr + load_size;
+ }
+ else
+ load_size = load_end_addr - header->load_addr;
+
+ if (load_end_addr < header->load_addr)
+ return grub_error (GRUB_ERR_BAD_OS, "Code and data size is negative");
+
+ if (-(grub_uint64_t) load_size <= load_offset
+ || load_offset + load_size > file_size)
+ return grub_error (GRUB_ERR_BAD_OS, "Code and data go out of file");
+
+ if (header->entry_addr < header->load_addr
+ || header->entry_addr >= load_end_addr)
+ return grub_error (GRUB_ERR_BAD_OS,
+ "Entry point is outside of code and data area");
+
+ if (bss_end_addr == 0)
+ bss_end_addr = load_end_addr;
+
+ if (bss_end_addr < load_end_addr)
+ return grub_error (GRUB_ERR_BAD_OS, "BSS size is negative");
+
+ total_size = load_size + (bss_end_addr - load_end_addr);
+
+ if (-load_size <= (bss_end_addr - load_end_addr)
+ || header->load_addr < grub_os_area_addr
+ || -total_size <= header->load_addr
+ || (header->load_addr + total_size)
+ > (grub_os_area_addr + grub_os_area_size))
+ return grub_error (GRUB_ERR_BAD_OS,
+ "Kernel doesn't fit in memory reserved for the OS");
+
+ if (grub_file_seek (file, load_offset) == (grub_off_t) -1
+ || grub_file_read (file, (char *) header->load_addr, load_size)
+ != (grub_ssize_t) load_size)
+ return grub_error (GRUB_ERR_READ_ERROR, "Cannot read code and data");
+
+ grub_memset ((void *) load_end_addr, 0, total_size - load_size);
+
+ entry = header->entry_addr;
+
+ return GRUB_ERR_NONE;
+}
+
void
grub_rescue_cmd_multiboot (int argc, char *argv[])
{
@@ -293,7 +360,13 @@
goto fail;
}
- if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
+ if (header->flags & GRUB_MB_AOUT_KLUDGE)
+ {
+ if (grub_multiboot_load_raw (file, (char *) header - buffer, header)
+ != GRUB_ERR_NONE)
+ goto fail;
+ }
+ else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
goto fail;
mbi = grub_malloc (sizeof (struct grub_multiboot_info));
@@ -325,6 +398,15 @@
mbi->flags |= GRUB_MB_INFO_CMDLINE;
mbi->cmdline = (grub_uint32_t) cmdline;
+ mbi->flags |= GRUB_MB_INFO_BOOTDEV;
+ mbi->boot_device = (grub_boot_drive << 24);
+ if (grub_install_dos_part >= 0)
+ mbi->boot_device |= 0x00FFFF | (grub_install_dos_part << 16);
+ else if (grub_install_bsd_part >= 0)
+ mbi->boot_device |= 0xFF00FF | (grub_install_bsd_part << 8);
+ else
+ mbi->boot_device |= 0xFFFFFF;
+
mbi->flags |= GRUB_MB_INFO_BOOT_LOADER_NAME;
mbi->boot_loader_name = (grub_uint32_t) grub_strdup (PACKAGE_STRING);
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel