[coreboot-gerrit] Patch set updated for coreboot: 4a26616 util/ifdtool: add option to change flash layout

Christopher Douglass (cdouglass.orion@gmail.com) gerrit at coreboot.org
Fri Feb 28 15:10:09 CET 2014


Christopher Douglass (cdouglass.orion at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5312

-gerrit

commit 4a2661620347a6e8deba6ed579f9c4ecf17c3c18
Author: Chris Douglass <cdouglass.orion at gmail.com>
Date:   Thu Feb 27 09:25:19 2014 -0500

    util/ifdtool: add option to change flash layout
    
    The new option "--newlayout <file>" will read <file> in flashrom's
    layout format and copy flash regions from the current flash image
    file to a new flash image file.
    
    If a region grows, the padding is added at the beginning of the target
    region in the new file so that the data is "right-aligned" to the
    end of the region.
    
    If a region shrinks, a warning is given and the tail end of existing
    data is copied to the target region in the new file.
    
    Regions of zero or negative size are ignored. (In the example below
    00fff000:00000fff regions are an artifact of the address encoding
    in the register fields.)
    
    Example Usage:
    
    Given a flash image for a board with a Sandy Bridge processor and
    Intel 6-Series chipset in the file vpx7654.bin
    
    ifdtool --layout layout.txt vpx7564.bin
    will yield the file layout.txt:
    	00000000:00000fff fd
    	00180000:003fffff bios
    	00001000:0017ffff me
    	00fff000:00000fff gbe
    	00fff000:00000fff pd
    
    Notice that the "bios" portion extends to the end of the 4MB flash.
    It may be edited to extend the bios portion to consume to the extent
    of an 8MB flash. like layout2.txt:
    	00000000:00000fff fd
    	00180000:007fffff bios
    	00001000:0017ffff me
    	00fff000:00000fff gbe
    	00fff000:00000fff pd
    
    ifdtool --newlayout layout.txt vpx7654.bin
    will create a file vpx7654.bin.new that is 8MB.
    
    Change-Id: I0e0925a725c40fa44d8c4b6e86552028779d0523
    Signed-off-by: Christopher Douglass <cdouglass.orion at gmail.com>
---
 util/ifdtool/ifdtool.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 234 insertions(+), 4 deletions(-)

diff --git a/util/ifdtool/ifdtool.c b/util/ifdtool/ifdtool.c
index b5a0ac2..28dbaac 100644
--- a/util/ifdtool/ifdtool.c
+++ b/util/ifdtool/ifdtool.c
@@ -95,6 +95,35 @@ static region_t get_region(frba_t *frba, int region_type)
 	return region;
 }
 
