From 5520e303a1238e5f339c0114082d2cbe0facd001 Mon Sep 17 00:00:00 2001
From: Yang Hamo Bai <hamo.by@gmail.com>
Date: Wed, 29 Jun 2011 21:21:40 +0800
Subject: [PATCH 05/12] cbfstool: added support for ARM architecture

Through using different ways for different arch to
recalculate rom geometry, cbfstool now can support
both X86 and ARM architectures.

Signed-off-by: Yang Hamo Bai <hamo.by@gmail.com>
---
 src/arch/x86/Makefile.inc    |    2 +-
 util/cbfstool/cbfs-mkstage.c |   10 ++-
 util/cbfstool/cbfstool.c     |   33 ++++++--
 util/cbfstool/common.c       |  198 ++++++++++++++++++++++++++++++++++--------
 util/cbfstool/common.h       |   11 ++-
 5 files changed, 206 insertions(+), 48 deletions(-)

diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc
index e9c00de..faae8f9 100644
--- a/src/arch/x86/Makefile.inc
+++ b/src/arch/x86/Makefile.inc
@@ -63,7 +63,7 @@ prebuilt-files = $(foreach file,$(cbfs-files), $(call extract_nth,1,$(file)))
 
 $(obj)/coreboot.pre1: $(obj)/coreboot.bootblock $$(prebuilt-files) $(CBFSTOOL)
 	rm -f $@
-	$(CBFSTOOL) $@ create $(CONFIG_COREBOOT_ROMSIZE_KB)K $(obj)/coreboot.bootblock
+	$(CBFSTOOL) $@ create x86 $(CONFIG_COREBOOT_ROMSIZE_KB)K $(obj)/coreboot.bootblock
 	$(prebuild-files)
 else
 $(obj)/coreboot.pre1: $(CBFSTOOL)
diff --git a/util/cbfstool/cbfs-mkstage.c b/util/cbfstool/cbfs-mkstage.c
index 2f81da0..e90bc93 100644
--- a/util/cbfstool/cbfs-mkstage.c
+++ b/util/cbfstool/cbfs-mkstage.c
@@ -3,7 +3,9 @@
  *
  * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
  *               2009 coresystems GmbH
- *                 written by Patrick Georgi <patrick.georgi@coresystems.de>
+ *               2010 Google Inc
+ *               2011 Yang Bai <hamo.by@gmail.com>
+ * written by Patrick Georgi <patrick.georgi@coresystems.de>
  *
  * 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
@@ -70,6 +72,12 @@ int parse_elf_to_stage(unsigned char *input, unsigned char **output,
 		return -1;
 	}
 
+	if (!((ehdr->e_machine == EM_ARM) && (arch == ARCH_ARM)) &&
+	    !((ehdr->e_machine == EM_386) && (arch == ARCH_X86))) {
+		fprintf(stderr, "E:  The incoming file has the wrong architecture\n");
+		return -1;
+	}
+
 	if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
 		elf_bigendian = 1;
 	}
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index 4c28c29..811310b 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -2,7 +2,9 @@
  * cbfstool, CLI utility for CBFS file manipulation
  *
  * Copyright (C) 2009 coresystems GmbH
- *                 written by Patrick Georgi <patrick.georgi@coresystems.de>
+ * written by Patrick Georgi <patrick.georgi@coresystems.de>
+ * Copyright (C) 2010 Google Inc
+ * Copyright (C) 2011 Yang Bai <hamo.by@gmail.com>
  *
  * 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
