Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 /*
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 }