8 #include "../../src/include/pc80/mc146818rtc.h"
9 #include "../../src/include/boot/coreboot_tables.h"
11 #define CMOS_IMAGE_BUFFER_SIZE 256
12 #define INPUT_LINE_MAX 256
13 #define MAX_VALUE_BYTE_LENGTH 64
15 #define TMPFILE_LEN 256
16 #define TMPFILE_TEMPLATE "/build_opt_tbl_XXXXXX"
18 static unsigned char cmos_table[4096];
20 /* This array is used to isolate bits that are to be changed in a byte */
21 static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
24 /* This routine loops through the entried and tests if any of the fields overlap
25 input entry_start = the memory pointer to the start of the entries.
26 entry_end = the byte past the entries.
28 if there is an overlap, the routine exits, other wise it returns.
30 void test_for_entry_overlaps(void *entry_start, void *entry_end)
38 struct cmos_entries *ce;
39 unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
42 /* calculate the size of the cmos buffer in bits */
43 buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
44 /* clear the temporary test buffer */
45 for(ptr=0; ptr < CMOS_IMAGE_BUFFER_SIZE; ptr++)
48 /* loop through each entry in the table testing for errors */
49 for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
50 ce=(struct cmos_entries *)cptr;
51 /* test if entry goes past the end of the buffer */
52 if((ce->bit+ce->length)>buffer_bit_size) {
53 printf("Error - Entry %s start bit + length must be less than %d\n",
54 ce->name,buffer_bit_size);
59 byte_length=ce->length/8;
60 if(byte_length) { /* entry is 8 bits long or more */
61 if(offset) { /* if 8 bits or more long, it must be byte aligned */
62 printf("Error - Entry %s length over 8 must be byte aligned\n",
66 /* test if entries 8 or more in length are even bytes */
68 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
72 /* test if any of the bits have been previously used */
73 for(;byte_length;byte_length--,byte++) {
75 printf("Error - Entry %s uses same bits previously used\n",
79 test[byte]=clip[8]; /* set the bits defined in test */
82 /* test if bits overlap byte boundaries */
83 if(ce->length>(8-offset)) {
84 printf("Error - Entry %s length overlaps a byte boundry\n",
88 /* test for bits previously used */
89 set=(clip[ce->length]<<offset);
91 printf("Error - Entry %s uses same bits previously used\n",
95 test[byte]|=set; /* set the bits defined in test */
101 /* This routine displays the usage options */
102 void display_usage(char *name)
104 printf("Usage: %s [--config filename]\n", name);
105 printf(" [--option filename]\n");
106 printf(" [--header filename]\n\n");
107 printf("--config = Build the definitions table from the given file.\n");
108 printf("--option = Output a C source file with the definitions.\n");
109 printf("--header = Ouput a C header file with the definitions.\n");
114 static void skip_spaces(char *line, char **ptr)
116 if (!isspace(**ptr)) {
117 printf("Error missing whitespace in line\n%s\n", line);
120 while(isspace(**ptr)) {
125 static unsigned long get_number(char *line, char **ptr, int base)
129 value = strtoul(*ptr, &ptr2, base);
131 printf("Error missing digits at: \n%s\n in line:\n%s\n",
139 static int is_ident_digit(int c)
143 case '0': case '1': case '2': case '3':
144 case '4': case '5': case '6': case '7':
155 static int is_ident_nondigit(int c)
159 case 'A': case 'B': case 'C': case 'D':
160 case 'E': case 'F': case 'G': case 'H':
161 case 'I': case 'J': case 'K': case 'L':
162 case 'M': case 'N': case 'O': case 'P':
163 case 'Q': case 'R': case 'S': case 'T':
164 case 'U': case 'V': case 'W': case 'X':
166 case 'a': case 'b': case 'c': case 'd':
167 case 'e': case 'f': case 'g': case 'h':
168 case 'i': case 'j': case 'k': case 'l':
169 case 'm': case 'n': case 'o': case 'p':
170 case 'q': case 'r': case 's': case 't':
171 case 'u': case 'v': case 'w': case 'x':
183 static int is_ident(char *str)
189 if (is_ident_nondigit(ch)) {
193 } while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
194 result = (ch == '\0');
200 /* This routine builds the cmos definition table from the cmos layout file
201 input The input comes from the configuration file which contains two parts
202 entries and enumerations. Each section is started with the key words
203 entries and enumerations. Records then follow in their respective
205 output The output of this program is the cmos definitions table. It is stored
206 in the cmos_table array. If this module is called, and the global
207 table_file has been implimented by the user, the table is also written
208 to the specified file.
209 This program exits on and error. It returns a 1 on successful
212 int main(int argc, char **argv)
220 char tmpfilename[TMPFILE_LEN];
221 struct cmos_option_table *ct;
222 struct cmos_entries *ce;
223 struct cmos_enums *c_enums, *c_enums_start;
224 struct cmos_checksum *cs;
225 char line[INPUT_LINE_MAX];
233 void *entry_start, *entry_end;
239 for(i=1;i<argc;i++) {
240 if(argv[i][0]!='-') {
241 display_usage(argv[0]);
244 case '-': /* data is requested from a file */
246 case 'c': /* use a configuration file */
247 if(strcmp(&argv[i][2],"config")) {
248 display_usage(argv[0]);
252 case 'o': /* use a cmos definitions table file */
253 if(strcmp(&argv[i][2],"option")) {
254 display_usage(argv[0]);
258 case 'h': /* Output a header file */
259 if (strcmp(&argv[i][2], "header") != 0) {
260 display_usage(argv[0]);
265 display_usage(argv[0]);
271 display_usage(argv[0]);
277 /* Has the user specified a configuration file */
278 if(config) { /* if yes, open it */
279 if((fp=fopen(config,"r"))==NULL){
280 fprintf(stderr, "Error - Can not open config file %s\n",config);
281 exit(1); /* exit if it can not be opened */
284 else { /* no configuration file specified, so try the default */
285 if((fp=fopen("cmos.layout","r"))==NULL){
286 fprintf(stderr, "Error - Can not open cmos.layout\n");
287 exit(1); /* end of no configuration file is found */
290 /* type cast a pointer, so we can us the structure */
291 ct=(struct cmos_option_table*)cmos_table;
292 /* start the table with the type signature */
293 ct->tag = LB_TAG_CMOS_OPTION_TABLE;
294 /* put in the header length */
295 ct->header_length=sizeof(*ct);
297 /* Get the entry records */
298 ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
300 for(;;){ /* this section loops through the entry records */
301 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
302 break; /* end if no more input */
303 if(!entry_mode) { /* skip input until the entries key word */
304 if (strstr(line,"entries") != 0) {
309 else{ /* Test if we are done with entries and starting enumerations */
310 if (strstr(line,"enumerations") != 0){
315 if (strstr(line, "checksums") != 0) {
322 /* skip commented and blank lines */
323 if(line[0]=='#') continue;
324 if(line[strspn(line," ")]=='\n') continue;
325 /* scan in the input data */
326 sscanf(line,"%d %d %c %d %s",
327 &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
329 /* check bit and length ranges */
330 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
331 fprintf(stderr, "Error - bit is to big in line \n%s\n",line);
334 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
335 fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
338 if (!is_ident((char *)ce->name)) {
340 "Error - Name %s is an invalid identifier in line\n %s\n",
344 /* put in the record type */
345 ce->tag=LB_TAG_OPTION;
346 /* calculate and save the record length */
347 len=strlen((char *)ce->name)+1;
348 /* make the record int aligned */
351 ce->size=sizeof(struct cmos_entries)-32+len;
353 cptr += ce->size; /* increment to the next table position */
354 ce = (struct cmos_entries*) cptr;
357 /* put the length of the entries into the header section */
358 entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
360 /* compute the start of the enumerations section */
361 entry_start = ((char*)&cmos_table) + ct->header_length;
362 entry_end = ((char *)entry_start) + entries_length;
363 c_enums_start = c_enums = (struct cmos_enums*)entry_end;
364 /* test for overlaps in the entry records */
365 test_for_entry_overlaps(entry_start, entry_end);
367 for(;enum_mode;){ /* loop to build the enumerations section */
368 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
369 break; /* go till end of input */
371 if (strstr(line, "checksums") != 0) {
377 /* skip commented and blank lines */
378 if(line[0]=='#') continue;
379 if(line[strspn(line," ")]=='\n') continue;
381 /* scan in the data */
382 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
383 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
384 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
385 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
386 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
387 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
388 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
389 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
390 c_enums->text[cnt]=line[ptr];
391 c_enums->text[cnt]=0;
393 /* make the record int aligned */
397 /* store the record length */
398 c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums;
399 /* store the record type */
400 c_enums->tag=LB_TAG_OPTION_ENUM;
401 /* increment to the next record */
402 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
404 /* save the enumerations length */
405 enum_length= (char *)c_enums - (char *)c_enums_start;
406 ct->size=ct->header_length+enum_length+entries_length;
408 /* Get the checksum records */
409 cs=(struct cmos_checksum *)(cmos_table+(ct->size));
411 for(;checksum_mode;) { /* This section finds the checksums */
413 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
414 break; /* end if no more input */
416 /* skip commented and blank lines */
417 if (line[0]=='#') continue;
418 if (line[strspn(line, " ")]=='\n') continue;
419 if (memcmp(line, "checksum", 8) != 0) continue;
421 /* get the information */
423 skip_spaces(line, &ptr);
424 cs->range_start = get_number(line, &ptr, 10);
426 skip_spaces(line, &ptr);
427 cs->range_end = get_number(line, &ptr, 10);
429 skip_spaces(line, &ptr);
430 cs->location = get_number(line, &ptr, 10);
432 /* Make certain there are spaces until the end of the line */
433 skip_spaces(line, &ptr);
435 if ((cs->range_start%8) != 0) {
436 fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
439 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
440 fprintf(stderr, "Error - range start is to big in line\n%s\n", line);
443 if ((cs->range_end%8) != 7) {
444 fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
447 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
448 fprintf(stderr, "Error - range end is to long in line\n%s\n", line);
451 if ((cs->location%8) != 0) {
452 fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
455 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
456 ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
458 fprintf(stderr, "Error - location is to big in line\n%s\n", line);
461 /* And since we are not ready to be fully general purpose yet.. */
462 if ((cs->range_start/8) != CONFIG_LB_CKS_RANGE_START) {
463 fprintf(stderr, "Error - Range start(%d) does not match define(%d) in line\n%s\n",
464 cs->range_start/8, CONFIG_LB_CKS_RANGE_START, line);
467 if ((cs->range_end/8) != CONFIG_LB_CKS_RANGE_END) {
468 fprintf(stderr, "Error - Range end (%d) does not match define (%d) in line\n%s\n",
469 (cs->range_end/8), CONFIG_LB_CKS_RANGE_END, line);
472 if ((cs->location/8) != CONFIG_LB_CKS_LOC) {
473 fprintf(stderr, "Error - Location does not match define in line\n%s\n", line);
477 cs->tag = LB_TAG_OPTION_CHECKSUM;
478 cs->size = sizeof(*cs);
479 cs->type = CHECKSUM_PCBIOS;
482 cs = (struct cmos_checksum *)cptr;
485 ct->size += (cptr - (char *)(cmos_table + ct->size));
488 /* See if we want to output a C source file */
491 strncpy(tmpfilename, dirname(option), TMPFILE_LEN);
492 strncat(tmpfilename, TMPFILE_TEMPLATE, TMPFILE_LEN);
493 tmpfile = mkstemp(tmpfilename);
495 perror("Error - Could not create temporary file");
499 if((fp=fdopen(tmpfile,"w"))==NULL){
500 perror("Error - Could not open temporary file");
505 /* write the header */
506 if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
507 perror("Error - Could not write image file");
512 /* write the array values */
513 for(i=0;i<(ct->size-1);i++) {
514 if(!(i%10) && !err) err=!fwrite("\n\t",1,2,fp);
515 sprintf(buf,"0x%02x,",cmos_table[i]);
516 if(!err) err=!fwrite(buf,1,5,fp);
519 sprintf(buf,"0x%02x\n",cmos_table[i]);
520 if(!err) err=!fwrite(buf,1,4,fp);
521 if(!fwrite("};\n",1,3,fp)) {
522 perror("Error - Could not write image file");
529 if (rename(tmpfilename, option)) {
530 fprintf(stderr, "Error - Could not write %s: ", option);
537 /* See if we also want to output a C header file */
539 struct cmos_option_table *hdr;
540 struct lb_record *ptr, *end;
542 strncpy(tmpfilename, dirname(option), TMPFILE_LEN);
543 strncat(tmpfilename, TMPFILE_TEMPLATE, TMPFILE_LEN);
544 tmpfile = mkstemp(tmpfilename);
546 perror("Error - Could not create temporary file");
550 fp = fdopen(tmpfile, "w");
552 perror("Error - Could not open temporary file");
557 /* Get the cmos table header */
558 hdr = (struct cmos_option_table *)cmos_table;
559 /* Walk through the entry records */
560 ptr = (struct lb_record *)(cmos_table + hdr->header_length);
561 end = (struct lb_record *)(cmos_table + hdr->size);
562 for(;ptr < end; ptr = (struct lb_record *)(((char *)ptr) + ptr->size)) {
563 if (ptr->tag != LB_TAG_OPTION) {
566 ce = (struct cmos_entries *)ptr;
568 if (!is_ident((char *)ce->name)) {
569 fprintf(stderr, "Invalid identifier: %s\n",
575 fprintf(fp, "#define CMOS_VSTART_%s %d\n",
577 fprintf(fp, "#define CMOS_VLEN_%s %d\n",
578 ce->name, ce->length);
582 if (rename(tmpfilename, header)) {
583 fprintf(stderr, "Error - Could not write %s: ", header);