[coreboot-gerrit] New patch to review for coreboot: util/igbetool: Add tool for Intel GbE flash region generation

Damien Zammit (damien@zamaudio.com) gerrit at coreboot.org
Tue Nov 15 06:09:42 CET 2016


Damien Zammit (damien at zamaudio.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17423

-gerrit

commit 5b321784cb9512a671fd116d844d0be43d4c8a04
Author: Damien Zammit <damien at zamaudio.com>
Date:   Tue Nov 15 16:00:36 2016 +1100

    util/igbetool: Add tool for Intel GbE flash region generation
    
    This supercedes the original prototype tool.
    It is endian safe and does not rely on "struct bitfields".
    
    This tool generates a binary iGbE region based on
    an input spec and a set of values.
    
    Usage:
    	make && make gen-ich9m
    
    Dependencies:
    	bison and flex
    
    Outputs by default valid `flashregion_3_gbe.bin` for ICH9M
    using Lenovo X200 settings.
    
    This configuration can be both extended or altered to
    produce either other ICH9M configs or other chipset GbEs.
    
    Signed-off-by: Damien Zammit <damien at zamaudio.com>
    
    Change-Id: I7f925078ae551c7a7b34101ea633f23dad2df421
---
 util/igbetool/Makefile   |  28 ++++
 util/igbetool/ich9m.set  |  88 ++++++++++
 util/igbetool/ich9m.spec | 150 +++++++++++++++++
 util/igbetool/igbetool.l | 130 +++++++++++++++
 util/igbetool/igbetool.y | 417 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 813 insertions(+)

diff --git a/util/igbetool/Makefile b/util/igbetool/Makefile
new file mode 100644
index 0000000..1d34f91
--- /dev/null
+++ b/util/igbetool/Makefile
@@ -0,0 +1,28 @@
+MACADDRESS ?= 00:f5:f0:40:71:fe
+CC = gcc
+YACC = bison
+LEX = flex
+
+igbetool: igbetool.o
+	mv igbetool.o igbetool
+
+%.o: %.lex.c %.tab.c %.tab.h
+	$(CC) -Wall -Wno-unused-function -g -o $@ $^ -lfl
+
+%.lex.c: %.l
+	$(LEX) -o $(patsubst %.l,%.lex.c,$<) $<
+
+%.tab.c %.tab.h: %.y
+	$(YACC) -d $<
+
+# Use this target to generate flashregion_3_gbe.bin
+gen-ich9m:
+	cat ich9m.spec ich9m.set | ./igbetool -m $(MACADDRESS) > flashregion_3_gbe.bin
+	# duplicate binary as per spec
+	cat ich9m.spec ich9m.set | ./igbetool -m $(MACADDRESS) >> flashregion_3_gbe.bin
+
+
+.PHONY: clean gen-ich9m
+
+clean:
+	rm -f *.lex.c *.tab.c *.tab.h *.o igbetool flashregion_3_gbe.bin
diff --git a/util/igbetool/ich9m.set b/util/igbetool/ich9m.set
new file mode 100644
index 0000000..9b4fe29
--- /dev/null
+++ b/util/igbetool/ich9m.set
@@ -0,0 +1,88 @@
+#
+# Copyright (C) 2016 Damien Zammit <damien at 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" = 0xbaad,
+	"reserved23" = 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/igbetool/ich9m.spec b/util/igbetool/ich9m.spec
new file mode 100644
index 0000000..70b3050
--- /dev/null
+++ b/util/igbetool/ich9m.spec
@@ -0,0 +1,150 @@
+#
+# Copyright (C) 2014 Steve Shenton <sgsit at libreboot.org>
+#                    Leah Rowe <info at minifree.org>
+# Copyright (C) 2016 Damien Zammit <damien at 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
+
+# GbE SPEC for ICH9M
+{
+	"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"		: 16,
+	"reserved23"		: 16,
+	"reserved24"		: 16,
+	"reserved25"		: 16,
+	"reserved26"		: 16,
+	"reserved27"		: 16,
+	"reserved28"		: 16,
+	"reserved29"		: 16,
+	"reserved2a"		: 16,
+	"reserved2b"		: 16,
+	"reserved2c"		: 16,
+	"reserved2d"		: 16,
+	"reserved2e"		: 16,
+	"reserved2f"		: 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"		: 16,
+	"padding"[0xf80]	: 8
+}
diff --git a/util/igbetool/igbetool.l b/util/igbetool/igbetool.l
new file mode 100644
index 0000000..af62940
--- /dev/null
+++ b/util/igbetool/igbetool.l
@@ -0,0 +1,130 @@
+/*
+ * igbetool - Generator for Intel GigaBit Ethernet flash region
+ * Copyright (C) 2016 Damien Zammit <damien at 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 "igbetool.tab.h"
+
+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;
+		}
+
+		val |= nib << (((nibs - 1) - (i - 2)) * 4);
+	}
+	return val;
+}
+
+char* stripquotes (char *string)
+{
+	char *stripped;
+	unsigned int len = strlen(string);
+	if (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;
+}
+
+%}
+
+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 */
+
+. {
+    printf("Unexpected: %c\nExiting...\n",*yytext);
+    exit(0);
+}
+%%
diff --git a/util/igbetool/igbetool.y b/util/igbetool/igbetool.y
new file mode 100644
index 0000000..a5fd10a
--- /dev/null
+++ b/util/igbetool/igbetool.y
@@ -0,0 +1,417 @@
+/*
+ * igbetool - Generator for Intel GigaBit Ethernet flash region
+ * Copyright (C) 2016 Damien Zammit <damien at 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>
+int yylex (void);
+void yyerror (char const *);
+
+struct macaddr {
+	unsigned char byte[6];
+};
+
+struct pciids {
+	unsigned short ssdid;	// Subsystem device id
+	unsigned short ssvid;	// Subsystem vendor id
+	unsigned short did;	// Device id
+	unsigned short vid;	// Vendor id
+};
+
+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;
+
+struct blob {
+	unsigned int bloblen;
+	unsigned char *blb;
+	unsigned short checksum;
+};
+
+#define VALID_BIT 0x80
+#define MAX_WIDTH 32
+#define CHECKSUM_SIZE 16
+
+struct blob *binary;
+struct macaddr mac;
+struct pciids ids;
+
+static struct macaddr parsemac(char *mac)
+{
+	struct macaddr m = { 0 };
+	int i, j;
+
+	for (i = 0; i < 6; i++) {
+		/* Go through each nibble of the byte */
+		for (j = 0; j < 2; j++) {
+			if (mac[(i*3) + j] >= 'a' && mac[(i*3) + j] <= 'f')
+				m.byte[i] |= (uint8_t)(
+					(mac[(i*3)+j] - 87) << ((j^1) << 2)
+					);
+			else if (mac[(i*3) + j] >= 'A' && mac[(i*3) + j] <= 'F')
+				m.byte[i] |= (uint8_t)(
+					(mac[(i*3) + j] - 55) << ((j^1) << 2)
+					);
+			else if (mac[(i*3) +j ] >= '0' && mac[(i*3) + j] <= '9')
+				m.byte[i] |= (uint8_t)(
+					(mac[(i*3) + j] - 48) << ((j^1) << 2)
+					);
+			else {
+				fprintf(stderr, "Error: MAC address invalid \n");
+				exit(1);
+			}
+		}
+	}
+	return m;
+}
+
+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[0x%0x] = %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 generate_setter_bitfields(void)
+{
+	fprintf(stderr, "TODO: binary decompiler\n");
+}
+
+/* {}{} -> [] */
+void generate_binary(void)
+{
+	unsigned int i;
+
+	if (binary->bloblen % 8) {
+		fprintf (stderr, "ERROR: Spec must be multiple of 8 bits wide\n");
+		exit (1);
+	}
+
+	set_bitfield("macaddress0", mac.byte[0]);
+	set_bitfield("macaddress1", mac.byte[1]);
+	set_bitfield("macaddress2", mac.byte[2]);
+	set_bitfield("macaddress3", mac.byte[3]);
+	set_bitfield("macaddress4", mac.byte[4]);
+	set_bitfield("macaddress5", mac.byte[5]);
+
+	/* 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") == 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(stdout, "%c", byte);
+
+		/* incremental 16 bit checksum */
+		if ((i % 16) < 8) {
+			binary->checksum += byte;
+		} else {
+			binary->checksum += byte << 8;
+		}
+	}
+
+	/* Now write checksum */
+	set_bitfield ("checksum", binary->checksum);
+
+	fprintf(stdout, "%c", 0xba - (binary->checksum & 0xff));
+	fprintf(stdout, "%c", 0xba - ((binary->checksum & 0xff00) >> 8));
+
+	append_field_to_blob (value_to_bits(binary->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(stdout, "%c", byte);
+	}
+}
+
+%}
+
+%union
+{
+	char *str;
+	unsigned int u32;
+	unsigned char u8;
+	unsigned int *u32array;
+}
+
+%token <u32> val
+%token <u32array> vals
+%token <str> name
+%token <u8> hexbyte
+
+%left '{' '}'
+%left '[' ']'
+%left ','
+%left ':'
+%left '='
+
+%%
+
+input:
+  %empty
+| input spec setter		{ empty_field_table(); }
+| input spec binary		{ empty_field_table(); }
+;
+
+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); }
+;
+
+binary:
+  '[' ']'		{	fprintf (stderr, "No binary\n"); }
+| '[' bytes ']'		{	fprintf (stderr, "Parsed all bytes\n");
+				generate_setter_bitfields(); }
+;
+
+bytes:
+  hexbyte		{	append_field_to_blob(value_to_bits($1, 8), 8); }
+| bytes ',' hexbyte	{	append_field_to_blob(value_to_bits($3, 8), 8); }
+;
+
+%%
+
+/* Called by yyparse on error.  */
+void yyerror (char const *s)
+{
+	fprintf (stderr, "yyerror: %s\n", s);
+}
+
+int main (int argc, char *argv[])
+{
+	if (argc > 1) {
+		if (strcmp (argv[1], "-m") == 0) {
+			mac = parsemac (argv[2]);
+		}
+	}
+
+	return yyparse ();
+}



More information about the coreboot-gerrit mailing list