summaryrefslogtreecommitdiff
path: root/util/cbfstool/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/cbfstool/common.c')
-rw-r--r--util/cbfstool/common.c211
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);