get rid of pointer/int cast warnings on 64bit.
[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         long 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         long ptr;
159         int cnt;
160         char *cptr;
161         long offset;
162         int entry_start;
163         int entries_length;
164         int enum_length;
165         int len;
166         unsigned char buf[16];
167
168         for(i=1;i<argc;i++) {
169                 if(argv[i][0]!='-') {
170                         display_usage();
171                 }
172                 switch(argv[i][1]) {
173                         case 'b':       /* build the table */
174                                 break;
175                         case '-':       /* data is requested from a file */
176                                 switch(argv[i][2]) {
177                                         case 'c':  /* use a configuration file */
178                                                 if(strcmp(&argv[i][2],"config")) {
179                                                         display_usage();
180                                                 }
181                                                 config=argv[++i];
182                                                 break;
183                                         case 'o':  /* use a cmos definitions table file */
184                                                 if(strcmp(&argv[i][2],"option")) {
185                                                         display_usage();
186                                                 }
187                                                 option=argv[++i];
188                                                 break;
189                                         default:
190                                                 display_usage();
191                                                 break;
192                                 }
193                                 break;
194                         default:
195                                 display_usage();
196                                 break;
197                 }
198         }
199
200
201         /* Has the user specified a configuration file */
202         if(config) {    /* if yes, open it */
203                 if((fp=fopen(config,"r"))==NULL){
204                         printf("Error - Can not open config file %s\n",config);
205                         exit(1);  /* exit if it can not be opened */
206                 }
207         }
208         else {  /* no configuration file specified, so try the default */
209                 if((fp=fopen("cmos.layout","r"))==NULL){
210                         printf("Error - Can not open cmos.layout\n");
211                         exit(1);  /* end of no configuration file is found */
212                 }
213         }
214         /* type cast a pointer, so we can us the structure */
215         ct=(struct cmos_option_table*)cmos_table;
216         /* start the table with the type signature */
217         ct->tag = LB_TAG_CMOS_OPTION_TABLE;
218         /* put in the header length */
219         ct->header_length=sizeof(*ct);
220
221         /* Get the entry records */
222         ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
223         cptr = (char*)ce;
224         for(;;){  /* this section loops through the entry records */
225                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
226                         break; /* end if no more input */
227                 if(!entry_mode) {  /* skip input until the entries key word */
228                         if (strstr(line,"entries") != 0) {
229                                 entry_mode=1;
230                                 continue;
231                         }
232                 }
233                 else{  /* Test if we are done with entries and starting enumerations */
234                         if (strstr(line,"enumerations") != 0){
235                                 entry_mode=0;
236                                 enum_mode=1;
237                                 break;
238                         }
239                         if (strstr(line, "checksums") != 0) {
240                                 enum_mode=0;
241                                 checksum_mode=1;
242                                 break;
243                         }
244                 }
245
246                 /* skip commented and blank lines */
247                 if(line[0]=='#') continue;
248                 if(line[strspn(line," ")]=='\n') continue;
249                 /* scan in the input data */
250                 sscanf(line,"%d %d %c %d %s",
251                         &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
252                 ce->config=(int)uc;
253                 /* check bit and length ranges */
254                 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
255                         printf("Error - bit is to big in line \n%s\n",line);
256                         exit(1);
257                 }
258                 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
259                         printf("Error - Length is to long in line \n%s\n",line);
260                         exit(1);
261                 }
262                 /* put in the record type */
263                 ce->tag=LB_TAG_OPTION;
264                 /* calculate and save the record length */
265                 len=strlen(ce->name)+1;
266                 /* make the record int aligned */
267                 if(len%4)
268                         len+=(4-(len%4));
269                 ce->size=sizeof(struct cmos_entries)-32+len;
270                 cptr = (char*)ce;
271                 cptr+=ce->size;  /* increment to the next table position */
272                 ce = (struct cmos_entries*) cptr;
273         }
274
275         /* put the length of the entries into the header section */
276         entries_length=(long)cptr;
277         entries_length-=(long)(cmos_table+ct->header_length);
278
279         /* compute the start of the enumerations section */
280         entry_start=(int)cmos_table;
281         entry_start+=ct->header_length;
282         offset=entry_start+entries_length;
283         c_enums_start=c_enums=(struct cmos_enums*)offset;
284         /* test for overlaps in the entry records */
285         test_for_entry_overlaps(entry_start,offset);
286
287         for(;enum_mode;){ /* loop to build the enumerations section */
288                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
289                         break; /* go till end of input */
290
291                 if (strstr(line, "checksums") != 0) {
292                         enum_mode=0;
293                         checksum_mode=1;
294                         break;
295                 }
296
297                 /* skip commented and blank lines */
298                 if(line[0]=='#') continue;
299                 if(line[strspn(line," ")]=='\n') continue;
300
301                 /* scan in the data */
302                 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
303                 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
304                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
305                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
306                 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
307                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
308                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
309                 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
310                         c_enums->text[cnt]=line[ptr];
311                 c_enums->text[cnt]=0;
312         
313                 /* make the record int aligned */
314                 cnt++;
315                 if(cnt%4)
316                         cnt+=4-(cnt%4);
317                 /* store the record length */
318                 c_enums->size=((long)&c_enums->text[cnt])-(long)c_enums;
319                 /* store the record type */
320                 c_enums->tag=LB_TAG_OPTION_ENUM;
321                 /* increment to the next record */
322                 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
323         }
324         /* save the enumerations length */
325         enum_length=(long)c_enums-(long)c_enums_start;
326         ct->size=ct->header_length+enum_length+entries_length;
327
328         /* Get the checksum records */
329         cs=(struct cmos_checksum *)(cmos_table+(ct->size));
330         cptr = (char*)cs;
331         for(;checksum_mode;) { /* This section finds the checksums */
332                 char *ptr;
333                 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
334                         break; /* end if no more input */
335
336                 /* skip commented and blank lines */
337                 if (line[0]=='#') continue;
338                 if (line[strspn(line, " ")]=='\n') continue;
339                 if (memcmp(line, "checksum", 8) != 0) continue;
340
341                 /* get the information */
342                 ptr = line + 8;
343                 skip_spaces(line, &ptr);
344                 cs->range_start = get_number(line, &ptr, 10);
345
346                 skip_spaces(line, &ptr);
347                 cs->range_end = get_number(line, &ptr, 10);
348
349                 skip_spaces(line, &ptr);
350                 cs->location = get_number(line, &ptr, 10);
351                 
352                 /* Make certain there are spaces until the end of the line */
353                 skip_spaces(line, &ptr);
354
355                 if ((cs->range_start%8) != 0) {
356                         printf("Error - range start is not byte aligned in line\n%s\n", line);
357                         exit(1);
358                 }
359                 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
360                         printf("Error - range start is to big in line\n%s\n", line);
361                         exit(1);
362                 }
363                 if ((cs->range_end%8) != 7) {
364                         printf("Error - range end is not byte aligned in line\n%s\n", line);
365                         exit(1);
366                 }
367                 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
368                         printf("Error - range end is to long in line\n%s\n", line);
369                         exit(1);
370                 }
371                 if ((cs->location%8) != 0) {
372                         printf("Error - location is not byte aligned in line\n%s\n", line);
373                         exit(1);
374                 }
375                 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
376                         ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8))) 
377                 {
378                         printf("Error - location is to big in line\n%s\n", line);
379                         exit(1);
380                 }
381                 /* And since we are not ready to be fully general purpose yet.. */
382                 if ((cs->range_start/8) != LB_CKS_RANGE_START) {
383                         printf("Error - Range start(%d) does not match define(%d) in line\n%s\n", 
384                                 cs->range_start/8, LB_CKS_RANGE_START, line);
385                         exit(1);
386                 }
387                 if ((cs->range_end/8) != LB_CKS_RANGE_END) {
388                         printf("Error - Range end does not match define in line\n%s\n", line);
389                         exit(1);
390                 }
391                 if ((cs->location/8) != LB_CKS_LOC) {
392                         printf("Error - Location does not match define in line\n%s\n", line);
393                         exit(1);
394                 }
395
396                 cs->tag = LB_TAG_OPTION_CHECKSUM;
397                 cs->size = sizeof(*cs);
398                 cs->type = CHECKSUM_PCBIOS;
399                 cptr = (char *)cs;
400                 cptr += cs->size;
401                 cs = (struct cmos_checksum *)cptr;
402
403         }
404         ct->size += (cptr - (char *)(cmos_table + ct->size));
405         fclose(fp);
406
407         /* test if an alternate file is to be created */
408         if(option) {
409                 if((fp=fopen(option,"w"))==NULL){
410                         printf("Error - Can not open %s\n",option);
411                         exit(1);
412                 }
413         }
414         else {  /* no, so use the default option_table.c */
415                 if((fp=fopen("option_table.c","w"))==NULL){
416                         printf("Error - Can not open option_table.c\n");
417                         exit(1);
418                 }
419         }
420         /* write the header */
421         if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
422                 printf("Error - Could not write image file\n");
423                 fclose(fp);
424                 exit(1);
425         }
426         /* write the array values */
427         for(i=0;i<(ct->size-1);i++) {
428                 if(!(i%10)) fwrite("\n\t",1,2,fp);
429                 sprintf(buf,"0x%02x,",cmos_table[i]);
430                 fwrite(buf,1,5,fp);
431         }
432         /* write the end */
433         sprintf(buf,"0x%02x",cmos_table[i]);
434         fwrite(buf,1,4,fp);
435         if(!fwrite("};\n",1,3,fp)) {
436                 printf("Error - Could not write image file\n");
437                 fclose(fp);
438                 exit(1);
439         }
440
441         fclose(fp);
442         return(0);
443 }
444
445