1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12 
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 #include <cfgparse.h>
23 #include <createcrc.h>
24 
25 #define FFS_TARGET_HEADER_SIZE (4 * 8)
26 
27 extern int verbose;
28 
29 #define pad8_num(x) (((x) + 7) & ~7)
30 
31 static int
file_exist(const char * name,int errdisp)32 file_exist(const char *name, int errdisp)
33 {
34 	struct stat fileinfo;
35 
36 	memset((void *) &fileinfo, 0, sizeof(struct stat));
37 	if (stat(name, &fileinfo) != 0) {
38 		if (0 != errdisp) {
39 			perror(name);
40 		}
41 		return 0;
42 	}
43 	if (S_ISREG(fileinfo.st_mode)) {
44 		return 1;
45 	}
46 	return 0;
47 }
48 
49 static int
file_getsize(const char * name)50 file_getsize(const char *name)
51 {
52 	int rc;
53 	struct stat fi;
54 
55 	rc = stat(name, &fi);
56 	if (rc != 0)
57 		return -1;
58 	return fi.st_size;
59 }
60 
61 static int
ffshdr_compare(const void * _a,const void * _b)62 ffshdr_compare(const void *_a, const void *_b)
63 {
64 	const struct ffs_header_t *a = *(struct ffs_header_t * const *) _a;
65 	const struct ffs_header_t *b = *(struct ffs_header_t * const *) _b;
66 
67 	if (a->romaddr == b->romaddr)
68 		return 0;
69 	if (a->romaddr > b->romaddr)
70 		return 1;
71 	return -1;
72 }
73 
74 static void
hdr_print(struct ffs_header_t * hdr)75 hdr_print(struct ffs_header_t *hdr)
76 {
77 	printf("hdr: %p\n", hdr);
78 	printf("\taddr:      %08llx token:    %s\n"
79 	       "\tflags:     %08llx romaddr:  %08llx image_len: %08x\n"
80 	       "\tsave_len:  %08llx ffsize:   %08x hdrsize:   %08x\n"
81 	       "\ttokensize: %08x\n",
82 	       hdr->addr, hdr->token, hdr->flags, hdr->romaddr,
83 	       hdr->imagefile_length, hdr->save_data_len,
84 	       hdr->ffsize, hdr->hdrsize, hdr->tokensize);
85 }
86 
87 int
reorder_ffs_chain(struct ffs_chain_t * fs)88 reorder_ffs_chain(struct ffs_chain_t *fs)
89 {
90 	int i, j;
91 	int free_space;
92 	unsigned long long addr;
93 	struct ffs_header_t *hdr;
94 	int fix, flx, res, tab_size = fs->count;
95 	struct ffs_header_t *fix_tab[tab_size];	/* fixed offset */
96 	struct ffs_header_t *flx_tab[tab_size];	/* flexible offset */
97 	struct ffs_header_t *res_tab[tab_size];	/* result */
98 
99 	/* determine size data to be able to do the reordering */
100 	for (hdr = fs->first; hdr; hdr = hdr->next) {
101 		if (hdr->linked_to)
102 			hdr->imagefile_length = 0;
103 		else
104 			hdr->imagefile_length = file_getsize(hdr->imagefile);
105 		if (hdr->imagefile_length == -1)
106 			return -1;
107 
108 		hdr->tokensize = pad8_num(strlen(hdr->token) + 1);
109 		hdr->hdrsize = FFS_TARGET_HEADER_SIZE + hdr->tokensize;
110 		hdr->ffsize =
111 		    hdr->hdrsize + pad8_num(hdr->imagefile_length) + 8;
112 	}
113 
114 	memset(res_tab, 0, tab_size * sizeof(struct ffs_header_t *));
115 	memset(fix_tab, 0, tab_size * sizeof(struct ffs_header_t *));
116 	memset(flx_tab, 0, tab_size * sizeof(struct ffs_header_t *));
117 
118 	/* now start with entries having fixed offs, reorder if needed */
119 	for (fix = 0, flx = 0, hdr = fs->first; hdr; hdr = hdr->next)
120 		if (needs_fix_offset(hdr))
121 			fix_tab[fix++] = hdr;
122 		else
123 			flx_tab[flx++] = hdr;
124 	qsort(fix_tab, fix, sizeof(struct ffs_header_t *), ffshdr_compare);
125 
126 	/*
127 	 * for fixed files we need to also remove the hdrsize from the
128 	 * free space because it placed in front of the romaddr
129 	 */
130 	for (addr = 0, res = 0, i = 0, j = 0; i < fix; i++) {
131 		fix_tab[i]->addr = fix_tab[i]->romaddr - fix_tab[i]->hdrsize;
132 		free_space = fix_tab[i]->addr - addr;
133 
134 		/* insert as many flexible files as possible */
135 		for (; free_space > 0 && j < flx; j++) {
136 			if (flx_tab[j]->ffsize <= free_space) {	/* fits */
137 				flx_tab[j]->addr = addr;
138 				free_space -= flx_tab[j]->ffsize;
139 				addr += flx_tab[j]->ffsize;
140 				res_tab[res++] = flx_tab[j];
141 			} else
142 				break;
143 		}
144 		res_tab[res++] = fix_tab[i];
145 		addr = fix_tab[i]->romaddr + fix_tab[i]->ffsize -
146 		    fix_tab[i]->hdrsize;
147 	}
148 	/* at the end fill up the table with remaining flx entries */
149 	for (; j < flx; j++) {
150 		flx_tab[j]->addr = addr;
151 		addr += flx_tab[j]->ffsize;
152 		res_tab[res++] = flx_tab[j];
153 	}
154 
155 	if (verbose) {
156 		printf("--- resulting order ---\n");
157 		for (i = 0; i < tab_size; i++)
158 			hdr_print(res_tab[i]);
159 	}
160 
161 	/* to check if the requested romfs images is greater than
162 	 * the specified romfs_size it is necessary to add 8 for
163 	 * the CRC to the totalsize */
164 	addr += 8;
165 
166 	/* sanity checking if user specified maximum romfs size */
167 	if ((fs->romfs_size != 0) && addr > fs->romfs_size) {
168 		fprintf(stderr, "[build_romfs] romfs_size specified as %d "
169 			"bytes, but %lld bytes need to be written.\n",
170 			fs->romfs_size, addr);
171 		return 1;
172 	}
173 
174 	/* resort result list */
175 	for (i = 0; i < tab_size - 1; i++)
176 		res_tab[i]->next = res_tab[i + 1];
177 	res_tab[i]->next = NULL;
178 	fs->first = res_tab[0];
179 	return 0;
180 }
181 
182 /**
183  * allocate memory for a romfs file including header
184  */
185 static unsigned char *
malloc_file(int hdrsz,int datasz,int * ffsz)186 malloc_file(int hdrsz, int datasz, int *ffsz)
187 {
188 	void *tmp;
189 
190 	/* complete file size is:
191 	 * header + 8byte aligned(data) + end of file marker (-1) */
192 	*ffsz = hdrsz + pad8_num(datasz) + 8;
193 	/* get the mem */
194 	tmp = malloc(*ffsz);
195 
196 	if (!tmp)
197 		return NULL;
198 
199 	memset(tmp, 0, *ffsz);
200 
201 	return (unsigned char *) tmp;
202 }
203 
204 static int
copy_file(struct ffs_header_t * hdr,unsigned char * ffile,int datasize,int ffile_offset,int ffsize)205 copy_file(struct ffs_header_t *hdr, unsigned char *ffile, int datasize,
206 	  int ffile_offset, int ffsize)
207 {
208 	int cnt = 0;
209 	int imgfd;
210 	int i;
211 
212 	if (!file_exist(hdr->imagefile, 1)) {
213 		printf("access error to file: %s\n", hdr->imagefile);
214 		free(ffile);
215 		return -1;
216 	}
217 
218 	imgfd = open(hdr->imagefile, O_RDONLY);
219 	if (0 >= imgfd) {
220 		perror(hdr->imagefile);
221 		free(ffile);
222 		return -1;
223 	}
224 
225 	/* now copy file to file buffer */
226 	/* FIXME using fread might be a good idea so
227 	   that we do not need to deal with shortened
228 	   reads/writes. Also error handling looks
229 	   broken to me. Are we sure that all data is
230 	   read when exiting this loop? */
231 	while (1) {
232 		i = read(imgfd, ffile + ffile_offset, ffsize - ffile_offset);
233 		if (i <= 0)
234 			break;
235 		ffile_offset += i;
236 		cnt += i;
237 	}
238 
239 	/* sanity check */
240 	if (cnt != datasize) {
241 		printf("BUG!!! copy error on image file [%s](e%d, g%d)\n",
242 		       hdr->imagefile, datasize, cnt);
243 		close(imgfd);
244 		free(ffile);
245 		return -1;
246 	}
247 
248 	close(imgfd);
249 
250 	return cnt;
251 }
252 
253 static uint64_t
next_file_offset(struct ffs_header_t * hdr,int rom_pos,int ffsize)254 next_file_offset(struct ffs_header_t *hdr, int rom_pos, int ffsize)
255 {
256 	uint64_t tmp;
257 
258 	/* no next file; end of filesystem */
259 	if (hdr->next == NULL)
260 		return 0;
261 
262 	if (hdr->next->romaddr > 0) {
263 		/* the next file does not follow directly after the
264 		 * current file because it requested to be
265 		 * placed at a special address;
266 		 * we need to calculate the offset of the
267 		 * next file;
268 		 * the next file starts at hdr->next->romaddr which
269 		 * is the address requested by the user */
270 		tmp = hdr->next->romaddr;
271 		/* the next file starts, however, a bit earlier;
272 		 * we need to point at the header of the next file;
273 		 * therefore it is necessary to subtract the header size
274 		 * of the _next_ file */
275 		tmp -= FFS_TARGET_HEADER_SIZE;
276 		/* also remove the length of the filename of the _next_
277 		 * file */
278 		tmp -= pad8_num(strlen(hdr->next->token) + 1);
279 		/* and it needs to be relative to the current file */
280 		tmp -= rom_pos;
281 		return tmp;
282 	}
283 
284 	/* if no special treatment is required the next file just
285 	 * follows after the current file;
286 	 * therefore just return the complete filesize as offset */
287 	return ffsize;
288 }
289 
290 static int
next_file_address(struct ffs_header_t * hdr,unsigned int rom_pos,int hdrsize,unsigned int num_files)291 next_file_address(struct ffs_header_t *hdr, unsigned int rom_pos, int hdrsize,
292 		  unsigned int num_files)
293 {
294 	/* check if file wants a specific address */
295 	void *tmp;
296 
297 	if ((hdr->flags & FLAG_LLFW) == 0)
298 		/* flag to get a specific address has been set */
299 		return rom_pos;
300 
301 	if (hdr->romaddr == 0)
302 		/* if the requested address is 0 then
303 		 * something is not right; ignore the flag */
304 		return rom_pos;
305 
306 	/* check if romaddress is below current position */
307 	if (hdr->romaddr < (rom_pos + hdrsize)) {
308 		printf("[%s] ERROR: requested impossible " "romaddr of %llx\n",
309 		       hdr->token, hdr->romaddr);
310 		return -1;
311 	}
312 
313 	/* spin offset to new position */
314 	if (pad8_num(hdr->romaddr) != hdr->romaddr) {
315 		printf("BUG!!!! pad8_num(hdr->romaddr) != hdr->romaddr\n");
316 		return -1;
317 	}
318 
319 	tmp = malloc(hdr->romaddr - rom_pos - hdrsize);
320 
321 	if (!tmp)
322 		return -1;
323 
324 	memset(tmp, 0, hdr->romaddr - rom_pos - hdrsize);
325 	if (buildDataStream(tmp, hdr->romaddr - rom_pos - hdrsize)) {
326 		free(tmp);
327 		printf("write failed\n");
328 		return -1;
329 	}
330 
331 	free(tmp);
332 
333 	if (!num_files)
334 		printf("\nWARNING: The filesystem will have no entry header!\n"
335 		       "         It is still usable but you need to find\n"
336 		       "         the FS by yourself in the image.\n\n");
337 
338 	return hdr->romaddr - hdrsize;
339 }
340 
341 int
build_ffs(struct ffs_chain_t * fs,const char * outfile,int notime)342 build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime)
343 {
344 	int ofdCRC;
345 	int ffsize, datasize, i;
346 	int tokensize, hdrsize, ffile_offset, hdrbegin;
347 	struct ffs_header_t *hdr;
348 	unsigned char *ffile;
349 	unsigned int rom_pos = 0;
350 	unsigned int num_files = 0;
351 	uint64_t tmp;
352 
353 	if (NULL == fs->first) {
354 		return 1;
355 	}
356 	hdr = fs->first;
357 
358 	/* check output file and open it for creation */
359 	if (file_exist(outfile, 0)) {
360 		printf("Output file (%s) will be overwritten\n", outfile);
361 	}
362 
363 	while (hdr) {
364 
365 		if (hdr->linked_to) {
366 			printf("\nBUG!!! links not supported anymore\n");
367 			return 1;
368 		}
369 
370 		/* add +1 to strlen for zero termination */
371 		tokensize = pad8_num(strlen(hdr->token) + 1);
372 		hdrsize = FFS_TARGET_HEADER_SIZE + tokensize;
373 		datasize = file_getsize(hdr->imagefile);
374 
375 		if (datasize == -1) {
376 			perror(hdr->imagefile);
377 			return 1;
378 		}
379 
380 		ffile_offset = 0;
381 		ffile = malloc_file(hdrsize, datasize, &ffsize);
382 
383 		if (NULL == ffile) {
384 			perror("alloc mem for ffile");
385 			return 1;
386 		}
387 
388 		/* check if file wants a specific address */
389 		rom_pos = next_file_address(hdr, rom_pos, hdrsize, num_files);
390 		hdrbegin = rom_pos;
391 
392 		if (hdrbegin == -1) {
393 			/* something went wrong */
394 			free(ffile);
395 			return 1;
396 		}
397 
398 		/* write header ******************************************* */
399 		/* next addr ********************************************** */
400 		tmp = next_file_offset(hdr, rom_pos, ffsize);
401 
402 		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
403 		rom_pos += 8;
404 		ffile_offset += 8;
405 
406 		/* length ************************************************* */
407 		hdr->save_data_len = datasize;
408 
409 		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(datasize);
410 		rom_pos += 8;
411 		ffile_offset += 8;
412 
413 		/* flags ************************************************** */
414 		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(hdr->flags);
415 		rom_pos += 8;
416 		ffile_offset += 8;
417 
418 		/* datapointer ******************************************** */
419 
420 		//save-data pointer is relative to rombase
421 		hdr->save_data = hdrbegin + hdrsize;
422 		hdr->save_data_valid = 1;
423 		//changed pointers to be relative to file:
424 		tmp = hdr->save_data - hdrbegin;
425 
426 		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
427 		rom_pos += 8;
428 		ffile_offset += 8;
429 
430 		/* name (token) ******************************************* */
431 		memset(ffile + ffile_offset, 0, tokensize);
432 		strcpy((char *) ffile + ffile_offset, hdr->token);
433 		rom_pos += tokensize;
434 		ffile_offset += tokensize;
435 
436 		/* image file ********************************************* */
437 		i = copy_file(hdr, ffile, datasize, ffile_offset, ffsize);
438 
439 		if (i == -1)
440 			return 1;
441 
442 		/* pad file */
443 		rom_pos += i + pad8_num(datasize) - datasize;
444 		ffile_offset += i + pad8_num(datasize) - datasize;
445 
446 		/* limiter ************************************************ */
447 		*(uint64_t *) (ffile + ffile_offset) = -1;
448 		rom_pos += 8;
449 		ffile_offset += 8;
450 
451 		if (buildDataStream(ffile, ffsize) != 0) {
452 			printf
453 			    ("Failed while processing file '%s' (size = %d bytes)\n",
454 			     hdr->imagefile, datasize);
455 			return 1;
456 		}
457 		free(ffile);
458 		hdr = hdr->next;
459 		num_files++;
460 	}
461 
462 	/*
463 	 * FIXME Current limination seems to be about 4MiB.
464 	 */
465 	ofdCRC = open(outfile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
466 	if (0 > ofdCRC) {
467 		perror(outfile);
468 		return 1;
469 	}
470 	i = writeDataStream(ofdCRC, notime);
471 	close(ofdCRC);
472 
473 	if (i)
474 		return 1;
475 	return 0;
476 }
477