summaryrefslogtreecommitdiff
path: root/util/cbfstool/rmodule.c
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2015-10-28 11:39:34 -0500
committerAaron Durbin <adurbin@chromium.org>2015-10-29 17:01:03 +0100
commit694fd133905ba6c87b2cef59b841660d1d82aeaa (patch)
tree754b2fb64a6502d398cb49d0c1149273caa6f40b /util/cbfstool/rmodule.c
parentcedcb882c1f0a2b9b61ffed9a646744d3e481e60 (diff)
downloadcoreboot-694fd133905ba6c87b2cef59b841660d1d82aeaa.tar.xz
cbfstool: extract rmodules as ELFs properly
With the previous ELF stage extract support the resulting ELF files wouldn't handle rmodules correctly in that the rmodule header as well as the relocations were a part of the program proper. Instead, try an initial pass at converting the stage as if it was an rmodule first. If it doesn't work fall back on the normal ELF extraction. TEST=Pulled an rmodule out of Chrome OS shellball. Manually matched up the metadata and relocations. Change-Id: Iaf222f92d145116ca4dfaa955fb7278e583161f2 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/12222 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Diffstat (limited to 'util/cbfstool/rmodule.c')
-rw-r--r--util/cbfstool/rmodule.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/util/cbfstool/rmodule.c b/util/cbfstool/rmodule.c
index 986ba623de..96c834f2c1 100644
--- a/util/cbfstool/rmodule.c
+++ b/util/cbfstool/rmodule.c
@@ -677,3 +677,173 @@ out:
rmodule_cleanup(&ctx);
return ret;
}
+
+static void rmod_deserialize(struct rmodule_header *rmod, struct buffer *buff,
+ struct xdr *xdr)
+{
+ rmod->magic = xdr->get16(buff);
+ rmod->version = xdr->get8(buff);
+ rmod->type = xdr->get8(buff);
+ rmod->payload_begin_offset = xdr->get32(buff);
+ rmod->payload_end_offset = xdr->get32(buff);
+ rmod->relocations_begin_offset = xdr->get32(buff);
+ rmod->relocations_end_offset = xdr->get32(buff);
+ rmod->module_link_start_address = xdr->get32(buff);
+ rmod->module_program_size = xdr->get32(buff);
+ rmod->module_entry_point = xdr->get32(buff);
+ rmod->parameters_begin = xdr->get32(buff);
+ rmod->parameters_end = xdr->get32(buff);
+ rmod->bss_begin = xdr->get32(buff);
+ rmod->bss_end = xdr->get32(buff);
+ rmod->padding[0] = xdr->get32(buff);
+ rmod->padding[1] = xdr->get32(buff);
+ rmod->padding[2] = xdr->get32(buff);
+ rmod->padding[3] = xdr->get32(buff);
+}
+
+int rmodule_stage_to_elf(Elf64_Ehdr *ehdr, struct buffer *buff)
+{
+ struct buffer reader;
+ struct buffer elf_out;
+ struct rmodule_header rmod;
+ struct xdr *xdr;
+ struct elf_writer *ew;
+ Elf64_Shdr shdr;
+ int bit64;
+ size_t payload_sz;
+ const char *section_name = ".program";
+ const size_t input_sz = buffer_size(buff);
+
+ buffer_clone(&reader, buff);
+
+ xdr = (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) ? &xdr_be : &xdr_le;
+ bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
+
+ rmod_deserialize(&rmod, &reader, xdr);
+
+ /* Indicate that file is not an rmodule if initial checks fail. */
+ if (rmod.magic != RMODULE_MAGIC)
+ return 1;
+ if (rmod.version != RMODULE_VERSION_1)
+ return 1;
+
+ if (rmod.payload_begin_offset > input_sz ||
+ rmod.payload_end_offset > input_sz ||
+ rmod.relocations_begin_offset > input_sz ||
+ rmod.relocations_end_offset > input_sz) {
+ ERROR("Rmodule fields out of bounds.\n");
+ return -1;
+ }
+
+ ehdr->e_entry = rmod.module_entry_point;
+ ew = elf_writer_init(ehdr);
+
+ if (ew == NULL)
+ return -1;
+
+ payload_sz = rmod.payload_end_offset - rmod.payload_begin_offset;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
+ shdr.sh_addr = rmod.module_link_start_address;
+ shdr.sh_size = payload_sz;
+ buffer_splice(&reader, buff, rmod.payload_begin_offset, payload_sz);
+
+ if (elf_writer_add_section(ew, &shdr, &reader, section_name)) {
+ ERROR("Unable to add ELF section: %s\n", section_name);
+ elf_writer_destroy(ew);
+ return -1;
+ }
+
+ if (payload_sz != rmod.module_program_size) {
+ struct buffer b;
+
+ buffer_init(&b, NULL, NULL, 0);
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_NOBITS;
+ shdr.sh_flags = SHF_WRITE | SHF_ALLOC;
+ shdr.sh_addr = rmod.module_link_start_address + payload_sz;
+ shdr.sh_size = rmod.module_program_size - payload_sz;
+ if (elf_writer_add_section(ew, &shdr, &b, ".empty")) {
+ ERROR("Unable to add ELF section: .empty\n");
+ elf_writer_destroy(ew);
+ return -1;
+ }
+ }
+
+ /* Provide a section symbol so the relcoations can reference that. */
+ if (elf_writer_add_symbol(ew, section_name, section_name, shdr.sh_addr,
+ 0, STB_LOCAL, STT_SECTION)) {
+ ERROR("Unable to add section symbol to ELF.\n");
+ elf_writer_destroy(ew);
+ return -1;
+ }
+
+ /* Add symbols for the parameters if they are non-zero. */
+ if (rmod.parameters_begin != rmod.parameters_end) {
+ int ret = 0;
+
+ ret |= elf_writer_add_symbol(ew, "_rmodule_params",
+ section_name,
+ rmod.parameters_begin, 0,
+ STB_GLOBAL, STT_NOTYPE);
+ ret |= elf_writer_add_symbol(ew, "_ermodule_params",
+ section_name,
+ rmod.parameters_end, 0,
+ STB_GLOBAL, STT_NOTYPE);
+
+ if (ret != 0) {
+ ERROR("Unable to add module params symbols to ELF\n");
+ elf_writer_destroy(ew);
+ return -1;
+ }
+ }
+
+ if (elf_writer_add_symbol(ew, "_bss", section_name, rmod.bss_begin, 0,
+ STB_GLOBAL, STT_NOTYPE) ||
+ elf_writer_add_symbol(ew, "_ebss", section_name, rmod.bss_end, 0,
+ STB_GLOBAL, STT_NOTYPE)) {
+ ERROR("Unable to add bss symbols to ELF\n");
+ elf_writer_destroy(ew);
+ return -1;
+ }
+
+ ssize_t relocs_sz = rmod.relocations_end_offset;
+ relocs_sz -= rmod.relocations_begin_offset;
+ buffer_splice(&reader, buff, rmod.relocations_begin_offset, relocs_sz);
+ while (relocs_sz > 0) {
+ Elf64_Addr addr;
+
+ if (bit64) {
+ relocs_sz -= sizeof(Elf64_Addr);
+ addr = xdr->get64(&reader);
+ } else {
+ relocs_sz -= sizeof(Elf32_Addr);
+ addr = xdr->get32(&reader);
+ }
+
+ /* Skip any relocations that are below the link address. */
+ if (addr < rmod.module_link_start_address)
+ continue;
+
+ if (elf_writer_add_rel(ew, section_name, addr)) {
+ ERROR("Relocation addition failure.\n");
+ elf_writer_destroy(ew);
+ return -1;
+ }
+ }
+
+ if (elf_writer_serialize(ew, &elf_out)) {
+ ERROR("ELF writer serialize failure.\n");
+ elf_writer_destroy(ew);
+ return -1;
+ }
+
+ elf_writer_destroy(ew);
+
+ /* Flip buffer with the created ELF one. */
+ buffer_delete(buff);
+ *buff = elf_out;
+
+ return 0;
+}