2010-03-29 19:14:28 +02:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2003-04-22 21:02:15 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2008-11-30 15:52:46 +01:00
|
|
|
#include <unistd.h>
|
2003-04-22 21:02:15 +02:00
|
|
|
#include <ctype.h>
|
2004-03-11 16:01:31 +01:00
|
|
|
#include <errno.h>
|
2008-12-02 13:26:17 +01:00
|
|
|
#include <libgen.h>
|
2003-04-22 21:02:15 +02:00
|
|
|
#include "../../src/include/pc80/mc146818rtc.h"
|
2008-01-18 17:16:45 +01:00
|
|
|
#include "../../src/include/boot/coreboot_tables.h"
|
2003-04-22 21:02:15 +02:00
|
|
|
|
2009-04-22 11:03:08 +02:00
|
|
|
#define CMOS_IMAGE_BUFFER_SIZE 256
|
2003-04-22 21:02:15 +02:00
|
|
|
#define INPUT_LINE_MAX 256
|
|
|
|
#define MAX_VALUE_BYTE_LENGTH 64
|
|
|
|
|
2008-12-02 13:26:17 +01:00
|
|
|
#define TMPFILE_LEN 256
|
|
|
|
#define TMPFILE_TEMPLATE "/build_opt_tbl_XXXXXX"
|
2003-04-22 21:02:15 +02:00
|
|
|
|
|
|
|
static unsigned char cmos_table[4096];
|
|
|
|
|
2009-06-03 16:19:33 +02:00
|
|
|
/* 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};
|
|
|
|
|
2009-11-21 20:54:02 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
#include <fcntl.h>
|
2010-03-29 19:14:28 +02:00
|
|
|
char *mkstemp(char* name)
|
|
|
|
{
|
2009-11-21 20:54:02 +01:00
|
|
|
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
|
2009-06-03 16:19:33 +02:00
|
|
|
|
2010-03-29 19:14:28 +02:00
|
|
|
/**
|
|
|
|
* 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)
|
2003-04-22 21:02:15 +02:00
|
|
|
{
|
2009-06-03 16:19:33 +02:00
|
|
|
int ptr;
|
2003-10-11 08:20:25 +02:00
|
|
|
char *cptr;
|
2009-06-03 16:19:33 +02:00
|
|
|
int buffer_bit_size;
|
|
|
|
int offset;
|
|
|
|
int byte;
|
|
|
|
int byte_length;
|
|
|
|
struct cmos_entries *ce;
|
2003-04-22 21:02:15 +02:00
|
|
|
unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
|
2009-06-03 16:19:33 +02:00
|
|
|
unsigned char set;
|
2003-04-22 21:02:15 +02:00
|
|
|
|
2009-06-03 16:19:33 +02:00
|
|
|
/* 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;
|
2003-10-11 08:20:25 +02:00
|
|
|
|
2009-06-03 16:19:33 +02:00
|
|
|
/* loop through each entry in the table testing for errors */
|
|
|
|
for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
|
|
|
|
ce=(struct cmos_entries *)cptr;
|
2003-04-22 21:02:15 +02:00
|
|
|
/* test if entry goes past the end of the buffer */
|
2010-03-29 19:14:28 +02:00
|
|
|
if((int)(ce->bit+ce->length) > buffer_bit_size) {
|
2009-06-03 16:19:33 +02:00
|
|
|
printf("Error - Entry %s start bit + length must be less than %d\n",
|
|
|
|
ce->name,buffer_bit_size);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2009-06-03 16:19:33 +02:00
|
|
|
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);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2009-06-03 16:19:33 +02:00
|
|
|
/* 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 */
|
2010-03-29 19:14:28 +02:00
|
|
|
if((int)ce->length > (8-offset)) {
|
2009-06-03 16:19:33 +02:00
|
|
|
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 */
|
|
|
|
}
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
2009-06-03 16:19:33 +02:00
|
|
|
return;
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This routine displays the usage options */
|
2010-03-29 19:14:28 +02:00
|
|
|
static void display_usage(char *name)
|
2003-04-22 21:02:15 +02:00
|
|
|
{
|
2008-11-30 15:52:46 +01:00
|
|
|
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("--option = Output a C source file with the definitions.\n");
|
|
|
|
printf("--header = Ouput a C header file with the definitions.\n");
|
|
|
|
exit(1);
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2010-03-29 19:14:28 +02:00
|
|
|
|
2003-04-22 21:02:15 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-06-03 16:19:33 +02:00
|
|
|
static int is_ident_digit(int c)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
switch(c) {
|
|
|
|
case '0': case '1': case '2': case '3':
|
|
|
|
case '4': case '5': case '6': case '7':
|
|
|
|
case '8': case '9':
|
|
|
|
result = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2004-03-11 16:01:31 +01:00
|
|
|
static int is_ident_nondigit(int c)
|
|
|
|
{
|
2009-06-03 16:19:33 +02:00
|
|
|
int result;
|
|
|
|
switch(c) {
|
|
|
|
case 'A': case 'B': case 'C': case 'D':
|
|
|
|
case 'E': case 'F': case 'G': case 'H':
|
|
|
|
case 'I': case 'J': case 'K': case 'L':
|
|
|
|
case 'M': case 'N': case 'O': case 'P':
|
|
|
|
case 'Q': case 'R': case 'S': case 'T':
|
|
|
|
case 'U': case 'V': case 'W': case 'X':
|
|
|
|
case 'Y': case 'Z':
|
|
|
|
case 'a': case 'b': case 'c': case 'd':
|
|
|
|
case 'e': case 'f': case 'g': case 'h':
|
|
|
|
case 'i': case 'j': case 'k': case 'l':
|
|
|
|
case 'm': case 'n': case 'o': case 'p':
|
|
|
|
case 'q': case 'r': case 's': case 't':
|
|
|
|
case 'u': case 'v': case 'w': case 'x':
|
|
|
|
case 'y': case 'z':
|
|
|
|
case '_':
|
|
|
|
result = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
2004-03-11 16:01:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int is_ident(char *str)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
int ch;
|
|
|
|
ch = *str;
|
|
|
|
result = 0;
|
|
|
|
if (is_ident_nondigit(ch)) {
|
|
|
|
do {
|
|
|
|
str++;
|
|
|
|
ch = *str;
|
2009-06-03 16:19:33 +02:00
|
|
|
} while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
|
2004-03-11 16:01:31 +01:00
|
|
|
result = (ch == '\0');
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-03-29 19:14:28 +02:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2003-04-22 21:02:15 +02:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *config=0;
|
|
|
|
char *option=0;
|
2004-03-11 16:01:31 +01:00
|
|
|
char *header=0;
|
2003-04-22 21:02:15 +02:00
|
|
|
FILE *fp;
|
2010-03-29 19:14:28 +02:00
|
|
|
int tempfile;
|
|
|
|
char tempfilename[TMPFILE_LEN];
|
2003-04-22 21:02:15 +02:00
|
|
|
struct cmos_option_table *ct;
|
|
|
|
struct cmos_entries *ce;
|
|
|
|
struct cmos_enums *c_enums, *c_enums_start;
|
2010-03-29 19:14:28 +02:00
|
|
|
struct cmos_checksum *cs, *new_cs;
|
2007-10-24 13:12:15 +02:00
|
|
|
char line[INPUT_LINE_MAX];
|
2003-04-22 21:02:15 +02:00
|
|
|
unsigned char uc;
|
|
|
|
int entry_mode=0;
|
|
|
|
int enum_mode=0;
|
|
|
|
int checksum_mode=0;
|
2003-09-26 11:47:41 +02:00
|
|
|
int cnt;
|
2003-04-22 21:02:15 +02:00
|
|
|
char *cptr;
|
2003-10-11 08:20:25 +02:00
|
|
|
void *entry_start, *entry_end;
|
2003-04-22 21:02:15 +02:00
|
|
|
int entries_length;
|
|
|
|
int enum_length;
|
|
|
|
int len;
|
2007-10-24 13:12:15 +02:00
|
|
|
char buf[16];
|
2003-04-22 21:02:15 +02:00
|
|
|
|
|
|
|
for(i=1;i<argc;i++) {
|
|
|
|
if(argv[i][0]!='-') {
|
2008-11-30 15:52:46 +01:00
|
|
|
display_usage(argv[0]);
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
switch(argv[i][1]) {
|
|
|
|
case '-': /* data is requested from a file */
|
|
|
|
switch(argv[i][2]) {
|
|
|
|
case 'c': /* use a configuration file */
|
|
|
|
if(strcmp(&argv[i][2],"config")) {
|
2008-11-30 15:52:46 +01:00
|
|
|
display_usage(argv[0]);
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
config=argv[++i];
|
|
|
|
break;
|
|
|
|
case 'o': /* use a cmos definitions table file */
|
|
|
|
if(strcmp(&argv[i][2],"option")) {
|
2008-11-30 15:52:46 +01:00
|
|
|
display_usage(argv[0]);
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
option=argv[++i];
|
|
|
|
break;
|
2004-03-11 16:01:31 +01:00
|
|
|
case 'h': /* Output a header file */
|
|
|
|
if (strcmp(&argv[i][2], "header") != 0) {
|
2008-11-30 15:52:46 +01:00
|
|
|
display_usage(argv[0]);
|
2004-03-11 16:01:31 +01:00
|
|
|
}
|
|
|
|
header=argv[++i];
|
|
|
|
break;
|
2003-04-22 21:02:15 +02:00
|
|
|
default:
|
2008-11-30 15:52:46 +01:00
|
|
|
display_usage(argv[0]);
|
2003-04-22 21:02:15 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2004-03-11 16:01:31 +01:00
|
|
|
|
2003-04-22 21:02:15 +02:00
|
|
|
default:
|
2008-11-30 15:52:46 +01:00
|
|
|
display_usage(argv[0]);
|
2003-04-22 21:02:15 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Has the user specified a configuration file */
|
|
|
|
if(config) { /* if yes, open it */
|
|
|
|
if((fp=fopen(config,"r"))==NULL){
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - Can not open config file %s\n",config);
|
2003-04-22 21:02:15 +02:00
|
|
|
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){
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - Can not open cmos.layout\n");
|
2003-04-22 21:02:15 +02:00
|
|
|
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 */
|
2010-03-29 19:14:28 +02:00
|
|
|
// FIXME mode should be a single enum.
|
2003-04-22 21:02:15 +02:00
|
|
|
if(!entry_mode) { /* skip input until the entries key word */
|
|
|
|
if (strstr(line,"entries") != 0) {
|
|
|
|
entry_mode=1;
|
2010-03-29 19:14:28 +02:00
|
|
|
enum_mode=0;
|
|
|
|
checksum_mode=0;
|
2003-04-22 21:02:15 +02:00
|
|
|
continue;
|
|
|
|
}
|
2010-03-29 19:14:28 +02:00
|
|
|
} else { /* Test if we are done with entries and starting enumerations */
|
2003-04-22 21:02:15 +02:00
|
|
|
if (strstr(line,"enumerations") != 0){
|
|
|
|
entry_mode=0;
|
|
|
|
enum_mode=1;
|
2010-03-29 19:14:28 +02:00
|
|
|
checksum_mode=0;
|
2003-04-22 21:02:15 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (strstr(line, "checksums") != 0) {
|
2010-03-29 19:14:28 +02:00
|
|
|
entry_mode=0;
|
2003-04-22 21:02:15 +02:00
|
|
|
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)) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - bit is to big in line \n%s\n",line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
|
|
|
|
exit(1);
|
|
|
|
}
|
2007-10-24 13:12:15 +02:00
|
|
|
if (!is_ident((char *)ce->name)) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr,
|
|
|
|
"Error - Name %s is an invalid identifier in line\n %s\n",
|
|
|
|
ce->name, line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/* put in the record type */
|
|
|
|
ce->tag=LB_TAG_OPTION;
|
|
|
|
/* calculate and save the record length */
|
2007-10-24 13:12:15 +02:00
|
|
|
len=strlen((char *)ce->name)+1;
|
2003-04-22 21:02:15 +02:00
|
|
|
/* make the record int aligned */
|
|
|
|
if(len%4)
|
|
|
|
len+=(4-(len%4));
|
|
|
|
ce->size=sizeof(struct cmos_entries)-32+len;
|
|
|
|
cptr = (char*)ce;
|
2003-10-11 08:20:25 +02:00
|
|
|
cptr += ce->size; /* increment to the next table position */
|
2003-04-22 21:02:15 +02:00
|
|
|
ce = (struct cmos_entries*) cptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* put the length of the entries into the header section */
|
2003-10-11 08:20:25 +02:00
|
|
|
entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
|
2003-04-22 21:02:15 +02:00
|
|
|
|
|
|
|
/* compute the start of the enumerations section */
|
2003-10-11 08:20:25 +02:00
|
|
|
entry_start = ((char*)&cmos_table) + ct->header_length;
|
|
|
|
entry_end = ((char *)entry_start) + entries_length;
|
|
|
|
c_enums_start = c_enums = (struct cmos_enums*)entry_end;
|
2003-04-22 21:02:15 +02:00
|
|
|
/* test for overlaps in the entry records */
|
2003-10-11 08:20:25 +02:00
|
|
|
test_for_entry_overlaps(entry_start, entry_end);
|
2003-04-22 21:02:15 +02:00
|
|
|
|
|
|
|
for(;enum_mode;){ /* loop to build the enumerations section */
|
2010-03-29 19:14:28 +02:00
|
|
|
long ptr;
|
2003-04-22 21:02:15 +02:00
|
|
|
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++);
|
2009-06-03 16:19:33 +02:00
|
|
|
c_enums->value=strtol(&line[ptr],(char**)NULL,10);
|
2003-04-22 21:02:15 +02:00
|
|
|
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 */
|
2003-10-11 08:20:25 +02:00
|
|
|
c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums;
|
2003-04-22 21:02:15 +02:00
|
|
|
/* 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 */
|
2003-10-11 08:20:25 +02:00
|
|
|
enum_length= (char *)c_enums - (char *)c_enums_start;
|
2003-04-22 21:02:15 +02:00
|
|
|
ct->size=ct->header_length+enum_length+entries_length;
|
|
|
|
|
|
|
|
/* Get the checksum records */
|
2010-03-29 19:14:28 +02:00
|
|
|
new_cs = (struct cmos_checksum *)(cmos_table+(ct->size));
|
2003-04-22 21:02:15 +02:00
|
|
|
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;
|
|
|
|
|
2010-03-29 19:14:28 +02:00
|
|
|
/* We actually found a new cmos checksum entry */
|
|
|
|
cs = new_cs;
|
|
|
|
|
2003-04-22 21:02:15 +02:00
|
|
|
/* 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) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - range start is to big in line\n%s\n", line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if ((cs->range_end%8) != 7) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - range end is to long in line\n%s\n", line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if ((cs->location%8) != 0) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
|
|
|
|
((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
|
|
|
|
{
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Error - location is to big in line\n%s\n", line);
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
cs->tag = LB_TAG_OPTION_CHECKSUM;
|
|
|
|
cs->size = sizeof(*cs);
|
|
|
|
cs->type = CHECKSUM_PCBIOS;
|
2010-03-29 19:14:28 +02:00
|
|
|
|
2003-04-22 21:02:15 +02:00
|
|
|
cptr = (char *)cs;
|
|
|
|
cptr += cs->size;
|
2010-03-29 19:14:28 +02:00
|
|
|
new_cs = (struct cmos_checksum *)cptr;
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
ct->size += (cptr - (char *)(cmos_table + ct->size));
|
|
|
|
fclose(fp);
|
|
|
|
|
2008-11-30 15:52:46 +01:00
|
|
|
/* See if we want to output a C source file */
|
2003-04-22 21:02:15 +02:00
|
|
|
if(option) {
|
2009-05-01 00:45:41 +02:00
|
|
|
int err=0;
|
2010-03-29 19:14:28 +02:00
|
|
|
strncpy(tempfilename, dirname(strdup(option)), TMPFILE_LEN);
|
|
|
|
strncat(tempfilename, TMPFILE_TEMPLATE, TMPFILE_LEN);
|
|
|
|
tempfile = mkstemp(tempfilename);
|
|
|
|
if(tempfile == -1) {
|
2008-11-30 15:52:46 +01:00
|
|
|
perror("Error - Could not create temporary file");
|
2003-04-22 21:02:15 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2008-11-30 15:52:46 +01:00
|
|
|
|
2010-03-29 19:14:28 +02:00
|
|
|
if((fp=fdopen(tempfile,"w"))==NULL){
|
2008-11-30 15:52:46 +01:00
|
|
|
perror("Error - Could not open temporary file");
|
2010-03-29 19:14:28 +02:00
|
|
|
unlink(tempfilename);
|
2008-11-30 15:52:46 +01:00
|
|
|
exit(1);
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
|
2008-11-30 15:52:46 +01:00
|
|
|
/* write the header */
|
|
|
|
if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
|
|
|
|
perror("Error - Could not write image file");
|
|
|
|
fclose(fp);
|
2010-03-29 19:14:28 +02:00
|
|
|
unlink(tempfilename);
|
2008-11-30 15:52:46 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/* write the array values */
|
2010-03-29 19:14:28 +02:00
|
|
|
for(i=0; i<(int)(ct->size-1); i++) {
|
I would have liked to get an ack, but the error this corrects is pretty
critical, since unless it is fixed this tool creates empty tables that cause
coreboot to (in some cases, e.g. on qemu) triple fault and die.
For the record, an empty option_table is not allowed. The table must,
at least, have 3 32-bit entries in this order:
type -- should be 200, 0r 0xc8, i.e. 0xc8, 0, 0, 0
size of table in LE order, 4 bytes
size of header in LE order, which is always 12,0,0,0
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4264 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2009-05-09 19:14:58 +02:00
|
|
|
if(!(i%10) && !err) err=!fwrite("\n\t",1,2,fp);
|
2008-11-30 15:52:46 +01:00
|
|
|
sprintf(buf,"0x%02x,",cmos_table[i]);
|
I would have liked to get an ack, but the error this corrects is pretty
critical, since unless it is fixed this tool creates empty tables that cause
coreboot to (in some cases, e.g. on qemu) triple fault and die.
For the record, an empty option_table is not allowed. The table must,
at least, have 3 32-bit entries in this order:
type -- should be 200, 0r 0xc8, i.e. 0xc8, 0, 0, 0
size of table in LE order, 4 bytes
size of header in LE order, which is always 12,0,0,0
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4264 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2009-05-09 19:14:58 +02:00
|
|
|
if(!err) err=!fwrite(buf,1,5,fp);
|
2008-11-30 15:52:46 +01:00
|
|
|
}
|
|
|
|
/* write the end */
|
|
|
|
sprintf(buf,"0x%02x\n",cmos_table[i]);
|
I would have liked to get an ack, but the error this corrects is pretty
critical, since unless it is fixed this tool creates empty tables that cause
coreboot to (in some cases, e.g. on qemu) triple fault and die.
For the record, an empty option_table is not allowed. The table must,
at least, have 3 32-bit entries in this order:
type -- should be 200, 0r 0xc8, i.e. 0xc8, 0, 0, 0
size of table in LE order, 4 bytes
size of header in LE order, which is always 12,0,0,0
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4264 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2009-05-09 19:14:58 +02:00
|
|
|
if(!err) err=!fwrite(buf,1,4,fp);
|
2008-11-30 15:52:46 +01:00
|
|
|
if(!fwrite("};\n",1,3,fp)) {
|
|
|
|
perror("Error - Could not write image file");
|
|
|
|
fclose(fp);
|
2010-03-29 19:14:28 +02:00
|
|
|
unlink(tempfilename);
|
2008-11-30 15:52:46 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
2009-11-21 20:54:02 +01:00
|
|
|
UNLINK_IF_NECESSARY(option);
|
2010-03-29 19:14:28 +02:00
|
|
|
if (rename(tempfilename, option)) {
|
2008-11-30 15:52:46 +01:00
|
|
|
fprintf(stderr, "Error - Could not write %s: ", option);
|
|
|
|
perror(NULL);
|
2010-03-29 19:14:28 +02:00
|
|
|
unlink(tempfilename);
|
2008-11-30 15:52:46 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
2004-03-11 16:01:31 +01:00
|
|
|
|
|
|
|
/* See if we also want to output a C header file */
|
|
|
|
if (header) {
|
|
|
|
struct cmos_option_table *hdr;
|
|
|
|
struct lb_record *ptr, *end;
|
2008-11-30 15:52:46 +01:00
|
|
|
|
2010-04-15 16:55:01 +02:00
|
|
|
strncpy(tempfilename, dirname(strdup(header)), TMPFILE_LEN);
|
2010-03-29 19:14:28 +02:00
|
|
|
strncat(tempfilename, TMPFILE_TEMPLATE, TMPFILE_LEN);
|
|
|
|
tempfile = mkstemp(tempfilename);
|
|
|
|
if(tempfile == -1) {
|
2008-11-30 15:52:46 +01:00
|
|
|
perror("Error - Could not create temporary file");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2010-03-29 19:14:28 +02:00
|
|
|
fp = fdopen(tempfile, "w");
|
2004-03-11 16:01:31 +01:00
|
|
|
if (!fp) {
|
2008-11-30 15:52:46 +01:00
|
|
|
perror("Error - Could not open temporary file");
|
2010-03-29 19:14:28 +02:00
|
|
|
unlink(tempfilename);
|
2004-03-11 16:01:31 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
2008-11-30 15:52:46 +01:00
|
|
|
|
2004-03-11 16:01:31 +01:00
|
|
|
/* 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);
|
|
|
|
for(;ptr < end; ptr = (struct lb_record *)(((char *)ptr) + ptr->size)) {
|
|
|
|
if (ptr->tag != LB_TAG_OPTION) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ce = (struct cmos_entries *)ptr;
|
2009-04-22 11:03:08 +02:00
|
|
|
|
2007-10-24 13:12:15 +02:00
|
|
|
if (!is_ident((char *)ce->name)) {
|
2004-03-11 16:01:31 +01:00
|
|
|
fprintf(stderr, "Invalid identifier: %s\n",
|
|
|
|
ce->name);
|
2008-11-30 15:52:46 +01:00
|
|
|
fclose(fp);
|
2010-03-29 19:14:28 +02:00
|
|
|
unlink(tempfilename);
|
2004-03-11 16:01:31 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
fprintf(fp, "#define CMOS_VSTART_%s %d\n",
|
|
|
|
ce->name, ce->bit);
|
|
|
|
fprintf(fp, "#define CMOS_VLEN_%s %d\n",
|
|
|
|
ce->name, ce->length);
|
|
|
|
}
|
2010-03-30 11:59:23 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2004-03-11 16:01:31 +01:00
|
|
|
fclose(fp);
|
2008-11-30 15:52:46 +01:00
|
|
|
|
2009-11-21 20:54:02 +01:00
|
|
|
UNLINK_IF_NECESSARY(header);
|
2010-03-29 19:14:28 +02:00
|
|
|
if (rename(tempfilename, header)) {
|
2008-11-30 15:52:46 +01:00
|
|
|
fprintf(stderr, "Error - Could not write %s: ", header);
|
|
|
|
perror(NULL);
|
2010-03-29 19:14:28 +02:00
|
|
|
unlink(tempfilename);
|
2008-11-30 15:52:46 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
2004-03-11 16:01:31 +01:00
|
|
|
}
|
2010-03-29 19:14:28 +02:00
|
|
|
|
|
|
|
return 0;
|
2003-04-22 21:02:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|