Hello,

our project uses various (micro)kernels booted via GRUB2 using the
Multiboot & Multiboot2 protocol. Some of the kernels have several ELF
segments which are not necessarily placed close together.

When booting such kernels with GRUB2 in BIOS legacy mode we observed
that the screen shows colored blinking scrambled output, until the
graphic drivers takes over. (Looks very fancy, but our customers don't
like it ;-) ). We could track down the issue and have a fix for GRUB2,
which is attached.

Can you please have a look and check regarding what should/could be
changed to get it upstream? We did not test the dynamic relocation part,
since we have no such (kernel) setup. Thanks in advance.

Regards,

Alex.

-- 
Alexander Boettcher
Genode Labs

http://www.genode-labs.com - http://www.genode.org -
https://github.com/genodelabs/genode

Genode Labs GmbH - Amtsgericht Dresden - HRB 28424 - Sitz Dresden
Geschäftsführer: Dr.-Ing. Norman Feske, Christian Helmuth
From 605ca41045f97f92fb698ea49d7267e1cb29f40c Mon Sep 17 00:00:00 2001
From: Alexander Boettcher <alexander.boettc...@genode-labs.com>
Date: Tue, 20 Mar 2018 09:21:06 +0100
Subject: [PATCH] multiboot: use per segment a separate relocator chunk

If the segments are not dense packed, the original code set up a huge
relocator chunk comprising all segments.

During the final relocation in grub_relocator_prepare_relocs, the chunk
is moved to its desired place and overrides memory which are actually not
covered/touched by the specified segments.

The overridden memory may contain reserved memory
(vga text mode, acpi tables e.g.), which leads to strange boot behaviour.
---
 grub-core/loader/multiboot_elfxx.c | 59 +++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 30 deletions(-)

diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c
index 67daf59..0d10c64 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -57,7 +57,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
   char *phdr_base;
   grub_err_t err;
   grub_relocator_chunk_t ch;
-  grub_uint32_t load_offset, load_size;
+  grub_uint32_t load_size;
   int i;
   void *source;
 
@@ -99,29 +99,6 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
 
   load_size = highest_load - mld->link_base_addr;
 
-  if (mld->relocatable)
-    {
-      if (load_size > mld->max_addr || mld->min_addr > mld->max_addr - load_size)
-	return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size");
-
-      err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch,
-					      mld->min_addr, mld->max_addr - load_size,
-					      load_size, mld->align ? mld->align : 1,
-					      mld->preference, mld->avoid_efi_boot_services);
-    }
-  else
-    err = grub_relocator_alloc_chunk_addr (GRUB_MULTIBOOT (relocator), &ch,
-					   mld->link_base_addr, load_size);
-
-  if (err)
-    {
-      grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n");
-      return err;
-    }
-
-  mld->load_base_addr = get_physical_target_address (ch);
-  source = get_virtual_current_address (ch);
-
   grub_dprintf ("multiboot_loader", "link_base_addr=0x%x, load_base_addr=0x%x, "
 		"load_size=0x%x, relocatable=%d\n", mld->link_base_addr,
 		mld->load_base_addr, load_size, mld->relocatable);
@@ -133,21 +110,44 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
   /* Load every loadable segment in memory.  */
   for (i = 0; i < ehdr->e_phnum; i++)
     {
-      if (phdr(i)->p_type == PT_LOAD)
+      if (phdr(i)->p_type != PT_LOAD)
+        continue;
+
+      if (mld->relocatable)
         {
+          if (load_size > mld->max_addr || mld->min_addr > mld->max_addr - load_size)
+            return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size");
+
+          err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch,
+                                                  mld->min_addr, mld->max_addr - load_size,
+                                                  phdr(i)->p_memsz, mld->align ? mld->align : 1,
+                                                  mld->preference, mld->avoid_efi_boot_services);
+        } else {
+          err = grub_relocator_alloc_chunk_addr (GRUB_MULTIBOOT (relocator), &ch,
+                                                 phdr(i)->p_paddr, phdr(i)->p_memsz);
+        }
+
+      if (err)
+        {
+          grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n");
+          return err;
+        }
+
+      if (mld->load_base_addr > get_physical_target_address (ch))
+        mld->load_base_addr = get_physical_target_address (ch);
+
+      source = get_virtual_current_address (ch);
 
 	  grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n",
 			i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr);
 
-	  load_offset = phdr(i)->p_paddr - mld->link_base_addr;
-
 	  if (phdr(i)->p_filesz != 0)
 	    {
 	      if (grub_file_seek (mld->file, (grub_off_t) phdr(i)->p_offset)
 		  == (grub_off_t) -1)
 		return grub_errno;
 
-	      if (grub_file_read (mld->file, (grub_uint8_t *) source + load_offset, phdr(i)->p_filesz)
+	      if (grub_file_read (mld->file, (grub_uint8_t *) source, phdr(i)->p_filesz)
 		  != (grub_ssize_t) phdr(i)->p_filesz)
 		{
 		  if (!grub_errno)
@@ -158,9 +158,8 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
 	    }
 
           if (phdr(i)->p_filesz < phdr(i)->p_memsz)
-            grub_memset ((grub_uint8_t *) source + load_offset + phdr(i)->p_filesz, 0,
+            grub_memset ((grub_uint8_t *) source + phdr(i)->p_filesz, 0,
 			 phdr(i)->p_memsz - phdr(i)->p_filesz);
-        }
     }
 
   for (i = 0; i < ehdr->e_phnum; i++)
-- 
2.7.4

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to