Magellan Linux

Annotation of /trunk/linterm_tools/fw_builder/bundle-tools/fwpack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 658 - (hide annotations) (download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 4 months ago) by niro
File MIME type: text/plain
File size: 9591 byte(s)
initial import

1 niro 658 /*
2     A small tool to generate Wyse WinTerm firmware upgrade/add-on images
3     Copyright (C) 2005 Wilmer van der Gaast <wilmer@gaast.net>
4    
5     This program is free software; you can redistribute it and/or
6     modify it under the terms of the second version of the GNU
7     General Public License as published by the Free Software
8     Foundation.
9    
10     !!! GPL EXCEPTION: Since this program includes bits of data from original
11     WYSE images during the compilation progress, you're NOT allowed to
12     distribute binaries! Distribute this program ONLY IN SOURCE FORM !!!
13    
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     GNU General Public License for more details.
18    
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22     */
23    
24     #include <stdio.h>
25     #include <stdlib.h>
26     #include <sys/types.h>
27     #include <sys/stat.h>
28     #include <fcntl.h>
29     #include <unistd.h>
30     #include <string.h>
31     #include <errno.h>
32    
33     #include "fwstruct.h"
34     #include "fwhead.h"
35    
36     #ifndef BYTE_ORDER
37     #error "Couldn't determine byte order"
38     #endif
39    
40     #define BUFSIZE 512
41    
42     struct fwfile
43     {
44     int fd;
45     u_int32_t cs;
46     u_int8_t cslen;
47     union
48     {
49     u_int8_t byte[4];
50     u_int32_t val;
51     } csbuf;
52     };
53    
54     struct fwfile *fwstart( char *fn );
55     int fwwrite( struct fwfile *fw, void *data, int size );
56     int fwpad( struct fwfile *fw, int align );
57     u_int32_t fwcs( struct fwfile *fw );
58     void fwclose( struct fwfile *fw );
59    
60     int pad( off_t offset, int align );
61     char *basename( char *fn );
62     void verify_offset( int fd, off_t expect );
63    
64     int main( int argc, char *argv[] )
65     {
66     struct index *idx = NULL, *idxstart = NULL;
67     struct fwfile *fw = NULL;
68     u_int32_t int32;
69     off_t cur;
70     int fd, i;
71    
72     printf( "fwpack - Generate WYSE Winterm firmware bundles\n\n" );
73    
74     structcheck();
75    
76     if( argc < 3 )
77     {
78     fprintf( stderr, "Syntax: %s <image> <bios> [<other files> <...>]\n"
79     "\n"
80     "First argument is the destination file. After that, specify the files to put\n"
81     "into the image. The first file will be used as the BIOS file, after that you\n"
82     "can put other files you want to be in the image. The original firmware files\n"
83     "have some flags that this tool won't create, so this tool is probably not\n"
84     "suitable to create original WinCE firmware (or add-on) images. It's mainly\n"
85     "meant to create Linux images.\n"
86     "\n"
87     "Also, a file named k will automatically be used for the hardware magic section\n"
88     "in the headers.\n"
89     "\n"
90     "Don't forget to read the documentation before using this tool!\n", argv[0] );
91     return( 1 );
92     }
93    
94     if( strlen( basename( argv[2] ) ) > 8 )
95     {
96     fprintf( stderr, "BIOS filename too long!\n" );
97     return( 1 );
98     }
99    
100     printf( "Checking all files and building index" );
101     fflush( stdout );
102     cur = 0x59;
103     for( i = 2; i < argc; i ++ )
104     {
105     struct fwfile *cscalc;
106     char rdbuf[BUFSIZE];
107     struct stat fs;
108     int n;
109    
110     fd = open( argv[i], O_RDONLY );
111     if( fd < 0 )
112     {
113     perror( "open" );
114     return( 1 );
115     }
116     if( fstat( fd, &fs ) != 0 )
117     {
118     perror( "fstat" );
119     return( 1 );
120     }
121    
122     if( idx == NULL )
123     {
124     idx = idxstart = calloc( sizeof( struct index ), 1 );
125     }
126     else
127     {
128     idx->next = calloc( sizeof( struct index ), 1 );
129     idx = idx->next;
130     }
131     idx->idx_offset = cur;
132     idx->realfile = argv[i];
133    
134     /* Add one byte so the filename will be ASCIIZ. */
135     idx->h = calloc( 1, 1 + sizeof( struct header ) + strlen( basename( argv[i] ) ) );
136     idx->h->fnlen = strlen( basename( argv[i] ) );
137     idx->h->hsize = idx->h->fnlen + sizeof( struct header );
138     memcpy( idx->h->fn, basename( argv[i] ), idx->h->fnlen );
139    
140     /* BIOS gets a special flag. */
141     if( i == 2 )
142     idx->h->bios_flag = 0x10000;
143     else
144     idx->h->bios_flag = 0x20000;
145    
146     /* This flag is always 1 for system files, 5 for addon files. We have only system files. */
147     idx->h->sys_flag[0] = 1;
148    
149     /* No idea what this is for, just typing something. :-) */
150     idx->h->time = fs.st_mtime;
151    
152     /* This is a bit of a hack, but isn't that exactly what we're doing anyway? :-) */
153     cscalc = fwstart( "/dev/null" );
154     while( ( n = read( fd, rdbuf, BUFSIZE ) ) > 0 )
155     {
156     fwwrite( cscalc, rdbuf, n );
157     idx->h->fsize += n;
158     }
159     idx->h->checksum = fwcs( cscalc );
160     fwclose( cscalc );
161    
162     if( i == 2 && idx->h->fsize != 0x40000 )
163     printf( "\nWARNING: BIOS file isn't %d bytes long!\n", 0x40000 );
164    
165     /* See if this is a hardware magic code? */
166     if( ( strcmp( idx->h->fn, "k" ) == 0 ) && idx->h->fsize == 20 )
167     {
168     lseek( fd, 0, SEEK_SET );
169     if( read( fd, fhead + 0x3f, 20 ) != 20 )
170     {
171     perror( "read" );
172     return( 1 );
173     }
174     }
175    
176     cur += idx->h->hsize;
177     close( fd );
178    
179     printf( "." );
180     fflush( stdout );
181     }
182     printf( " Done!\n" );
183    
184     printf( "Building for machine type: %02x %02x %02x %02x\n",
185     fhead[0x3f], fhead[0x40], fhead[0x41], fhead[0x42] );
186    
187     /* Make sure there are at least two 0-bytes to end the index */
188     if( pad( cur, 4 ) < 2 )
189     {
190     cur += 2;
191     }
192     cur += pad( cur, 4 );
193    
194     printf( "Calculating file offsets...\n" );
195     for( idx = idxstart; idx; idx = idx->next )
196     {
197     idx->h->offset = cur;
198     cur += idx->h->fsize;
199     cur += pad( cur, 4 );
200     }
201    
202     /* Add four bytes for the checksum. */
203     cur += 4;
204     printf( "Expected image size: %d\n", (int) cur );
205    
206     printf( "Now creating image headers and index... " );
207     fflush( stdout );
208     fw = fwstart( argv[1] );
209     if( fw == NULL )
210     {
211     perror( "fwstart" );
212     return( 1 );
213     }
214    
215     /* Put the name of the BIOS image in the header. */
216     strncpy( fhead + 0x37, basename( argv[2] ), 8 );
217    
218     /* The image size. */
219     int32 = cvt32( cur );
220     memcpy( fhead + 0x13, &int32, 4 );
221    
222     /* Write the image header. */
223     fwwrite( fw, fhead, sizeof( fhead ) );
224    
225     for( idx = idxstart; idx; idx = idx->next )
226     {
227     /* Save this one now, we don't want to use it in swapped byte order. */
228     int size = idx->h->hsize;
229    
230     verify_offset( fw->fd, idx->idx_offset );
231    
232     cvtheader( idx->h );
233     fwwrite( fw, idx->h, size );
234     cvtheader( idx->h );
235     }
236    
237     /* There should be at least two 0-bytes at the end of the index. */
238     if( pad( lseek( fw->fd, 0, SEEK_CUR ), 4 ) < 2 )
239     {
240     u_int16_t zero = 0;
241     fwwrite( fw, &zero, 2 );
242     }
243    
244     printf( "Done!\n" );
245    
246     printf( "Writing the files...\n" );
247     for( idx = idxstart; idx; idx = idx->next )
248     {
249     char rdbuf[BUFSIZE];
250     int n;
251    
252     printf( " %s\n", idx->h->fn );
253    
254     /* Since we opened this same file a few moments ago, let's assume it can't go wrong. */
255     fd = open( idx->realfile, O_RDONLY );
256    
257     /* Try to start every file at a 4-byte boundary. */
258     fwpad( fw, 4 );
259    
260     verify_offset( fw->fd, idx->h->offset );
261    
262     while( ( n = read( fd, rdbuf, BUFSIZE ) ) > 0 )
263     {
264     if( fwwrite( fw, rdbuf, n ) <= 0 )
265     {
266     perror( "fwwrite" );
267     return( 1 );
268     }
269     }
270    
271     close( fd );
272     }
273    
274     fwpad( fw, 4 );
275    
276     int32 = fwcs( fw );
277     int32 = cvt32( int32 );
278     fwwrite( fw, &int32, 4 );
279    
280     verify_offset( fw->fd, cur );
281    
282     /* This is actually not very likely to go wrong... */
283     if( fwcs( fw ) == 0 )
284     {
285     printf( "End checksum of file is 0, good!\n" );
286     }
287     else
288     {
289     fprintf( stderr, "WARNING: The file checksum is not right!\n" );
290     }
291    
292     fwclose( fw );
293    
294     return( 0 );
295     }
296    
297     struct fwfile *fwstart( char *fn )
298     {
299     struct fwfile *fw;
300    
301     /* Using calloc because it gives zeroed mem. */
302     fw = calloc( 1, sizeof( struct fwfile ) );
303     fw->fd = open( fn, O_RDWR | O_CREAT | O_TRUNC, 0644 );
304     fw->cs = 0xfffe1000;
305    
306     if( fw->fd < 0 )
307     {
308     free( fw );
309     return( NULL );
310     }
311    
312     return( fw );
313     }
314    
315     int fwwrite( struct fwfile *fw, void *data, int size )
316     {
317     if( write( fw->fd, data, size ) != size )
318     return( -1 );
319    
320     /* If the checksum buffer isn't empty, try to empty it first. */
321     if( fw->cslen != 0 )
322     {
323     if( size < ( 4 - fw->cslen ) )
324     {
325     memcpy( fw->csbuf.byte + fw->cslen, data, size );
326     fw->cslen += size;
327     return( size );
328     }
329     memcpy( fw->csbuf.byte + fw->cslen, data, ( 4 - fw->cslen ) );
330     fw->cs -= cvt32( fw->csbuf.val );
331     data += ( 4 - fw->cslen );
332     size -= ( 4 - fw->cslen );
333     fw->cslen = 0;
334     }
335    
336     while( size >= 4 )
337     {
338     memcpy( fw->csbuf.byte, data, 4 );
339     fw->cs -= cvt32( fw->csbuf.val );
340     data += 4;
341     size -= 4;
342     }
343    
344     if( size > 0 )
345     {
346     fw->csbuf.val = 0;
347     memcpy( fw->csbuf.byte, data, size );
348     fw->cslen = size;
349     }
350    
351     return( 1 );
352     }
353    
354     int fwpad( struct fwfile *fw, int align )
355     {
356     int padlen;
357     char *dat;
358    
359     padlen = pad( lseek( fw->fd, 0, SEEK_CUR ), align );
360     if( padlen == 0 )
361     return( 0 );
362    
363     dat = calloc( padlen, 1 );
364     if( fwwrite( fw, dat, padlen ) < 0 )
365     return( -1 );
366     else
367     return( padlen );
368     }
369    
370     u_int32_t fwcs( struct fwfile *fw )
371     {
372     if( fw->cslen != 0 )
373     return( fw->cs - fw->csbuf.val );
374     else
375     return( fw->cs );
376     }
377    
378     void fwclose( struct fwfile *fw )
379     {
380     close( fw->fd );
381     free( fw );
382     }
383    
384     int pad( off_t offset, int align )
385     {
386     return( ( align - ( offset % align ) ) % align );
387     }
388    
389     char *basename( char *fn )
390     {
391     char *base = fn;
392    
393     while( *fn )
394     {
395     if( fn[0] == '/' && fn[1] && fn[1] != '/' )
396     base = fn + 1;
397    
398     fn ++;
399     }
400    
401     return( base );
402     }
403    
404     void verify_offset( int fd, off_t expect )
405     {
406     off_t cur;
407    
408     if( ( cur = lseek( fd, 0, SEEK_CUR ) ) != expect )
409     {
410     fprintf( stderr, "BUG: Something went wrong! Current offset: 0x%x, expected offset: 0x%x\n",
411     (int) cur, (int) expect );
412     exit( 1 );
413     }
414     }