@@ -189,26 +191,41 @@ static int cbfs_add_stage(int argc, char **argv)
 
 static int cbfs_create(int argc, char **argv)
 {
+	char *arch_string = argv[3];
+	arch = ARCH_NONE;
+
+	if (!strncasecmp(arch_string, "arm", 4))
+		arch = ARCH_ARM;
+	else if (!strncasecmp(arch_string, "x86", 4))
+		arch = ARCH_X86;
+	else if (!strncasecmp(arch_string, "i386", 5))
+		arch = ARCH_X86;
+
 	char *romname = argv[1];
 	char *cmd = argv[2];
-	if (argc < 5) {
+	if (argc < 6) {
 		printf("not enough arguments to 'create'.\n");
 		return 1;
 	}
 
 	char* suffix;
-	uint32_t size = strtoul(argv[3], &suffix, 0);
+	uint32_t size = strtoul(argv[4], &suffix, 0);
 	if (tolower(suffix[0])=='k') {
 		size *= 1024;
 	}
 	if (tolower(suffix[0])=='m') {
 		size *= 1024 * 1024;
 	}
-	char *bootblock = argv[4];
+	char *bootblock = argv[5];
 	uint32_t align = 0;
 
-	if (argc > 5)
-		align = strtoul(argv[5], NULL, 0);
+	if (argc > 6)
+		align = strtoul(argv[6], NULL, 0);
+
+	if (arch == ARCH_NONE) {
+		printf("unknown architecture '%s'\n", arch_string);
+		return 1;
+	}
 
 	return create_cbfs_image(romname, size, bootblock, align);
 }
@@ -286,11 +303,13 @@ void usage(void)
 	     " add FILE NAME TYPE [base address]    Add a component\n"
 	     " add-payload FILE NAME [COMP] [base]  Add a payload to the ROM\n"
 	     " add-stage FILE NAME [COMP] [base]    Add a stage to the ROM\n"
-	     " create SIZE BOOTBLOCK [ALIGN]        Create a ROM file\n"
+	     " create ARCH SIZE BOOTBLOCK [ALIGN]   Create a ROM file\n"
 	     " locate FILE NAME ALIGN               Find a place for a file of that size\n"
 	     " print                                Show the contents of the ROM\n"
 	     " extract NAME FILE                    Extracts a raw payload from ROM\n"
 	     "\n"
+	     "ARCHes:\n"
+	     " x86, arm\n\n"
 	     "TYPEs:\n"
 	     );
 	print_supported_filetypes();
diff --git a/util/cbfstool/common.c b/util/cbfstool/common.c
index cbf0757..8059ca2 100644
--- a/util/cbfstool/common.c
+++ b/util/cbfstool/common.c
@@ -2,7 +2,9 @@
  * common utility functions for cbfstool
  *
  * Copyright (C) 2009 coresystems GmbH
- *                 written by Patrick Georgi <patrick.georgi@coresystems.de>
+ * written by Patrick Georgi <patrick.georgi@coresystems.de>
+ * Copyright (C) 2010 Google Inc
+ * Copyright (C) 2011 Yang Bai <hamo.by@gmail.com>
  *
  * 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
@@ -68,24 +70,105 @@ void *loadfile(const char *filename, uint32_t * romsize_p, void *content,
 struct cbfs_header *master_header;
 uint32_t phys_start, phys_end, align, romsize;
 void *offset;
+arch_t arch = ARCH_NONE;
 
 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;
+	switch (arch) {
+	case ARCH_ARM:
+		offset = romarea;
+		master_header = (struct cbfs_header *)
+		    phys_to_virt(0x20);
+		phys_start = (0 + ntohl(master_header->offset)) & 0xffffffff;
+		phys_end = romsize  & 0xffffffff;
+		break;
+	case ARCH_X86:
+		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;
+		break;
+	default:
+		printf("Unknown architecture\n");
+		exit(1);
+	}
 	align = ntohl(master_header->align);
 }
 
