[coreboot-gerrit] Patch set updated for coreboot: cbfstool: create ELF files when extracting stages

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Wed Oct 28 18:58:00 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/12219

-gerrit

commit 2d67588cbde66f409539c52abbe9544573057e52
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Tue Oct 27 21:02:30 2015 -0500

    cbfstool: create ELF files when extracting stages
    
    Instead of dumping the raw stage data when cbfstool
    extract is used on stage create an equivalent ELF file.
    Because there isn't a lot of information within a stage
    file only a rudimentary ELF can be created.
    
    Note: this will break Chrome OS' current usage of extract
    since the file is no longer a cbfs_stage. It's an ELF file.
    
    TEST=Extracted romstage from rom.
    
    Change-Id: I8d24a7fa4c5717e4bbba5963139d0d9af4ef8f52
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 util/cbfstool/cbfs_image.c | 173 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 137 insertions(+), 36 deletions(-)

diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 245230a..bd432d4 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -27,6 +27,7 @@
 
 #include "common.h"
 #include "cbfs_image.h"
+#include "elfparsing.h"
 
 /* Even though the file-adding functions---cbfs_add_entry() and
  * cbfs_add_entry_at()---perform their sizing checks against the beginning of
@@ -657,11 +658,9 @@ struct cbfs_file *cbfs_get_entry(struct cbfs_image *image, const char *name)
 	return NULL;
 }
 
-static int cbfs_stage_decompress(struct buffer *buff)
+static int cbfs_stage_decompress(struct cbfs_stage *stage, struct buffer *buff)
 {
 	struct buffer reader;
-	struct buffer writer;
-	struct cbfs_stage metadata;
 	char *orig_buffer;
 	char *new_buffer;
 	size_t new_buff_sz;
@@ -670,16 +669,27 @@ static int cbfs_stage_decompress(struct buffer *buff)
 	buffer_clone(&reader, buff);
 
 	/* The stage metadata is in little endian. */
-	metadata.compression = xdr_le.get32(&reader);
-	metadata.entry = xdr_le.get64(&reader);
-	metadata.load = xdr_le.get64(&reader);
-	metadata.len = xdr_le.get32(&reader);
-	metadata.memlen = xdr_le.get32(&reader);
-
-	if (metadata.compression == CBFS_COMPRESS_NONE)
+	stage->compression = xdr_le.get32(&reader);
+	stage->entry = xdr_le.get64(&reader);
+	stage->load = xdr_le.get64(&reader);
+	stage->len = xdr_le.get32(&reader);
+	stage->memlen = xdr_le.get32(&reader);
+
+	/* Create a buffer just with the uncompressed program now that the
+	 * struct cbfs_stage has been peeled off. */
+	if (stage->compression == CBFS_COMPRESS_NONE) {
+		new_buff_sz = buffer_size(buff) - sizeof(struct cbfs_stage);
+
+		orig_buffer = buffer_get(buff);
+		new_buffer = calloc(1, new_buff_sz);
+		memcpy(new_buffer, orig_buffer + sizeof(struct cbfs_stage),
+			new_buff_sz);
+		buffer_init(buff, buff->name, new_buffer, new_buff_sz);
+		free(orig_buffer);
 		return 0;
+	}
 
-	decompress = decompression_function(metadata.compression);
+	decompress = decompression_function(stage->compression);
 	if (decompress == NULL)
 		return -1;
 
@@ -687,45 +697,142 @@ static int cbfs_stage_decompress(struct buffer *buff)
 
 	/* This can be too big of a buffer needed, but there's no current
 	 * field indicating decompressed size of data. */
-	new_buff_sz = metadata.memlen + sizeof(struct cbfs_stage);
+	new_buff_sz = stage->memlen;
 	new_buffer = calloc(1, new_buff_sz);
 
 	if (decompress(orig_buffer + sizeof(struct cbfs_stage),
 			(int)(buffer_size(buff) - sizeof(struct cbfs_stage)),
-			new_buffer + sizeof(struct cbfs_stage),
-			(int)(new_buff_sz - sizeof(struct cbfs_stage)),
-			&new_buff_sz)) {
+			new_buffer, (int)new_buff_sz, &new_buff_sz)) {
 		ERROR("Couldn't decompress stage.\n");
 		free(new_buffer);
 		return -1;
 	}
 
 	/* Include correct size for full stage info. */
-	new_buff_sz += sizeof(struct cbfs_stage);
 	buffer_init(buff, buff->name, new_buffer, new_buff_sz);
-	buffer_clone(&writer, buff);
-	/* Set size to 0 to please xdr. */
-	buffer_set_size(&writer, 0);
 
 	/* True decompressed size is just the data size -- no metadata. */
-	metadata.len = new_buff_sz - sizeof(struct cbfs_stage);
+	stage->len = new_buff_sz;
 	/* Stage is not compressed. */
