6 #include "../../src/include/pc80/mc146818rtc.h"
7 #include "../../src/include/boot/linuxbios_tables.h"
9 #define CMOS_IMAGE_BUFFER_SIZE 128
10 #define INPUT_LINE_MAX 256
11 #define MAX_VALUE_BYTE_LENGTH 64
14 static unsigned char cmos_table[4096];
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};
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.
24 if there is an overlap, the routine exits, other wise it returns.
26 void test_for_entry_overlaps(void *entry_start, void *entry_end)
34 struct cmos_entries *ce;
35 unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
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++)
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);
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",
62 /* test if entries 8 or more in length are even bytes */
64 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
68 /* test if any of the bits have been previously used */
69 for(;byte_length;byte_length--,byte++) {
71 printf("Error - Entry %s uses same bits previously used\n",
75 test[byte]=clip[8]; /* set the bits defined in test */
78 /* test if bits overlap byte boundaries */
79 if(ce->length>(8-offset)) {
80 printf("Error - Entry %s length overlaps a byte boundry\n",
84 /* test for bits previously used */
85 set=(clip[ce->length]<<offset);
87 printf("Error - Entry %s uses same bits previously used\n",
91 test[byte]|=set; /* set the bits defined in test */
97 /* This routine displays the usage options */
98 void display_usage(void)
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");
111 static void skip_spaces(char *line, char **ptr)
113 if (!isspace(**ptr)) {
114 printf("Error missing whitespace in line\n%s\n", line);
117 while(isspace(**ptr)) {
122 static unsigned long get_number(char *line, char **ptr, int base)
126 value = strtoul(*ptr, &ptr2, base);
128 printf("Error missing digits at: \n%s\n in line:\n%s\n",
136 static int is_ident_digit(int c)
140 case '0': case '1': case '2': case '3':
141 case '4': case '5': case '6': case '7':
152 static int is_ident_nondigit(int 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':
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':
180 static int is_ident(char *str)
186 if (is_ident_nondigit(ch)) {
190 } while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
191 result = (ch == '\0');
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
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
209 int main(int argc, char **argv)
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];
228 void *entry_start, *entry_end;
234 for(i=1;i<argc;i++) {
235 if(argv[i][0]!='-') {
239 case 'b': /* build the table */
241 case '-': /* data is requested from a file */
243 case 'c': /* use a configuration file */
244 if(strcmp(&argv[i][2],"config")) {
249 case 'o': /* use a cmos definitions table file */
250 if(strcmp(&argv[i][2],"option")) {
255 case 'h': /* Output a header file */
256 if (strcmp(&argv[i][2], "header") != 0) {
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 */
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 */
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);
294 /* Get the entry records */
295 ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
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) {
306 else{ /* Test if we are done with entries and starting enumerations */
307 if (strstr(line,"enumerations") != 0){
312 if (strstr(line, "checksums") != 0) {
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]);
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);
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);
335 if (!is_ident((char *)ce->name)) {
337 "Error - Name %s is an invalid identifier in line\n %s\n",
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 */
348 ce->size=sizeof(struct cmos_entries)-32+len;
350 cptr += ce->size; /* increment to the next table position */
351 ce = (struct cmos_entries*) cptr;
354 /* put the length of the entries into the header section */
355 entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
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);
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 */
368 if (strstr(line, "checksums") != 0) {
374 /* skip commented and blank lines */
375 if(line[0]=='#') continue;
376 if(line[strspn(line," ")]=='\n') continue;
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;
390 /* make the record int aligned */
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];
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;
405 /* Get the checksum records */
406 cs=(struct cmos_checksum *)(cmos_table+(ct->size));
408 for(;checksum_mode;) { /* This section finds the checksums */
410 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
411 break; /* end if no more input */
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;
418 /* get the information */
420 skip_spaces(line, &ptr);
421 cs->range_start = get_number(line, &ptr, 10);
423 skip_spaces(line, &ptr);
424 cs->range_end = get_number(line, &ptr, 10);
426 skip_spaces(line, &ptr);
427 cs->location = get_number(line, &ptr, 10);
429 /* Make certain there are spaces until the end of the line */
430 skip_spaces(line, &ptr);
432 if ((cs->range_start%8) != 0) {
433 fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
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);
440 if ((cs->range_end%8) != 7) {
441 fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
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);
448 if ((cs->location%8) != 0) {
449 fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
452 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
453 ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
455 fprintf(stderr, "Error - location is to big in line\n%s\n", line);
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);
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);
469 if ((cs->location/8) != LB_CKS_LOC) {
470 fprintf(stderr, "Error - Location does not match define in line\n%s\n", line);
474 cs->tag = LB_TAG_OPTION_CHECKSUM;
475 cs->size = sizeof(*cs);
476 cs->type = CHECKSUM_PCBIOS;
479 cs = (struct cmos_checksum *)cptr;
482 ct->size += (cptr - (char *)(cmos_table + ct->size));
485 /* test if an alternate file is to be created */
487 if((fp=fopen(option,"w"))==NULL){
488 fprintf(stderr, "Error - Can not open %s\n",option);
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");
498 /* write the header */
499 if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
500 fprintf(stderr, "Error - Could not write image file\n");
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]);
511 sprintf(buf,"0x%02x",cmos_table[i]);
513 if(!fwrite("};\n",1,3,fp)) {
514 fprintf(stderr, "Error - Could not write image file\n");
521 /* See if we also want to output a C header file */
523 struct cmos_option_table *hdr;
524 struct lb_record *ptr, *end;
525 fp = fopen(header, "w");
527 fprintf(stderr, "Error Can not open %s: %s\n",
528 header, strerror(errno));
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) {
540 ce = (struct cmos_entries *)ptr;
541 if (ce->config == 'r') {
544 if (!is_ident((char *)ce->name)) {
545 fprintf(stderr, "Invalid identifier: %s\n",
549 fprintf(fp, "#define CMOS_VSTART_%s %d\n",
551 fprintf(fp, "#define CMOS_VLEN_%s %d\n",
552 ce->name, ce->length);