+static void set_region(frba_t *frba, int region_type, region_t region)
+{
+	switch (region_type) {
+	case 0:
+		frba->flreg0 = (((region.limit >> 12) & 0x7fff) << 16)
+			| ((region.base >> 12) & 0x7fff);
+		break;
+	case 1:
+		frba->flreg1 = (((region.limit >> 12) & 0x7fff) << 16)
+			| ((region.base >> 12) & 0x7fff);
+		break;
+	case 2:
+		frba->flreg2 = (((region.limit >> 12) & 0x7fff) << 16)
+			| ((region.base >> 12) & 0x7fff);
+		break;
+	case 3:
+		frba->flreg3 = (((region.limit >> 12) & 0x7fff) << 16)
+			| ((region.base >> 12) & 0x7fff);
+		break;
+	case 4:
+		frba->flreg4 = (((region.limit >> 12) & 0x7fff) << 16)
+			| ((region.base >> 12) & 0x7fff);
+		break;
+	default:
+		fprintf(stderr, "Invalid region type.\n");
+		exit (EXIT_FAILURE);
+	}
+}
+
 static const char *region_name(int region_type)
 {
 	if (region_type < 0 || region_type > 4) {
@@ -115,6 +144,20 @@ static const char *region_name_short(int region_type)
 	return region_names[region_type].terse;
 }
 
+static int region_num(const char *name)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		if (strcasecmp(name, region_names[i].pretty) == 0)
+			return i;
+		if (strcasecmp(name, region_names[i].terse) == 0)
+			return i;
+	}
+
+	return -1;
+}
+
 static const char *region_filename(int region_type)
 {
 	static const char *region_filenames[5] = {
@@ -641,6 +684,179 @@ void inject_region(char *filename, char *image, int size, int region_type,
 	write_image(filename, image, size);
 }
 
+unsigned int next_pow2(unsigned int x)
+{
+	unsigned int y = 1;
+	if (x == 0)
+		return 0;
+	while (y <= x)
+		y = y << 1;
+
+	return y;
+}
+
+/**
+ * Determine if two memory regions overlap.
+ *
+ * @param r1, r2 Memory regions to compare.
+ * @return 0 if the two regions are seperate
+ * @return 1 if the two regions overlap
+ */
+static int regions_collide(region_t r1, region_t r2)
+{
+	if ((r1.size == 0) || (r2.size == 0))
+		return 0;
+
+	if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
+	     ((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
+		return 1;
+
+	return 0;
+}
+
+void new_layout(char *filename, char *image, int size, char *layout_fname)
+{
+	FILE *romlayout;
+	char tempstr[256];
+	char layout_region_name[256];
+	int i, j;
+	int region_number;
+	region_t current_regions[5];
+	region_t new_regions[5];
+	int new_extent = 0;
+	char *new_image;
+
+	/* load current descriptor map and regions */
+	fdbar_t *fdb = find_fd(image, size);
+	if (!fdb)
+		exit(EXIT_FAILURE);
+
+	frba_t *frba =
+	    (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
+
+	for (i = 0; i < 5; i++) {
+		current_regions[i] = get_region(frba, i);
+		new_regions[i] = get_region(frba, i);
+	}
+
+	/* read new layout */
+	romlayout = fopen(layout_fname, "r");
+
+	if (!romlayout) {
+		perror("Could not read layout file.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	while (!feof(romlayout)) {
+		char *tstr1, *tstr2;
+
+		if (2 != fscanf(romlayout, "%s %s\n", tempstr,
+					layout_region_name))
+			continue;
+
+		region_number = region_num(layout_region_name);
+		if (region_number < 0)
+			continue;
+
+		tstr1 = strtok(tempstr, ":");
+		tstr2 = strtok(NULL, ":");
+		if (!tstr1 || !tstr2) {
+			fprintf(stderr, "Could not parse layout file.\n");
+			exit(EXIT_FAILURE);
+		}
+		new_regions[region_number].base = strtol(tstr1,
+				(char **)NULL, 16);
+		new_regions[region_number].limit = strtol(tstr2,
+				(char **)NULL, 16);
+		new_regions[region_number].size =
+			new_regions[region_number].limit -
+			new_regions[region_number].base + 1;
+
+		if (new_regions[region_number].size < 0)
+			new_regions[region_number].size = 0;
+	}
+	fclose(romlayout);
+
+	/* check new layout */
+	for (i = 0; i < 5; i++) {
+		if (new_regions[i].size == 0)
+			continue;
+
+		if (new_regions[i].size < current_regions[i].size) {
+			printf("DANGER: Region %s is shrinking.\n",
+					region_name(i));
+			printf("    The region will be truncated to fit.\n");
+			printf("    This may result in an unusable image.\n");
+		}
+
+		for (j = i + 1; j < 5; j++) {
+			if (regions_collide(new_regions[i], new_regions[j])) {
+				fprintf(stderr, "Regions would overlap.\n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		/* detect if the image size should grow */
+		if (new_extent < new_regions[i].limit)
+			new_extent = new_regions[i].limit;
+	}
+
+	new_extent = next_pow2(new_extent - 1);
+	if (new_extent != size) {
+		printf("The image has changed in size.\n");
+		printf("The old image is %d bytes.\n", size);
+		printf("The new image is %d bytes.\n", new_extent);
+	}
+
+	/* copy regions to a new image */
+	new_image = malloc(new_extent);
+	memset(new_image, 0xff, new_extent);
+	for (i = 0; i < 5; i++) {
+		int copy_size = new_regions[i].size;
+		int offset_current = 0, offset_new = 0;
+		region_t current = current_regions[i];
+		region_t new = new_regions[i];
+
+		if (new.size == 0)
+			continue;
+
+		if (new.size > current.size) {
+			/* copy from the end of the current region */
+			copy_size = current.size;
+			offset_new = new.size - current.size;
+		}
+
+		if (new.size < current.size) {
+			/* copy to the end of the new region */
+			offset_current = current.size - new.size;
+		}
+
+		printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
+				region_name(i), copy_size);
+		printf("   from %08x+%08x:%08x (%10d)\n", current.base,
+				offset_current, current.limit, current.size);
+		printf("     to %08x+%08x:%08x (%10d)\n", new.base,
+				offset_new, new.limit, new.size);
+
+		memcpy(new_image + new.base + offset_new,
+				image + current.base + offset_current,
+				copy_size);
+	}
+
+	/* update new descriptor regions */
+	fdb = find_fd(new_image, new_extent);
+	if (!fdb)
+		exit(EXIT_FAILURE);
+
+	frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
+	for (i = 1; i < 5; i++) {
+		set_region(frba, i, new_regions[i]);
+	}
+
+	write_image(filename, new_image, new_extent);
+	free(new_image);
+}
+
 static void print_version(void)
 {
 	printf("ifdtool v%s -- ", IFDTOOL_VERSION);
@@ -665,6 +881,7 @@ static void print_usage(const char *name)
 	       "   -f | --layout <filename>          dump regions into a flashrom layout file\n"
 	       "   -x | --extract:                   extract intel fd modules\n"
 	       "   -i | --inject <region>:<module>   inject file <module> into region <region>\n"
+	       "   -n | --newlayout <filename>       update regions using a flashrom layout file\n"
 	       "   -s | --spifreq <20|33|50>         set the SPI frequency\n"
 	       "   -e | --em100                      set SPI frequency to 20MHz and disable\n"
 	       "                                     Dual Output Fast Read Support\n"
@@ -681,7 +898,7 @@ int main(int argc, char *argv[])
 	int opt, option_index = 0;
 	int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
 	int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
-	int mode_layout = 0;
+	int mode_layout = 0, mode_newlayout = 0;
 	char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
 	int region_type = -1, inputfreq = 0;
 	enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
@@ -691,6 +908,7 @@ int main(int argc, char *argv[])
 		{"layout", 1, NULL, 'f'},
 		{"extract", 0, NULL, 'x'},
 		{"inject", 1, NULL, 'i'},
+		{"newlayout", 1, NULL, 'n'},
 		{"spifreq", 1, NULL, 's'},
 		{"em100", 0, NULL, 'e'},
 		{"lock", 0, NULL, 'l'},
@@ -700,7 +918,7 @@ int main(int argc, char *argv[])
 		{0, 0, 0, 0}
 	};
 
-	while ((opt = getopt_long(argc, argv, "df:xi:s:eluvh?",
+	while ((opt = getopt_long(argc, argv, "df:xi:n:s:eluvh?",
 				  long_options, &option_index)) != EOF) {
 		switch (opt) {
 		case 'd':
@@ -748,6 +966,15 @@ int main(int argc, char *argv[])
 			}
 			mode_inject = 1;
 			break;
+		case 'n':
+			mode_newlayout = 1;
+			layout_fname = strdup(optarg);
+			if (!layout_fname) {
+				fprintf(stderr, "No layout file specified\n");
+				print_usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+			break;
 		case 's':
 			// Parse the requested SPI frequency
 			inputfreq = strtol(optarg, NULL, 0);
@@ -800,7 +1027,7 @@ int main(int argc, char *argv[])
 	}
 
 	if ((mode_dump + mode_layout + mode_extract + mode_inject +
-		(mode_spifreq | mode_em100 | mode_unlocked |
+		mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
 		 mode_locked)) > 1) {
 		fprintf(stderr, "You may not specify more than one mode.\n\n");
 		print_usage(argv[0]);
@@ -808,7 +1035,7 @@ int main(int argc, char *argv[])
 	}
 
 	if ((mode_dump + mode_layout + mode_extract + mode_inject +
-	     mode_spifreq + mode_em100 + mode_locked +
+	     mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
 	     mode_unlocked) == 0) {
 		fprintf(stderr, "You need to specify a mode.\n\n");
 		print_usage(argv[0]);
@@ -862,6 +1089,9 @@ int main(int argc, char *argv[])
 		inject_region(filename, image, size, region_type,
 				region_fname);
 
+	if (mode_newlayout)
+		new_layout(filename, image, size, layout_fname);
+
 	if (mode_spifreq)
 		set_spi_frequency(filename, image, size, spifreq);
 



More information about the coreboot-gerrit mailing list