/*
* makeflash.c - Generate boot image file for programming a FlashCard
*
* Copyright (C) 1997-2003 Gero Kuhlmann <gero@gkminix.han.de>
*
* 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; either version 2 of the License, or
* any later version.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: makeflash.c,v 1.5 2003/03/09 00:43:08 gkminix Exp $
*/
#define NEED_BINARY 1
#include <common.h>
#include <nblib.h>
#include "makerom.h"
#include "makeflash.h"
#include "doconfig.h"
/*
* Variables private to this module
*/
static char *outname; /* Name of output file */
static int outfile; /* File handle for output file */
static int cur_rec_num = -1; /* Number of current load record */
static struct load_header header; /* Load header */
static struct load_record *cur_rec; /* Pointer to current load record */
/*
* Check if the device for a certain network driver is supported
* by the Flash EPROM programmer, except FlashCard. For this we
* scan through the list of interface definitions contained in the
* Flash EPROM programmer binary.
*/
int checkflash(bp)
struct bootdef *bp;
{
__u8 *cp;
int i;
int devtype;
int vendid, devid;
unsigned int textsize;
unsigned int tableofs;
unsigned int ifofs;
unsigned int idofs;
struct istruct *ip;
textsize = roundup(ttoh(getval(*((__u16 *)&(flash_data[0x0002])))), 16);
tableofs = ttoh(getval(*((__u16 *)&(flash_data[0x0006]))));
while ((ifofs = ttoh(getval(*((__u16 *)&(flash_data[tableofs + textsize]))))) != 0) {
ip = (struct istruct *)&(flash_data[ifofs + textsize]);
devtype = ttoh(getval(ip->devtype));
idofs = ttoh(getval(ip->devlist));
if (devtype == IDEVTYPE_PCI &&
bp->bus_type == BUSTYPE_PCI &&
idofs != 0) {
vendid = ttoh(getval(*((__u16 *)&(flash_data[idofs + textsize]))));
idofs += 2;
while ((devid = ttoh(getval(*((__u16 *)&(flash_data[idofs + textsize]))))) != 0) {
if (vendid == bp->pci_vendid && devid == bp->pci_devid)
return(TRUE);
idofs += 2;
}
} else if (devtype == IDEVTYPE_ISA &&
bp->bus_type != BUSTYPE_PCI &&
bp->pnp_devid != NULL &&
idofs != 0) {
cp = &(flash_data[idofs + textsize]);
while (*cp != 0) {
for (i = 0; i < PNPIDLEN; i++)
if (totarget(toupper(bp->pnp_devid[i])) != cp[i])
break;
if (i == PNPIDLEN)
return(TRUE);
cp += PNPIDLEN;
}
}
tableofs += 2;
}
return(FALSE);
}
/*
* Read one sector from the temporary rom image file
*/
static int readsect(buf, romimage)
__u8 *buf;
int romimage;
{
int i;
if ((i = nbread(buf, SECTSIZE, romimage)) == 0)
return(FALSE);
else if (i != SECTSIZE) {
/* The ROM image file has to have a multiple of SECTSIZE bytes */
prnerr0("unexpected end of temporary rom image file");
exit(EXIT_MAKEROM_ROMEOF);
}
return(TRUE);
}
/*
* Write a buffer into the output file and update the load record
*/
static void putrec(recnum, src, size)
int recnum;
__u8 *src;
int size;
{
unsigned long l;
size_t isize;
__u8 *buf;
assert(cur_rec_num == recnum);
isize = ((size / (SECTSIZE + 1)) + 1) * SECTSIZE;
buf = (__u8 *)nbmalloc(isize);
memcpy(buf, src, size);
(void)nbwrite(buf, isize, outfile);
free(buf);
l = get_long(cur_rec->ilength) + isize;
assign(cur_rec->ilength.low, htot(low_word(l)));
assign(cur_rec->ilength.high, htot(high_word(l)));
l = get_long(cur_rec->mlength) + isize;
assign(cur_rec->mlength.low, htot(low_word(l)));
assign(cur_rec->mlength.high, htot(high_word(l)));
}
/*
* Initialize a load record
*/
static void initrec(recnum, segment, flags, vendor_size)
int recnum;
unsigned long segment;
int flags;
int vendor_size;
{
assert(++cur_rec_num == recnum);
if (cur_rec_num > 0)
cur_rec = (struct load_record *)((__u8 *)cur_rec +
((cur_rec->rlength << 2) & 0x3c) +
((cur_rec->rlength >> 2) & 0x3c));
cur_rec->rlength = (((sizeof(struct load_record) -
sizeof(union vendor_data)) >> 2) |
(((vendor_size + 3) & 0x3c) << 2)) & 0xff;
cur_rec->rtag1 = (recnum + VENDOR_OFF) & 0xff;
cur_rec->rflags = flags & 0xff;
assign(cur_rec->address.low, htot(low_word(segment << 4)));
assign(cur_rec->address.high, htot(high_word(segment << 4)));
}
/*
* Process Flash EPROM programmer image
*/
static void do_programmer()
{
unsigned long tsize, dsize, msize;
/*
* Determine the image memory size, which is a word value stored at
* offsets 0x0002 and 0x0004 of the image.
*/
tsize = (int)(flash_data[0x0002] & 0x00FF) +
((int)(flash_data[0x0003] & 0x00FF) << 8);
dsize = (int)(flash_data[0x0004] & 0x00FF) +
((int)(flash_data[0x0005] & 0x00FF) << 8);
msize = roundup(tsize, 16) + dsize + 1;
/*
* Check that the size values are within range. We can use assert()
* here because an error should never happen. The images are stored
* within this program and can never change.
*/
assert(flash_data_size <= PROGRAMLSIZE);
assert(msize <= PROGRAMMSIZE && msize >= flash_data_size);
/*
* Finally copy the image into the output file and set the load record
* according to the sizes determined above.
*/
initrec(PROGRAMNUM, PROGRAMSEG, 0, 0);
putrec(PROGRAMNUM, flash_data, flash_data_size);
assign(cur_rec->mlength.low, htot(low_word(msize)));
assign(cur_rec->mlength.high, htot(high_word(msize)));
}
/*
* Dump the load record information to stderr
*/
static void dump_header(lh)
struct load_header *lh;
{
static char *s_tags[] = { /* PROGRAMNUM */ "flash EPROM programmer",
/* ROMIMAGENUM */ "boot rom image"};
static char *s_flags[]= { "absolute address", "after previous segment",
"at end of memory", "before previos segment"};
struct load_record *lr;
char *vendstr = NULL;
int i, num = 0;
i = (lh->hlength >> 2) & 0x3c;
vendstr = (char *)nbmalloc(i + 2);
while (i > 0) {
i--;
vendstr[i] = lh->dummy[i];
}
printf("\nLoad record information:\n"
" Magic number: 0x%08lX\n"
" Length of header: %d bytes\n"
" Flags: 0x%08lX\n"
" Location address: %04X:%04X\n"
" Execute address: %04X:%04X\n"
" Vendor data: %s\n"
"\n",
get_long(lh->magic),
(lh->hlength << 2) & 0x3c,
(unsigned long)lh->hflags1 +
((unsigned long)lh->hflags2 << 8) +
((unsigned long)lh->hflags3 << 16),
ttoh(getval(lh->locn.segment)), ttoh(getval(lh->locn.offset)),
ttoh(getval(lh->execute.segment)), ttoh(getval(lh->execute.offset)),
vendstr);
i = ((lh->hlength >> 2) & 0x3c) + ((lh->hlength << 2) & 0x3c);
lr = (struct load_record *)&(((__u8 *)lh)[i]);
while (TRUE) {
printf("Record #%d:\n"
" Length of header: %d bytes (standard) + %d bytes (vendor)\n"
" Vendor tag: 0x%02X (%s)\n"
" Reserved flags: 0x%02X\n"
" Flags: 0x%02X (%s%s)\n"
" Load address: 0x%08lX%s\n"
" Image length: 0x%08lX bytes\n"
" Memory length: 0x%08lX bytes\n",
++num,
(lr->rlength << 2) & 0x3c,
(lr->rlength >> 2) & 0x3c,
(int)lr->rtag1,
lr->rtag1 < 16 || lr->rtag1-16 >= NUM_RECORDS ? "unknown" : s_tags[lr->rtag1-16],
(int)lr->rtag2,
(int)lr->rflags, s_flags[lr->rflags & 0x03],
lr->rflags & FLAG_EOF ? ", last record" : "",
get_long(lr->address),
get_long(lr->address) >= 0x100000L &&
(lr->rflags & 0x03) == 0? " (high memory)" : "",
get_long(lr->ilength),
get_long(lr->mlength));
if (lr->rflags & FLAG_EOF)
break;
i = ((lr->rlength >> 2) & 0x3c) + ((lr->rlength << 2) & 0x3c);
lr = (struct load_record *)&(((__u8 *)lr)[i]);
}
free(vendstr);
}
/*
* Routine to generate a boot image file which can program a FlashCard with
* a new boot rom image.
*/
void makeflash(fname, romimage, ldsize)
char *fname;
int romimage;
unsigned long ldsize;
{
__u8 copyrec_buf[SECTSIZE];
int vendor_size;
/* Open the input and output files */
outname = fname;
if ((outfile = open(outname, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
0644)) < 0) {
prnerr1("unable to create %s", outname);
exit(EXIT_CREATE);
}
/* Initialize the boot header */
vendor_size = (strlen(VENDOR_ID) / sizeof(__u32) + 1) * sizeof(__u32);
memset(&header, 0, sizeof(header));
assign(header.magic.low, htot(low_word(HEADER_MAGIC)));
assign(header.magic.high, htot(high_word(HEADER_MAGIC)));
assign(header.locn.segment, htot(HEADERSEG));
assign(header.locn.offset, htot(0));
assign(header.execute.segment, htot(PROGRAMSEG));
assign(header.execute.offset, htot(0));
assign(header.bootsig, htot(BOOT_SIGNATURE));
header.hlength = ((__u8)(((int)(header.dummy - (__u8 *)&header) /
sizeof(__u32))) & 0x0f) |
((__u8)(((vendor_size / sizeof(__u32)) << 4) & 0xf0));
bytecpy(VENDOR_ID, header.dummy, strlen(VENDOR_ID));
(void)nbwrite((__u8 *)&header, sizeof(header), outfile);
/* Initialize pointer to first load record */
cur_rec = (struct load_record *)&(header.dummy[vendor_size]);
/* Process the Flash EPROM programmer record */
do_programmer();
/* Process the boot rom image */
initrec(ROMIMAGENUM, ROMIMAGESEG, FLAG_EOF, sizeof(cur_rec->vendor_data));
assign(cur_rec->vendor_data.ldsize.low, htot(low_word(ldsize)));
assign(cur_rec->vendor_data.ldsize.high, htot(high_word(ldsize)));
assign(cur_rec->mlength.low, htot(low_word(ROMIMAGEMADD)));
assign(cur_rec->mlength.high, htot(high_word(ROMIMAGEMADD)));
while (readsect(copyrec_buf, romimage))
putrec(ROMIMAGENUM, copyrec_buf, SECTSIZE);
if (get_long(cur_rec->mlength) > ROMIMAGEMAX) {
prnerr0("flash rom image size too large");
exit(EXIT_MAKEROM_IMAGESIZE);
}
/* After writing out all this stuff, finally update the boot header */
if (lseek(outfile, 0, 0) != 0) {
prnerr1("unable to seek to beginning of %s", outname);
exit(EXIT_SEEK);
}
(void)nbwrite((__u8 *)&header, sizeof(header), outfile);
close(outfile);
/* If user asked for detailed output, parse the header and output all of */
/* the load record information */
if (verbose > 1)
dump_header(&header);
}
syntax highlighted by Code2HTML, v. 0.9.1