/ util / bincfg / bincfg.y
bincfg.y
  1  /* bincfg - Compiler/Decompiler for data blobs with specs */
  2  /* SPDX-License-Identifier: GPL-3.0-or-later */
  3  
  4  %{
  5  #include <stdio.h>
  6  #include <inttypes.h>
  7  #include <stdlib.h>
  8  #include <string.h>
  9  #include "bincfg.h"
 10  //#define YYDEBUG 1
 11  
 12  static void check_pointer (void *ptr)
 13  {
 14  	if (ptr == NULL) {
 15  		printf("Error: Out of memory\n");
 16  		exit(1);
 17  	}
 18  }
 19  
 20  static unsigned char* value_to_bits (unsigned int v, unsigned int w)
 21  {
 22  	unsigned int i;
 23  	unsigned char* bitarr;
 24  
 25  	if (w > MAX_WIDTH) w = MAX_WIDTH;
 26  	bitarr = (unsigned char *) malloc (w * sizeof (unsigned char));
 27  	check_pointer(bitarr);
 28  	memset (bitarr, 0, w);
 29  
 30  	for (i = 0; i < w; i++) {
 31  		bitarr[i] = VALID_BIT | ((v & (1 << i)) >> i);
 32  	}
 33  	return bitarr;
 34  }
 35  
 36  /* Store each bit of a bitfield in a new byte sequentially 0x80 or 0x81 */
 37  static void append_field_to_blob (unsigned char b[], unsigned int w)
 38  {
 39  	unsigned int i, j;
 40  	binary->blb = (unsigned char *) realloc (binary->blb,
 41  						 binary->bloblen + w);
 42  	check_pointer(binary->blb);
 43  	for (j = 0, i = binary->bloblen; i < binary->bloblen + w; i++, j++) {
 44  		binary->blb[i] = VALID_BIT | (b[j] & 1);
 45  		//fprintf (stderr, "blob[%d] = %d\n", i, binary->blb[i] & 1);
 46  	}
 47  	binary->bloblen += w;
 48  }
 49  
 50  static void set_bitfield(char *name, unsigned int value)
 51  {
 52  	unsigned long long i;
 53  	struct field *bf = getsym (name);
 54  	if (bf) {
 55  		bf->value = value & 0xffffffff;
 56  		i = (1 << bf->width) - 1;
 57  		if (bf->width > 8 * sizeof (unsigned int)) {
 58  			fprintf(stderr,
 59  				"Overflow in bitfield, truncating bits to"
 60  				" fit\n");
 61  			bf->value = value & i;
 62  		}
 63  		//fprintf(stderr, "Setting `%s` = %d\n", bf->name, bf->value);
 64  	} else {
 65  		fprintf(stderr, "Can't find bitfield `%s` in spec\n", name);
 66  	}
 67  }
 68  
 69  static void set_bitfield_array(char *name, unsigned int n, unsigned int value)
 70  {
 71  	unsigned int i;
 72  	unsigned long len = strlen (name);
 73  	char *namen = (char *) malloc ((len + 9) * sizeof (char));
 74  	check_pointer(namen);
 75  	for (i = 0; i < n; i++) {
 76  		snprintf (namen, len + 8, "%s%x", name, i);
 77  		set_bitfield (namen, value);
 78  	}
 79  	free(namen);
 80  }
 81  
 82  static void create_new_bitfield(char *name, unsigned int width)
 83  {
 84  	struct field *bf;
 85  
 86  	if (!(bf = putsym (name, width))) return;
 87  	//fprintf(stderr, "Added bitfield `%s` : %d\n", bf->name, width);
 88  }
 89  
 90  static void create_new_bitfields(char *name, unsigned int n, unsigned int width)
 91  {
 92  	unsigned int i;
 93  	unsigned long len = strlen (name);
 94  	char *namen = (char *) malloc ((len + 9) * sizeof (char));
 95  	check_pointer(namen);
 96  	for (i = 0; i < n; i++) {
 97  		snprintf (namen, len + 8, "%s%x", name, i);
 98  		create_new_bitfield (namen, width);
 99  	}
100  	free(namen);
101  }
102  
103  static struct field *putsym (char const *sym_name, unsigned int w)
104  {
105  	if (getsym(sym_name)) {
106  		fprintf(stderr, "Cannot add duplicate named bitfield `%s`\n",
107  			sym_name);
108  		return 0;
109  	}
110  	struct field *ptr = (struct field *) malloc (sizeof (struct field));
111  	check_pointer(ptr);
112  	ptr->name = (char *) malloc (strlen (sym_name) + 1);
113  	check_pointer(ptr->name);
114  	strcpy (ptr->name, sym_name);
115  	ptr->width = w;
116  	ptr->value = 0;
117  	ptr->next = (struct field *)0;
118  	if (sym_table_tail) {
119  		sym_table_tail->next = ptr;
120  	} else {
121  		sym_table = ptr;
122  	}
123  	sym_table_tail = ptr;
124  	return ptr;
125  }
126  
127  static struct field *getsym (char const *sym_name)
128  {
129  	struct field *ptr;
130  	for (ptr = sym_table; ptr != (struct field *) 0;
131  			ptr = (struct field *)ptr->next) {
132  		if (strcmp (ptr->name, sym_name) == 0)
133  			return ptr;
134  	}
135  	return 0;
136  }
137  
138  static void dump_all_values (void)
139  {
140  	struct field *ptr;
141  	for (ptr = sym_table; ptr != (struct field *) 0;
142  			ptr = (struct field *)ptr->next) {
143  		fprintf(stderr, "%s = %d (%d bits)\n",
144  				ptr->name,
145  				ptr->value,
146  				ptr->width);
147  	}
148  }
149  
150  static void empty_field_table(void)
151  {
152  	struct field *ptr;
153  	struct field *ptrnext;
154  
155  	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptrnext) {
156  		if (ptr) {
157  			ptrnext = ptr->next;
158  			free(ptr);
159  		} else {
160  			ptrnext = (struct field *) 0;
161  		}
162  	}
163  	sym_table = 0;
164  	sym_table_tail = 0;
165  }
166  
167  static void create_binary_blob (void)
168  {
169  	if (binary && binary->blb) {
170  		free(binary->blb);
171  		free(binary);
172  	}
173  	binary = (struct blob *) malloc (sizeof (struct blob));
174  	check_pointer(binary);
175  	binary->blb = (unsigned char *) malloc (sizeof (unsigned char));
176  	check_pointer(binary->blb);
177  	binary->bloblen = 0;
178  	binary->blb[0] = VALID_BIT;
179  }
180  
181  static void interpret_next_blob_value (struct field *f)
182  {
183  	unsigned int i;
184  	unsigned int v = 0;
185  
186  	if (binary->bloblen >= binary->lenactualblob * 8) {
187  		f->value = 0;
188  		return;
189  	}
190  
191  	for (i = 0; i < f->width; i++) {
192  		v |= (binary->blb[binary->bloblen++] & 1) << i;
193  	}
194  
195  	f->value = v;
196  }
197  
198  /* {}%BIN -> {} */
199  static void generate_setter_bitfields(FILE* fp, unsigned char *bin)
200  {
201  	unsigned int i;
202  	struct field *ptr;
203  
204  	/* Convert bytes to bit array */
205  	for (i = 0; i < binary->lenactualblob; i++) {
206  		append_field_to_blob (value_to_bits(bin[i], 8), 8);
207  	}
208  
209  	/* Reset blob position to zero */
210  	binary->bloblen = 0;
211  
212  	fprintf (fp, "# AUTOGENERATED SETTER BY BINCFG\n{\n");
213  
214  	/* Traverse spec and output bitfield setters based on blob values */
215  	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
216  
217  		interpret_next_blob_value(ptr);
218  		fprintf (fp, "\t\"%s\" = 0x%x,\n", ptr->name, ptr->value);
219  	}
220  	fseek(fp, -2, SEEK_CUR);
221  	fprintf (fp, "\n}\n");
222  }
223  
224  static void generate_binary_with_gbe_checksum(FILE* fp)
225  {
226  	unsigned int i;
227  	unsigned short checksum;
228  
229  	/* traverse spec, push to blob and add up for checksum */
230  	struct field *ptr;
231  	unsigned int uptochksum = 0;
232  	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
233  		if (strcmp (ptr->name, "checksum_gbe") == 0) {
234  			/* Stop traversing because we hit checksum */
235  			ptr = ptr->next;
236  			break;
237  		}
238  		append_field_to_blob (
239  			value_to_bits(ptr->value, ptr->width),
240  			ptr->width);
241  		uptochksum += ptr->width;
242  	}
243  
244  	/* deserialize bits of blob up to checksum */
245  	for (i = 0; i < uptochksum; i += 8) {
246  		unsigned char byte = (((binary->blb[i+0] & 1) << 0)
247  					| ((binary->blb[i+1] & 1) << 1)
248  					| ((binary->blb[i+2] & 1) << 2)
249  					| ((binary->blb[i+3] & 1) << 3)
250  					| ((binary->blb[i+4] & 1) << 4)
251  					| ((binary->blb[i+5] & 1) << 5)
252  					| ((binary->blb[i+6] & 1) << 6)
253  					| ((binary->blb[i+7] & 1) << 7)
254  		);
255  		fprintf(fp, "%c", byte);
256  
257  		/* incremental 16 bit checksum */
258  		if ((i % 16) < 8) {
259  			binary->checksum += byte;
260  		} else {
261  			binary->checksum += byte << 8;
262  		}
263  	}
264  
265  	checksum = (0xbaba - binary->checksum) & 0xffff;
266  
267  	/* Now write checksum */
268  	set_bitfield ("checksum_gbe", checksum);
269  
270  	fprintf(fp, "%c", checksum & 0xff);
271  	fprintf(fp, "%c", (checksum & 0xff00) >> 8);
272  
273  	append_field_to_blob (value_to_bits(checksum, 16), 16);
274  
275  	for (; ptr != (struct field *) 0; ptr = ptr->next) {
276  		append_field_to_blob (
277  			value_to_bits(ptr->value, ptr->width), ptr->width);
278  	}
279  
280  	/* deserialize rest of blob past checksum */
281  	for (i = uptochksum + CHECKSUM_SIZE; i < binary->bloblen; i += 8) {
282  		unsigned char byte = (((binary->blb[i+0] & 1) << 0)
283  					| ((binary->blb[i+1] & 1) << 1)
284  					| ((binary->blb[i+2] & 1) << 2)
285  					| ((binary->blb[i+3] & 1) << 3)
286  					| ((binary->blb[i+4] & 1) << 4)
287  					| ((binary->blb[i+5] & 1) << 5)
288  					| ((binary->blb[i+6] & 1) << 6)
289  					| ((binary->blb[i+7] & 1) << 7)
290  		);
291  		fprintf(fp, "%c", byte);
292  	}
293  }
294  
295  /* {}{} -> BIN */
296  static void generate_binary(FILE* fp)
297  {
298  	unsigned int i;
299  	struct field *ptr;
300  
301  	if (binary->bloblen % 8) {
302  		fprintf (stderr,
303  			 "ERROR: Spec must be multiple of 8 bits wide\n");
304  		exit (1);
305  	}
306  
307  	if (getsym ("checksum_gbe")) {
308  		generate_binary_with_gbe_checksum(fp);
309  		return;
310  	}
311  
312  	/* traverse spec, push to blob */
313  	for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
314  		append_field_to_blob (
315  			value_to_bits(ptr->value, ptr->width),
316  			ptr->width);
317  	}
318  
319  	/* deserialize bits of blob */
320  	for (i = 0; i < binary->bloblen; i += 8) {
321  		unsigned char byte = (((binary->blb[i+0] & 1) << 0)
322  				| ((binary->blb[i+1] & 1) << 1)
323  				| ((binary->blb[i+2] & 1) << 2)
324  				| ((binary->blb[i+3] & 1) << 3)
325  				| ((binary->blb[i+4] & 1) << 4)
326  				| ((binary->blb[i+5] & 1) << 5)
327  				| ((binary->blb[i+6] & 1) << 6)
328  				| ((binary->blb[i+7] & 1) << 7)
329  		);
330  		fprintf(fp, "%c", byte);
331  	}
332  }
333  
334  %}
335  
336  %union
337  {
338  	char *str;
339  	unsigned int u32;
340  	unsigned int *u32array;
341  	unsigned char u8;
342  	unsigned char *u8array;
343  }
344  %parse-param {FILE* fp}
345  
346  %token <str> name
347  %token <u32> val
348  %token <u32array> vals
349  %token <u8> hexbyte
350  %token <u8array> binblob
351  %token <u8> eof
352  
353  %left '%'
354  %left '{' '}'
355  %left ','
356  %left ':'
357  %left '='
358  
359  %%
360  
361  input:
362    /* empty */
363  | input spec setter eof		{ empty_field_table(); YYACCEPT;}
364  | input spec blob		{ fprintf (stderr, "Parsed all bytes\n");
365  				  empty_field_table(); YYACCEPT;}
366  ;
367  
368  blob:
369    '%' eof			{ generate_setter_bitfields(fp,
370  				  binary->actualblob); }
371  ;
372  
373  spec:
374    '{' '}'		{	fprintf (stderr, "No spec\n"); }
375  | '{' specmembers '}'	{	fprintf (stderr, "Parsed all spec\n");
376  				create_binary_blob(); }
377  ;
378  
379  specmembers:
380    specpair
381  | specpair ',' specmembers
382  ;
383  
384  specpair:
385    name ':' val		{	create_new_bitfield($1, $3); }
386  | name '[' val ']' ':' val	{ create_new_bitfields($1, $3, $6); }
387  ;
388  
389  setter:
390    '{' '}'		{	fprintf (stderr, "No values\n"); }
391  | '{' valuemembers '}'	{	fprintf (stderr, "Parsed all values\n");
392  				generate_binary(fp); }
393  ;
394  
395  valuemembers:
396    setpair
397  | setpair ',' valuemembers
398  ;
399  
400  setpair:
401    name '=' val		{	set_bitfield($1, $3); }
402  | name '[' val ']' '=' val	{ set_bitfield_array($1, $3, $6); }
403  ;
404  
405  %%
406  
407  /* Called by yyparse on error.  */
408  static void yyerror (FILE* fp, char const *s)
409  {
410  	(void)fp;
411  	fprintf (stderr, "yyerror: %s\n", s);
412  }
413  
414  /* Declarations */
415  void set_input_string(char* in);
416  
417  /* This function parses a string */
418  static int parse_string(FILE* fp, unsigned char* in) {
419  	set_input_string ((char *)in);
420  	return yyparse (fp);
421  }
422  
423  static unsigned int loadfile (FILE* fp, char *file, char *filetype,
424  	unsigned char **parsestring, unsigned int lenstr)
425  {
426  	unsigned int lenfile;
427  
428  	if ((fp = fopen(file, "r")) == NULL) {
429  		printf("Error: Could not open %s file: %s\n",filetype,file);
430  		exit(1);
431  	}
432  	fseek(fp, 0, SEEK_END);
433  	lenfile = ftell(fp);
434  	fseek(fp, 0, SEEK_SET);
435  
436  	if (lenstr == 0)
437  		*parsestring = (unsigned char *) malloc (lenfile + 2);
438  	else
439  		*parsestring = (unsigned char *) realloc (*parsestring,
440  						lenfile + lenstr);
441  
442  	check_pointer(*parsestring);
443  	fread(*parsestring + lenstr, 1, lenfile, fp);
444  	fclose(fp);
445  	return lenfile;
446  }
447  
448  int main (int argc, char *argv[])
449  {
450  	unsigned int lenspec;
451  	unsigned char *parsestring;
452  	int ret = 0;
453  	FILE* fp;
454  
455  #if YYDEBUG == 1
456  	yydebug = 1;
457  #endif
458  	create_binary_blob();
459  	binary->lenactualblob = 0;
460  
461  	if (argc == 4 && strcmp(argv[1], "-d") != 0) {
462  		/* Compile mode */
463  
464  		/* Load Spec */
465  		lenspec = loadfile(fp, argv[1], "spec", &parsestring, 0);
466  		loadfile(fp, argv[2], "setter", &parsestring, lenspec);
467  
468  		/* Open output and parse string - output to fp */
469  		if ((fp = fopen(argv[3], "wb")) == NULL) {
470  			printf("Error: Could not open output file: %s\n",
471  			       argv[3]);
472  			exit(1);
473  		}
474  		ret = parse_string(fp, parsestring);
475  		free(parsestring);
476  	} else if (argc == 5 && strcmp (argv[1], "-d") == 0) {
477  		/* Decompile mode */
478  
479  		/* Load Spec */
480  		lenspec = loadfile(fp, argv[2], "spec", &parsestring, 0);
481  
482  		parsestring[lenspec] = '%';
483  		parsestring[lenspec + 1] = '\0';
484  
485  		/* Load Actual Binary */
486  		if ((fp = fopen(argv[3], "rb")) == NULL) {
487  			printf("Error: Could not open binary file: %s\n",
488  			       argv[3]);
489  			exit(1);
490  		}
491  		fseek(fp, 0, SEEK_END);
492  		binary->lenactualblob = ftell(fp);
493  		fseek(fp, 0, SEEK_SET);
494  		binary->actualblob = (unsigned char *)malloc(
495  			binary->lenactualblob);
496  		check_pointer(binary->actualblob);
497  		fread(binary->actualblob, 1, binary->lenactualblob, fp);
498  		fclose(fp);
499  
500  		/* Open output and parse - output to fp */
501  		if ((fp = fopen(argv[4], "w")) == NULL) {
502  			printf("Error: Could not open output file: %s\n",
503  			       argv[4]);
504  			exit(1);
505  		}
506  		ret = parse_string(fp, parsestring);
507  		free(parsestring);
508  		free(binary->actualblob);
509  		fclose(fp);
510  	} else {
511  		printf("Usage: Compile mode\n\n");
512  		printf("       bincfg    spec  setter  binaryoutput\n");
513  		printf("                  (file) (file)     (file)\n");
514  		printf(" OR  : Decompile mode\n\n");
515  		printf("       bincfg -d spec  binary  setteroutput\n");
516  	}
517  	return ret;
518  }