smaller changes to silence build warnings. (trivial)
[coreboot.git] / util / options / build_opt_tbl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include "../../src/include/pc80/mc146818rtc.h"
7 #include "../../src/include/boot/linuxbios_tables.h"
8
9 #define CMOS_IMAGE_BUFFER_SIZE 128
10 #define INPUT_LINE_MAX 256
11 #define MAX_VALUE_BYTE_LENGTH 64
12
13
14 static unsigned char cmos_table[4096];
15
16 /* This array is used to isolate bits that are to be changed in a byte */
17 static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
18
19
20 /* This routine loops through the entried and tests if any of the fields overlap
21         input entry_start = the memory pointer to the start of the entries.
22               entry_end = the byte past the entries.
23         output  none
24                 if there is an overlap, the routine exits, other wise it returns.
25 */
26 void test_for_entry_overlaps(void *entry_start, void *entry_end)
27 {
28         int ptr;
29         char *cptr;
30         int buffer_bit_size;
31         int offset;
32         int byte;
33         int byte_length;
34         struct cmos_entries *ce;
35         unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
36         unsigned char set;
37
38         /* calculate the size of the cmos buffer in bits */
39         buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
40         /* clear the temporary test buffer */
41         for(ptr=0; ptr < CMOS_IMAGE_BUFFER_SIZE; ptr++)
42                 test[ptr]=0;
43
44         /* loop through each entry in the table testing for errors */
45         for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
46                 ce=(struct cmos_entries *)cptr;
47                 /* test if entry goes past the end of the buffer */
48                 if((ce->bit+ce->length)>buffer_bit_size) {
49                         printf("Error - Entry %s start bit + length must be less than %d\n",
50                                 ce->name,buffer_bit_size);
51                         exit(1);
52                 }
53                 byte=ce->bit/8;
54                 offset=ce->bit%8;
55                 byte_length=ce->length/8;
56                 if(byte_length) {       /* entry is 8 bits long or more */
57                         if(offset) { /* if 8 bits or more long, it must be byte aligned */
58                                 printf("Error - Entry %s length over 8 must be byte aligned\n",
59                                         ce->name);
60                                 exit(1);
61                         }
62                         /* test if entries 8 or more in length are even bytes */ 
63                         if(ce->length%8){
64                                 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
65                                         ce->name);
66                                 exit(1);
67                         }
68                         /* test if any of the bits have been previously used */
69                         for(;byte_length;byte_length--,byte++) {
70                                 if(test[byte]) {
71                                         printf("Error - Entry %s uses same bits previously used\n",
72                                                 ce->name);
73                                         exit(1);
74                                 }
75                                 test[byte]=clip[8]; /* set the bits defined in test */
76                         }
77                 } else {
78                         /* test if bits overlap byte boundaries */
79                         if(ce->length>(8-offset)) {
80                                 printf("Error - Entry %s length overlaps a byte boundry\n",
81                                         ce->name);
82                                 exit(1);
83                         }
84                         /* test for bits previously used */
85                         set=(clip[ce->length]<<offset);
86                         if(test[byte]&set) {
87                                 printf("Error - Entry %s uses same bits previously used\n",
88                                                 ce->name);
89                                 exit(1);
90                         }
91                         test[byte]|=set;  /* set the bits defined in test */
92                 }
93         }
94         return;
95 }
96
97 /* This routine displays the usage options */
98 void display_usage(void)
99 {
100         printf("Usage build_opt_table [-b] [--option filename]\n");
101         printf("                [--config filename]\n");
102         printf("                [--header filename]\n");
103         printf("b = build option_table.c\n");
104         printf("--option = name of option table output file\n");
105         printf("--config = build the definitions table from the given file\n");
106         printf("--header = ouput a header file with the definitions\n");
107         exit(1);
108 }
109
110
111 static void skip_spaces(char *line, char **ptr)
112 {
113         if (!isspace(**ptr)) {
114                 printf("Error missing whitespace in line\n%s\n", line);
115                 exit(1);
116         }
117         while(isspace(**ptr)) {
118                 (*ptr)++;
119         }
120         return;
121 }
122 static unsigned long get_number(char *line, char **ptr, int base)
123 {
124         unsigned long value;
125         char *ptr2;
126         value = strtoul(*ptr, &ptr2, base);
127         if (ptr2 == *ptr) {
128                 printf("Error missing digits at: \n%s\n in line:\n%s\n", 
129                         *ptr, line);
130                 exit(1);
131         }
132         *ptr = ptr2;
133         return value;
134 }
135
136 static int is_ident_digit(int c)
137 {
138         int result;
139         switch(c) {
140         case '0':       case '1':       case '2':       case '3':
141         case '4':       case '5':       case '6':       case '7':
142         case '8':       case '9':
143                 result = 1;
144                 break;
145         default:
146                 result = 0;
147                 break;
148         }
149         return result;
150 }
151
152 static int is_ident_nondigit(int c)
153 {
154         int result;
155         switch(c) {
156         case 'A':       case 'B':       case 'C':       case 'D':
157         case 'E':       case 'F':       case 'G':       case 'H':
158         case 'I':       case 'J':       case 'K':       case 'L':
159         case 'M':       case 'N':       case 'O':       case 'P':
160         case 'Q':       case 'R':       case 'S':       case 'T':
161         case 'U':       case 'V':       case 'W':       case 'X':
162         case 'Y':       case 'Z':
163         case 'a':       case 'b':       case 'c':       case 'd':
164         case 'e':       case 'f':       case 'g':       case 'h':
165         case 'i':       case 'j':       case 'k':       case 'l':
166         case 'm':       case 'n':       case 'o':       case 'p':
167         case 'q':       case 'r':       case 's':       case 't':
168         case 'u':       case 'v':       case 'w':       case 'x':
169         case 'y':       case 'z':
170         case '_':
171                 result = 1;
172                 break;
173         default:
174                 result = 0;
175                 break;
176         }
177         return result;
178 }
179
180 static int is_ident(char *str)
181 {
182         int result;
183         int ch;
184         ch = *str;
185         result = 0;
186         if (is_ident_nondigit(ch)) {
187                 do {
188                         str++;
189                         ch = *str;
190                 } while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
191                 result = (ch == '\0');
192         }
193         return result;
194 }
195
196
197 /* This routine builds the cmos definition table from the cmos layout file
198         input The input comes from the configuration file which contains two parts
199                 entries and enumerations. Each section is started with the key words
200                 entries and enumerations.  Records then follow in their respective 
201                 formats.
202         output The output of this program is the cmos definitions table.  It is stored
203                 in the cmos_table array. If this module is called, and the global 
204                 table_file has been implimented by the user, the table is also written
205                 to the specified file.
206                 This program exits on and error.  It returns a 1 on successful 
207                 completion
208 */
209 int main(int argc, char **argv)
210 {
211         int i;
212         char *config=0;
213         char *option=0;
214         char *header=0;
215         FILE *fp;
216         struct cmos_option_table *ct;
217         struct cmos_entries *ce;
218         struct cmos_enums *c_enums, *c_enums_start;
219         struct cmos_checksum *cs;
220         char line[INPUT_LINE_MAX];
221         unsigned char uc;
222         int entry_mode=0;
223         int enum_mode=0;
224         int checksum_mode=0;
225         long ptr;
226         int cnt;
227         char *cptr;
228         void *entry_start, *entry_end;
229         int entries_length;
230         int enum_length;
231         int len;
232         char buf[16];
233
234         for(i=1;i<argc;i++) {
235                 if(argv[i][0]!='-') {
236                         display_usage();
237                 }
238                 switch(argv[i][1]) {
239                         case 'b':       /* build the table */
240                                 break;
241                         case '-':       /* data is requested from a file */
242                                 switch(argv[i][2]) {
243                                         case 'c':  /* use a configuration file */
244                                                 if(strcmp(&argv[i][2],"config")) {
245                                                         display_usage();
246                                                 }
247                                                 config=argv[++i];
248                                                 break;
249                                         case 'o':  /* use a cmos definitions table file */
250                                                 if(strcmp(&argv[i][2],"option")) {
251                                                         display_usage();
252                                                 }
253                                                 option=argv[++i];
254                                                 break;
255                                         case 'h': /* Output a header file */
256                                                 if (strcmp(&argv[i][2], "header") != 0) {
257                                                         display_usage();
258                                                 }
259                                                 header=argv[++i];
260                                                 break;
261                                         default:
262                                                 display_usage();
263                                                 break;
264                                 }
265                                 break;
266
267                         default:
268                                 display_usage();
269                                 break;
270                 }
271         }
272
273
274         /* Has the user specified a configuration file */
275         if(config) {    /* if yes, open it */
276                 if((fp=fopen(config,"r"))==NULL){
277                         fprintf(stderr, "Error - Can not open config file %s\n",config);
278                         exit(1);  /* exit if it can not be opened */
279                 }
280         }
281         else {  /* no configuration file specified, so try the default */
282                 if((fp=fopen("cmos.layout","r"))==NULL){
283                         fprintf(stderr, "Error - Can not open cmos.layout\n");
284                         exit(1);  /* end of no configuration file is found */
285                 }
286         }
287         /* type cast a pointer, so we can us the structure */
288         ct=(struct cmos_option_table*)cmos_table;
289         /* start the table with the type signature */
290         ct->tag = LB_TAG_CMOS_OPTION_TABLE;
291         /* put in the header length */
292         ct->header_length=sizeof(*ct);
293
294         /* Get the entry records */
295         ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
296         cptr = (char*)ce;
297         for(;;){  /* this section loops through the entry records */
298                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
299                         break; /* end if no more input */
300                 if(!entry_mode) {  /* skip input until the entries key word */
301                         if (strstr(line,"entries") != 0) {
302                                 entry_mode=1;
303                                 continue;
304                         }
305                 }
306                 else{  /* Test if we are done with entries and starting enumerations */
307                         if (strstr(line,"enumerations") != 0){
308                                 entry_mode=0;
309                                 enum_mode=1;
310                                 break;
311                         }
312                         if (strstr(line, "checksums") != 0) {
313                                 enum_mode=0;
314                                 checksum_mode=1;
315                                 break;
316                         }
317                 }
318
319                 /* skip commented and blank lines */
320                 if(line[0]=='#') continue;
321                 if(line[strspn(line," ")]=='\n') continue;
322                 /* scan in the input data */
323                 sscanf(line,"%d %d %c %d %s",
324                         &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
325                 ce->config=(int)uc;
326                 /* check bit and length ranges */
327                 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
328                         fprintf(stderr, "Error - bit is to big in line \n%s\n",line);
329                         exit(1);
330                 }
331                 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
332                         fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
333                         exit(1);
334                 }
335                 if (!is_ident((char *)ce->name)) {
336                         fprintf(stderr, 
337                                 "Error - Name %s is an invalid identifier in line\n %s\n", 
338                                 ce->name, line);
339                         exit(1);
340                 }
341                 /* put in the record type */
342                 ce->tag=LB_TAG_OPTION;
343                 /* calculate and save the record length */
344                 len=strlen((char *)ce->name)+1;
345                 /* make the record int aligned */
346                 if(len%4)
347                         len+=(4-(len%4));
348                 ce->size=sizeof(struct cmos_entries)-32+len;
349                 cptr = (char*)ce;
350                 cptr += ce->size;  /* increment to the next table position */
351                 ce = (struct cmos_entries*) cptr;
352         }
353
354         /* put the length of the entries into the header section */
355         entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
356
357         /* compute the start of the enumerations section */
358         entry_start = ((char*)&cmos_table) + ct->header_length;
359         entry_end   = ((char *)entry_start) + entries_length;
360         c_enums_start = c_enums = (struct cmos_enums*)entry_end;
361         /* test for overlaps in the entry records */
362         test_for_entry_overlaps(entry_start, entry_end);
363
364         for(;enum_mode;){ /* loop to build the enumerations section */
365                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
366                         break; /* go till end of input */
367
368                 if (strstr(line, "checksums") != 0) {
369                         enum_mode=0;
370                         checksum_mode=1;
371                         break;
372                 }
373
374                 /* skip commented and blank lines */
375                 if(line[0]=='#') continue;
376                 if(line[strspn(line," ")]=='\n') continue;
377
378                 /* scan in the data */
379                 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
380                 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
381                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
382                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
383                 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
384                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
385                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
386                 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
387                         c_enums->text[cnt]=line[ptr];
388                 c_enums->text[cnt]=0;
389         
390                 /* make the record int aligned */
391                 cnt++;
392                 if(cnt%4)
393                         cnt+=4-(cnt%4);
394                 /* store the record length */
395                 c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums;
396                 /* store the record type */
397                 c_enums->tag=LB_TAG_OPTION_ENUM;
398                 /* increment to the next record */
399                 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
400         }
401         /* save the enumerations length */
402         enum_length= (char *)c_enums - (char *)c_enums_start;
403         ct->size=ct->header_length+enum_length+entries_length;
404
405         /* Get the checksum records */
406         cs=(struct cmos_checksum *)(cmos_table+(ct->size));
407         cptr = (char*)cs;
408         for(;checksum_mode;) { /* This section finds the checksums */
409                 char *ptr;
410                 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
411                         break; /* end if no more input */
412
413                 /* skip commented and blank lines */
414                 if (line[0]=='#') continue;
415                 if (line[strspn(line, " ")]=='\n') continue;
416                 if (memcmp(line, "checksum", 8) != 0) continue;
417
418                 /* get the information */
419                 ptr = line + 8;
420                 skip_spaces(line, &ptr);
421                 cs->range_start = get_number(line, &ptr, 10);
422
423                 skip_spaces(line, &ptr);
424                 cs->range_end = get_number(line, &ptr, 10);
425
426                 skip_spaces(line, &ptr);
427                 cs->location = get_number(line, &ptr, 10);
428                 
429                 /* Make certain there are spaces until the end of the line */
430                 skip_spaces(line, &ptr);
431
432                 if ((cs->range_start%8) != 0) {
433                         fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
434                         exit(1);
435                 }
436                 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
437                         fprintf(stderr, "Error - range start is to big in line\n%s\n", line);
438                         exit(1);
439                 }
440                 if ((cs->range_end%8) != 7) {
441                         fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
442                         exit(1);
443                 }
444                 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
445                         fprintf(stderr, "Error - range end is to long in line\n%s\n", line);
446                         exit(1);
447                 }
448                 if ((cs->location%8) != 0) {
449                         fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
450                         exit(1);
451                 }
452                 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
453                         ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8))) 
454                 {
455                         fprintf(stderr, "Error - location is to big in line\n%s\n", line);
456                         exit(1);
457                 }
458                 /* And since we are not ready to be fully general purpose yet.. */
459                 if ((cs->range_start/8) != LB_CKS_RANGE_START) {
460                         fprintf(stderr, "Error - Range start(%d) does not match define(%d) in line\n%s\n", 
461                                 cs->range_start/8, LB_CKS_RANGE_START, line);
462                         exit(1);
463                 }
464                 if ((cs->range_end/8) != LB_CKS_RANGE_END) {
465                         fprintf(stderr, "Error - Range end (%d) does not match define (%d) in line\n%s\n", 
466                                         (cs->range_end/8), LB_CKS_RANGE_END, line);
467                         exit(1);
468                 }
469                 if ((cs->location/8) != LB_CKS_LOC) {
470                         fprintf(stderr, "Error - Location does not match define in line\n%s\n", line);
471                         exit(1);
472                 }
473
474                 cs->tag = LB_TAG_OPTION_CHECKSUM;
475                 cs->size = sizeof(*cs);
476                 cs->type = CHECKSUM_PCBIOS;
477                 cptr = (char *)cs;
478                 cptr += cs->size;
479                 cs = (struct cmos_checksum *)cptr;
480
481         }
482         ct->size += (cptr - (char *)(cmos_table + ct->size));
483         fclose(fp);
484
485         /* test if an alternate file is to be created */
486         if(option) {
487                 if((fp=fopen(option,"w"))==NULL){
488                         fprintf(stderr, "Error - Can not open %s\n",option);
489                         exit(1);
490                 }
491         }
492         else {  /* no, so use the default option_table.c */
493                 if((fp=fopen("option_table.c","w"))==NULL){
494                         fprintf(stderr, "Error - Can not open option_table.c\n");
495                         exit(1);
496                 }
497         }
498         /* write the header */
499         if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
500                 fprintf(stderr, "Error - Could not write image file\n");
501                 fclose(fp);
502                 exit(1);
503         }
504         /* write the array values */
505         for(i=0;i<(ct->size-1);i++) {
506                 if(!(i%10)) fwrite("\n\t",1,2,fp);
507                 sprintf(buf,"0x%02x,",cmos_table[i]);
508                 fwrite(buf,1,5,fp);
509         }
510         /* write the end */
511         sprintf(buf,"0x%02x",cmos_table[i]);
512         fwrite(buf,1,4,fp);
513         if(!fwrite("};\n",1,3,fp)) {
514                 fprintf(stderr, "Error - Could not write image file\n");
515                 fclose(fp);
516                 exit(1);
517         }
518
519         fclose(fp);
520
521         /* See if we also want to output a C header file */
522         if (header) {
523                 struct cmos_option_table *hdr;
524                 struct lb_record *ptr, *end;
525                 fp = fopen(header, "w");
526                 if (!fp) {
527                         fprintf(stderr, "Error Can not open %s: %s\n", 
528                                 header, strerror(errno));
529                         exit(1);
530                 }
531                 /* Get the cmos table header */
532                 hdr = (struct cmos_option_table *)cmos_table;
533                 /* Walk through the entry records */
534                 ptr = (struct lb_record *)(cmos_table + hdr->header_length);
535                 end = (struct lb_record *)(cmos_table + hdr->size);
536                 for(;ptr < end; ptr = (struct lb_record *)(((char *)ptr) + ptr->size)) {
537                         if (ptr->tag != LB_TAG_OPTION) {
538                                 continue;
539                         }
540                         ce = (struct cmos_entries *)ptr;
541                         if (ce->config == 'r') {
542                                 continue;
543                         }
544                         if (!is_ident((char *)ce->name)) {
545                                 fprintf(stderr, "Invalid identifier: %s\n",
546                                         ce->name);
547                                 exit(1);
548                         }
549                         fprintf(fp, "#define CMOS_VSTART_%s %d\n",
550                                 ce->name, ce->bit);
551                         fprintf(fp, "#define CMOS_VLEN_%s %d\n",
552                                 ce->name, ce->length);
553                 }
554                 fclose(fp);
555         }
556         return(0);
557 }
558
559