xref: /aosp_15_r20/external/coreboot/util/bincfg/bincfg.y (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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 
check_pointer(void * ptr)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 
value_to_bits(unsigned int v,unsigned int w)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 */
append_field_to_blob(unsigned char b[],unsigned int w)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 
set_bitfield(char * name,unsigned int value)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 
set_bitfield_array(char * name,unsigned int n,unsigned int value)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 
create_new_bitfield(char * name,unsigned int width)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 
create_new_bitfields(char * name,unsigned int n,unsigned int width)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 
putsym(char const * sym_name,unsigned int w)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 
getsym(char const * sym_name)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 
dump_all_values(void)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 
empty_field_table(void)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 
create_binary_blob(void)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 
interpret_next_blob_value(struct field * f)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 -> {} */
generate_setter_bitfields(FILE * fp,unsigned char * 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 
generate_binary_with_gbe_checksum(FILE * fp)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 */
generate_binary(FILE * fp)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 */
parse_string(FILE * fp,unsigned char * in)418 static int parse_string(FILE* fp, unsigned char* in) {
419 	set_input_string ((char *)in);
420 	return yyparse (fp);
421 }
422 
loadfile(FILE * fp,char * file,char * filetype,unsigned char ** parsestring,unsigned int lenstr)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 
main(int argc,char * argv[])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 }
519