First working newreloc
This commit is contained in:
parent
6b60576149
commit
14e43c6e02
7 changed files with 127 additions and 102 deletions
|
@ -202,14 +202,14 @@ serial_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||||
serial_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
serial_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||||
|
|
||||||
# For multiboot.mod.
|
# For multiboot.mod.
|
||||||
#pkglib_MODULES += multiboot.mod
|
pkglib_MODULES += multiboot.mod
|
||||||
multiboot_mod_SOURCES = loader/i386/multiboot.c \
|
multiboot_mod_SOURCES = loader/i386/multiboot.c \
|
||||||
loader/multiboot_loader.c
|
loader/multiboot_loader.c
|
||||||
multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
|
multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||||
multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||||
multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS)
|
multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS)
|
||||||
|
|
||||||
#pkglib_MODULES += multiboot2.mod
|
pkglib_MODULES += multiboot2.mod
|
||||||
multiboot2_mod_SOURCES = loader/i386/multiboot.c \
|
multiboot2_mod_SOURCES = loader/i386/multiboot.c \
|
||||||
loader/multiboot_loader.c
|
loader/multiboot_loader.c
|
||||||
multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2
|
multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2
|
||||||
|
|
|
@ -27,9 +27,7 @@ void grub_multiboot2_real_boot (grub_addr_t entry,
|
||||||
struct multiboot_info *mbi)
|
struct multiboot_info *mbi)
|
||||||
__attribute__ ((noreturn));
|
__attribute__ ((noreturn));
|
||||||
|
|
||||||
|
extern struct grub_relocator *grub_multiboot_relocator;
|
||||||
extern grub_uint32_t grub_multiboot_payload_eip;
|
extern grub_uint32_t grub_multiboot_payload_eip;
|
||||||
extern char *grub_multiboot_payload_orig;
|
|
||||||
extern grub_addr_t grub_multiboot_payload_dest;
|
|
||||||
extern grub_size_t grub_multiboot_payload_size;
|
|
||||||
|
|
||||||
#endif /* ! GRUB_MULTIBOOT_CPU_HEADER */
|
#endif /* ! GRUB_MULTIBOOT_CPU_HEADER */
|
||||||
|
|
|
@ -190,7 +190,7 @@ grub_machine_init (void)
|
||||||
from 1MB. This region is partially used for loading OS images.
|
from 1MB. This region is partially used for loading OS images.
|
||||||
For now, 1/4 of this is added to free memory. */
|
For now, 1/4 of this is added to free memory. */
|
||||||
for (i = 0; i < num_regions; i++)
|
for (i = 0; i < num_regions; i++)
|
||||||
if (mem_regions[i].addr == 0x100000)
|
/* if (mem_regions[i].addr == 0x100000)
|
||||||
{
|
{
|
||||||
grub_size_t quarter = mem_regions[i].size >> 2;
|
grub_size_t quarter = mem_regions[i].size >> 2;
|
||||||
|
|
||||||
|
@ -199,11 +199,11 @@ grub_machine_init (void)
|
||||||
grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size),
|
grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size),
|
||||||
quarter);
|
quarter);
|
||||||
}
|
}
|
||||||
else
|
else*/
|
||||||
grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);
|
grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);
|
||||||
|
|
||||||
if (! grub_os_area_addr)
|
// if (! grub_os_area_addr)
|
||||||
grub_fatal ("no upper memory");
|
//grub_fatal ("no upper memory");
|
||||||
|
|
||||||
grub_tsc_init ();
|
grub_tsc_init ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
#include <grub/mm.h>
|
#include <grub/mm.h>
|
||||||
#include <grub/misc.h>
|
#include <grub/misc.h>
|
||||||
|
|
||||||
#include <grub/types.h>
|
|
||||||
#include <grub/types.h>
|
#include <grub/types.h>
|
||||||
#include <grub/err.h>
|
#include <grub/err.h>
|
||||||
|
#include <grub/term.h>
|
||||||
|
|
||||||
#include <grub/i386/relocator.h>
|
#include <grub/i386/relocator.h>
|
||||||
#include <grub/relocator_private.h>
|
#include <grub/relocator_private.h>
|
||||||
|
@ -67,15 +67,16 @@ grub_cpu_relocator_jumper (void *rels, grub_addr_t addr)
|
||||||
{
|
{
|
||||||
grub_uint8_t *ptr;
|
grub_uint8_t *ptr;
|
||||||
ptr = rels;
|
ptr = rels;
|
||||||
|
/* movl $addr, %eax (for relocator) */
|
||||||
|
*(grub_uint8_t *) ptr = 0xb8;
|
||||||
|
ptr++;
|
||||||
|
*(grub_uint32_t *) ptr = addr;
|
||||||
|
ptr += 4;
|
||||||
/* jmp $addr */
|
/* jmp $addr */
|
||||||
*(grub_uint8_t *) ptr = 0xe9;
|
*(grub_uint8_t *) ptr = 0xe9;
|
||||||
ptr++;
|
ptr++;
|
||||||
*(grub_uint32_t *) ptr = addr - (grub_uint32_t) (ptr + 4);
|
*(grub_uint32_t *) ptr = addr - (grub_uint32_t) (ptr + 4);
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
/* movl $addr, %eax (for relocator) */
|
|
||||||
*(grub_uint8_t *) ptr = 0xb8;
|
|
||||||
ptr++;
|
|
||||||
*(grub_uint32_t *) ptr = addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -112,6 +113,7 @@ grub_relocator32_boot (struct grub_relocator *rel,
|
||||||
void *src;
|
void *src;
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
grub_addr_t relst;
|
grub_addr_t relst;
|
||||||
|
|
||||||
err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0,
|
err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0,
|
||||||
(0xffffffff - RELOCATOR_SIZEOF (32))
|
(0xffffffff - RELOCATOR_SIZEOF (32))
|
||||||
+ 1, RELOCATOR_SIZEOF (32), 16);
|
+ 1, RELOCATOR_SIZEOF (32), 16);
|
||||||
|
@ -130,6 +132,7 @@ grub_relocator32_boot (struct grub_relocator *rel,
|
||||||
err = grub_relocator_prepare_relocs (rel, target, &relst);
|
err = grub_relocator_prepare_relocs (rel, target, &relst);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
asm volatile ("cli");
|
asm volatile ("cli");
|
||||||
((void (*) (void)) relst) ();
|
((void (*) (void)) relst) ();
|
||||||
|
|
||||||
|
|
|
@ -68,12 +68,18 @@ get_best_header (struct grub_relocator *rel,
|
||||||
for (chunk = rel->chunks; chunk; chunk = chunk->next)
|
for (chunk = rel->chunks; chunk; chunk = chunk->next)
|
||||||
if ((chunk->target <= addr
|
if ((chunk->target <= addr
|
||||||
&& addr < chunk->target + chunk->size)
|
&& addr < chunk->target + chunk->size)
|
||||||
|| (chunk->target <= addr + size
|
|| (chunk->target < addr + size
|
||||||
&& addr + size < chunk->target + chunk->size)
|
&& addr + size < chunk->target + chunk->size)
|
||||||
|| (addr <= chunk->target && chunk->target < addr + size)
|
|| (addr <= chunk->target && chunk->target < addr + size)
|
||||||
|| (addr <= chunk->target + chunk->size
|
|| (addr < chunk->target + chunk->size
|
||||||
&& chunk->target + chunk->size < addr + size))
|
&& chunk->target + chunk->size < addr + size))
|
||||||
{
|
{
|
||||||
|
grub_dprintf ("relocator",
|
||||||
|
"collision 0x%llx+0x%llx, 0x%llx+0x%llx\n",
|
||||||
|
(unsigned long long) chunk->target,
|
||||||
|
(unsigned long long) chunk->size,
|
||||||
|
(unsigned long long) addr,
|
||||||
|
(unsigned long long) size);
|
||||||
addr = ALIGN_UP (chunk->target + chunk->size, align);
|
addr = ALIGN_UP (chunk->target + chunk->size, align);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -110,10 +116,10 @@ get_best_header (struct grub_relocator *rel,
|
||||||
for (chunk = rel->chunks; chunk; chunk = chunk->next)
|
for (chunk = rel->chunks; chunk; chunk = chunk->next)
|
||||||
if ((chunk->target <= addr
|
if ((chunk->target <= addr
|
||||||
&& addr < chunk->target + chunk->size)
|
&& addr < chunk->target + chunk->size)
|
||||||
|| (chunk->target <= addr + size
|
|| (chunk->target < addr + size
|
||||||
&& addr + size < chunk->target + chunk->size)
|
&& addr + size < chunk->target + chunk->size)
|
||||||
|| (addr <= chunk->target && chunk->target < addr + size)
|
|| (addr <= chunk->target && chunk->target < addr + size)
|
||||||
|| (addr <= chunk->target + chunk->size
|
|| (addr < chunk->target + chunk->size
|
||||||
&& chunk->target + chunk->size < addr + size))
|
&& chunk->target + chunk->size < addr + size))
|
||||||
{
|
{
|
||||||
addr = ALIGN_DOWN (chunk->target - size, align);
|
addr = ALIGN_DOWN (chunk->target - size, align);
|
||||||
|
@ -138,18 +144,29 @@ get_best_header (struct grub_relocator *rel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (hp = NULL, h = rb->first; h; hp = h, h = h->next)
|
hp = rb->first;
|
||||||
|
h = hp->next;
|
||||||
|
grub_dprintf ("relocator", "alive\n");
|
||||||
|
do
|
||||||
{
|
{
|
||||||
grub_addr_t allowable_start, allowable_end;
|
grub_addr_t allowable_start, allowable_end;
|
||||||
allowable_start = (grub_addr_t) h;
|
allowable_start = (grub_addr_t) h;
|
||||||
allowable_end = (grub_addr_t) (h + 1 + h->size);
|
allowable_end = (grub_addr_t) (h + 1 + h->size);
|
||||||
|
|
||||||
try_addr (allowable_start, allowable_end);
|
try_addr (allowable_start, allowable_end);
|
||||||
|
|
||||||
if ((grub_addr_t) h == (grub_addr_t) (rb + 1))
|
if ((grub_addr_t) h == (grub_addr_t) (rb + 1))
|
||||||
try_addr (allowable_start - sizeof (*rb) - rb->pre_size,
|
{
|
||||||
allowable_end - sizeof (*rb));
|
grub_dprintf ("relocator", "Trying region start 0x%llx\n",
|
||||||
|
(unsigned long long) (allowable_start
|
||||||
|
- sizeof (*rb) - rb->pre_size));
|
||||||
|
try_addr (allowable_start - sizeof (*rb) - rb->pre_size,
|
||||||
|
allowable_end - sizeof (*rb));
|
||||||
|
}
|
||||||
|
hp = h;
|
||||||
|
h = hp->next;
|
||||||
}
|
}
|
||||||
|
while (hp && hp != rb->first);
|
||||||
*prev = hbp;
|
*prev = hbp;
|
||||||
return hb;
|
return hb;
|
||||||
}
|
}
|
||||||
|
@ -172,7 +189,7 @@ malloc_in_range (struct grub_relocator *rel,
|
||||||
{
|
{
|
||||||
if ((grub_addr_t) r + r->size + sizeof (*r) > start
|
if ((grub_addr_t) r + r->size + sizeof (*r) > start
|
||||||
&& (grub_addr_t) r <= end && r->size + sizeof (*r) >= size
|
&& (grub_addr_t) r <= end && r->size + sizeof (*r) >= size
|
||||||
&& (rb == NULL || from_low_priv ? rb > r : rb < r))
|
&& (rb == NULL || (from_low_priv ? rb > r : rb < r)))
|
||||||
{
|
{
|
||||||
rb = r;
|
rb = r;
|
||||||
rbp = rp;
|
rbp = rp;
|
||||||
|
@ -183,8 +200,13 @@ malloc_in_range (struct grub_relocator *rel,
|
||||||
if (!rb)
|
if (!rb)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
grub_dprintf ("relocator", "trying region %p - %p\n", rb, rb + rb->size + 1);
|
||||||
|
|
||||||
hb = get_best_header (rel, start, end, align, size, rb, &hbp, &best_addr,
|
hb = get_best_header (rel, start, end, align, size, rb, &hbp, &best_addr,
|
||||||
from_low_priv, collisioncheck);
|
from_low_priv, collisioncheck);
|
||||||
|
|
||||||
|
grub_dprintf ("relocator", "best header %p\n", hb);
|
||||||
|
|
||||||
if (!hb)
|
if (!hb)
|
||||||
{
|
{
|
||||||
if (from_low_priv)
|
if (from_low_priv)
|
||||||
|
@ -263,9 +285,8 @@ malloc_in_range (struct grub_relocator *rel,
|
||||||
if (foll)
|
if (foll)
|
||||||
{
|
{
|
||||||
foll->next = hb;
|
foll->next = hb;
|
||||||
if (hbp)
|
hbp->next = foll;
|
||||||
hbp->next = foll;
|
if (rb->first == hbp)
|
||||||
else
|
|
||||||
rb->first = foll;
|
rb->first = foll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,9 +296,7 @@ malloc_in_range (struct grub_relocator *rel,
|
||||||
foll->next = hb->next;
|
foll->next = hb->next;
|
||||||
else
|
else
|
||||||
foll = hb->next;
|
foll = hb->next;
|
||||||
if (hbp)
|
if (rb->first == hbp)
|
||||||
hbp->next = foll;
|
|
||||||
else
|
|
||||||
rb->first = foll;
|
rb->first = foll;
|
||||||
}
|
}
|
||||||
*res = best_addr;
|
*res = best_addr;
|
||||||
|
@ -315,6 +334,9 @@ grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, void **src,
|
||||||
if (!chunk)
|
if (!chunk)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
||||||
|
grub_dprintf ("relocator", "min_addr = 0x%llx, max_addr = 0x%llx\n",
|
||||||
|
(unsigned long long) min_addr, (unsigned long long) max_addr);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* A trick to improve Linux allocation. */
|
/* A trick to improve Linux allocation. */
|
||||||
|
@ -339,6 +361,9 @@ grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, void **src,
|
||||||
}
|
}
|
||||||
while (0);
|
while (0);
|
||||||
|
|
||||||
|
grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n",
|
||||||
|
(unsigned long long) start, (unsigned long long) target);
|
||||||
|
|
||||||
if (rel->highestaddr < target + size)
|
if (rel->highestaddr < target + size)
|
||||||
rel->highestaddr = target + size;
|
rel->highestaddr = target + size;
|
||||||
|
|
||||||
|
@ -415,7 +440,8 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src,
|
||||||
grub_free (chunk);
|
grub_free (chunk);
|
||||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: check memory map. */
|
||||||
chunk->target = ALIGN_UP (min_addr, align);
|
chunk->target = ALIGN_UP (min_addr, align);
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -455,6 +481,8 @@ void
|
||||||
grub_relocator_unload (struct grub_relocator *rel)
|
grub_relocator_unload (struct grub_relocator *rel)
|
||||||
{
|
{
|
||||||
struct grub_relocator_chunk *chunk, *next;
|
struct grub_relocator_chunk *chunk, *next;
|
||||||
|
if (!rel)
|
||||||
|
return;
|
||||||
for (chunk = rel->chunks; chunk; chunk = next)
|
for (chunk = rel->chunks; chunk; chunk = next)
|
||||||
{
|
{
|
||||||
grub_fatal ("Relocator unloading isn't implemented yet");
|
grub_fatal ("Relocator unloading isn't implemented yet");
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The bits in the required part of flags field we don't support. */
|
/* The bits in the required part of flags field we don't support. */
|
||||||
#define UNSUPPORTED_FLAGS 0x0000fffc
|
#define UNSUPPORTED_FLAGS 0x0000fff0
|
||||||
|
|
||||||
#include <grub/loader.h>
|
#include <grub/loader.h>
|
||||||
#include <grub/machine/loader.h>
|
#include <grub/machine/loader.h>
|
||||||
|
@ -55,12 +55,10 @@
|
||||||
|
|
||||||
extern grub_dl_t my_mod;
|
extern grub_dl_t my_mod;
|
||||||
static struct multiboot_info *mbi, *mbi_dest;
|
static struct multiboot_info *mbi, *mbi_dest;
|
||||||
|
struct grub_relocator *grub_multiboot_relocator = NULL;
|
||||||
|
|
||||||
static grub_size_t code_size;
|
static grub_size_t code_size;
|
||||||
|
|
||||||
char *grub_multiboot_payload_orig;
|
|
||||||
grub_addr_t grub_multiboot_payload_dest;
|
|
||||||
grub_size_t grub_multiboot_payload_size;
|
|
||||||
grub_uint32_t grub_multiboot_payload_eip;
|
grub_uint32_t grub_multiboot_payload_eip;
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
@ -78,9 +76,7 @@ grub_multiboot_boot (void)
|
||||||
.esp = 0x7ff00
|
.esp = 0x7ff00
|
||||||
};
|
};
|
||||||
|
|
||||||
grub_relocator32_boot (grub_multiboot_payload_orig,
|
grub_relocator32_boot (grub_multiboot_relocator, state);
|
||||||
grub_multiboot_payload_dest,
|
|
||||||
state);
|
|
||||||
|
|
||||||
/* Not reached. */
|
/* Not reached. */
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
|
@ -101,10 +97,10 @@ grub_multiboot_unload (void)
|
||||||
}
|
}
|
||||||
grub_free ((void *) mbi->mods_addr);
|
grub_free ((void *) mbi->mods_addr);
|
||||||
}
|
}
|
||||||
grub_relocator32_free (grub_multiboot_payload_orig);
|
grub_relocator_unload (grub_multiboot_relocator);
|
||||||
|
grub_multiboot_relocator = NULL;
|
||||||
|
|
||||||
mbi = NULL;
|
mbi = NULL;
|
||||||
grub_multiboot_payload_orig = NULL;
|
|
||||||
grub_dl_unref (my_mod);
|
grub_dl_unref (my_mod);
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
|
@ -224,6 +220,10 @@ grub_multiboot (int argc, char *argv[])
|
||||||
int i;
|
int i;
|
||||||
int cmdline_argc;
|
int cmdline_argc;
|
||||||
char **cmdline_argv;
|
char **cmdline_argv;
|
||||||
|
int mbichunk_size;
|
||||||
|
void *mbichunk;
|
||||||
|
grub_addr_t mbichunk_dest;
|
||||||
|
grub_err_t err;
|
||||||
|
|
||||||
grub_loader_unset ();
|
grub_loader_unset ();
|
||||||
|
|
||||||
|
@ -271,8 +271,8 @@ grub_multiboot (int argc, char *argv[])
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_relocator32_free (grub_multiboot_payload_orig);
|
grub_relocator_unload (grub_multiboot_relocator);
|
||||||
grub_multiboot_payload_orig = NULL;
|
grub_multiboot_relocator = NULL;
|
||||||
|
|
||||||
mmap_length = grub_get_multiboot_mmap_len ();
|
mmap_length = grub_get_multiboot_mmap_len ();
|
||||||
|
|
||||||
|
@ -289,68 +289,81 @@ grub_multiboot (int argc, char *argv[])
|
||||||
|
|
||||||
boot_loader_name_length = sizeof(PACKAGE_STRING);
|
boot_loader_name_length = sizeof(PACKAGE_STRING);
|
||||||
|
|
||||||
#define cmdline_addr(x) ((void *) ((x) + code_size))
|
#define cmdline_addr(x) ((void *) (((grub_uint8_t *) x)))
|
||||||
#define boot_loader_name_addr(x) \
|
#define boot_loader_name_addr(x) \
|
||||||
((void *) ((x) + code_size + cmdline_length))
|
((void *) (((grub_uint8_t *) x) + cmdline_length))
|
||||||
#define mbi_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length))
|
#define mbi_addr(x) ((void *) (((grub_uint8_t *) x) + cmdline_length + boot_loader_name_length))
|
||||||
#define mmap_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length + sizeof (struct multiboot_info)))
|
#define mmap_addr(x) ((void *) (((grub_uint8_t *) x) + cmdline_length + boot_loader_name_length + sizeof (struct multiboot_info)))
|
||||||
|
|
||||||
grub_multiboot_payload_size = cmdline_length
|
mbichunk_size = cmdline_length
|
||||||
/* boot_loader_name_length might need to grow for mbi,etc to be aligned (see below) */
|
/* boot_loader_name_length might need to grow for mbi,etc to be aligned (see below) */
|
||||||
+ boot_loader_name_length + 3
|
+ boot_loader_name_length + 3
|
||||||
+ sizeof (struct multiboot_info) + mmap_length;
|
+ sizeof (struct multiboot_info) + mmap_length;
|
||||||
|
|
||||||
|
grub_multiboot_relocator = grub_relocator_new ();
|
||||||
|
|
||||||
|
if (!grub_multiboot_relocator)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (header->flags & MULTIBOOT_AOUT_KLUDGE)
|
if (header->flags & MULTIBOOT_AOUT_KLUDGE)
|
||||||
{
|
{
|
||||||
int offset = ((char *) header - buffer -
|
int offset = ((char *) header - buffer -
|
||||||
(header->header_addr - header->load_addr));
|
(header->header_addr - header->load_addr));
|
||||||
int load_size = ((header->load_end_addr == 0) ? file->size - offset :
|
int load_size = ((header->load_end_addr == 0) ? file->size - offset :
|
||||||
header->load_end_addr - header->load_addr);
|
header->load_end_addr - header->load_addr);
|
||||||
|
void *source;
|
||||||
|
|
||||||
if (header->bss_end_addr)
|
if (header->bss_end_addr)
|
||||||
code_size = (header->bss_end_addr - header->load_addr);
|
code_size = (header->bss_end_addr - header->load_addr);
|
||||||
else
|
else
|
||||||
code_size = load_size;
|
code_size = load_size;
|
||||||
grub_multiboot_payload_dest = header->load_addr;
|
|
||||||
|
|
||||||
grub_multiboot_payload_size += code_size;
|
err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator,
|
||||||
|
&source, header->load_addr,
|
||||||
grub_multiboot_payload_orig
|
code_size);
|
||||||
= grub_relocator32_alloc (grub_multiboot_payload_size);
|
if (err)
|
||||||
|
{
|
||||||
if (! grub_multiboot_payload_orig)
|
grub_dprintf ("multiboot_loader", "Error loading aout kludge\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
|
if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size);
|
grub_file_read (file, source, load_size);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (header->bss_end_addr)
|
if (header->bss_end_addr)
|
||||||
grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0,
|
grub_memset ((grub_uint32_t *) source + load_size, 0,
|
||||||
header->bss_end_addr - header->load_addr - load_size);
|
header->bss_end_addr - header->load_addr - load_size);
|
||||||
|
|
||||||
grub_multiboot_payload_eip = header->entry_addr;
|
grub_multiboot_payload_eip = header->entry_addr;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
|
else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* This provides alignment for the MBI, the memory map and the backward relocator. */
|
/* This provides alignment for the MBI, the memory map and the backward relocator. */
|
||||||
boot_loader_name_length += (0x04 - ((unsigned long) mbi_addr (grub_multiboot_payload_dest) & 0x03));
|
boot_loader_name_length += (0x04 - ((unsigned long) mbi_addr (0) & 0x03));
|
||||||
|
|
||||||
|
err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &mbichunk,
|
||||||
|
&mbichunk_dest,
|
||||||
|
0, (0xffffffff - mbichunk_size) + 1,
|
||||||
|
mbichunk_size, 4);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
grub_dprintf ("multiboot_loader", "Error allocating mbi chunk\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
mbi = mbi_addr (mbichunk);
|
||||||
|
mbi_dest = mbi_addr (mbichunk_dest);
|
||||||
|
|
||||||
mbi = mbi_addr (grub_multiboot_payload_orig);
|
|
||||||
mbi_dest = mbi_addr (grub_multiboot_payload_dest);
|
|
||||||
grub_memset (mbi, 0, sizeof (struct multiboot_info));
|
grub_memset (mbi, 0, sizeof (struct multiboot_info));
|
||||||
mbi->mmap_length = mmap_length;
|
mbi->mmap_length = mmap_length;
|
||||||
|
|
||||||
grub_fill_multiboot_mmap (mmap_addr (grub_multiboot_payload_orig));
|
grub_fill_multiboot_mmap (mmap_addr (mbichunk));
|
||||||
|
|
||||||
/* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated
|
mbi->mmap_addr = (grub_uint32_t) mmap_addr (mbichunk_dest);
|
||||||
by the spec. Is there something we can do about it? */
|
|
||||||
mbi->mmap_addr = (grub_uint32_t) mmap_addr (grub_multiboot_payload_dest);
|
|
||||||
mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
|
mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
|
||||||
|
|
||||||
/* Convert from bytes to kilobytes. */
|
/* Convert from bytes to kilobytes. */
|
||||||
|
@ -358,7 +371,7 @@ grub_multiboot (int argc, char *argv[])
|
||||||
mbi->mem_upper = grub_mmap_get_upper () / 1024;
|
mbi->mem_upper = grub_mmap_get_upper () / 1024;
|
||||||
mbi->flags |= MULTIBOOT_INFO_MEMORY;
|
mbi->flags |= MULTIBOOT_INFO_MEMORY;
|
||||||
|
|
||||||
cmdline = p = cmdline_addr (grub_multiboot_payload_orig);
|
cmdline = p = cmdline_addr (mbichunk);
|
||||||
if (! cmdline)
|
if (! cmdline)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -374,17 +387,17 @@ grub_multiboot (int argc, char *argv[])
|
||||||
*p = 0;
|
*p = 0;
|
||||||
|
|
||||||
mbi->flags |= MULTIBOOT_INFO_CMDLINE;
|
mbi->flags |= MULTIBOOT_INFO_CMDLINE;
|
||||||
mbi->cmdline = (grub_uint32_t) cmdline_addr (grub_multiboot_payload_dest);
|
mbi->cmdline = (grub_uint32_t) cmdline_addr (mbichunk_dest);
|
||||||
|
|
||||||
|
|
||||||
grub_strcpy (boot_loader_name_addr (grub_multiboot_payload_orig), PACKAGE_STRING);
|
grub_strcpy (boot_loader_name_addr (mbichunk), PACKAGE_STRING);
|
||||||
mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
|
mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
|
||||||
mbi->boot_loader_name = (grub_uint32_t) boot_loader_name_addr (grub_multiboot_payload_dest);
|
mbi->boot_loader_name = (grub_uint32_t) boot_loader_name_addr (mbichunk_dest);
|
||||||
|
|
||||||
if (grub_multiboot_get_bootdev (&mbi->boot_device))
|
if (grub_multiboot_get_bootdev (&mbi->boot_device))
|
||||||
mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
|
mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
|
||||||
|
|
||||||
grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1);
|
grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (file)
|
if (file)
|
||||||
|
|
|
@ -51,7 +51,6 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer)
|
||||||
{
|
{
|
||||||
Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer;
|
Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer;
|
||||||
char *phdr_base;
|
char *phdr_base;
|
||||||
int lowest_segment = -1, highest_segment = -1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX)
|
if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX)
|
||||||
|
@ -82,54 +81,38 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer)
|
||||||
phdr_base = (char *) buffer + ehdr->e_phoff;
|
phdr_base = (char *) buffer + ehdr->e_phoff;
|
||||||
#define phdr(i) ((Elf_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
|
#define phdr(i) ((Elf_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
|
||||||
|
|
||||||
for (i = 0; i < ehdr->e_phnum; i++)
|
|
||||||
if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
|
|
||||||
{
|
|
||||||
/* Beware that segment 0 isn't necessarily loadable */
|
|
||||||
if (lowest_segment == -1
|
|
||||||
|| phdr(i)->p_paddr < phdr(lowest_segment)->p_paddr)
|
|
||||||
lowest_segment = i;
|
|
||||||
if (highest_segment == -1
|
|
||||||
|| phdr(i)->p_paddr > phdr(highest_segment)->p_paddr)
|
|
||||||
highest_segment = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lowest_segment == -1)
|
|
||||||
return grub_error (GRUB_ERR_BAD_OS, "ELF contains no loadable segments");
|
|
||||||
|
|
||||||
code_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
|
|
||||||
grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr;
|
|
||||||
|
|
||||||
grub_multiboot_payload_size += code_size;
|
|
||||||
|
|
||||||
grub_multiboot_payload_orig
|
|
||||||
= grub_relocator32_alloc (grub_multiboot_payload_size);
|
|
||||||
|
|
||||||
if (!grub_multiboot_payload_orig)
|
|
||||||
return grub_errno;
|
|
||||||
|
|
||||||
/* Load every loadable segment in memory. */
|
/* Load every loadable segment in memory. */
|
||||||
for (i = 0; i < ehdr->e_phnum; i++)
|
for (i = 0; i < ehdr->e_phnum; i++)
|
||||||
{
|
{
|
||||||
if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
|
if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
|
||||||
{
|
{
|
||||||
char *load_this_module_at = (char *) (grub_multiboot_payload_orig + (long) (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr));
|
grub_err_t err;
|
||||||
|
void *source;
|
||||||
|
|
||||||
grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n",
|
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);
|
i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr);
|
||||||
|
|
||||||
|
err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator,
|
||||||
|
&source, phdr(i)->p_paddr,
|
||||||
|
phdr(i)->p_memsz);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
grub_dprintf ("multiboot_loader", "Error loading phdr %d\n", i);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
== (grub_off_t) -1)
|
||||||
return grub_error (GRUB_ERR_BAD_OS,
|
return grub_error (GRUB_ERR_BAD_OS,
|
||||||
"invalid offset in program header");
|
"invalid offset in program header");
|
||||||
|
|
||||||
if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz)
|
if (grub_file_read (file, source, phdr(i)->p_filesz)
|
||||||
!= (grub_ssize_t) phdr(i)->p_filesz)
|
!= (grub_ssize_t) phdr(i)->p_filesz)
|
||||||
return grub_error (GRUB_ERR_BAD_OS,
|
return grub_error (GRUB_ERR_BAD_OS,
|
||||||
"couldn't read segment from file");
|
"couldn't read segment from file");
|
||||||
|
|
||||||
if (phdr(i)->p_filesz < phdr(i)->p_memsz)
|
if (phdr(i)->p_filesz < phdr(i)->p_memsz)
|
||||||
grub_memset (load_this_module_at + phdr(i)->p_filesz, 0,
|
grub_memset ((grub_uint8_t *) source + phdr(i)->p_filesz, 0,
|
||||||
phdr(i)->p_memsz - phdr(i)->p_filesz);
|
phdr(i)->p_memsz - phdr(i)->p_filesz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,8 +121,8 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer)
|
||||||
if (phdr(i)->p_vaddr <= ehdr->e_entry
|
if (phdr(i)->p_vaddr <= ehdr->e_entry
|
||||||
&& phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry)
|
&& phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry)
|
||||||
{
|
{
|
||||||
grub_multiboot_payload_eip = grub_multiboot_payload_dest
|
grub_multiboot_payload_eip = (ehdr->e_entry - phdr(i)->p_vaddr)
|
||||||
+ (ehdr->e_entry - phdr(i)->p_vaddr) + (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr);
|
+ phdr(i)->p_paddr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue