import of upstream version 1.17
[mw/micromonitor-lm32.git] / umon_main / host / src / utils / f2mem.c
1 /* f2mem.c:
2  * This program takes as input a group of files and builds them into
3  * one file that can be burned into embedded system memory.
4  * The first file specified is assumed to be a binary file containing
5  * the embedded system's monitor.  All remaining files are assumed to
6  * be the TFS files that will be seen by the monitor as files in TFS.
7  * 
8  * General notice:
9  * This code is part of a boot-monitor package developed as a generic base
10  * platform for embedded system designs.  As such, it is likely to be
11  * distributed to various projects beyond the control of the original
12  * author.  Please notify the author of any enhancements made or bugs found
13  * so that all may benefit from the changes.  In addition, notification back
14  * to the author will allow the new user to pick up changes that may have
15  * been made by other users after this version of the code was distributed.
16  * 
17  * Author:      Ed Sutter
18  * email:       esutter@lucent.com
19  * phone:       908-582-2351
20  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #ifdef BUILD_WITH_VCC
28 #else
29 #include <unistd.h>
30 #endif
31 #include "version.h"
32 #include "utils.h"
33
34 #ifdef BUILD_WITH_VCC
35 typedef unsigned short ushort;
36 #endif
37
38 #ifndef O_BINARY
39 #define O_BINARY 0
40 #endif
41
42 typedef unsigned char uchar;
43
44 #define TYPE_ASCII              1
45 #define TYPE_BINARY             2
46 #define TYPE_MONITOR    3
47
48 #define MAXFILES                64
49 #define TFSNAMESIZE             23
50 #define TFSHDRSIZ               sizeof(struct tfshdr)
51
52 #define TFS_RESERVED            4
53
54 /* Flags: */
55 #define TFS_EXEC        0x00000001      /* 'e': Executable. */
56 #define TFS_BRUN        0x00000002      /* 'b': To be executed at boot. */
57 #define TFS_QRYBRUN     0x00000004      /* 'B': To be executed at boot if */
58                                                                 /*      query passes. */
59 #define TFS_COFF        0x00000008      /* 'C': COFF absolute. */
60 #define TFS_ELF         0x00000010      /* 'E': ELF absolute. */
61 #define TFS_AOUT        0x00000020      /* 'A': AOUT absolute. */
62 #define TFS_CPRS        0x00000040      /* 'c': File is compressed. */
63 #define TFS_IPMOD       0x00000080      /* 'i': File is in-place modifiable. */
64 #define TFS_UNREAD      0x00000100      /* 'u': File is not even readable if the */
65                                                                 /*              user-level requirement is not met; */
66                                                                 /*              else, it is read-only. */
67 #define TFS_ULVLMSK     0x00000600      /*      User level mask defines 4 access levels: */
68 #define TFS_ULVL0       0x00000000      /* '0'  level 0 */
69 #define TFS_ULVL1       0x00000200      /* '1'  level 1 */
70 #define TFS_ULVL2       0x00000400      /* '2'  level 2 */
71 #define TFS_ULVL3       0x00000600      /* '3'  level 3 */
72 #define TFS_AIPNOT      0x00000800      /* Append not in progress, invisible to user. */
73                                                                 /* When this bit is clear, AIP is in    */
74                                                                 /* progress for the file. */
75                                                                 /* See notes in tfsclose() for this. */
76 #define TFS_ACTIVE      0x00008000      /* Used to indicate that file is not deleted. */
77
78 struct tfsflg {
79         long    flag;
80         char    sdesc;
81 };
82
83 struct tfshdr {
84         unsigned short  hdrsize;                /* Size of this header.                                 */
85         unsigned short  hdrvrsn;                /* Header version #.                                    */
86         long    filsize;                                /* Size of the file.                                    */
87         long    flags;                                  /* Flags describing the file.                   */
88         unsigned long  filcrc;                  /* 32 bit CRC of file.                                  */
89         unsigned long  hdrcrc;                  /* 32 bit CRC of header.                                */
90         unsigned long   modtime;                /* Time when file was last modified.    */
91         struct  tfshdr  *next;                  /* Pointer to next file in list.                */
92         char    name[TFSNAMESIZE+1];    /* Name of file.                                                */
93         char    info[TFSNAMESIZE+1];    /* Miscellaneous info field.                    */
94         unsigned long   rsvd[TFS_RESERVED];
95 };
96
97 struct finfo {
98         char *name;
99         char *filecontent;
100         char *flags;
101         char *info;
102         int     type;
103         int     size;
104 };
105
106 struct tfsflg tfsflgtbl[] = {
107         { TFS_BRUN,                     'b' },
108         { TFS_QRYBRUN,          'B' },
109         { TFS_EXEC,                     'e' },
110         { TFS_AOUT,                     'A' },
111         { TFS_COFF,                     'C' },
112         { TFS_ELF,                      'E' },
113         { TFS_IPMOD,            'i' },
114         { TFS_UNREAD,           'u' },
115         { TFS_ULVL0,            '0' },
116         { TFS_ULVL1,            '1' },
117         { TFS_ULVL2,            '2' },
118         { TFS_ULVL3,            '3' },
119         { TFS_CPRS,                     'c' },
120         { 0, 0 }
121 };
122
123 char *usage_txt[] = {
124         "f2mem (files to memory translator) is a tool that allows the user to",
125         "take a group of files and generate a file that is suitable for a flash",
126         "programmer.  The intent is to feed it a monitor binary followed by a",
127         "list of files that are destined to exist in TFS (Tiny File System).",
128         "The monitor binary is placed at the base of the memory, then, starting",
129         "at the offset specified by -t, each of the remaining files are processed",
130         "and made to look as if they were residing in flash memory under TFS.",
131         "",
132         "Usage: f2mem [options] ",
133         " Options:",
134         " -a tfsname   ascii file for TFS",
135         " -B address   address flash base in CPU memory (default=0)",
136         " -b tfsname   binary file for TFS",
137         " -e           endian swap on portions of TFS struct",
138         " -f hexbyte   byte to be used as filler (default=0xff)",
139         " -m filename  monitor file",
140         " -O 's|b'     output type: S3-record or binary (default=S3)",
141         " -o filename  output file (default = mem.bin | mem.srec)",
142         " -p padto     pad-to size (default is no padding; uses -f hexbyte as pad)",
143         " -s {m|a}     swap bytes in monitor binary (m) or all bytes (a)",
144         " -S address   s-record base address (default=0)",
145         " -t ###       tfs offset",
146         " -T ###       tfs header version (default = 1)",
147         " -V           show version",
148         " -v           verbose",
149         "",
150         " Notes:",
151         "  * The -m and -t options are required.",
152         "  * Syntax for tfsname:  name,flags[,info]",
153         "  * This tool creates an image that could also be created by populating",
154         "    the target with all files, then using TFTP to retrieve the content",
155         "    of that freshly populated memory space.",
156         " Example:",
157         "  * f2mem -v -Ob -mmonppc.bin -amonrc,e -t0x40000 -B0x80000000",
158         "",
159         (char *)0,
160 };
161
162 unsigned long crc32tab[] = {
163         0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
164         0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 
165         0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
166         0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 
167         0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
168         0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 
169         0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
170         0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 
171         0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
172         0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 
173         0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
174         0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 
175         0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
176         0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 
177         0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
178         0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 
179         0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
180         0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 
181         0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
182         0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 
183         0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
184         0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 
185         0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
186         0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 
187         0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
188         0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 
189         0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
190         0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 
191         0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
192         0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 
193         0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
194         0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 
195         0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
196         0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 
197         0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
198         0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 
199         0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
200         0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 
201         0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
202         0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 
203         0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
204         0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 
205         0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
206 };
207
208 struct finfo FileTable[MAXFILES];
209 int     verbose, debug, endianSwap;
210 short TFSHeaderVersion;
211 char *Outfile;
212 unsigned long   SrecBase;
213
214 /* tfsflagsatob():
215    Convert ascii flags to binary and return the long.
216 */
217 static long
218 tfsflagsatob(char *fstr)
219 {
220         long    flag;
221         struct  tfsflg  *tfp;
222
223         if (!fstr)
224                 return(0);
225
226         flag = 0;
227         while(*fstr) {
228                 tfp = tfsflgtbl;
229                 while(tfp->sdesc) {
230                         if (*fstr == tfp->sdesc) {
231                                 flag |= tfp->flag;
232                                 break;
233                         }
234                         tfp++;
235                 }
236                 if (!tfp->flag)
237                         return(-1);
238                 fstr++;
239         }
240         return(flag);
241 }
242
243 /* crc32():
244 */
245 unsigned long
246 crc32(uchar *buffer,unsigned long nbytes)
247 {
248         unsigned long crc_rslt, temp;
249
250         crc_rslt = 0xffffffff;
251         while(nbytes) {
252                 temp = (crc_rslt ^ *buffer++) & 0x000000FFL;
253                 crc_rslt = ((crc_rslt >> 8) & 0x00FFFFFFL) ^ crc32tab[temp];
254                 nbytes--;
255         }
256         return(~crc_rslt);
257 }
258
259 void
260 err(int exitval, char *msg1, char *msg2)
261 {
262         if (!msg2)
263                 msg2 = "";
264         fprintf(stderr,"ERROR: %s %s.\n",msg1,msg2);
265         exit(exitval);
266 }
267
268 /* buildTfsHeader():
269         Build the header into the buffer pointed to by buf.
270         Use the incoming fip pointer to retrieve file information and
271         assume the incoming value of address is the physical location
272         at which the file will be in CPU memory.
273         Return the number of bytes of adjustment made so that the next
274         file is properly aligned.
275 */
276 int
277 buildTfsHeader(unsigned long address, struct finfo *fip, struct tfshdr *tfp)
278 {
279         int     modnext, alignadjust, rsvd;
280         
281         memset((char *)tfp,0,TFSHDRSIZ);
282         strncpy(tfp->name,fip->name,TFSNAMESIZE);
283         if (fip->info)
284                 strncpy(tfp->info,fip->info,TFSNAMESIZE);
285         tfp->name[TFSNAMESIZE] = 0;
286         tfp->info[TFSNAMESIZE] = 0;
287         tfp->hdrsize = otherEnd16(endianSwap,TFSHDRSIZ);
288         tfp->filsize = otherEnd32(endianSwap,fip->size);
289         tfp->flags = tfsflagsatob(fip->flags);
290         if (tfp->flags == -1)
291                 tfp->flags = 0;
292         tfp->flags |= (TFS_ACTIVE | TFS_AIPNOT);
293         if (!(tfp->flags & TFS_IPMOD))
294                 tfp->filcrc = otherEnd32(endianSwap,
295                         crc32((uchar *)fip->filecontent,fip->size));
296         else
297                 tfp->filcrc = 0xffffffff;
298
299         tfp->flags = otherEnd32(endianSwap,tfp->flags);
300         tfp->hdrvrsn = otherEnd16(endianSwap,TFSHeaderVersion);
301         tfp->next = 0;
302         tfp->hdrcrc = 0;
303         tfp->modtime = 0xffffffff;
304         for(rsvd=0;rsvd<TFS_RESERVED;rsvd++)
305                 tfp->rsvd[rsvd] = 0xffffffff;
306         tfp->hdrcrc = otherEnd32(endianSwap,crc32((uchar *)tfp,TFSHDRSIZ));
307
308         /* Put next pointer on mod 16 address... */
309         modnext = address + TFSHDRSIZ + fip->size;
310         if (modnext % 16)
311                 alignadjust = 16 - ((unsigned)modnext % 16);
312         else
313                 alignadjust = 0;
314
315         tfp->next = (struct tfshdr *)(address+TFSHDRSIZ+fip->size+alignadjust);
316         tfp->next = (struct tfshdr *)otherEnd32(endianSwap,
317                 (unsigned long)(tfp->next));
318
319         return(alignadjust);
320 }
321
322 void
323 storeFileinfo(int idx,char *fstring,int type)
324 {
325         char *comma1, *comma2;
326         struct  finfo *fip;
327
328         fip = &FileTable[idx];
329         comma1 = strchr(fstring,',');
330
331         if (!comma1)
332                 err(1,"file name must have flags appended:",fstring);
333         *comma1 = 0;
334         fip->name = fstring;
335         fip->flags = comma1+1;
336         comma2 = strchr(comma1+1,',');
337         if (comma2) {
338                 *comma2 = 0;
339                 fip->info = comma2+1;
340         }
341         else
342                 fip->info = (char *)0;
343         fip->type = type;
344 }
345
346 void
347 buf2bin(uchar *data, int size)
348 {
349         int     fd;
350
351         if (verbose)
352                 fprintf(stderr,"Building binary file...\n");
353
354         fd = open(Outfile,O_WRONLY|O_BINARY|O_CREAT|O_TRUNC,0777);
355         if (fd < 0)
356                 err(1,"Can't open output file:",Outfile);
357
358         if (write(fd,data,size) != size)
359                 err(1,"Can't write file:",Outfile);
360
361         close(fd);
362 }
363
364 void
365 buf2srec(uchar *data, int size)
366 {
367         FILE    *fp;
368         uchar   *cp, *dp;
369         unsigned long   address;
370         int             cnt, csum, i;
371
372         if (verbose)
373                 fprintf(stderr,"Building S-record file...\n");
374         
375         fp = fopen(Outfile,"w+");
376         if (fp == NULL)
377                 err(1,"Can't open output file:",Outfile);
378
379         /* Create Srecord output file: */
380         fprintf(fp,"S0030000FC\n");
381         address = SrecBase;
382         dp = data;
383
384         while(size) {
385                 if (size > 32)
386                         cnt = 32;
387                 else
388                         cnt = size;
389
390                 /* Print S3 idendifier with byte count for line plus
391                    4-byte address: */
392                 fprintf(fp,"S3%02X%08X",cnt+5,address);
393
394                 /* Accumlate checksum subtotal: */
395                 csum = 0;
396                 cp = (uchar *)&address;
397                 csum += (cnt+5);
398                 csum += cp[0]; csum += cp[1]; csum += cp[2]; csum += cp[3];
399
400                 /* Print each byte of data: */
401                 for(i=0;i<cnt;i++) {
402                         fprintf(fp,"%02X",dp[i]);
403                         csum += (int)dp[i];
404                 }
405
406                 /* Print sumcheck (includes bytecount, address & data): */
407                 /* (binary one's compliment) */
408                 fprintf(fp,"%02X\n",255 - (csum & 0xff));
409                 size -= cnt;
410                 dp += cnt;
411                 address += cnt;
412         }
413         fprintf(fp,"S705000019E001\n");
414         fclose(fp);
415 }
416
417 int
418 main(int argc,char *argv[])
419 {
420         unsigned long   tfsoffset, flashbase, padto;
421         struct  stat statbuf;
422         struct  finfo   *fip;
423         int             ftot, totalmem;
424         int             i, opt, ifd, swapmonitor, swapall;
425         uchar   fillbyte;
426         struct  tfshdr  hdrbuf;
427         char    *membase, *memptr, outtype;
428
429         if (argc == 1)
430                 usage(0);
431
432         endianSwap = 1;
433         swapmonitor = swapall = 0;
434         TFSHeaderVersion = 1;
435         SrecBase = 0;
436         verbose = 0;
437         padto = 0;
438         outtype = 's';
439         tfsoffset = 0;
440         flashbase = 0;
441         Outfile = (char *)0;
442         fillbyte = 0xff;
443         for(i=0;i<MAXFILES;i++)
444                 FileTable[0].name = (char *)0;
445         ftot = 1;
446
447         while ((opt=getopt(argc,argv,"a:B:b:ef:m:O:o:p:s:S:t:T:vV")) != EOF) {
448                 switch(opt) {
449                 case 'a':       /* ascii file */
450                         storeFileinfo(ftot++,optarg,TYPE_ASCII);
451                         break;
452                 case 'B':       /* CPU address that base of flash resides at */
453                         flashbase = strtoul(optarg,(char **)0,0);
454                         break;
455                 case 'b':       /* binary file */
456                         storeFileinfo(ftot++,optarg,TYPE_BINARY);
457                         break;
458                 case 'e':       /* disable endian swap */
459                         endianSwap = 0;
460                         break;
461                 case 'f':       /* filler byte */
462                         fillbyte = (uchar)strtoul(optarg,(char **)0,0);
463                         break;
464                 case 'm':       /* monitor file */
465                         /* Slot 0 of the file table is reserved for the monitor. */
466                         if (FileTable[0].name)
467                                 err(1,"only one monitor file should be specified",0);
468                         FileTable[0].name = optarg;
469                         FileTable[0].type = TYPE_MONITOR;
470                         break;
471                 case 'O':       /* output file type */
472                         outtype = *optarg;
473                         if ((outtype != 's') && (outtype != 'b'))
474                                 err(1,"output type must be 's' or 'b'",0);
475                         break;
476                 case 'o':       /* output file */
477                         Outfile = optarg;
478                         break;
479                 case 'p':       /* output file */
480                         padto = strtoul(optarg,(char **)0,0);
481                         break;
482                 case 's':       /* swap binary */
483                         if (*optarg == 'm')
484                                 swapmonitor = 1;
485                         else if (*optarg == 'a')
486                                 swapall = 1;
487                         else {
488                                 fprintf(stderr,"Invalid argument to 's' option\n");
489                                 usage(0);
490                         }
491                         break;
492                 case 'S':       /* S-record base */
493                         SrecBase = strtoul(optarg,(char **)0,0);
494                         break;
495                 case 'T':       /* TFS header version */
496                         TFSHeaderVersion = atoi(optarg);
497                         break;
498                 case 't':       /* TFS offset */
499                         tfsoffset = strtoul(optarg,(char **)0,0);
500                         break;
501                 case 'V':
502                         showVersion();
503                         break;
504                 case 'v':
505                         verbose++;
506                         break;
507                 default:
508                         usage(0);
509                 }
510         }
511
512         if (!FileTable[0].name)
513                 err(1,"monitor file must be specified",0);
514         
515         if (stat(FileTable[0].name,&statbuf) < 0)
516                 err(1,"can't find file:",FileTable[0].name);
517
518         if (statbuf.st_size > tfsoffset) {
519                 fprintf(stderr,"TFS offset = 0x%x, monitor size = 0x%x\n",
520                         tfsoffset,statbuf.st_size);
521                 err(1,"TFS offset must be greater than size of monitor",0);
522         }
523
524         if (swapall & swapmonitor)
525                 err(1,"Can't swap monitor, then swap all... Do one or the other.",0);
526
527         FileTable[0].size = statbuf.st_size;
528
529         /* Now build each of the FileTable entries after the monitor... */
530         /* Determine the size of the file, and copy the entire file into a */
531         /* newly allocated buffer pointed to by filecontent... */
532         /* Also keep track of just how much memory must be allocated to */
533         /* fit the entire image into (store this in totalmem). */
534         totalmem = tfsoffset;
535         fip = &FileTable[1];
536         for(i=1;i<ftot;i++) {
537                 if (stat(fip->name,&statbuf) < 0)
538                         err(1,"can't find file:",fip->name);
539                 totalmem += statbuf.st_size + TFSHDRSIZ;
540                 fip->size = statbuf.st_size;
541                 
542                 if ((ifd = open(fip->name,O_RDONLY | O_BINARY)) < 0)
543                         err(1,"can't open file:",fip->name);
544                 fip->filecontent = malloc(fip->size);
545                 if (!fip->filecontent)
546                         err(1,"can't allocate memory",0);
547
548                 if (read(ifd,fip->filecontent,fip->size) != fip->size)
549                         err(1,"read failed:",fip->name);
550                 close(ifd);
551                 fip++;
552         }
553
554         memptr = membase = malloc(totalmem+1024);
555         if (!memptr)
556                 err(1,"can't allocate memory",0);
557
558         /* Load the memory with the fill byte prior to loading anything else... */
559         memset(membase,fillbyte,totalmem+1024);
560
561         if (verbose > 1)
562                 fprintf(stderr,"TFS header size: %d\n",TFSHDRSIZ);
563
564         /* First transfer the monitor file directly into allocated space... */
565         fip = &FileTable[0];
566         if ((ifd = open(fip->name,O_RDONLY | O_BINARY)) < 0)
567                 err(1,"can't open file:",fip->name);
568
569         if (read(ifd,memptr,fip->size) != fip->size)
570                 err(1,"read failed:",fip->name);
571
572         close(ifd);
573
574         if (swapmonitor) {
575                 char tmp;
576                 i = 0;
577                 while(i < fip->size) {
578                         tmp = membase[i];
579                         membase[i] = membase[i+1];
580                         membase[i+1] = tmp;
581                         i += 2;
582                 }
583         }
584
585         if (verbose) {
586                 fprintf(stderr,"Processing files...\n");
587                 fprintf(stderr," 0: %-20s @ 0x%08x (%d bytes)\n",
588                         fip->name,flashbase,fip->size);
589         }
590
591         /* Now that we have loaded the monitor binary into ram, adjust the              */
592         /* memory pointer to the start of TFS and begin loading each file and   */
593         /* create the TFS header for each... */
594         memptr += tfsoffset;
595         fip = &FileTable[1];
596         for(i=1;i<ftot;i++,fip++) {
597                 int     alignadjust;
598
599                 /* If filetype is TYPE_ASCII, strip out all CRs first... */
600                 if (fip->type == TYPE_ASCII) {
601                         int     j, choppedCRcnt;
602                         char *from, *to;
603
604                         choppedCRcnt = 0;
605                         from = to = fip->filecontent;
606                         for(j=0;j<fip->size;j++,from++) {
607                                 if (*from == 0x0d)
608                                         choppedCRcnt++;
609                                 else
610                                         *to++ = *from;
611                         }
612                         fip->size -= choppedCRcnt;
613                         totalmem -= choppedCRcnt;
614                 }
615
616                 if (verbose)
617                         fprintf(stderr,"%2d: %-20s @ 0x%08x (%d bytes)\n",
618                                 i,fip->name,flashbase+(memptr-membase)+TFSHDRSIZ,fip->size);
619
620                 /* Build the header: */
621                 alignadjust = buildTfsHeader(flashbase+(memptr-membase),fip,&hdrbuf);
622
623                 /* Transfer header to memory: */
624                 memcpy(memptr,(char *)&hdrbuf,TFSHDRSIZ);
625                 memptr += TFSHDRSIZ;
626
627                 /* Copy file content to buffer... */
628                 memcpy(memptr,fip->filecontent,fip->size);
629                 memptr += fip->size;
630                 totalmem += alignadjust;
631                 memptr += alignadjust;
632         }
633
634         /* If padto is non-zero, and it is smaller than the current value of */
635         /* totalmem, then use the fillbyte value to padd the memory out to the */
636         /* size specified by padto... */
637         if (padto) {
638                 char *paddedspace;
639
640                 if (padto > totalmem) {
641                         paddedspace = realloc(membase,padto);
642                         if (!paddedspace)
643                                 fprintf(stderr,"Can't allocate space for padding\n");
644                         else {
645                                 memset(paddedspace+totalmem,fillbyte,padto-totalmem);
646                                 totalmem = padto;
647                                 membase = paddedspace;
648                         }
649                 }
650                 else {
651                         fprintf(stderr,
652                                 "Warning: pad-to value (0x%x) <= total memspace (0x%x)\n", 
653                                 padto,totalmem);
654                 }
655         }
656
657         if (verbose)
658                 fprintf(stderr,"Total flash space required: %d (0x%x) bytes.\n",
659                         totalmem,totalmem);
660         if (verbose > 1) {
661                 unsigned long   gap;
662                 gap = tfsoffset - FileTable[0].size;
663                 fprintf(stderr,
664                         "Gap between end of monitor and TFS: %d (0x%x) bytes.\n",gap,gap);
665         }
666                         
667         if (swapall) {
668                 char tmp;
669                 i = 0;
670                 while(i < totalmem) {
671                         tmp = membase[i];
672                         membase[i] = membase[i+1];
673                         membase[i+1] = tmp;
674                         i += 2;
675                 }
676         }
677
678         /* Now convert buffer to Srecord... */
679         if (outtype == 's') {
680                 if (!Outfile)
681                         Outfile = "mem.srec";
682                 buf2srec((uchar *)membase,totalmem);
683         }
684         else {
685                 if (!Outfile)
686                         Outfile = "mem.bin";
687                 buf2bin((uchar *)membase,totalmem);
688         }
689
690         if (verbose)
691                 fprintf(stderr,"Output saved to file %s.\n",Outfile);
692
693         /* Cleanup... */
694         for(i=1;i<ftot;i++) 
695                 free(FileTable[i].filecontent);
696         
697         free(membase);
698         return(0);
699 }