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;
}
next prev parent 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.