/* * passes.c - Compress kernel image and concatenate it with a boot loader * * 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: passes.c,v 1.5 2003/03/09 00:43:08 gkminix Exp $ */ #define NEED_TIME 1 #define NEED_BINARY 1 #include #include #include #include "makerom.h" /* * Definitions local to this module */ #define PNPHDROFS ROMPNPPTROFS /* Offset to ptr to PnP expansion hdr */ #define PNPEXPLENOFS 0x0005 /* Offset to length of expansion hdr */ #define PNPEXPCHKSUM 0x0009 /* Offset to PnP header checksum */ #define PNPDEVIDOFS 0x000A /* Offset to PnP device ID */ #define PNPINDICATOR 0x0015 /* Offset to PnP device indicator */ #define PNPDDIM 0x80 /* Bitmask if DDIM is supported */ #define PNPSIG "$PnP" /* Signature of PnP expansion header */ #define PCIHDROFS ROMPCIPTROFS /* Offset to ptr to PCI structure */ #define PCIVENDIDOFS 0x0004 /* Offset to vendor ID */ #define PCIDEVIDOFS 0x0006 /* Offset to device ID */ #define PCIHDRLENOFS 0x000A /* Offset to length of PCI structure */ #define PCIIMGLENOFS 0x0010 /* Offset to image length */ #define PCISIG "PCIR" /* Signature of PCI data structure */ #define ROMSIG 0xAA55 /* ROM signature */ #define ROMVECT18 0x18 /* ROM interrupt vector 18h */ #define ROMVECT19 0x19 /* ROM interrupt vector 19h */ #define KERNROMID "$BC$" /* Kernel ROM ID signature */ #define NETROMID "UNDI" /* Network driver ROM ID signature */ #define NBROMID "netboot" /* Netboot rom ID signature */ #define MINROMSIZE 8192 /* Minimum ROM size */ #define MAXROMSIZE ((FLOPEND - FLOPMEM) * 16L) /* Maximum ROM size */ #define MAXOUTSIZE ((DECOMPEND - DECOMPMEM) * 16L) /* Maximum kern size */ /* * Table of bus type strings */ static char *bustypestr[] = { "ISAR", "EISA", "MCAR", "PCIR", "VESA", "PCCR" }; /* * Convert a hex character into a binary number */ static int gethex(c) char c; { if (isdigit(c)) return(c - '0'); else if (c >= 'a' && c <= 'f') return(c - 'a' + 10); else if (c >= 'A' && c <= 'F') return(c - 'A' + 10); prnerr0("invalid PnP ID string"); exit(EXIT_MAKEROM_INVPNPID); } /* * Set a PnP device ID */ static void setpnpid(buf, cp) __u8 *buf; char *cp; { int i; for (i = 0; i < 3; i++) if (!isalpha(cp[i])) break; if (i != 3 || strlen(cp) != PNPIDLEN) { prnerr1("invalid PnP ID string %s", cp); exit(EXIT_MAKEROM_INVPNPID); } i = ((totarget(toupper(*(cp++))) - 0x40) & 0x1f) << 2; i |= ((totarget(toupper(*cp)) - 0x40) & 0x1f) >> 3; *(buf++) = i & 0x7f; i = ((totarget(toupper(*(cp++))) - 0x40) & 0x1f) << 5; i |= ((totarget(toupper(*(cp++))) - 0x40) & 0x1f); *(buf++) = i & 0xff; i = (gethex(*(cp++)) & 0x0f) << 4; i |= (gethex(*(cp++)) & 0x0f); *(buf++) = i & 0xff; i = (gethex(*(cp++)) & 0x0f) << 4; i |= (gethex(*(cp++)) & 0x0f); *(buf++) = i & 0xff; } /* * Pass 1 - concatenate the kernel image with the network driver */ static unsigned long pass1(bp, tempfile) struct bootdef *bp; int tempfile; { __u8 kernbuf[BLKSIZE]; __u8 netbuf[BLKSIZE]; __u8 firstnetbuf[BLKSIZE]; unsigned long netdrvofs; unsigned long writecnt; unsigned long krnlength; unsigned long netlength; unsigned long romidofs; unsigned long kerntotsize, nettotsize, totsize; unsigned int kernbuflen, netbuflen; unsigned int firstnetbuflen; int kernfile, netfile; int romidlen, romidchksum, i; __u16 *u16p; /* Open the kernel input file */ if ((kernfile = open(bp->kernelname, O_RDONLY | O_BINARY)) < 0) { prnerr1("unable to open kernel file %s", bp->kernelname); exit(EXIT_MAKEROM_OPENKERN); } /* Open the network driver interface input file */ if ((netfile = open(bp->netdrv.name, O_RDONLY | O_BINARY)) < 0) { prnerr1("unable to open network driver interface file %s", bp->netdrv.name); exit(EXIT_MAKEROM_OPENNET); } /* * Read the first kernel block and determine the actual size of the rom kernel * without the BSS segment. Also check the version number. */ kernbuflen = BLKSIZE; if (nbread(kernbuf, kernbuflen, kernfile) != kernbuflen) { prnerr1("unexpected end of file %s", bp->kernelname); exit(EXIT_MAKEROM_READKERN); } if (kernbuf[KRNMAJOROFS] != (__u8)VER_MAJOR || kernbuf[KRNMINOROFS] != (__u8)VER_MINOR) { prnerr0("invalid kernel version number"); exit(EXIT_MAKEROM_INVKERN); } krnlength = (ttoh(getval(*((__u16 *)(&kernbuf[KRNTEXTOFS])))) + 15L) & 0xfff0L; krnlength += ttoh(getval(*((__u16 *)(&kernbuf[KRNDATAOFS])))); /* * Check that the kernel ROM ID structure is correct, determine it's * checksum and get the total memory size required for the kernel. */ romidofs = ttoh(getval(*((__u16 *)(&kernbuf[KRNROMIDOFS])))); if (romidofs + ROMID_LENGTH > kernbuflen) romidlen = kernbuflen; else romidlen = kernbuf[romidofs + ROMID_LENGTH] & 0xff; if (romidlen < ROMID_MIN_SIZE || romidofs + romidlen > kernbuflen) { prnerr0("invalid ROM ID structure in kernel file"); exit(EXIT_MAKEROM_INVKERN); } if (!bytecmp(KERNROMID, &kernbuf[romidofs + ROMID_SIG], strlen(KERNROMID))) { prnerr1("file %s is not a netboot kernel", bp->kernelname); exit(EXIT_MAKEROM_INVKERN); } romidchksum = 0; for (i = 0; i < romidlen; i++) romidchksum += kernbuf[romidofs + i] & 0xff; kernbuf[romidofs + ROMID_CHKSUM] = (__u8)((0 - romidchksum) & 0xff); kerntotsize = (ttoh(getval(*((__u16 *)(&kernbuf[romidofs + ROMID_STKSIZE])))) + 15L) & 0xfff0L; kerntotsize += (ttoh(getval(*((__u16 *)(&kernbuf[romidofs + ROMID_DATASIZE])))) + 15L) & 0xfff0L; kerntotsize += (ttoh(getval(*((__u16 *)(&kernbuf[romidofs + ROMID_CODESIZE])))) + 15L) & 0xfff0L; kerntotsize /= 16L; /* Set the total number of kernel paragraphs into kernel image */ u16p = (__u16 *)(&kernbuf[KRNSIZEOFS]); assign(*u16p, htot(kerntotsize & 0xffff)); /* * Read the first network driver interface block and determine the * actual size of the interface without the BSS segment. Also check * the version number. */ netbuflen = BLKSIZE; if (nbread(netbuf, netbuflen, netfile) != netbuflen) { prnerr1("unexpected end of file %s", bp->netdrv.name); exit(EXIT_MAKEROM_READNET); } if (netbuf[NETMAJOROFS] != (__u8)VER_MAJOR || netbuf[NETMINOROFS] != (__u8)VER_MINOR) { prnerr0("invalid network driver interface version number"); exit(EXIT_MAKEROM_INVDRV); } netlength = (ttoh(getval(*((__u16 *)(&netbuf[NETTEXTOFS])))) + 15L) & 0xfff0L; netlength += ttoh(getval(*((__u16 *)(&netbuf[NETDATAOFS])))); /* * Check that the network driver ROM ID structure is correct and determine * it's checksum. The total number of paragraphs required for the network * driver can only be determined after all drivers have been written. We * also setup the bus type string in the ROM ID structure. */ romidofs = ttoh(getval(*((__u16 *)(&netbuf[NETROMIDOFS])))); if (romidofs + ROMID_LENGTH > netbuflen) romidlen = netbuflen; else romidlen = netbuf[romidofs + ROMID_LENGTH] & 0xff; if (romidlen < ROMID_MIN_SIZE || romidofs + romidlen > netbuflen) { prnerr0("invalid ROM ID structure in network driver interface file"); exit(EXIT_MAKEROM_INVDRV); } if (!bytecmp(NETROMID, &netbuf[romidofs + ROMID_SIG], strlen(NETROMID))) { prnerr1("file %s is not a network driver interface", bp->netdrv.name); exit(EXIT_MAKEROM_INVDRV); } bytecpy(bustypestr[bp->bus_type - 1], &netbuf[romidofs + ROMID_BUSTYPE], BUSTYPE_SIZE); romidchksum = 0; for (i = 0; i < romidlen; i++) romidchksum += netbuf[romidofs + i] & 0xff; netbuf[romidofs + ROMID_CHKSUM] = (__u8)((0 - romidchksum) & 0xff); nettotsize = (ttoh(getval(*((__u16 *)(&netbuf[romidofs + ROMID_STKSIZE])))) + 15L) & 0xfff0L; nettotsize += (ttoh(getval(*((__u16 *)(&netbuf[romidofs + ROMID_DATASIZE])))) + 15L) & 0xfff0L; nettotsize += (ttoh(getval(*((__u16 *)(&netbuf[romidofs + ROMID_CODESIZE])))) + 15L) & 0xfff0L; nettotsize /= 16L; /* Set the bus type into network driver image */ netbuf[NETBUSTYPEOFS] = (__u8)((bp->bus_type - 1) & 0xff); /* * Now copy the kernel image file into the output file. Only copy the * relevant bytes excluding the BSS segment, which has only zero bytes * anyway. */ writecnt = 0L; krnlength -= kernbuflen; while (TRUE) { writecnt += nbwrite(kernbuf, kernbuflen, tempfile); if (krnlength <= 0) break; kernbuflen = nbread(kernbuf, BLKSIZE, kernfile); if (kernbuflen == 0) { prnerr0("unexpected end of kernel image file"); exit(EXIT_MAKEROM_KERNEOF); } if (kernbuflen > krnlength) kernbuflen = krnlength; krnlength -= kernbuflen; } close(kernfile); if (verbose > 2) printf("End position of kernel: %lu\n", writecnt); /* * Copy the first network driver interface buffer into a temporary * space so that we can restore it after we know the total network * driver size. */ memcpy(firstnetbuf, netbuf, sizeof(netbuf)); firstnetbuflen = netbuflen; netdrvofs = writecnt; /* * Next copy the network driver interface file into the output file in the * same way as the kernel image has been copied. */ netlength -= netbuflen; while (TRUE) { writecnt += nbwrite(netbuf, netbuflen, tempfile); if (netlength <= 0) break; netbuflen = nbread(netbuf, BLKSIZE, netfile); if (netbuflen == 0) { prnerr0("unexpected end of network interface file"); exit(EXIT_MAKEROM_DRVEOF); } if (netbuflen > netlength) netbuflen = netlength; netlength -= netbuflen; } close(netfile); if (verbose > 2) printf("End position of interface file: %lu\n", writecnt); /* * Postprocess the network driver. This usually means to copy the * driver (like the packet driver) into the output file. */ writecnt += donetdrv(&(bp->netdrv), &nettotsize, tempfile); if (verbose > 2) { printf("End position of bootrom image: %lu\n", writecnt); printf("Paragraphs for network driver: %lu (0x%lX)\n", nettotsize, nettotsize); } /* Check that the output file size is not too large */ if (writecnt > MAXOUTSIZE) { prnerr1("size of output file exceeds %lu kB", MAXOUTSIZE / 1024L); exit(EXIT_MAKEROM_SIZE); } /* * Compute the total size required for the bootrom and check that it * doesn't exceed a limit. */ totsize = kerntotsize + nettotsize; if (totsize > (MEMEND - OSENDMEM)) { prnerr1("size of bootrom run image exceeds %lu kB", (MEMEND - OSENDMEM) / (1024L / 16L)); exit(EXIT_MAKEROM_SIZE); } /* * Set the total network driver size into the first network driver * interface buffer and rewrite it into the output file. */ u16p = (__u16 *)(&firstnetbuf[NETSIZEOFS]); assign(*u16p, htot(nettotsize & 0xffff)); if (lseek(tempfile, netdrvofs, 0) < 0) { prnerr0("unable to seek output file"); exit(EXIT_SEEK); } (void)nbwrite(firstnetbuf, firstnetbuflen, tempfile); /* Rewind to beginning of output file for the following pass 2 */ if (lseek(tempfile, 0L, 0) < 0) { prnerr0("unable to seek to beginning of output file"); exit(EXIT_SEEK); } if (verbose > 2) printf("\n\n"); return(totsize); } /* * Pass 2 - compress kernel image and concatenate it with the loader */ static void pass2(bp, totsize, kernfile, loader) struct bootdef *bp; unsigned long totsize; int kernfile; int loader; { struct loaderdef *lp = &(bp->loaders[loader]); __u8 inbuf[BLKSIZE]; /* Input file buffer */ __u8 firstbuf[BLKSIZE]; /* Buffer for first sector of ROM */ unsigned long firstofs; /* Offset to first ROM sector */ unsigned long writecnt; /* number of bytes in output file */ unsigned int len, firstlen; unsigned long ldsize; /* Size of rom image loader */ unsigned long pci_ofs; /* Offset to PCI header */ unsigned long pnp_ofs; /* Offset to PnP header */ unsigned long serno; /* Rom serial number */ unsigned long romvector; /* Rom interrupt vector */ unsigned long romsize; /* Physical size of ROM */ unsigned long romlength; /* Size of bootrom kernel image */ unsigned char romsizchar; int i, dorom, bootflags; int infile, outfile; char *tmpfname; __u16 *u16p; /* * Check for the ROM signature to determine whether we are going to build * a ROM or a floppy image. */ if ((infile = open(lp->name, O_RDONLY | O_BINARY)) < 0) { prnerr1("unable to open loader file %s", lp->name); exit(EXIT_MAKEROM_OPENLDR); } len = nbread(inbuf, BLKSIZE, infile); dorom = (ttoh(getval(*((__u16 *)(&inbuf[0])))) == ROMSIG); if (!dorom && (lp->outtype == OUT_FLASH || lp->outtype == OUT_FC)) { /* Don't produce a flash header for floppy images */ prnerr0("unable to produce floppy image with flash header"); exit(EXIT_MAKEROM_INVLDR); } /* * Open the output file. If we have to produce anything different than raw * binary we have to initially use a temporary file. */ if (lp->outtype != OUT_BINARY) { if ((tmpfname = tempnam(NULL, "mkrom")) == NULL) { prnerr0("unable to generate temporary file name"); exit(EXIT_TEMPNAME); } if ((outfile = open(tmpfname, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0644)) < 0) { prnerr1("unable to open temporary file %s", tmpfname); exit(EXIT_CREATE); } if (verbose < 2) unlink(tmpfname); } else { if ((outfile = open(lp->outname, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0644)) < 0) { prnerr1("unable to open output file %s", lp->outname); exit(EXIT_CREATE); } } /* * Now copy the specified bootrom loader into the output file. If * it's a floppy loader, save the first sector of the loader, and * read the next sector which is then the first ROM sector. Also * set the offset to that first ROM sector within the output file * to later allow rewriting it. */ firstofs = 0L; if (!dorom) { if (len != BLKSIZE) { prnerr1("unexpected end of loader image %s", lp->name); exit(EXIT_MAKEROM_INVLDR); } (void)nbwrite(inbuf, len, outfile); firstofs = BLKSIZE; len = nbread(inbuf, BLKSIZE, infile); } /* Check for correct version */ if (inbuf[ROMMAJOROFS] != (__u8)VER_MAJOR || inbuf[ROMMINOROFS] != (__u8)VER_MINOR) { prnerr0("invalid loader version number"); exit(EXIT_MAKEROM_INVLDR); } /* Check that we really have a netboot loader */ if (!bytecmp(NBROMID, &inbuf[ROMIDOFS], strlen(NBROMID))) { prnerr1("file %s is not a netboot loader image", lp->name); exit(EXIT_MAKEROM_INVLDR); } /* Compute the serial number from the version number and the current time */ serno = (unsigned long)((time(NULL) + (VER_MAJOR * 100 + VER_MINOR)) & 0x7fffffffL); u16p = (__u16 *)(&inbuf[ROMSEROFS + 0]); assign(*u16p, htot(serno & 0xffff)); u16p = (__u16 *)(&inbuf[ROMSEROFS + 2]); assign(*u16p, htot((serno >> 16) & 0xffff)); /* Compute the ROM interrupt vector - always int 18h for floppy loader */ romvector = ((dorom ? (lp->useint18 ? ROMVECT18 : ROMVECT19) : ROMVECT18) * 4) & 0xffff; u16p = (__u16 *)(&inbuf[ROMVECTOFS]); assign(*u16p, htot(romvector & 0xffff)); /* Set the bootrom flags */ bootflags = 0; if (lp->bootask) { bootflags |= ROMFLG_ASKNET; if (lp->asktime > 0) { if (lp->asktime < 2) bootflags|= 0x02 & ROMFLG_ASKTIME; else /* The time is set in 2 second intervalls */ bootflags|= ((lp->asktime / 2) << 1) & ROMFLG_ASKTIME; } } inbuf[ROMBOOTFLGOFS] = (__u8)(bootflags & 0xff); /* Write total number of paragraphs required for the bootrom */ u16p = (__u16 *)(&inbuf[ROMTOTSIZEOFS]); assign(*u16p, htot(totsize & 0xffff)); /* Determine offset to PCI data structure and set vendor/device ID */ pci_ofs = ttoh(getval(*((__u16 *)(&inbuf[PCIHDROFS])))); if (pci_ofs) { unsigned long pci_len; pci_len = ttoh(getval(*((__u16 *)(&inbuf[pci_ofs + PCIHDRLENOFS])))); if (pci_ofs + pci_len > len || !bytecmp(PCISIG, &inbuf[pci_ofs], strlen(PCISIG))) { prnerr0("invalid PCI header"); exit(EXIT_MAKEROM_INVLDR); } if (bp->bus_type == BUSTYPE_PCI) { u16p = (__u16 *)(&inbuf[pci_ofs + PCIVENDIDOFS]); assign(*u16p, htot(bp->pci_vendid & 0xffff)); u16p = (__u16 *)(&inbuf[pci_ofs + PCIDEVIDOFS]); assign(*u16p, htot(bp->pci_devid & 0xffff)); } } /* If we don't have a PCI card, set offset to PCI structure to zero */ if (!lp->cardinst || bp->bus_type != BUSTYPE_PCI) { inbuf[PCIHDROFS + 0] = (__u8)0; inbuf[PCIHDROFS + 1] = (__u8)0; } /* Compute the PnP expansion header checksum */ pnp_ofs = ttoh(getval(*((__u16 *)(&inbuf[PNPHDROFS])))); if (pnp_ofs) { int pnp_chksum = 0; unsigned long pnp_len; /* Check if PnP header is correct */ pnp_len = ttoh(getval(*((__u16 *) (&inbuf[pnp_ofs + PNPEXPLENOFS])))) * 16; if (pnp_ofs + pnp_len > len || !bytecmp(PNPSIG, &inbuf[pnp_ofs], strlen(PNPSIG))) { prnerr0("invalid PnP header"); exit(EXIT_MAKEROM_INVLDR); } /* Generate PnP vendor and device ID */ if (bp->bus_type != BUSTYPE_PCI && bp->pnp_devid != NULL) setpnpid(&inbuf[pnp_ofs + PNPDEVIDOFS], bp->pnp_devid); /* Compute new checksum of PnP header */ for (i = 0; i < pnp_len; i++) { pnp_chksum += inbuf[pnp_ofs + i]; pnp_chksum &= 0xff; } inbuf[pnp_ofs + PNPEXPCHKSUM] = (__u8)((0 - pnp_chksum) & 0xff); } /* Save the first ROM loader sector for later reference. */ memcpy(firstbuf, inbuf, sizeof(inbuf)); firstlen = len; /* Always have to set the checksum to zero before writing the ROM code */ write_chksum = 0; /* Write the loader image into the output file */ writecnt = 0; while (TRUE) { writecnt += nbwrite(inbuf, len, outfile); if ((len = nbread(inbuf, BLKSIZE, infile)) == 0) break; } close(infile); /* The kernel image has to start at a paragraph boundary */ if ((writecnt & 0x0f) != 0) { memset(inbuf, 0, 16); writecnt += nbwrite(inbuf, 16 - (writecnt & 0x0f), outfile); } ldsize = writecnt; /* Next copy the kernel image into the output file */ romlength = freeze(kernfile, outfile); writecnt += romlength; if (writecnt > MAXROMSIZE) { prnerr1("bootrom code cannot exceed %lu kB", MAXROMSIZE / 1024L); exit(EXIT_MAKEROM_SIZE); } /* * If we got a real ROM here, determine the next available ROM size and * fill the output file up to that amount with FF bytes. The last byte * has to remain for the checksum. Then update the size of the physical * ROM at the beginning of the output file, and write the size of the * bootrom kernel image. */ /* Determine required ROM size. */ if (lp->outsize) { unsigned long ul = (unsigned long)(lp->outsize) * 1024L; if (ul < writecnt + 3 || ul > MAXROMSIZE) { prnerr1("invalid ROM output size %d kb given", lp->outsize); exit(EXIT_MAKEROM_SIZE); } romsize = ul; } else for (romsize = MINROMSIZE; romsize < writecnt + 3; ) romsize <<= 1; /* Compute the missing size values and the final checksum */ romsizchar = (romsize >> 9) & 0xff; /* Divide by 512 */ write_chksum += romsizchar; if (pci_ofs) write_chksum += romsizchar; for (i = 0; i < 4; i++) write_chksum += (romlength >> (8 * i)) & 0xff; /* * Copy 0xFF byte buffer and checksum to output file (only for real ROM). * For some network cards (notably 3Com), the last two bytes of the ROM * code have to be 0x80. */ if (dorom) { memset(inbuf, 0xff, sizeof(inbuf)); while (TRUE) { /* Check if this is the last block */ if (romsize - writecnt <= BLKSIZE + 3) { len = (int)(romsize - writecnt); assert(len >= 3); writecnt += nbwrite(inbuf, len - 3, outfile); write_chksum += 0x80 * 2; inbuf[0] = (__u8)((0 - (write_chksum & 0xff)) & 0xff); inbuf[1] = 0x80; inbuf[2] = 0x80; writecnt += nbwrite(inbuf, 3, outfile); break; } writecnt += nbwrite((unsigned char *)inbuf, BLKSIZE, outfile); } } /* Put the physical ROM length into the output file */ firstbuf[ROMLENOFS] = (__u8)romsizchar; /* Put the image length into the PCI data structure */ if (pci_ofs) firstbuf[pci_ofs + PCIIMGLENOFS] = (__u8)romsizchar; /* Put the length of the compressed kernel image into the output file */ u16p = (__u16 *)(&firstbuf[ROMCOMPSIZEOFS + 0]); assign(*u16p, htot(romlength & 0xffff)); u16p = (__u16 *)(&firstbuf[ROMCOMPSIZEOFS + 2]); assign(*u16p, htot((romlength >> 16) & 0xffff)); /* Finally rewrite the first sector of the loader */ if (lseek(outfile, firstofs, 0) < 0) { prnerr1("unable to seek %s", lp->outname); exit(EXIT_SEEK); } (void)nbwrite(firstbuf, firstlen, outfile); /* Rewind to beginning of kernel file for another pass 2 */ if (lseek(kernfile, 0L, 0) < 0) { prnerr0("unable to seek to beginning of kernel file"); exit(EXIT_SEEK); } /* Generate the final output file format */ if (lp->outtype != OUT_BINARY) { if (lseek(outfile, 0L, 0) < 0) { prnerr0("unable to seek to beginning of temporary file"); exit(EXIT_SEEK); } if (lp->outtype == OUT_FLASH || lp->outtype == OUT_FC) makeflash(lp->outname, outfile, ldsize); else makehex(lp->outname, outfile, lp->outtype); } close(outfile); } /* * Generate bootrom output files by successively calling both passes */ void dopasses(bp) struct bootdef *bp; { char *tmpfname; unsigned long totsize; int i, tmpfile; if ((tmpfname = tempnam(NULL, "mkrom")) == NULL) { prnerr0("unable to generate temporary file name"); exit(EXIT_TEMPNAME); } if ((tmpfile = open(tmpfname, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0644)) < 0) { prnerr1("unable to open temporary file %s", tmpfname); exit(EXIT_CREATE); } if (verbose < 2) unlink(tmpfname); totsize = pass1(bp, tmpfile); for (i = 0; i < bp->loadernum; i++) pass2(bp, totsize, tmpfile, i); close(tmpfile); }