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];
19 void test_for_entry_overlaps(void *entry_start, void *entry_end);
21 /* This array is used to isolate bits that are to be changed in a byte */
22 static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
26 char* mkstemp(char* name) {
31 return open(name,O_CREAT | O_RDWR);
33 #define UNLINK_IF_NECESSARY(x) unlink(x)
35 #define UNLINK_IF_NECESSARY(x)
38 /* This routine loops through the entried and tests if any of the fields overlap
39 input entry_start = the memory pointer to the start of the entries.
40 entry_end = the byte past the entries.
42 if there is an overlap, the routine exits, other wise it returns.
44 void test_for_entry_overlaps(void *entry_start, void *entry_end)
52 struct cmos_entries *ce;
53 unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
56 /* calculate the size of the cmos buffer in bits */
57 buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
58 /* clear the temporary test buffer */
59 for(ptr=0; ptr < CMOS_IMAGE_BUFFER_SIZE; ptr++)
62 /* loop through each entry in the table testing for errors */
63 for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
64 ce=(struct cmos_entries *)cptr;
65 /* test if entry goes past the end of the buffer */
66 if((ce->bit+ce->length)>buffer_bit_size) {
67 printf("Error - Entry %s start bit + length must be less than %d\n",
68 ce->name,buffer_bit_size);
73 byte_length=ce->length/8;
74 if(byte_length) { /* entry is 8 bits long or more */
75 if(offset) { /* if 8 bits or more long, it must be byte aligned */
76 printf("Error - Entry %s length over 8 must be byte aligned\n",
80 /* test if entries 8 or more in length are even bytes */
82 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
86 /* test if any of the bits have been previously used */
87 for(;byte_length;byte_length--,byte++) {
89 printf("Error - Entry %s uses same bits previously used\n",
93 test[byte]=clip[8]; /* set the bits defined in test */
96 /* test if bits overlap byte boundaries */
97 if(ce->length>(8-offset)) {
98 printf("Error - Entry %s length overlaps a byte boundry\n",
102 /* test for bits previously used */
103 set=(clip[ce->length]<<offset);
105 printf("Error - Entry %s uses same bits previously used\n",
109 test[byte]|=set; /* set the bits defined in test */
115 /* This routine displays the usage options */
116 void display_usage(char *name)
118 printf("Usage: %s [--config filename]\n", name);
119 printf(" [--option filename]\n");
120 printf(" [--header filename]\n\n");
121 printf("--config = Build the definitions table from the given file.\n");
122 printf("--option = Output a C source file with the definitions.\n");
123 printf("--header = Ouput a C header file with the definitions.\n");
128 static void skip_spaces(char *line, char **ptr)
130 if (!isspace(**ptr)) {
131 printf("Error missing whitespace in line\n%s\n", line);
134 while(isspace(**ptr)) {
139 static unsigned long get_number(char *line, char **ptr, int base)
143 value = strtoul(*ptr, &ptr2, base);
145 printf("Error missing digits at: \n%s\n in line:\n%s\n",
153 static int is_ident_digit(int c)
157 case '0': case '1': case '2': case '3':
158 case '4': case '5': case '6': case '7':
169 static int is_ident_nondigit(int c)
173 case 'A': case 'B': case 'C': case 'D':
174 case 'E': case 'F': case 'G': case 'H':
175 case 'I': case 'J': case 'K': case 'L':
176 case 'M': case 'N': case 'O': case 'P':
177 case 'Q': case 'R': case 'S': case 'T':
178 case 'U': case 'V': case 'W': case 'X':
180 case 'a': case 'b': case 'c': case 'd':
181 case 'e': case 'f': case 'g': case 'h':
182 case 'i': case 'j': case 'k': case 'l':
183 case 'm': case 'n': case 'o': case 'p':
184 case 'q': case 'r': case 's': case 't':
185 case 'u': case 'v': case 'w': case 'x':
197 static int is_ident(char *str)
203 if (is_ident_nondigit(ch)) {
207 } while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
208 result = (ch == '\0');
214 /* This routine builds the cmos definition table from the cmos layout file
215 input The input comes from the configuration file which contains two parts
216 entries and enumerations. Each section is started with the key words
217 entries and enumerations. Records then follow in their respective
219 output The output of this program is the cmos definitions table. It is stored
220 in the cmos_table array. If this module is called, and the global
221 table_file has been implimented by the user, the table is also written
222 to the specified file.
223 This program exits on and error. It returns a 1 on successful
226 int main(int argc, char **argv)
234 char tmpfilename[TMPFILE_LEN];
235 struct cmos_option_table *ct;
236 struct cmos_entries *ce;
237 struct cmos_enums *c_enums, *c_enums_start;
238 struct cmos_checksum *cs;
239 char line[INPUT_LINE_MAX];
247 void *entry_start, *entry_end;
253 for(i=1;i<argc;i++) {
254 if(argv[i][0]!='-') {
255 display_usage(argv[0]);
258 case '-': /* data is requested from a file */
260 case 'c': /* use a configuration file */
261 if(strcmp(&argv[i][2],"config")) {
262 display_usage(argv[0]);
266 case 'o': /* use a cmos definitions table file */
267 if(strcmp(&argv[i][2],"option")) {
268 display_usage(argv[0]);
272 case 'h': /* Output a header file */
273 if (strcmp(&argv[i][2], "header") != 0) {
274 display_usage(argv[0]);
279 display_usage(argv[0]);
285 display_usage(argv[0]);
291 /* Has the user specified a configuration file */
292 if(config) { /* if yes, open it */
293 if((fp=fopen(config,"r"))==NULL){
294 fprintf(stderr, "Error - Can not open config file %s\n",config);
295 exit(1); /* exit if it can not be opened */
298 else { /* no configuration file specified, so try the default */
299 if((fp=fopen("cmos.layout","r"))==NULL){
300 fprintf(stderr, "Error - Can not open cmos.layout\n");
301 exit(1); /* end of no configuration file is found */
304 /* type cast a pointer, so we can us the structure */
305 ct=(struct cmos_option_table*)cmos_table;
306 /* start the table with the type signature */
307 ct->tag = LB_TAG_CMOS_OPTION_TABLE;
308 /* put in the header length */
309 ct->header_length=sizeof(*ct);
311 /* Get the entry records */
312 ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
314 for(;;){ /* this section loops through the entry records */
315 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
316 break; /* end if no more input */
317 if(!entry_mode) { /* skip input until the entries key word */
318 if (strstr(line,"entries") != 0) {
323 else{ /* Test if we are done with entries and starting enumerations */
324 if (strstr(line,"enumerations") != 0){
329 if (strstr(line, "checksums") != 0) {
336 /* skip commented and blank lines */
337 if(line[0]=='#') continue;
338 if(line[strspn(line," ")]=='\n') continue;
339 /* scan in the input data */
340 sscanf(line,"%d %d %c %d %s",
341 &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
343 /* check bit and length ranges */
344 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
345 fprintf(stderr, "Error - bit is to big in line \n%s\n",line);
348 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
349 fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
352 if (!is_ident((char *)ce->name)) {
354 "Error - Name %s is an invalid identifier in line\n %s\n",
358 /* put in the record type */
359 ce->tag=LB_TAG_OPTION;
360 /* calculate and save the record length */
361 len=strlen((char *)ce->name)+1;
362 /* make the record int aligned */
365 ce->size=sizeof(struct cmos_entries)-32+len;
367 cptr += ce->size; /* increment to the next table position */
368 ce = (struct cmos_entries*) cptr;
371 /* put the length of the entries into the header section */
372 entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
374 /* compute the start of the enumerations section */
375 entry_start = ((char*)&cmos_table) + ct->header_length;
376 entry_end = ((char *)entry_start) + entries_length;
377 c_enums_start = c_enums = (struct cmos_enums*)entry_end;
378 /* test for overlaps in the entry records */
379 test_for_entry_overlaps(entry_start, entry_end);
381 for(;enum_mode;){ /* loop to build the enumerations section */
382 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
383 break; /* go till end of input */
385 if (strstr(line, "checksums") != 0) {
391 /* skip commented and blank lines */
392 if(line[0]=='#') continue;
393 if(line[strspn(line," ")]=='\n') continue;
395 /* scan in the data */
396 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
397 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
398 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
399 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
400 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
401 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
402 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
403 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
404 c_enums->text[cnt]=line[ptr];
405 c_enums->text[cnt]=0;
407 /* make the record int aligned */
411 /* store the record length */
412 c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums;
413 /* store the record type */
414 c_enums->tag=LB_TAG_OPTION_ENUM;
415 /* increment to the next record */
416 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
418 /* save the enumerations length */
419 enum_length= (char *)c_enums - (char *)c_enums_start;
420 ct->size=ct->header_length+enum_length+entries_length;
422 /* Get the checksum records */
423 cs=(struct cmos_checksum *)(cmos_table+(ct->size));
425 for(;checksum_mode;) { /* This section finds the checksums */
427 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
428 break; /* end if no more input */
430 /* skip commented and blank lines */
431 if (line[0]=='#') continue;
432 if (line[strspn(line, " ")]=='\n') continue;
433 if (memcmp(line, "checksum", 8) != 0) continue;
435 /* get the information */
437 skip_spaces(line, &ptr);
438 cs->range_start = get_number(line, &ptr, 10);
440 skip_spaces(line, &ptr);
441 cs->range_end = get_number(line, &ptr, 10);
443 skip_spaces(line, &ptr);
444 cs->location = get_number(line, &ptr, 10);
446 /* Make certain there are spaces until the end of the line */
447 skip_spaces(line, &ptr);
449 if ((cs->range_start%8) != 0) {
450 fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
453 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
454 fprintf(stderr, "Error - range start is to big in line\n%s\n", line);
457 if ((cs->range_end%8) != 7) {
458 fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
461 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
462 fprintf(stderr, "Error - range end is to long in line\n%s\n", line);
465 if ((cs->location%8) != 0) {
466 fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
469 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
470 ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
472 fprintf(stderr, "Error - location is to big in line\n%s\n", line);
476 cs->tag = LB_TAG_OPTION_CHECKSUM;
477 cs->size = sizeof(*cs);
478 cs->type = CHECKSUM_PCBIOS;
481 cs = (struct cmos_checksum *)cptr;
484 ct->size += (cptr - (char *)(cmos_table + ct->size));
487 /* See if we want to output a C source file */
490 strncpy(tmpfilename, dirname(strdup(option)), TMPFILE_LEN);
491 strncat(tmpfilename, TMPFILE_TEMPLATE, TMPFILE_LEN);
492 tmpfile = mkstemp(tmpfilename);
494 perror("Error - Could not create temporary file");
498 if((fp=fdopen(tmpfile,"w"))==NULL){
499 perror("Error - Could not open temporary file");
504 /* write the header */
505 if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
506 perror("Error - Could not write image file");
511 /* write the array values */
512 for(i=0;i<(ct->size-1);i++) {
513 if(!(i%10) && !err) err=!fwrite("\n\t",1,2,fp);
514 sprintf(buf,"0x%02x,",cmos_table[i]);
515 if(!err) err=!fwrite(buf,1,5,fp);
518 sprintf(buf,"0x%02x\n",cmos_table[i]);
519 if(!err) err=!fwrite(buf,1,4,fp);
520 if(!fwrite("};\n",1,3,fp)) {
521 perror("Error - Could not write image file");
528 UNLINK_IF_NECESSARY(option);
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(strdup(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 UNLINK_IF_NECESSARY(header);
583 if (rename(tmpfilename, header)) {
584 fprintf(stderr, "Error - Could not write %s: ", header);