[coreboot-gerrit] Patch set updated for coreboot: cbfstool: extract rmodules as ELFs properly

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Wed Oct 28 18:57:55 CET 2015


Aaron Durbin (adurbin at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/12222

-gerrit

commit 0162209a8aaa02269450d456b43b7de0cec8a4d7
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Wed Oct 28 11:39:34 2015 -0500

    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 at chromium.org>
---
 util/cbfstool/cbfs_image.c |  13 ++++
 util/cbfstool/rmodule.c    | 170 +++++++++++++++++++++++++++++++++++++++++++++
 util/cbfstool/rmodule.h    |   7 ++
 3 files changed, 190 insertions(+)

diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index bd432d4..c23a6e8 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -28,6 +28,7 @@
 #include "common.h"
 #include "cbfs_image.h"
 #include "elfparsing.h"
+#include "rmodule.h"
 
 /* Even though the file-adding functions---cbfs_add_entry() and
  * cbfs_add_entry_at()---perform their sizing checks against the beginning of
@@ -770,6 +771,7 @@ static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch)
 	struct elf_writer *ew;
 	struct buffer elf_out;
 	size_t empty_sz;
+	int rmod_ret;
 
 	if (cbfs_stage_decompress(&stage, buff)) {
 		ERROR("Failed to decompress stage.\n");
@@ -781,6 +783,17 @@ static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch)
 
 	ehdr.e_entry = stage.entry;
 
+	/* Attempt rmodule translation first. */
+	rmod_ret = rmodule_stage_to_elf(&ehdr, buff);
+
+	if (rmod_ret < 0) {
+		ERROR("rmodule parsing failed\n");
+		return -1;
+	} else if (rmod_ret == 0)
+		return 0;
+
+	/* Rmodule couldn't do anything with the data. Continue on with SELF. */
+
 	ew = elf_writer_init(&ehdr);
 	if (ew == NULL) {
 		ERROR("Unable to init ELF writer.\n");
diff --git a/util/cbfstool/rmodule.c b/util/cbfstool/rmodule.c
index 986ba62..96c834f 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;
+}
diff --git a/util/cbfstool/rmodule.h b/util/cbfstool/rmodule.h
index 9a65677..fa71765 100644
--- a/util/cbfstool/rmodule.h
+++ b/util/cbfstool/rmodule.h
@@ -88,4 +88,11 @@ int rmodule_collect_relocations(struct rmod_context *c, struct reloc_filter *f);
 /* Clean up the memory consumed by the rmdoule context. */
 void rmodule_cleanup(struct rmod_context *ctx);
 
+/*
+ * Create an ELF file from the passed in rmodule in the buffer. The buffer
+ * contents will be replaced with an ELF file. Returns 1 if buff doesn't
+ * contain an rmodule and < 0 on failure, 0 on success.
+ */
+int rmodule_stage_to_elf(Elf64_Ehdr *ehdr, struct buffer *buff);
+
 #endif /* TOOL_RMODULE_H */



More information about the coreboot-gerrit mailing list