diff options
Diffstat (limited to 'qemu/roms/SLOF/romfs/tools/build_ffs.c')
-rw-r--r-- | qemu/roms/SLOF/romfs/tools/build_ffs.c | 476 |
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; +} |