summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf Ertzinger <ralf@skytale.net>2008-10-20 18:35:36 +0200
committerH. Peter Anvin <hpa@zytor.com>2008-10-20 11:31:30 -0700
commit5691a17ee9243df2248a987a103c8b56b4ac268e (patch)
treed818905348da9167e29515ef2fc634b11022bf48
parent1626ee4b93762c0eba7047ef005cedda21440624 (diff)
downloadsyslinux-5691a17ee9243df2248a987a103c8b56b4ac268e.tar.gz
mboot.c: prefer ELF header over multiboot headersyslinux-3.73-pre6
If a loaded kernel is in ELF format and contains a multiboot header indicating valid relocation information, prefer the informations from the ELF header. This is in violation of the Multiboot spec, but it's the way GRUB does things and Solaris kernels rely on this behaviour. Signed-of-by: Ralf Ertzinger <ralf@skytale.net> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--com32/modules/mboot.c120
1 files changed, 57 insertions, 63 deletions
diff --git a/com32/modules/mboot.c b/com32/modules/mboot.c
index ad659d99..edcb88e6 100644
--- a/com32/modules/mboot.c
+++ b/com32/modules/mboot.c
@@ -582,71 +582,11 @@ static size_t load_kernel(struct multiboot_info *mbi, char *cmdline)
/* This kernel will do: figure out where all the pieces will live */
- if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) {
-
- /* Use the offsets in the multiboot header */
-#ifdef DEBUG
- printf("Using multiboot header.\n");
-#endif
-
- /* Where is the code in the loaded file? */
- seg_addr = ((char *)mbh) - (mbh->header_addr - mbh->load_addr);
-
- /* How much code is there? */
- run_addr = mbh->load_addr;
- if (mbh->load_end_addr != 0)
- seg_size = mbh->load_end_addr - mbh->load_addr;
- else
- seg_size = load_size - (seg_addr - load_addr);
-
- /* How much memory will it take up? */
- if (mbh->bss_end_addr != 0)
- run_size = mbh->bss_end_addr - mbh->load_addr;
- else
- run_size = seg_size;
-
- if (seg_size > run_size) {
- printf("Fatal: can't put %i bytes of kernel into %i bytes "
- "of memory.\n", seg_size, run_size);
- exit(1);
- }
- if (seg_addr + seg_size > load_addr + load_size) {
- printf("Fatal: multiboot load segment runs off the "
- "end of the file.\n");
- exit(1);
- }
-
- /* Does it fit where it wants to be? */
- place_kernel_section(run_addr, run_size);
+ /* Look for a bootable ELF32 header */
+ if ((load_size > sizeof(Elf32_Ehdr) &&
+ BOOTABLE_I386_ELF((*((Elf32_Ehdr *) load_addr))))) {
- /* Put it on the relocation list */
- if (seg_size < run_size) {
- /* Set up the kernel BSS too */
- if (seg_size > 0)
- add_section(run_addr, seg_addr, seg_size);
- bss_size = run_size - seg_size;
- add_section(run_addr + seg_size, NULL, bss_size);
- } else {
- /* No BSS */
- add_section(run_addr, seg_addr, run_size);
- }
-
- /* Done. */
- return mbh->entry_addr;
-
- } else {
-
- /* Now look for an ELF32 header */
ehdr = (Elf32_Ehdr *)load_addr;
- if (*(unsigned long *)ehdr != 0x464c457f
- || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
- || ehdr->e_ident[EI_CLASS] != ELFCLASS32
- || ehdr->e_machine != EM_386)
- {
- printf("Fatal: kernel has neither ELF32/x86 nor multiboot load"
- " headers.\n");
- exit(1);
- }
if (ehdr->e_phoff + ehdr->e_phnum*sizeof (*phdr) > load_size) {
printf("Fatal: malformed ELF header overruns EOF.\n");
exit(1);
@@ -760,6 +700,60 @@ static size_t load_kernel(struct multiboot_info *mbi, char *cmdline)
/* Done! */
return ehdr->e_entry;
+ } else
+
+ /* Does the MB header specify load addresses? */
+ if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) {
+
+ /* Use the offsets in the multiboot header */
+#ifdef DEBUG
+ printf("Using multiboot header.\n");
+#endif
+
+ /* Where is the code in the loaded file? */
+ seg_addr = ((char *)mbh) - (mbh->header_addr - mbh->load_addr);
+
+ /* How much code is there? */
+ run_addr = mbh->load_addr;
+ if (mbh->load_end_addr != 0)
+ seg_size = mbh->load_end_addr - mbh->load_addr;
+ else
+ seg_size = load_size - (seg_addr - load_addr);
+
+ /* How much memory will it take up? */
+ if (mbh->bss_end_addr != 0)
+ run_size = mbh->bss_end_addr - mbh->load_addr;
+ else
+ run_size = seg_size;
+
+ if (seg_size > run_size) {
+ printf("Fatal: can't put %i bytes of kernel into %i bytes "
+ "of memory.\n", seg_size, run_size);
+ exit(1);
+ }
+ if (seg_addr + seg_size > load_addr + load_size) {
+ printf("Fatal: multiboot load segment runs off the "
+ "end of the file.\n");
+ exit(1);
+ }
+
+ /* Does it fit where it wants to be? */
+ place_kernel_section(run_addr, run_size);
+
+ /* Put it on the relocation list */
+ if (seg_size < run_size) {
+ /* Set up the kernel BSS too */
+ if (seg_size > 0)
+ add_section(run_addr, seg_addr, seg_size);
+ bss_size = run_size - seg_size;
+ add_section(run_addr + seg_size, NULL, bss_size);
+ } else {
+ /* No BSS */
+ add_section(run_addr, seg_addr, run_size);
+ }
+
+ /* Done. */
+ return mbh->entry_addr;
}
}