grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Self multiboot patch


From: Mikhail Vorozhtsov
Subject: Self multiboot patch
Date: Sun, 17 Jun 2007 19:24:00 +0700
User-agent: Mozilla-Thunderbird 2.0.0.0 (X11/20070601)

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);
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]