diff options
author | Ronald G. Minnich <rminnich@gmail.com> | 2009-03-31 11:57:36 +0000 |
---|---|---|
committer | Patrick Georgi <patrick.georgi@coresystems.de> | 2009-03-31 11:57:36 +0000 |
commit | 5d01ec0f80cc8379df17ed9a922de37b487770b4 (patch) | |
tree | 6994cd877e80a721cef1154239d4af6653980379 /util/romtool/tools/rom-mkpayload.c | |
parent | 0f0f9bb9a2e1c1257fdfee0b50061e82ea92161b (diff) |
This patch adds Jordan's romtool support for v2.
There are a few changes. The 20K bootblock size restriction is gone.
ROMFS has been tested and works on v2 with qemu and kontron. Once this
patch is in, those patches will follow.
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4032 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/romtool/tools/rom-mkpayload.c')
-rw-r--r-- | util/romtool/tools/rom-mkpayload.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/util/romtool/tools/rom-mkpayload.c b/util/romtool/tools/rom-mkpayload.c new file mode 100644 index 0000000000..54fde24cec --- /dev/null +++ b/util/romtool/tools/rom-mkpayload.c @@ -0,0 +1,269 @@ +/* + * rom-mkpayload + * + * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "elf.h" +#include <fcntl.h> +#include <getopt.h> +#include <sys/stat.h> +#include <arpa/inet.h> + +#include "common.h" +#include "../romfs.h" + +int parse_elf(unsigned char *input, unsigned char **output, int algo, + void (*compress) (char *, int, char *, int *)) +{ + Elf32_Phdr *phdr; + Elf32_Ehdr *ehdr; + Elf32_Shdr *shdr; + char *header; + char *strtab; + unsigned char *sptr; + int headers; + int segments = 1; + int isize = 0, osize = 0; + int doffset = 0; + struct romfs_payload_segment *segs; + int i; + + ehdr = (Elf32_Ehdr *) input; + headers = ehdr->e_phnum; + header = (char *)ehdr; + + phdr = (Elf32_Phdr *) & (header[ehdr->e_phoff]); + shdr = (Elf32_Shdr *) & (header[ehdr->e_shoff]); + + strtab = &header[shdr[ehdr->e_shstrndx].sh_offset]; + + /* Count the number of headers - look for the .notes.pinfo + * section */ + + for (i = 0; i < ehdr->e_shnum; i++) { + char *name; + + if (i == ehdr->e_shstrndx) + continue; + + if (shdr[i].sh_size == 0) + continue; + + name = (char *)(strtab + shdr[i].sh_name); + + if (!strcmp(name, ".note.pinfo")) + segments++; + } + + /* Now, regular headers - we only care about PT_LOAD headers, + * because thats what we're actually going to load + */ + + for (i = 0; i < headers; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + + /* Empty segments are never interesting */ + if (phdr[i].p_memsz == 0) + continue; + + isize += phdr[i].p_filesz; + + segments++; + } + + /* Allocate a block of memory to store the data in */ + + sptr = + calloc((segments * sizeof(struct romfs_payload_segment)) + isize, + 1); + doffset = (segments * sizeof(struct romfs_payload_segment)); + + if (sptr == NULL) + goto err; + + segs = (struct romfs_payload_segment *)sptr; + segments = 0; + + for (i = 0; i < ehdr->e_shnum; i++) { + char *name; + + if (i == ehdr->e_shstrndx) + continue; + + if (shdr[i].sh_size == 0) + continue; + + name = (char *)(strtab + shdr[i].sh_name); + + if (!strcmp(name, ".note.pinfo")) { + segs[segments].type = PAYLOAD_SEGMENT_PARAMS; + segs[segments].load_addr = 0; + segs[segments].len = (unsigned int)shdr[i].sh_size; + segs[segments].offset = doffset; + + memcpy((unsigned long *)(sptr + doffset), + &header[shdr[i].sh_offset], shdr[i].sh_size); + + doffset += segs[segments].len; + osize += segs[segments].len; + + segments++; + } + } + + for (i = 0; i < headers; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + + if (phdr[i].p_memsz == 0) + continue; + + if (phdr[i].p_filesz == 0) { + segs[segments].type = PAYLOAD_SEGMENT_BSS; + segs[segments].load_addr = + (unsigned long long)htonl(phdr[i].p_paddr); + segs[segments].mem_len = (unsigned int)htonl(phdr[i].p_memsz); + segs[segments].offset = htonl(doffset); + + segments++; + continue; + } + + segs[segments].type = PAYLOAD_SEGMENT_DATA; + segs[segments].load_addr = (unsigned int)htonl(phdr[i].p_paddr); + segs[segments].mem_len = (unsigned int)htonl(phdr[i].p_memsz); + segs[segments].compression = htonl(algo); + segs[segments].offset = htonl(doffset); + + int len; + compress((char *)&header[phdr[i].p_offset], + phdr[i].p_filesz, + (char *)(sptr + doffset), &len); + segs[segments].len = htonl(len); + + /* If the compressed section is larger, then use the + original stuff */ + + if (len > phdr[i].p_filesz) { + segs[segments].compression = 0; + segs[segments].len = htonl(phdr[i].p_filesz); + + memcpy((char *)(sptr + doffset), + &header[phdr[i].p_offset], phdr[i].p_filesz); + } + + doffset += ntohl(segs[segments].len); + osize += ntohl(segs[segments].len); + + segments++; + } + + segs[segments].type = PAYLOAD_SEGMENT_ENTRY; + segs[segments++].load_addr = (unsigned long long)htonl(ehdr->e_entry); + + *output = sptr; + + return (segments * sizeof(struct romfs_payload_segment)) + osize; + +err: + return -1; +} + +int main(int argc, char **argv) +{ + void (*compress) (char *, int, char *, int *); + int algo; + + char *output = NULL; + char *input = NULL; + + unsigned char *buffer, *obuffer; + int size, osize; + + while (1) { + int option_index; + static struct option longopt[] = { + {"output", 1, 0, 'o'}, + {"lzma", 0, 0, 'l'}, + {"nocompress", 0, 0, 'n'}, + }; + + signed char ch = getopt_long(argc, argv, "o:ln", + longopt, &option_index); + + if (ch == -1) + break; + + switch (ch) { + case 'o': + output = optarg; + break; + case 'l': + algo = ROMFS_COMPRESS_LZMA; + break; + case 'n': + algo = ROMFS_COMPRESS_NONE; + break; + default: + //usage(); + return -1; + } + } + + if (optind < argc) + input = argv[optind]; + + if (input == NULL || !strcmp(input, "-")) + buffer = file_read_to_buffer(STDIN_FILENO, &size); + else { + printf("Reading from %s\n", input); + buffer = file_read(input, &size); + } + + if (!iself(buffer)) { + fprintf(stderr, "E: This does not appear to be an ELF file\n"); + return -1; + } + + switch (algo) { + case ROMFS_COMPRESS_NONE: + compress = none_compress; + break; + case ROMFS_COMPRESS_LZMA: + compress = lzma_compress; + break; + } + + osize = parse_elf(buffer, &obuffer, algo, compress); + + if (osize == -1) { + fprintf(stderr, "E: Error while converting the payload\n"); + return -1; + } + + if (output == NULL || !strcmp(output, "-")) + file_write_from_buffer(STDOUT_FILENO, obuffer, osize); + else + file_write(output, obuffer, osize); + + return 0; +} |