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."
2008-08-01 Robert Millan <[EMAIL PROTECTED]>
* 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;
}
_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel