Add multi-architecture support to cbfstool

This is an initial re-factoring of CBFS code to enable multiple
architectures. To achieve a clean solution, an additional field
describing the architecture has to be added to the master header.
Hence we also increase the version number in the master header.

Change-Id: Icda681673221f8c27efbc46f16c2c5682b16a265
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Signed-off-by: David Hendricks <dhendrix@chromium.org>
Reviewed-on: http://review.coreboot.org/1944
Tested-by: build bot (Jenkins)
This commit is contained in:
David Hendricks
2012-11-16 14:48:22 -08:00
committed by Stefan Reinauer
parent 11a20b614e
commit 90ca3b6bd7
11 changed files with 288 additions and 71 deletions

View File

@@ -35,7 +35,7 @@ int parse_elf_to_payload(unsigned char *input, unsigned char **output,
comp_algo algo)
{
Elf32_Phdr *phdr;
Elf32_Ehdr *ehdr;
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) input;
Elf32_Shdr *shdr;
char *header;
char *strtab;
@@ -48,16 +48,20 @@ int parse_elf_to_payload(unsigned char *input, unsigned char **output,
int i;
if(!iself(input)){
printf("Fatal error: the payload file is not in ELF format!\n");
exit(1);
fprintf(stderr, "E: The payload file is not in ELF format!\n");
return -1;
}
if (!((ehdr->e_machine == EM_ARM) && (arch == CBFS_ARCHITECTURE_ARMV7)) &&
!((ehdr->e_machine == EM_386) && (arch == CBFS_ARCHITECTURE_X86))) {
fprintf(stderr, "E: The payload file has the wrong architecture\n");
return -1;
}
comp_func_ptr compress = compression_function(algo);
if (!compress)
return -1;
ehdr = (Elf32_Ehdr *) input;
headers = ehdr->e_phnum;
header = (char *)ehdr;

View File

@@ -4,6 +4,7 @@
* Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
* 2009 coresystems GmbH
* written by Patrick Georgi <patrick.georgi@coresystems.de>
* Copyright (C) 2012 Google, Inc.
*
* 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
@@ -67,7 +68,13 @@ int parse_elf_to_stage(unsigned char *input, unsigned char **output,
return -1;
if (!iself(input)) {
fprintf(stderr, "E: The incoming file is not an ELF\n");
fprintf(stderr, "E: The stage file is not in ELF format!\n");
return -1;
}
if (!((ehdr->e_machine == EM_ARM) && (arch == CBFS_ARCHITECTURE_ARMV7)) &&
!((ehdr->e_machine == EM_386) && (arch == CBFS_ARCHITECTURE_X86))) {
fprintf(stderr, "E: The stage file has the wrong architecture\n");
return -1;
}

View File

@@ -21,6 +21,12 @@
#include <stdint.h>
#define CBFS_HEADER_MAGIC 0x4F524243
#define CBFS_HEADPTR_ADDR_X86 0xFFFFFFFC
#define VERSION1 0x31313131
#define VERSION2 0x31313132
#define VERSION VERSION2
struct cbfs_header {
uint32_t magic;
uint32_t version;
@@ -28,9 +34,14 @@ struct cbfs_header {
uint32_t bootblocksize;
uint32_t align;
uint32_t offset;
uint32_t pad[2];
uint32_t architecture; /* Version 2 */
uint32_t pad[1];
} __attribute__ ((packed));
#define CBFS_ARCHITECTURE_UNKNOWN 0xFFFFFFFF
#define CBFS_ARCHITECTURE_X86 0x00000001
#define CBFS_ARCHITECTURE_ARMV7 0x00000010
struct cbfs_file {
uint8_t magic[8];
uint32_t len;
@@ -94,7 +105,7 @@ struct cbfs_payload {
*/
#define CBFS_COMPONENT_NULL 0xFFFFFFFF
int cbfs_file_header(uint32_t physaddr);
int cbfs_file_header(unsigned long physaddr);
struct cbfs_file *cbfs_create_empty_file(uint32_t physaddr, uint32_t size);
#endif

View File

@@ -3,6 +3,7 @@
*
* Copyright (C) 2009 coresystems GmbH
* written by Patrick Georgi <patrick.georgi@coresystems.de>
* Copyright (C) 2012 Google, Inc.
*
* 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
@@ -372,6 +373,11 @@ static int cbfs_create(void)
return 1;
}
if (arch == CBFS_ARCHITECTURE_UNKNOWN) {
fprintf(stderr, "E: You need to specify -m/--machine arch\n");
return 1;
}
return create_cbfs_image(cbfs_name, rom_size, rom_bootblock,
rom_alignment, rom_offset);
}
@@ -450,7 +456,7 @@ static const struct command commands[] = {
{"add-stage", "f:n:t:c:b:h?", cbfs_add_stage},
{"add-flat-binary", "f:n:l:e:c:b:h?", cbfs_add_flat_binary},
{"remove", "n:h?", cbfs_remove},
{"create", "s:B:a:o:h?", cbfs_create},
{"create", "s:B:a:o:m:h?", cbfs_create},
{"locate", "f:n:a:h?", cbfs_locate},
{"print", "h?", cbfs_print},
{"extract", "n:f:h?", cbfs_extract},
@@ -468,6 +474,7 @@ static struct option long_options[] = {
{"alignment", required_argument, 0, 'a' },
{"offset", required_argument, 0, 'o' },
{"file", required_argument, 0, 'f' },
{"arch", required_argument, 0, 'm' },
{"verbose", no_argument, 0, 'v' },
{"help", no_argument, 0, 'h' },
{NULL, 0, 0, 0 }
@@ -481,26 +488,28 @@ static void usage(char *name)
" %s FILE COMMAND [PARAMETERS]...\n\n" "OPTIONs:\n"
" -h Display this help message\n\n"
"COMMANDs:\n"
" add -f FILE -n NAME -t TYPE [-b base-address] "
" add -f FILE -n NAME -t TYPE [-b base-address] "
"Add a component\n"
" add-payload -f FILE -n NAME [-c compression] [-b base] "
" add-payload -f FILE -n NAME [-c compression] [-b base] "
"Add a payload to the ROM\n"
" add-stage -f FILE -n NAME [-c compression] [-b base] "
" add-stage -f FILE -n NAME [-c compression] [-b base] "
"Add a stage to the ROM\n"
" add-flat-binary -f FILE -n NAME -l load-address \\\n"
" -e entry-point [-c compression] [-b base] "
" -e entry-point [-c compression] [-b base] "
"Add a 32bit flat mode binary\n"
" remove -n NAME "
" remove -n NAME "
"Remove a component\n"
" create -s size -B bootblock [-a align] [-o offset] "
" create -s size -B bootblock -m ARCH [-a align] [-o offset] "
"Create a ROM file\n"
" locate -f FILE -n NAME -a align "
" locate -f FILE -n NAME -a align "
"Find a place for a file of that size\n"
" print "
" print "
"Show the contents of the ROM\n"
" extract -n NAME -f FILE "
" extract -n NAME -f FILE "
"Extracts a raw payload from ROM\n"
"\n"
"ARCHes:\n"
" armv7, x86\n"
"TYPEs:\n", name, name
);
print_supported_filetypes();
@@ -610,6 +619,9 @@ int main(int argc, char **argv)
case 'v':
verbose++;
break;
case 'm':
arch = string_to_arch(optarg);
break;
case 'h':
case '?':
usage(argv[0]);

View File

@@ -3,6 +3,7 @@
*
* Copyright (C) 2009 coresystems GmbH
* written by Patrick Georgi <patrick.georgi@coresystems.de>
* Copyright (C) 2012 Google, Inc.
*
* 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
@@ -73,16 +74,101 @@ static struct cbfs_header *master_header;
static uint32_t phys_start, phys_end, align;
uint32_t romsize;
void *offset;
uint32_t arch = CBFS_ARCHITECTURE_UNKNOWN;
static struct {
uint32_t arch;
const char *name;
} arch_names[] = {
{ CBFS_ARCHITECTURE_ARMV7, "armv7" },
{ CBFS_ARCHITECTURE_X86, "x86" },
{ CBFS_ARCHITECTURE_UNKNOWN, "unknown" }
};
uint32_t string_to_arch(const char *arch_string)
{
int i;
uint32_t ret = CBFS_ARCHITECTURE_UNKNOWN;
for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
if (!strcasecmp(arch_string, arch_names[i].name)) {
ret = arch_names[i].arch;
break;
}
}
return ret;
}
const char *arch_to_string(uint32_t a)
{
int i;
const char *ret = NULL;
for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
if (a == arch_names[i].arch) {
ret = arch_names[i].name;
break;
}
}
return ret;
}
int find_master_header(void *romarea, size_t size)
{
size_t offset;
if (master_header)
return 0;
for (offset = 0; offset < size - sizeof(struct cbfs_header); offset++) {
struct cbfs_header *tmp = romarea + offset;
if (tmp->magic == ntohl(CBFS_HEADER_MAGIC)) {
master_header = tmp;
break;
}
}
return master_header ? 0 : 1;
}
void recalculate_rom_geometry(void *romarea)
{
offset = romarea + romsize - 0x100000000ULL;
master_header = (struct cbfs_header *)
phys_to_virt(*((uint32_t *) phys_to_virt(0xfffffffc)));
phys_start = (0 - romsize + ntohl(master_header->offset)) & 0xffffffff;
phys_end =
(0 - ntohl(master_header->bootblocksize) -
sizeof(struct cbfs_header)) & 0xffffffff;
if (find_master_header(romarea, romsize)) {
fprintf(stderr, "E: Cannot find master header\n");
exit(1);
}
/* Update old headers */
if (master_header->version == VERSION1 &&
ntohl(master_header->architecture) == CBFS_ARCHITECTURE_UNKNOWN) {
printf("Updating CBFS master header to version 2\n");
master_header->architecture = htonl(CBFS_ARCHITECTURE_X86);
}
arch = ntohl(master_header->architecture);
switch (arch) {
case CBFS_ARCHITECTURE_ARMV7:
offset = romarea;
phys_start = (0 + ntohl(master_header->offset)) & 0xffffffff;
phys_end = romsize & 0xffffffff;
break;
case CBFS_ARCHITECTURE_X86:
offset = romarea + romsize - 0x100000000ULL;
phys_start = (0 - romsize + ntohl(master_header->offset)) &
0xffffffff;
phys_end = (0 - ntohl(master_header->bootblocksize) -
sizeof(struct cbfs_header)) & 0xffffffff;
break;
default:
fprintf(stderr, "E: Unknown architecture\n");
exit(1);
}
align = ntohl(master_header->align);
}
@@ -114,7 +200,7 @@ int writerom(const char *filename, void *start, uint32_t size)
return 0;
}
int cbfs_file_header(uint32_t physaddr)
int cbfs_file_header(unsigned long physaddr)
{
/* maybe improve this test */
return (strncmp(phys_to_virt(physaddr), "LARCHIVE", 8) == 0);
@@ -188,9 +274,10 @@ uint64_t intfiletype(const char *name)
void print_cbfs_directory(const char *filename)
{
printf
("%s: %d kB, bootblocksize %d, romsize %d, offset 0x%x\nAlignment: %d bytes\n\n",
("%s: %d kB, bootblocksize %d, romsize %d, offset 0x%x\n"
"Alignment: %d bytes, architecture: %s\n\n",
basename((char *)filename), romsize / 1024, ntohl(master_header->bootblocksize),
romsize, ntohl(master_header->offset), align);
romsize, ntohl(master_header->offset), align, arch_to_string(arch));
printf("%-30s %-10s %-12s Size\n", "Name", "Offset", "Type");
uint32_t current = phys_start;
while (current < phys_end) {
@@ -206,8 +293,8 @@ void print_cbfs_directory(const char *filename)
fname = "(empty)";
printf("%-30s 0x%-8x %-12s %d\n", fname,
current - phys_start, strfiletype(ntohl(thisfile->type)),
length);
current - phys_start + ntohl(master_header->offset),
strfiletype(ntohl(thisfile->type)), length);
current =
ALIGN(current + ntohl(thisfile->len) +
ntohl(thisfile->offset), align);
@@ -451,7 +538,7 @@ void *create_cbfs_file(const char *filename, void *data, uint32_t * datasize,
}
int create_cbfs_image(const char *romfile, uint32_t _romsize,
const char *bootblock, uint32_t align, uint32_t offs)
const char *bootblock, uint32_t align, uint32_t offs)
{
uint32_t bootblocksize = 0;
struct cbfs_header *master_header;
@@ -466,9 +553,6 @@ int create_cbfs_image(const char *romfile, uint32_t _romsize,
}
memset(romarea, 0xff, romsize);
// Set up physical/virtual mapping
offset = romarea + romsize - 0x100000000ULL;
if (align == 0)
align = 64;
@@ -481,24 +565,83 @@ int create_cbfs_image(const char *romfile, uint32_t _romsize,
return 1;
}
master_header =
(struct cbfs_header *)(romarea + romsize - bootblocksize -
sizeof(struct cbfs_header));
master_header->magic = ntohl(0x4f524243);
master_header->version = ntohl(0x31313131);
master_header->romsize = htonl(romsize);
master_header->bootblocksize = htonl(bootblocksize);
master_header->align = htonl(align);
master_header->offset = htonl(offs);
((uint32_t *) phys_to_virt(0xfffffffc))[0] =
virt_to_phys(master_header);
// TODO(hungte) Replace magic numbers by named constants.
switch (arch) {
case CBFS_ARCHITECTURE_ARMV7:
/* Set up physical/virtual mapping */
offset = romarea;
recalculate_rom_geometry(romarea);
// should be aligned to align but then we need to dynamically
// create the jump to the bootblock
loadfile(bootblock, &bootblocksize, romarea + 0x20 +
sizeof(struct cbfs_header), SEEK_SET);
master_header = (struct cbfs_header *)(romarea + 0x20);
uint32_t *arm_vec = (uint32_t *)romarea;
/*
* Encoding for this branch instruction is:
* 31:28 - condition (0xe for always/unconditional)
* 27:24 - 0xa
* 23: 0 - sign-extended offset (in multiples of 4)
*
* When executing the branch, the PC will read as the address
* of current instruction + 8.
*/
arm_vec[0] = htonl(0x0e0000ea); // branch to . + 64 bytes
cbfs_create_empty_file((0 - romsize + offs) & 0xffffffff,
romsize - offs - bootblocksize -
sizeof(struct cbfs_header) -
sizeof(struct cbfs_file) - 16);
master_header->magic = ntohl(CBFS_HEADER_MAGIC);
master_header->version = ntohl(VERSION);
master_header->romsize = htonl(romsize);
master_header->bootblocksize = htonl(bootblocksize);
master_header->align = htonl(align);
master_header->offset = htonl(
ALIGN((0x40 + bootblocksize), align));
master_header->architecture = htonl(CBFS_ARCHITECTURE_ARMV7);
((uint32_t *) phys_to_virt(0x4))[0] =
virt_to_phys(master_header);
recalculate_rom_geometry(romarea);
cbfs_create_empty_file(
ALIGN((0x40 + bootblocksize), align),
romsize - ALIGN((bootblocksize + 0x40), align)
//- sizeof(struct cbfs_header)
- sizeof(struct cbfs_file) );
break;
case CBFS_ARCHITECTURE_X86:
// Set up physical/virtual mapping
offset = romarea + romsize - 0x100000000ULL;
loadfile(bootblock, &bootblocksize, romarea + romsize,
SEEK_END);
master_header = (struct cbfs_header *)(romarea + romsize -
bootblocksize - sizeof(struct cbfs_header));
master_header->magic = ntohl(CBFS_HEADER_MAGIC);
master_header->version = ntohl(VERSION);
master_header->romsize = htonl(romsize);
master_header->bootblocksize = htonl(bootblocksize);
master_header->align = htonl(align);
master_header->offset = htonl(offs);
master_header->architecture = htonl(CBFS_ARCHITECTURE_X86);
((uint32_t *) phys_to_virt(CBFS_HEADPTR_ADDR_X86))[0] =
virt_to_phys(master_header);
recalculate_rom_geometry(romarea);
cbfs_create_empty_file((0 - romsize + offs) & 0xffffffff,
romsize - offs - bootblocksize -
sizeof(struct cbfs_header) -
sizeof(struct cbfs_file) - 16);
break;
default:
// Should not happen.
fprintf(stderr, "E: You found a bug in cbfstool.\n");
exit(1);
}
writerom(romfile, romarea, romsize);
free(romarea);

View File

@@ -1,6 +1,7 @@
/*
* Copyright (C) 2009 coresystems GmbH
* written by Patrick Georgi <patrick.georgi@coresystems.de>
* Copyright (C) 2012 Google, Inc.
*
* 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
@@ -29,6 +30,10 @@
extern void *offset;
extern uint32_t romsize;
extern int host_bigendian;
extern uint32_t arch;
const char *arch_to_string(uint32_t a);
uint32_t string_to_arch(const char *arch_string);
static inline void *phys_to_virt(uint32_t addr)
{