util/blobtool: Add new tool for compiling/decompiling data blobs

Given a specification of bitfields defined e.g. as follows:

	specfile:
		{
			"field1" : 8,
			"field2" : 4,
			"field3" : 4
		}
and a set of values for setting defaults:
	setterfile:
		{
			"field1" = 0xff,
			"field2" = 0xf,
			"field3" = 0xf
		}

You can generate a binary packed blob as follows:
	./blobtool specfile setterfile binaryoutput
	binaryoutput:	ff ff

The reverse is also possible, i.e. you can regenerate the setter:
	./blobtool -d specfile binaryoutput setterorig
	setterorig:
		# AUTOGENERATED SETTER BY BLOBTOOL
		{
			"field1" = 0xff,
			"field2" = 0xf,
			"field3" = 0xf
		}

This tool comes with spec/set files for X200 flash descriptor
and ICH9M GbE region, and can be extended or used to decompile
other data blobs with known specs.

Change-Id: I744d6b421003feb4fc460133603af7e6bd80b1d6
Signed-off-by: Damien Zammit <damien@zamaudio.com>
Reviewed-on: https://review.coreboot.org/17445
Tested-by: build bot (Jenkins)
Reviewed-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
Reviewed-by: Martin Roth <martinroth@google.com>
diff --git a/util/blobtool/Makefile b/util/blobtool/Makefile
new file mode 100644
index 0000000..ee706db
--- /dev/null
+++ b/util/blobtool/Makefile
@@ -0,0 +1,29 @@
+CC = gcc
+YACC = bison
+LEX = flex
+TARGET=blobtool
+
+$(TARGET): $(TARGET).lex.o $(TARGET).tab.o
+	$(CC) $^ -Wall -Wno-unused-function -g -lfl -o $@
+
+$(TARGET).lex.c: $(TARGET).l $(TARGET).tab.h
+	$(LEX) -o $(patsubst $(TARGET).l,$(TARGET).lex.c,$<) $<
+
+$(TARGET).tab.c $(TARGET).tab.h: $(TARGET).y
+	$(YACC) -d $<
+
+# Use this target to generate GbE for X200
+gen-gbe-ich9m:
+	./blobtool gbe-ich9m.spec gbe-ich9m.set gbe1.bin
+	# duplicate binary as per spec
+	cat gbe1.bin gbe1.bin > flashregion_3_gbe.bin
+	rm -f gbe1.bin
+
+# Use this target to generate IFD for X200
+gen-ifd-x200:
+	./blobtool ifd-x200.spec ifd-x200.set flashregion_0_fd.bin
+
+.PHONY: clean gen-gbe-ich9m gen-ifd-x200
+
+clean:
+	rm -f *.lex.c *.tab.c *.tab.h *.o blobtool flashregion_0_fd.bin flashregion_3_gbe.bin
diff --git a/util/blobtool/blobtool.l b/util/blobtool/blobtool.l
new file mode 100644
index 0000000..43c2b15
--- /dev/null
+++ b/util/blobtool/blobtool.l
@@ -0,0 +1,145 @@
+/*
+ * blobtool - Compiler/Decompiler for data blobs with specs
+ * Copyright (C) 2017 Damien Zammit <damien@zamaudio.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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "blobtool.tab.h"
+
+extern struct blob binary;
+
+unsigned int parsehex (char *s)
+{
+	unsigned int i, nib, val = 0;
+	unsigned int nibs = strlen(s) - 2;
+
+	for (i = 2; i < nibs + 2; i++) {
+		if (s[i] >= '0' && s[i] <= '9') {
+			nib = s[i] - '0';
+		} else if (s[i] >= 'a' && s[i] <= 'f') {
+			nib = s[i] - 'a' + 10;
+		} else if (s[i] >= 'A' && s[i] <= 'F') {
+			nib = s[i] - 'A' + 10;
+		} else {
+			return 0;
+		}
+		val |= nib << (((nibs - 1) - (i - 2)) * 4);
+	}
+	return val;
+}
+
+char* stripquotes (char *string)
+{
+	char *stripped;
+	unsigned int len = strlen(string);
+	if (len >= 2 && string[0] == '\"' && string[len-1] == '\"') {
+		stripped = (char *) malloc (len - 2 + 1);
+		snprintf (stripped, len - 2 + 1, "%s", string+1);
+		stripped[len-2] = '\0';
+		return stripped;
+	} else {
+		return 0;
+	}
+}
+
+%}
+
+%option noyywrap
+%option nounput
+
+DIGIT1to9 [1-9]
+DIGIT [0-9]
+DIGITS {DIGIT}+
+INT {DIGIT}|{DIGIT1to9}{DIGITS}|-{DIGIT}|-{DIGIT1to9}{DIGITS}
+FRAC [.]{DIGITS}
+E [eE][+-]?
+EXP {E}{DIGITS}
+HEX_DIGIT [0-9a-fA-F]
+HEX_DIGITS {HEX_DIGIT}+
+NUMBER {INT}|{INT}{FRAC}|{INT}{EXP}|{INT}{FRAC}{EXP}
+UNICODECHAR \\u{HEX_DIGIT}{HEX_DIGIT}{HEX_DIGIT}{HEX_DIGIT}
+ALPHA [a-zA-Z]
+SPECIAL [()\[\]"'@_\-+:;/\\.,<> 	]
+VARCHAR {ALPHA}|{DIGIT}|{SPECIAL}
+CHAR {VARCHAR}|{UNICODECHAR}
+CHARS {CHAR}+
+QUOTE ["]
+HEX_PREFIX [0][x]
+HEX {HEX_PREFIX}{HEX_DIGITS}
+STRING {QUOTE}{QUOTE}|{QUOTE}{CHARS}{QUOTE}
+COMMENT [#]{CHARS}[\n]|[#]\n
+
+%%
+
+{STRING} {
+    yylval.str = stripquotes(yytext);
+    return name;
+};
+
+{NUMBER} {
+    yylval.u32 = atoi(yytext);
+    return val;
+};
+
+{HEX} {
+    yylval.u32 = parsehex(yytext);
+    return val;
+};
+
+\{ {
+    return '{';
+};
+
+\} {
+    return '}';
+};
+
+\[ {
+    return '[';
+};
+
+\] {
+    return ']';
+};
+
+, {
+    return ',';
+};
+
+: {
+    return ':';
+};
+
+= {
+    return '=';
+};
+
+[ \t\n]+ /* ignore whitespace */;
+
+{COMMENT} /* ignore comments */
+
+\% {
+    return '%';
+};
+
+<<EOF>> { return eof; };
+
+%%
+
+void set_input_string(char* in) {
+	yy_scan_string(in);
+}
+
diff --git a/util/blobtool/blobtool.y b/util/blobtool/blobtool.y
new file mode 100644
index 0000000..909102d
--- /dev/null
+++ b/util/blobtool/blobtool.y
@@ -0,0 +1,537 @@
+/*
+ * blobtool - Compiler/Decompiler for data blobs with specs
+ * Copyright (C) 2017 Damien Zammit <damien@zamaudio.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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+%{
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+//#define YYDEBUG 1
+int yylex (void);
+void yyerror (char const *);
+
+struct field {
+	char *name;
+	unsigned int width;
+	unsigned int value;
+	struct field *next;
+};
+
+extern struct field *sym_table;
+struct field *putsym (char const *, unsigned int);
+struct field *getsym (char const *);
+
+struct field *sym_table;
+struct field *sym_table_tail;
+
+FILE* fp;
+
+/* Bit array intermediary representation */
+struct blob {
+	unsigned int bloblen;
+	unsigned char *blb;
+	unsigned short checksum;
+	unsigned char *actualblob;
+	unsigned int lenactualblob;
+};
+
+#define VALID_BIT 0x80
+#define MAX_WIDTH 32
+#define CHECKSUM_SIZE 16
+
+struct blob *binary;
+
+unsigned char* value_to_bits (unsigned int v, unsigned int w)
+{
+	unsigned int i;
+	unsigned char* bitarr;
+
+	if (w > MAX_WIDTH) w = MAX_WIDTH;
+	bitarr = (unsigned char *) malloc (w * sizeof (unsigned char));
+	memset (bitarr, 0, w);
+
+	for (i = 0; i < w; i++) {
+		bitarr[i] = VALID_BIT | ((v & (1 << i)) >> i);
+	}
+	return bitarr;
+}
+
+/* Store each bit of a bitfield in a new byte sequentially 0x80 or 0x81 */
+void append_field_to_blob (unsigned char b[], unsigned int w)
+{
+	unsigned int i, j;
+	binary->blb = (unsigned char *) realloc (binary->blb, binary->bloblen + w);
+	for (j = 0, i = binary->bloblen; i < binary->bloblen + w; i++, j++) {
+		binary->blb[i] = VALID_BIT | (b[j] & 1);
+		//fprintf (stderr, "blob[%d] = %d\n", i, binary->blb[i] & 1);
+	}
+	binary->bloblen += w;
+}
+
+void set_bitfield(char *name, unsigned int value)
+{
+	unsigned long long i;
+	struct field *bf = getsym (name);
+	if (bf) {
+		bf->value = value & 0xffffffff;
+		i = (1 << bf->width) - 1;
+		if (bf->width > 8 * sizeof (unsigned int)) {
+			fprintf(stderr, "Overflow in bitfield, truncating bits to fit\n");
+			bf->value = value & i;
+		}
+		//fprintf(stderr, "Setting `%s` = %d\n", bf->name, bf->value);
+	} else {
+		fprintf(stderr, "Can't find bitfield `%s` in spec\n", name);
+	}
+}
+
+void set_bitfield_array(char *name, unsigned int n, unsigned int value)
+{
+	unsigned int i;
+	unsigned int len = strlen (name);
+	char *namen = (char *) malloc ((len + 9) * sizeof (char));
+	for (i = 0; i < n; i++) {
+		snprintf (namen, len + 8, "%s%x", name, i);
+		set_bitfield (namen, value);
+	}
+	free(namen);
+}
+
+void create_new_bitfield(char *name, unsigned int width)
+{
+	struct field *bf;
+
+	if (!(bf = putsym (name, width))) return;
+	//fprintf(stderr, "Added bitfield `%s` : %d\n", bf->name, width);
+}
+
+void create_new_bitfields(char *name, unsigned int n, unsigned int width)
+{
+	unsigned int i;
+	unsigned int len = strlen (name);
+	char *namen = (char *) malloc ((len + 9) * sizeof (char));
+	for (i = 0; i < n; i++) {
+		snprintf (namen, len + 8, "%s%x", name, i);
+		create_new_bitfield (namen, width);
+	}
+	free(namen);
+}
+
+struct field *putsym (char const *sym_name, unsigned int w)
+{
+	if (getsym(sym_name)) {
+		fprintf(stderr, "Cannot add duplicate named bitfield `%s`\n", sym_name);
+		return 0;
+	}
+	struct field *ptr = (struct field *) malloc (sizeof (struct field));
+	ptr->name = (char *) malloc (strlen (sym_name) + 1);
+	strcpy (ptr->name, sym_name);
+	ptr->width = w;
+	ptr->value = 0;
+	ptr->next = (struct field *)0;
+	if (sym_table_tail) {
+		sym_table_tail->next = ptr;
+	} else {
+		sym_table = ptr;
+	}
+	sym_table_tail = ptr;
+	return ptr;
+}
+
+struct field *getsym (char const *sym_name)
+{
+	struct field *ptr;
+	for (ptr = sym_table; ptr != (struct field *) 0;
+			ptr = (struct field *)ptr->next) {
+		if (strcmp (ptr->name, sym_name) == 0)
+			return ptr;
+	}
+	return 0;
+}
+
+void dump_all_values (void)
+{
+	struct field *ptr;
+	for (ptr = sym_table; ptr != (struct field *) 0;
+			ptr = (struct field *)ptr->next) {
+		fprintf(stderr, "%s = %d (%d bits)\n",
+				ptr->name,
+				ptr->value,
+				ptr->width);
+	}
+}
+
+void empty_field_table(void)
+{
+	struct field *ptr;
+	struct field *ptrnext;
+
+	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptrnext) {
+		if (ptr) {
+			ptrnext = ptr->next;
+			free(ptr);
+		} else {
+			ptrnext = (struct field *) 0;
+		}
+	}
+	sym_table = 0;
+	sym_table_tail = 0;
+}
+
+void create_binary_blob (void)
+{
+	if (binary && binary->blb) {
+		free(binary->blb);
+		free(binary);
+	}
+	binary = (struct blob *) malloc (sizeof (struct blob));
+	binary->blb = (unsigned char *) malloc (sizeof (unsigned char));
+	binary->bloblen = 0;
+	binary->blb[0] = VALID_BIT;
+}
+
+void interpret_next_blob_value (struct field *f)
+{
+	int i;
+	unsigned int v = 0;
+
+	if (binary->bloblen >= binary->lenactualblob * 8) {
+		f->value = 0;
+		return;
+	}
+
+	for (i = 0; i < f->width; i++) {
+		v |= (binary->blb[binary->bloblen++] & 1) << i;
+	}
+
+	f->value = v;
+}
+
+/* {}%BIN -> {} */
+void generate_setter_bitfields(unsigned char *bin)
+{
+	unsigned int i;
+	struct field *ptr;
+
+	/* Convert bytes to bit array */
+	for (i = 0; i < binary->lenactualblob; i++) {
+		append_field_to_blob (value_to_bits(bin[i], 8), 8);
+	}
+
+	/* Reset blob position to zero */
+	binary->bloblen = 0;
+
+	fprintf (fp, "# AUTOGENERATED SETTER BY BLOBTOOL\n{\n");
+
+	/* Traverse spec and output bitfield setters based on blob values */
+	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
+
+		interpret_next_blob_value(ptr);
+		fprintf (fp, "\t\"%s\" = 0x%x,\n", ptr->name, ptr->value);
+	}
+	fseek(fp, -2, SEEK_CUR);
+	fprintf (fp, "\n}\n");
+}
+
+void generate_binary_with_gbe_checksum(void)
+{
+	int i;
+	unsigned short checksum;
+
+	/* traverse spec, push to blob and add up for checksum */
+	struct field *ptr;
+	unsigned int uptochksum = 0;
+	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
+		if (strcmp (ptr->name, "checksum_gbe") == 0) {
+			/* Stop traversing because we hit checksum */
+			ptr = ptr->next;
+			break;
+		}
+		append_field_to_blob (
+			value_to_bits(ptr->value, ptr->width),
+			ptr->width);
+		uptochksum += ptr->width;
+	}
+
+	/* deserialize bits of blob up to checksum */
+	for (i = 0; i < uptochksum; i += 8) {
+		unsigned char byte = (((binary->blb[i+0] & 1) << 0)
+					| ((binary->blb[i+1] & 1) << 1)
+					| ((binary->blb[i+2] & 1) << 2)
+					| ((binary->blb[i+3] & 1) << 3)
+					| ((binary->blb[i+4] & 1) << 4)
+					| ((binary->blb[i+5] & 1) << 5)
+					| ((binary->blb[i+6] & 1) << 6)
+					| ((binary->blb[i+7] & 1) << 7)
+		);
+		fprintf(fp, "%c", byte);
+
+		/* incremental 16 bit checksum */
+		if ((i % 16) < 8) {
+			binary->checksum += byte;
+		} else {
+			binary->checksum += byte << 8;
+		}
+	}
+
+	checksum = (0xbaba - binary->checksum) & 0xffff;
+
+	/* Now write checksum */
+	set_bitfield ("checksum_gbe", checksum);
+
+	fprintf(fp, "%c", checksum & 0xff);
+	fprintf(fp, "%c", (checksum & 0xff00) >> 8);
+
+	append_field_to_blob (value_to_bits(checksum, 16), 16);
+
+	for (; ptr != (struct field *) 0; ptr = ptr->next) {
+		append_field_to_blob (
+			value_to_bits(ptr->value, ptr->width), ptr->width);
+	}
+
+	/* deserialize rest of blob past checksum */
+	for (i = uptochksum + CHECKSUM_SIZE; i < binary->bloblen; i += 8) {
+		unsigned char byte = (((binary->blb[i+0] & 1) << 0)
+					| ((binary->blb[i+1] & 1) << 1)
+					| ((binary->blb[i+2] & 1) << 2)
+					| ((binary->blb[i+3] & 1) << 3)
+					| ((binary->blb[i+4] & 1) << 4)
+					| ((binary->blb[i+5] & 1) << 5)
+					| ((binary->blb[i+6] & 1) << 6)
+					| ((binary->blb[i+7] & 1) << 7)
+		);
+		fprintf(fp, "%c", byte);
+	}
+}
+
+/* {}{} -> BIN */
+void generate_binary(void)
+{
+	unsigned int i;
+	struct field *ptr;
+
+	if (binary->bloblen % 8) {
+		fprintf (stderr, "ERROR: Spec must be multiple of 8 bits wide\n");
+		exit (1);
+	}
+
+	if (getsym ("checksum_gbe")) {
+		generate_binary_with_gbe_checksum();
+		return;
+	}
+
+	/* traverse spec, push to blob */
+	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
+		append_field_to_blob (
+			value_to_bits(ptr->value, ptr->width),
+			ptr->width);
+	}
+
+	/* deserialize bits of blob */
+	for (i = 0; i < binary->bloblen; i += 8) {
+		unsigned char byte = (((binary->blb[i+0] & 1) << 0)
+				| ((binary->blb[i+1] & 1) << 1)
+				| ((binary->blb[i+2] & 1) << 2)
+				| ((binary->blb[i+3] & 1) << 3)
+				| ((binary->blb[i+4] & 1) << 4)
+				| ((binary->blb[i+5] & 1) << 5)
+				| ((binary->blb[i+6] & 1) << 6)
+				| ((binary->blb[i+7] & 1) << 7)
+		);
+		fprintf(fp, "%c", byte);
+	}
+}
+
+%}
+
+%union
+{
+	char *str;
+	unsigned int u32;
+	unsigned int *u32array;
+	unsigned char u8;
+	unsigned char *u8array;
+}
+
+%token <str> name
+%token <u32> val
+%token <u32array> vals
+%token <u8> hexbyte
+%token <u8array> binblob
+%token <u8> eof
+
+%left '%'
+%left '{' '}'
+%left ','
+%left ':'
+%left '='
+
+%%
+
+input:
+  /* empty */
+| input spec setter eof		{ empty_field_table(); YYACCEPT;}
+| input spec blob		{ fprintf (stderr, "Parsed all bytes\n");
+				  empty_field_table(); YYACCEPT;}
+;
+
+blob:
+  '%' eof			{ generate_setter_bitfields(binary->actualblob); }
+;
+
+spec:
+  '{' '}'		{	fprintf (stderr, "No spec\n"); }
+| '{' specmembers '}'	{	fprintf (stderr, "Parsed all spec\n");
+				create_binary_blob(); }
+;
+
+specmembers:
+  specpair
+| specpair ',' specmembers
+;
+
+specpair:
+  name ':' val		{	create_new_bitfield($1, $3); }
+| name '[' val ']' ':' val	{ create_new_bitfields($1, $3, $6); }
+;
+
+setter:
+  '{' '}'		{	fprintf (stderr, "No values\n"); }
+| '{' valuemembers '}'	{	fprintf (stderr, "Parsed all values\n");
+				generate_binary(); }
+;
+
+valuemembers:
+  setpair
+| setpair ',' valuemembers
+;
+
+setpair:
+  name '=' val		{	set_bitfield($1, $3); }
+| name '[' val ']' '=' val	{ set_bitfield_array($1, $3, $6); }
+;
+
+%%
+
+/* Called by yyparse on error.  */
+void yyerror (char const *s)
+{
+	fprintf (stderr, "yyerror: %s\n", s);
+}
+
+/* Declarations */
+void set_input_string(char* in);
+
+/* This function parses a string */
+int parse_string(unsigned char* in) {
+	set_input_string ((char *)in);
+	return yyparse ();
+}
+
+int main (int argc, char *argv[])
+{
+	unsigned int lenspec, lensetter;
+	unsigned char *parsestring;
+	unsigned char c;
+	unsigned int pos = 0;
+	int ret = 0;
+
+#if YYDEBUG == 1
+	yydebug = 1;
+#endif
+	create_binary_blob();
+	binary->lenactualblob = 0;
+
+	if (argc == 4 && strcmp(argv[1], "-d") != 0) {
+		/* Compile mode */
+
+		/* Load Spec */
+		fp = fopen(argv[1], "r");
+		fseek(fp, 0, SEEK_END);
+		lenspec = ftell(fp);
+		fseek(fp, 0, SEEK_SET);
+		parsestring = (unsigned char *) malloc (lenspec);
+		if (!parsestring) {
+			printf("Out of memory\n");
+			exit(1);
+		}
+		fread(parsestring, 1, lenspec, fp);
+		fclose(fp);
+
+		/* Load Setter */
+		fp = fopen(argv[2], "r");
+		fseek(fp, 0, SEEK_END);
+		lensetter = ftell(fp);
+		fseek(fp, 0, SEEK_SET);
+		parsestring = (unsigned char *) realloc (parsestring,
+							lenspec + lensetter);
+		if (!parsestring) {
+			printf("Out of memory\n");
+			exit(1);
+		}
+		fread(parsestring + lenspec, 1, lensetter, fp);
+		fclose(fp);
+
+		/* Open output and parse string - output to fp */
+		fp = fopen(argv[3], "wb");
+		ret = parse_string(parsestring);
+		free(parsestring);
+	} else if (argc == 5 && strcmp (argv[1], "-d") == 0) {
+		/* Decompile mode */
+
+		/* Load Spec */
+		fp = fopen(argv[2], "r");
+		fseek(fp, 0, SEEK_END);
+		lenspec = ftell(fp);
+		fseek(fp, 0, SEEK_SET);
+		parsestring = (unsigned char *) malloc (lenspec + 1);
+		fread(parsestring, 1, lenspec, fp);
+		if (!parsestring) {
+			printf("Out of memory\n");
+			exit(1);
+		}
+		fclose(fp);
+
+		/* Add binary read trigger token */
+		parsestring[lenspec] = '%';
+
+		/* Load Actual Binary */
+		fp = fopen(argv[3], "rb");
+		fseek(fp, 0, SEEK_END);
+		binary->lenactualblob = ftell(fp);
+		fseek(fp, 0, SEEK_SET);
+		binary->actualblob = (unsigned char *) malloc (binary->lenactualblob);
+		if (!binary->actualblob) {
+			printf("Out of memory\n");
+			exit(1);
+		}
+		fread(binary->actualblob, 1, binary->lenactualblob, fp);
+		fclose(fp);
+
+		/* Open output and parse - output to fp */
+		fp = fopen(argv[4], "w");
+		ret = parse_string(parsestring);
+		free(parsestring);
+		free(binary->actualblob);
+		fclose(fp);
+	} else {
+		printf("Usage: Compile mode\n\n");
+		printf("       blobtool    spec  setter  binaryoutput\n");
+		printf("                  (file) (file)     (file)\n");
+		printf(" OR  : Decompile mode\n\n");
+		printf("       blobtool -d spec  binary  setteroutput\n");
+	}
+	return ret;
+}
diff --git a/util/blobtool/gbe-ich9m.set b/util/blobtool/gbe-ich9m.set
new file mode 100644
index 0000000..01f85ab
--- /dev/null
+++ b/util/blobtool/gbe-ich9m.set
@@ -0,0 +1,88 @@
+#
+# Copyright (C) 2017 Damien Zammit <damien@zamaudio.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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+
+# GbE values for ICH9M
+{
+	# Hardcoded chipset values
+	"reserved04" = 0xffff,
+	"version05" = 0x1083,
+	"reserved06" = 0xffff,
+	"reserved07" = 0xffff,
+	"pbalow" = 0xffff,
+	"pbahigh" = 0xffff,
+	"pci_loadvid" = 1,
+	"pci_loadssid" = 1,
+	"pci_pmen" = 1,
+	"pci_auxpwr" = 1,
+	"pci_reserved4" = 1,
+	"sh_phy_enpwrdown" = 1,
+	"sh_reserved1" = 0x5,
+	"sh_reserved3" = 1,
+	"sh_sign" = 0x2,
+	"cw1_extcfgptr" = 0x020,
+	"cw1_oemload" = 1,
+	"cw1_reserved1" = 1,
+	"cw2_extphylen" = 0x05,
+	"l1_reserved2" = 1,
+	"l1_reserved4" = 1,
+	"l1_lplu_non_d0a" = 1,
+	"l1_gbedis_non_d0a" = 1,
+	"reserved19" = 0x2b40,
+	"reserved1a" = 0x0043,
+	"reserved1c" = 0x10f5,
+	"reserved1d" = 0xbaad,
+	"_82567lm" = 0x10f5,
+	"_82567lf" = 0x10bf,
+	"reserved20" = 0xbaad,
+	"_82567v" = 0x10cb,
+	"reserved22_0" = 0xbaad,
+	"reserved22_1" = 0xbaad,
+
+	# Hardcoded PXE setup (disabled)
+	"pxe30_defbootsel" = 0x3,
+	"pxe30_ctrlsprompt" = 0x3,
+	"pxe30_pxeabsent" = 1,
+	"pxe31_disablemenu" = 1,
+	"pxe31_disabletitle" = 1,
+	"pxe31_signature" = 1,
+	"pxe32_buildnum" = 0x18,
+	"pxe32_minorversion" = 0x3,
+	"pxe32_majorversion" = 0x1,
+	"pxe33_basecodeabsent" = 1,
+	"pxe33_undipresent" = 1,
+	"pxe33_reserved1" = 1,
+	"pxe33_signature" = 1,
+	"pxe_padding"[11] = 0xffff,
+
+	# GbE power settings
+	"lanpwr_d3pwr" = 1,
+	"lanpwr_d0pwr" = 13,
+
+	# GbE LED modes
+	"l1_led1mode" = 0xb,
+	"l1_led1blinks" = 1,
+	"l02_led0mode" = 0x2,
+	"l02_led2mode" = 0x1,
+
+	# Padding 0xf80 bytes
+	"padding"[0xf80] = 0xff,
+
+	# TODO: make command line switch for these
+
+	# Configurable PCI IDs
+	"ssdid" = 0x20ee,
+	"ssvid" = 0x17aa,
+	"did" = 0x10f5,
+	"vid" = 0x8086
+}
diff --git a/util/blobtool/gbe-ich9m.spec b/util/blobtool/gbe-ich9m.spec
new file mode 100644
index 0000000..45eed0e
--- /dev/null
+++ b/util/blobtool/gbe-ich9m.spec
@@ -0,0 +1,142 @@
+#
+# Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+#                    Leah Rowe <info@minifree.org>
+# Copyright (C) 2017 Damien Zammit <damien@zamaudio.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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+#
+# Datasheets:
+#
+# http://www.intel.co.uk/content/dam/doc/application-note/i-o-controller-hub-9m-82567lf-lm-v-nvm-map-appl-note.pdf
+# https://communities.intel.com/community/wired/blog/2010/10/14/how-to-basic-eeprom-checksums
+
+# The datasheet says that this spec covers the following pci ids:
+# 8086:10F5 - Intel 82567LM gigabit ethernet controller
+# 8086:10BF - Intel 82567LF gigabit ethernet controller
+# 8086:10CB - Intel 82567V gigabit ethernet controller
+
+# GbE SPEC for ICH9M (82567LM/LF/V)
+{
+	"macaddress"[6]		: 8,
+	"ba_reserved1_0"	: 8,
+	"ba_reserved1_1"	: 3,
+	"ba_ibootagent"		: 1,
+	"ba_reserved2"		: 4,
+	"reserved04"		: 16,
+	"version05"		: 16,
+	"reserved06"		: 16,
+	"reserved07"		: 16,
+	"pbalow"		: 16,
+	"pbahigh"		: 16,
+	"pci_loadvid"		: 1,
+	"pci_loadssid"		: 1,
+	"pci_reserved1"		: 1,
+	"pci_reserved2"		: 3,
+	"pci_pmen"		: 1,
+	"pci_auxpwr"		: 1,
+	"pci_reserved3"		: 4,
+	"pci_reserved4"		: 4,
+	"ssdid"			: 16,
+	"ssvid"			: 16,
+	"did"			: 16,
+	"vid"			: 16,
+	"devrevid"		: 16,
+	"lanpwr_d3pwr"		: 5,
+	"lanpwr_reserved"	: 3,
+	"lanpwr_d0pwr"		: 8,
+	"reserved11"		: 16,
+	"reserved12"		: 16,
+	"sh_reserved1"		: 3,
+	"sh_force_halfduplex"	: 1,
+	"sh_force_lowspeed"	: 1,
+	"sh_reserved2_0"	: 3,
+	"sh_reserved2_1"	: 1,
+	"sh_phy_enpwrdown"	: 1,
+	"sh_reserved3"		: 1,
+	"sh_reserved4"		: 3,
+	"sh_sign"		: 2,
+	"cw1_extcfgptr"		: 12,
+	"cw1_oemload"		: 1,
+	"cw1_reserved1"		: 1,
+	"cw1_reserved2"		: 1,
+	"cw1_reserved3"		: 1,
+	"cw2_reserved"		: 8,
+	"cw2_extphylen"		: 8,
+	"extcfg16"		: 16,
+	"l1_led1mode"		: 4,
+	"l1_reserved1"		: 1,
+	"l1_led1fastblink"	: 1,
+	"l1_led1invert"		: 1,
+	"l1_led1blinks"		: 1,
+	"l1_reserved2"		: 1,
+	"l1_lplu_all"		: 1,
+	"l1_lplu_non_d0a"	: 1,
+	"l1_gbedis_non_d0a"	: 1,
+	"l1_reserved3"		: 2,
+	"l1_gbedis"		: 1,
+	"l1_reserved4"		: 1,
+	"l02_led0mode"		: 4,
+	"l02_reserved1"		: 1,
+	"l02_led0fastblink"	: 1,
+	"l02_led0invert"	: 1,
+	"l02_led0blinks"	: 1,
+	"l02_led2mode"		: 4,
+	"l02_reserved2"		: 1,
+	"l02_led2fastblink"	: 1,
+	"l02_led2invert"	: 1,
+	"l02_led2blinks"	: 1,
+	"reserved19"		: 16,
+	"reserved1a"		: 16,
+	"reserved1b"		: 16,
+	"reserved1c"		: 16,
+	"reserved1d"		: 16,
+	"_82567lm"		: 16,
+	"_82567lf"		: 16,
+	"reserved20"		: 16,
+	"_82567v"		: 16,
+	"reserved22_"[14]	: 16,
+	"pxe30_protocolsel"	: 2,
+	"pxe30_reserved1"	: 1,
+	"pxe30_defbootsel"	: 2,
+	"pxe30_reserved2"	: 1,
+	"pxe30_ctrlsprompt"	: 2,
+	"pxe30_dispsetup"	: 1,
+	"pxe30_reserved3"	: 1,
+	"pxe30_forcespeed"	: 2,
+	"pxe30_forcefullduplex"	: 1,
+	"pxe30_reserved4"	: 1,
+	"pxe30_efipresent"	: 1,
+	"pxe30_pxeabsent"	: 1,
+	"pxe31_disablemenu"	: 1,
+	"pxe31_disabletitle"	: 1,
+	"pxe31_disableprotsel"	: 1,
+	"pxe31_disablebootorder": 1,
+	"pxe31_disablelegacywak": 1,
+	"pxe31_disableflash_pro": 1,
+	"pxe31_reserved1"	: 2,
+	"pxe31_ibootagentmode"	: 3,
+	"pxe31_reserved2"	: 3,
+	"pxe31_signature"	: 2,
+	"pxe32_buildnum"	: 8,
+	"pxe32_minorversion"	: 4,
+	"pxe32_majorversion"	: 4,
+	"pxe33_basecodeabsent"	: 1,
+	"pxe33_undipresent"	: 1,
+	"pxe33_reserved1"	: 1,
+	"pxe33_efiundipresent"	: 1,
+	"pxe33_reserved2_0"	: 4,
+	"pxe33_reserved2_1"	: 6,
+	"pxe33_signature"	: 2,
+	"pxe_padding"[11]	: 16,
+	"checksum_gbe"		: 16,
+	"padding"[0xf80]	: 8
+}
diff --git a/util/blobtool/ifd-x200.set b/util/blobtool/ifd-x200.set
new file mode 100644
index 0000000..2894562
--- /dev/null
+++ b/util/blobtool/ifd-x200.set
@@ -0,0 +1,167 @@
+#
+# Copyright (C) 2017 Damien Zammit <damien@zamaudio.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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+#
+# X200 Liberated Flash Descriptor
+# Layout:
+#	0x0000 - 0x1000  : IFD
+#	0x1000 - 0x3000  : GbE x2
+#	0x3000 - ROMSIZE : BIOS
+{
+	"fd_signature" = 0xff0a55a,
+
+	"flmap0_fcba" = 0x1,
+	"flmap0_nc" = 0x0,
+	"flmap0_reserved0" = 0x0,
+	"flmap0_frba" = 0x4,
+	"flmap0_nr" = 0x2,
+	"flmap0_reserved1" = 0x0,
+	"flmap1_fmba" = 0x6,
+	"flmap1_nm" = 0x2,
+	"flmap1_reserved" = 0x0,
+	"flmap1_fisba" = 0x10,
+	"flmap1_isl" = 0x2,
+	"flmap2_fmsba" = 0x20,
+	"flmap2_msl" = 0x1,
+	"flmap2_reserved" = 0x0,
+
+	"flcomp_density1" = 0x4,
+	"flcomp_density2" = 0x2,
+	"flcomp_reserved0" = 0x0,
+	"flcomp_reserved1" = 0x0,
+	"flcomp_reserved2" = 0x0,
+	"flcomp_readclockfreq" = 0x0,
+	"flcomp_fastreadsupp" = 0x1,
+	"flcomp_fastreadfreq" = 0x1,
+	"flcomp_w_eraseclkfreq" = 0x0,
+	"flcomp_r_statclkfreq" = 0x0,
+	"flcomp_reserved3" = 0x0,
+	"flill" = 0x0,
+	"flbp" = 0x0,
+	"comp_padding"[0x24] = 0xff,
+
+	"flreg0_base" = 0x0,
+	"flreg0_reserved0" = 0x0,
+	"flreg0_limit" = 0x0,
+	"flreg0_reserved1" = 0x0,
+	"flreg1_base" = 0x3,
+	"flreg1_reserved0" = 0x0,
+	"flreg1_limit" = 0x7ff,
+	"flreg1_reserved1" = 0x0,
+	"flreg2_base" = 0x1fff,
+	"flreg2_reserved0" = 0x0,
+	"flreg2_limit" = 0x0,
+	"flreg2_reserved1" = 0x0,
+	"flreg3_base" = 0x1,
+	"flreg3_reserved0" = 0x0,
+	"flreg3_limit" = 0x2,
+	"flreg3_reserved1" = 0x0,
+	"flreg4_base" = 0x1fff,
+	"flreg4_reserved0" = 0x0,
+	"flreg4_limit" = 0x0,
+	"flreg4_reserved1" = 0x0,
+	"flreg_padding"[12] = 0xff,
+
+	"flmstr1_requesterid" = 0x0,
+	"flmstr1_r_fd" = 0x1,
+	"flmstr1_r_bios" = 0x1,
+	"flmstr1_r_me" = 0x1,
+	"flmstr1_r_gbe" = 0x1,
+	"flmstr1_r_pd" = 0x1,
+	"flmstr1_r_reserved" = 0x0,
+	"flmstr1_w_fd" = 0x1,
+	"flmstr1_w_bios" = 0x1,
+	"flmstr1_w_me" = 0x1,
+	"flmstr1_w_gbe" = 0x1,
+	"flmstr1_w_pd" = 0x1,
+	"flmstr1_w_reserved" = 0x0,
+	"flmstr2_requesterid" = 0x0,
+	"flmstr2_r_fd" = 0x0,
+	"flmstr2_r_bios" = 0x0,
+	"flmstr2_r_me" = 0x0,
+	"flmstr2_r_gbe" = 0x0,
+	"flmstr2_r_pd" = 0x0,
+	"flmstr2_r_reserved" = 0x0,
+	"flmstr2_w_fd" = 0x0,
+	"flmstr2_w_bios" = 0x0,
+	"flmstr2_w_me" = 0x0,
+	"flmstr2_w_gbe" = 0x0,
+	"flmstr2_w_pd" = 0x0,
+	"flmstr2_w_reserved" = 0x0,
+	"flmstr3_requesterid" = 0x218,
+	"flmstr3_r_fd" = 0x0,
+	"flmstr3_r_bios" = 0x0,
+	"flmstr3_r_me" = 0x0,
+	"flmstr3_r_gbe" = 0x1,
+	"flmstr3_r_pd" = 0x0,
+	"flmstr3_r_reserved" = 0x0,
+	"flmstr3_w_fd" = 0x0,
+	"flmstr3_w_bios" = 0x0,
+	"flmstr3_w_me" = 0x0,
+	"flmstr3_w_gbe" = 0x1,
+	"flmstr3_w_pd" = 0x0,
+	"flmstr3_w_reserved" = 0x0,
+	"flmstr_padding"[0x94] = 0xff,
+
+	"ich0_medisable" = 0x1,
+	"ich0_reserved0" = 0x4,
+	"ich0_tcomode" = 0x1,
+	"ich0_mesmbusaddr" = 0x64,
+	"ich0_bmcmode" = 0x0,
+	"ich0_trippointsel" = 0x0,
+	"ich0_reserved1" = 0x0,
+	"ich0_integratedgbe" = 0x1,
+	"ich0_lanphy" = 0x1,
+	"ich0_reserved2" = 0x0,
+	"ich0_dmireqiddisable" = 0x0,
+	"ich0_me2smbusaddr" = 0x0,
+	"ich1_dynclk_nmlink" = 0x1,
+	"ich1_dynclk_smlink" = 0x1,
+	"ich1_dynclk_mesmbus" = 0x1,
+	"ich1_dynclk_sst" = 0x1,
+	"ich1_reserved0" = 0x0,
+	"ich1_nmlink_npostreqs" = 0x1,
+	"ich1_reserved1" = 0x0,
+	"ich1_reserved2" = 0x0,
+	"ichstrap_padding"[0xf8] = 0xff,
+	"mch0_medisable" = 0x1,
+	"mch0_mebootfromflash" = 0x0,
+	"mch0_tpmdisable" = 0x1,
+	"mch0_reserved0" = 0x7,
+	"mch0_spifingerprinton" = 0x1,
+	"mch0_mealtdisable" = 0x0,
+	"mch0_reserved1" = 0xff,
+	"mch0_reserved2" = 0xffff,
+	"mchstrap_padding"[0xcdc] = 0xff,
+
+	"mevscc_jid0" = 0x1720c2,
+	"mevscc_vscc0" = 0x20052005,
+	"mevscc_jid1" = 0x1730ef,
+	"mevscc_vscc1" = 0x20052005,
+	"mevscc_jid2" = 0x481f,
+	"mevscc_vscc2" = 0x20152015,
+	"mevscc_padding"[4] = 0xff,
+	"mevscc_tablebase" = 0xee,
+	"mevscc_tablelength" = 0x6,
+	"mevscc_reserved" = 0x0,
+
+	"oem_magic0" = 0x4c,
+	"oem_magic1" = 0x49,
+	"oem_magic2" = 0x42,
+	"oem_magic3" = 0x45,
+	"oem_magic4" = 0x52,
+	"oem_magic5" = 0x41,
+	"oem_magic6" = 0x54,
+	"oem_magic7" = 0x45,
+	"oem_padding"[0xf8] = 0xff
+}
diff --git a/util/blobtool/ifd-x200.spec b/util/blobtool/ifd-x200.spec
new file mode 100644
index 0000000..0cdbb9d
--- /dev/null
+++ b/util/blobtool/ifd-x200.spec
@@ -0,0 +1,187 @@
+#
+# Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+# Copyright (C) 2014, 2015 Leah Rowe <info@minifree.org>
+# Copyright (C) 2017 Damien Zammit <damien@zamaudio.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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+#
+# Info on flash descriptor (page 845 onwards):
+#
+# http://www.intel.co.uk/content/dam/doc/datasheet/io-controller-hub-9-datasheet.pdf
+
+# Flash Descriptor SPEC for GM45/ICH9M
+{
+	# Signature for descriptor mode
+	"fd_signature"		: 32,
+
+	# Flash map registers
+	"flmap0_fcba"		: 8,
+	"flmap0_nc"		: 2,
+	"flmap0_reserved0"	: 6,
+	"flmap0_frba"		: 8,
+	"flmap0_nr"		: 3,
+	"flmap0_reserved1"	: 5,
+	"flmap1_fmba"		: 8,
+	"flmap1_nm"		: 3,
+	"flmap1_reserved"	: 5,
+	"flmap1_fisba"		: 8,
+	"flmap1_isl"		: 8,
+	"flmap2_fmsba"		: 8,
+	"flmap2_msl"		: 8,
+	"flmap2_reserved"	: 16,
+
+	# Component section
+	"flcomp_density1"	: 3,
+	"flcomp_density2"	: 3,
+	"flcomp_reserved0"	: 2,
+	"flcomp_reserved1"	: 8,
+	"flcomp_reserved2"	: 1,
+	"flcomp_readclockfreq"	: 3,
+	"flcomp_fastreadsupp"	: 1,
+	"flcomp_fastreadfreq"	: 3,
+	"flcomp_w_eraseclkfreq"	: 3,
+	"flcomp_r_statclkfreq"	: 3,
+	"flcomp_reserved3"	: 2,
+	"flill"			: 32,
+	"flbp"			: 32,
+	"comp_padding"[36]	: 8,
+
+	# Region section
+	"flreg0_base"		: 13,
+	"flreg0_reserved0"	: 3,
+	"flreg0_limit"		: 13,
+	"flreg0_reserved1"	: 3,
+	"flreg1_base"		: 13,
+	"flreg1_reserved0"	: 3,
+	"flreg1_limit"		: 13,
+	"flreg1_reserved1"	: 3,
+	"flreg2_base"		: 13,
+	"flreg2_reserved0"	: 3,
+	"flreg2_limit"		: 13,
+	"flreg2_reserved1"	: 3,
+	"flreg3_base"		: 13,
+	"flreg3_reserved0"	: 3,
+	"flreg3_limit"		: 13,
+	"flreg3_reserved1"	: 3,
+	"flreg4_base"		: 13,
+	"flreg4_reserved0"	: 3,
+	"flreg4_limit"		: 13,
+	"flreg4_reserved1"	: 3,
+	"flreg_padding"[12]	: 8,
+
+	# Master access section
+
+	# 1: Host CPU/BIOS
+	"flmstr1_requesterid"	: 16,
+	"flmstr1_r_fd"		: 1,
+	"flmstr1_r_bios"	: 1,
+	"flmstr1_r_me"		: 1,
+	"flmstr1_r_gbe"		: 1,
+	"flmstr1_r_pd"		: 1,
+	"flmstr1_r_reserved"	: 3,
+	"flmstr1_w_fd"		: 1,
+	"flmstr1_w_bios"	: 1,
+	"flmstr1_w_me"		: 1,
+	"flmstr1_w_gbe"		: 1,
+	"flmstr1_w_pd"		: 1,
+	"flmstr1_w_reserved"	: 3,
+
+	# 2: ME
+	"flmstr2_requesterid"	: 16,
+	"flmstr2_r_fd"		: 1,
+	"flmstr2_r_bios"	: 1,
+	"flmstr2_r_me"		: 1,
+	"flmstr2_r_gbe"		: 1,
+	"flmstr2_r_pd"		: 1,
+	"flmstr2_r_reserved"	: 3,
+	"flmstr2_w_fd"		: 1,
+	"flmstr2_w_bios"	: 1,
+	"flmstr2_w_me"		: 1,
+	"flmstr2_w_gbe"		: 1,
+	"flmstr2_w_pd"		: 1,
+	"flmstr2_w_reserved"	: 3,
+
+	# 3: GbE
+	"flmstr3_requesterid"	: 16,
+	"flmstr3_r_fd"		: 1,
+	"flmstr3_r_bios"	: 1,
+	"flmstr3_r_me"		: 1,
+	"flmstr3_r_gbe"		: 1,
+	"flmstr3_r_pd"		: 1,
+	"flmstr3_r_reserved"	: 3,
+	"flmstr3_w_fd"		: 1,
+	"flmstr3_w_bios"	: 1,
+	"flmstr3_w_me"		: 1,
+	"flmstr3_w_gbe"		: 1,
+	"flmstr3_w_pd"		: 1,
+	"flmstr3_w_reserved"	: 3,
+
+	"flmstr_padding"[148]	: 8,
+
+	# ICHSTRAP0
+	"ich0_medisable"	: 1,
+	"ich0_reserved0"	: 6,
+	"ich0_tcomode"		: 1,
+	"ich0_mesmbusaddr"	: 7,
+	"ich0_bmcmode"		: 1,
+	"ich0_trippointsel"	: 1,
+	"ich0_reserved1"	: 2,
+	"ich0_integratedgbe"	: 1,
+	"ich0_lanphy"		: 1,
+	"ich0_reserved2"	: 3,
+	"ich0_dmireqiddisable"	: 1,
+	"ich0_me2smbusaddr"	: 7,
+
+	# ICHSTRAP1
+	"ich1_dynclk_nmlink"	: 1,
+	"ich1_dynclk_smlink"	: 1,
+	"ich1_dynclk_mesmbus"	: 1,
+	"ich1_dynclk_sst"	: 1,
+	"ich1_reserved0"	: 4,
+	"ich1_nmlink_npostreqs"	: 1,
+	"ich1_reserved1"	: 7,
+	"ich1_reserved2"	: 16,
+
+	"ichstrap_padding"[248]	: 8,
+
+	# MCHSTRAP0
+	"mch0_medisable"	: 1,
+	"mch0_mebootfromflash"	: 1,
+	"mch0_tpmdisable"	: 1,
+	"mch0_reserved0"	: 3,
+	"mch0_spifingerprinton"	: 1,
+	# Alternate disable - allows ME to perform chipset
+	# init functions but disables FW apps such as AMT
+	"mch0_mealtdisable"	: 1,
+	"mch0_reserved1"	: 8,
+	"mch0_reserved2"	: 16,
+
+	"mchstrap_padding"[3292]: 8,
+
+	# ME VSCC Table
+	"mevscc_jid0"		: 32,
+	"mevscc_vscc0"		: 32,
+	"mevscc_jid1"		: 32,
+	"mevscc_vscc1"		: 32,
+	"mevscc_jid2"		: 32,
+	"mevscc_vscc2"		: 32,
+	"mevscc_padding"[4]	: 8,
+
+	# Descriptor Map 2 Record
+	"mevscc_tablebase"	: 8,
+	"mevscc_tablelength"	: 8,
+	"mevscc_reserved"	: 16,
+
+	# OEM section
+	"oem_magic"[8]		: 8,
+	"oem_padding"[248]	: 8
+}
diff --git a/util/blobtool/it8718f-ec.spec b/util/blobtool/it8718f-ec.spec
new file mode 100644
index 0000000..7fa325f
--- /dev/null
+++ b/util/blobtool/it8718f-ec.spec
@@ -0,0 +1,368 @@
+# ITE IT8718F SuperIO EC registers
+{
+	# 00 Configuration register
+	"conf00_start"		: 1,
+	"conf00_smien"		: 1,
+	"conf00_irqen"		: 1,
+	"conf00_irqclr"		: 1,
+	"conf00_ro_one"		: 1,
+	"conf00_copen"		: 1,
+	"conf00_vbat"		: 1,
+	"conf00_initreset"	: 1,
+
+	# 01 Interrupt Status register 1
+	"irq1_maxfantac1"	: 1,
+	"irq1_maxfantac2"	: 1,
+	"irq1_maxfantac3"	: 1,
+	"irq1_maxfantac4"	: 1,
+	"irq1_copen"		: 1,
+	"irq1_reserved0"	: 1,
+	"irq1_maxfantac5"	: 1,
+	"irq1_reserved1"	: 1,
+
+	# 02 Interrupt Status register 2
+	"irq2_limit_vin"[8]	: 1,
+
+	# 03 Interrupt Status register 3
+	"irq3_limit_temp1"	: 1,
+	"irq3_limit_temp2"	: 1,
+	"irq3_limit_temp3"	: 1,
+	"irq3_reserved"		: 5,
+
+	# 04 SMI Mask register 1
+	"smi1_dis_fantac1"	: 1,
+	"smi1_dis_fantac2"	: 1,
+	"smi1_dis_fantac3"	: 1,
+	"smi1_dis_fantac4"	: 1,
+	"smi1_dis_copen"	: 1,
+	"smi1_reserved0"	: 1,
+	"smi1_dis_fantac5"	: 1,
+	"smi1_reserved1"	: 1,
+
+	# 05 SMI Mask register 2
+	"smi2_dis_vin"[8]	: 1,
+
+	# 06 SMI Mask register 3
+	"smi3_dis_temp1"	: 1,
+	"smi3_dis_temp2"	: 1,
+	"smi3_dis_temp3"	: 1,
+	"smi3_reserved"		: 5,
+
+	# 07 Interrupt Mask register 1
+	"irqmask1_fantac1"	: 1,
+	"irqmask1_fantac2"	: 1,
+	"irqmask1_fantac3"	: 1,
+	"irqmask1_fantac4"	: 1,
+	"irqmask1_copen"	: 1,
+	"irqmask1_reserved0"	: 1,
+	"irqmask1_fantac5"	: 1,
+	"irqmask1_reserved1"	: 1,
+
+	# 08 Interrupt Mask register 2
+	"irqmask2_vin"[8]	: 1,
+
+	# 09 Interrupt Mask register 3
+	"irqmask3_temp1"	: 1,
+	"irqmask3_temp2"	: 1,
+	"irqmask3_temp3"	: 1,
+	"irqmask3_reserved"	: 4,
+	"irqmask3_extsensor"	: 1,
+
+	# 0a Interface Selection register
+	"iface_reserved"	: 4,
+	"iface_extsensor_select": 3,
+	"iface_pseudo_eoc"	: 1,
+
+	# 0b Fan PWM smoothing step selection reg
+	"fanpwm_reserved"	: 6,
+	"fanpwm_smoothing_step"	: 2,
+
+	# 0c Fan Tachometer 16 bit enable register
+	"fantach16_en_tac1"	: 1,
+	"fantach16_en_tac2"	: 1,
+	"fantach16_en_tac3"	: 1,
+	"fantach16_tmpin1_enh"	: 1,
+	"fantach16_en_tac4"	: 1,
+	"fantach16_en_tac5"	: 1,
+	"fantach16_tmpin2_enh"	: 1,
+	"fantach16_tmpin3_enh"	: 1,
+
+	# 0d-0f Fan Tachmometer read registers
+	"fantach_lo_counts1"	: 8,
+	"fantach_lo_counts2"	: 8,
+	"fantach_lo_counts3"	: 8,
+
+	# 10-12 Fan Tachometer limit registers
+	"fantach_lo_limit1"	: 8,
+	"fantach_lo_limit2"	: 8,
+	"fantach_lo_limit3"	: 8,
+
+	# 13 Fan controller main control register
+	"fanctlmain_mode1"	: 1,
+	"fanctlmain_mode2"	: 1,
+	"fanctlmain_mode3"	: 1,
+	"fanctlmain_reserved0"	: 1,
+	"fanctlmain_en_tac1"	: 1,
+	"fanctlmain_en_tac2"	: 1,
+	"fanctlmain_en_tac3"	: 1,
+	"fanctlmain_reserved1"	: 1,
+
+	# 14 FAN_CTL control register
+	"fanctl_enable1"	: 1,
+	"fanctl_enable2"	: 1,
+	"fanctl_enable3"	: 1,
+	"fanctl_minduty_sel"	: 1,
+	# 000: 48Mhz (PWM Frequency 375Khz)
+	# 001: 24Mhz (PWM Frequency 187.5Khz)
+	# 010: 12Mhz (PWM Frequency 93.75Khz)
+	# 011: 8Mhz (PWM Frequency 62.5Khz)
+	# 100: 6Mhz (PWM Frequency 46.875Khz)
+	# 101: 3Mhz (PWM Frequency 23.43Khz)
+	# 110: 1.5Mhz (PWM Frequency 11.7Khz)
+	# 111: 0.75Mhz (PWM Frequency 5.86Khz)
+	"fanctl_pwm_base_clock"	: 3,
+	"fanctl_allpolarity"	: 1,
+
+	# 15 FAN_CTL1 PWM control register
+	"fanctl1_tmpin_sel"	: 2,
+	"fanctl1_steps"		: 5,
+	"fanctl1_pwm_mode"	: 1,
+
+	# 16 FAN_CTL2 PWM control register
+	"fanctl2_tmpin_sel"	: 2,
+	"fanctl2_steps"		: 5,
+	"fanctl2_pwm_mode"	: 1,
+
+	# 17 FAN_CTL3 PWM control register
+	"fanctl3_tmpin_sel"	: 2,
+	"fanctl3_steps"		: 5,
+	"fanctl3_pwm_mode"	: 1,
+
+	# 18-1a Fan Tachometer extended read registers
+	"fantach_hi_counts1"	: 8,
+	"fantach_hi_counts2"	: 8,
+	"fantach_hi_counts3"	: 8,
+
+	# 1b-1d Fan Tachometer extended limit registers
+	"fantach_hi_limit1"	: 8,
+	"fantach_hi_limit2"	: 8,
+	"fantach_hi_limit3"	: 8,
+
+	"reserved1e"		: 8,
+	"reserved1f"		: 8,
+
+
+	# 20-27 Reading registers
+	"vin"[8]		: 8,
+
+	"vbat"			: 8,
+	"tmpin1"		: 8,
+	"tmpin2"		: 8,
+	"tmpin3"		: 8,
+	"reserved2c"		: 8,
+	"reserved2d"		: 8,
+	"reserved2e"		: 8,
+	"reserved2f"		: 8,
+	"limit_hi_vin0"		: 8,
+	"limit_lo_vin0"		: 8,
+	"limit_hi_vin1"		: 8,
+	"limit_lo_vin1"		: 8,
+	"limit_hi_vin2"		: 8,
+	"limit_lo_vin2"		: 8,
+	"limit_hi_vin3"		: 8,
+	"limit_lo_vin3"		: 8,
+	"limit_hi_vin4"		: 8,
+	"limit_lo_vin4"		: 8,
+	"limit_hi_vin5"		: 8,
+	"limit_lo_vin5"		: 8,
+	"limit_hi_vin6"		: 8,
+	"limit_lo_vin6"		: 8,
+	"limit_hi_vin7"		: 8,
+	"limit_lo_vin7"		: 8,
+	"limit_hi_tmpin1"	: 8,
+	"limit_lo_tmpin1"	: 8,
+	"limit_hi_tmpin2"	: 8,
+	"limit_lo_tmpin2"	: 8,
+	"limit_hi_tmpin3"	: 8,
+	"limit_lo_tmpin3"	: 8,
+
+	"reserved46"		: 8,
+	"reserved47"		: 8,
+	"reserved48"		: 8,
+	"reserved49"		: 8,
+	"reserved4a"		: 8,
+	"reserved4b"		: 8,
+	"reserved4c"		: 8,
+	"reserved4d"		: 8,
+	"reserved4e"		: 8,
+	"reserved4f"		: 8,
+
+	# 50 ADC Voltage channel enable register
+	"adc_scan_enable_vin"[8]: 1,
+
+	# 51 ADC Temperature channel enable register
+	"therm_diode_tmpin1"	: 1,
+	"therm_diode_tmpin2"	: 1,
+	"therm_diode_tmpin3"	: 1,
+	# Mututally exclusive settings
+	"therm_resistor_tmpin1"	: 1,
+	"therm_resistor_tmpin2"	: 1,
+	"therm_resistor_tmpin3"	: 1,
+	"therm_reserved"	: 2,
+
+	"therm_limit_tmpin1"	: 8,
+	"therm_limit_tmpin2"	: 8,
+	"therm_limit_tmpin3"	: 8,
+
+	# 55 Temperature extra channel enable reg
+	"therm_resistor_vin4"	: 1,
+	"therm_resistor_vin5"	: 1,
+	"therm_resistor_vin6"	: 1,
+	"adc_fanctl2_pwm_duty"	: 1,
+	# 000: 48Mhz (PWM Frequency 375Khz)
+	# 001: 24Mhz (PWM Frequency 187.5Khz)
+	# 010: 12Mhz (PWM Frequency 93.75Khz)
+	# 011: 8Mhz (PWM Frequency 62.5Khz)
+	# 100: 6Mhz (PWM Frequency 46.875Khz)
+	# 101: 3Mhz (PWM Frequency 23.43Khz)
+	# 110: 1.5Mhz (PWM Frequency 11.7Khz)
+	# 111: 0.75Mhz (PWM Frequency 5.86Khz)
+	"adc_fanctl2_pwm_bclk"	: 3,
+	"adc_tmpin3_ext_select"	: 1,
+
+	"thermal_zero_diode1"	: 8,
+	"thermal_zero_diode2"	: 8,
+	"ite_vendor_id"		: 8,
+	"thermal_zero_diode3"	: 8,
+	"reserved5a"		: 8,
+	"ite_code_id"		: 8,
+
+	"beep_fantac"		: 1,
+	"beep_vin"		: 1,
+	"beep_tmpin"		: 1,
+	"beep_reserved"		: 1,
+	# ADC clock select
+	# 000: 500Khz (Default)
+	# 001: 250Khz
+	# 010: 125K
+	# 011: 62.5Khz
+	# 100: 31.25Khz
+	# 101: 24Mhz
+	# 110: 1Mhz
+	# 111: 2Mhz
+	"adc_clock_select"	: 3,
+	"thermal_zero_adj_en"	: 1,
+
+	"beep_fan_freq_div"	: 4,
+	"beep_fan_tone_div"	: 4,
+	"beep_volt_freq_div"	: 4,
+	"beep_volt_tone_div"	: 4,
+	"beep_temp_freq_div"	: 4,
+	"beep_temp_tone_div"	: 4,
+
+	# 60 SmartGuardian registers
+	"sguard1_temp_lim_off"	: 8,
+	"sguard1_temp_lim_fan"	: 8,
+	"reserved62"		: 8,
+	"sguard1_pwm_start"	: 7,
+	"sguard1_pwm_slope6"	: 1,
+	"sguard1_pwm_slope05"	: 6,
+	"sguard1_pwm_reserved"	: 1,
+	"sguard1_fan_smooth_en"	: 1,
+	"sguard1_temp_interval"	: 5,
+	"sguard1_temp_reserved"	: 2,
+	"sguard1_temp_pwm_lin"	: 1,
+	"reserved66"		: 8,
+	"reserved67"		: 8,
+	"sguard2_temp_lim_off"	: 8,
+	"sguard2_temp_lim_fan"	: 8,
+	"reserved6a"		: 8,
+	"sguard2_pwm_start"	: 7,
+	"sguard2_pwm_slope6"	: 1,
+	"sguard2_pwm_slope05"	: 6,
+	"sguard2_pwm_reserved"	: 1,
+	"sguard2_fan_smooth_en"	: 1,
+	"sguard2_temp_interval"	: 5,
+	"sguard2_temp_reserved"	: 2,
+	"sguard2_temp_pwm_lin"	: 1,
+	"reserved6e"		: 8,
+	"reserved6f"		: 8,
+	"sguard3_temp_lim_off"	: 8,
+	"sguard3_temp_lim_fan"	: 8,
+	"reserved72"		: 8,
+	"sguard3_pwm_start"	: 7,
+	"sguard3_pwm_slope6"	: 1,
+	"sguard3_pwm_slope05"	: 6,
+	"sguard3_pwm_reserved"	: 1,
+	"sguard3_fan_smooth_en"	: 1,
+	"sguard3_temp_interval"	: 5,
+	"sguard3_temp_reserved"	: 2,
+	"sguard3_temp_pwm_lin"	: 1,
+	"reserved76"		: 8,
+	"reserved77"		: 8,
+	"reserved78"		: 8,
+	"reserved79"		: 8,
+	"reserved7a"		: 8,
+	"reserved7b"		: 8,
+	"reserved7c"		: 8,
+	"reserved7d"		: 8,
+	"reserved7e"		: 8,
+	"reserved7f"		: 8,
+
+	# 80 Fan Tachometer 4-5 read registers
+	"fantach_lo_counts4"	: 8,
+	"fantach_hi_counts4"	: 8,
+	"fantach_lo_counts5"	: 8,
+	"fantach_hi_counts5"	: 8,
+	"fantach_lo_limit4"	: 8,
+	"fantach_hi_limit4"	: 8,
+	"fantach_lo_limit5"	: 8,
+	"fantach_hi_limit5"	: 8,
+
+	# 88 External temperature sensor host status
+	"ext_host_busy"		: 1,
+	"ext_host_fnsh"		: 1,
+	"ext_host_r_fcs_error"	: 1,
+	"ext_host_w_fcs_error"	: 1,
+	"ext_host_peci_highz"	: 1,
+	"ext_host_sst_slave"	: 1,
+	"ext_host_sst_bus"	: 1,
+	"ext_host_data_fifo_clr": 1,
+
+	"ext_host_target_addr"	: 8,
+	"ext_host_write_length"	: 8,
+	"ext_host_read_length"	: 8,
+	"ext_host_cmd"		: 8,
+	"ext_host_writedata"	: 8,
+
+	"ext_hostctl_start"	: 1,
+	"ext_hostctl_sst_amdsi"	: 1,
+	"ext_hostctl_sst_ctl"	: 1,
+	"ext_hostctl_resetfifo"	: 1,
+	"ext_hostctl_fcs_abort"	: 1,
+	"ext_hostctl_start_en"	: 1,
+	# Auto-Start Control
+	# The host will start the transaction
+	# at a regular rate automatically.
+	# 00: 32 Hz
+	# 01: 16 Hz
+	# 10: 8 Hz
+	# 11: 4 Hz
+	"ext_hostctl_start_ctl"	: 2,
+
+	"ext_host_readdata"	: 8,
+
+	"fan1_temp_limit_start"	: 8,
+	"fan1_slope_pwm"	: 7,
+	"fan1_temp_input_sel0"	: 1,
+	"fan1_ctlmode_temp_ivl"	: 5,
+	"fan1_ctlmode_target"	: 2,
+	"fan1_temp_input_sel1"	: 1,
+	"reserved93"		: 8,
+	"fan2_temp_limit_start"	: 8,
+	"fan2_slope_pwm"	: 7,
+	"fan2_temp_input_sel0"	: 1,
+	"fan2_ctlmode_temp_ivl"	: 5,
+	"fan2_ctlmode_target"	: 2,
+	"fan2_temp_input_sel1"	: 1
+}