/*
* passes.c - Compress kernel image and concatenate it with a boot loader
*
* 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: passes.c,v 1.5 2003/03/09 00:43:08 gkminix Exp $
*/
#define NEED_TIME 1
#define NEED_BINARY 1
#include <common.h>
#include <nblib.h>
#include <memory.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1