+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003 Eric Biederman (ebiederm@xmission.com)
+ * Copyright (C) 2007-2010 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
#include <stdio.h>
#include <stdlib.h>
-#include <sys/io.h>
#include <string.h>
+#include <unistd.h>
#include <ctype.h>
#include <errno.h>
+#include <libgen.h>
+#define UTIL_BUILD_OPTION_TABLE
#include "../../src/include/pc80/mc146818rtc.h"
-#include "../../src/include/boot/linuxbios_tables.h"
+#include "../../src/include/boot/coreboot_tables.h"
-#define CMOS_IMAGE_BUFFER_SIZE 128
+#define CMOS_IMAGE_BUFFER_SIZE 256
#define INPUT_LINE_MAX 256
#define MAX_VALUE_BYTE_LENGTH 64
+#define TMPFILE_LEN 25600
+#define TMPFILE_TEMPLATE "/build_opt_tbl_XXXXXX"
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(void *entry_start, void *entry_end)
+#ifdef WIN32
+#include <fcntl.h>
+char *mkstemp(char* name)
+{
+ static char val='0';
+ char *c=name;
+ while (*c!='X') c++;
+ *c=val++;
+ return open(name,O_CREAT | O_RDWR);
+}
+#define UNLINK_IF_NECESSARY(x) unlink(x)
+#else
+#define UNLINK_IF_NECESSARY(x)
+#endif
+
+/**
+ * This routine loops through the entried and tests if any of the fields
+ * overlap.
+ * If there is an overlap, the routine exits, otherwise it returns.
+ *
+ * @param entry_start memory pointer to the start of the entries.
+ * @param entry_end memory pointer to the byte past the entries.
+ */
+static void test_for_entry_overlaps(void *entry_start, void *entry_end)
{
int ptr;
char *cptr;
for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
ce=(struct cmos_entries *)cptr;
/* test if entry goes past the end of the buffer */
- if((ce->bit+ce->length)>buffer_bit_size) {
+ if((int)(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);
ce->name);
exit(1);
}
- /* test if entries 8 or more in length are even bytes */
+ /* 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);
}
} else {
/* test if bits overlap byte boundaries */
- if(ce->length>(8-offset)) {
+ if((int)ce->length > (8-offset)) {
printf("Error - Entry %s length overlaps a byte boundry\n",
ce->name);
exit(1);
}
/* This routine displays the usage options */
-void display_usage(void)
+static void display_usage(char *name)
{
- printf("Usage build_opt_table [-b] [--option filename]\n");
- printf(" [--config filename]\n");
- printf(" [--header 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");
- printf("--header = ouput a header file with the definitions\n");
- exit(1);
+ printf("Usage: %s [--config filename]\n", name);
+ printf(" [--option filename]\n");
+ printf(" [--header filename]\n\n");
+ printf("--config = Build the definitions table from the given file.\n");
+ printf("--binary = Output a binary file with the definitions.\n");
+ printf("--option = Output a C source file with the definitions.\n");
+ printf("--header = Output a C header file with the definitions.\n");
+ exit(1);
}
-
static void skip_spaces(char *line, char **ptr)
{
if (!isspace(**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",
+ printf("Error missing digits at: \n%s\n in line:\n%s\n",
*ptr, line);
exit(1);
}
return result;
}
-
-/* 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
-*/
+/**
+ * This routine builds the cmos definition table from the cmos layout file
+ *
+ * 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.
+ *
+ * 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 with a return code of 1 on error. It returns 0 on
+ * successful completion
+ */
int main(int argc, char **argv)
{
int i;
char *config=0;
+ char *binary=0;
char *option=0;
char *header=0;
FILE *fp;
+ int tempfile;
+ char tempfilename[TMPFILE_LEN];
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];
+ struct cmos_checksum *cs, *new_cs;
+ char line[INPUT_LINE_MAX];
unsigned char uc;
int entry_mode=0;
int enum_mode=0;
int checksum_mode=0;
- long ptr;
int cnt;
char *cptr;
void *entry_start, *entry_end;
int entries_length;
int enum_length;
int len;
- unsigned char buf[16];
+ char buf[16];
+ char val;
for(i=1;i<argc;i++) {
if(argv[i][0]!='-') {
- display_usage();
+ display_usage(argv[0]);
}
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();
+ display_usage(argv[0]);
}
config=argv[++i];
break;
+ case 'b': /* Emit a binary file */
+ if(strcmp(&argv[i][2],"binary")) {
+ display_usage(argv[0]);
+ }
+ binary=argv[++i];
+ break;
case 'o': /* use a cmos definitions table file */
if(strcmp(&argv[i][2],"option")) {
- display_usage();
+ display_usage(argv[0]);
}
option=argv[++i];
break;
case 'h': /* Output a header file */
if (strcmp(&argv[i][2], "header") != 0) {
- display_usage();
+ display_usage(argv[0]);
}
header=argv[++i];
break;
default:
- display_usage();
+ display_usage(argv[0]);
break;
}
break;
default:
- display_usage();
+ display_usage(argv[0]);
break;
}
}
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)
+ if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
break; /* end if no more input */
+ // FIXME mode should be a single enum.
if(!entry_mode) { /* skip input until the entries key word */
if (strstr(line,"entries") != 0) {
entry_mode=1;
+ enum_mode=0;
+ checksum_mode=0;
continue;
}
- }
- else{ /* Test if we are done with entries and starting enumerations */
+ } else { /* Test if we are done with entries and starting enumerations */
if (strstr(line,"enumerations") != 0){
entry_mode=0;
enum_mode=1;
+ checksum_mode=0;
break;
}
if (strstr(line, "checksums") != 0) {
+ entry_mode=0;
enum_mode=0;
checksum_mode=1;
break;
}
/* skip commented and blank lines */
- if(line[0]=='#') continue;
- if(line[strspn(line," ")]=='\n') continue;
+ val = line[strspn(line," ")];
+ /* takes care of *nix, Mac and Windows line ending formats */
+ if (val=='#' || val=='\n' || val=='\r') continue;
/* scan in the input data */
sscanf(line,"%d %d %c %d %s",
&ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
exit(1);
}
- if (!is_ident(ce->name)) {
- fprintf(stderr,
- "Error - Name %s is an invalid identifier in line\n %s\n",
+ if (!is_ident((char *)ce->name)) {
+ fprintf(stderr,
+ "Error - Name %s is an invalid identifier in line\n %s\n",
ce->name, line);
exit(1);
}
/* put in the record type */
ce->tag=LB_TAG_OPTION;
/* calculate and save the record length */
- len=strlen(ce->name)+1;
+ len=strlen((char *)ce->name)+1;
/* make the record int aligned */
if(len%4)
len+=(4-(len%4));
test_for_entry_overlaps(entry_start, entry_end);
for(;enum_mode;){ /* loop to build the enumerations section */
- if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
+ long ptr;
+ if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
break; /* go till end of input */
if (strstr(line, "checksums") != 0) {
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)
ct->size=ct->header_length+enum_length+entries_length;
/* Get the checksum records */
- cs=(struct cmos_checksum *)(cmos_table+(ct->size));
- cptr = (char*)cs;
+ new_cs = (struct cmos_checksum *)(cmos_table+(ct->size));
for(;checksum_mode;) { /* This section finds the checksums */
char *ptr;
if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
if (line[strspn(line, " ")]=='\n') continue;
if (memcmp(line, "checksum", 8) != 0) continue;
+ /* We actually found a new cmos checksum entry */
+ cs = new_cs;
+
/* get the information */
ptr = line + 8;
skip_spaces(line, &ptr);
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);
exit(1);
}
if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
- ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
+ ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
{
fprintf(stderr, "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) {
- fprintf(stderr, "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) {
- fprintf(stderr, "Error - Range end does not match define in line\n%s\n", line);
- exit(1);
- }
- if ((cs->location/8) != LB_CKS_LOC) {
- fprintf(stderr, "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;
-
+ new_cs = (struct cmos_checksum *)cptr;
}
ct->size += (cptr - (char *)(cmos_table + ct->size));
fclose(fp);
- /* test if an alternate file is to be created */
+ /* See if we want to output a C source file */
if(option) {
- if((fp=fopen(option,"w"))==NULL){
- fprintf(stderr, "Error - Can not open %s\n",option);
+ int err=0;
+ snprintf(tempfilename, TMPFILE_LEN, "%s%s", dirname(strdup(option)), TMPFILE_TEMPLATE);
+ tempfile = mkstemp(tempfilename);
+ if(tempfile == -1) {
+ perror("Error - Could not create temporary file");
exit(1);
}
+
+ if((fp=fdopen(tempfile,"w"))==NULL){
+ perror("Error - Could not open temporary file");
+ unlink(tempfilename);
+ exit(1);
+ }
+
+ /* write the header */
+ if(fwrite("unsigned char option_table[] = {",1,32,fp) != 32) {
+ perror("Error - Could not write image file");
+ fclose(fp);
+ unlink(tempfilename);
+ exit(1);
+ }
+ /* write the array values */
+ for(i=0; i<(int)(ct->size-1); i++) {
+ if(!(i%10) && !err) err=(fwrite("\n\t",1,2,fp) != 2);
+ sprintf(buf,"0x%02x,",cmos_table[i]);
+ if(!err) err=(fwrite(buf,1,5,fp) != 5);
+ }
+ /* write the end */
+ sprintf(buf,"0x%02x\n",cmos_table[i]);
+ if(!err) err=(fwrite(buf,1,4,fp) != 4);
+ if(fwrite("};\n",1,3,fp) != 3) {
+ perror("Error - Could not write image file");
+ fclose(fp);
+ unlink(tempfilename);
+ exit(1);
+ }
+
+ fclose(fp);
+ UNLINK_IF_NECESSARY(option);
+ if (rename(tempfilename, option)) {
+ fprintf(stderr, "Error - Could not write %s: ", option);
+ perror(NULL);
+ unlink(tempfilename);
+ exit(1);
+ }
}
- else { /* no, so use the default option_table.c */
- if((fp=fopen("option_table.c","w"))==NULL){
- fprintf(stderr, "Error - Can not open option_table.c\n");
+
+ /* See if we also want to output a binary file */
+ if(binary) {
+ int err=0;
+ snprintf(tempfilename, TMPFILE_LEN, "%s%s", dirname(strdup(binary)), TMPFILE_TEMPLATE);
+ tempfile = mkstemp(tempfilename);
+ if(tempfile == -1) {
+ perror("Error - Could not create temporary file");
exit(1);
}
- }
- /* write the header */
- if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
- fprintf(stderr, "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)) {
- fprintf(stderr, "Error - Could not write image file\n");
- fclose(fp);
- exit(1);
- }
- fclose(fp);
+ if((fp=fdopen(tempfile,"wb"))==NULL){
+ perror("Error - Could not open temporary file");
+ unlink(tempfilename);
+ exit(1);
+ }
+
+ /* write the array values */
+ if(fwrite(cmos_table, (int)(ct->size-1), 1, fp) != 1) {
+ perror("Error - Could not write image file");
+ fclose(fp);
+ unlink(tempfilename);
+ exit(1);
+ }
+
+ fclose(fp);
+ UNLINK_IF_NECESSARY(binary);
+ if (rename(tempfilename, binary)) {
+ fprintf(stderr, "Error - Could not write %s: ", binary);
+ perror(NULL);
+ unlink(tempfilename);
+ exit(1);
+ }
+ }
/* See if we also want to output a C header file */
if (header) {
struct cmos_option_table *hdr;
struct lb_record *ptr, *end;
- fp = fopen(header, "w");
+
+ snprintf(tempfilename, TMPFILE_LEN, "%s%s", dirname(strdup(header)), TMPFILE_TEMPLATE);
+ tempfile = mkstemp(tempfilename);
+ if(tempfile == -1) {
+ perror("Error - Could not create temporary file");
+ exit(1);
+ }
+
+ fp = fdopen(tempfile, "w");
if (!fp) {
- fprintf(stderr, "Error Can not open %s: %s\n",
- header, strerror(errno));
+ perror("Error - Could not open temporary file");
+ unlink(tempfilename);
exit(1);
}
+
/* Get the cmos table header */
hdr = (struct cmos_option_table *)cmos_table;
/* Walk through the entry records */
ptr = (struct lb_record *)(cmos_table + hdr->header_length);
end = (struct lb_record *)(cmos_table + hdr->size);
+ fprintf(fp, "/* This file is autogenerated.\n"
+ " * See mainboard's cmos.layout file.\n */\n\n"
+ "#ifndef __OPTION_TABLE_H\n#define __OPTION_TABLE_H\n\n");
+
for(;ptr < end; ptr = (struct lb_record *)(((char *)ptr) + ptr->size)) {
if (ptr->tag != LB_TAG_OPTION) {
continue;
}
ce = (struct cmos_entries *)ptr;
- if (ce->config == 'r') {
- continue;
- }
- if (!is_ident(ce->name)) {
+
+ if (!is_ident((char *)ce->name)) {
fprintf(stderr, "Invalid identifier: %s\n",
ce->name);
+ fclose(fp);
+ unlink(tempfilename);
exit(1);
}
fprintf(fp, "#define CMOS_VSTART_%s %d\n",
fprintf(fp, "#define CMOS_VLEN_%s %d\n",
ce->name, ce->length);
}
+
+ if (cs != NULL) {
+ fprintf(fp, "\n#define LB_CKS_RANGE_START %d\n", cs->range_start / 8);
+ fprintf(fp, "#define LB_CKS_RANGE_END %d\n", cs->range_end / 8);
+ fprintf(fp, "#define LB_CKS_LOC %d\n", cs->location / 8);
+ } else {
+ fprintf(stderr, "Error - No checksums defined.\n");
+ fclose(fp);
+ unlink(tempfilename);
+ exit(1);
+ }
+ fprintf(fp, "\n#endif // __OPTION_TABLE_H\n");
fclose(fp);
+
+ UNLINK_IF_NECESSARY(header);
+ if (rename(tempfilename, header)) {
+ fprintf(stderr, "Error - Could not write %s: ", header);
+ perror(NULL);
+ unlink(tempfilename);
+ exit(1);
+ }
}
- return(0);
+
+ return 0;
}