[coreboot-gerrit] Patch set updated for coreboot: cbfstool: Extract payload in ELF
Antonello Dettori (dev@dettori.io)
gerrit at coreboot.org
Wed Jun 15 15:53:54 CEST 2016
Antonello Dettori (dev at dettori.io) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15139
-gerrit
commit e9d4a2781bbc52bd92017047d600d5a79520c484
Author: Antonello Dettori <dettori.an at gmail.com>
Date: Thu Jun 9 12:35:36 2016 +0200
cbfstool: Extract payload in ELF
Implement function that automatically converts a SELF payload,
extracted from the CBFS, into an ELF file.
The code has been tested on the following payloads:
Working: FILO, SeaBIOS, nvramcui, coreinfo and tint
Currently not working: grub
Change-Id: I51599e65419bfa4ada8fe24b119acb20c9936227
Signed-off-by: Antonello Dettori <dettori.an at gmail.com>
---
util/cbfstool/cbfs_image.c | 236 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 232 insertions(+), 4 deletions(-)
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 0e20c80..a794be5 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -827,6 +827,84 @@ static int cbfs_stage_decompress(struct cbfs_stage *stage, struct buffer *buff)
return 0;
}
+static int cbfs_payload_decompress(struct cbfs_payload_segment *segments,
+ struct buffer *buff, int num_seg)
+{
+ struct buffer new_buffer;
+ size_t new_buff_sz = 0;
+ char *in_ptr;
+ char *out_ptr;
+ size_t new_offset = 0;
+ decomp_func_ptr decompress;
+
+ /* Find out and allocate the amount of memory occupied
+ * by the binary data */
+ for (int i = 0; i < num_seg; i++)
+ new_buff_sz += segments[i].mem_len;
+
+ buffer_create(&new_buffer, new_buff_sz, "decompressed_buff");
+
+ in_ptr = buffer_get(buff) +
+ sizeof(struct cbfs_payload_segment) * num_seg;
+ out_ptr = buffer_get(&new_buffer);
+
+ for (int i = 0; i < num_seg; i++) {
+ struct buffer tbuff;
+ size_t decomp_size;
+
+ /* The payload uses an unknown compression algorithm. */
+ decompress = decompression_function(segments[i].compression);
+ if (decompress == NULL) {
+ ERROR("Unknown decompression algorithm: %u",
+ segments[i].compression);
+ return -1;
+ }
+
+ /* Segments BSS and ENTRY do not have binary data. */
+ if (segments[i].type == PAYLOAD_SEGMENT_BSS ||
+ segments[i].type == PAYLOAD_SEGMENT_ENTRY) {
+ continue;
+ } else if (segments[i].type == PAYLOAD_SEGMENT_PARAMS) {
+ buffer_create(&tbuff, segments[i].len, "params");
+ // TODO: handle PARAMS
+ continue;
+ }
+
+ buffer_create(&tbuff, segments[i].mem_len, "segment");
+
+ if (decompress(in_ptr, segments[i].len, buffer_get(&tbuff),
+ (int) buffer_size(&tbuff),
+ &decomp_size)) {
+ ERROR("Couldn't decompress payload segment %u\n", i);
+ buffer_delete(&new_buffer);
+ return -1;
+ }
+
+ memcpy(out_ptr, buffer_get(&tbuff), buffer_size(&tbuff));
+
+ /* Since buff doesn't contain the segments the first offset
+ * points to the beginning of the buffer. */
+ segments[i].offset = new_offset;
+ new_offset += segments[i].mem_len;
+
+ /* Adjust input and output buffer pointers */
+ in_ptr += segments[i].len;
+ out_ptr += segments[i].mem_len;
+
+ /* True decompressed size is just the data size. No metadata */
+ segments[i].len = decomp_size;
+ /* Segment is not compressed. */
+ segments[i].compression = CBFS_COMPRESS_NONE;
+
+ buffer_delete(&tbuff);
+ }
+
+ buffer_delete(buff);
+ *buff = new_buffer;
+
+ return 0;
+}
+
static int init_elf_from_arch(Elf64_Ehdr *ehdr, uint32_t cbfs_arch)
{
int endian;
@@ -949,6 +1027,155 @@ static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch)
return 0;
}
+static int cbfs_payload_make_elf(struct buffer *buff, uint32_t arch)
+{
+ Elf64_Ehdr ehdr;
+ Elf64_Shdr shdr;
+ struct cbfs_payload_segment *segs;
+ struct elf_writer *ew;
+ struct buffer elf_out;
+ size_t empty_sz;
+ int segments = 0;
+
+ /* Count the number of segments inside buffer */
+ while (true) {
+ uint32_t payload_type = 0;
+
+ memcpy(&payload_type, buff->data +
+ sizeof(struct cbfs_payload_segment) * segments,
+ sizeof(PAYLOAD_SEGMENT_CODE));
+ payload_type = ntohl(payload_type);
+
+ if (payload_type == PAYLOAD_SEGMENT_CODE) {
+ segments++;
+ } else if (payload_type == PAYLOAD_SEGMENT_DATA) {
+ segments++;
+ } else if (payload_type == PAYLOAD_SEGMENT_BSS) {
+ segments++;
+ } else if (payload_type == PAYLOAD_SEGMENT_PARAMS) {
+ segments++;
+ } else if (payload_type == PAYLOAD_SEGMENT_ENTRY) {
+ /* The last segment in a payload is always ENTRY as
+ * specified by the parse_elf_to_payload() function.
+ * Therefore there is no need to continue looking for
+ * segments.*/
+ segments++;
+ break;
+ } else {
+ ERROR("Unknown payload segment type: %x\n",
+ payload_type);
+ return -1;
+ }
+ }
+
+ segs = malloc(segments * sizeof(*segs));
+
+ /* Decode xdr segments */
+ for (int i = 0; i < segments; i++) {
+ struct cbfs_payload_segment *serialized_seg = buffer_get(buff);
+
+ xdr_get_seg(&segs[i], &serialized_seg[i]);
+ }
+
+ if (cbfs_payload_decompress(segs, buff, segments)) {
+ ERROR("Failed to decompress payload.\n");
+ return -1;
+ }
+
+ if (init_elf_from_arch(&ehdr, arch))
+ return -1;
+
+ ehdr.e_entry = segs[segments-1].load_addr;
+
+ ew = elf_writer_init(&ehdr);
+ if (ew == NULL) {
+ ERROR("Unable to init ELF writer.\n");
+ return -1;
+ }
+
+ for (int i = 0; i < segments; i++) {
+ struct buffer tbuff;
+
+ memset(&shdr, 0, sizeof(shdr));
+ char *name = NULL;
+
+ if (segs[i].type == PAYLOAD_SEGMENT_CODE) {
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
+ shdr.sh_addr = segs[i].load_addr;
+ shdr.sh_size = segs[i].len;
+ empty_sz = segs[i].mem_len - segs[i].len;
+ name = strdup(".text");
+ buffer_splice(&tbuff, buff, segs[i].offset,
+ segs[i].len);
+ } else if (segs[i].type == PAYLOAD_SEGMENT_DATA) {
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
+ shdr.sh_addr = segs[i].load_addr;
+ shdr.sh_size = segs[i].len;
+ empty_sz = segs[i].mem_len - segs[i].len;
+ name = strdup(".data");
+ buffer_splice(&tbuff, buff, segs[i].offset,
+ segs[i].len);
+ } else if (segs[i].type == PAYLOAD_SEGMENT_BSS) {
+ shdr.sh_type = SHT_NOBITS;
+ shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
+ shdr.sh_addr = segs[i].load_addr;
+ shdr.sh_size = segs[i].len;
+ name = strdup(".bss");
+ buffer_splice(&tbuff, buff, 0, 0);
+ } else if (segs[i].type == PAYLOAD_SEGMENT_PARAMS) {
+ shdr.sh_type = SHT_NOTE;
+ shdr.sh_flags = 0;
+ shdr.sh_size = segs[i].len;
+ name = strdup(".note.pinfo");
+ buffer_splice(&tbuff, buff, segs[i].offset,
+ segs[i].len);
+ } else if (segs[i].type == PAYLOAD_SEGMENT_ENTRY) {
+ break;
+ }
+
+
+ if (elf_writer_add_section(ew, &shdr, &tbuff, name)) {
+ ERROR("Unable to add ELF section: %s\n", name);
+ 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 = segs[i].load_addr + segs[i].len;
+ shdr.sh_size = empty_sz;
+ name = strdup(".empty");
+ if (elf_writer_add_section(ew, &shdr, &b, name)) {
+ ERROR("Unable to add ELF section: %s\n", name);
+ 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, uint32_t arch)
{
@@ -973,10 +1200,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_PAYLOAD) {
- WARN("Payloads are extracted in SELF format.\n");
- }
-
buffer_init(&buffer, strdup("(cbfs_export_entry)"), NULL, 0);
buffer.data = malloc(decompressed_size);
@@ -999,6 +1222,11 @@ int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
buffer_delete(&buffer);
return -1;
}
+ } else if (ntohl(entry->type) == CBFS_COMPONENT_PAYLOAD) {
+ if (cbfs_payload_make_elf(&buffer, arch)) {
+ buffer_delete(&buffer);
+ return -1;
+ }
}
if (buffer_write_file(&buffer, filename) != 0) {
More information about the coreboot-gerrit
mailing list