Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / romfs / tools / build_ffs.c
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
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
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
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
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
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 *
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
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
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
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
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 }