diff options
Diffstat (limited to 'util/cbfstool/common.c')
-rw-r--r-- | util/cbfstool/common.c | 211 |
1 files changed, 177 insertions, 34 deletions
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 <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); - - 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); |