diff options
Diffstat (limited to 'ubi-utils')
-rw-r--r-- | ubi-utils/Makefile | 7 | ||||
-rw-r--r-- | ubi-utils/inc/libpfi.h (renamed from ubi-utils/src/pfi.h) | 49 | ||||
-rw-r--r-- | ubi-utils/inc/libubigen.h | 104 | ||||
-rw-r--r-- | ubi-utils/src/bootenv.c | 8 | ||||
-rw-r--r-- | ubi-utils/src/common.h | 1 | ||||
-rw-r--r-- | ubi-utils/src/crc32.c | 156 | ||||
-rw-r--r-- | ubi-utils/src/crc32.h | 47 | ||||
-rw-r--r-- | ubi-utils/src/libpfi.c | 628 | ||||
-rw-r--r-- | ubi-utils/src/libubigen.c | 665 | ||||
-rw-r--r-- | ubi-utils/src/list.c | 52 | ||||
-rw-r--r-- | ubi-utils/src/list.h | 55 | ||||
-rw-r--r-- | ubi-utils/src/peb.c | 116 | ||||
-rw-r--r-- | ubi-utils/src/peb.h | 41 | ||||
-rw-r--r-- | ubi-utils/src/pfi.c | 458 | ||||
-rw-r--r-- | ubi-utils/src/pfi2bin.c | 465 | ||||
-rw-r--r-- | ubi-utils/src/reader.c | 482 | ||||
-rw-r--r-- | ubi-utils/src/reader.h | 87 | ||||
-rw-r--r-- | ubi-utils/src/ubicrc32.c | 9 | ||||
-rw-r--r-- | ubi-utils/src/ubigen.h | 150 | ||||
-rw-r--r-- | ubi-utils/src/unubi.c | 14 | ||||
-rw-r--r-- | ubi-utils/src/unubi_analyze.c | 8 |
21 files changed, 1261 insertions, 2341 deletions
diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index a6062a2..1f8e543 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -10,8 +10,7 @@ MANDIR=/usr/man INCLUDEDIR=/usr/include CC := $(CROSS)gcc -CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror \ - -Wwrite-strings -W -std=gnu99 -DPACKAGE_VERSION=\"1.0\" +CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall -O0 -g PERLPROGS = mkpfi TARGETS = ubiupdate ubimkvol ubirmvol ubicrc32 ubinfo ubiattach ubidetach \ @@ -60,8 +59,8 @@ ubicrc32: ubicrc32.o crc32.o unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o $(CC) $(LDFLAGS) -o $@ $^ -pfi2bin: pfi2bin.o common.o peb.o list.o crc32.o libubigen.o bootenv.o \ - hashmap.o reader.o pfi.o +pfi2bin: pfi2bin.o common.o list.o crc32.o libubigen.o bootenv.o \ + hashmap.o libpfi.o common.o $(CC) $(LDFLAGS) -o $@ $^ install: ${TARGETS} diff --git a/ubi-utils/src/pfi.h b/ubi-utils/inc/libpfi.h index 8c5cc07..6aca4be 100644 --- a/ubi-utils/src/pfi.h +++ b/ubi-utils/inc/libpfi.h @@ -35,11 +35,30 @@ */ #include <stdio.h> /* FILE */ +#include "list.h" #ifdef __cplusplus extern "C" { #endif +struct pfi_ubi { + long long data_offs; + uint32_t data_size; + uint32_t alignment; + uint32_t *ids; + uint32_t ids_size; + char **names; + uint32_t names_size; + uint32_t size; + int vol_type; + int curr_seqnum; /* specifies the seqnum taken in an update, + default: 0 (used by pfiflash, ubimirror) */ + uint32_t crc; +}; + +int read_pfi_headers(struct list_entry **ubi_list, FILE *fp_pfi); +int free_pfi_ubi(struct pfi_ubi **pfi_ubi); + /* Definitions. */ #define PFI_HDRVERSION 1 /* current header version */ @@ -73,13 +92,7 @@ extern "C" { */ #define PFI_FLAG_PROTECTED 0x00000001 - -/** - * @brief Handle to pfi header. Used in most of the functions associated - * with pfi file handling. - */ -typedef struct pfi_header *pfi_header; - +struct pfi_header; /** * @brief Initialize a pfi header object. @@ -89,7 +102,7 @@ typedef struct pfi_header *pfi_header; * @return 0 on success, otherwise: * PFI_ENOMEM : no memory available for the handle. */ -int pfi_header_init (pfi_header *head); +int pfi_header_init (struct pfi_header **head); /** @@ -98,7 +111,7 @@ int pfi_header_init (pfi_header *head); * @param head handle. head is invalid after calling this function. * @return 0 always. */ -int pfi_header_destroy (pfi_header *head); +int pfi_header_destroy (struct pfi_header **head); /** @@ -115,7 +128,7 @@ int pfi_header_destroy (pfi_header *head); * new value is not convertable e.g. not in * 0xXXXXXXXX format. */ -int pfi_header_setvalue (pfi_header head, +int pfi_header_setvalue (struct pfi_header *head, const char *key, const char *value); @@ -131,7 +144,7 @@ int pfi_header_setvalue (pfi_header head, * PFI_EBADTYPE : value is not a string. This happens * when the key stores a string. */ -int pfi_header_setnumber (pfi_header head, +int pfi_header_setnumber (struct pfi_header *head, const char *key, uint32_t value); @@ -146,12 +159,12 @@ int pfi_header_setnumber (pfi_header head, * PFI_EUNDEF : key was not found. * PFI_EBADTYPE : stored value is not an integer but a string. */ -int pfi_header_getnumber (pfi_header head, +int pfi_header_getnumber (struct pfi_header *head, const char *key, uint32_t *value); static inline uint32_t -pfi_getnumber(pfi_header head, const char *key) +pfi_getnumber(struct pfi_header *head, const char *key) { uint32_t value; pfi_header_getnumber(head, key, &value); @@ -169,7 +182,7 @@ pfi_getnumber(pfi_header head, const char *key) * PFI_EUNDEF : key was not found. * PFI_EBADTYPE : stored value is not a string but an integer. */ -int pfi_header_getstring (pfi_header head, +int pfi_header_getstring (struct pfi_header *head, const char *key, char *value, size_t size); @@ -183,7 +196,7 @@ int pfi_header_getstring (pfi_header head, * PFI_ENOHEADER : wrong header version or magic number. * -E* : see <asm/errno.h>. */ -int pfi_header_write (FILE *out, pfi_header head); +int pfi_header_write (FILE *out, struct pfi_header *head); /** @@ -203,7 +216,7 @@ int pfi_header_write (FILE *out, pfi_header head); * required in those cases. For optional fields the checking must still be * done. */ -int pfi_header_read (FILE *in, pfi_header head); +int pfi_header_read (FILE *in, struct pfi_header *head); /** @@ -216,7 +229,7 @@ int pfi_header_read (FILE *in, pfi_header head); * @note Prints out that it is not implemented and whom you should * contact if you need it urgently!. */ -int pfi_header_dump (FILE *out, pfi_header head); +int pfi_header_dump (FILE *out, struct pfi_header *head); /* @@ -232,7 +245,7 @@ int pfi_header_dump (FILE *out, pfi_header head); * PFI_EINVAL : func is not valid * 0 ok. */ -typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data); +typedef int (* pfi_read_func)(FILE *in, struct pfi_header *hdr, void *priv_data); int pfi_read (FILE *in, pfi_read_func func, void *priv_data); diff --git a/ubi-utils/inc/libubigen.h b/ubi-utils/inc/libubigen.h new file mode 100644 index 0000000..5315a72 --- /dev/null +++ b/ubi-utils/inc/libubigen.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Authors: Frank Haverkamp + * Artem Bityutskiy + */ + +#ifndef __LIBUBIGEN_H__ +#define __LIBUBIGEN_H__ + +#include <stdio.h> +#include <asm/byteorder.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * struct ubigen_info - libubigen information. + * @leb_size: logical eraseblock size + * @peb_size: size of the physical eraseblock + * @min_io_size: minimum input/output unit size + * @vid_hdr_offs: offset of the VID header + * @data_offs: data offset + * @ubi_ver: UBI version + * @ec: initial erase counter + */ +struct ubigen_info +{ + int leb_size; + int peb_size; + int min_io_size; + int vid_hdr_offs; + int data_offs; + int ubi_ver; + long long ec; +}; + +/** + * struct ubigen_vol_info - information about a volume. + * @id: volume id + * @type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) + * @alignment: volume alignment + * @data_pad: how many bytes are unused at the end of the each physical + * eraseblock to satisfy the requested alignment + * @usable_leb_size: LEB size accessible for volume users + * @name: volume name + * @name_len: volume name length + * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, + * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) + * @used_ebs: total number of used logical eraseblocks in this volume (relevant + * for static volumes only) + * @bytes: size of the volume contents in bytes (relevant for static volumes + * only) + */ +struct ubigen_vol_info +{ + int id; + int type; + int alignment; + int data_pad; + int usable_leb_size; + const char *name; + int name_len; + int compat; + int used_ebs; + long long bytes; +}; + +void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, + int subpage_size, int vid_hdr_offs, int ubi_ver, + long long ec); +struct ubi_vtbl_record *ubigen_create_empty_vtbl(int *size); +void ubigen_add_volume(const struct ubigen_info *ui, + const struct ubigen_vol_info *vi, + struct ubi_vtbl_record *vtbl); +int ubigen_write_volume(const struct ubigen_info *ui, + const struct ubigen_vol_info *vi, + long long bytes, FILE *in, FILE *out); +int ubigen_write_layout_vol(const struct ubigen_info *ui, + struct ubi_vtbl_record *vtbl, FILE *out); + +#ifdef __cplusplus +} +#endif + +#endif /* !__LIBUBIGEN_H__ */ diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c index a6dd4de..5a4205f 100644 --- a/ubi-utils/src/bootenv.c +++ b/ubi-utils/src/bootenv.c @@ -282,7 +282,6 @@ bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc) int rc; char *buf = NULL; size_t i = 0; - uint32_t crc32_table[256]; if ((fp == NULL) || (env == NULL)) return -EINVAL; @@ -317,8 +316,7 @@ bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc) /* calculate crc to return */ if (ret_crc != NULL) { - init_crc32_table(crc32_table); - *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); + *ret_crc = crc32(UBI_CRC32_INIT, buf, size); } /* transfer to hashmap */ @@ -442,7 +440,6 @@ bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc) int rc = 0; size_t size = 0; char *buf = NULL; - uint32_t crc32_table[256]; if ((fp == NULL) || (env == NULL)) return -EINVAL; @@ -458,8 +455,7 @@ bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc) /* calculate crc to return */ if (ret_crc != NULL) { - init_crc32_table(crc32_table); - *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); + *ret_crc = crc32(UBI_CRC32_INIT, buf, size); } if (fwrite(buf, size, 1, fp) != 1) { diff --git a/ubi-utils/src/common.h b/ubi-utils/src/common.h index b27f866..89094ab 100644 --- a/ubi-utils/src/common.h +++ b/ubi-utils/src/common.h @@ -24,6 +24,7 @@ extern "C" { #endif #define MIN(a ,b) ((a) < (b) ? (a) : (b)) +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /* Error messages */ #define errmsg(fmt, ...) do { \ diff --git a/ubi-utils/src/crc32.c b/ubi-utils/src/crc32.c index 666e217..6b1e50c 100644 --- a/ubi-utils/src/crc32.c +++ b/ubi-utils/src/crc32.c @@ -1,83 +1,95 @@ /* - * Copyright (c) International Business Machines Corp., 2006 + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly * - * Author: Thomas Gleixner - */ - -/* - * CRC32 functions + * The feedback terms table consists of 256, 32-bit entries. Notes * - * Can be compiled as seperate object, but is included into the ipl source - * so gcc can inline the functions. We optimize for size so the omission of - * the function frame is helpful. + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 */ #include <stdint.h> -#include <crc32.h> - -/* CRC polynomial */ -#define CRC_POLY 0xEDB88320 - -/** - * init_crc32_table - Initialize crc table - * - * @table: pointer to the CRC table which must be initialized - * - * Create CRC32 table for given polynomial. The table is created with - * the lowest order term in the highest order bit. So the x^32 term - * has to implied in the crc calculation function. - */ -void init_crc32_table(uint32_t *table) -{ - uint32_t crc; - int i, j; - - for (i = 0; i < 256; i++) { - crc = i; - for (j = 8; j > 0; j--) { - if (crc & 1) - crc = (crc >> 1) ^ CRC_POLY; - else - crc >>= 1; - } - table[i] = crc; - } -} - -/** - * clc_crc32 - Calculate CRC32 over a buffer - * - * @table: pointer to the CRC table - * @crc: initial crc value - * @buf: pointer to the buffer - * @len: number of bytes to calc - * - * Returns the updated crc value. - * - * The algorithm resembles a hardware shift register, but calculates 8 - * bit at once. - */ -uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, - int len) -{ - const unsigned char *p = buf; - while(--len >= 0) - crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8); - return crc; -} +const uint32_t crc32_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; diff --git a/ubi-utils/src/crc32.h b/ubi-utils/src/crc32.h index 31362b0..ee3145b 100644 --- a/ubi-utils/src/crc32.h +++ b/ubi-utils/src/crc32.h @@ -1,36 +1,19 @@ -#ifndef __CRC32_H__ -#define __CRC32_H__ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +#ifndef CRC32_H +#define CRC32_H -/* - * Author: Thomas Gleixner - * - * CRC32 functions - * - * Can be compiled as seperate object, but is included into the ipl source - * so gcc can inline the functions. We optimize for size so the omission of - * the function frame is helpful. - * - */ #include <stdint.h> -void init_crc32_table(uint32_t *table); -uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len); +extern const uint32_t crc32_table[256]; -#endif /* __CRC32_H__ */ +/* Return a 32-bit CRC of the contents of the buffer. */ + + static inline uint32_t +crc32(uint32_t val, const void *ss, int len) +{ + const unsigned char *s = ss; + while (--len >= 0) + val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); + return val; +} + +#endif diff --git a/ubi-utils/src/libpfi.c b/ubi-utils/src/libpfi.c new file mode 100644 index 0000000..6de24ea --- /dev/null +++ b/ubi-utils/src/libpfi.c @@ -0,0 +1,628 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * A library to work with pfi files. + * + * Authors Oliver Lohmann + * Andreas Arnez + * Joern Engel + * Frank Haverkamp + * Artem Bityutskiy + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <mtd/ubi-header.h> +#include <libpfi.h> +#include "common.h" +#include "bootenv.h" + +#define PROGRAM_NAME "libpfi" + +#define PFI_MAGIC "PFI!\n" +#define PFI_MAGIC_LEN (sizeof(PFI_MAGIC) - 1) +#define PFI_DATA "DATA\n" + + + + + + + + + + + + + + + + +#define PFI_MANDATORY 0x0001 +#define PFI_STRING 0x0002 +#define PFI_LISTVALUE 0x0004 +#define PFI_MANDATORY_UBI 0x0008 + +enum key_id { + /* version 1 */ + key_version, /* must be index position 0! */ + key_mode, + key_size, + key_crc, + key_label, + key_flags, + key_ubi_ids, + key_ubi_size, + key_ubi_type, + key_ubi_names, + key_ubi_alignment, + num_keys, +}; + +struct pfi_header { + uint8_t defined[num_keys]; /* reserve all possible keys even if + version does not require this. */ + int mode_no; /* current mode no. -> can only increase */ + union { + char *str; + uint32_t num; + } value[num_keys]; +}; + +struct key_descriptor { + enum key_id id; + const char *name; + uint32_t flags; +}; + +static const struct key_descriptor key_desc_v1[] = { + { key_version, "version", PFI_MANDATORY }, + { key_mode, "mode", PFI_MANDATORY | PFI_STRING }, + { key_size, "size", PFI_MANDATORY }, + { key_crc, "crc", PFI_MANDATORY }, + { key_label, "label", PFI_MANDATORY | PFI_STRING }, + { key_flags, "flags", PFI_MANDATORY }, + { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING }, + { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI }, + { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING }, + { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING }, + { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI }, +}; + +static const struct key_descriptor *key_descriptors[] = { + NULL, + key_desc_v1, /* version 1 */ +}; + +static const int key_descriptors_max[] = { + 0, /* version 0 */ + sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */ +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static const char* modes[] = {"ubi"}; + +/* latest version contains all possible keys */ +static const struct key_descriptor *key_desc = key_desc_v1; + +#define PFI_IS_UBI(mode) \ + (((mode) != NULL) && (strcmp("ubi", (mode)) == 0)) + +static int get_mode_no(const char *mode) +{ + int i; + + for (i = 0; i < (int)ARRAY_SIZE(modes); i++) + if (strcmp(mode, modes[i]) == 0) + return i; + return -1; +} + +static int +find_key_by_name (const char *name) +{ + int i; + + for (i = 0; i < num_keys; i++) { + if (strcmp(name, key_desc[i].name) == 0) + return i; + } + return -1; +} + +static int +check_valid (struct pfi_header *head) +{ + int i; + int max_keys; + uint32_t version; + const char *mode; + const struct key_descriptor *desc; + uint32_t to_check = PFI_MANDATORY; + + /* + * For the validity check the list of possible keys depends on + * the version of the PFI file used. + */ + version = head->value[key_version].num; + if (version > PFI_HDRVERSION) + return PFI_ENOHEADER; + + max_keys = key_descriptors_max[version]; + desc = key_descriptors[version]; + + if (!desc) + return PFI_ENOVERSION; + + mode = head->value[key_mode].str; + if (PFI_IS_UBI(mode)) { + to_check |= PFI_MANDATORY_UBI; + } + else { /* neither UBI nor RAW == ERR */ + return PFI_EINSUFF; + } + + for (i = 0; i < max_keys; i++) { + if ((desc[i].flags & to_check) && !head->defined[i]) { + fprintf(stderr, "libpfi: %s missing\n", desc[i].name); + return PFI_EINSUFF; + } + } + + return 0; +} + +int pfi_header_init (struct pfi_header **head) +{ + int i; + struct pfi_header *self = malloc(sizeof(*self)); + + *head = self; + if (self == NULL) + return PFI_ENOMEM; + + /* initialize maximum number of possible keys */ + for (i = 0; i < num_keys; i++) { + memset(self, 0, sizeof(*self)); + self->defined[i] = 0; + } + + return 0; +} + +int pfi_header_destroy (struct pfi_header **head) +{ + int i; + struct pfi_header *self = *head; + + for (i = 0; i < num_keys; i++) { + if (self->defined[i] && (key_desc[i].flags & PFI_STRING) && + self->value[i].str) { + free(self->value[i].str); + } + } + free(*head); + *head = NULL; + return 0; +} + +int pfi_header_setnumber (struct pfi_header *head, + const char *key, uint32_t value) +{ + int key_id = find_key_by_name(key); + + if (key_id < 0) + return PFI_EUNDEF; + + if (key_desc[key_id].flags & PFI_STRING) + return PFI_EBADTYPE; + + head->value[key_id].num = value; + head->defined[key_id] = 1; + return 0; +} + +int pfi_header_setvalue (struct pfi_header *head, + const char *key, const char *value) +{ + int key_id = find_key_by_name(key); + + if (value == NULL) + return PFI_EINSUFF; + + if ((key_id < 0) || (key_id >= num_keys)) + return PFI_EUNDEF; + + if (key_desc[key_id].flags & PFI_STRING) { + /* + * The value is a string. Copy to a newly allocated + * buffer. Delete the old value, if already set. + */ + size_t len = strlen(value) + 1; + char *old_str = NULL; + char *str; + + old_str = head->value[key_id].str; + if (old_str != NULL) + free(old_str); + + str = head->value[key_id].str = (char *) malloc(len); + if (str == NULL) + return PFI_ENOMEM; + + strcpy(str, value); + } else { + int len; + int ret; + /* FIXME: here we assume that the value is always + given in hex and starts with '0x'. */ + ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len); + if (ret < 1 || value[len] != '\0') + return PFI_EBADTYPE; + } + head->defined[key_id] = 1; + return 0; +} + +int pfi_header_getnumber (struct pfi_header *head, + const char *key, uint32_t *value) +{ + int key_id = find_key_by_name(key); + + if (key_id < 0) + return PFI_EUNDEF; + + if (key_desc[key_id].flags & PFI_STRING) + return PFI_EBADTYPE; + + if (!head->defined[key_id]) + return PFI_EUNDEF; + + *value = head->value[key_id].num; + return 0; +} + +int pfi_header_getstring (struct pfi_header *head, + const char *key, char *value, size_t size) +{ + int key_id = find_key_by_name(key); + + if (key_id < 0) + return PFI_EUNDEF; + + if (!(key_desc[key_id].flags & PFI_STRING)) + return PFI_EBADTYPE; + + if (!head->defined[key_id]) + return PFI_EUNDEF; + + strncpy(value, head->value[key_id].str, size-1); + value[size-1] = '\0'; + return 0; +} + +int pfi_header_read(FILE *in, struct pfi_header *head) +{ + char mode[PFI_KEYWORD_LEN]; + char buf[256]; + + if (fread(buf, 1, PFI_MAGIC_LEN, in) != PFI_MAGIC_LEN) { + errmsg("cannot read %d bytes", PFI_MAGIC_LEN); + perror("fread"); + return -1; + } + + if (memcmp(buf, PFI_MAGIC, PFI_MAGIC_LEN) != 0) { + if (memcmp(buf, PFI_DATA, PFI_MAGIC_LEN) == 0) + return 1; + + errmsg("PFI magic \"%s\" not found", PFI_MAGIC); + return -1; + } + + while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') { + char *value; + char *end; + value = strchr(buf, '='); + if (value == NULL) + return PFI_ENOHEADER; + + *value = '\0'; + value++; + end = strchr(value, '\n'); + if (end) + *end = '\0'; + + if (pfi_header_setvalue(head, buf, value)) + return PFI_ENOHEADER; + } + + if (check_valid(head) != 0) + return PFI_ENOHEADER; + + /* set current mode no. in head */ + pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN); + if (head->mode_no > get_mode_no(mode)) { + return PFI_EMODE; + } + head->mode_no = get_mode_no(mode); + return 0; +} +int +read_pfi_ubi(struct pfi_header *pfi_hd, struct pfi_ubi **pfi_ubi, + const char *label) +{ + int err = 0; + const char** tmp_names = NULL; + char tmp_str[PFI_KEYWORD_LEN]; + bootenv_list_t ubi_id_list = NULL; + bootenv_list_t ubi_name_list = NULL; + struct pfi_ubi *res; + uint32_t i; + size_t size; + + res = (struct pfi_ubi *) calloc(1, sizeof(struct pfi_ubi)); + if (!res) + return -ENOMEM; + + err = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); + if (err != 0) { + errmsg("cannot read 'size' from PFI."); + goto err; + } + + err = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); + if (err != 0) { + errmsg("cannot read 'crc' from PFI."); + goto err; + } + + err = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN); + if (err != 0) { + errmsg("cannot read 'ubi_ids' from PFI."); + goto err; + } + + err = bootenv_list_create(&ubi_id_list); + if (err != 0) { + goto err; + } + err = bootenv_list_create(&ubi_name_list); + if (err != 0) { + goto err; + } + + err = bootenv_list_import(ubi_id_list, tmp_str); + if (err != 0) { + errmsg("cannot translate PFI value: %s", tmp_str); + goto err; + } + + err = bootenv_list_to_num_vector(ubi_id_list, &size, + &(res->ids)); + res->ids_size = size; + if (err != 0) { + errmsg("cannot create numeric value array: %s", tmp_str); + goto err; + } + + if (res->ids_size == 0) { + err = -1; + errmsg("sanity check failed: No ubi_ids specified."); + goto err; + } + + err = pfi_header_getstring(pfi_hd, "ubi_type", + tmp_str, PFI_KEYWORD_LEN); + if (err != 0) { + errmsg("cannot read 'ubi_type' from PFI."); + goto err; + } + if (strcmp(tmp_str, "static") == 0) + res->vol_type = UBI_VID_STATIC; + else if (strcmp(tmp_str, "dynamic") == 0) + res->vol_type = UBI_VID_DYNAMIC; + else { + errmsg("unknown ubi_type in PFI."); + goto err; + } + + err = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment)); + if (err != 0) { + errmsg("cannot read 'ubi_alignment' from PFI."); + goto err; + } + + err = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size)); + if (err != 0) { + errmsg("cannot read 'ubi_size' from PFI."); + goto err; + } + + err = pfi_header_getstring(pfi_hd, "ubi_names", + tmp_str, PFI_KEYWORD_LEN); + if (err != 0) { + errmsg("cannot read 'ubi_names' from PFI."); + goto err; + } + + err = bootenv_list_import(ubi_name_list, tmp_str); + if (err != 0) { + errmsg("cannot translate PFI value: %s", tmp_str); + goto err; + } + err = bootenv_list_to_vector(ubi_name_list, &size, + &(tmp_names)); + res->names_size = size; + if (err != 0) { + errmsg("cannot create string array: %s", tmp_str); + goto err; + } + + if (res->names_size != res->ids_size) { + errmsg("sanity check failed: ubi_ids list does not match " + "sizeof ubi_names list."); + err = -1; + } + + /* copy tmp_names to own structure */ + res->names = calloc(1, res->names_size * sizeof (char*)); + if (res->names == NULL) + goto err; + + for (i = 0; i < res->names_size; i++) { + res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char)); + if (res->names[i] == NULL) + goto err; + strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1); + } + + goto out; + + err: + if (res) { + if (res->names) { + for (i = 0; i < res->names_size; i++) { + if (res->names[i]) { + free(res->names[i]); + } + } + free(res->names); + } + if (res->ids) { + free(res->ids); + } + free(res); + res = NULL; + } + + out: + bootenv_list_destroy(&ubi_id_list); + bootenv_list_destroy(&ubi_name_list); + if (tmp_names != NULL) + free(tmp_names); + *pfi_ubi = res; + return err; +} + +int +free_pfi_ubi(struct pfi_ubi **pfi_ubi) +{ + size_t i; + struct pfi_ubi *tmp = *pfi_ubi; + if (tmp) { + if (tmp->ids) + free(tmp->ids); + if (tmp->names) { + for (i = 0; i < tmp->names_size; i++) { + if (tmp->names[i]) { + free(tmp->names[i]); + } + } + free(tmp->names); + } + free(tmp); + } + *pfi_ubi = NULL; + + return 0; +} + +int read_pfi_headers(struct list_entry **ubi_list, FILE *fp_pfi) +{ + int err = 0; + long long data_offs = 0; + long fpos; + char mode[PFI_KEYWORD_LEN]; + char label[PFI_LABEL_LEN]; + struct list_entry *tmp; + + *ubi_list = list_empty(); struct pfi_ubi *ubi = NULL; + struct pfi_header *pfi_header = NULL; + + /* read all headers from PFI and store them in lists */ + err = pfi_header_init(&pfi_header); + if (err != 0) { + errmsg("cannot initialize pfi header."); + goto err; + } + while ((err == 0) && !feof(fp_pfi)) { + err = pfi_header_read(fp_pfi, pfi_header); + if (err != 0) { + if (err == 1) { + err = 0; + break; /* data section starts, + all headers read */ + } + else { + goto err; + } + } + err = pfi_header_getstring(pfi_header, "label", label, + PFI_LABEL_LEN); + if (err != 0) { + errmsg("cannot read 'label' from PFI."); + goto err; + } + err = pfi_header_getstring(pfi_header, "mode", mode, + PFI_KEYWORD_LEN); + if (err != 0) { + errmsg("cannot read 'mode' from PFI."); + goto err; + } + if (strcmp(mode, "ubi") == 0) { + err = read_pfi_ubi(pfi_header, &ubi, label); + if (err != 0) { + goto err; + } + *ubi_list = append_elem(ubi, *ubi_list); + } + else { + errmsg("recvieved unknown mode from PFI: %s", mode); + goto err; + } + ubi->data_offs = data_offs; + data_offs += ubi->data_size; + } + + fpos = ftell(fp_pfi); + if (fpos == -1) { + errmsg("ftell returned error"); + perror("ftell"); + goto err; + } + + list_for_each(ubi, tmp, *ubi_list) + ubi->data_offs += fpos; + + goto out; + + err: + *ubi_list = remove_all((free_func_t)&free_pfi_ubi, *ubi_list); + out: + pfi_header_destroy(&pfi_header); + return err; + +} diff --git a/ubi-utils/src/libubigen.c b/ubi-utils/src/libubigen.c index 6aef291..c3a0f9c 100644 --- a/ubi-utils/src/libubigen.c +++ b/ubi-utils/src/libubigen.c @@ -1,5 +1,6 @@ /* * Copyright (c) International Business Machines Corp., 2006 + * Copyright (C) 2008 Nokia Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,473 +15,297 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Generating UBI images. * - * Author: Oliver Lohmann - * - * Add UBI headers to binary data. + * Authors: Oliver Lohmann + * Artem Bityutskiy */ #include <stdlib.h> #include <stdint.h> #include <stdio.h> -#include <errno.h> +#include <unistd.h> #include <string.h> -#include <mtd/ubi-header.h> -#include "config.h" -#include "ubigen.h" +#include <mtd/ubi-header.h> +#include <libubigen.h> #include "crc32.h" +#include "common.h" -#define UBI_NAME_SIZE 256 -#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -static uint32_t crc32_table[256]; - -struct ubi_info { - struct ubi_vid_hdr* v; /* Volume ID header */ - struct ubi_ec_hdr* ec; /* Erase count header */ - - FILE* fp_in; /* Input Stream */ - FILE* fp_out; /* Output stream */ - - size_t peb_size; /* Physical EB size in bytes */ - size_t leb_size; /* Size of a logical EB in a physical EB */ - size_t leb_total; /* Total input size in logical EB */ - size_t alignment; /* Block alignment */ - size_t data_pad; /* Size of padding in each physical EB */ - - size_t bytes_total; /* Total input size in bytes */ - size_t bytes_read; /* Nymber of read bytes (total) */ - - uint32_t blks_written; /* Number of written logical EB */ - - uint8_t* buf; /* Allocated buffer */ - uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */ - uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */ - uint8_t* ptr_data; /* Pointer to data region in buf */ -}; - - -static uint32_t -byte_to_blk(uint64_t byte, uint32_t peb_size) -{ - return (byte % peb_size) == 0 - ? (byte / peb_size) - : (byte / peb_size) + 1; -} +#define PROGRAM_NAME "libubigen" -static int -validate_ubi_info(ubi_info_t u) -{ - if ((u->v->vol_type != UBI_VID_DYNAMIC) && - (u->v->vol_type != UBI_VID_STATIC)) { - return EUBIGEN_INVALID_TYPE; - } - - if (__be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) { - return EUBIGEN_INVALID_HDR_OFFSET; - } - - return 0; -} - -static int -skip_blks(ubi_info_t u, uint32_t blks) -{ - uint32_t i; - size_t read = 0, to_read = 0; - - /* Step to a maximum of leb_total - 1 to keep the - restrictions. */ - for (i = 0; i < MIN(blks, u->leb_total-1); i++) { - /* Read in data */ - to_read = MIN(u->leb_size, - (u->bytes_total - u->bytes_read)); - read = fread(u->ptr_data, 1, to_read, u->fp_in); - if (read != to_read) { - return -EIO; - } - u->bytes_read += read; - u->blks_written++; - } - - return 0; -} - -static void -clear_buf(ubi_info_t u) -{ - memset(u->buf, 0xff, u->peb_size); -} - -static void -write_ec_hdr(ubi_info_t u) +/** + * ubigen_create_empty_vtbl - creates empty volume table. + * @size: physical eraseblock size on input, size of the volume table on output + * + * This function creates an empty volume table and returns a pointer to it in + * case of success and %NULL in case of failure. The volume table size is + * returned in @size which has to contain PEB size on input. + */ +struct ubi_vtbl_record *ubigen_create_empty_vtbl(int *size) { - memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE); -} + struct ubi_vtbl_record *vtbl; + int i; -static int -fill_data_buffer_from_file(ubi_info_t u, size_t* read) -{ - size_t to_read = 0; + if (*size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE) + *size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; - if (u-> fp_in == NULL) - return -EIO; + vtbl = calloc(1, *size); + if (!vtbl) + return NULL; - to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read)); - *read = fread(u->ptr_data, 1, to_read, u->fp_in); - if (*read != to_read) { - return -EIO; + for (i = 0; i < UBI_MAX_VOLUMES; i++) { + uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i], + UBI_VTBL_RECORD_SIZE_CRC); + vtbl[i].crc = __cpu_to_be32(crc); } - return 0; -} -static void -add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action) -{ - uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - u->ptr_data, data_size); - - u->v->data_size = __cpu_to_be32(data_size); - u->v->data_crc = __cpu_to_be32(crc); - - if (action & BROKEN_DATA_CRC) { - u->v->data_crc = - __cpu_to_be32(__be32_to_cpu(u->v->data_crc) + 1); - } - if (action & BROKEN_DATA_SIZE) { - u->v->data_size = - __cpu_to_be32(__be32_to_cpu(u->v->data_size) + 1); - } + return vtbl; } -static void -write_vid_hdr(ubi_info_t u, ubigen_action_t action) +/** + * ubigen_info_init - initialize libubigen. + * @ui: libubigen information + * @peb_size: flash physical eraseblock size + * @min_io_size: flash minimum input/output unit size + * @subpage_size: flash sub-page, if present (has to be equivalent to + * @min_io_size if does not exist) + * @vid_hdr_offs: offset of the VID header + * @ubi_ver: UBI version + * @ec: initial erase counter + */ +void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, + int subpage_size, int vid_hdr_offs, int ubi_ver, + long long ec) { - uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - u->v, UBI_VID_HDR_SIZE_CRC); - /* Write VID header */ - u->v->hdr_crc = __cpu_to_be32(crc); - if (action & BROKEN_HDR_CRC) { - u->v->hdr_crc = __cpu_to_be32(__be32_to_cpu(u->v->hdr_crc) + 1); - } - memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE); + if (!vid_hdr_offs) + vid_hdr_offs = subpage_size; + + ui->peb_size = peb_size; + ui->min_io_size = min_io_size; + ui->vid_hdr_offs = vid_hdr_offs; + ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1; + ui->data_offs /= min_io_size; + ui->data_offs *= min_io_size; + ui->leb_size = peb_size - ui->data_offs; + ui->ubi_ver = ubi_ver; + ui->ec = ec; } -static int -write_to_output_stream(ubi_info_t u) +/** + * ubigen_add_volume - add a volume to the volume table. + * @vol_id: volume ID + * @bytes: volume size in bytes + * @alignment: volume alignment + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @name: volume name + * @ui: libubigen information + * @vtbl: volume table to add to + * + * This function adds volume described by input parameters to the volume table + * @vtbl. + */ +void ubigen_add_volume(const struct ubigen_info *ui, + const struct ubigen_vol_info *vi, + struct ubi_vtbl_record *vtbl) { - size_t written; - - written = fwrite(u->buf, 1, u->peb_size, u->fp_out); - if (written != u->peb_size) { - return -EIO; - } - return 0; + struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id]; + uint32_t tmp; + + memset(vtbl_rec, '\0', sizeof(struct ubi_vtbl_record)); + tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size; + vtbl_rec->reserved_pebs = __cpu_to_be32(tmp); + vtbl_rec->alignment = __cpu_to_be32(vi->alignment); + vtbl_rec->vol_type = vi->type; + tmp = ui->leb_size % vi->alignment; + vtbl_rec->data_pad = __cpu_to_be32(tmp); + + memcpy(vtbl_rec->name, vi->name, vi->name_len); + vtbl_rec->name[vi->name_len] = '\0'; + vtbl_rec->name_len = __cpu_to_be16(vi->name_len); + + tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); + vtbl_rec->crc = __cpu_to_be32(tmp); } -int -ubigen_write_leb(ubi_info_t u, ubigen_action_t action) +/** + * init_ec_hdr - initialize EC header. + * @ui: libubigen information + * @hdr: the EC header to initialize + */ +static void init_ec_hdr(const struct ubigen_info *ui, + struct ubi_ec_hdr *hdr) { - int rc = 0; - size_t read = 0; - - clear_buf(u); - write_ec_hdr(u); - - rc = fill_data_buffer_from_file(u, &read); - if (rc != 0) - return rc; - - if (u->v->vol_type == UBI_VID_STATIC) { - add_static_info(u, read, action); - } + uint32_t crc; - u->v->lnum = __cpu_to_be32(u->blks_written); + memset(hdr, '\0', sizeof(struct ubi_ec_hdr)); - if (action & MARK_AS_UPDATE) { - u->v->copy_flag = (u->v->copy_flag)++; - } + hdr->magic = __cpu_to_be32(UBI_EC_HDR_MAGIC); + hdr->version = ui->ubi_ver; + hdr->ec = __cpu_to_be64(ui->ec); + hdr->vid_hdr_offset = __cpu_to_be32(ui->vid_hdr_offs); - write_vid_hdr(u, action); - rc = write_to_output_stream(u); - if (rc != 0) - return rc; + hdr->data_offset = __cpu_to_be32(ui->data_offs); - /* Update current handle */ - u->bytes_read += read; - u->blks_written++; - return 0; + crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); + hdr->hdr_crc = __cpu_to_be32(crc); } -int -ubigen_write_complete(ubi_info_t u) +/** + * init_vid_hdr - initialize VID header. + * @ui: libubigen information + * @vi: volume information + * @hdr: the VID header to initialize + * @lnum: logical eraseblock number + * @data: the contents of the LEB (static volumes only) + * @data_size: amount of data in this LEB (static volumes only) + * + * Note, @used_ebs, @data and @data_size are ignored in case of dynamic + * volumes. + */ +static void init_vid_hdr(const struct ubigen_info *ui, + const struct ubigen_vol_info *vi, + struct ubi_vid_hdr *hdr, int lnum, + const void *data, int data_size) { - size_t i; - int rc = 0; + uint32_t crc; - for (i = 0; i < u->leb_total; i++) { - rc = ubigen_write_leb(u, NO_ERROR); - if (rc != 0) - return rc; + memset(hdr, '\0', sizeof(struct ubi_vid_hdr)); + + hdr->magic = __cpu_to_be32(UBI_VID_HDR_MAGIC); + hdr->version = ui->ubi_ver; + hdr->vol_type = vi->type; + hdr->vol_id = __cpu_to_be32(vi->id); + hdr->lnum = __cpu_to_be32(lnum); + hdr->data_pad = __cpu_to_be32(vi->data_pad); + hdr->compat = vi->compat; + + if (vi->type == UBI_VID_STATIC) { + hdr->data_size = __cpu_to_be32(data_size); + hdr->used_ebs = __cpu_to_be32(vi->used_ebs); + crc = crc32(UBI_CRC32_INIT, data, data_size); + hdr->data_crc = __cpu_to_be32(crc); } - return 0; + crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC); + hdr->hdr_crc = __cpu_to_be32(crc); } -int -ubigen_write_broken_update(ubi_info_t u, uint32_t blk) +/** + * ubigen_write_volume - write UBI volume. + * @ui: libubigen information + * @vi: volume information + * @bytes: volume size in bytes + * @in: input file descriptor (has to be properly seeked) + * @out: output file descriptor + * + * This function reads the contents of the volume from the input file @in and + * writes the UBI volume to the output file @out. Returns zero on success and + * %-1 on failure. + */ +int ubigen_write_volume(const struct ubigen_info *ui, + const struct ubigen_vol_info *vi, + long long bytes, FILE *in, FILE *out) { - int rc = 0; - - rc = skip_blks(u, blk); - if (rc != 0) - return rc; - - rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC); - if (rc != 0) - return rc; - - - return 0; -} + int len = vi->usable_leb_size, rd, lnum = 0; + char inbuf[ui->leb_size], outbuf[ui->peb_size]; + + memset(outbuf, 0xFF, ui->data_offs); + init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf); + + while (bytes) { + int l; + struct ubi_vid_hdr *vid_hdr; + + if (bytes < len) + len = bytes; + bytes -= len; + + l = len; + do { + rd = fread(inbuf + len - l, 1, l, in); + if (rd == 0) { + if (ferror(in)) + errmsg("cannot read %d bytes from the input" + " file", l); + else + errmsg("not enough data in the input file"); + return -1; + } + + l -= rd; + } while (l); + + vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); + init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len); + + memcpy(outbuf + ui->data_offs, inbuf, len); + memset(outbuf + ui->data_offs + len, 0xFF, + ui->peb_size - ui->data_offs - len); + + if (fwrite(outbuf, 1, ui->peb_size, out) != ui->peb_size) { + errmsg("cannot write %d bytes from the output" + " file", l); + return -1; + } -void -dump_info(ubi_info_t u ubi_unused) -{ -#ifdef DEBUG - int err = 0; - if (!u) { - fprintf(stderr, "<empty>"); - return; - } - if (!u->ec) { - fprintf(stderr, "<ec-empty>"); - err = 1; - } - if (!u->v) { - fprintf(stderr, "<v-empty>"); - err = 1; + lnum += 1; } - if (err) return; - - fprintf(stderr, "ubi volume\n"); - fprintf(stderr, "version : %8d\n", u->v->version); - fprintf(stderr, "vol_id : %8d\n", __be32_to_cpu(u->v->vol_id)); - fprintf(stderr, "vol_type : %8s\n", - u->v->vol_type == UBI_VID_STATIC ? - "static" : "dynamic"); - fprintf(stderr, "used_ebs : %8d\n", - __be32_to_cpu(u->v->used_ebs)); - fprintf(stderr, "peb_size : 0x%08x\n", u->peb_size); - fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size); - fprintf(stderr, "data_pad : 0x%08x\n", - __be32_to_cpu(u->v->data_pad)); - fprintf(stderr, "leb_total : %8d\n", u->leb_total); - fprintf(stderr, "header offs : 0x%08x\n", - __be32_to_cpu(u->ec->vid_hdr_offset)); - fprintf(stderr, "bytes_total : %8d\n", u->bytes_total); - fprintf(stderr, " + in MiB : %8.2f M\n", - ((float)(u->bytes_total)) / 1024 / 1024); - fprintf(stderr, "-------------------------------\n\n"); -#else - return; -#endif -} -int -ubigen_destroy(ubi_info_t *u) -{ - if (u == NULL) - return -EINVAL; - - ubi_info_t tmp = *u; - - if (tmp) { - if (tmp->v) - free(tmp->v); - if (tmp->ec) - free(tmp->ec); - if (tmp->buf) - free(tmp->buf); - free(tmp); - } - *u = NULL; return 0; } -void -ubigen_init(void) -{ - init_crc32_table(crc32_table); -} - -int -ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type, - uint32_t peb_size, uint64_t ec, uint32_t alignment, - uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag, - size_t data_size, FILE* fp_in, FILE* fp_out) +/** + * ubigen_write_layout_vol - write UBI layout volume + * @ui: libubigen information + * @vtbl: volume table + * @out: output file stream + * + * This function creates the UBI layout volume which contains 2 copies of the + * volume table. Returns zero in case of success and %-1 in case of failure. + */ +int ubigen_write_layout_vol(const struct ubigen_info *ui, + struct ubi_vtbl_record *vtbl, FILE *out) { - int rc = 0; - ubi_info_t res = NULL; - uint32_t crc; - uint32_t data_offset; - - if (alignment == 0) { - rc = EUBIGEN_INVALID_ALIGNMENT; - goto ubigen_create_err; - } - if ((fp_in == NULL) || (fp_out == NULL)) { - rc = -EINVAL; - goto ubigen_create_err; - } - - res = (ubi_info_t) calloc(1, sizeof(struct ubi_info)); - if (res == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr)); - if (res->v == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr)); - if (res->ec == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - /* data which is needed in the general process */ - vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET; - data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE; - res->bytes_total = data_size; - res->peb_size = peb_size ? peb_size : DEFAULT_BLOCKSIZE; - res->data_pad = (res->peb_size - data_offset) % alignment; - res->leb_size = res->peb_size - data_offset - res->data_pad; - res->leb_total = byte_to_blk(data_size, res->leb_size); - res->alignment = alignment; - - if ((res->peb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) { - rc = EUBIGEN_TOO_SMALL_EB; - goto ubigen_create_err; - } - res->fp_in = fp_in; - res->fp_out = fp_out; - - /* vid hdr data which doesn't change */ - res->v->magic = __cpu_to_be32(UBI_VID_HDR_MAGIC); - res->v->version = version ? version : UBI_VERSION; - res->v->vol_type = vol_type; - res->v->vol_id = __cpu_to_be32(vol_id); - res->v->compat = compat_flag; - res->v->data_pad = __cpu_to_be32(res->data_pad); - - /* static only: used_ebs */ - if (res->v->vol_type == UBI_VID_STATIC) { - res->v->used_ebs = __cpu_to_be32(byte_to_blk - (res->bytes_total, - res->leb_size)); - } - - /* ec hdr (fixed, doesn't change) */ - res->ec->magic = __cpu_to_be32(UBI_EC_HDR_MAGIC); - res->ec->version = version ? version : UBI_VERSION; - res->ec->ec = __cpu_to_be64(ec); - res->ec->vid_hdr_offset = __cpu_to_be32(vid_hdr_offset); - - res->ec->data_offset = __cpu_to_be32(data_offset); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec, - UBI_EC_HDR_SIZE_CRC); - res->ec->hdr_crc = __cpu_to_be32(crc); - - /* prepare a read buffer */ - res->buf = (uint8_t*) malloc (res->peb_size * sizeof(uint8_t)); - if (res->buf == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - /* point to distinct regions within the buffer */ - res->ptr_ec_hdr = res->buf; - res->ptr_vid_hdr = res->buf + __be32_to_cpu(res->ec->vid_hdr_offset); - res->ptr_data = res->buf + __be32_to_cpu(res->ec->vid_hdr_offset) - + UBI_VID_HDR_SIZE; - - rc = validate_ubi_info(res); - if (rc != 0) { - fprintf(stderr, "Volume validation failed: %d\n", rc); - goto ubigen_create_err; - } - - dump_info(res); - *u = res; - return rc; - -ubigen_create_err: - if (res) { - if (res->v) - free(res->v); - if (res->ec) - free(res->ec); - if (res->buf) - free(res->buf); - free(res); + int size = ui->leb_size; + struct ubigen_vol_info vi; + char outbuf[ui->peb_size]; + struct ubi_vid_hdr *vid_hdr; + + if (size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE) + size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; + + vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS; + vi.id = UBI_LAYOUT_VOL_ID; + vi.alignment = 1; + vi.data_pad = 0; + vi.usable_leb_size = ui->leb_size; + vi.type = UBI_VID_DYNAMIC; + vi.name = UBI_LAYOUT_VOLUME_NAME; + vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME); + vi.compat = UBI_LAYOUT_VOLUME_COMPAT; + + memset(outbuf, 0xFF, ui->data_offs); + vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); + init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf); + memcpy(outbuf + ui->data_offs, vtbl, size); + memset(outbuf + ui->data_offs + size, 0xFF, + ui->peb_size - ui->data_offs - size); + + init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0); + size = fwrite(outbuf, 1, ui->peb_size, out); + if (size == ui->peb_size) { + init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0); + size = fwrite(outbuf, 1, ui->peb_size, out); + if (size != ui->peb_size) { + errmsg("cannot write %d bytes", ui->peb_size); + perror("write"); + return -1; + } } - *u = NULL; - return rc; -} - -int -ubigen_get_leb_size(ubi_info_t u, size_t* size) -{ - if (u == NULL) - return -EINVAL; - - *size = u->leb_size; - return 0; -} - - -int -ubigen_get_leb_total(ubi_info_t u, size_t* total) -{ - if (u == NULL) - return -EINVAL; - - *total = u->leb_total; - return 0; -} - -int -ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, - const char* vol_name, struct ubi_vtbl_record *lvol_rec) -{ - uint32_t crc; - - if ((u == NULL) || (vol_name == NULL)) - return -EINVAL; - - memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE); - - lvol_rec->reserved_pebs = - __cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size)); - lvol_rec->alignment = __cpu_to_be32(u->alignment); - lvol_rec->data_pad = u->v->data_pad; - lvol_rec->vol_type = u->v->vol_type; - - lvol_rec->name_len = - __cpu_to_be16((uint16_t)strlen((const char*)vol_name)); - - memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - lvol_rec, UBI_VTBL_RECORD_SIZE_CRC); - lvol_rec->crc = __cpu_to_be32(crc); return 0; } diff --git a/ubi-utils/src/list.c b/ubi-utils/src/list.c index 6eb716b..a701158 100644 --- a/ubi-utils/src/list.c +++ b/ubi-utils/src/list.c @@ -24,36 +24,30 @@ #include "list.h" -list_t -mk_empty(void) -{ - return (list_t) NULL; -} - int -is_empty(list_t l) +is_empty(struct list_entry *l) { return l == NULL; } info_t -head(list_t l) +head(struct list_entry *l) { assert(!is_empty(l)); return l->info; } -list_t -tail(list_t l) +struct list_entry * +tail(struct list_entry *l) { assert(!is_empty(l)); return l->next; } -list_t -remove_head(list_t l) +struct list_entry * +remove_head(struct list_entry *l) { - list_t res; + struct list_entry *res; assert(!is_empty(l)); res = l->next; @@ -61,10 +55,10 @@ remove_head(list_t l) return res; } -list_t -cons(info_t e, list_t l) +struct list_entry * +cons(info_t e, struct list_entry *l) { - list_t res = malloc(sizeof(*l)); + struct list_entry *res = malloc(sizeof(*l)); if (!res) return NULL; res->info = e; @@ -73,14 +67,14 @@ cons(info_t e, list_t l) return res; } -list_t -prepend_elem(info_t e, list_t l) +struct list_entry * +prepend_elem(info_t e, struct list_entry *l) { return cons(e,l); } -list_t -append_elem(info_t e, list_t l) +struct list_entry * +append_elem(info_t e, struct list_entry *l) { if (is_empty(l)) { return cons(e,l); @@ -90,8 +84,8 @@ append_elem(info_t e, list_t l) return l; } -list_t -insert_sorted(cmp_func_t cmp, info_t e, list_t l) +struct list_entry * +insert_sorted(cmp_func_t cmp, info_t e, struct list_entry *l) { if (is_empty(l)) return cons(e, l); @@ -112,12 +106,12 @@ insert_sorted(cmp_func_t cmp, info_t e, list_t l) return NULL; } -list_t -remove_all(free_func_t free_func, list_t l) +struct list_entry * +remove_all(free_func_t free_func, struct list_entry *l) { if (is_empty(l)) return l; - list_t lnext = l->next; + struct list_entry *lnext = l->next; if (free_func && l->info) { free_func(&(l->info)); @@ -129,7 +123,7 @@ remove_all(free_func_t free_func, list_t l) info_t -is_in(cmp_func_t cmp, info_t e, list_t l) +is_in(cmp_func_t cmp, info_t e, struct list_entry *l) { return (is_empty(l)) @@ -139,11 +133,11 @@ is_in(cmp_func_t cmp, info_t e, list_t l) void -apply(process_func_t process_func, list_t l) +apply(process_func_t process_func, struct list_entry *l) { - list_t ptr; + struct list_entry *ptr; void *i; - foreach(i, ptr, l) { + list_for_each(i, ptr, l) { process_func(i); } } diff --git a/ubi-utils/src/list.h b/ubi-utils/src/list.h index e8452a2..58bfe7e 100644 --- a/ubi-utils/src/list.h +++ b/ubi-utils/src/list.h @@ -1,5 +1,3 @@ -#ifndef __LIST_H__ -#define __LIST_H__ /* * Copyright (c) International Business Machines Corp., 2006 * @@ -20,37 +18,44 @@ * Author: Oliver Lohmann */ +#ifndef __UBIUTILS_LIST_H__ +#define __UBIUTILS_LIST_H__ + #include <stdint.h> -#define foreach(elem, ptr, list) \ - for (elem = list != NULL ? (typeof(elem)) head(list) \ - : NULL, ptr = list; \ - ptr != NULL; \ - ptr = tail(ptr), \ - elem = (typeof(elem)) ptr ? head(ptr) : NULL) +#define list_for_each(elem, ptr, list) \ + for ((elem) = (list) != NULL ? (typeof(elem)) head(list) \ + : NULL, (ptr) = (list); \ + ptr != NULL; \ + ptr = tail(ptr), \ + elem = (typeof(elem)) (ptr) ? head(ptr) : NULL) + +static inline struct list_entry *list_empty(void) +{ + return NULL; +} -typedef struct node* list_t; typedef void* info_t; typedef int (*free_func_t)(info_t*); typedef int (*cmp_func_t)(info_t, info_t); typedef void (*process_func_t)(info_t); -struct node { - list_t next; +struct list_entry { + struct list_entry *next; info_t info; }; -list_t mk_empty(void); -int is_empty(list_t l); -info_t is_in(cmp_func_t cmp, info_t e, list_t l); -info_t head(list_t l); -list_t tail(list_t l); -list_t remove_head(list_t l); -list_t cons(info_t e, list_t l); -list_t prepend_elem(info_t e, list_t); -list_t append_elem(info_t e, list_t); -list_t remove_all(free_func_t free_func, list_t l); -list_t insert_sorted(cmp_func_t cmp_func, info_t e, list_t l); -void apply(process_func_t process_func, list_t l); - -#endif /* __LIST_H__ */ +struct list_entry *list_empty(void); +int is_empty(struct list_entry *l); +info_t is_in(cmp_func_t cmp, info_t e, struct list_entry *l); +info_t head(struct list_entry *l); +struct list_entry *tail(struct list_entry *l); +struct list_entry *remove_head(struct list_entry *l); +struct list_entry *cons(info_t e, struct list_entry *l); +struct list_entry *prepend_elem(info_t e, struct list_entry *); +struct list_entry *append_elem(info_t e, struct list_entry *); +struct list_entry *remove_all(free_func_t free_func, struct list_entry *l); +struct list_entry *insert_sorted(cmp_func_t cmp_func, info_t e, struct list_entry *l); +void apply(process_func_t process_func, struct list_entry *l); + +#endif /* !__UBIUTILS_LIST_H__ */ diff --git a/ubi-utils/src/peb.c b/ubi-utils/src/peb.c deleted file mode 100644 index 160a463..0000000 --- a/ubi-utils/src/peb.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#include "peb.h" - -int -peb_cmp(peb_t eb_1, peb_t eb_2) -{ - assert(eb_1); - assert(eb_2); - - return eb_1->num == eb_2->num ? 0 - : eb_1->num > eb_2->num ? 1 : -1; -} - -int -peb_new(uint32_t eb_num, uint32_t peb_size, peb_t *peb) -{ - int rc = 0; - - peb_t res = (peb_t) malloc(sizeof(struct peb)); - if (!res) { - rc = -ENOMEM; - goto err; - } - - res->num = eb_num; - res->size = peb_size; - res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t)); - if (!res->data) { - rc = -ENOMEM; - goto err; - } - memset(res->data, 0xff, res->size); - - *peb = res; - return 0; -err: - if (res) { - if (res->data) - free(res->data); - free(res); - } - *peb = NULL; - return rc; -} - -int -peb_fill(peb_t peb, uint8_t* buf, size_t buf_size) -{ - if (!peb) - return -EINVAL; - - if (buf_size > peb->size) - return -EINVAL; - - memcpy(peb->data, buf, buf_size); - return 0; -} - -int -peb_write(FILE* fp_out, peb_t peb) -{ - size_t written = 0; - - if (peb == NULL) - return -EINVAL; - - written = fwrite(peb->data, 1, peb->size, fp_out); - - if (written != peb->size) - return -EIO; - - return 0; -} - -int -peb_free(peb_t* peb) -{ - peb_t tmp = *peb; - if (tmp) { - if (tmp->data) - free(tmp->data); - free(tmp); - } - *peb = NULL; - - return 0; -} - -void peb_dump(FILE* fp_out, peb_t peb) -{ - fprintf(fp_out, "num: %08d\tsize: 0x%08x\n", peb->num, peb->size); -} diff --git a/ubi-utils/src/peb.h b/ubi-utils/src/peb.h deleted file mode 100644 index 246bce8..0000000 --- a/ubi-utils/src/peb.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __RAW_BLOCK_H__ -#define __RAW_BLOCK_H__ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Oliver Lohmann - */ - -#include <stdint.h> -#include <stdio.h> - -typedef struct peb *peb_t; -struct peb { - uint32_t num; /* Physical eraseblock number - * in the RAW file. */ - uint32_t size; /* Data Size (equals physical - * erase block size) */ - uint8_t* data; /* Data buffer */ -}; - -int peb_new(uint32_t peb_num, uint32_t peb_size, peb_t* peb); -int peb_free(peb_t* peb); -int peb_cmp(peb_t peb_1, peb_t peb_2); -int peb_write(FILE* fp_out, peb_t peb); -void peb_dump(FILE* fp_out, peb_t peb); - -#endif /* __RAW_BLOCK_H__ */ diff --git a/ubi-utils/src/pfi.c b/ubi-utils/src/pfi.c deleted file mode 100644 index fa835e2..0000000 --- a/ubi-utils/src/pfi.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * @file pfi.c - * - * @author Oliver Lohmann - * Andreas Arnez - * Joern Engel - * Frank Haverkamp - * - * @brief libpfi holds all code to create and process pfi files. - * - * <oliloh@de.ibm.com> Wed Feb 8 11:38:22 CET 2006: Initial creation. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <syslog.h> -#include <stdarg.h> -#include <errno.h> - -#include "pfi.h" - -#define PFI_MAGIC "PFI!\n" -#define PFI_DATA "DATA\n" /* The same size as PFI_MAGIC */ -#define PFI_MAGIC_LEN 5 - -static const char copyright [] __attribute__((unused)) = - "Copyright (c) International Business Machines Corp., 2006"; - -enum key_id { - /* version 1 */ - key_version, /* must be index position 0! */ - key_mode, - key_size, - key_crc, - key_label, - key_flags, - key_ubi_ids, - key_ubi_size, - key_ubi_type, - key_ubi_names, - key_ubi_alignment, - key_raw_starts, - key_raw_total_size, - num_keys, -}; - -struct pfi_header { - char defined[num_keys]; /* reserve all possible keys even if - version does not require this. */ - int mode_no; /* current mode no. -> can only increase */ - union { - char *str; - uint32_t num; - } value[num_keys]; -}; - - -#define PFI_MANDATORY 0x0001 -#define PFI_STRING 0x0002 -#define PFI_LISTVALUE 0x0004 /* comma seperated list of nums */ -#define PFI_MANDATORY_UBI 0x0008 -#define PFI_MANDATORY_RAW 0x0010 - -struct key_descriptor { - enum key_id id; - const char *name; - uint32_t flags; -}; - -static const struct key_descriptor key_desc_v1[] = { - { key_version, "version", PFI_MANDATORY }, - { key_mode, "mode", PFI_MANDATORY | PFI_STRING }, - { key_size, "size", PFI_MANDATORY }, - { key_crc, "crc", PFI_MANDATORY }, - { key_label, "label", PFI_MANDATORY | PFI_STRING }, - { key_flags, "flags", PFI_MANDATORY }, - { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI }, - { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI }, - { key_raw_starts, "raw_starts", PFI_MANDATORY_RAW | PFI_STRING }, - { key_raw_total_size, "raw_total_size", PFI_MANDATORY_RAW }, -}; - -static const struct key_descriptor *key_descriptors[] = { - NULL, - key_desc_v1, /* version 1 */ -}; - -static const int key_descriptors_max[] = { - 0, /* version 0 */ - sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */ -}; - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -static const char* modes[] = {"raw", "ubi"}; /* order isn't arbitrary! */ - -/* latest version contains all possible keys */ -static const struct key_descriptor *key_desc = key_desc_v1; - -#define PFI_IS_UBI(mode) \ - (((mode) != NULL) && (strcmp("ubi", (mode)) == 0)) - -#define PFI_IS_RAW(mode) \ - (((mode) != NULL) && (strcmp("raw", (mode)) == 0)) - -/** - * @return <0 On Error. - * >=0 Mode no. - */ -static int -get_mode_no(const char* mode) -{ - int i; - - for (i = 0; i < (int)ARRAY_SIZE(modes); i++) - if (strcmp(mode, modes[i]) == 0) - return i; - return -1; -} - -static int -find_key_by_name (const char *name) -{ - int i; - - for (i = 0; i < num_keys; i++) { - if (strcmp(name, key_desc[i].name) == 0) - return i; - } - return -1; -} - -static int -check_valid (pfi_header head) -{ - int i; - int max_keys; - uint32_t version; - const char *mode; - const struct key_descriptor *desc; - uint32_t to_check = PFI_MANDATORY; - - /* - * For the validity check the list of possible keys depends on - * the version of the PFI file used. - */ - version = head->value[key_version].num; - if (version > PFI_HDRVERSION) - return PFI_ENOHEADER; - - max_keys = key_descriptors_max[version]; - desc = key_descriptors[version]; - - if (!desc) - return PFI_ENOVERSION; - - mode = head->value[key_mode].str; - if (PFI_IS_UBI(mode)) { - to_check |= PFI_MANDATORY_UBI; - } - else if (PFI_IS_RAW(mode)) { - to_check |= PFI_MANDATORY_RAW; - } - else { /* neither UBI nor RAW == ERR */ - return PFI_EINSUFF; - } - - for (i = 0; i < max_keys; i++) { - if ((desc[i].flags & to_check) && !head->defined[i]) { - fprintf(stderr, "libpfi: %s missing\n", desc[i].name); - return PFI_EINSUFF; - } - } - - return 0; -} - -int pfi_header_init (pfi_header *head) -{ - int i; - pfi_header self = (pfi_header) malloc(sizeof(*self)); - - *head = self; - if (self == NULL) - return PFI_ENOMEM; - - /* initialize maximum number of possible keys */ - for (i = 0; i < num_keys; i++) { - memset(self, 0, sizeof(*self)); - self->defined[i] = 0; - } - - return 0; -} - -int pfi_header_destroy (pfi_header *head) -{ - int i; - pfi_header self = *head; - - for (i = 0; i < num_keys; i++) { - if (self->defined[i] && (key_desc[i].flags & PFI_STRING) && - self->value[i].str) { - free(self->value[i].str); - } - } - free(*head); - *head = NULL; - return 0; -} - -int pfi_header_setnumber (pfi_header head, - const char *key, uint32_t value) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) - return PFI_EBADTYPE; - - head->value[key_id].num = value; - head->defined[key_id] = 1; - return 0; -} - -int pfi_header_setvalue (pfi_header head, - const char *key, const char *value) -{ - int key_id = find_key_by_name(key); - - if (value == NULL) - return PFI_EINSUFF; - - if ((key_id < 0) || (key_id >= num_keys)) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) { - /* - * The value is a string. Copy to a newly allocated - * buffer. Delete the old value, if already set. - */ - size_t len = strlen(value) + 1; - char *old_str = NULL; - char *str; - - old_str = head->value[key_id].str; - if (old_str != NULL) - free(old_str); - - str = head->value[key_id].str = (char *) malloc(len); - if (str == NULL) - return PFI_ENOMEM; - - strcpy(str, value); - } else { - int len; - int ret; - /* FIXME: here we assume that the value is always - given in hex and starts with '0x'. */ - ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len); - if (ret < 1 || value[len] != '\0') - return PFI_EBADTYPE; - } - head->defined[key_id] = 1; - return 0; -} - -int pfi_header_getnumber (pfi_header head, - const char *key, uint32_t *value) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) - return PFI_EBADTYPE; - - if (!head->defined[key_id]) - return PFI_EUNDEF; - - *value = head->value[key_id].num; - return 0; -} - -int pfi_header_getstring (pfi_header head, - const char *key, char *value, size_t size) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (!(key_desc[key_id].flags & PFI_STRING)) - return PFI_EBADTYPE; - - if (!head->defined[key_id]) - return PFI_EUNDEF; - - strncpy(value, head->value[key_id].str, size-1); - value[size-1] = '\0'; - return 0; -} - -int pfi_header_write (FILE *out, pfi_header head) -{ - int i; - int ret; - - pfi_header_setnumber(head, "version", PFI_HDRVERSION); - - if ((ret = check_valid(head)) != 0) - return ret; - - /* OK. Now write the header. */ - - ret = fwrite(PFI_MAGIC, 1, PFI_MAGIC_LEN, out); - if (ret < PFI_MAGIC_LEN) - return ret; - - - for (i = 0; i < num_keys; i++) { - if (!head->defined[i]) - continue; - - ret = fprintf(out, "%s=", key_desc[i].name); - if (ret < 0) - return PFI_EFILE; - - if (key_desc[i].flags & PFI_STRING) { - ret = fprintf(out, "%s", head->value[i].str); - if (ret < 0) - return PFI_EFILE; - } else { - ret = fprintf(out, "0x%8x", head->value[i].num); - if (ret < 0) - return PFI_EFILE; - - } - ret = fprintf(out, "\n"); - if (ret < 0) - return PFI_EFILE; - } - ret = fprintf(out, "\n"); - if (ret < 0) - return PFI_EFILE; - - ret = fflush(out); - if (ret != 0) - return PFI_EFILE; - - return 0; -} - -int pfi_header_read (FILE *in, pfi_header head) -{ - char magic[PFI_MAGIC_LEN]; - char mode[PFI_KEYWORD_LEN]; - char buf[256]; - - if (PFI_MAGIC_LEN != fread(magic, 1, PFI_MAGIC_LEN, in)) - return PFI_EFILE; - if (memcmp(magic, PFI_MAGIC, PFI_MAGIC_LEN) != 0) { - if (memcmp(magic, PFI_DATA, PFI_MAGIC_LEN) == 0) { - return PFI_DATA_START; - } - return PFI_ENOHEADER; - } - - while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') { - char *value; - char *end; - value = strchr(buf, '='); - if (value == NULL) - return PFI_ENOHEADER; - - *value = '\0'; - value++; - end = strchr(value, '\n'); - if (end) - *end = '\0'; - - if (pfi_header_setvalue(head, buf, value)) - return PFI_ENOHEADER; - } - - if (check_valid(head) != 0) - return PFI_ENOHEADER; - - /* set current mode no. in head */ - pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN); - if (head->mode_no > get_mode_no(mode)) { - return PFI_EMODE; - } - head->mode_no = get_mode_no(mode); - return 0; -} - -int pfi_header_dump (FILE *out, pfi_header head __attribute__((__unused__))) -{ - fprintf(out, "Sorry not implemented yet. Write mail to " - "Andreas Arnez and complain!\n"); - return 0; -} - -int pfi_read (FILE *in, pfi_read_func func, void *priv_data) -{ - int rc; - pfi_header header; - - rc = pfi_header_init (&header); - if (0 != rc) - return rc; - if (!func) - return PFI_EINVAL; - - while ((0 == rc) && !feof(in)) { - /* - * Read header and check consistency of the fields. - */ - rc = pfi_header_read( in, header ); - if (0 != rc) - break; - if (func) { - rc = func(in, header, priv_data); - if (rc != 0) - break; - } - } - - pfi_header_destroy(&header); - return rc; -} diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c index cacf33f..4289fca 100644 --- a/ubi-utils/src/pfi2bin.c +++ b/ubi-utils/src/pfi2bin.c @@ -1,6 +1,6 @@ /* * Copyright (c) International Business Machines Corp., 2006 - * Copyright (C) 2007 Nokia Corporation + * Copyright (C) 2008 Nokia Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,29 +30,21 @@ */ #include <stdlib.h> -#include <stdint.h> #include <getopt.h> #include <stdio.h> #include <string.h> -#include <assert.h> #include <errno.h> +#include <unistd.h> -#include <ubigen.h> #include <mtd/ubi-header.h> +#include <libubigen.h> +#include <libpfi.h> #include "common.h" #include "list.h" -#include "reader.h" -#include "peb.h" -#include "crc32.h" #define PROGRAM_VERSION "1.5" #define PROGRAM_NAME "pfi2bin" -#define ERR_BUF_SIZE 1024 - -static uint32_t crc32_table[256]; -static char err_buf[ERR_BUF_SIZE]; - static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION " - a tool to convert PFI files into raw flash images. Note, if not\n" "sure about some of the parameters, do not specify them and let the utility to\n" @@ -269,386 +261,110 @@ static int parse_opt(int argc, char * const argv[]) return 0; } - -static size_t -byte_to_blk(size_t byte, size_t blk_size) -{ - return (byte % blk_size) == 0 - ? byte / blk_size - : byte / blk_size + 1; -} - - - - /** - * @precondition IO: File stream points to first byte of RAW data. - * @postcondition IO: File stream points to first byte of next - * or EOF. + * pfi2vol_info - convert PFI UBI volume information to libubigen. + * @pfi: PFI UBI volume information + * @n: PFI volume index to convert + * @vi: libubigen volume information */ -static int -memorize_raw_eb(pfi_raw_t pfi_raw, list_t *raw_pebs) -{ - int err = 0; - int i, read, to_read, eb_num, bytes_left; - list_t pebs = *raw_pebs; - peb_t peb = NULL; - - long old_file_pos = ftell(args.fp_in); - for (i = 0; i < (int)pfi_raw->starts_size; i++) { - bytes_left = pfi_raw->data_size; - err = fseek(args.fp_in, old_file_pos, SEEK_SET); - if (err != 0) - goto err; - - eb_num = byte_to_blk(pfi_raw->starts[i], args.peb_size); - while (bytes_left) { - to_read = MIN(bytes_left, args.peb_size); - err = peb_new(eb_num++, args.peb_size, &peb); - if (err != 0) - goto err; - read = fread(peb->data, 1, to_read, args.fp_in); - if (read != to_read) { - err = -EIO; - goto err; - } - pebs = append_elem(peb, pebs); - bytes_left -= read; - } - - } - *raw_pebs = pebs; - return 0; -err: - pebs = remove_all((free_func_t)&peb_free, pebs); - return err; -} - -static int -convert_ubi_volume(pfi_ubi_t ubi, list_t raw_pebs, - struct ubi_vtbl_record *vol_tab, - size_t *ebs_written) +static void pfi2vol_info(const struct pfi_ubi *pfi, int n, + struct ubigen_vol_info *vi, + const struct ubigen_info *ui) { - int err = 0; - uint32_t i, j; - peb_t raw_peb; - peb_t cmp_peb; - ubi_info_t u; - size_t leb_total = 0; - uint8_t vol_type; - - switch (ubi->type) { - case pfi_ubi_static: - vol_type = UBI_VID_STATIC; break; - case pfi_ubi_dynamic: - vol_type = UBI_VID_DYNAMIC; break; - default: - vol_type = UBI_VID_DYNAMIC; - } - - err = peb_new(0, 0, &cmp_peb); - if (err != 0) - goto err; - - long old_file_pos = ftell(args.fp_in); - for (i = 0; i < ubi->ids_size; i++) { - err = fseek(args.fp_in, old_file_pos, SEEK_SET); - if (err != 0) - goto err; - err = ubigen_create(&u, ubi->ids[i], vol_type, - args.peb_size, args.ec, - ubi->alignment, args.ubi_ver, - args.vid_hdr_offs, 0, ubi->data_size, - args.fp_in, args.fp_out); - if (err != 0) - goto err; - - err = ubigen_get_leb_total(u, &leb_total); - if (err != 0) - goto err; - - j = 0; - while(j < leb_total) { - cmp_peb->num = *ebs_written; - raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, - raw_pebs); - if (raw_peb) { - err = peb_write(args.fp_out, raw_peb); - } - else { - err = ubigen_write_leb(u, NO_ERROR); - j++; - } - if (err != 0) - goto err; - (*ebs_written)++; - } - /* memorize volume table entry */ - err = ubigen_set_lvol_rec(u, ubi->size, - ubi->names[i], - (void*) &vol_tab[ubi->ids[i]]); - if (err != 0) - goto err; - ubigen_destroy(&u); + vi->id = pfi->ids[n]; + vi->bytes = pfi->size; + vi->alignment = pfi->alignment; + vi->data_pad = ui->leb_size % vi->alignment; + vi->usable_leb_size = ui->leb_size - vi->data_pad; + vi->type = pfi->vol_type; + vi->name = pfi->names[n]; + vi->name_len = strlen(vi->name); + if (vi->name_len > UBI_VOL_NAME_MAX) { + errmsg("too long name, cut to %d symbols: \"%s\"", + UBI_VOL_NAME_MAX, vi->name); + vi->name_len = UBI_VOL_NAME_MAX; } - peb_free(&cmp_peb); - return 0; - -err: - peb_free(&cmp_peb); - ubigen_destroy(&u); - return err; -} - - -static FILE* -my_fmemopen (void *buf, size_t size, const char *opentype) -{ - FILE* f; - size_t ret; - - assert(strcmp(opentype, "r") == 0); - - f = tmpfile(); - ret = fwrite(buf, 1, size, f); - rewind(f); - - return f; + vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size; + vi->compat = 0; } -/** - * @brief Builds a UBI volume table from a volume entry list. - * @return 0 On success. - * else Error. - */ -static int -write_ubi_volume_table(list_t raw_pebs, - struct ubi_vtbl_record *vol_tab, size_t vol_tab_size, - size_t *ebs_written) +static int create_flash_image(void) { - int err = 0; - ubi_info_t u; - peb_t raw_peb; - peb_t cmp_peb; - size_t leb_size, leb_total, j = 0; - uint8_t *ptr = NULL; - FILE* fp_leb = NULL; - int vt_slots; - size_t vol_tab_size_limit; - - err = peb_new(0, 0, &cmp_peb); - if (err != 0) - goto err; - - /* @FIXME: Artem creates one volume with 2 LEBs. - * IMO 2 volumes would be more convenient. In order - * to get 2 reserved LEBs from ubigen, I have to - * introduce this stupid mechanism. Until no final - * decision of the VTAB structure is made... Good enough. - */ - err = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, - args.peb_size, args.ec, - 1, args.ubi_ver, - args.vid_hdr_offs, UBI_COMPAT_REJECT, - vol_tab_size, stdin, args.fp_out); - /* @FIXME stdin for fp_in is a hack */ - if (err != 0) - goto err; - err = ubigen_get_leb_size(u, &leb_size); - if (err != 0) - goto err; - ubigen_destroy(&u); - - /* - * The number of supported volumes is restricted by the eraseblock size - * and by the UBI_MAX_VOLUMES constant. - */ - vt_slots = leb_size / UBI_VTBL_RECORD_SIZE; - if (vt_slots > UBI_MAX_VOLUMES) - vt_slots = UBI_MAX_VOLUMES; - vol_tab_size_limit = vt_slots * UBI_VTBL_RECORD_SIZE; - - ptr = (uint8_t*) malloc(leb_size * sizeof(uint8_t)); - if (ptr == NULL) - goto err; - - memset(ptr, 0xff, leb_size); - memcpy(ptr, vol_tab, vol_tab_size_limit); - fp_leb = my_fmemopen(ptr, leb_size, "r"); - - err = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, - args.peb_size, args.ec, - 1, args.ubi_ver, args.vid_hdr_offs, - UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS, - fp_leb, args.fp_out); - if (err != 0) - goto err; - err = ubigen_get_leb_total(u, &leb_total); - if (err != 0) - goto err; - - long old_file_pos = ftell(fp_leb); - while(j < leb_total) { - err = fseek(fp_leb, old_file_pos, SEEK_SET); - if (err != 0) - goto err; - - cmp_peb->num = *ebs_written; - raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, - raw_pebs); - if (raw_peb) { - err = peb_write(args.fp_out, raw_peb); - } - else { - err = ubigen_write_leb(u, NO_ERROR); - j++; - } - - if (err != 0) - goto err; - (*ebs_written)++; - } - -err: - free(ptr); - peb_free(&cmp_peb); - ubigen_destroy(&u); - fclose(fp_leb); - return err; -} - -static int -write_remaining_raw_ebs(list_t raw_blocks, size_t *ebs_written, - FILE* fp_out) -{ - int err = 0; - uint32_t j, delta; - list_t ptr; - peb_t empty_eb, peb; - - /* create an empty 0xff EB (for padding) */ - err = peb_new(0, args.peb_size, &empty_eb); - - foreach(peb, ptr, raw_blocks) { - if (peb->num < *ebs_written) { - continue; /* omit blocks which - are already passed */ - } - - if (peb->num < *ebs_written) { - errmsg("eb_num: %d\n", peb->num); - errmsg("Bug: This should never happen. %d %s", - __LINE__, __FILE__); - goto err; - } - - delta = peb->num - *ebs_written; - for (j = 0; j < delta; j++) { - err = peb_write(fp_out, empty_eb); - if (err != 0) - goto err; - (*ebs_written)++; - } - err = peb_write(fp_out, peb); - if (err != 0) - goto err; - (*ebs_written)++; + int i, err, vtbl_size = args.peb_size; + struct ubigen_info ui; + struct list_entry *ubi_list = list_empty(), *ptr; + struct ubi_vtbl_record *vtbl; + struct pfi_ubi *pfi; + + vtbl = ubigen_create_empty_vtbl(&vtbl_size); + if (!vtbl) { + errmsg("cannot initialize volume table"); + return -1; } -err: - peb_free(&empty_eb); - return err; -} - -static int -init_vol_tab(struct ubi_vtbl_record **vol_tab, size_t *vol_tab_size) -{ - uint32_t crc; - size_t i; - struct ubi_vtbl_record* res = NULL; - - *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; + ubigen_info_init(&ui, args.peb_size, args.min_io_size, + args.subpage_size, args.vid_hdr_offs, args.ubi_ver, + args.ec); - res = (struct ubi_vtbl_record*) calloc(1, *vol_tab_size); - if (vol_tab == NULL) { - return -ENOMEM; + err = read_pfi_headers(&ubi_list, args.fp_in); + if (err != 0) { + errmsg("cannot read PFI headers, error %d", err); + goto error; } - for (i = 0; i < UBI_MAX_VOLUMES; i++) { - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - &(res[i]), UBI_VTBL_RECORD_SIZE_CRC); - res[i].crc = __cpu_to_be32(crc); - } + /* Add all volumes to the volume table */ + list_for_each(pfi, ptr, ubi_list) + for (i = 0; i < pfi->ids_size; i++) { + struct ubigen_vol_info vi; - *vol_tab = res; - return 0; -} - -static int -create_raw(void) -{ - int err = 0; - size_t ebs_written = 0; /* eraseblocks written already... */ - size_t vol_tab_size; - list_t ptr; - - list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ - list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ - list_t raw_pebs = mk_empty(); /* list of raw eraseblocks */ - - struct ubi_vtbl_record *vol_tab = NULL; + pfi2vol_info(pfi, i, &vi, &ui); + ubigen_add_volume(&ui, &vi, vtbl); + } - err = init_vol_tab (&vol_tab, &vol_tab_size); - if (err != 0) { - errmsg("cannot initialize volume table"); - goto err; + err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out); + if (err) { + errmsg("cannot create layout volume"); + goto error; } - err = read_pfi_headers(&pfi_raws, &pfi_ubis, args.fp_in, - err_buf, ERR_BUF_SIZE); - if (err != 0) { - errmsg("cannot read pfi header: %s err: %d", err_buf, err); - goto err; - } + /* Write all volumes */ + list_for_each(pfi, ptr, ubi_list) + for (i = 0; i < pfi->ids_size; i++) { + struct ubigen_vol_info vi; + + pfi2vol_info(pfi, i, &vi, &ui); + err = fseek(args.fp_in, pfi->data_offs, SEEK_SET); + if (err == -1) { + errmsg("cannot seek input file"); + perror("fseek"); + goto error; + } - pfi_raw_t pfi_raw; - foreach(pfi_raw, ptr, pfi_raws) { - err = memorize_raw_eb(pfi_raw, &raw_pebs); - if (err != 0) { - errmsg("cannot create raw_block in mem. err: %d\n", err); - goto err; + err = ubigen_write_volume(&ui, &vi, pfi->data_size, + args.fp_in, args.fp_out); + if (err) { + errmsg("cannot write volume %d", vi.id); + goto error; + } } - } - pfi_ubi_t pfi_ubi; - foreach(pfi_ubi, ptr, pfi_ubis) { - err = convert_ubi_volume(pfi_ubi, raw_pebs, - vol_tab, &ebs_written); - if (err != 0) { - errmsg("cannot convert UBI volume. err: %d\n", err); - goto err; + if (args.fp_out != stdout) { + i = ftell(args.fp_out); + if (i == -1) { + errmsg("cannot seek output file"); + perror("ftell"); + goto error; } - } - err = write_ubi_volume_table(raw_pebs, vol_tab, vol_tab_size, - &ebs_written); - if (err != 0) { - errmsg("cannot write UBI volume table. err: %d\n", err); - goto err; + printf("physical eraseblocks written: %d (", i / ui.peb_size); + ubiutils_print_bytes(i, 0); + printf(")\n"); } - err = write_remaining_raw_ebs(raw_pebs, &ebs_written, args.fp_out); - if (err != 0) - goto err; - - if (args.fp_out != stdout) - printf("Physical eraseblocks written: %8d\n", ebs_written); -err: - free(vol_tab); - pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); - pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); - raw_pebs = remove_all((free_func_t)&peb_free, raw_pebs); +error: + free(vtbl); + ubi_list = remove_all((free_func_t)&free_pfi_ubi, ubi_list); return err; } @@ -660,17 +376,8 @@ int main(int argc, char * const argv[]) if (err) return -1; - ubigen_init(); - init_crc32_table(crc32_table); - - err = create_raw(); - if (err != 0) { - errmsg("creating RAW failed"); - goto err; - } - -err: - if (err != 0) + err = create_flash_image(); + if (err) remove(args.f_out); return err; diff --git a/ubi-utils/src/reader.c b/ubi-utils/src/reader.c deleted file mode 100644 index 0ea8c6d..0000000 --- a/ubi-utils/src/reader.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Oliver Lohmann - * - * Read in PFI (partial flash image) data and store it into internal - * data structures for further processing. Take also care about - * special handling if the data contains PDD (platform description - * data/boot-parameters). - */ - -#include <string.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - -#include "bootenv.h" -#include "reader.h" - -#define __unused __attribute__((unused)) - -/* @FIXME hard coded offsets right now - get them from Artem? */ -#define NAND2048_DEFAULT_VID_HDR_OFF 1984 -#define NAND512_DEFAULT_VID_HDR_OFF 448 -#define NOR_DEFAULT_VID_HDR_OFF 64 - -#define EBUF_PFI(fmt...) \ - do { int i = snprintf(err_buf, err_buf_size, "%s\n", label); \ - snprintf(err_buf + i, err_buf_size - i, fmt); \ - } while (0) - -#define EBUF(fmt...) \ - do { snprintf(err_buf, err_buf_size, fmt); } while (0) - - -int -read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data, - char* err_buf, size_t err_buf_size) -{ - int rc = 0; - bootenv_t pdd = NULL; - pdd_data_t res = NULL; - const char* value; - - res = (pdd_data_t) malloc(sizeof(struct pdd_data)); - if (!res) { - rc = -ENOMEM; - goto err; - } - rc = bootenv_create(&pdd); - if (rc != 0) { - goto err; - } - rc = bootenv_read_txt(fp_pdd, pdd); - if (rc != 0) { - goto err; - } - rc = bootenv_get(pdd, "flash_type", &value); - if (rc != 0) { - goto err; - } - - if (strcmp(value, "NAND") == 0) { - - rc = bootenv_get_num(pdd, "flash_page_size", - &(res->flash_page_size)); - if (rc != 0) { - EBUF("Cannot read 'flash_page_size' from pdd."); - goto err; - } - res->flash_type = NAND_FLASH; - - switch (res->flash_page_size) { - case 512: - res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF; - break; - case 2048: - res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF; - break; - default: - EBUF("Unsupported 'flash_page_size' %d.", - res->flash_page_size); - goto err; - } - } - else if (strcmp(value, "NOR") == 0){ - res->flash_type = NOR_FLASH; - res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF; - } - else { - snprintf(err_buf, err_buf_size, - "Unkown flash type: %s", value); - goto err; - } - - rc = bootenv_get_num(pdd, "flash_eraseblock_size", - &(res->eb_size)); - if (rc != 0) { - EBUF("Cannot read 'flash_eraseblock_size' from pdd."); - goto err; - } - - rc = bootenv_get_num(pdd, "flash_size", - &(res->flash_size)); - if (rc != 0) { - EBUF("Cannot read 'flash_size' from pdd."); - goto err; - } - - goto out; - err: - if (res) { - free(res); - res = NULL; - } - out: - bootenv_destroy(&pdd); - *pdd_data = res; - return rc; -} - -int -read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, - const char* label, char* err_buf, size_t err_buf_size) -{ - int rc = 0; - char tmp_str[PFI_KEYWORD_LEN]; - bootenv_list_t raw_start_list = NULL; - pfi_raw_t res; - size_t size; - - res = (pfi_raw_t) malloc(sizeof(struct pfi_raw)); - if (!res) - return -ENOMEM; - - rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); - if (rc != 0) { - EBUF_PFI("Cannot read 'size' from PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); - if (rc != 0) { - EBUF_PFI("Cannot read 'crc' from PFI."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "raw_starts", - tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'raw_starts' from PFI."); - goto err; - } - - rc = bootenv_list_create(&raw_start_list); - if (rc != 0) { - goto err; - } - - rc = bootenv_list_import(raw_start_list, tmp_str); - if (rc != 0) { - EBUF_PFI("Cannot translate PFI value: %s", tmp_str); - goto err; - } - - rc = bootenv_list_to_num_vector(raw_start_list, - &size, &(res->starts)); - res->starts_size = size; - - if (rc != 0) { - EBUF_PFI("Cannot create numeric value array: %s", tmp_str); - goto err; - } - - goto out; - - err: - if (res) { - free(res); - res = NULL; - } - out: - bootenv_list_destroy(&raw_start_list); - *pfi_raw = res; - return rc; -} - -int -read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, - const char *label, char* err_buf, size_t err_buf_size) -{ - int rc = 0; - const char** tmp_names = NULL; - char tmp_str[PFI_KEYWORD_LEN]; - bootenv_list_t ubi_id_list = NULL; - bootenv_list_t ubi_name_list = NULL; - pfi_ubi_t res; - uint32_t i; - size_t size; - - res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi)); - if (!res) - return -ENOMEM; - - rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); - if (rc != 0) { - EBUF_PFI("Cannot read 'size' from PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); - if (rc != 0) { - EBUF_PFI("Cannot read 'crc' from PFI."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_ids' from PFI."); - goto err; - } - - rc = bootenv_list_create(&ubi_id_list); - if (rc != 0) { - goto err; - } - rc = bootenv_list_create(&ubi_name_list); - if (rc != 0) { - goto err; - } - - rc = bootenv_list_import(ubi_id_list, tmp_str); - if (rc != 0) { - EBUF_PFI("Cannot translate PFI value: %s", tmp_str); - goto err; - } - - rc = bootenv_list_to_num_vector(ubi_id_list, &size, - &(res->ids)); - res->ids_size = size; - if (rc != 0) { - EBUF_PFI("Cannot create numeric value array: %s", tmp_str); - goto err; - } - - if (res->ids_size == 0) { - rc = -1; - EBUF_PFI("Sanity check failed: No ubi_ids specified."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "ubi_type", - tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_type' from PFI."); - goto err; - } - if (strcmp(tmp_str, "static") == 0) - res->type = pfi_ubi_static; - else if (strcmp(tmp_str, "dynamic") == 0) - res->type = pfi_ubi_dynamic; - else { - EBUF_PFI("Unknown ubi_type in PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment)); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_alignment' from PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size)); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_size' from PFI."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "ubi_names", - tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_names' from PFI."); - goto err; - } - - rc = bootenv_list_import(ubi_name_list, tmp_str); - if (rc != 0) { - EBUF_PFI("Cannot translate PFI value: %s", tmp_str); - goto err; - } - rc = bootenv_list_to_vector(ubi_name_list, &size, - &(tmp_names)); - res->names_size = size; - if (rc != 0) { - EBUF_PFI("Cannot create string array: %s", tmp_str); - goto err; - } - - if (res->names_size != res->ids_size) { - EBUF_PFI("Sanity check failed: ubi_ids list does not match " - "sizeof ubi_names list."); - rc = -1; - } - - /* copy tmp_names to own structure */ - res->names = (char**) calloc(1, res->names_size * sizeof (char*)); - if (res->names == NULL) - goto err; - - for (i = 0; i < res->names_size; i++) { - res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char)); - if (res->names[i] == NULL) - goto err; - strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1); - } - - goto out; - - err: - if (res) { - if (res->names) { - for (i = 0; i < res->names_size; i++) { - if (res->names[i]) { - free(res->names[i]); - } - } - free(res->names); - } - if (res->ids) { - free(res->ids); - } - free(res); - res = NULL; - } - - out: - bootenv_list_destroy(&ubi_id_list); - bootenv_list_destroy(&ubi_name_list); - if (tmp_names != NULL) - free(tmp_names); - *pfi_ubi = res; - return rc; -} - - -int -free_pdd_data(pdd_data_t* pdd_data) -{ - if (*pdd_data) { - free(*pdd_data); - } - *pdd_data = NULL; - - return 0; -} - -int -free_pfi_raw(pfi_raw_t* pfi_raw) -{ - pfi_raw_t tmp = *pfi_raw; - if (tmp) { - if (tmp->starts) - free(tmp->starts); - free(tmp); - } - *pfi_raw = NULL; - - return 0; -} - -int -free_pfi_ubi(pfi_ubi_t* pfi_ubi) -{ - size_t i; - pfi_ubi_t tmp = *pfi_ubi; - if (tmp) { - if (tmp->ids) - free(tmp->ids); - if (tmp->names) { - for (i = 0; i < tmp->names_size; i++) { - if (tmp->names[i]) { - free(tmp->names[i]); - } - } - free(tmp->names); - } - free(tmp); - } - *pfi_ubi = NULL; - - return 0; -} - - -int -read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, - char* err_buf, size_t err_buf_size) -{ - int rc = 0; - char mode[PFI_KEYWORD_LEN]; - char label[PFI_LABEL_LEN]; - - *pfi_raws = mk_empty(); pfi_raw_t raw = NULL; - *pfi_ubis = mk_empty(); pfi_ubi_t ubi = NULL; - pfi_header pfi_header = NULL; - - /* read all headers from PFI and store them in lists */ - rc = pfi_header_init(&pfi_header); - if (rc != 0) { - EBUF("Cannot initialize pfi header."); - goto err; - } - while ((rc == 0) && !feof(fp_pfi)) { - rc = pfi_header_read(fp_pfi, pfi_header); - if (rc != 0) { - if (rc == PFI_DATA_START) { - rc = 0; - break; /* data section starts, - all headers read */ - } - else { - goto err; - } - } - rc = pfi_header_getstring(pfi_header, "label", label, - PFI_LABEL_LEN); - if (rc != 0) { - EBUF("Cannot read 'label' from PFI."); - goto err; - } - rc = pfi_header_getstring(pfi_header, "mode", mode, - PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF("Cannot read 'mode' from PFI."); - goto err; - } - if (strcmp(mode, "ubi") == 0) { - rc = read_pfi_ubi(pfi_header, fp_pfi, &ubi, label, - err_buf, err_buf_size); - if (rc != 0) { - goto err; - } - *pfi_ubis = append_elem(ubi, *pfi_ubis); - } - else if (strcmp(mode, "raw") == 0) { - rc = read_pfi_raw(pfi_header, fp_pfi, &raw, label, - err_buf, err_buf_size); - if (rc != 0) { - goto err; - } - *pfi_raws = append_elem(raw, *pfi_raws); - } - else { - EBUF("Recvieved unknown mode from PFI: %s", mode); - goto err; - } - } - goto out; - - err: - *pfi_raws = remove_all((free_func_t)&free_pfi_raw, *pfi_raws); - *pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, *pfi_ubis); - out: - pfi_header_destroy(&pfi_header); - return rc; - -} diff --git a/ubi-utils/src/reader.h b/ubi-utils/src/reader.h deleted file mode 100644 index 715e464..0000000 --- a/ubi-utils/src/reader.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef __READER_H__ -#define __READER_H__ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Oliver Lohmann - * - * Read Platform Description Data (PDD). - */ - -#include <stdint.h> -#include <stdio.h> - -#include "pfi.h" -#include "bootenv.h" -#include "list.h" - -typedef enum flash_type_t { - NAND_FLASH = 0, - NOR_FLASH, -} flash_type_t; - -typedef struct pdd_data *pdd_data_t; -typedef struct pfi_raw *pfi_raw_t; -typedef struct pfi_ubi *pfi_ubi_t; - -struct pdd_data { - uint32_t flash_size; - uint32_t flash_page_size; - uint32_t eb_size; - uint32_t vid_hdr_offset; - flash_type_t flash_type; -}; - -struct pfi_raw { - uint32_t data_size; - uint32_t *starts; - uint32_t starts_size; - uint32_t crc; -}; - -struct pfi_ubi { - uint32_t data_size; - uint32_t alignment; - uint32_t *ids; - uint32_t ids_size; - char **names; - uint32_t names_size; - uint32_t size; - enum { pfi_ubi_dynamic, pfi_ubi_static } type; - int curr_seqnum; /* specifies the seqnum taken in an update, - default: 0 (used by pfiflash, ubimirror) */ - uint32_t crc; -}; - -int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data, - char *err_buf, size_t err_buf_size); -int read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi, pfi_raw_t *pfi_raw, - const char *label, char *err_buf, size_t err_buf_size); -int read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi, pfi_ubi_t *pfi_ubi, - const char *label, char *err_buf, size_t err_buf_size); - -/** - * @brief Reads all pfi headers into list structures, separated by - * RAW and UBI sections. - */ -int read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, - char* err_buf, size_t err_buf_size); -int free_pdd_data(pdd_data_t *pdd_data); -int free_pfi_raw(pfi_raw_t *raw_pfi); -int free_pfi_ubi(pfi_ubi_t *pfi_ubi); - -#endif /* __READER_H__ */ diff --git a/ubi-utils/src/ubicrc32.c b/ubi-utils/src/ubicrc32.c index 0f10b31..8064439 100644 --- a/ubi-utils/src/ubicrc32.c +++ b/ubi-utils/src/ubicrc32.c @@ -91,8 +91,7 @@ static int parse_opt(int argc, char * const argv[]) int main(int argc, char * const argv[]) { int err = 0; - uint32_t crc32_table[256]; - uint32_t crc32 = UBI_CRC32_INIT; + uint32_t crc = UBI_CRC32_INIT; char buf[BUFSIZE]; FILE *fp; @@ -110,8 +109,6 @@ int main(int argc, char * const argv[]) if (err) return err; - init_crc32_table(crc32_table); - while (!feof(fp)) { size_t read; @@ -122,10 +119,10 @@ int main(int argc, char * const argv[]) err = -1; goto out_close; } - crc32 = clc_crc32(crc32_table, crc32, buf, read); + crc = crc32(crc, buf, read); } - printf("0x%08x\n", crc32); + printf("0x%08x\n", crc); out_close: if (fp != stdin) diff --git a/ubi-utils/src/ubigen.h b/ubi-utils/src/ubigen.h deleted file mode 100644 index bf4b384..0000000 --- a/ubi-utils/src/ubigen.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Frank Haverkamp - * - * An utility to update UBI volumes. - */ - -#ifndef __UBIGEN_H__ -#define __UBIGEN_H__ - -#include <stdio.h> -#include <stdint.h> -#include <mtd/ubi-header.h> -#include <asm/byteorder.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define DEFAULT_BLOCKSIZE (128 * 1024) -#define DEFAULT_PAGESIZE (2*1024) - -#define EUBIGEN_INVALID_TYPE 1 -#define EUBIGEN_INVALID_HDR_OFFSET 2 -#define EUBIGEN_INVALID_ALIGNMENT 3 -#define EUBIGEN_TOO_SMALL_EB 4 -#define EUBIGEN_MAX_ERROR 5 - -typedef enum action { - NO_ERROR = 0x00000000, - BROKEN_HDR_CRC = 0x00000001, - BROKEN_DATA_CRC = 0x00000002, - BROKEN_DATA_SIZE = 0x00000004, - BROKEN_OMIT_BLK = 0x00000008, - MARK_AS_UPDATE = 0x00000010, -} ubigen_action_t; - -typedef struct ubi_info *ubi_info_t; - -/** - * @brief Initialize the internal CRC32 table. - * @note Necessary because of the used crc32 function in UBI. - * A usage of CRC32, from e.g. zlib will fail. - */ -void ubigen_init(void); - -/** - * @brief Create an ubigen handle. - * @param ... - * @return 0 On sucess. - * else Error. - * @note This parameterlist is ugly. But we have to use - * two big structs and meta information internally, - * filling them would be even uglier. - */ -int ubigen_create(ubi_info_t *u, uint32_t vol_id, uint8_t vol_type, - uint32_t eb_size, uint64_t ec, uint32_t alignment, - uint8_t version, uint32_t vid_hdr_offset, - uint8_t compat_flag, size_t data_size, - FILE* fp_in, FILE* fp_out); - -/** - * @brief Destroy an ubigen handle. - * @param u Handle to free. - * @return 0 On success. - * else Error. - */ -int ubigen_destroy(ubi_info_t *u); - -/** - * @brief Get number of total logical EBs, necessary for the - * complete storage of data in the handle. - * @param u The handle. - * @return 0 On success. - * else Error. - */ -int ubigen_get_leb_total(ubi_info_t u, size_t* total); - -/** - * @brief Get the size in bytes of one logical EB in the handle. - * @param u The handle. - * @return 0 On success. - * else Error. - */ -int ubigen_get_leb_size(ubi_info_t u, size_t* size); - - -/** - * @brief Write a logical EB (fits exactly into 1 physical EB). - * @param u Handle which holds all necessary data. - * @param action Additional operations which shall be applied on this - * logical eraseblock. Mostly injecting artifical errors. - * @return 0 On success. - * else Error. - */ -int ubigen_write_leb(ubi_info_t u, ubigen_action_t action); - -/** - * @brief Write a complete array of logical eraseblocks at once. - * @param u Handle which holds all necessary data. - * @return 0 On success. - * else Error. - */ -int ubigen_write_complete(ubi_info_t u); - -/** - * @brief Write a single block which is extracted from the - * binary input data. - * @param u Handle which holds all necessary data. - * @param blk Logical eraseblock which shall hold a inc. copy entry - * and a bad data crc. - * @return 0 On success. - * else Error. - */ -int ubigen_write_broken_update(ubi_info_t u, uint32_t blk); - -/** - * @brief Use the current ubi_info data and some additional data - * to set an UBI volume table entry from it. - * @param u Handle which holds some of the necessary data. - * @param res_bytes Number of reserved bytes which is stored in the volume - * table entry. - * @param name A string which shall be used as a volume label. - * @param lvol_r A pointer to a volume table entry. - * @return 0 On success. - * else Error. - */ -int ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, - const char* name, struct ubi_vtbl_record *lvol_rec); - -#ifdef __cplusplus -} -#endif - -#endif /* !__UBIGEN_H__ */ diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c index 5c1d324..1d4b35b 100644 --- a/ubi-utils/src/unubi.c +++ b/ubi-utils/src/unubi.c @@ -121,8 +121,6 @@ static const char *usage = #define FN_VOLWH "%s/volume%03u" /* whole volume */ #define FN_VITBL "%s/vol_info_table%u" /* vol info table */ -static uint32_t crc32_table[256]; - /* struct args: * bsize int, blocksize of image blocks * hsize int, eraseblock header size @@ -351,7 +349,7 @@ data_crc(FILE* fpin, size_t length, uint32_t *ret_crc) if (rc < 0) return -1; - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, length); + crc = crc32(UBI_CRC32_INIT, buf, length); *ret_crc = crc; return 0; } @@ -462,8 +460,7 @@ extract_itable(FILE *fpin, struct eb_info *cur, size_t bsize, size_t num, } /* check crc */ - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &rec, - UBI_VTBL_RECORD_SIZE_CRC); + crc = crc32(UBI_CRC32_INIT, &rec, UBI_VTBL_RECORD_SIZE_CRC); if (crc != __be32_to_cpu(rec.crc)) continue; @@ -689,8 +686,7 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) } /* check erasecounter header crc */ - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->ec), - UBI_EC_HDR_SIZE_CRC); + crc = crc32(UBI_CRC32_INIT, &(cur->ec), UBI_EC_HDR_SIZE_CRC); if (__be32_to_cpu(cur->ec.hdr_crc) != crc) { snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc"); goto invalid; @@ -734,8 +730,7 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) cur->ec_crc_ok = 1; /* check volume id header crc */ - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->vid), - UBI_VID_HDR_SIZE_CRC); + crc = crc32(UBI_CRC32_INIT, &(cur->vid), UBI_VID_HDR_SIZE_CRC); if (__be32_to_cpu(cur->vid.hdr_crc) != crc) { snprintf(reason, MAXPATH, ".invalid.vid_hdr_crc"); goto invalid; @@ -932,7 +927,6 @@ main(int argc, char *argv[]) vols_len = 0; vols = NULL; fpin = NULL; - init_crc32_table(crc32_table); /* setup struct args a */ memset(&a, 0, sizeof(a)); diff --git a/ubi-utils/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c index 2ab3b87..3f3a480 100644 --- a/ubi-utils/src/unubi_analyze.c +++ b/ubi-utils/src/unubi_analyze.c @@ -100,7 +100,7 @@ unubi_analyze_ec_hdr(struct eb_info *first, const char *path) { char filename[PATH_MAX + 1]; size_t count, eraseblocks; - uint32_t crc, crc32_table[256]; + uint32_t crc; uint64_t *erase_counts; FILE* fpdata; FILE* fpplot; @@ -109,9 +109,6 @@ unubi_analyze_ec_hdr(struct eb_info *first, const char *path) if (first == NULL) return -1; - /* crc check still needed for `first' linked list */ - init_crc32_table(crc32_table); - /* prepare output files */ memset(filename, 0, PATH_MAX + 1); snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_DATA); @@ -164,8 +161,7 @@ unubi_analyze_ec_hdr(struct eb_info *first, const char *path) fprintf(fpdata, "# eraseblock_no actual_erase_count " "sorted_erase_count\n"); while (cur != NULL) { - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->ec, - UBI_EC_HDR_SIZE_CRC); + crc = crc32(UBI_CRC32_INIT, &cur->ec, UBI_EC_HDR_SIZE_CRC); if ((__be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) || (crc != __be32_to_cpu(cur->ec.hdr_crc))) |