Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / romfs / tools / build_ffs.c
diff --git a/qemu/roms/SLOF/romfs/tools/build_ffs.c b/qemu/roms/SLOF/romfs/tools/build_ffs.c
new file mode 100644 (file)
index 0000000..218de75
--- /dev/null
@@ -0,0 +1,476 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cfgparse.h>
+#include <createcrc.h>
+
+#define FFS_TARGET_HEADER_SIZE (4 * 8)
+
+extern int verbose;
+
+#define pad8_num(x) (((x) + 7) & ~7)
+
+static int
+file_exist(const char *name, int errdisp)
+{
+       struct stat fileinfo;
+
+       memset((void *) &fileinfo, 0, sizeof(struct stat));
+       if (stat(name, &fileinfo) != 0) {
+               if (0 != errdisp) {
+                       perror(name);
+               }
+               return 0;
+       }
+       if (S_ISREG(fileinfo.st_mode)) {
+               return 1;
+       }
+       return 0;
+}
+
+static int
+file_getsize(const char *name)
+{
+       int rc;
+       struct stat fi;
+
+       rc = stat(name, &fi);
+       if (rc != 0)
+               return -1;
+       return fi.st_size;
+}
+
+static int
+ffshdr_compare(const void *_a, const void *_b)
+{
+       const struct ffs_header_t *a = *(struct ffs_header_t * const *) _a;
+       const struct ffs_header_t *b = *(struct ffs_header_t * const *) _b;
+
+       if (a->romaddr == b->romaddr)
+               return 0;
+       if (a->romaddr > b->romaddr)
+               return 1;
+       return -1;
+}
+
+static void
+hdr_print(struct ffs_header_t *hdr)
+{
+       printf("hdr: %p\n", hdr);
+       printf("\taddr:      %08llx token:    %s\n"
+              "\tflags:     %08llx romaddr:  %08llx image_len: %08x\n"
+              "\tsave_len:  %08llx ffsize:   %08x hdrsize:   %08x\n"
+              "\ttokensize: %08x\n",
+              hdr->addr, hdr->token, hdr->flags, hdr->romaddr,
+              hdr->imagefile_length, hdr->save_data_len,
+              hdr->ffsize, hdr->hdrsize, hdr->tokensize);
+}
+
+int
+reorder_ffs_chain(struct ffs_chain_t *fs)
+{
+       int i, j;
+       int free_space;
+       unsigned long long addr;
+       struct ffs_header_t *hdr;
+       int fix, flx, res, tab_size = fs->count;
+       struct ffs_header_t *fix_tab[tab_size]; /* fixed offset */
+       struct ffs_header_t *flx_tab[tab_size]; /* flexible offset */
+       struct ffs_header_t *res_tab[tab_size]; /* result */
+
+       /* determine size data to be able to do the reordering */
+       for (hdr = fs->first; hdr; hdr = hdr->next) {
+               if (hdr->linked_to)
+                       hdr->imagefile_length = 0;
+               else
+                       hdr->imagefile_length = file_getsize(hdr->imagefile);
+               if (hdr->imagefile_length == -1)
+                       return -1;
+
+               hdr->tokensize = pad8_num(strlen(hdr->token) + 1);
+               hdr->hdrsize = FFS_TARGET_HEADER_SIZE + hdr->tokensize;
+               hdr->ffsize =
+                   hdr->hdrsize + pad8_num(hdr->imagefile_length) + 8;
+       }
+
+       memset(res_tab, 0, tab_size * sizeof(struct ffs_header_t *));
+       memset(fix_tab, 0, tab_size * sizeof(struct ffs_header_t *));
+       memset(flx_tab, 0, tab_size * sizeof(struct ffs_header_t *));
+
+       /* now start with entries having fixed offs, reorder if needed */
+       for (fix = 0, flx = 0, hdr = fs->first; hdr; hdr = hdr->next)
+               if (needs_fix_offset(hdr))
+                       fix_tab[fix++] = hdr;
+               else
+                       flx_tab[flx++] = hdr;
+       qsort(fix_tab, fix, sizeof(struct ffs_header_t *), ffshdr_compare);
+
+       /*
+        * for fixed files we need to also remove the hdrsize from the
+        * free space because it placed in front of the romaddr
+        */
+       for (addr = 0, res = 0, i = 0, j = 0; i < fix; i++) {
+               fix_tab[i]->addr = fix_tab[i]->romaddr - fix_tab[i]->hdrsize;
+               free_space = fix_tab[i]->addr - addr;
+
+               /* insert as many flexible files as possible */
+               for (; free_space > 0 && j < flx; j++) {
+                       if (flx_tab[j]->ffsize <= free_space) { /* fits */
+                               flx_tab[j]->addr = addr;
+                               free_space -= flx_tab[j]->ffsize;
+                               addr += flx_tab[j]->ffsize;
+                               res_tab[res++] = flx_tab[j];
+                       } else
+                               break;
+               }
+               res_tab[res++] = fix_tab[i];
+               addr = fix_tab[i]->romaddr + fix_tab[i]->ffsize -
+                   fix_tab[i]->hdrsize;
+       }
+       /* at the end fill up the table with remaining flx entries */
+       for (; j < flx; j++) {
+               flx_tab[j]->addr = addr;
+               addr += flx_tab[j]->ffsize;
+               res_tab[res++] = flx_tab[j];
+       }
+
+       if (verbose) {
+               printf("--- resulting order ---\n");
+               for (i = 0; i < tab_size; i++)
+                       hdr_print(res_tab[i]);
+       }
+
+       /* to check if the requested romfs images is greater than
+        * the specified romfs_size it is necessary to add 8 for
+        * the CRC to the totalsize */
+       addr += 8;
+
+       /* sanity checking if user specified maximum romfs size */
+       if ((fs->romfs_size != 0) && addr > fs->romfs_size) {
+               fprintf(stderr, "[build_romfs] romfs_size specified as %d "
+                       "bytes, but %lld bytes need to be written.\n",
+                       fs->romfs_size, addr);
+               return 1;
+       }
+
+       /* resort result list */
+       for (i = 0; i < tab_size - 1; i++)
+               res_tab[i]->next = res_tab[i + 1];
+       res_tab[i]->next = NULL;
+       fs->first = res_tab[0];
+       return 0;
+}
+
+/**
+ * allocate memory for a romfs file including header
+ */
+static unsigned char *
+malloc_file(int hdrsz, int datasz, int *ffsz)
+{
+       void *tmp;
+
+       /* complete file size is:
+        * header + 8byte aligned(data) + end of file marker (-1) */
+       *ffsz = hdrsz + pad8_num(datasz) + 8;
+       /* get the mem */
+       tmp = malloc(*ffsz);
+
+       if (!tmp)
+               return NULL;
+
+       memset(tmp, 0, *ffsz);
+
+       return (unsigned char *) tmp;
+}
+
+static int
+copy_file(struct ffs_header_t *hdr, unsigned char *ffile, int datasize,
+         int ffile_offset, int ffsize)
+{
+       int cnt = 0;
+       int imgfd;
+       int i;
+
+       if (!file_exist(hdr->imagefile, 1)) {
+               printf("access error to file: %s\n", hdr->imagefile);
+               free(ffile);
+               return -1;
+       }
+
+       imgfd = open(hdr->imagefile, O_RDONLY);
+       if (0 >= imgfd) {
+               perror(hdr->imagefile);
+               free(ffile);
+               return -1;
+       }
+
+       /* now copy file to file buffer */
+       /* FIXME using fread might be a good idea so
+          that we do not need to deal with shortened
+          reads/writes. Also error handling looks
+          broken to me. Are we sure that all data is
+          read when exiting this loop? */
+       while (1) {
+               i = read(imgfd, ffile + ffile_offset, ffsize - ffile_offset);
+               if (i <= 0)
+                       break;
+               ffile_offset += i;
+               cnt += i;
+       }
+
+       /* sanity check */
+       if (cnt != datasize) {
+               printf("BUG!!! copy error on image file [%s](e%d, g%d)\n",
+                      hdr->imagefile, datasize, cnt);
+               close(imgfd);
+               free(ffile);
+               return -1;
+       }
+
+       close(imgfd);
+
+       return cnt;
+}
+
+static uint64_t
+next_file_offset(struct ffs_header_t *hdr, int rom_pos, int ffsize)
+{
+       uint64_t tmp;
+
+       /* no next file; end of filesystem */
+       if (hdr->next == NULL)
+               return 0;
+
+       if (hdr->next->romaddr > 0) {
+               /* the next file does not follow directly after the
+                * current file because it requested to be
+                * placed at a special address;
+                * we need to calculate the offset of the
+                * next file;
+                * the next file starts at hdr->next->romaddr which
+                * is the address requested by the user */
+               tmp = hdr->next->romaddr;
+               /* the next file starts, however, a bit earlier;
+                * we need to point at the header of the next file;
+                * therefore it is necessary to subtract the header size
+                * of the _next_ file */
+               tmp -= FFS_TARGET_HEADER_SIZE;
+               /* also remove the length of the filename of the _next_
+                * file */
+               tmp -= pad8_num(strlen(hdr->next->token) + 1);
+               /* and it needs to be relative to the current file */
+               tmp -= rom_pos;
+               return tmp;
+       }
+
+       /* if no special treatment is required the next file just
+        * follows after the current file;
+        * therefore just return the complete filesize as offset */
+       return ffsize;
+}
+
+static int
+next_file_address(struct ffs_header_t *hdr, unsigned int rom_pos, int hdrsize,
+                 unsigned int num_files)
+{
+       /* check if file wants a specific address */
+       void *tmp;
+
+       if ((hdr->flags & FLAG_LLFW) == 0)
+               /* flag to get a specific address has been set */
+               return rom_pos;
+
+       if (hdr->romaddr == 0)
+               /* if the requested address is 0 then
+                * something is not right; ignore the flag */
+               return rom_pos;
+
+       /* check if romaddress is below current position */
+       if (hdr->romaddr < (rom_pos + hdrsize)) {
+               printf("[%s] ERROR: requested impossible " "romaddr of %llx\n",
+                      hdr->token, hdr->romaddr);
+               return -1;
+       }
+
+       /* spin offset to new position */
+       if (pad8_num(hdr->romaddr) != hdr->romaddr) {
+               printf("BUG!!!! pad8_num(hdr->romaddr) != hdr->romaddr\n");
+               return -1;
+       }
+
+       tmp = malloc(hdr->romaddr - rom_pos - hdrsize);
+
+       if (!tmp)
+               return -1;
+
+       memset(tmp, 0, hdr->romaddr - rom_pos - hdrsize);
+       if (buildDataStream(tmp, hdr->romaddr - rom_pos - hdrsize)) {
+               free(tmp);
+               printf("write failed\n");
+               return -1;
+       }
+
+       free(tmp);
+
+       if (!num_files)
+               printf("\nWARNING: The filesystem will have no entry header!\n"
+                      "         It is still usable but you need to find\n"
+                      "         the FS by yourself in the image.\n\n");
+
+       return hdr->romaddr - hdrsize;
+}
+
+int
+build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime)
+{
+       int ofdCRC;
+       int ffsize, datasize, i;
+       int tokensize, hdrsize, ffile_offset, hdrbegin;
+       struct ffs_header_t *hdr;
+       unsigned char *ffile;
+       unsigned int rom_pos = 0;
+       unsigned int num_files = 0;
+       uint64_t tmp;
+
+       if (NULL == fs->first) {
+               return 1;
+       }
+       hdr = fs->first;
+
+       /* check output file and open it for creation */
+       if (file_exist(outfile, 0)) {
+               printf("Output file (%s) will be overwritten\n", outfile);
+       }
+
+       while (hdr) {
+
+               if (hdr->linked_to) {
+                       printf("\nBUG!!! links not supported anymore\n");
+                       return 1;
+               }
+
+               /* add +1 to strlen for zero termination */
+               tokensize = pad8_num(strlen(hdr->token) + 1);
+               hdrsize = FFS_TARGET_HEADER_SIZE + tokensize;
+               datasize = file_getsize(hdr->imagefile);
+
+               if (datasize == -1) {
+                       perror(hdr->imagefile);
+                       return 1;
+               }
+
+               ffile_offset = 0;
+               ffile = malloc_file(hdrsize, datasize, &ffsize);
+
+               if (NULL == ffile) {
+                       perror("alloc mem for ffile");
+                       return 1;
+               }
+
+               /* check if file wants a specific address */
+               rom_pos = next_file_address(hdr, rom_pos, hdrsize, num_files);
+               hdrbegin = rom_pos;
+
+               if (hdrbegin == -1) {
+                       /* something went wrong */
+                       free(ffile);
+                       return 1;
+               }
+
+               /* write header ******************************************* */
+               /* next addr ********************************************** */
+               tmp = next_file_offset(hdr, rom_pos, ffsize);
+
+               *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
+               rom_pos += 8;
+               ffile_offset += 8;
+
+               /* length ************************************************* */
+               hdr->save_data_len = datasize;
+
+               *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(datasize);
+               rom_pos += 8;
+               ffile_offset += 8;
+
+               /* flags ************************************************** */
+               *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(hdr->flags);
+               rom_pos += 8;
+               ffile_offset += 8;
+
+               /* datapointer ******************************************** */
+
+               //save-data pointer is relative to rombase
+               hdr->save_data = hdrbegin + hdrsize;
+               hdr->save_data_valid = 1;
+               //changed pointers to be relative to file:
+               tmp = hdr->save_data - hdrbegin;
+
+               *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
+               rom_pos += 8;
+               ffile_offset += 8;
+
+               /* name (token) ******************************************* */
+               memset(ffile + ffile_offset, 0, tokensize);
+               strcpy((char *) ffile + ffile_offset, hdr->token);
+               rom_pos += tokensize;
+               ffile_offset += tokensize;
+
+               /* image file ********************************************* */
+               i = copy_file(hdr, ffile, datasize, ffile_offset, ffsize);
+
+               if (i == -1)
+                       return 1;
+
+               /* pad file */
+               rom_pos += i + pad8_num(datasize) - datasize;
+               ffile_offset += i + pad8_num(datasize) - datasize;
+
+               /* limiter ************************************************ */
+               *(uint64_t *) (ffile + ffile_offset) = -1;
+               rom_pos += 8;
+               ffile_offset += 8;
+
+               if (buildDataStream(ffile, ffsize) != 0) {
+                       printf
+                           ("Failed while processing file '%s' (size = %d bytes)\n",
+                            hdr->imagefile, datasize);
+                       return 1;
+               }
+               free(ffile);
+               hdr = hdr->next;
+               num_files++;
+       }
+
+       /*
+        * FIXME Current limination seems to be about 4MiB.
+        */
+       ofdCRC = open(outfile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+       if (0 > ofdCRC) {
+               perror(outfile);
+               return 1;
+       }
+       i = writeDataStream(ofdCRC, notime);
+       close(ofdCRC);
+
+       if (i)
+               return 1;
+       return 0;
+}