- Initial checkin of the freebios2 tree
[coreboot.git] / util / options / build_opt_tbl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/io.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include "../../src/include/pc80/mc146818rtc.h"
7 #include "../../src/include/boot/linuxbios_tables.h"
8
9 #define CMOS_IMAGE_BUFFER_SIZE 128
10 #define INPUT_LINE_MAX 256
11 #define MAX_VALUE_BYTE_LENGTH 64
12
13
14 static unsigned char cmos_table[4096];
15
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};
18
19
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.
23         output  none
24                 if there is an overlap, the routine exits, other wise it returns.
25 */
26 void test_for_entry_overlaps(int entry_start,int entry_end)
27 {
28         int ptr;
29         int buffer_bit_size;
30         int offset;
31         int byte;
32         int byte_length;
33         struct cmos_entries *ce;
34         unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
35         unsigned char set;
36
37         /* calculate the size of the cmos buffer in bits */
38         buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
39         /* clear the temporary test buffer */
40         for(ptr=0;ptr<CMOS_IMAGE_BUFFER_SIZE;ptr++)
41                 test[ptr]=0;
42         /* loop through each entry in the table testing for errors */
43         for(ptr=entry_start;ptr<entry_end;ptr+=ce->size) {
44                 ce=(struct cmos_entries *)ptr;
45                 /* test if entry goes past the end of the buffer */
46                 if((ce->bit+ce->length)>buffer_bit_size) {
47                         printf("Error - Entry %s start bit + length must be less than %d\n",
48                                 ce->name,buffer_bit_size);
49                         exit(1);
50                 }
51                 byte=ce->bit/8;
52                 offset=ce->bit%8;
53                 byte_length=ce->length/8;
54                 if(byte_length) {       /* entry is 8 bits long or more */
55                         if(offset) { /* if 8 bits or more long, it must be byte aligned */
56                                 printf("Error - Entry %s length over 8 must be byte aligned\n",
57                                         ce->name);
58                                 exit(1);
59                         }
60                         /* test if entries 8 or more in length are even bytes */ 
61                         if(ce->length%8){
62                                 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
63                                         ce->name);
64                                 exit(1);
65                         }
66                         /* test if any of the bits have been previously used */
67                         for(;byte_length;byte_length--,byte++) {
68                                 if(test[byte]) {
69                                     printf("Error - Entry %s uses same bits previously used\n",
70                                                 ce->name);
71                                     exit(1);
72                                 }
73                                 test[byte]=clip[8]; /* set the bits defined in test */
74                         }
75                 } else {
76                         /* test if bits overlap byte boundaries */
77                         if(ce->length>(8-offset)) {
78                                 printf("Error - Entry %s length overlaps a byte boundry\n",                                        ce->name);
79                                 exit(1);
80                         }
81                         /* test for bits previously used */
82                         set=(clip[ce->length]<<offset);
83                         if(test[byte]&set) {
84                                 printf("Error - Entry %s uses same bits previously used\n",
85                                                 ce->name);
86                                 exit(1);
87                         }
88                         test[byte]|=set;  /* set the bits defined in test */
89                 }
90         }
91         return;
92 }
93
94 /* This routine displays the usage options */
95 void display_usage(void)
96 {
97         printf("Usage build_opt_table [-b] [--option filename]\n");
98         printf("                [--config filename]\n");
99         printf("b = build option_table.c\n");
100         printf("--option = name of option table output file\n");
101         printf("--config = build the definitions table from the given file\n");
102         exit(1);
103 }
104
105
106 static void skip_spaces(char *line, char **ptr)
107 {
108         if (!isspace(**ptr)) {
109                 printf("Error missing whitespace in line\n%s\n", line);
110                 exit(1);
111         }
112         while(isspace(**ptr)) {
113                 (*ptr)++;
114         }
115         return;
116 }
117 static unsigned long get_number(char *line, char **ptr, int base)
118 {
119         unsigned long value;
120         char *ptr2;
121         value = strtoul(*ptr, &ptr2, base);
122         if (ptr2 == *ptr) {
123                 printf("Error missing digits at: \n%s\n in line:\n%s\n", 
124                         *ptr, line);
125                 exit(1);
126         }
127         *ptr = ptr2;
128         return value;
129 }
130
131 /* This routine builds the cmos definition table from the cmos layout file
132         input The input comes from the configuration file which contains two parts
133                 entries and enumerations. Each section is started with the key words
134                 entries and enumerations.  Records then follow in their respective 
135                 formats.
136         output The output of this program is the cmos definitions table.  It is stored
137                 in the cmos_table array. If this module is called, and the global 
138                 table_file has been implimented by the user, the table is also written
139                 to the specified file.
140                 This program exits on and error.  It returns a 1 on successful 
141                 completion
142 */
143 int main(int argc, char **argv)
144 {
145         int i;
146         char *config=0;
147         char *option=0;
148         FILE *fp;
149         struct cmos_option_table *ct;
150         struct cmos_entries *ce;
151         struct cmos_enums *c_enums, *c_enums_start;
152         struct cmos_checksum *cs;
153         unsigned char line[INPUT_LINE_MAX];
154         unsigned char uc;
155         int entry_mode=0;
156         int enum_mode=0;
157         int checksum_mode=0;
158         int ptr,cnt;
159         char *cptr;
160         int offset,entry_start;
161         int entries_length;
162         int enum_length;
163         int len;
164         unsigned char buf[16];
165
166         for(i=1;i<argc;i++) {
167                 if(argv[i][0]!='-') {
168                         display_usage();
169                 }
170                 switch(argv[i][1]) {
171                         case 'b':       /* build the table */
172                                 break;
173                         case '-':       /* data is requested from a file */
174                                 switch(argv[i][2]) {
175                                         case 'c':  /* use a configuration file */
176                                                 if(strcmp(&argv[i][2],"config")) {
177                                                         display_usage();
178                                                 }
179                                                 config=argv[++i];
180                                                 break;
181                                         case 'o':  /* use a cmos definitions table file */
182                                                 if(strcmp(&argv[i][2],"option")) {
183                                                         display_usage();
184                                                 }
185                                                 option=argv[++i];
186                                                 break;
187                                         default:
188                                                 display_usage();
189                                                 break;
190                                 }
191                                 break;
192                         default:
193                                 display_usage();
194                                 break;
195                 }
196         }
197
198
199         /* Has the user specified a configuration file */
200         if(config) {    /* if yes, open it */
201                 if((fp=fopen(config,"r"))==NULL){
202                         printf("Error - Can not open config file %s\n",config);
203                         exit(1);  /* exit if it can not be opened */
204                 }
205         }
206         else {  /* no configuration file specified, so try the default */
207                 if((fp=fopen("cmos.layout","r"))==NULL){
208                         printf("Error - Can not open cmos.layout\n");
209                         exit(1);  /* end of no configuration file is found */
210                 }
211         }
212         /* type cast a pointer, so we can us the structure */
213         ct=(struct cmos_option_table*)cmos_table;
214         /* start the table with the type signature */
215         ct->tag = LB_TAG_CMOS_OPTION_TABLE;
216         /* put in the header length */
217         ct->header_length=sizeof(*ct);
218
219         /* Get the entry records */
220         ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
221         cptr = (char*)ce;
222         for(;;){  /* this section loops through the entry records */
223                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
224                         break; /* end if no more input */
225                 if(!entry_mode) {  /* skip input until the entries key word */
226                         if (strstr(line,"entries") != 0) {
227                                 entry_mode=1;
228                                 continue;
229                         }
230                 }
231                 else{  /* Test if we are done with entries and starting enumerations */
232                         if (strstr(line,"enumerations") != 0){
233                                 entry_mode=0;
234                                 enum_mode=1;
235                                 break;
236                         }
237                         if (strstr(line, "checksums") != 0) {
238                                 enum_mode=0;
239                                 checksum_mode=1;
240                                 break;
241                         }
242                 }
243
244                 /* skip commented and blank lines */
245                 if(line[0]=='#') continue;
246                 if(line[strspn(line," ")]=='\n') continue;
247                 /* scan in the input data */
248                 sscanf(line,"%d %d %c %d %s",
249                         &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
250                 ce->config=(int)uc;
251                 /* check bit and length ranges */
252                 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
253                         printf("Error - bit is to big in line \n%s\n",line);
254                         exit(1);
255                 }
256                 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
257                         printf("Error - Length is to long in line \n%s\n",line);
258                         exit(1);
259                 }
260                 /* put in the record type */
261                 ce->tag=LB_TAG_OPTION;
262                 /* calculate and save the record length */
263                 len=strlen(ce->name)+1;
264                 /* make the record int aligned */
265                 if(len%4)
266                         len+=(4-(len%4));
267                 ce->size=sizeof(struct cmos_entries)-32+len;
268                 cptr = (char*)ce;
269                 cptr+=ce->size;  /* increment to the next table position */
270                 ce = (struct cmos_entries*) cptr;
271         }
272
273         /* put the length of the entries into the header section */
274         entries_length=(int)cptr;
275         entries_length-=(int)(cmos_table+ct->header_length);
276
277         /* compute the start of the enumerations section */
278         entry_start=(int)cmos_table;
279         entry_start+=ct->header_length;
280         offset=entry_start+entries_length;
281         c_enums_start=c_enums=(struct cmos_enums*)offset;
282         /* test for overlaps in the entry records */
283         test_for_entry_overlaps(entry_start,offset);
284
285         for(;enum_mode;){ /* loop to build the enumerations section */
286                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
287                         break; /* go till end of input */
288
289                 if (strstr(line, "checksums") != 0) {
290                         enum_mode=0;
291                         checksum_mode=1;
292                         break;
293                 }
294
295                 /* skip commented and blank lines */
296                 if(line[0]=='#') continue;
297                 if(line[strspn(line," ")]=='\n') continue;
298
299                 /* scan in the data */
300                 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
301                 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
302                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
303                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
304                 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
305                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
306                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
307                 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
308                         c_enums->text[cnt]=line[ptr];
309                 c_enums->text[cnt]=0;
310         
311                 /* make the record int aligned */
312                 cnt++;
313                 if(cnt%4)
314                         cnt+=4-(cnt%4);
315                 /* store the record length */
316                 c_enums->size=((int)&c_enums->text[cnt])-(int)c_enums;
317                 /* store the record type */
318                 c_enums->tag=LB_TAG_OPTION_ENUM;
319                 /* increment to the next record */
320                 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
321         }
322         /* save the enumerations length */
323         enum_length=(int)c_enums-(int)c_enums_start;
324         ct->size=ct->header_length+enum_length+entries_length;
325
326         /* Get the checksum records */
327         cs=(struct cmos_checksum *)(cmos_table+(ct->size));
328         cptr = (char*)cs;
329         for(;checksum_mode;) { /* This section finds the checksums */
330                 char *ptr;
331                 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
332                         break; /* end if no more input */
333
334                 /* skip commented and blank lines */
335                 if (line[0]=='#') continue;
336                 if (line[strspn(line, " ")]=='\n') continue;
337                 if (memcmp(line, "checksum", 8) != 0) continue;
338
339                 /* get the information */
340                 ptr = line + 8;
341                 skip_spaces(line, &ptr);
342                 cs->range_start = get_number(line, &ptr, 10);
343
344                 skip_spaces(line, &ptr);
345                 cs->range_end = get_number(line, &ptr, 10);
346
347                 skip_spaces(line, &ptr);
348                 cs->location = get_number(line, &ptr, 10);
349                 
350                 /* Make certain there are spaces until the end of the line */
351                 skip_spaces(line, &ptr);
352
353                 if ((cs->range_start%8) != 0) {
354                         printf("Error - range start is not byte aligned in line\n%s\n", line);
355                         exit(1);
356                 }
357                 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
358                         printf("Error - range start is to big in line\n%s\n", line);
359                         exit(1);
360                 }
361                 if ((cs->range_end%8) != 7) {
362                         printf("Error - range end is not byte aligned in line\n%s\n", line);
363                         exit(1);
364                 }
365                 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
366                         printf("Error - range end is to long in line\n%s\n", line);
367                         exit(1);
368                 }
369                 if ((cs->location%8) != 0) {
370                         printf("Error - location is not byte aligned in line\n%s\n", line);
371                         exit(1);
372                 }
373                 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
374                         ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8))) 
375                 {
376                         printf("Error - location is to big in line\n%s\n", line);
377                         exit(1);
378                 }
379                 /* And since we are not ready to be fully general purpose yet.. */
380                 if ((cs->range_start/8) != LB_CKS_RANGE_START) {
381                         printf("Error - Range start(%d) does not match define(%d) in line\n%s\n", 
382                                 cs->range_start/8, LB_CKS_RANGE_START, line);
383                         exit(1);
384                 }
385                 if ((cs->range_end/8) != LB_CKS_RANGE_END) {
386                         printf("Error - Range end does not match define in line\n%s\n", line);
387                         exit(1);
388                 }
389                 if ((cs->location/8) != LB_CKS_LOC) {
390                         printf("Error - Location does not match define in line\n%s\n", line);
391                         exit(1);
392                 }
393
394                 cs->tag = LB_TAG_OPTION_CHECKSUM;
395                 cs->size = sizeof(*cs);
396                 cs->type = CHECKSUM_PCBIOS;
397                 cptr = (char *)cs;
398                 cptr += cs->size;
399                 cs = (struct cmos_checksum *)cptr;
400
401         }
402         ct->size += (cptr - (char *)(cmos_table + ct->size));
403         fclose(fp);
404
405         /* test if an alternate file is to be created */
406         if(option) {
407                 if((fp=fopen(option,"w"))==NULL){
408                         printf("Error - Can not open %s\n",option);
409                         exit(1);
410                 }
411         }
412         else {  /* no, so use the default option_table.c */
413                 if((fp=fopen("option_table.c","w"))==NULL){
414                         printf("Error - Can not open option_table.c\n");
415                         exit(1);
416                 }
417         }
418         /* write the header */
419         if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
420                 printf("Error - Could not write image file\n");
421                 fclose(fp);
422                 exit(1);
423         }
424         /* write the array values */
425         for(i=0;i<(ct->size-1);i++) {
426                 if(!(i%10)) fwrite("\n\t",1,2,fp);
427                 sprintf(buf,"0x%02x,",cmos_table[i]);
428                 fwrite(buf,1,5,fp);
429         }
430         /* write the end */
431         sprintf(buf,"0x%02x",cmos_table[i]);
432         fwrite(buf,1,4,fp);
433         if(!fwrite("};\n",1,3,fp)) {
434                 printf("Error - Could not write image file\n");
435                 fclose(fp);
436                 exit(1);
437         }
438
439         fclose(fp);
440         return(0);
441 }
442
443