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 18:16:06 +0200	[thread overview]
Message-ID: <20080801161606.GA31439@thorin> (raw)
In-Reply-To: <20080731234530.GA18681@thorin>

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

On Fri, Aug 01, 2008 at 01:45:30AM +0200, Robert Millan wrote:
> 
>   - What to do about physical_entry_addr now?  My patch currently discards
>     it, which I suppose is not what we want.

Fixed after some discussion with Bean on IRC.  This version of the patch
should handle physical_entry_addr fine.

-- 
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: 6654 bytes --]

2008-08-01  Robert Millan  <rmh@aybabtu.com>

	* loader/i386/pc/multiboot.c (playground, forward_relocator)
	(backward_relocator): New variables.  Used to allocate and relocate
	the payload, respectively.
	(grub_multiboot_load_elf32): Load into heap instead of requested
	address, install the appropiate relocator code in each bound of
	the payload, and set the entry point such that
	grub_multiboot_real_boot() will jump to one of them.

	* kern/i386/loader.S (grub_multiboot_payload_size)
	(grub_multiboot_payload_orig, grub_multiboot_payload_dest): New
	variables.
	(grub_multiboot_real_boot): Set cpu context to what the relocator
	expects, and jump to the relocator instead of the payload.

	* include/grub/i386/pc/loader.h (grub_multiboot_payload_size)
	(grub_multiboot_payload_orig, grub_multiboot_payload_dest): Export.

Index: kern/i386/loader.S
===================================================================
--- kern/i386/loader.S	(revision 1758)
+++ 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/loader.h
===================================================================
--- include/grub/i386/pc/loader.h	(revision 1758)
+++ include/grub/i386/pc/loader.h	(working copy)
@@ -25,4 +25,8 @@
 /* This is an asm part of the chainloader.  */
 void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn));
 
+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 /* ! GRUB_LOADER_MACHINE_HEADER */
Index: loader/i386/pc/multiboot.c
===================================================================
--- loader/i386/pc/multiboot.c	(revision 1758)
+++ loader/i386/pc/multiboot.c	(working copy)
@@ -50,6 +50,26 @@
 static struct grub_multiboot_info *mbi;
 static grub_addr_t entry;
 
+static char *playground = NULL;
+
+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)
 {
@@ -98,7 +118,7 @@
 {
   Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer;
   char *phdr_base;
-  grub_addr_t physical_entry_addr = 0;
+  grub_off_t physical_entry_offset = 0;
   int i;
 
   if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
@@ -118,47 +138,66 @@
 
   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) &&
 	      (entry < phdr(i)->p_vaddr + phdr(i)->p_memsz))
-	    physical_entry_addr = entry + phdr(i)->p_paddr - phdr(i)->p_vaddr;
+	    physical_entry_offset = phdr(i)->p_paddr - phdr(i)->p_vaddr;
         }
     }
 #undef phdr
-
-  if (physical_entry_addr)
-    entry = physical_entry_addr;
-
+  
+  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;
+  
+  entry += physical_entry_offset;
+  
   return grub_errno;
 }
 

  reply	other threads:[~2008-08-01 16:17 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
2008-08-01 16:16         ` Robert Millan [this message]
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=20080801161606.GA31439@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.