diff options
author | Eric Biederman <ebiederm@xmission.com> | 2003-04-22 19:02:15 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2003-04-22 19:02:15 +0000 |
commit | 8ca8d7665d671e10d72b8fcb4d69121d75f7906e (patch) | |
tree | daad2699b4e6b6014bce5a76e82dd9c974801777 /util/options/build_opt_tbl.c | |
parent | b138ac83b53da9abf3dc9a87a1cd4b3d3a8150bd (diff) | |
download | coreboot-8ca8d7665d671e10d72b8fcb4d69121d75f7906e.tar.xz |
- Initial checkin of the freebios2 tree
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@784 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/options/build_opt_tbl.c')
-rw-r--r-- | util/options/build_opt_tbl.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/util/options/build_opt_tbl.c b/util/options/build_opt_tbl.c new file mode 100644 index 0000000000..6a489bdb52 --- /dev/null +++ b/util/options/build_opt_tbl.c @@ -0,0 +1,443 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/io.h> +#include <string.h> +#include <ctype.h> +#include "../../src/include/pc80/mc146818rtc.h" +#include "../../src/include/boot/linuxbios_tables.h" + +#define CMOS_IMAGE_BUFFER_SIZE 128 +#define INPUT_LINE_MAX 256 +#define MAX_VALUE_BYTE_LENGTH 64 + + +static unsigned char cmos_table[4096]; + +/* This array is used to isolate bits that are to be changed in a byte */ +static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff}; + + +/* This routine loops through the entried and tests if any of the fields overlap + input entry_start = the memory pointer to the start of the entries. + entry_end = the byte past the entries. + output none + if there is an overlap, the routine exits, other wise it returns. +*/ +void test_for_entry_overlaps(int entry_start,int entry_end) +{ + int ptr; + int buffer_bit_size; + int offset; + int byte; + int byte_length; + struct cmos_entries *ce; + unsigned char test[CMOS_IMAGE_BUFFER_SIZE]; + unsigned char set; + + /* calculate the size of the cmos buffer in bits */ + buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8); + /* clear the temporary test buffer */ + for(ptr=0;ptr<CMOS_IMAGE_BUFFER_SIZE;ptr++) + test[ptr]=0; + /* loop through each entry in the table testing for errors */ + for(ptr=entry_start;ptr<entry_end;ptr+=ce->size) { + ce=(struct cmos_entries *)ptr; + /* test if entry goes past the end of the buffer */ + if((ce->bit+ce->length)>buffer_bit_size) { + printf("Error - Entry %s start bit + length must be less than %d\n", + ce->name,buffer_bit_size); + exit(1); + } + byte=ce->bit/8; + offset=ce->bit%8; + byte_length=ce->length/8; + if(byte_length) { /* entry is 8 bits long or more */ + if(offset) { /* if 8 bits or more long, it must be byte aligned */ + printf("Error - Entry %s length over 8 must be byte aligned\n", + ce->name); + exit(1); + } + /* test if entries 8 or more in length are even bytes */ + if(ce->length%8){ + printf("Error - Entry %s length over 8 must be a multiple of 8\n", + ce->name); + exit(1); + } + /* test if any of the bits have been previously used */ + for(;byte_length;byte_length--,byte++) { + if(test[byte]) { + printf("Error - Entry %s uses same bits previously used\n", + ce->name); + exit(1); + } + test[byte]=clip[8]; /* set the bits defined in test */ + } + } else { + /* test if bits overlap byte boundaries */ + if(ce->length>(8-offset)) { + printf("Error - Entry %s length overlaps a byte boundry\n", ce->name); + exit(1); + } + /* test for bits previously used */ + set=(clip[ce->length]<<offset); + if(test[byte]&set) { + printf("Error - Entry %s uses same bits previously used\n", + ce->name); + exit(1); + } + test[byte]|=set; /* set the bits defined in test */ + } + } + return; +} + +/* This routine displays the usage options */ +void display_usage(void) +{ + printf("Usage build_opt_table [-b] [--option filename]\n"); + printf(" [--config filename]\n"); + printf("b = build option_table.c\n"); + printf("--option = name of option table output file\n"); + printf("--config = build the definitions table from the given file\n"); + exit(1); +} + + +static void skip_spaces(char *line, char **ptr) +{ + if (!isspace(**ptr)) { + printf("Error missing whitespace in line\n%s\n", line); + exit(1); + } + while(isspace(**ptr)) { + (*ptr)++; + } + return; +} +static unsigned long get_number(char *line, char **ptr, int base) +{ + unsigned long value; + char *ptr2; + value = strtoul(*ptr, &ptr2, base); + if (ptr2 == *ptr) { + printf("Error missing digits at: \n%s\n in line:\n%s\n", + *ptr, line); + exit(1); + } + *ptr = ptr2; + return value; +} + +/* This routine builds the cmos definition table from the cmos layout file + input The input comes from the configuration file which contains two parts + entries and enumerations. Each section is started with the key words + entries and enumerations. Records then follow in their respective + formats. + output The output of this program is the cmos definitions table. It is stored + in the cmos_table array. If this module is called, and the global + table_file has been implimented by the user, the table is also written + to the specified file. + This program exits on and error. It returns a 1 on successful + completion +*/ +int main(int argc, char **argv) +{ + int i; + char *config=0; + char *option=0; + FILE *fp; + struct cmos_option_table *ct; + struct cmos_entries *ce; + struct cmos_enums *c_enums, *c_enums_start; + struct cmos_checksum *cs; + unsigned char line[INPUT_LINE_MAX]; + unsigned char uc; + int entry_mode=0; + int enum_mode=0; + int checksum_mode=0; + int ptr,cnt; + char *cptr; + int offset,entry_start; + int entries_length; + int enum_length; + int len; + unsigned char buf[16]; + + for(i=1;i<argc;i++) { + if(argv[i][0]!='-') { + display_usage(); + } + switch(argv[i][1]) { + case 'b': /* build the table */ + break; + case '-': /* data is requested from a file */ + switch(argv[i][2]) { + case 'c': /* use a configuration file */ + if(strcmp(&argv[i][2],"config")) { + display_usage(); + } + config=argv[++i]; + break; + case 'o': /* use a cmos definitions table file */ + if(strcmp(&argv[i][2],"option")) { + display_usage(); + } + option=argv[++i]; + break; + default: + display_usage(); + break; + } + break; + default: + display_usage(); + break; + } + } + + + /* Has the user specified a configuration file */ + if(config) { /* if yes, open it */ + if((fp=fopen(config,"r"))==NULL){ + printf("Error - Can not open config file %s\n",config); + exit(1); /* exit if it can not be opened */ + } + } + else { /* no configuration file specified, so try the default */ + if((fp=fopen("cmos.layout","r"))==NULL){ + printf("Error - Can not open cmos.layout\n"); + exit(1); /* end of no configuration file is found */ + } + } + /* type cast a pointer, so we can us the structure */ + ct=(struct cmos_option_table*)cmos_table; + /* start the table with the type signature */ + ct->tag = LB_TAG_CMOS_OPTION_TABLE; + /* put in the header length */ + ct->header_length=sizeof(*ct); + + /* Get the entry records */ + ce=(struct cmos_entries*)(cmos_table+(ct->header_length)); + cptr = (char*)ce; + for(;;){ /* this section loops through the entry records */ + if(fgets(line,INPUT_LINE_MAX,fp)==NULL) + break; /* end if no more input */ + if(!entry_mode) { /* skip input until the entries key word */ + if (strstr(line,"entries") != 0) { + entry_mode=1; + continue; + } + } + else{ /* Test if we are done with entries and starting enumerations */ + if (strstr(line,"enumerations") != 0){ + entry_mode=0; + enum_mode=1; + break; + } + if (strstr(line, "checksums") != 0) { + enum_mode=0; + checksum_mode=1; + break; + } + } + + /* skip commented and blank lines */ + if(line[0]=='#') continue; + if(line[strspn(line," ")]=='\n') continue; + /* scan in the input data */ + sscanf(line,"%d %d %c %d %s", + &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]); + ce->config=(int)uc; + /* check bit and length ranges */ + if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) { + printf("Error - bit is to big in line \n%s\n",line); + exit(1); + } + if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) { + printf("Error - Length is to long in line \n%s\n",line); + exit(1); + } + /* put in the record type */ + ce->tag=LB_TAG_OPTION; + /* calculate and save the record length */ + len=strlen(ce->name)+1; + /* make the record int aligned */ + if(len%4) + len+=(4-(len%4)); + ce->size=sizeof(struct cmos_entries)-32+len; + cptr = (char*)ce; + cptr+=ce->size; /* increment to the next table position */ + ce = (struct cmos_entries*) cptr; + } + + /* put the length of the entries into the header section */ + entries_length=(int)cptr; + entries_length-=(int)(cmos_table+ct->header_length); + + /* compute the start of the enumerations section */ + entry_start=(int)cmos_table; + entry_start+=ct->header_length; + offset=entry_start+entries_length; + c_enums_start=c_enums=(struct cmos_enums*)offset; + /* test for overlaps in the entry records */ + test_for_entry_overlaps(entry_start,offset); + + for(;enum_mode;){ /* loop to build the enumerations section */ + if(fgets(line,INPUT_LINE_MAX,fp)==NULL) + break; /* go till end of input */ + + if (strstr(line, "checksums") != 0) { + enum_mode=0; + checksum_mode=1; + break; + } + + /* skip commented and blank lines */ + if(line[0]=='#') continue; + if(line[strspn(line," ")]=='\n') continue; + + /* scan in the data */ + for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++); + c_enums->config_id=strtol(&line[ptr],(char**)NULL,10); + for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++); + for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++); + c_enums->value=strtol(&line[ptr],(char**)NULL,10); + for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++); + for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++); + for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++) + c_enums->text[cnt]=line[ptr]; + c_enums->text[cnt]=0; + + /* make the record int aligned */ + cnt++; + if(cnt%4) + cnt+=4-(cnt%4); + /* store the record length */ + c_enums->size=((int)&c_enums->text[cnt])-(int)c_enums; + /* store the record type */ + c_enums->tag=LB_TAG_OPTION_ENUM; + /* increment to the next record */ + c_enums=(struct cmos_enums*)&c_enums->text[cnt]; + } + /* save the enumerations length */ + enum_length=(int)c_enums-(int)c_enums_start; + ct->size=ct->header_length+enum_length+entries_length; + + /* Get the checksum records */ + cs=(struct cmos_checksum *)(cmos_table+(ct->size)); + cptr = (char*)cs; + for(;checksum_mode;) { /* This section finds the checksums */ + char *ptr; + if(fgets(line, INPUT_LINE_MAX,fp)==NULL) + break; /* end if no more input */ + + /* skip commented and blank lines */ + if (line[0]=='#') continue; + if (line[strspn(line, " ")]=='\n') continue; + if (memcmp(line, "checksum", 8) != 0) continue; + + /* get the information */ + ptr = line + 8; + skip_spaces(line, &ptr); + cs->range_start = get_number(line, &ptr, 10); + + skip_spaces(line, &ptr); + cs->range_end = get_number(line, &ptr, 10); + + skip_spaces(line, &ptr); + cs->location = get_number(line, &ptr, 10); + + /* Make certain there are spaces until the end of the line */ + skip_spaces(line, &ptr); + + if ((cs->range_start%8) != 0) { + printf("Error - range start is not byte aligned in line\n%s\n", line); + exit(1); + } + if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) { + printf("Error - range start is to big in line\n%s\n", line); + exit(1); + } + if ((cs->range_end%8) != 7) { + printf("Error - range end is not byte aligned in line\n%s\n", line); + exit(1); + } + if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) { + printf("Error - range end is to long in line\n%s\n", line); + exit(1); + } + if ((cs->location%8) != 0) { + printf("Error - location is not byte aligned in line\n%s\n", line); + exit(1); + } + if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) || + ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8))) + { + printf("Error - location is to big in line\n%s\n", line); + exit(1); + } + /* And since we are not ready to be fully general purpose yet.. */ + if ((cs->range_start/8) != LB_CKS_RANGE_START) { + printf("Error - Range start(%d) does not match define(%d) in line\n%s\n", + cs->range_start/8, LB_CKS_RANGE_START, line); + exit(1); + } + if ((cs->range_end/8) != LB_CKS_RANGE_END) { + printf("Error - Range end does not match define in line\n%s\n", line); + exit(1); + } + if ((cs->location/8) != LB_CKS_LOC) { + printf("Error - Location does not match define in line\n%s\n", line); + exit(1); + } + + cs->tag = LB_TAG_OPTION_CHECKSUM; + cs->size = sizeof(*cs); + cs->type = CHECKSUM_PCBIOS; + cptr = (char *)cs; + cptr += cs->size; + cs = (struct cmos_checksum *)cptr; + + } + ct->size += (cptr - (char *)(cmos_table + ct->size)); + fclose(fp); + + /* test if an alternate file is to be created */ + if(option) { + if((fp=fopen(option,"w"))==NULL){ + printf("Error - Can not open %s\n",option); + exit(1); + } + } + else { /* no, so use the default option_table.c */ + if((fp=fopen("option_table.c","w"))==NULL){ + printf("Error - Can not open option_table.c\n"); + exit(1); + } + } + /* write the header */ + if(!fwrite("unsigned char option_table[] = {",1,32,fp)) { + printf("Error - Could not write image file\n"); + fclose(fp); + exit(1); + } + /* write the array values */ + for(i=0;i<(ct->size-1);i++) { + if(!(i%10)) fwrite("\n\t",1,2,fp); + sprintf(buf,"0x%02x,",cmos_table[i]); + fwrite(buf,1,5,fp); + } + /* write the end */ + sprintf(buf,"0x%02x",cmos_table[i]); + fwrite(buf,1,4,fp); + if(!fwrite("};\n",1,3,fp)) { + printf("Error - Could not write image file\n"); + fclose(fp); + exit(1); + } + + fclose(fp); + return(0); +} + + |