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:
committed by
Stefan Reinauer
parent
11a20b614e
commit
90ca3b6bd7
@@ -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);
|
||||
|
Reference in New Issue
Block a user