2008-08-12 Robert Millan <rmh@aybabtu.com>
* loader/i386/pc/multiboot.c (grub_multiboot_load_elf32): Move part of the relocation code from here ... (grub_multiboot): ... to here. (forward_relocator, backward_relocator): Move from here ... * kern/i386/loader.S (grub_multiboot_forward_relocator) (grub_multiboot_backward_relocator): ... to here. (grub_multiboot_real_boot): Use %edx for entry offset. Put Multiboot magic in %eax. Use %ebp for jumping (so %edx is not trashed). * include/grub/i386/loader.h (grub_multiboot_forward_relocator) (grub_multiboot_forward_relocator_end) (grub_multiboot_backward_relocator) (grub_multiboot_backward_relocator_end): New variables.
This commit is contained in:
parent
05f9452b12
commit
371458b576
4 changed files with 113 additions and 56 deletions
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
2008-08-12 Robert Millan <rmh@aybabtu.com>
|
||||||
|
|
||||||
|
* loader/i386/pc/multiboot.c (grub_multiboot_load_elf32): Move part
|
||||||
|
of the relocation code from here ...
|
||||||
|
(grub_multiboot): ... to here.
|
||||||
|
(forward_relocator, backward_relocator): Move from here ...
|
||||||
|
* kern/i386/loader.S (grub_multiboot_forward_relocator)
|
||||||
|
(grub_multiboot_backward_relocator): ... to here.
|
||||||
|
(grub_multiboot_real_boot): Use %edx for entry offset. Put Multiboot
|
||||||
|
magic in %eax. Use %ebp for jumping (so %edx is not trashed).
|
||||||
|
* include/grub/i386/loader.h (grub_multiboot_forward_relocator)
|
||||||
|
(grub_multiboot_forward_relocator_end)
|
||||||
|
(grub_multiboot_backward_relocator)
|
||||||
|
(grub_multiboot_backward_relocator_end): New variables.
|
||||||
|
|
||||||
2008-08-12 Bean <bean123ch@gmail.com>
|
2008-08-12 Bean <bean123ch@gmail.com>
|
||||||
|
|
||||||
* disk/raid.c (grub_raid_read): Fix a bug in raid0 code.
|
* disk/raid.c (grub_raid_read): Fix a bug in raid0 code.
|
||||||
|
|
|
@ -53,4 +53,11 @@ extern grub_uint32_t EXPORT_VAR(grub_multiboot_payload_entry_offset);
|
||||||
void grub_rescue_cmd_linux (int argc, char *argv[]);
|
void grub_rescue_cmd_linux (int argc, char *argv[]);
|
||||||
void grub_rescue_cmd_initrd (int argc, char *argv[]);
|
void grub_rescue_cmd_initrd (int argc, char *argv[]);
|
||||||
|
|
||||||
|
extern grub_uint8_t EXPORT_VAR(grub_multiboot_forward_relocator);
|
||||||
|
extern grub_uint8_t EXPORT_VAR(grub_multiboot_forward_relocator_end);
|
||||||
|
extern grub_uint8_t EXPORT_VAR(grub_multiboot_backward_relocator);
|
||||||
|
extern grub_uint8_t EXPORT_VAR(grub_multiboot_backward_relocator_end);
|
||||||
|
|
||||||
|
#define RELOCATOR_SIZEOF(x) (&grub_multiboot_##x##_relocator_end - &grub_multiboot_##x##_relocator)
|
||||||
|
|
||||||
#endif /* ! GRUB_LOADER_CPU_HEADER */
|
#endif /* ! GRUB_LOADER_CPU_HEADER */
|
||||||
|
|
|
@ -132,6 +132,36 @@ VARIABLE(grub_multiboot_payload_dest)
|
||||||
VARIABLE(grub_multiboot_payload_entry_offset)
|
VARIABLE(grub_multiboot_payload_entry_offset)
|
||||||
.long 0
|
.long 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The relocators below understand the following parameters:
|
||||||
|
* ecx: Size of the block to be copied.
|
||||||
|
* esi: Where to copy from (always lowest address, even if we're relocating
|
||||||
|
* backwards).
|
||||||
|
* edi: Where to copy to (likewise).
|
||||||
|
* edx: Offset of the entry point (relative to the beginning of the block).
|
||||||
|
*/
|
||||||
|
VARIABLE(grub_multiboot_forward_relocator)
|
||||||
|
cld
|
||||||
|
addl %edi, %edx
|
||||||
|
rep
|
||||||
|
movsb
|
||||||
|
jmp *%edx
|
||||||
|
VARIABLE(grub_multiboot_forward_relocator_end)
|
||||||
|
|
||||||
|
VARIABLE(grub_multiboot_backward_relocator)
|
||||||
|
std
|
||||||
|
addl %ecx, %esi
|
||||||
|
addl %ecx, %edi
|
||||||
|
/* backward movsb is implicitly off-by-one. compensate that. */
|
||||||
|
incl %ecx
|
||||||
|
rep
|
||||||
|
movsb
|
||||||
|
/* same problem again. */
|
||||||
|
incl %edi
|
||||||
|
addl %edi, %edx
|
||||||
|
jmp *%edx
|
||||||
|
VARIABLE(grub_multiboot_backward_relocator_end)
|
||||||
|
|
||||||
FUNCTION(grub_multiboot_real_boot)
|
FUNCTION(grub_multiboot_real_boot)
|
||||||
/* Push the entry address on the stack. */
|
/* Push the entry address on the stack. */
|
||||||
pushl %eax
|
pushl %eax
|
||||||
|
@ -149,11 +179,14 @@ FUNCTION(grub_multiboot_real_boot)
|
||||||
movl EXT_C(grub_multiboot_payload_size), %ecx
|
movl EXT_C(grub_multiboot_payload_size), %ecx
|
||||||
movl EXT_C(grub_multiboot_payload_orig), %esi
|
movl EXT_C(grub_multiboot_payload_orig), %esi
|
||||||
movl EXT_C(grub_multiboot_payload_dest), %edi
|
movl EXT_C(grub_multiboot_payload_dest), %edi
|
||||||
movl EXT_C(grub_multiboot_payload_entry_offset), %eax
|
movl EXT_C(grub_multiboot_payload_entry_offset), %edx
|
||||||
|
|
||||||
|
/* Move the magic value into eax. */
|
||||||
|
movl $MULTIBOOT_MAGIC2, %eax
|
||||||
|
|
||||||
/* Jump to the relocator. */
|
/* Jump to the relocator. */
|
||||||
popl %edx
|
popl %ebp
|
||||||
jmp *%edx
|
jmp *%ebp
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This starts the multiboot 2 kernel.
|
* This starts the multiboot 2 kernel.
|
||||||
|
|
|
@ -52,31 +52,6 @@ static grub_addr_t entry;
|
||||||
|
|
||||||
static char *playground = NULL;
|
static char *playground = NULL;
|
||||||
|
|
||||||
static grub_uint8_t forward_relocator[] =
|
|
||||||
{
|
|
||||||
0xfc, /* cld */
|
|
||||||
0x89, 0xf2, /* movl %esi, %edx */
|
|
||||||
0xf3, 0xa4, /* rep movsb */
|
|
||||||
0x01, 0xc2, /* addl %eax, %edx */
|
|
||||||
0xb8, 0x02, 0xb0, 0xad, 0x2b, /* movl $MULTIBOOT_MAGIC2, %eax */
|
|
||||||
0xff, 0xe2, /* jmp *%edx */
|
|
||||||
};
|
|
||||||
|
|
||||||
static grub_uint8_t backward_relocator[] =
|
|
||||||
{
|
|
||||||
0xfd, /* std */
|
|
||||||
0x01, 0xce, /* addl %ecx, %esi */
|
|
||||||
0x01, 0xcf, /* addl %ecx, %edi */
|
|
||||||
/* backward movsb is implicitly off-by-one. compensate that. */
|
|
||||||
0x41, /* incl %ecx */
|
|
||||||
0xf3, 0xa4, /* rep movsb */
|
|
||||||
/* same problem again. */
|
|
||||||
0x47, /* incl %edi */
|
|
||||||
0x01, 0xc7, /* addl %eax, %edi */
|
|
||||||
0xb8, 0x02, 0xb0, 0xad, 0x2b, /* movl $MULTIBOOT_MAGIC2, %eax */
|
|
||||||
0xff, 0xe7, /* jmp *%edi */
|
|
||||||
};
|
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_multiboot_boot (void)
|
grub_multiboot_boot (void)
|
||||||
{
|
{
|
||||||
|
@ -155,16 +130,11 @@ grub_multiboot_load_elf32 (grub_file_t file, void *buffer)
|
||||||
grub_multiboot_payload_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
|
grub_multiboot_payload_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_dest = phdr(lowest_segment)->p_paddr;
|
||||||
|
|
||||||
if (playground)
|
playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward));
|
||||||
grub_free (playground);
|
|
||||||
playground = grub_malloc (sizeof (forward_relocator) + grub_multiboot_payload_size + sizeof (backward_relocator));
|
|
||||||
if (! playground)
|
if (! playground)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
||||||
grub_multiboot_payload_orig = (long) playground + sizeof (forward_relocator);
|
grub_multiboot_payload_orig = (long) playground + RELOCATOR_SIZEOF(forward);
|
||||||
|
|
||||||
grub_memmove (playground, forward_relocator, sizeof (forward_relocator));
|
|
||||||
grub_memmove ((char *) (grub_multiboot_payload_orig + grub_multiboot_payload_size), backward_relocator, sizeof (backward_relocator));
|
|
||||||
|
|
||||||
/* 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++)
|
||||||
|
@ -196,16 +166,6 @@ grub_multiboot_load_elf32 (grub_file_t file, void *buffer)
|
||||||
|
|
||||||
#undef phdr
|
#undef phdr
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
grub_dprintf ("multiboot_loader", "dest=%p, size=0x%x, entry_offset=0x%x\n",
|
|
||||||
(void *) grub_multiboot_payload_dest,
|
|
||||||
grub_multiboot_payload_size,
|
|
||||||
grub_multiboot_payload_entry_offset);
|
|
||||||
|
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,24 +373,66 @@ grub_multiboot (int argc, char *argv[])
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (playground)
|
||||||
|
{
|
||||||
|
grub_free (playground);
|
||||||
|
playground = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (header->flags & MULTIBOOT_AOUT_KLUDGE)
|
if (header->flags & MULTIBOOT_AOUT_KLUDGE)
|
||||||
{
|
{
|
||||||
int ofs;
|
int offset = ((char *) header - buffer -
|
||||||
|
(header->header_addr - header->load_addr));
|
||||||
|
int load_size = ((header->load_end_addr == 0) ? file->size - offset :
|
||||||
|
header->load_end_addr - header->load_addr);
|
||||||
|
|
||||||
ofs = (char *) header - buffer -
|
if (header->bss_end_addr)
|
||||||
(header->header_addr - header->load_addr);
|
grub_multiboot_payload_size = (header->bss_end_addr - header->load_addr);
|
||||||
if ((grub_aout_load (file, ofs, header->load_addr,
|
else
|
||||||
((header->load_end_addr == 0) ? 0 :
|
grub_multiboot_payload_size = load_size;
|
||||||
header->load_end_addr - header->load_addr),
|
grub_multiboot_payload_dest = header->load_addr;
|
||||||
header->bss_end_addr))
|
|
||||||
!=GRUB_ERR_NONE)
|
playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward));
|
||||||
|
if (! playground)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
entry = header->entry_addr;
|
grub_multiboot_payload_orig = (long) playground + RELOCATOR_SIZEOF(forward);
|
||||||
|
|
||||||
|
if ((grub_file_seek (file, offset)) == (grub_off_t) - 1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
grub_file_read (file, grub_multiboot_payload_orig, load_size);
|
||||||
|
if (grub_errno)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (header->bss_end_addr)
|
||||||
|
grub_memset (grub_multiboot_payload_orig + load_size, 0,
|
||||||
|
header->bss_end_addr - header->load_addr - load_size);
|
||||||
|
|
||||||
|
grub_multiboot_payload_entry_offset = header->entry_addr - header->load_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;
|
||||||
|
|
||||||
|
|
||||||
|
if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig)
|
||||||
|
{
|
||||||
|
grub_memmove (playground, &grub_multiboot_forward_relocator, RELOCATOR_SIZEOF(forward));
|
||||||
|
entry = (grub_addr_t) playground;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
grub_memmove ((char *) (grub_multiboot_payload_orig + grub_multiboot_payload_size),
|
||||||
|
&grub_multiboot_backward_relocator, RELOCATOR_SIZEOF(backward));
|
||||||
|
entry = (grub_addr_t) grub_multiboot_payload_orig + grub_multiboot_payload_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
grub_dprintf ("multiboot_loader", "dest=%p, size=0x%x, entry_offset=0x%x\n",
|
||||||
|
(void *) grub_multiboot_payload_dest,
|
||||||
|
grub_multiboot_payload_size,
|
||||||
|
grub_multiboot_payload_entry_offset);
|
||||||
|
|
||||||
mbi = grub_malloc (sizeof (struct grub_multiboot_info));
|
mbi = grub_malloc (sizeof (struct grub_multiboot_info));
|
||||||
if (! mbi)
|
if (! mbi)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
Loading…
Reference in a new issue