+static void auto_detect_architecture(void *romarea)
+{
+	struct cbfs_header *master_header;
+	uint32_t *header_ptr;
+
+	/* First, Let's try arm. */
+	do {
+		arch = ARCH_ARM;
+		// Set up physical/virtual mapping because we need to access the master header.
+		offset = romarea;
+		master_header = (struct cbfs_header *)phys_to_virt(0x20);
+		if((void *)master_header < romarea ||
+		   (void *)master_header >= (romarea + romsize - sizeof(struct cbfs_header)))
+			break;
+		if(master_header->magic == ntohl(0x4F524243) &&
+		   master_header->architecture == ntohl(CBFS_ARCHITECTURE_ARM))
+			return;
+	} while(0);
+
+	/* Now, Let's try x86. */
+	do {
+		arch = ARCH_X86;
+		// Set up physical/virtual mapping because we need to access the master header.
+		offset = romarea + romsize - 0x100000000ULL;
+		header_ptr = (uint32_t *)phys_to_virt(0xfffffffc);
+		if((void *)header_ptr < romarea ||
+		   (void *)header_ptr >= (romarea + romsize))
+			break;
+		master_header = (struct cbfs_header *)phys_to_virt(*header_ptr);
+		if((void *)master_header < romarea ||
+		   (void *)master_header >= (romarea + romsize - sizeof(struct cbfs_header)))
+			break;
+		if(master_header->magic == ntohl(0x4F524243) &&
+		   master_header->architecture == ntohl(CBFS_ARCHITECTURE_X86))
+			return;
+	} while(0);
+
+	/* Fallback to ARCH_NONE */
+	arch = ARCH_NONE;
+	return;
+}
+
+static struct arch_name {
+	arch_t arch;
+	const char *name;
+} arch_names[] = {
+	{ ARCH_X86, "x86" },
+	{ ARCH_ARM, "ARM" },
+	{ ARCH_NONE, "unknown" }
+};
+
+static const char *arch_string(void)
+{
+	int i;
+	const char *ret;
+	for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
+		ret = arch_names[i].name;
+		if (arch == arch_names[i].arch)
+			break;
+	}
+	// if it's an unknown/invalid architecture, the returned
+	// string will be "unknown" (ie. the last entry in the array)
+	return ret;
+}
+
 void *loadrom(const char *filename)
 {
 	void *romarea = loadfile(filename, &romsize, 0, SEEK_SET);
 	if (romarea == NULL)
 		return NULL;
+	auto_detect_architecture(romarea);
 	recalculate_rom_geometry(romarea);
 	return romarea;
 }
@@ -115,7 +198,7 @@ int cbfs_file_header(uint32_t physaddr)
 	return (strncmp(phys_to_virt(physaddr), "LARCHIVE", 8) == 0);
 }
 
