From 90ca3b6bd7d7849898fe2363a9e6d0e002c95943 Mon Sep 17 00:00:00 2001 From: David Hendricks Date: Fri, 16 Nov 2012 14:48:22 -0800 Subject: 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 Signed-off-by: Hung-Te Lin Signed-off-by: David Hendricks Reviewed-on: http://review.coreboot.org/1944 Tested-by: build bot (Jenkins) --- util/cbfstool/cbfs-mkpayload.c | 12 ++- util/cbfstool/cbfs-mkstage.c | 9 +- util/cbfstool/cbfs.h | 15 ++- util/cbfstool/cbfstool.c | 32 +++++-- util/cbfstool/common.c | 211 ++++++++++++++++++++++++++++++++++------- util/cbfstool/common.h | 5 + 6 files changed, 233 insertions(+), 51 deletions(-) (limited to 'util') diff --git a/util/cbfstool/cbfs-mkpayload.c b/util/cbfstool/cbfs-mkpayload.c index e4ef5c8351..0d3986e429 100644 --- a/util/cbfstool/cbfs-mkpayload.c +++ b/util/cbfstool/cbfs-mkpayload.c @@ -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; diff --git a/util/cbfstool/cbfs-mkstage.c b/util/cbfstool/cbfs-mkstage.c index 55c81c6ebe..0541d4b48e 100644 --- a/util/cbfstool/cbfs-mkstage.c +++ b/util/cbfstool/cbfs-mkstage.c @@ -4,6 +4,7 @@ * Copyright (C) 2008 Jordan Crouse * 2009 coresystems GmbH * written by Patrick Georgi + * 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; } diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h index f161ed445a..5251d6501d 100644 --- a/util/cbfstool/cbfs.h +++ b/util/cbfstool/cbfs.h @@ -21,6 +21,12 @@ #include +#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 diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index 66db379d02..a09e75b1f1 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -3,6 +3,7 @@ * * Copyright (C) 2009 coresystems GmbH * written by Patrick Georgi + * 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]); diff --git a/util/cbfstool/common.c b/util/cbfstool/common.c index 6c67c396f4..d29df60aeb 100644 --- a/util/cbfstool/common.c +++ b/util/cbfstool/common.c @@ -3,6 +3,7 @@ * * Copyright (C) 2009 coresystems GmbH * written by Patrick Georgi + * 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); - - recalculate_rom_geometry(romarea); - - cbfs_create_empty_file((0 - romsize + offs) & 0xffffffff, - romsize - offs - bootblocksize - - sizeof(struct cbfs_header) - - sizeof(struct cbfs_file) - 16); + // TODO(hungte) Replace magic numbers by named constants. + switch (arch) { + case CBFS_ARCHITECTURE_ARMV7: + /* Set up physical/virtual mapping */ + offset = 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 + + 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); diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h index 4fcc1eee68..b5258a3e6d 100644 --- a/util/cbfstool/common.h +++ b/util/cbfstool/common.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2009 coresystems GmbH * written by Patrick Georgi + * 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) { -- cgit v1.2.3