123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680 |
- #include <grub/loader.h>
- #include <grub/i386/bsd.h>
- #include <grub/mm.h>
- #include <grub/elf.h>
- #include <grub/misc.h>
- #include <grub/i386/relocator.h>
- #include <grub/i18n.h>
- #define ALIGN_PAGE(a) ALIGN_UP (a, 4096)
- static inline grub_err_t
- load (grub_file_t file, const char *filename, void *where, grub_off_t off, grub_size_t size)
- {
- if (grub_file_seek (file, off) == (grub_off_t) -1)
- return grub_errno;
- if (grub_file_read (file, where, size) != (grub_ssize_t) size)
- {
- if (grub_errno)
- return grub_errno;
- return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- }
- return GRUB_ERR_NONE;
- }
- static inline grub_err_t
- read_headers (grub_file_t file, const char *filename, Elf_Ehdr *e, char **shdr)
- {
- if (grub_file_seek (file, 0) == (grub_off_t) -1)
- return grub_errno;
- if (grub_file_read (file, (char *) e, sizeof (*e)) != sizeof (*e))
- {
- if (grub_errno)
- return grub_errno;
- return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- }
- if (e->e_ident[EI_MAG0] != ELFMAG0
- || e->e_ident[EI_MAG1] != ELFMAG1
- || e->e_ident[EI_MAG2] != ELFMAG2
- || e->e_ident[EI_MAG3] != ELFMAG3
- || e->e_ident[EI_VERSION] != EV_CURRENT
- || e->e_version != EV_CURRENT)
- return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
- if (e->e_ident[EI_CLASS] != SUFFIX (ELFCLASS))
- return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
- *shdr = grub_malloc ((grub_uint32_t) e->e_shnum * e->e_shentsize);
- if (! *shdr)
- return grub_errno;
- if (grub_file_seek (file, e->e_shoff) == (grub_off_t) -1)
- return grub_errno;
- if (grub_file_read (file, *shdr, (grub_uint32_t) e->e_shnum * e->e_shentsize)
- != (grub_ssize_t) ((grub_uint32_t) e->e_shnum * e->e_shentsize))
- {
- if (grub_errno)
- return grub_errno;
- return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- }
- return GRUB_ERR_NONE;
- }
- /* On i386 FreeBSD uses "elf module" approarch for 32-bit variant
- and "elf obj module" for 64-bit variant. However it may differ on other
- platforms. So I keep both versions. */
- #if OBJSYM
- grub_err_t
- SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator,
- grub_file_t file, int argc,
- char *argv[], grub_addr_t *kern_end)
- {
- Elf_Ehdr e;
- Elf_Shdr *s;
- char *shdr = 0;
- grub_addr_t curload, module;
- grub_err_t err;
- grub_size_t chunk_size = 0;
- void *chunk_src;
- curload = module = ALIGN_PAGE (*kern_end);
- err = read_headers (file, argv[0], &e, &shdr);
- if (err)
- goto out;
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- {
- if (s->sh_size == 0)
- continue;
- if (s->sh_addralign)
- chunk_size = ALIGN_UP (chunk_size + *kern_end, s->sh_addralign)
- - *kern_end;
- chunk_size += s->sh_size;
- }
- {
- grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- module, chunk_size);
- if (err)
- goto out;
- chunk_src = get_virtual_current_address (ch);
- }
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- {
- if (s->sh_size == 0)
- continue;
- if (s->sh_addralign)
- curload = ALIGN_UP (curload, s->sh_addralign);
- s->sh_addr = curload;
- grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
- (unsigned) curload, (int) s->sh_size,
- (int) s->sh_addralign);
- switch (s->sh_type)
- {
- default:
- case SHT_PROGBITS:
- err = load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end,
- s->sh_offset, s->sh_size);
- if (err)
- goto out;
- break;
- case SHT_NOBITS:
- grub_memset ((grub_uint8_t *) chunk_src + curload - *kern_end, 0,
- s->sh_size);
- break;
- }
- curload += s->sh_size;
- }
- *kern_end = ALIGN_PAGE (curload);
- err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ,
- argc - 1, argv + 1, module,
- curload - module);
- if (! err)
- err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
- | FREEBSD_MODINFOMD_ELFHDR,
- &e, sizeof (e));
- if (! err)
- err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
- | FREEBSD_MODINFOMD_SHDR,
- shdr, e.e_shnum * e.e_shentsize);
- out:
- grub_free (shdr);
- return err;
- }
- #else
- grub_err_t
- SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator,
- grub_file_t file, int argc, char *argv[],
- grub_addr_t *kern_end)
- {
- Elf_Ehdr e;
- Elf_Shdr *s;
- char *shdr = 0;
- grub_addr_t curload, module;
- grub_err_t err;
- grub_size_t chunk_size = 0;
- void *chunk_src;
- curload = module = ALIGN_PAGE (*kern_end);
- err = read_headers (file, argv[0], &e, &shdr);
- if (err)
- goto out;
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- {
- if (s->sh_size == 0)
- continue;
- if (! (s->sh_flags & SHF_ALLOC))
- continue;
- if (chunk_size < s->sh_addr + s->sh_size)
- chunk_size = s->sh_addr + s->sh_size;
- }
- if (chunk_size < sizeof (e))
- chunk_size = sizeof (e);
- chunk_size += (grub_uint32_t) e.e_phnum * e.e_phentsize;
- chunk_size += (grub_uint32_t) e.e_shnum * e.e_shentsize;
- {
- grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- module, chunk_size);
- if (err)
- goto out;
- chunk_src = get_virtual_current_address (ch);
- }
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- {
- if (s->sh_size == 0)
- continue;
- if (! (s->sh_flags & SHF_ALLOC))
- continue;
- grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
- (unsigned) curload, (int) s->sh_size,
- (int) s->sh_addralign);
- switch (s->sh_type)
- {
- default:
- case SHT_PROGBITS:
- err = load (file, argv[0],
- (grub_uint8_t *) chunk_src + module
- + s->sh_addr - *kern_end,
- s->sh_offset, s->sh_size);
- if (err)
- goto out;
- break;
- case SHT_NOBITS:
- grub_memset ((grub_uint8_t *) chunk_src + module
- + s->sh_addr - *kern_end, 0, s->sh_size);
- break;
- }
- if (curload < module + s->sh_addr + s->sh_size)
- curload = module + s->sh_addr + s->sh_size;
- }
- load (file, argv[0], (grub_uint8_t *) chunk_src + module - *kern_end, 0, sizeof (e));
- if (curload < module + sizeof (e))
- curload = module + sizeof (e);
- load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end, e.e_shoff,
- (grub_uint32_t) e.e_shnum * e.e_shentsize);
- e.e_shoff = curload - module;
- curload += (grub_uint32_t) e.e_shnum * e.e_shentsize;
- load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end, e.e_phoff,
- (grub_uint32_t) e.e_phnum * e.e_phentsize);
- e.e_phoff = curload - module;
- curload += (grub_uint32_t) e.e_phnum * e.e_phentsize;
- *kern_end = curload;
- grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
- argc - 1, argv + 1, module,
- curload - module);
- out:
- grub_free (shdr);
- if (err)
- return err;
- return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, argv[0], kern_end);
- }
- #endif
- grub_err_t
- SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator,
- grub_file_t file,
- const char *filename,
- grub_addr_t *kern_end)
- {
- grub_err_t err;
- Elf_Ehdr e;
- Elf_Shdr *s;
- char *shdr = 0;
- unsigned symoff, stroff, symsize, strsize;
- grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
- Elf_Sym *sym;
- void *sym_chunk;
- grub_uint8_t *curload;
- grub_freebsd_addr_t symtarget;
- const char *str;
- unsigned i;
- grub_size_t chunk_size;
- err = read_headers (file, filename, &e, &shdr);
- if (err)
- goto out;
- err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
- FREEBSD_MODINFOMD_ELFHDR, &e,
- sizeof (e));
- if (err)
- goto out;
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- if (s->sh_type == SHT_SYMTAB)
- break;
- if (s >= (Elf_Shdr *) ((char *) shdr
- + e.e_shnum * e.e_shentsize))
- {
- err = grub_error (GRUB_ERR_BAD_OS, N_("no symbol table"));
- goto out;
- }
- symoff = s->sh_offset;
- symsize = s->sh_size;
- symentsize = s->sh_entsize;
- s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
- stroff = s->sh_offset;
- strsize = s->sh_size;
- chunk_size = ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t))
- + 2 * sizeof (grub_freebsd_addr_t);
- symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
- {
- grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- symtarget, chunk_size);
- if (err)
- goto out;
- sym_chunk = get_virtual_current_address (ch);
- }
- symstart = symtarget;
- symend = symstart + chunk_size;
- curload = sym_chunk;
- *((grub_freebsd_addr_t *) curload) = symsize;
- curload += sizeof (grub_freebsd_addr_t);
- if (grub_file_seek (file, symoff) == (grub_off_t) -1)
- {
- err = grub_errno;
- goto out;
- }
- sym = (Elf_Sym *) curload;
- if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
- {
- if (! grub_errno)
- err = grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- else
- err = grub_errno;
- goto out;
- }
- curload += symsize;
- *((grub_freebsd_addr_t *) curload) = strsize;
- curload += sizeof (grub_freebsd_addr_t);
- if (grub_file_seek (file, stroff) == (grub_off_t) -1)
- {
- err = grub_errno;
- goto out;
- }
- str = (char *) curload;
- if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
- {
- if (! grub_errno)
- err = grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- else
- err = grub_errno;
- goto out;
- }
- for (i = 0;
- i * symentsize < symsize;
- i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
- {
- const char *name = str + sym->st_name;
- if (grub_strcmp (name, "_DYNAMIC") == 0)
- break;
- }
- if (i * symentsize < symsize)
- {
- dynamic = sym->st_value;
- grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic);
- err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
- FREEBSD_MODINFOMD_DYNAMIC, &dynamic,
- sizeof (dynamic));
- if (err)
- goto out;
- }
- err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
- FREEBSD_MODINFOMD_SSYM, &symstart,
- sizeof (symstart));
- if (err)
- goto out;
- err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
- FREEBSD_MODINFOMD_ESYM, &symend,
- sizeof (symend));
- out:
- grub_free (shdr);
- if (err)
- return err;
- *kern_end = ALIGN_PAGE (symend);
- return GRUB_ERR_NONE;
- }
- grub_err_t
- SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator,
- grub_file_t file, const char *filename,
- grub_addr_t *kern_end)
- {
- grub_err_t err;
- Elf_Ehdr e;
- Elf_Shdr *s, *symsh, *strsh;
- char *shdr = NULL;
- unsigned symsize, strsize;
- void *sym_chunk;
- grub_uint8_t *curload;
- grub_size_t chunk_size;
- Elf_Ehdr *e2;
- struct grub_netbsd_btinfo_symtab symtab;
- grub_addr_t symtarget;
- err = read_headers (file, filename, &e, &shdr);
- if (err)
- {
- grub_free (shdr);
- return grub_errno;
- }
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- if (s->sh_type == SHT_SYMTAB)
- break;
- if (s >= (Elf_Shdr *) ((char *) shdr
- + e.e_shnum * e.e_shentsize))
- {
- grub_free (shdr);
- return GRUB_ERR_NONE;
- }
- symsize = s->sh_size;
- symsh = s;
- s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
- strsize = s->sh_size;
- strsh = s;
- chunk_size = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t))
- + ALIGN_UP (strsize, sizeof (grub_freebsd_addr_t))
- + sizeof (e) + (grub_uint32_t) e.e_shnum * e.e_shentsize;
- symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
- {
- grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- symtarget, chunk_size);
- if (err)
- goto out;
- sym_chunk = get_virtual_current_address (ch);
- }
- symtab.nsyms = 1;
- symtab.ssyms = symtarget;
- symtab.esyms = symtarget + chunk_size;
- curload = sym_chunk;
-
- e2 = (Elf_Ehdr *) curload;
- grub_memcpy (curload, &e, sizeof (e));
- e2->e_phoff = 0;
- e2->e_phnum = 0;
- e2->e_phentsize = 0;
- e2->e_shstrndx = 0;
- e2->e_shoff = sizeof (e);
- curload += sizeof (e);
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- {
- Elf_Shdr *s2;
- s2 = (Elf_Shdr *) curload;
- grub_memcpy (curload, s, e.e_shentsize);
- if (s == symsh)
- s2->sh_offset = sizeof (e) + (grub_uint32_t) e.e_shnum * e.e_shentsize;
- else if (s == strsh)
- s2->sh_offset = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t))
- + sizeof (e) + (grub_uint32_t) e.e_shnum * e.e_shentsize;
- else
- s2->sh_offset = 0;
- s2->sh_addr = s2->sh_offset;
- curload += e.e_shentsize;
- }
- if (grub_file_seek (file, symsh->sh_offset) == (grub_off_t) -1)
- {
- err = grub_errno;
- goto out;
- }
- if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
- {
- if (! grub_errno)
- err = grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- else
- err = grub_errno;
- goto out;
- }
- curload += ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t));
- if (grub_file_seek (file, strsh->sh_offset) == (grub_off_t) -1)
- {
- err = grub_errno;
- goto out;
- }
- if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
- {
- if (! grub_errno)
- err = grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- else
- err = grub_errno;
- goto out;
- }
- err = grub_bsd_add_meta (NETBSD_BTINFO_SYMTAB,
- &symtab,
- sizeof (symtab));
- out:
- grub_free (shdr);
- if (err)
- return err;
- *kern_end = ALIGN_PAGE (symtarget + chunk_size);
- return GRUB_ERR_NONE;
- }
- grub_err_t
- SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file,
- const char *filename,
- grub_addr_t kern_start,
- void *kern_chunk_src,
- struct grub_openbsd_ramdisk_descriptor *desc)
- {
- unsigned symoff, stroff, symsize, strsize, symentsize;
- {
- grub_err_t err;
- Elf_Ehdr e;
- Elf_Shdr *s;
- char *shdr = NULL;
-
- err = read_headers (file, filename, &e, &shdr);
- if (err)
- {
- grub_free (shdr);
- return err;
- }
- for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
- + e.e_shnum * e.e_shentsize);
- s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
- if (s->sh_type == SHT_SYMTAB)
- break;
- if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize))
- {
- grub_free (shdr);
- return GRUB_ERR_NONE;
- }
- symsize = s->sh_size;
- symentsize = s->sh_entsize;
- symoff = s->sh_offset;
-
- s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
- stroff = s->sh_offset;
- strsize = s->sh_size;
- grub_free (shdr);
- }
- {
- Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL;
- unsigned i;
- char *strs;
- syms = grub_malloc (symsize);
- if (!syms)
- return grub_errno;
- if (grub_file_seek (file, symoff) == (grub_off_t) -1)
- {
- grub_free (syms);
- return grub_errno;
- }
- if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize)
- {
- grub_free (syms);
- if (! grub_errno)
- return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- return grub_errno;
- }
- strs = grub_malloc (strsize);
- if (!strs)
- {
- grub_free (syms);
- return grub_errno;
- }
- if (grub_file_seek (file, stroff) == (grub_off_t) -1)
- {
- grub_free (syms);
- grub_free (strs);
- return grub_errno;
- }
- if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize)
- {
- grub_free (syms);
- grub_free (strs);
- if (! grub_errno)
- return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- filename);
- return grub_errno;
- }
- for (i = 0, sym = syms; i * symentsize < symsize;
- i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
- {
- if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT)
- continue;
- if (!sym->st_name)
- continue;
- if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0)
- imagesym = sym;
- if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0)
- sizesym = sym;
- if (imagesym && sizesym)
- break;
- }
- if (!imagesym || !sizesym)
- {
- grub_free (syms);
- grub_free (strs);
- return GRUB_ERR_NONE;
- }
- if (sizeof (*desc->size) != sizesym->st_size)
- {
- grub_free (syms);
- grub_free (strs);
- return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size");
- }
- desc->max_size = imagesym->st_size;
- desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start
- + (grub_uint8_t *) kern_chunk_src;
- desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start
- + (grub_uint8_t *) kern_chunk_src);
- grub_free (syms);
- grub_free (strs);
- return GRUB_ERR_NONE;
- }
- }
|