-struct cbfs_file *cbfs_create_empty_file(uint32_t physaddr, uint32_t size)
+static struct cbfs_file *cbfs_create_empty_file(uint32_t physaddr, uint32_t size)
 {
 	struct cbfs_file *nextfile = (struct cbfs_file *)phys_to_virt(physaddr);
 	strncpy(nextfile->magic, "LARCHIVE", 8);
@@ -182,9 +265,9 @@ 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\nalignment: %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_string());
 	printf("%-30s %-10s %-12s Size\n", "Name", "Offset", "Type");
 	uint32_t current = phys_start;
 	while (current < phys_end) {
@@ -200,7 +283,7 @@ void print_cbfs_directory(const char *filename)
 			fname = "(empty)";
 
 		printf("%-30s 0x%-8x %-12s %d\n", fname,
-		       current - phys_start, strfiletype(ntohl(thisfile->type)),
+		       current - phys_start + ntohl(master_header->offset), strfiletype(ntohl(thisfile->type)),
 		       length);
 		current =
 		    ALIGN(current + ntohl(thisfile->len) +
@@ -283,18 +366,18 @@ int add_file_to_cbfs(void *content, uint32_t contentsize, uint32_t location)
 		    (struct cbfs_file *)phys_to_virt(current);
 		uint32_t length = ntohl(thisfile->len);
 
-		dprintf("at %x, %x bytes\n", current, length);
+		dprintf("at 0x%x, 0x%x bytes\n", current, length);
 		/* Is this a free chunk? */
 		if ((thisfile->type == CBFS_COMPONENT_DELETED)
 		    || (thisfile->type == CBFS_COMPONENT_NULL)) {
-			dprintf("null||deleted at %x, %x bytes\n", current,
+			dprintf("null||deleted at 0x%x, 0x%x bytes\n", current,
 				length);
 			/* if this is the right size, and if specified, the right location, use it */
 			if ((contentsize <= length)
 			    && ((location == 0) || (current == location))) {
 				if (contentsize < length) {
 					dprintf
-					    ("this chunk is %x bytes, we need %x. create a new chunk at %x with %x bytes\n",
+					    ("this chunk is 0x%x bytes, we need 0x%x. create a new chunk at 0x%x with 0x%x bytes\n",
 					     length, contentsize,
 					     ALIGN(current + contentsize,
 						   align),
@@ -326,7 +409,7 @@ int add_file_to_cbfs(void *content, uint32_t contentsize, uint32_t location)
 				    && ((location + contentsize) <=
 					(current + length))) {
 					/* Split it up. In the next iteration the code will be at the right place. */
-					dprintf("split up. new length: %x\n",
+					dprintf("split up. new length: 0x%x\n",
 						location - current -
 						ntohl(thisfile->offset));
 					thisfile->len =
@@ -399,33 +482,69 @@ 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;
 
 	uint32_t bootblocksize = 0;
-	loadfile(bootblock, &bootblocksize, romarea + romsize, SEEK_END);
-	struct cbfs_header *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(0);
-	((uint32_t *) phys_to_virt(0xfffffffc))[0] =
-	    virt_to_phys(master_header);
-
-	recalculate_rom_geometry(romarea);
-
-	struct cbfs_file *one_empty_file =
-	    cbfs_create_empty_file((0 - romsize) & 0xffffffff,
-				   romsize - bootblocksize -
-				   sizeof(struct cbfs_header) -
-				   sizeof(struct cbfs_file) - 16);
+	struct cbfs_header *master_header;
+	struct cbfs_file *one_empty_file;
+
+	switch (arch) {
+	case ARCH_ARM:
+		// Set up physical/virtual mapping
+		offset = romarea;
+
+		loadfile(bootblock, &bootblocksize, romarea, SEEK_SET);
+		master_header = (struct cbfs_header *)(romarea + 0x20);
+
+		master_header->magic = ntohl(0x4f524243);
+		master_header->version = ntohl(0x31313132);
+		master_header->romsize = htonl(romsize);
+		master_header->bootblocksize = htonl(bootblocksize);
+		master_header->align = htonl(align);
+		master_header->offset = htonl(ALIGN((bootblocksize), align));
+		master_header->architecture = htonl(CBFS_ARCHITECTURE_ARM);
+
+		recalculate_rom_geometry(romarea);
+
+		one_empty_file = cbfs_create_empty_file(ALIGN(bootblocksize, align),
+		   romsize - ALIGN(bootblocksize, align) 
+		   - sizeof(struct cbfs_file) );
+
+		break;
+	case ARCH_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(0x4f524243);
+		master_header->version = ntohl(0x31313132);
+		master_header->romsize = htonl(romsize);
+		master_header->bootblocksize = htonl(bootblocksize);
+		master_header->align = htonl(align);
+		master_header->offset = htonl(0);
+		master_header->architecture = htonl(CBFS_ARCHITECTURE_X86);
+
+		((uint32_t *) phys_to_virt(0xfffffffc))[0] =
+		    virt_to_phys(master_header);
+
+		recalculate_rom_geometry(romarea);
+
+		one_empty_file = cbfs_create_empty_file((0 - romsize) & 0xffffffff,
+					   romsize - bootblocksize -
+					   sizeof(struct cbfs_header) -
+					   sizeof(struct cbfs_file) - 16);
+		break;
+	case ARCH_NONE:
+		// Can not happen.
+		printf("You found a bug in cbfstool.\n");
+		exit(1);
+	}
 
 	writerom(romfile, romarea, romsize);
 	return 0;
@@ -453,6 +572,9 @@ uint32_t cbfs_find_location(const char *romfile, uint32_t filesize,
 			current += align;
 			continue;
 		}
+
+		dprintf("locate trying 0x%x\n", current);
+
 		struct cbfs_file *thisfile =
 		    (struct cbfs_file *)phys_to_virt(current);
 
diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h
index 8f397d8..dc99bd9 100644
--- a/util/cbfstool/common.h
+++ b/util/cbfstool/common.h
@@ -1,6 +1,8 @@
 /*
  * Copyright (C) 2009 coresystems GmbH
- *                 written by Patrick Georgi <patrick.georgi@coresystems.de>
+ * written by Patrick Georgi <patrick.georgi@coresystems.de>
+ * Copyright (C) 2010 Google Inc
+ * Copyright (C) 2011 Yang Bai <hamo.by@gmail.com>
  *
  * 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
@@ -24,9 +26,16 @@
 #define htonl ntohl
 #endif
 
+typedef enum {
+	ARCH_ARM,
+	ARCH_X86,
+	ARCH_NONE,
+} arch_t;
+
 extern void *offset;
 extern struct cbfs_header *master_header;
 extern uint32_t phys_start, phys_end, align, romsize;
+extern arch_t arch;
 
 static void *phys_to_virt(uint32_t addr)
 {
-- 
1.7.6

