summaryrefslogtreecommitdiff
path: root/util/bincfg/bincfg.y
diff options
context:
space:
mode:
authorDenis 'GNUtoo' Carikli <GNUtoo@no-log.org>2018-01-10 14:35:55 +0100
committerNico Huber <nico.h@gmx.de>2018-01-18 13:47:20 +0000
commit780e931eed8937bd8e304449913f487fa1d056c5 (patch)
tree24446641394bdabfee26130913eed808fe658ffa /util/bincfg/bincfg.y
parent86391f16054ff1aa8af75b552204d24f3c00d50e (diff)
util/blobtool: rename to bincfg
The name blobtool is confusing as 'blob' is also used to describe nonfree software in binary form. Since this utility deals with binary configurations it makes more sense to call it bincfg. Change-Id: I3339274f1c42df4bb4a6b30b9538d91c3c03d7d0 Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@no-log.org> Reviewed-on: https://review.coreboot.org/23239 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Paul Kocialkowski <contact@paulk.fr> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'util/bincfg/bincfg.y')
-rw-r--r--util/bincfg/bincfg.y551
1 files changed, 551 insertions, 0 deletions
diff --git a/util/bincfg/bincfg.y b/util/bincfg/bincfg.y
new file mode 100644
index 0000000000..7a098cd258
--- /dev/null
+++ b/util/bincfg/bincfg.y
@@ -0,0 +1,551 @@
+/*
+ * bincfg - 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;
+
+static void check_pointer (void *ptr)
+{
+ if (ptr == NULL) {
+ printf("Error: Out of memory\n");
+ exit(1);
+ }
+}
+
+static 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));
+ check_pointer(bitarr);
+ 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 */
+static 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);
+ check_pointer(binary->blb);
+ 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;
+}
+
+static 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);
+ }
+}
+
+static void set_bitfield_array(char *name, unsigned int n, unsigned int value)
+{
+ unsigned int i;
+ unsigned long len = strlen (name);
+ char *namen = (char *) malloc ((len + 9) * sizeof (char));
+ check_pointer(namen);
+ for (i = 0; i < n; i++) {
+ snprintf (namen, len + 8, "%s%x", name, i);
+ set_bitfield (namen, value);
+ }
+ free(namen);
+}
+
+static 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);
+}
+
+static void create_new_bitfields(char *name, unsigned int n, unsigned int width)
+{
+ unsigned int i;
+ unsigned long len = strlen (name);
+ char *namen = (char *) malloc ((len + 9) * sizeof (char));
+ check_pointer(namen);
+ 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));
+ check_pointer(ptr);
+ ptr->name = (char *) malloc (strlen (sym_name) + 1);
+ check_pointer(ptr->name);
+ 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;
+}
+
+static 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);
+ }
+}
+
+static 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;
+}
+
+static void create_binary_blob (void)
+{
+ if (binary && binary->blb) {
+ free(binary->blb);
+ free(binary);
+ }
+ binary = (struct blob *) malloc (sizeof (struct blob));
+ check_pointer(binary);
+ binary->blb = (unsigned char *) malloc (sizeof (unsigned char));
+ check_pointer(binary->blb);
+ binary->bloblen = 0;
+ binary->blb[0] = VALID_BIT;
+}
+
+static void interpret_next_blob_value (struct field *f)
+{
+ unsigned 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 -> {} */
+static 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 BINCFG\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");
+}
+
+static 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 */
+static 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 */
+static int parse_string(unsigned char* in) {
+ set_input_string ((char *)in);
+ return yyparse ();
+}
+
+static unsigned int loadfile (char *file, char *filetype,
+ unsigned char **parsestring, unsigned int lenstr)
+{
+ unsigned int lenfile;
+
+ if ((fp = fopen(file, "r")) == NULL) {
+ printf("Error: Could not open %s file: %s\n",filetype,file);
+ exit(1);
+ }
+ fseek(fp, 0, SEEK_END);
+ lenfile = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ if (lenstr == 0)
+ *parsestring = (unsigned char *) malloc (lenfile + 2);
+ else
+ *parsestring = (unsigned char *) realloc (*parsestring,
+ lenfile + lenstr);
+
+ check_pointer(*parsestring);
+ fread(*parsestring + lenstr, 1, lenfile, fp);
+ fclose(fp);
+ return lenfile;
+}
+
+int main (int argc, char *argv[])
+{
+ unsigned int lenspec;
+ 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 */
+ lenspec = loadfile(argv[1], "spec", &parsestring, 0);
+ loadfile(argv[2], "setter", &parsestring, lenspec);
+
+ /* Open output and parse string - output to fp */
+ if ((fp = fopen(argv[3], "wb")) == NULL) {
+ printf("Error: Could not open output file: %s\n",argv[3]);
+ exit(1);
+ }
+ ret = parse_string(parsestring);
+ free(parsestring);
+ } else if (argc == 5 && strcmp (argv[1], "-d") == 0) {
+ /* Decompile mode */
+
+ /* Load Spec */
+ lenspec = loadfile(argv[2], "spec", &parsestring, 0);
+
+ parsestring[lenspec] = '%';
+ parsestring[lenspec + 1] = '\0';
+
+ /* Load Actual Binary */
+ if ((fp = fopen(argv[3], "rb")) == NULL) {
+ printf("Error: Could not open binary file: %s\n",argv[3]);
+ exit(1);
+ }
+ fseek(fp, 0, SEEK_END);
+ binary->lenactualblob = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ binary->actualblob = (unsigned char *) malloc (binary->lenactualblob);
+ check_pointer(binary->actualblob);
+ fread(binary->actualblob, 1, binary->lenactualblob, fp);
+ fclose(fp);
+
+ /* Open output and parse - output to fp */
+ if ((fp = fopen(argv[4], "w")) == NULL) {
+ printf("Error: Could not open output file: %s\n",argv[4]);
+ exit(1);
+ }
+ ret = parse_string(parsestring);
+ free(parsestring);
+ free(binary->actualblob);
+ fclose(fp);
+ } else {
+ printf("Usage: Compile mode\n\n");
+ printf(" bincfg spec setter binaryoutput\n");
+ printf(" (file) (file) (file)\n");
+ printf(" OR : Decompile mode\n\n");
+ printf(" bincfg -d spec binary setteroutput\n");
+ }
+ return ret;
+}