All of lore.kernel.org
 help / color / mirror / Atom feed
From: Robert Millan <rmh@aybabtu.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Cc: "Yoshinori K. Okuji" <okuji@enbug.org>
Subject: Re: loadee relocation (Re: loader modules jumping back to kernel)
Date: Fri, 1 Aug 2008 01:45:30 +0200	[thread overview]
Message-ID: <20080731234530.GA18681@thorin> (raw)
In-Reply-To: <20080730191510.GA18619@thorin>

[-- Attachment #1: Type: text/plain, Size: 1813 bytes --]

On Wed, Jul 30, 2008 at 09:15:10PM +0200, Robert Millan wrote:
> 
> Let's try to revive this discussion.  Here's a patch I made a while ago that
> implements support for loading at any address.  It works by having a "special"
> version of malloc() that is told to allocate a chunk of memory that does
> _not_ overlap with a specific region.  It does so by iteratively reserving
> memory (and keeping track of what was reserved, of course).
> 
> Then we use this function to allocate the asm relocator code in heap, asking
> it to garantee that it won't overlap with our final destination.  Finally,
> our loadee can be put anywhere (e.g. in heap), and we just jump to the
> relocator which will jump to the loadee.
> 
> But I really find the approach really ugly.  What do you think?  If we agree
> that this is the way to go, I can do some cleanup & update it to current svn
> for a merge.

Here's a new patch, with the following approach.  We put this in a single
heap area:

  <forward_relocator> <payload> <backward_relocator>

we pick the relocator we want depending on wether we want to copy to a lower
or higher address.  This garantees that the relocator itself isn't
overwritten.  Then we set cpu context appropiately, and jump.

I like this much better.  Also, it doesn't depend on the static OS load
area.

Some doubts:

  - What to do about physical_entry_addr now?  My patch currently discards
    it, which I suppose is not what we want.

  - Should we do the same for the elf64 loader?  And how?  I don't know of
    any example ELF64 images I could test with.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."

[-- Attachment #2: relocate_payload.diff --]
[-- Type: text/x-diff, Size: 5529 bytes --]

Index: kern/i386/loader.S
===================================================================
--- kern/i386/loader.S	(revision 1755)
+++ kern/i386/loader.S	(working copy)
@@ -123,6 +123,13 @@
  * This starts the multiboot kernel.
  */
 
+VARIABLE(grub_multiboot_payload_size)
+	.long	0
+VARIABLE(grub_multiboot_payload_orig)
+	.long	0
+VARIABLE(grub_multiboot_payload_dest)
+	.long	0
+
 FUNCTION(grub_multiboot_real_boot)
 	/* Push the entry address on the stack.  */
 	pushl	%eax
@@ -138,9 +145,16 @@
 
 	/* Move the magic value into eax and jump to the kernel.  */
 	movl	$MULTIBOOT_MAGIC2,%eax
-	popl	%ecx
-	jmp 	*%ecx
 
+	/* Where do we copy what from.  */
+	movl	EXT_C(grub_multiboot_payload_size), %ecx
+	movl	EXT_C(grub_multiboot_payload_orig), %esi
+	movl	EXT_C(grub_multiboot_payload_dest), %edi
+			
+	/* Jump to the relocator.  */
+	popl	%edx
+	jmp 	*%edx
+	
 /*
  * This starts the multiboot 2 kernel.
  */
Index: include/grub/i386/pc/kernel.h
===================================================================
--- include/grub/i386/pc/kernel.h	(revision 1755)
+++ include/grub/i386/pc/kernel.h	(working copy)
@@ -86,6 +86,10 @@
 extern grub_addr_t EXPORT_FUNC(grub_arch_memdisk_addr) (void);
 extern grub_off_t EXPORT_FUNC(grub_arch_memdisk_size) (void);
 
+extern grub_addr_t EXPORT_VAR(grub_multiboot_payload_orig);
+extern grub_addr_t EXPORT_VAR(grub_multiboot_payload_dest);
+extern grub_size_t EXPORT_VAR(grub_multiboot_payload_size);
+
 #endif /* ! ASM_FILE */
 
 #endif /* ! KERNEL_MACHINE_HEADER */
Index: loader/i386/pc/multiboot.c
===================================================================
--- loader/i386/pc/multiboot.c	(revision 1756)
+++ loader/i386/pc/multiboot.c	(working copy)
@@ -50,6 +50,28 @@
 static struct grub_multiboot_info *mbi;
 static grub_addr_t entry;
 
+static char *playground = NULL;
+extern char *grub_multiboot_payload_orig, *grub_multiboot_payload_dest;
+extern grub_size_t grub_multiboot_payload_size;
+
+static grub_uint8_t forward_relocator[] =
+{
+  0xfc,		/* cld */
+  0x89, 0xf2,	/* movl %esi, %edx */
+  0xf3, 0xa4,	/* rep movsb */
+  0xff, 0xe2,	/* jmp *%edx */
+};
+
+static grub_uint8_t backward_relocator[] =
+{
+  0xfd,		/* std */
+  0x01, 0xce,	/* addl %ecx, %esi */
+  0x01, 0xcf,	/* addl %ecx, %edi */
+  0x41,		/* incl %ecx */
+  0xf3, 0xa4,	/* rep movsb */
+  0xff, 0xe7,	/* jmp *%edi */
+};
+
 static grub_err_t
 grub_multiboot_boot (void)
 {
@@ -118,35 +140,50 @@
 
   phdr_base = (char *) buffer + ehdr->e_phoff;
 #define phdr(i)			((Elf32_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
+  
+  {
+    /* Find the highest address claimed by our payload.  */
+    char *end_addr = NULL;
+    for (i = 0; i < ehdr->e_phnum; i++)
+      {
+	grub_addr_t addr = (phdr(i)->p_paddr + phdr(i)->p_memsz);
+	if (addr > end_addr)
+	  end_addr = addr;
+      }
+    grub_multiboot_payload_size = end_addr - phdr(0)->p_paddr;
+  }
 
+  if (playground)
+    grub_free (playground);
+  playground = grub_malloc (sizeof (forward_relocator) + grub_multiboot_payload_size + sizeof (backward_relocator));
+  if (! playground)
+    return grub_errno;
+
+  grub_multiboot_payload_orig = playground + sizeof (forward_relocator);
+  grub_multiboot_payload_dest = (char *) phdr(0)->p_paddr;
+
+  grub_memmove (playground, forward_relocator, sizeof (forward_relocator));
+  grub_memmove (grub_multiboot_payload_orig + grub_multiboot_payload_size, backward_relocator, sizeof (backward_relocator));
+
   /* Load every loadable segment in memory.  */
   for (i = 0; i < ehdr->e_phnum; i++)
     {
       if (phdr(i)->p_type == PT_LOAD)
         {
-          /* The segment should fit in the area reserved for the OS.  */
-          if (phdr(i)->p_paddr < grub_os_area_addr)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "segment doesn't fit in memory reserved for the OS (0x%lx < 0x%lx)",
-			       phdr(i)->p_paddr, grub_os_area_addr);
-          if (phdr(i)->p_paddr + phdr(i)->p_memsz > grub_os_area_addr + grub_os_area_size)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)",
-			       phdr(i)->p_paddr + phdr(i)->p_memsz,
-			       grub_os_area_addr + grub_os_area_size);
+	  char *load_this_module_at = grub_multiboot_payload_orig + (phdr(i)->p_paddr - phdr(0)->p_paddr);
 
-          if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
+	  if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
 	      == (grub_off_t) -1)
 	    return grub_error (GRUB_ERR_BAD_OS,
 			       "invalid offset in program header");
 
-          if (grub_file_read (file, (void *) phdr(i)->p_paddr, phdr(i)->p_filesz)
+          if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz)
               != (grub_ssize_t) phdr(i)->p_filesz)
 	    return grub_error (GRUB_ERR_BAD_OS,
 			       "couldn't read segment from file");
 
           if (phdr(i)->p_filesz < phdr(i)->p_memsz)