-	metadata.compression = CBFS_COMPRESS_NONE;
-
-	/* Write back out the stage metadata. */
-	xdr_le.put32(&writer, metadata.compression);
-	xdr_le.put32(&writer, metadata.entry);
-	xdr_le.put32(&writer, metadata.load);
-	xdr_le.put32(&writer, metadata.len);
-	xdr_le.put32(&writer, metadata.memlen);
+	stage->compression = CBFS_COMPRESS_NONE;
 
 	free(orig_buffer);
 
 	return 0;
 }
 
+static int init_elf_from_arch(Elf64_Ehdr *ehdr, uint32_t cbfs_arch)
+{
+	int endian;
+	int nbits;
+	int machine;
+
+	switch (cbfs_arch) {
+	case CBFS_ARCHITECTURE_X86:
+		endian = ELFDATA2LSB;
+		nbits = ELFCLASS32;
+		machine = EM_386;
+		break;
+	case CBFS_ARCHITECTURE_ARM:
+		endian = ELFDATA2LSB;
+		nbits = ELFCLASS32;
+		machine = EM_ARM;
+		break;
+	case CBFS_ARCHITECTURE_AARCH64:
+		endian = ELFDATA2LSB;
+		nbits = ELFCLASS64;
+		machine = EM_AARCH64;
+		break;
+	case CBFS_ARCHITECTURE_MIPS:
+		endian = ELFDATA2LSB;
+		nbits = ELFCLASS32;
+		machine = EM_MIPS;
+		break;
+	case CBFS_ARCHITECTURE_RISCV:
+		endian = ELFDATA2LSB;
+		nbits = ELFCLASS32;
+		machine = EM_RISCV;
+		break;
+	default:
+		ERROR("Unsupported arch: %x\n", cbfs_arch);
+		return -1;
+	}
+
+	elf_init_eheader(ehdr, machine, nbits, endian);
+	return 0;
+}
+
+static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch)
+{
+	Elf64_Ehdr ehdr;
+	Elf64_Shdr shdr;
+	struct cbfs_stage stage;
+	struct elf_writer *ew;
+	struct buffer elf_out;
+	size_t empty_sz;
+
+	if (cbfs_stage_decompress(&stage, buff)) {
+		ERROR("Failed to decompress stage.\n");
+		return -1;
+	}
+
+	if (init_elf_from_arch(&ehdr, arch))
+		return -1;
+
+	ehdr.e_entry = stage.entry;
+
+	ew = elf_writer_init(&ehdr);
+	if (ew == NULL) {
+		ERROR("Unable to init ELF writer.\n");
+		return -1;
+	}
+
+	memset(&shdr, 0, sizeof(shdr));
+	shdr.sh_type = SHT_PROGBITS;
+	shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
+	shdr.sh_addr = stage.load;
+	shdr.sh_size = stage.len;
+	empty_sz = stage.memlen - stage.len;
+
+	if (elf_writer_add_section(ew, &shdr, buff, ".program")) {
+		ERROR("Unable to add ELF section: .program\n");
+		elf_writer_destroy(ew);
+		return -1;
+	}
+
+	if (empty_sz != 0) {
+		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 = stage.load + stage.len;
+		shdr.sh_size = empty_sz;
+		if (elf_writer_add_section(ew, &shdr, &b, ".empty")) {
+			ERROR("Unable to add ELF section: .empty\n");
+			elf_writer_destroy(ew);
+			return -1;
+		}
+	}
+
+	if (elf_writer_serialize(ew, &elf_out)) {
+		ERROR("Unable to create ELF file from stage.\n");
+		elf_writer_destroy(ew);
+		return -1;
+	}
+
+	/* Flip buffer with the created ELF one. */
+	buffer_delete(buff);
+	*buff = elf_out;
+
+	elf_writer_destroy(ew);
+
+	return 0;
+}
+
 int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
-		      const char *filename, unused uint32_t arch)
+		      const char *filename, uint32_t arch)
 {
 	struct cbfs_file *entry = cbfs_get_entry(image, entry_name);
 	struct buffer buffer;
@@ -748,10 +855,6 @@ int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
 	    entry_name, cbfs_get_entry_addr(image, entry),
 	    get_cbfs_entry_type_name(ntohl(entry->type)), decompressed_size);
 
-	if (ntohl(entry->type) == CBFS_COMPONENT_STAGE) {
-		WARN("Stages are extracted in SELF format.\n");
-	}
-
 	if (ntohl(entry->type) == CBFS_COMPONENT_PAYLOAD) {
 		WARN("Payloads are extracted in SELF format.\n");
 	}
@@ -774,9 +877,7 @@ int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
 	 * the stage data to make it more meaningful.
 	 */
 	if (ntohl(entry->type) == CBFS_COMPONENT_STAGE) {
-		if (cbfs_stage_decompress(&buffer)) {
-			ERROR("Failed to write %s into %s.\n",
-			      entry_name, filename);
+		if (cbfs_stage_make_elf(&buffer, arch)) {
 			buffer_delete(&buffer);
 			return -1;
 		}



More information about the coreboot-gerrit mailing list