7 #include "../../src/include/pc80/mc146818rtc.h"
8 #include "../../src/include/boot/linuxbios_tables.h"
10 #define CMOS_IMAGE_BUFFER_SIZE 128
11 #define INPUT_LINE_MAX 256
12 #define MAX_VALUE_BYTE_LENGTH 64
15 static unsigned char cmos_table[4096];
17 /* This array is used to isolate bits that are to be changed in a byte */
18 static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
21 /* This routine loops through the entried and tests if any of the fields overlap
22 input entry_start = the memory pointer to the start of the entries.
23 entry_end = the byte past the entries.
25 if there is an overlap, the routine exits, other wise it returns.
27 void test_for_entry_overlaps(void *entry_start, void *entry_end)
35 struct cmos_entries *ce;
36 unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
39 /* calculate the size of the cmos buffer in bits */
40 buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
41 /* clear the temporary test buffer */
42 for(ptr=0; ptr < CMOS_IMAGE_BUFFER_SIZE; ptr++)
45 /* loop through each entry in the table testing for errors */
46 for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
47 ce=(struct cmos_entries *)cptr;
48 /* test if entry goes past the end of the buffer */
49 if((ce->bit+ce->length)>buffer_bit_size) {
50 printf("Error - Entry %s start bit + length must be less than %d\n",
51 ce->name,buffer_bit_size);
56 byte_length=ce->length/8;
57 if(byte_length) { /* entry is 8 bits long or more */
58 if(offset) { /* if 8 bits or more long, it must be byte aligned */
59 printf("Error - Entry %s length over 8 must be byte aligned\n",
63 /* test if entries 8 or more in length are even bytes */
65 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
69 /* test if any of the bits have been previously used */
70 for(;byte_length;byte_length--,byte++) {
72 printf("Error - Entry %s uses same bits previously used\n",
76 test[byte]=clip[8]; /* set the bits defined in test */
79 /* test if bits overlap byte boundaries */
80 if(ce->length>(8-offset)) {
81 printf("Error - Entry %s length overlaps a byte boundry\n",
85 /* test for bits previously used */
86 set=(clip[ce->length]<<offset);
88 printf("Error - Entry %s uses same bits previously used\n",
92 test[byte]|=set; /* set the bits defined in test */
98 /* This routine displays the usage options */
99 void display_usage(void)
101 printf("Usage build_opt_table [-b] [--option filename]\n");
102 printf(" [--config filename]\n");
103 printf(" [--header filename]\n");
104 printf("b = build option_table.c\n");
105 printf("--option = name of option table output file\n");
106 printf("--config = build the definitions table from the given file\n");
107 printf("--header = ouput a header file with the definitions\n");
112 static void skip_spaces(char *line, char **ptr)
114 if (!isspace(**ptr)) {
115 printf("Error missing whitespace in line\n%s\n", line);
118 while(isspace(**ptr)) {
123 static unsigned long get_number(char *line, char **ptr, int base)
127 value = strtoul(*ptr, &ptr2, base);
129 printf("Error missing digits at: \n%s\n in line:\n%s\n",
137 static int is_ident_digit(int c)
141 case '0': case '1': case '2': case '3':
142 case '4': case '5': case '6': case '7':
153 static int is_ident_nondigit(int c)
157 case 'A': case 'B': case 'C': case 'D':
158 case 'E': case 'F': case 'G': case 'H':
159 case 'I': case 'J': case 'K': case 'L':
160 case 'M': case 'N': case 'O': case 'P':
161 case 'Q': case 'R': case 'S': case 'T':
162 case 'U': case 'V': case 'W': case 'X':
164 case 'a': case 'b': case 'c': case 'd':
165 case 'e': case 'f': case 'g': case 'h':
166 case 'i': case 'j': case 'k': case 'l':
167 case 'm': case 'n': case 'o': case 'p':
168 case 'q': case 'r': case 's': case 't':
169 case 'u': case 'v': case 'w': case 'x':
181 static int is_ident(char *str)
187 if (is_ident_nondigit(ch)) {
191 } while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
192 result = (ch == '\0');
198 /* This routine builds the cmos definition table from the cmos layout file
199 input The input comes from the configuration file which contains two parts
200 entries and enumerations. Each section is started with the key words
201 entries and enumerations. Records then follow in their respective
203 output The output of this program is the cmos definitions table. It is stored
204 in the cmos_table array. If this module is called, and the global
205 table_file has been implimented by the user, the table is also written
206 to the specified file.
207 This program exits on and error. It returns a 1 on successful
210 int main(int argc, char **argv)
217 struct cmos_option_table *ct;
218 struct cmos_entries *ce;
219 struct cmos_enums *c_enums, *c_enums_start;
220 struct cmos_checksum *cs;
221 unsigned char line[INPUT_LINE_MAX];
229 void *entry_start, *entry_end;
233 unsigned char buf[16];
235 for(i=1;i<argc;i++) {
236 if(argv[i][0]!='-') {
240 case 'b': /* build the table */
242 case '-': /* data is requested from a file */
244 case 'c': /* use a configuration file */
245 if(strcmp(&argv[i][2],"config")) {
250 case 'o': /* use a cmos definitions table file */
251 if(strcmp(&argv[i][2],"option")) {
256 case 'h': /* Output a header file */
257 if (strcmp(&argv[i][2], "header") != 0) {
275 /* Has the user specified a configuration file */
276 if(config) { /* if yes, open it */
277 if((fp=fopen(config,"r"))==NULL){
278 fprintf(stderr, "Error - Can not open config file %s\n",config);
279 exit(1); /* exit if it can not be opened */
282 else { /* no configuration file specified, so try the default */
283 if((fp=fopen("cmos.layout","r"))==NULL){
284 fprintf(stderr, "Error - Can not open cmos.layout\n");
285 exit(1); /* end of no configuration file is found */
288 /* type cast a pointer, so we can us the structure */
289 ct=(struct cmos_option_table*)cmos_table;
290 /* start the table with the type signature */
291 ct->tag = LB_TAG_CMOS_OPTION_TABLE;
292 /* put in the header length */
293 ct->header_length=sizeof(*ct);
295 /* Get the entry records */
296 ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
298 for(;;){ /* this section loops through the entry records */
299 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
300 break; /* end if no more input */
301 if(!entry_mode) { /* skip input until the entries key word */
302 if (strstr(line,"entries") != 0) {
307 else{ /* Test if we are done with entries and starting enumerations */
308 if (strstr(line,"enumerations") != 0){
313 if (strstr(line, "checksums") != 0) {
320 /* skip commented and blank lines */
321 if(line[0]=='#') continue;
322 if(line[strspn(line," ")]=='\n') continue;
323 /* scan in the input data */
324 sscanf(line,"%d %d %c %d %s",
325 &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
327 /* check bit and length ranges */
328 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
329 fprintf(stderr, "Error - bit is to big in line \n%s\n",line);
332 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
333 fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
336 if (!is_ident(ce->name)) {
338 "Error - Name %s is an invalid identifier in line\n %s\n",
342 /* put in the record type */
343 ce->tag=LB_TAG_OPTION;
344 /* calculate and save the record length */
345 len=strlen(ce->name)+1;
346 /* make the record int aligned */
349 ce->size=sizeof(struct cmos_entries)-32+len;
351 cptr += ce->size; /* increment to the next table position */
352 ce = (struct cmos_entries*) cptr;
355 /* put the length of the entries into the header section */
356 entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
358 /* compute the start of the enumerations section */
359 entry_start = ((char*)&cmos_table) + ct->header_length;
360 entry_end = ((char *)entry_start) + entries_length;
361 c_enums_start = c_enums = (struct cmos_enums*)entry_end;
362 /* test for overlaps in the entry records */
363 test_for_entry_overlaps(entry_start, entry_end);
365 for(;enum_mode;){ /* loop to build the enumerations section */
366 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
367 break; /* go till end of input */
369 if (strstr(line, "checksums") != 0) {
375 /* skip commented and blank lines */
376 if(line[0]=='#') continue;
377 if(line[strspn(line," ")]=='\n') continue;
379 /* scan in the data */
380 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
381 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
382 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
383 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
384 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
385 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
386 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
387 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
388 c_enums->text[cnt]=line[ptr];
389 c_enums->text[cnt]=0;
391 /* make the record int aligned */
395 /* store the record length */
396 c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums;
397 /* store the record type */
398 c_enums->tag=LB_TAG_OPTION_ENUM;
399 /* increment to the next record */
400 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
402 /* save the enumerations length */
403 enum_length= (char *)c_enums - (char *)c_enums_start;
404 ct->size=ct->header_length+enum_length+entries_length;
406 /* Get the checksum records */
407 cs=(struct cmos_checksum *)(cmos_table+(ct->size));
409 for(;checksum_mode;) { /* This section finds the checksums */
411 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
412 break; /* end if no more input */
414 /* skip commented and blank lines */
415 if (line[0]=='#') continue;
416 if (line[strspn(line, " ")]=='\n') continue;
417 if (memcmp(line, "checksum", 8) != 0) continue;
419 /* get the information */
421 skip_spaces(line, &ptr);
422 cs->range_start = get_number(line, &ptr, 10);
424 skip_spaces(line, &ptr);
425 cs->range_end = get_number(line, &ptr, 10);
427 skip_spaces(line, &ptr);
428 cs->location = get_number(line, &ptr, 10);
430 /* Make certain there are spaces until the end of the line */
431 skip_spaces(line, &ptr);
433 if ((cs->range_start%8) != 0) {
434 fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
437 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
438 fprintf(stderr, "Error - range start is to big in line\n%s\n", line);
441 if ((cs->range_end%8) != 7) {
442 fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
445 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
446 fprintf(stderr, "Error - range end is to long in line\n%s\n", line);
449 if ((cs->location%8) != 0) {
450 fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
453 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
454 ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
456 fprintf(stderr, "Error - location is to big in line\n%s\n", line);
459 /* And since we are not ready to be fully general purpose yet.. */
460 if ((cs->range_start/8) != LB_CKS_RANGE_START) {
461 fprintf(stderr, "Error - Range start(%d) does not match define(%d) in line\n%s\n",
462 cs->range_start/8, LB_CKS_RANGE_START, line);
465 if ((cs->range_end/8) != LB_CKS_RANGE_END) {
466 fprintf(stderr, "Error - Range end does not match define in line\n%s\n", 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(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);