-            grub_memset ((char *) phdr(i)->p_paddr + phdr(i)->p_filesz, 0,
+            grub_memset (load_this_module_at + phdr(i)->p_filesz, 0,
 			 phdr(i)->p_memsz - phdr(i)->p_filesz);
 
           if ((entry >= phdr(i)->p_vaddr) &&
@@ -159,6 +196,13 @@
   if (physical_entry_addr)
     entry = physical_entry_addr;
 
+  /* FIXME: how do we handle physical_entry_addr now?  */
+
+  if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig)
+    entry = (grub_addr_t) playground;
+  else
+    entry = (grub_addr_t) grub_multiboot_payload_orig + grub_multiboot_payload_size;
+
   return grub_errno;
 }
 

  reply	other threads:[~2008-07-31 23:46 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-19 23:06 loader modules jumping back to kernel Robert Millan
2008-07-20  3:26 ` Bean
2008-07-20  9:09 ` Yoshinori K. Okuji
2008-07-27 21:39   ` Robert Millan
2008-07-30 19:15     ` loadee relocation (Re: loader modules jumping back to kernel) Robert Millan
2008-07-31 23:45       ` Robert Millan [this message]
2008-08-01 16:16         ` Robert Millan
2008-08-01 22:45           ` Robert Millan
2008-08-02 12:11             ` Robert Millan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080731234530.GA18681@thorin \
    --to=rmh@aybabtu.com \
    --cc=grub-devel@gnu.org \
    --cc=okuji@enbug.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.