2 * This file is part of the coreboot project.
4 * Copyright (C) 2003 Eric Biederman (ebiederm@xmission.com)
5 * Copyright (C) 2007-2010 coresystems GmbH
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
28 #define UTIL_BUILD_OPTION_TABLE
29 #include "../../src/include/pc80/mc146818rtc.h"
30 #include "../../src/include/boot/coreboot_tables.h"
32 #define CMOS_IMAGE_BUFFER_SIZE 256
33 #define INPUT_LINE_MAX 256
34 #define MAX_VALUE_BYTE_LENGTH 64
36 #define TMPFILE_LEN 256
37 #define TMPFILE_TEMPLATE "/build_opt_tbl_XXXXXX"
39 static unsigned char cmos_table[4096];
41 /* This array is used to isolate bits that are to be changed in a byte */
42 static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
46 char *mkstemp(char* name)
52 return open(name,O_CREAT | O_RDWR);
54 #define UNLINK_IF_NECESSARY(x) unlink(x)
56 #define UNLINK_IF_NECESSARY(x)
60 * This routine loops through the entried and tests if any of the fields
62 * If there is an overlap, the routine exits, otherwise it returns.
64 * @param entry_start memory pointer to the start of the entries.
65 * @param entry_end memory pointer to the byte past the entries.
67 static void test_for_entry_overlaps(void *entry_start, void *entry_end)
75 struct cmos_entries *ce;
76 unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
79 /* calculate the size of the cmos buffer in bits */
80 buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
81 /* clear the temporary test buffer */
82 for(ptr=0; ptr < CMOS_IMAGE_BUFFER_SIZE; ptr++)
85 /* loop through each entry in the table testing for errors */
86 for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
87 ce=(struct cmos_entries *)cptr;
88 /* test if entry goes past the end of the buffer */
89 if((int)(ce->bit+ce->length) > buffer_bit_size) {
90 printf("Error - Entry %s start bit + length must be less than %d\n",
91 ce->name,buffer_bit_size);
96 byte_length=ce->length/8;
97 if(byte_length) { /* entry is 8 bits long or more */
98 if(offset) { /* if 8 bits or more long, it must be byte aligned */
99 printf("Error - Entry %s length over 8 must be byte aligned\n",
103 /* test if entries 8 or more in length are even bytes */
105 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
109 /* test if any of the bits have been previously used */
110 for(;byte_length;byte_length--,byte++) {
112 printf("Error - Entry %s uses same bits previously used\n",
116 test[byte]=clip[8]; /* set the bits defined in test */
119 /* test if bits overlap byte boundaries */
120 if((int)ce->length > (8-offset)) {
121 printf("Error - Entry %s length overlaps a byte boundry\n",
125 /* test for bits previously used */
126 set=(clip[ce->length]<<offset);
128 printf("Error - Entry %s uses same bits previously used\n",
132 test[byte]|=set; /* set the bits defined in test */
138 /* This routine displays the usage options */
139 static void display_usage(char *name)
141 printf("Usage: %s [--config filename]\n", name);
142 printf(" [--option filename]\n");
143 printf(" [--header filename]\n\n");
144 printf("--config = Build the definitions table from the given file.\n");
145 printf("--option = Output a C source file with the definitions.\n");
146 printf("--header = Ouput a C header file with the definitions.\n");
150 static void skip_spaces(char *line, char **ptr)
152 if (!isspace(**ptr)) {
153 printf("Error missing whitespace in line\n%s\n", line);
156 while(isspace(**ptr)) {
162 static unsigned long get_number(char *line, char **ptr, int base)
166 value = strtoul(*ptr, &ptr2, base);
168 printf("Error missing digits at: \n%s\n in line:\n%s\n",
176 static int is_ident_digit(int c)
180 case '0': case '1': case '2': case '3':
181 case '4': case '5': case '6': case '7':
192 static int is_ident_nondigit(int c)
196 case 'A': case 'B': case 'C': case 'D':
197 case 'E': case 'F': case 'G': case 'H':
198 case 'I': case 'J': case 'K': case 'L':
199 case 'M': case 'N': case 'O': case 'P':
200 case 'Q': case 'R': case 'S': case 'T':
201 case 'U': case 'V': case 'W': case 'X':
203 case 'a': case 'b': case 'c': case 'd':
204 case 'e': case 'f': case 'g': case 'h':
205 case 'i': case 'j': case 'k': case 'l':
206 case 'm': case 'n': case 'o': case 'p':
207 case 'q': case 'r': case 's': case 't':
208 case 'u': case 'v': case 'w': case 'x':
220 static int is_ident(char *str)
226 if (is_ident_nondigit(ch)) {
230 } while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
231 result = (ch == '\0');
237 * This routine builds the cmos definition table from the cmos layout file
239 * The input comes from the configuration file which contains two parts
240 * entries and enumerations. Each section is started with the key words
241 * entries and enumerations. Records then follow in their respective
244 * The output of this program is the cmos definitions table. It is stored
245 * in the cmos_table array. If this module is called, and the global
246 * table_file has been implimented by the user, the table is also written
247 * to the specified file.
249 * This program exits with a return code of 1 on error. It returns 0 on
250 * successful completion
252 int main(int argc, char **argv)
260 char tempfilename[TMPFILE_LEN];
261 struct cmos_option_table *ct;
262 struct cmos_entries *ce;
263 struct cmos_enums *c_enums, *c_enums_start;
264 struct cmos_checksum *cs, *new_cs;
265 char line[INPUT_LINE_MAX];
272 void *entry_start, *entry_end;
278 for(i=1;i<argc;i++) {
279 if(argv[i][0]!='-') {
280 display_usage(argv[0]);
283 case '-': /* data is requested from a file */
285 case 'c': /* use a configuration file */
286 if(strcmp(&argv[i][2],"config")) {
287 display_usage(argv[0]);
291 case 'o': /* use a cmos definitions table file */
292 if(strcmp(&argv[i][2],"option")) {
293 display_usage(argv[0]);
297 case 'h': /* Output a header file */
298 if (strcmp(&argv[i][2], "header") != 0) {
299 display_usage(argv[0]);
304 display_usage(argv[0]);
310 display_usage(argv[0]);
316 /* Has the user specified a configuration file */
317 if(config) { /* if yes, open it */
318 if((fp=fopen(config,"r"))==NULL){
319 fprintf(stderr, "Error - Can not open config file %s\n",config);
320 exit(1); /* exit if it can not be opened */
323 else { /* no configuration file specified, so try the default */
324 if((fp=fopen("cmos.layout","r"))==NULL){
325 fprintf(stderr, "Error - Can not open cmos.layout\n");
326 exit(1); /* end of no configuration file is found */
329 /* type cast a pointer, so we can us the structure */
330 ct=(struct cmos_option_table*)cmos_table;
331 /* start the table with the type signature */
332 ct->tag = LB_TAG_CMOS_OPTION_TABLE;
333 /* put in the header length */
334 ct->header_length=sizeof(*ct);
336 /* Get the entry records */
337 ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
339 for(;;){ /* this section loops through the entry records */
340 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
341 break; /* end if no more input */
342 // FIXME mode should be a single enum.
343 if(!entry_mode) { /* skip input until the entries key word */
344 if (strstr(line,"entries") != 0) {
350 } else { /* Test if we are done with entries and starting enumerations */
351 if (strstr(line,"enumerations") != 0){
357 if (strstr(line, "checksums") != 0) {
365 /* skip commented and blank lines */
366 if(line[0]=='#') continue;
367 if(line[strspn(line," ")]=='\n') continue;
368 /* scan in the input data */
369 sscanf(line,"%d %d %c %d %s",
370 &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
372 /* check bit and length ranges */
373 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
374 fprintf(stderr, "Error - bit is to big in line \n%s\n",line);
377 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
378 fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
381 if (!is_ident((char *)ce->name)) {
383 "Error - Name %s is an invalid identifier in line\n %s\n",
387 /* put in the record type */
388 ce->tag=LB_TAG_OPTION;
389 /* calculate and save the record length */
390 len=strlen((char *)ce->name)+1;
391 /* make the record int aligned */
394 ce->size=sizeof(struct cmos_entries)-32+len;
396 cptr += ce->size; /* increment to the next table position */
397 ce = (struct cmos_entries*) cptr;
400 /* put the length of the entries into the header section */
401 entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
403 /* compute the start of the enumerations section */
404 entry_start = ((char*)&cmos_table) + ct->header_length;
405 entry_end = ((char *)entry_start) + entries_length;
406 c_enums_start = c_enums = (struct cmos_enums*)entry_end;
407 /* test for overlaps in the entry records */
408 test_for_entry_overlaps(entry_start, entry_end);
410 for(;enum_mode;){ /* loop to build the enumerations section */
412 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
413 break; /* go till end of input */
415 if (strstr(line, "checksums") != 0) {
421 /* skip commented and blank lines */
422 if(line[0]=='#') continue;
423 if(line[strspn(line," ")]=='\n') continue;
425 /* scan in the data */
426 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
427 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
428 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
429 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
430 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
431 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
432 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
433 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
434 c_enums->text[cnt]=line[ptr];
435 c_enums->text[cnt]=0;
437 /* make the record int aligned */
441 /* store the record length */
442 c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums;
443 /* store the record type */
444 c_enums->tag=LB_TAG_OPTION_ENUM;
445 /* increment to the next record */
446 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
448 /* save the enumerations length */
449 enum_length= (char *)c_enums - (char *)c_enums_start;
450 ct->size=ct->header_length+enum_length+entries_length;
452 /* Get the checksum records */
453 new_cs = (struct cmos_checksum *)(cmos_table+(ct->size));
454 for(;checksum_mode;) { /* This section finds the checksums */
456 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
457 break; /* end if no more input */
459 /* skip commented and blank lines */
460 if (line[0]=='#') continue;
461 if (line[strspn(line, " ")]=='\n') continue;
462 if (memcmp(line, "checksum", 8) != 0) continue;
464 /* We actually found a new cmos checksum entry */
467 /* get the information */
469 skip_spaces(line, &ptr);
470 cs->range_start = get_number(line, &ptr, 10);
472 skip_spaces(line, &ptr);
473 cs->range_end = get_number(line, &ptr, 10);
475 skip_spaces(line, &ptr);
476 cs->location = get_number(line, &ptr, 10);
478 /* Make certain there are spaces until the end of the line */
479 skip_spaces(line, &ptr);
481 if ((cs->range_start%8) != 0) {
482 fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
485 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
486 fprintf(stderr, "Error - range start is to big in line\n%s\n", line);
489 if ((cs->range_end%8) != 7) {
490 fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
493 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
494 fprintf(stderr, "Error - range end is to long in line\n%s\n", line);
497 if ((cs->location%8) != 0) {
498 fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
501 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
502 ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
504 fprintf(stderr, "Error - location is to big in line\n%s\n", line);
508 cs->tag = LB_TAG_OPTION_CHECKSUM;
509 cs->size = sizeof(*cs);
510 cs->type = CHECKSUM_PCBIOS;
514 new_cs = (struct cmos_checksum *)cptr;
516 ct->size += (cptr - (char *)(cmos_table + ct->size));
519 /* See if we want to output a C source file */
522 strncpy(tempfilename, dirname(strdup(option)), TMPFILE_LEN);
523 strncat(tempfilename, TMPFILE_TEMPLATE, TMPFILE_LEN);
524 tempfile = mkstemp(tempfilename);
526 perror("Error - Could not create temporary file");
530 if((fp=fdopen(tempfile,"w"))==NULL){
531 perror("Error - Could not open temporary file");
532 unlink(tempfilename);
536 /* write the header */
537 if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
538 perror("Error - Could not write image file");
540 unlink(tempfilename);
543 /* write the array values */
544 for(i=0; i<(int)(ct->size-1); i++) {
545 if(!(i%10) && !err) err=!fwrite("\n\t",1,2,fp);
546 sprintf(buf,"0x%02x,",cmos_table[i]);
547 if(!err) err=!fwrite(buf,1,5,fp);
550 sprintf(buf,"0x%02x\n",cmos_table[i]);
551 if(!err) err=!fwrite(buf,1,4,fp);
552 if(!fwrite("};\n",1,3,fp)) {
553 perror("Error - Could not write image file");
555 unlink(tempfilename);
560 UNLINK_IF_NECESSARY(option);
561 if (rename(tempfilename, option)) {
562 fprintf(stderr, "Error - Could not write %s: ", option);
564 unlink(tempfilename);
569 /* See if we also want to output a C header file */
571 struct cmos_option_table *hdr;
572 struct lb_record *ptr, *end;
574 strncpy(tempfilename, dirname(strdup(header)), TMPFILE_LEN);
575 strncat(tempfilename, TMPFILE_TEMPLATE, TMPFILE_LEN);
576 tempfile = mkstemp(tempfilename);
578 perror("Error - Could not create temporary file");
582 fp = fdopen(tempfile, "w");
584 perror("Error - Could not open temporary file");
585 unlink(tempfilename);
589 /* Get the cmos table header */
590 hdr = (struct cmos_option_table *)cmos_table;
591 /* Walk through the entry records */
592 ptr = (struct lb_record *)(cmos_table + hdr->header_length);
593 end = (struct lb_record *)(cmos_table + hdr->size);
594 for(;ptr < end; ptr = (struct lb_record *)(((char *)ptr) + ptr->size)) {
595 if (ptr->tag != LB_TAG_OPTION) {
598 ce = (struct cmos_entries *)ptr;
600 if (!is_ident((char *)ce->name)) {
601 fprintf(stderr, "Invalid identifier: %s\n",
604 unlink(tempfilename);
607 fprintf(fp, "#define CMOS_VSTART_%s %d\n",
609 fprintf(fp, "#define CMOS_VLEN_%s %d\n",
610 ce->name, ce->length);
614 fprintf(fp, "\n#define LB_CKS_RANGE_START %d\n", cs->range_start / 8);
615 fprintf(fp, "#define LB_CKS_RANGE_END %d\n", cs->range_end / 8);
616 fprintf(fp, "#define LB_CKS_LOC %d\n", cs->location / 8);
618 fprintf(stderr, "Error - No checksums defined.\n");
620 unlink(tempfilename);
625 UNLINK_IF_NECESSARY(header);
626 if (rename(tempfilename, header)) {
627 fprintf(stderr, "Error - Could not write %s: ", header);
629 unlink(tempfilename);