coreboot-kgpe-d16/util/romtool/tools/rom-mkpayload.c
Stefan Reinauer 14ad50edf6 This fixes a race condition (revealed by my other check-in r4067) in the
romtool by changing the Makefiles to be no longer recursive (once again,
recursive make is to be considered harmful).  Tried to (quickly) unify most of
the Makefile code, but medium-term this is going to be worked on for Kconfig
support anyways.

Also fix a sign cast error in rom-mkpayload in case people want to compile this
with -W -Werror

Patch relative to coreboot-v2/util/romtool

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
and
Acked-by: Stefan Reinauer <stepan@coresystems.de>
in order to get the tree working decently asap



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4069 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2009-04-04 22:18:26 +00:00

269 lines
5.9 KiB
C

/*
* 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 ((unsigned int)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;
}