/* * makeflash.c - Generate boot image file for programming a FlashCard * * Copyright (C) 1997-2003 Gero Kuhlmann * * 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 #include #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); }