summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/romfs/tools/build_ffs.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/SLOF/romfs/tools/build_ffs.c')
-rw-r--r--qemu/roms/SLOF/romfs/tools/build_ffs.c476
1 files changed, 476 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/romfs/tools/build_ffs.c b/qemu/roms/SLOF/romfs/tools/build_ffs.c
new file mode 100644
index 000000000..218de75f0
--- /dev/null
+++ b/qemu/roms/SLOF/romfs/tools/build_ffs.c
@@ -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;
+}