From 6ccd7242c4c1404dafb64cd937adc3c65ce02385 Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Wed, 21 Jun 2006 14:26:02 +0200 Subject: [MTD] UBI: Removed automake, autoconf, added ubi userspace headers. Signed-off-by: Frank Haverkamp --- include/mtd/ubi-header.h | 390 ++++++++++++ include/mtd/ubi-user.h | 128 ++++ ubi-utils/Makefile | 126 ++-- ubi-utils/Makefile.am | 96 --- ubi-utils/bootstrap | 15 - ubi-utils/configure.ac | 52 -- ubi-utils/inc/Makefile.am | 5 - ubi-utils/inc/bootenv.h | 415 ------------- ubi-utils/inc/config-h.in | 74 --- ubi-utils/inc/crc32.h | 36 -- ubi-utils/inc/error.h | 84 --- ubi-utils/inc/example_ubi.h | 28 - ubi-utils/inc/list.h | 56 -- ubi-utils/inc/nandecc.h | 28 - ubi-utils/inc/peb.h | 41 -- ubi-utils/inc/pfi.h | 244 -------- ubi-utils/inc/pfiflash.h | 62 -- ubi-utils/inc/reader.h | 84 --- ubi-utils/inc/ubigen.h | 149 ----- ubi-utils/inc/ubimirror.h | 66 -- ubi-utils/perl/f128_nand_sample.cfg | 38 ++ ubi-utils/perl/f64_nor_sample.cfg | 39 ++ ubi-utils/perl/mkpfi | 723 ++++++++++++++++++++++ ubi-utils/perl/ubicrc32.pl | 74 +++ ubi-utils/scripts/ubi_test.sh | 2 +- ubi-utils/scripts/ubi_tools_test.sh | 2 +- ubi-utils/src/bin2nand.c | 356 +++++++++++ ubi-utils/src/bin2nand/bin2nand.c | 343 ----------- ubi-utils/src/bin2nand/nandecc.c | 159 ----- ubi-utils/src/bin2nand/nandecc.h | 11 - ubi-utils/src/bootenv.c | 961 ++++++++++++++++++++++++++++++ ubi-utils/src/bootenv.h | 415 +++++++++++++ ubi-utils/src/config.h | 28 + ubi-utils/src/crc32.c | 83 +++ ubi-utils/src/crc32.h | 36 ++ ubi-utils/src/error.c | 177 ++++++ ubi-utils/src/error.h | 84 +++ ubi-utils/src/example_ubi.h | 28 + ubi-utils/src/hashmap.c | 412 +++++++++++++ ubi-utils/src/hashmap.h | 49 ++ ubi-utils/src/libbootenv/bootenv.c | 959 ----------------------------- ubi-utils/src/libbootenv/hashmap.c | 412 ------------- ubi-utils/src/libbootenv/hashmap.h | 49 -- ubi-utils/src/libcrc32/crc32.c | 83 --- ubi-utils/src/liberror/error.c | 177 ------ ubi-utils/src/liblist/list.c | 149 ----- ubi-utils/src/libpeb/peb.c | 116 ---- ubi-utils/src/libpfi/pfi.c | 461 -------------- ubi-utils/src/libpfiflash.c | 619 +++++++++++++++++++ ubi-utils/src/libpfiflash/pfiflash.c | 617 ------------------- ubi-utils/src/libreader/reader.c | 442 -------------- ubi-utils/src/libubi.c | 773 ++++++++++++++++++++++++ ubi-utils/src/libubi/libubi.c | 773 ------------------------ ubi-utils/src/libubi/libubi_int.h | 119 ---- ubi-utils/src/libubi/libubi_sysfs.c | 231 ------- ubi-utils/src/libubi/libubi_sysfs.h | 109 ---- ubi-utils/src/libubi_int.h | 119 ++++ ubi-utils/src/libubi_sysfs.c | 232 ++++++++ ubi-utils/src/libubi_sysfs.h | 109 ++++ ubi-utils/src/libubigen.c | 486 +++++++++++++++ ubi-utils/src/libubigen/ubigen.c | 486 --------------- ubi-utils/src/libubimirror.c | 217 +++++++ ubi-utils/src/libubimirror/ubimirror.c | 217 ------- ubi-utils/src/list.c | 149 +++++ ubi-utils/src/list.h | 56 ++ ubi-utils/src/mkbootenv.c | 173 ++++++ ubi-utils/src/mkbootenv/mkbootenv.c | 173 ------ ubi-utils/src/mkpfi/f128_nand_sample.cfg | 38 -- ubi-utils/src/mkpfi/f64_nor_sample.cfg | 39 -- ubi-utils/src/mkpfi/mkpfi | 723 ---------------------- ubi-utils/src/nand2bin.c | 328 ++++++++++ ubi-utils/src/nand2bin/nand2bin.c | 327 ---------- ubi-utils/src/nand2bin/nandcorr.c | 85 --- ubi-utils/src/nandcorr.c | 85 +++ ubi-utils/src/nandecc.c | 159 +++++ ubi-utils/src/nandecc.h | 28 + ubi-utils/src/pddcustomize.c | 496 +++++++++++++++ ubi-utils/src/pddcustomize/pddcustomize.c | 496 --------------- ubi-utils/src/peb.c | 116 ++++ ubi-utils/src/peb.h | 41 ++ ubi-utils/src/pfi.c | 461 ++++++++++++++ ubi-utils/src/pfi.h | 244 ++++++++ ubi-utils/src/pfi2bin.c | 678 +++++++++++++++++++++ ubi-utils/src/pfi2bin/pfi2bin.c | 678 --------------------- ubi-utils/src/pfiflash.c | 243 ++++++++ ubi-utils/src/pfiflash.h | 62 ++ ubi-utils/src/pfiflash/pfiflash.c | 243 -------- ubi-utils/src/reader.c | 452 ++++++++++++++ ubi-utils/src/reader.h | 84 +++ ubi-utils/src/ubicrc32.c | 143 +++++ ubi-utils/src/ubicrc32/ubicrc32.c | 143 ----- ubi-utils/src/ubicrc32/ubicrc32.pl | 74 --- ubi-utils/src/ubigen.c | 369 ++++++++++++ ubi-utils/src/ubigen.h | 149 +++++ ubi-utils/src/ubigen/ubigen_main.c | 369 ------------ ubi-utils/src/ubiinfo/ubiflash.h | 185 ------ ubi-utils/src/ubiinfo/ubiinfo.c | 406 ------------- ubi-utils/src/ubiinfo/ubiipl.h | 87 --- ubi-utils/src/ubimirror.c | 206 +++++++ ubi-utils/src/ubimirror.h | 66 ++ ubi-utils/src/ubimirror/ubimirror.c | 206 ------- ubi-utils/src/ubimkvol.c | 251 ++++++++ ubi-utils/src/ubimkvol/ubimkvol.c | 252 -------- ubi-utils/src/ubirmvol.c | 174 ++++++ ubi-utils/src/ubirmvol/ubirmvol.c | 172 ------ ubi-utils/src/ubiupdatevol.c | 352 +++++++++++ ubi-utils/src/ubiwritevol/ubiwritevol.c | 352 ----------- ubi-utils/src/unubi.c | 392 ++++++++++++ ubi-utils/src/unubi/unubi.c | 391 ------------ 109 files changed, 12603 insertions(+), 12947 deletions(-) create mode 100644 include/mtd/ubi-header.h create mode 100644 include/mtd/ubi-user.h delete mode 100644 ubi-utils/Makefile.am delete mode 100755 ubi-utils/bootstrap delete mode 100644 ubi-utils/configure.ac delete mode 100644 ubi-utils/inc/Makefile.am delete mode 100644 ubi-utils/inc/bootenv.h delete mode 100644 ubi-utils/inc/config-h.in delete mode 100644 ubi-utils/inc/crc32.h delete mode 100644 ubi-utils/inc/error.h delete mode 100644 ubi-utils/inc/example_ubi.h delete mode 100644 ubi-utils/inc/list.h delete mode 100644 ubi-utils/inc/nandecc.h delete mode 100644 ubi-utils/inc/peb.h delete mode 100644 ubi-utils/inc/pfi.h delete mode 100644 ubi-utils/inc/pfiflash.h delete mode 100644 ubi-utils/inc/reader.h delete mode 100644 ubi-utils/inc/ubigen.h delete mode 100644 ubi-utils/inc/ubimirror.h create mode 100644 ubi-utils/perl/f128_nand_sample.cfg create mode 100644 ubi-utils/perl/f64_nor_sample.cfg create mode 100755 ubi-utils/perl/mkpfi create mode 100755 ubi-utils/perl/ubicrc32.pl create mode 100644 ubi-utils/src/bin2nand.c delete mode 100644 ubi-utils/src/bin2nand/bin2nand.c delete mode 100644 ubi-utils/src/bin2nand/nandecc.c delete mode 100644 ubi-utils/src/bin2nand/nandecc.h create mode 100644 ubi-utils/src/bootenv.c create mode 100644 ubi-utils/src/bootenv.h create mode 100644 ubi-utils/src/config.h create mode 100644 ubi-utils/src/crc32.c create mode 100644 ubi-utils/src/crc32.h create mode 100644 ubi-utils/src/error.c create mode 100644 ubi-utils/src/error.h create mode 100644 ubi-utils/src/example_ubi.h create mode 100644 ubi-utils/src/hashmap.c create mode 100644 ubi-utils/src/hashmap.h delete mode 100644 ubi-utils/src/libbootenv/bootenv.c delete mode 100644 ubi-utils/src/libbootenv/hashmap.c delete mode 100644 ubi-utils/src/libbootenv/hashmap.h delete mode 100644 ubi-utils/src/libcrc32/crc32.c delete mode 100644 ubi-utils/src/liberror/error.c delete mode 100644 ubi-utils/src/liblist/list.c delete mode 100644 ubi-utils/src/libpeb/peb.c delete mode 100644 ubi-utils/src/libpfi/pfi.c create mode 100644 ubi-utils/src/libpfiflash.c delete mode 100644 ubi-utils/src/libpfiflash/pfiflash.c delete mode 100644 ubi-utils/src/libreader/reader.c create mode 100644 ubi-utils/src/libubi.c delete mode 100644 ubi-utils/src/libubi/libubi.c delete mode 100644 ubi-utils/src/libubi/libubi_int.h delete mode 100644 ubi-utils/src/libubi/libubi_sysfs.c delete mode 100644 ubi-utils/src/libubi/libubi_sysfs.h create mode 100644 ubi-utils/src/libubi_int.h create mode 100644 ubi-utils/src/libubi_sysfs.c create mode 100644 ubi-utils/src/libubi_sysfs.h create mode 100644 ubi-utils/src/libubigen.c delete mode 100644 ubi-utils/src/libubigen/ubigen.c create mode 100644 ubi-utils/src/libubimirror.c delete mode 100644 ubi-utils/src/libubimirror/ubimirror.c create mode 100644 ubi-utils/src/list.c create mode 100644 ubi-utils/src/list.h create mode 100644 ubi-utils/src/mkbootenv.c delete mode 100644 ubi-utils/src/mkbootenv/mkbootenv.c delete mode 100644 ubi-utils/src/mkpfi/f128_nand_sample.cfg delete mode 100644 ubi-utils/src/mkpfi/f64_nor_sample.cfg delete mode 100755 ubi-utils/src/mkpfi/mkpfi create mode 100644 ubi-utils/src/nand2bin.c delete mode 100644 ubi-utils/src/nand2bin/nand2bin.c delete mode 100644 ubi-utils/src/nand2bin/nandcorr.c create mode 100644 ubi-utils/src/nandcorr.c create mode 100644 ubi-utils/src/nandecc.c create mode 100644 ubi-utils/src/nandecc.h create mode 100644 ubi-utils/src/pddcustomize.c delete mode 100644 ubi-utils/src/pddcustomize/pddcustomize.c create mode 100644 ubi-utils/src/peb.c create mode 100644 ubi-utils/src/peb.h create mode 100644 ubi-utils/src/pfi.c create mode 100644 ubi-utils/src/pfi.h create mode 100644 ubi-utils/src/pfi2bin.c delete mode 100644 ubi-utils/src/pfi2bin/pfi2bin.c create mode 100644 ubi-utils/src/pfiflash.c create mode 100644 ubi-utils/src/pfiflash.h delete mode 100644 ubi-utils/src/pfiflash/pfiflash.c create mode 100644 ubi-utils/src/reader.c create mode 100644 ubi-utils/src/reader.h create mode 100644 ubi-utils/src/ubicrc32.c delete mode 100644 ubi-utils/src/ubicrc32/ubicrc32.c delete mode 100755 ubi-utils/src/ubicrc32/ubicrc32.pl create mode 100644 ubi-utils/src/ubigen.c create mode 100644 ubi-utils/src/ubigen.h delete mode 100644 ubi-utils/src/ubigen/ubigen_main.c delete mode 100644 ubi-utils/src/ubiinfo/ubiflash.h delete mode 100644 ubi-utils/src/ubiinfo/ubiinfo.c delete mode 100644 ubi-utils/src/ubiinfo/ubiipl.h create mode 100644 ubi-utils/src/ubimirror.c create mode 100644 ubi-utils/src/ubimirror.h delete mode 100644 ubi-utils/src/ubimirror/ubimirror.c create mode 100644 ubi-utils/src/ubimkvol.c delete mode 100644 ubi-utils/src/ubimkvol/ubimkvol.c create mode 100644 ubi-utils/src/ubirmvol.c delete mode 100644 ubi-utils/src/ubirmvol/ubirmvol.c create mode 100644 ubi-utils/src/ubiupdatevol.c delete mode 100644 ubi-utils/src/ubiwritevol/ubiwritevol.c create mode 100644 ubi-utils/src/unubi.c delete mode 100644 ubi-utils/src/unubi/unubi.c diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h new file mode 100644 index 0000000..1b325a1 --- /dev/null +++ b/include/mtd/ubi-header.h @@ -0,0 +1,390 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Artem B. Bityutskiy + * Thomas Gleixner + * Frank Haverkamp + * Oliver Lohmann + * Andreas Arnez + */ + +/* + * This file defines the layout of UBI headers and all the other UBI on-flash + * data structures. + */ + +#ifndef __UBI_HEADER_H__ +#define __UBI_HEADER_H__ + +#include + +/* The version of this UBI implementation */ +#define UBI_VERSION 1 + +/* The highest erase counter value supported by this implementation of UBI */ +#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF + +/* The initial CRC32 value used when calculating CRC checksums */ +#define UBI_CRC32_INIT 0xFFFFFFFFU + +/** + * Magic numbers of the UBI headers. + * + * @UBI_EC_HDR_MAGIC: erase counter header magic number (ASCII "UBI#") + * @UBI_VID_HDR_MAGIC: volume identifier header magic number (ASCII "UBI!") + */ +enum { + UBI_EC_HDR_MAGIC = 0x55424923, + UBI_VID_HDR_MAGIC = 0x55424921 +}; + +/** + * Molume type constants used in volume identifier headers. + * + * @UBI_VID_DYNAMIC: dynamic volume + * @UBI_VID_STATIC: static volume + */ +enum { + UBI_VID_DYNAMIC = 1, + UBI_VID_STATIC = 2 +}; + +/** + * Compatibility constants used by internal volumes. + * + * @UBI_COMPAT_DELETE: delete this internal volume before anything is written + * to the flash + * @UBI_COMPAT_RO: attach this device in read-only mode + * @UBI_COMPAT_IGNORE: ignore this internal volume, but the UBI wear-leveling + * unit may still move these logical eraseblocks to ensure wear-leveling + * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its + * physical eraseblocks, don't even allow the wear-leveling unit to move + * them + * @UBI_COMPAT_REJECT: reject this UBI image + */ +enum { + UBI_COMPAT_DELETE = 1, + UBI_COMPAT_RO = 2, + UBI_COMPAT_IGNORE = 3, + UBI_COMPAT_PRESERVE = 4, + UBI_COMPAT_REJECT = 5 +}; + +/* + * ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash + * data structures. + */ +typedef struct { + uint16_t int16; +} __attribute__ ((packed)) ubi16_t; + +typedef struct { + uint32_t int32; +} __attribute__ ((packed)) ubi32_t; + +typedef struct { + uint64_t int64; +} __attribute__ ((packed)) ubi64_t; + +/* + * In this implementation UBI uses the big-endian format for on-flash integers. + * The below are the corresponding endianess conversion macros. + */ +#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)}) +#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16)) + +#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)}) +#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32)) + +#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)}) +#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64)) + +/* + * Sizes of UBI headers. + */ +#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) +#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) + +/* + * Sizes of UBI headers without the ending CRC. + */ +#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(ubi32_t)) +#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t)) + +/* + * How much private data may internal volumes store in the VID header. + */ +#define UBI_VID_HDR_IVOL_DATA_SIZE 12 + +/** + * struct ubi_ec_hdr - UBI erase counter header. + * + * @magic: the erase counter header magic number (%UBI_EC_HDR_MAGIC) + * @version: the version of UBI implementation which is supposed to accept this + * UBI image (%UBI_VERSION) + * @padding1: reserved for future, zeroes + * @ec: the erase counter + * @vid_hdr_offset: where the VID header begins + * @data_offset: where the user data begins + * @padding2: reserved for future, zeroes + * @hdr_crc: the erase counter header CRC checksum + * + * The erase counter header takes 64 bytes and has a plenty of unused space for + * future usage. The unused fields are zeroed. The @version field is used to + * indicate the version of UBI implementation which is supposed to be able to + * work with this UBI image. If @version is greater then the current UBI + * version, the image is rejecter. This may be useful in future if something + * is changed radically. This field is duplicated in the volume identifier + * header. + * + * The @vid_hdr_offset and @data_offset fields contain the offset of the the + * volume identifier header and user data, relative to the beginning of the + * eraseblock. These values have to be the same for all eraseblocks. + */ +struct ubi_ec_hdr { + ubi32_t magic; + uint8_t version; + uint8_t padding1[3]; + ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */ + ubi32_t vid_hdr_offset; + ubi32_t data_offset; + uint8_t padding2[36]; + ubi32_t hdr_crc; +} __attribute__ ((packed)); + +/** + * struct ubi_vid_hdr - on-flash UBI volume identifier header. + * + * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) + * @version: UBI implementation version which is supposed to accept this UBI + * image (%UBI_VERSION) + * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) + * @copy_flag: a flag indicating if this physical eraseblock was created by + * means of copying an original physical eraseblock to ensure wear-leveling. + * @compat: compatibility of this volume (%UBI_COMPAT_DELETE, + * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) + * @vol_id: volume ID + * @lnum: logical eraseblock number + * @leb_ver: eraseblock copy number + * @data_size: how many bytes of data this eraseblock contains. + * @used_ebs: total number of used logical eraseblocks in this volume + * @data_pad: how many bytes at the end of this eraseblock are not used + * @data_crc: CRC checksum of data containing in this eraseblock + * @padding1: reserved for future, zeroes + * @ivol_data: private data of internal volumes + * @hdr_crc: volume identifier header CRC checksum + * + * The @leb_ver and the @copy_flag fields are used to distinguish between older + * and newer copies of logical eraseblocks, as well as to guarantee robustness + * to unclean reboots. As UBI erases logical eraseblocks asynchronously, it has + * to distinguish between older and newer copies of eraseblocks. This is done + * using the @version field. On the other hand, when UBI moves an eraseblock, + * its version is also increased and the @copy_flag is set to 1. Additionally, + * when moving eraseblocks, UBI calculates data CRC and stores it in the + * @data_crc field, even for dynamic volumes. + * + * Thus, if there are 2 eraseblocks of the same volume and logical number, UBI + * uses the following algorithm to pick one of them. It first picks the one + * with larger version (say, A). If @copy_flag is not set, then A is picked. If + * @copy_flag is set, UBI checks the CRC of the eraseblock (@data_crc). This is + * needed to ensure that copying was finished. If the CRC is all right, A is + * picked. If not, the older eraseblock is picked. + * + * Note, the @leb_ver field may overflow. Thus, if you have 2 versions A and B, + * then A > B if abs(A-B) < 0x7FFFFFFF, and A < B otherwise. + * + * There are 2 sorts of volumes in UBI: user volumes and internal volumes. + * Internal volumes are not seen from outside and are used for different + * internal UBI purposes. In this implementation there are only two internal + * volumes: the layout volume and the update volume. Internal volumes are the + * main mechanism of UBI extensions. For example, in future one may introduce a + * journal internal volume. + * + * The @compat field is only used for internal volumes and contains the degree + * of their compatibility. This field is always zero for user volumes. This + * field provides a mechanism to introduce UBI extensions and to be still + * compatible with older UBI binaries. For example, if someone introduced an + * journal internal volume in future, he would probably use %UBI_COMPAT_DELETE + * compatibility. And in this case, older UBI binaries, which know nothing + * about the journal volume, would just delete this and work perfectly fine. + * This is somewhat similar to what Ext2fs does when it is fed by an Ext3fs + * image - it just ignores the Ext3fs journal. + * + * The @data_crc field contains the CRC checksum of the contents of the logical + * eraseblock if this is a static volume. In case of dynamic volumes, it does + * not contain the CRC checksum as a rule. The only exception is when the + * logical eraseblock was moved by the wear-leveling unit, then the + * wear-leveling unit calculates the eraseblocks' CRC and stores it at + * @data_crc. + * + * The @data_size field is always used for static volumes because we want to + * know about how many bytes of data are stored in this eraseblock. For + * dynamic eraseblocks, this field usually contains zero. The only exception is + * when the logical eraseblock is moved to another physical eraseblock due to + * wear-leveling reasons. In this case, UBI calculates CRC checksum of the + * contents and uses both @data_crc and @data_size fields. In this case, the + * @data_size field contains the size of logical eraseblock of this volume + * (which may vary owing to @alignment). + * + * The @used_ebs field is used only for static volumes and indicates how many + * eraseblocks the data of the volume takes. For dynamic volumes this field is + * not used and always contains zero. + * + * The @data_pad is calculated when volumes are created using the alignment + * parameter. So, effectively, the @data_pad field reduces the size of logical + * eraseblocks of this volume. This is very handy when one uses block-oriented + * software (say, cramfs) on top of the UBI volume. + * + * The @ivol_data contains private data of internal volumes. This might be very + * handy to store data in the VID header, not in the eraseblock's contents. For + * example it may make life of simple boot-loaders easier. The @ivol_data field + * contains zeroes for user volumes. + */ +struct ubi_vid_hdr { + ubi32_t magic; + uint8_t version; + uint8_t vol_type; + uint8_t copy_flag; + uint8_t compat; + ubi32_t vol_id; + ubi32_t lnum; + ubi32_t leb_ver; + ubi32_t data_size; + ubi32_t used_ebs; + ubi32_t data_pad; + ubi32_t data_crc; + uint8_t padding1[12]; + uint8_t ivol_data[UBI_VID_HDR_IVOL_DATA_SIZE]; + ubi32_t hdr_crc; +} __attribute__ ((packed)); + +/** + * struct ubi_vid_hdr_upd_vol - private data of the update internal volume + * stored in volume identifier headers. + * + * @vol_id: volume ID of the volume under update + * @padding: zeroes + */ +struct ubi_vid_hdr_upd_vol { + ubi32_t vol_id; + uint8_t padding[UBI_VID_HDR_IVOL_DATA_SIZE - 4]; +} __attribute__ ((packed)); + +/* + * Count of internal UBI volumes. + */ +#define UBI_INT_VOL_COUNT 2 + +/* + * Internal volume IDs start from this digit. There is a reserved room for 4096 + * internal volumes. + */ +#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) + +/** + * enum ubi_internal_volume_numbers - volume IDs of internal UBI volumes. + * + * %UBI_LAYOUT_VOL_ID: volume ID of the layout volume + * %UBI_UPDATE_VOL_ID: volume ID of the update volume + */ +enum ubi_internal_volume_ids { + UBI_LAYOUT_VOL_ID = UBI_INTERNAL_VOL_START, + UBI_UPDATE_VOL_ID = UBI_INTERNAL_VOL_START + 1 +}; + +/* + * Number of logical eraseblocks reserved for internal volumes. + */ +#define UBI_LAYOUT_VOLUME_EBS 2 +#define UBI_UPDATE_VOLUME_EBS 1 + +/* + * Names of internal volumes + */ +#define UBI_LAYOUT_VOLUME_NAME "The layout volume" +#define UBI_UPDATE_VOLUME_NAME "The update volume" + +/* + * Compatibility flags of internal volumes. + */ +#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT +#define UBI_UPDATE_VOLUME_COMPAT UBI_COMPAT_REJECT + +/* + * The maximum number of volumes per one UBI device. + */ +#define UBI_MAX_VOLUMES 128 + +/* + * The maximum volume name length. + */ +#define UBI_VOL_NAME_MAX 127 + +/* + * Size of volume table records. + */ +#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vol_tbl_record) + +/* + * Size of volume table records without the ending CRC. + */ +#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t)) + +/** + * struct ubi_vol_tbl_record - a record in the volume table. + * + * @reserved_pebs: how many physical eraseblocks are reserved for this volume + * @alignment: volume alignment + * @data_pad: how many bytes are not used at the end of the eraseblocks to + * satisfy the requested alignment + * @padding1: reserved, zeroes + * @name_len: the volume name length + * @name: the volume name + * @padding2: reserved, zeroes + * @crc: a CRC32 checksum of the record + * + * The layout volume consists of 2 logical eraseblock, each of which contains + * the volume table (i.e., the volume table is duplicated). The volume table is + * an array of &struct ubi_vol_tbl_record objects indexed by the volume ID. + * + * If the size of the logical eraseblock is large enough to fit + * %UBI_MAX_VOLUMES, the volume table contains %UBI_MAX_VOLUMES records. + * Otherwise, it contains as much records as can be fit (i.e., size of logical + * eraseblock divided by sizeof(struct ubi_vol_tbl_record)). + * + * The @alignment field is specified when the volume is created and cannot be + * later changed. It may be useful, for example, when a block-oriented file + * system works on top of UBI. The @data_pad field is calculated using the + * logical eraseblock size and @alignment. The alignment must be multiple to the + * minimal flash I/O unit. If @alignment is 1, all the available space of + * eraseblocks is used. + * + * Empty records contain all zeroes and the CRC checksum of those zeroes. + */ +struct ubi_vol_tbl_record { + ubi32_t reserved_pebs; + ubi32_t alignment; + ubi32_t data_pad; + uint8_t vol_type; + uint8_t padding1; + ubi16_t name_len; + uint8_t name[UBI_VOL_NAME_MAX + 1]; + uint8_t padding2[24]; + ubi32_t crc; +} __attribute__ ((packed)); + +#endif /* !__UBI_HEADER_H__ */ diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h new file mode 100644 index 0000000..161f674 --- /dev/null +++ b/include/mtd/ubi-user.h @@ -0,0 +1,128 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Artem B. Bityutskiy + */ + +#ifndef __UBI_USER_H__ +#define __UBI_USER_H__ + +#ifndef __KERNEL__ +#define __user +#endif + +/* + * When a new volume is created, users may either specify the volume number they + * want to create or to let UBI automatically assign a volume number using this + * constant. + */ +#define UBI_VOL_NUM_AUTO (-1) + +/* + * IOCTL commands of UBI character devices + */ + +#define UBI_IOC_MAGIC 'o' + +/* Create an UBI volume */ +#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req) +/* Remove an UBI volume */ +#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) +/* Re-size an UBI volume */ +#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) + +/* + * IOCTL commands of UBI volume character devices. + */ + +#define UBI_VOL_IOC_MAGIC 'O' + +/* Start UBI volume update */ +#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) +/* An eraseblock erasure command, used for debugging, disabled by dafault */ +#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 0, int32_t) + +/** + * UBI volume type constants. + * + * @UBI_DYNAMIC_VOLUME: dynamic volume + * @UBI_STATIC_VOLUME: static volume + */ +enum { + UBI_DYNAMIC_VOLUME = 3, + UBI_STATIC_VOLUME = 4 +}; + +/** + * struct ubi_mkvol_req - volume description data structure used in + * volume creation requests. + * + * @vol_id: volume number + * @alignment: volume alignment + * @bytes: volume size in bytes + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @padding: reserved for future, not used + * @name_len: volume name length + * @name: volume name + * + * This structure is used by userspace programs when creating new volumes. The + * @used_bytes field is only necessary when creating static volumes. + * + * The @alignment field specifies the required alignment of the volume logical + * eraseblock. This means, that the size of logical eraseblocks will be aligned + * to this number, i.e., + * (UBI device logical eraseblock size) mod (@alignment) = 0. + * + * To put it differently, the logical eraseblock of this volume may be slightly + * shortened in order to make it properly aligned. The alignment has to be + * multiple of the flash minimal input/output unit, or %1 to utilize the entire + * available space of logical eraseblocks. + * + * The @alignment field may be useful, for example, when one wants to maintain + * a block device on top of an UBI volume. In this case, it is desirable to fit + * an integer number of blocks in logical eraseblocks of this UBI volume. With + * alignment it is possible to update this volume using plane UBI volume image + * BLOBs, without caring about how to properly write them. + */ +struct ubi_mkvol_req { + int32_t vol_id; + int32_t alignment; + int64_t bytes; + int8_t vol_type; + int8_t padding[9]; + int16_t name_len; + __user const char *name; +} __attribute__ ((packed)); + +/** + * struct ubi_rsvol_req - a data structure used in volume re-size requests. + * + * @vol_id: ID of the volume to re-size + * @bytes: new size of the volume in bytes + * + * Re-sizing is possible for both dynamic and static volumes. But while dynamic + * volumes may be re-sized arbitrarily, static volumes cannot be made to be + * smaller then the number of bytes they bear. To arbitrarily shrink a static + * volume, it must be wiped out first (by means of volume update operation with + * zero number of bytes). + */ +struct ubi_rsvol_req { + int64_t bytes; + int32_t vol_id; +} __attribute__ ((packed)); + +#endif /* __UBI_USER_H__ */ diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index 686aa60..307da31 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -1,79 +1,89 @@ # -# This makefile simplifies the build process for a toolchain user. -# A toolchain developer should prefer a manual build process which -# fits to his original needs. +# Makefile for ubi-utils # -X86_PREFIX?=/usr/local -x86_path=./build_x86 -x86_status=$(x86_path)/config.status +HOST_OS_NAME := $(shell uname -s) +HOST_VERSION_NAME := $(shell uname -r) +BUILD_CPU := $(shell uname -m) +BUILD_OS := $(shell uname -o) -PPC_PREFIX?=/opt/ppcnf/crossroot -ppc_path=./build_ppc -ppc_status=$(ppc_path)/config.status +KERNELHDR := ../include # mtd-utils private headers +DESTDIR := /usr/local # default installation +SBINDIR := bin # default directory for binaries -all: x86 ppc +CC := $(CROSS)gcc +CFLAGS := -I./inc -I./src -I$(KERNELHDR) -O2 -g -Wall -Werror \ + -Wwrite-strings -W -std=gnu99 \ + -DHOST_OS_NAME=\"$(HOST_OS_NAME)\" \ + -DHOST_VERSION_NAME=\"$(HOST_VERSION_NAME)\" \ + -DBUILD_CPU=\"$(BUILD_CPU)\" -DBUILD_OS=\"$(BUILD_OS)\" -install: install_x86 install_ppc -uninstall: uninstall_x86 uninstall_ppc +PERLPROGS = mkpfi ubicrc32.pl +TARGETS = ubiupdatevol ubimkvol ubirmvol pfiflash pddcustomize ubimirror \ + bin2nand nand2bin ubigen mkbootenv unubi pfi2bin -install_x86: x86 - make -C $(x86_path) install +vpath %.c ./src -install_ppc: ppc - make -C $(ppc_path) install +%: %.o + $(CC) $(LDFLAGS) -g -o $@ $^ +%.o: %.c + $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,.$(shell basename $<).dep -uninstall_x86: x86 - make -C $(x86_path) uninstall +all: $(TARGETS) -uninstall_ppc: ppc - make -C $(ppc_path) uninstall +IGNORE=${wildcard .*.c.dep} +-include ${IGNORE} +clean: + rm -rf *.o $(TARGETS) .*.c.dep +ubiupdatevol: ubiupdatevol.o error.o libubi.o libubi_sysfs.o + $(CC) $(LDFLAGS) -o $@ $^ -x86: $(x86_status) - make -C $(x86_path) +ubimkvol: ubimkvol.o error.o libubi.o libubi_sysfs.o + $(CC) $(LDFLAGS) -o $@ $^ -ppc: $(ppc_status) - make -C $(ppc_path) +ubirmvol: ubirmvol.o error.o libubi.o libubi_sysfs.o + $(CC) $(LDFLAGS) -o $@ $^ -$(x86_status): $(x86_path) Makefile.in - cd $(x86_path) && ./config.status || ../configure \ - --prefix=$(X86_PREFIX) +pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \ + libubi.o libubi_sysfs.o + $(CC) $(LDFLAGS) -o $@ $^ -$(ppc_status): $(ppc_path) Makefile.in - cd $(ppc_path) && ./config.status || ../configure \ - --build=i686-pc-linux-gnu \ - --host=ppc-linux \ - --prefix=$(PPC_PREFIX) \ - --exec-prefix=$(PPC_PREFIX) +pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \ + bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o + $(CC) $(LDFLAGS) -o $@ $^ -Makefile.in: Makefile.am - ./bootstrap +ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \ + libubi.o libubi_sysfs.o + $(CC) $(LDFLAGS) -o $@ $^ -$(x86_path): - mkdir -p $(x86_path) +nand2bin: nand2bin.o nandecc.o nandcorr.o + $(CC) $(LDFLAGS) -o $@ $^ -$(ppc_path): - mkdir -p $(ppc_path) +bin2nand: bin2nand.o error.o nandecc.o + $(CC) $(LDFLAGS) -o $@ $^ -clean: - rm -rf depcomp install-sh missing .deps \ - config.log config.status \ - inc/Makefile.in lib/Makefile.in - find . -type f -name "*~" -print | xargs $(RM) - rm -f Makefile.in - rm -f aclocal.m4 - rm -rf autom4te.cache - rm -f config.guess - rm -f config.sub - rm -f configure - rm -f depcomp - rm -f install-sh - rm -f ltmain.sh - rm -f missing - rm -f lib/Makefile.in - rm -f inc/Makefile.in - rm -rf $(x86_path) - rm -rf $(ppc_path) +ubigen: ubigen.o libubigen.o crc32.o + $(CC) $(LDFLAGS) -o $@ $^ + +mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o + $(CC) $(LDFLAGS) -o $@ $^ + +unubi: unubi.o crc32.o + $(CC) $(LDFLAGS) -o $@ $^ + +pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \ + hashmap.o reader.o pfi.o + $(CC) $(LDFLAGS) -o $@ $^ + +install: ${TARGETS} + mkdir -p ${DESTDIR}/${SBINDIR} + install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/ + (cd perl && install ${PERLPROGS} ${DESTDIR}/${SBINDIR}/) + +uninstall: + for file in ${TARGETS} ${PERLPROGS}; do \ + $(RM) ${DESTDIR}/${SBINDIR}/$$file; \ + done diff --git a/ubi-utils/Makefile.am b/ubi-utils/Makefile.am deleted file mode 100644 index a5c9252..0000000 --- a/ubi-utils/Makefile.am +++ /dev/null @@ -1,96 +0,0 @@ -AUTOMAKE_OPTIONS = foreign -SUBDIRS=lib inc - - -# ----------------------------------------------------------------------------- -# Scripts (Perl/Bash) which shall be installed. -# -bin_SCRIPTS = $(top_srcdir)/src/mkpfi/mkpfi - -# ----------------------------------------------------------------------------- -# C programs which shall be build and installed. -# -INCLUDES=-I$(top_srcdir)/inc -I$(top_srcdir)/../../kernel/include - -bin_PROGRAMS = bin/pfi2bin \ - bin/bin2nand \ - bin/ubicrc32 \ - bin/mkbootenv \ - bin/ubimirror \ - bin/ubimkvol \ - bin/ubirmvol \ - bin/ubiwritevol \ - bin/pfiflash \ - bin/pddcustomize \ - bin/ubiinfo \ - bin/nand2bin \ - bin/unubi - -# ----------------------------------------------------------------------------- -# C programs which shall be build and NOT installed. (FLD dependency...) -# -noinst_PROGRAMS = bin/ubigen - -bin_ubigen_SOURCES = $(top_srcdir)/src/ubigen/ubigen_main.c -bin_ubigen_LDADD = $(top_builddir)/lib/libubigen.la \ - $(top_builddir)/lib/libcrc32.la - -bin_pfiflash_SOURCES = $(top_srcdir)/src/pfiflash/pfiflash.c -bin_pfiflash_LDADD = $(top_builddir)/lib/libpfiflash.la \ - $(top_builddir)/lib/liberror.la -bin_pfiflash_LDFLAGS = -static - -bin_pddcustomize_SOURCES= $(top_srcdir)/src/pddcustomize/pddcustomize.c -bin_pddcustomize_LDADD = $(top_builddir)/lib/libbootenv.la \ - $(top_builddir)/lib/liberror.la \ - $(top_builddir)/lib/libubi.la \ - $(top_builddir)/lib/libubimirror.la -bin_pddcustomize_LDFLAGS= -static - -bin_pfi2bin_SOURCES = $(top_srcdir)/src/pfi2bin/pfi2bin.c -bin_pfi2bin_LDADD = $(top_builddir)/lib/libubigen.la \ - $(top_builddir)/lib/liberror.la \ - $(top_builddir)/lib/liblist.la \ - $(top_builddir)/lib/libreader.la - -bin_bin2nand_SOURCES = $(top_srcdir)/src/bin2nand/bin2nand.c \ - $(top_srcdir)/src/bin2nand/nandecc.c -bin_bin2nand_LDADD = $(top_builddir)/lib/liberror.la - - -bin_ubicrc32_SOURCES = $(top_srcdir)/src/ubicrc32/ubicrc32.c -bin_ubicrc32_LDADD = $(top_builddir)/lib/libcrc32.la - -bin_mkbootenv_SOURCES = $(top_srcdir)/src/mkbootenv/mkbootenv.c -bin_mkbootenv_LDADD = $(top_builddir)/lib/libbootenv.la \ - $(top_builddir)/lib/liberror.la - - -bin_ubimirror_SOURCES = $(top_srcdir)/src/ubimirror/ubimirror.c -bin_ubimirror_LDADD = $(top_builddir)/lib/liberror.la \ - $(top_builddir)/lib/libubimirror.la -bin_ubimirror_LDFLAGS= -static - -bin_ubimkvol_SOURCES = $(top_srcdir)/src/ubimkvol/ubimkvol.c -bin_ubimkvol_LDADD = $(top_builddir)/lib/libubi.la -bin_ubimkvol_LDFLAGS = -static - -bin_ubirmvol_SOURCES = $(top_srcdir)/src/ubirmvol/ubirmvol.c -bin_ubirmvol_LDADD = $(top_builddir)/lib/libubi.la -bin_ubirmvol_LDFLAGS = -static - -bin_ubiwritevol_SOURCES = $(top_srcdir)/src/ubiwritevol/ubiwritevol.c -bin_ubiwritevol_LDADD = $(top_builddir)/lib/libubi.la -bin_ubiwritevol_LDFLAGS = -static - -bin_ubiinfo_SOURCES = $(top_srcdir)/src/ubiinfo/ubiinfo.c - -bin_nand2bin_SOURCES = $(top_srcdir)/src/nand2bin/nand2bin.c \ - $(top_srcdir)/src/bin2nand/nandecc.c \ - $(top_srcdir)/src/nand2bin/nandcorr.c - -bin_unubi_SOURCES = $(top_srcdir)/src/unubi/unubi.c -bin_unubi_LDADD = $(top_builddir)/lib/libcrc32.la - -clean-local: - rm -rf bin/ diff --git a/ubi-utils/bootstrap b/ubi-utils/bootstrap deleted file mode 100755 index f543912..0000000 --- a/ubi-utils/bootstrap +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -LIBTOOLM4="/usr/local/share/libtool/libltdl" - -if test -d "$LIBTOOLM4"; then - echo "+ aclocal ${LIBTOOLM4}" - aclocal -I ${LIBTOOLM4} -else - echo "+ aclocal" - aclocal -fi -set -x -libtoolize --force -autoheader -automake --foreign --add-missing --copy -autoconf diff --git a/ubi-utils/configure.ac b/ubi-utils/configure.ac deleted file mode 100644 index 9f45176..0000000 --- a/ubi-utils/configure.ac +++ /dev/null @@ -1,52 +0,0 @@ -# Don't remove this check. -AC_PREREQ(2.59) - -# AC_INIT: Package, Version, Bugs -AC_INIT([flashutils],[0.1],[arnez@de.ibm.com]) -AC_CONFIG_HEADERS([inc/config.h:inc/config-h.in]) -AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE([1.8 foreign]) -AM_MAINTAINER_MODE - -# Check debug options -AS_HELP_STRING -AC_ARG_ENABLE([debug], - AS_HELP_STRING([--enable-debug], - [build with debug information [default=yes]]),,enable_debug="yes") - -# Check for programs. -AM_PROG_LIBTOOL -AC_PROG_CC -AC_PROG_INSTALL -AC_PROG_MAKE_SET - -# Checks for header files. -AC_HEADER_STDC -# FIXME: Use AC_CHECK_HEADERS for UBI stuff. -# AC_CHECK_HEADERS([errno.h mtd/ubi-user.h]) -AC_CHECK_HEADERS([errno.h]) - -# Set build flags -if test "x$enable_debug" = "xyes"; then - CFLAGS="$CFLAGS -g -DDEBUG " -fi - -AC_DEFINE_UNQUOTED(HOST_OS, "${host}", [Host OS]) -AC_DEFINE_UNQUOTED(HOST_CPU, "${host_os}", [Host CPU]) -AC_DEFINE_UNQUOTED(BUILD_OS, "${build_os}", [Build OS]) -AC_DEFINE_UNQUOTED(BUILD_CPU, "${build_cpu}", [Build CPU]) - -# Additional Config -AC_C_BIGENDIAN - -# CFLAGS -CFLAGS="-std=gnu99 -Wundef -Wall $CFLAGS" - -# Init output. -AC_CONFIG_FILES([ - Makefile - lib/Makefile - inc/Makefile -]) - -AC_OUTPUT diff --git a/ubi-utils/inc/Makefile.am b/ubi-utils/inc/Makefile.am deleted file mode 100644 index ca22c37..0000000 --- a/ubi-utils/inc/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -AUTOMAKE_OPTIONS = foreign - -# You can export headers if necessary: -nobase_include_HEADERS = pfiflash.h \ - libubi.h diff --git a/ubi-utils/inc/bootenv.h b/ubi-utils/inc/bootenv.h deleted file mode 100644 index 86743ed..0000000 --- a/ubi-utils/inc/bootenv.h +++ /dev/null @@ -1,415 +0,0 @@ -#ifndef __BOOTENV_H__ -#define __BOOTENV_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. - */ - -#include /* FILE */ -#include -#include - -/* DOXYGEN DOCUMENTATION */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @file bootenv.h - * @author oliloh@de.ibm.com - * @version 1.3 - * - * 1.3 Some renaming - */ - -/** - * @mainpage Usage - * - * @section intro Introduction - * This library provides all functionality to handle with the so-called - * platform description data (PDD) and the bootparameters defined in - * U-Boot. It is able to apply the defined PDD operations in PDD update - * scenarios. For more information about the PDD and bootparameter - * environment "bootenv" confer the PDD documentation. - * - * @section ret Return codes - * This library defines some return codes which will be delivered classified - * as warnings or errors. See the "Defines" section for details and numeric - * values. - * - * @section benv Bootenv format description - * There are two different input formats: - * - text files - * - binary files - * - * @subsection txt Text Files - * Text files have to be specified like: - * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim - * - * @subsection bin Binary files - * Binary files have to be specified like: - * @verbatimkey1=value1,value2,value7\0key2=value55,value1\0... @endverbatim - * You can confer the U-Boot documentation for more details. - * - * @section benvlists Bootenv lists format description. - * Values referenced in the preceeding subsection can be - * defined like lists: - * @verbatim value1,value2,value3 @endverbatim - * There are some situation where a conversion of a comma - * seperated list can be useful, e.g. to get a list - * of defined PDD entries. - */ - -#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */ - -/** - * @def BOOTENV_ECRC - * @brief Given binary file is to large. - * @def BOOTENV_EFMT - * @brief Given bootenv section has an invalid format - * @def BOOTENV_EBADENTRY - * @brief Bad entry in the bootenv section. - * @def BOOTENV_EINVAL - * @brief Invalid bootenv defintion. - * @def BOOTENV_ENOPDD - * @brief Given bootenv sectoin has no PDD defintion string (pdd=...). - * @def BOOTENV_EPDDINVAL - * @brief Given bootenv section has an invalid PDD defintion. - * @def BOOTENV_ENOTIMPL - * @brief Functionality not implemented. - * @def BOOTENV_ECOPY - * @brief Bootenv memory copy error - * @def BOOTENV_ENOTFOUND - * @brief Given key has has no value. - * @def BOOTENV_EMAX - * @brief Highest error value. - */ -#define BOOTENV_ETOOBIG 1 -#define BOOTENV_EFMT 2 -#define BOOTENV_EBADENTRY 3 -#define BOOTENV_EINVAL 4 -#define BOOTENV_ENOPDD 5 -#define BOOTENV_EPDDINVAL 6 -#define BOOTENV_ENOTIMPL 7 -#define BOOTENV_ECOPY 8 -#define BOOTENV_ENOTFOUND 9 -#define BOOTENV_EMAX 10 - -/** - * @def BOOTENV_W - * @brief A warning which is handled internally as an error - * but can be recovered by manual effort. - * @def BOOTENV_WPDD_STRING_DIFFERS - * @brief The PDD strings of old and new PDD differ and - * can cause update problems, because new PDD values - * are removed from the bootenv section completely. - */ -#define BOOTENV_W 20 -#define BOOTENV_WPDD_STRING_DIFFERS 21 -#define BOOTENV_WMAX 22 /* highest warning value */ - - -typedef struct bootenv *bootenv_t; - /**< A bootenv library handle. */ - -typedef struct bootenv_list *bootenv_list_t; - /**< A handle for a value list. */ - -typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*, - int*, char*, size_t); - - -/** - * @brief Get a new handle. - * @return 0 - * @return or error - * */ -int bootenv_create(bootenv_t *env); - -/** - * @brief Cleanup structure. - * @param env Bootenv structure which shall be destroyed. - * @return 0 - * @return or error - */ -int bootenv_destroy(bootenv_t *env); - -/** - * @brief Copy a bootenv handle. - * @param in The input bootenv. - * @param out The copied output bootenv. Discards old data. - * @return 0 - * @return or error - */ -int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out); - -/** - * @brief Looks for a value inside the bootenv data. - * @param env Handle to a bootenv structure. - * @param key The key. - * @return NULL key not found - * @return !NULL ptr to value - */ -int bootenv_get(bootenv_t env, const char *key, const char **value); - - -/** - * @brief Looks for a value inside the bootenv data and converts it to num. - * @param env Handle to a bootenv structure. - * @param key The key. - * @param value A pointer to the resulting numerical value - * @return NULL key not found - * @return !NULL ptr to value - */ -int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value); - -/** - * @brief Set a bootenv value by key. - * @param env Handle to a bootenv structure. - * @param key Key. - * @param value Value to set. - * @return 0 - * @return or error - */ -int bootenv_set(bootenv_t env, const char *key, const char *value); - -/** - * @brief Remove the given key (and its value) from a bootenv structure. - * @param env Handle to a bootenv structure. - * @param key Key. - * @return 0 - * @return or error - */ -int bootenv_unset(bootenv_t env, const char *key); - - -/** - * @brief Get a vector of all keys which are currently set - * within a bootenv handle. - * @param env Handle to a bootenv structure. - * @param size The size of the allocated array structure. - * @param sort Flag, if set the vector is sorted ascending. - * @return NULL on error. - * @return !NULL a pointer to the first element the allocated vector. - * @warning Free the allocate memory yourself! - */ -int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort, - const char ***vector); - -/** - * @brief Calculate the size in bytes which are necessary to write the - * current bootenv section in a *binary file. - * @param env bootenv handle. - * @param size The size in bytes of the bootenv handle. - * @return 0 - * @return or ERROR. - */ -int bootenv_size(bootenv_t env, size_t *size); - -/** - * @brief Read a binary bootenv file. - * @param fp File pointer to input stream. - * @param env bootenv handle. - * @param size maximum data size. - * @return 0 - * @return or ERROR. - */ -int bootenv_read(FILE* fp, bootenv_t env, size_t size); - - -/** - * @brief Read bootenv data from an text/ascii file. - * @param fp File pointer to ascii PDD file. - * @param env bootenv handle - * @return 0 - * @return or ERROR. - */ -int bootenv_read_txt(FILE* fp, bootenv_t env); - -/** - * @brief Write a bootenv structure to the given location (binary). - * @param fp Filepointer to binary file. - * @param env Bootenv structure which shall be written. - * @return 0 - * @return or error - */ -int bootenv_write(FILE* fp, bootenv_t env); - -/** - * @brief Write a bootenv structure to the given location (text). - * @param fp Filepointer to text file. - * @param env Bootenv structure which shall be written. - * @return 0 - * @return or error - */ -int bootenv_write_txt(FILE* fp, bootenv_t env); - -/** - * @brief Prototype for a PDD handling funtion - */ - -/** - * @brief The PDD keep operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of PDD keep. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - - -/** - * @brief The PDD merge operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of merge-pdd. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - -/** - * @brief The PDD overwrite operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of overwrite-pdd. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_overwrite(bootenv_t env_new, - bootenv_t env_old, bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - -/** - * @brief Dump a bootenv structure to stdout. (Debug) - * @param env Handle to a bootenv structure. - * @return 0 - * @return or error - */ -int bootenv_dump(bootenv_t env); - -/** - * @brief Validate a bootenv structure. - * @param env Handle to a bootenv structure. - * @return 0 - * @return or error - */ -int bootenv_valid(bootenv_t env); - -/** - * @brief Create a new bootenv list structure. - * @return NULL on error - * @return or a new list handle. - * @note This structure is used to store values in a list. - * A useful addition when handling PDD strings. - */ -int bootenv_list_create(bootenv_list_t *list); - -/** - * @brief Destroy a bootenv list structure - * @param list Handle to a bootenv list structure. - * @return 0 - * @return or error - */ -int bootenv_list_destroy(bootenv_list_t *list); - -/** - * @brief Import a list from a comma seperated string - * @param list Handle to a bootenv list structure. - * @param str Comma seperated string list. - * @return 0 - * @return or error - */ -int bootenv_list_import(bootenv_list_t list, const char *str); - -/** - * @brief Export a list to a string of comma seperated values. - * @param list Handle to a bootenv list structure. - * @return NULL one error - * @return or pointer to a newly allocated string. - * @warning Free the allocated memory by yourself! - */ -int bootenv_list_export(bootenv_list_t list, char **string); - -/** - * @brief Add an item to the list. - * @param list A handle of a list structure. - * @param item An item. - * @return 0 - * @return or error - */ -int bootenv_list_add(bootenv_list_t list, const char *item); - -/** - * @brief Remove an item from the list. - * @param list A handle of a list structure. - * @param item An item. - * @return 0 - * @return or error - */ -int bootenv_list_remove(bootenv_list_t list, const char *item); - -/** - * @brief Check if a given item is in a given list. - * @param list A handle of a list structure. - * @param item An item. - * @return 1 Item is in list. - * @return 0 Item is not in list. - */ -int bootenv_list_is_in(bootenv_list_t list, const char *item); - - -/** - * @brief Convert a list into a vector of all values inside the list. - * @param list Handle to a bootenv structure. - * @param size The size of the allocated vector structure. - * @return 0 - * @return or error - * @warning Free the allocate memory yourself! - */ -int bootenv_list_to_vector(bootenv_list_t list, size_t *size, - const char ***vector); - -/** - * @brief Convert a list into a vector of all values inside the list. - * @param list Handle to a bootenv structure. - * @param size The size of the allocated vector structure. - * @return 0 - * @return or error - * @warning Free the allocate memory yourself! - */ -int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, - uint32_t **vector); - -#ifdef __cplusplus -} -#endif -#endif /*__BOOTENV_H__ */ diff --git a/ubi-utils/inc/config-h.in b/ubi-utils/inc/config-h.in deleted file mode 100644 index ce4998b..0000000 --- a/ubi-utils/inc/config-h.in +++ /dev/null @@ -1,74 +0,0 @@ -/* inc/config-h.in. Generated from configure.ac by autoheader. */ - -/* Build CPU */ -#undef BUILD_CPU - -/* Build OS */ -#undef BUILD_OS - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ERRNO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Host CPU */ -#undef HOST_CPU - -/* Host OS */ -#undef HOST_OS - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -#undef WORDS_BIGENDIAN diff --git a/ubi-utils/inc/crc32.h b/ubi-utils/inc/crc32.h deleted file mode 100644 index 31362b0..0000000 --- a/ubi-utils/inc/crc32.h +++ /dev/null @@ -1,36 +0,0 @@ -#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. - */ - -/* - * 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 - -void init_crc32_table(uint32_t *table); -uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len); - -#endif /* __CRC32_H__ */ diff --git a/ubi-utils/inc/error.h b/ubi-utils/inc/error.h deleted file mode 100644 index 25a1cee..0000000 --- a/ubi-utils/inc/error.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef __ERROR_H__ -#define __ERROR_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. - */ - -#include - -void error_initlog(const char *logfile); -int read_procfile(FILE *fp_out, const char *procfile); - -void __err_ret(const char *fmt, ...); -void __err_sys(const char *fmt, ...); -void __err_msg(const char *fmt, ...); -void __err_quit(const char *fmt, ...); -void __err_dump(const char *fmt, ...); - -void info_msg(const char *fmt, ...); - -#ifdef DEBUG -#define __loc_msg(str) do { \ - __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \ - str, __FILE__, __FUNCTION__, __LINE__); \ -} while (0) -#elif -#define __loc_msg(str) -#endif - - -#define err_dump(fmt, ...) do { \ - __loc_msg("ErrDump"); \ - __err_dump(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_quit(fmt, ...) do { \ - __loc_msg("ErrQuit"); \ - __err_quit(fmt, ##__VA_ARGS__); \ -} while (0) - - -#define err_ret(fmt, ...) do { \ - __loc_msg("ErrRet"); \ - __err_ret(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_sys(fmt, ...) do { \ - __loc_msg("ErrSys"); \ - __err_sys(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_msg(fmt, ...) do { \ - __loc_msg("ErrMsg"); \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) - -#define log_msg(fmt, ...) do { \ - /* __loc_msg("LogMsg"); */ \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) - -#ifdef DEBUG -#define dbg_msg(fmt, ...) do { \ - __loc_msg("DbgMsg"); \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) -#elif -#define dbg_msg(fmt, ...) -#endif - -#endif /* __ERROR_H__ */ diff --git a/ubi-utils/inc/example_ubi.h b/ubi-utils/inc/example_ubi.h deleted file mode 100644 index 23c7b54..0000000 --- a/ubi-utils/inc/example_ubi.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __EXAMPLE_UBI_H__ -#define __EXAMPLE_UBI_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. - */ - -/** - * Defaults for our cards. - */ -#define EXAMPLE_UBI_DEVICE 0 -#define EXAMPLE_BOOTENV_VOL_ID_1 4 -#define EXAMPLE_BOOTENV_VOL_ID_2 5 - -#endif /* __EXAMPLE_UBI_H__ */ diff --git a/ubi-utils/inc/list.h b/ubi-utils/inc/list.h deleted file mode 100644 index e8452a2..0000000 --- a/ubi-utils/inc/list.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __LIST_H__ -#define __LIST_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 - -#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) - -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; - 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__ */ diff --git a/ubi-utils/inc/nandecc.h b/ubi-utils/inc/nandecc.h deleted file mode 100644 index fb5d529..0000000 --- a/ubi-utils/inc/nandecc.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _NAND_ECC_H -#define _NAND_ECC_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. - * - * NAND ecc functions - */ - -#include - -extern int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code); -extern int nand_correct_data(uint8_t *dat, const uint8_t *fail_ecc); - -#endif diff --git a/ubi-utils/inc/peb.h b/ubi-utils/inc/peb.h deleted file mode 100644 index 246bce8..0000000 --- a/ubi-utils/inc/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 -#include - -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/inc/pfi.h b/ubi-utils/inc/pfi.h deleted file mode 100644 index 8c5cc07..0000000 --- a/ubi-utils/inc/pfi.h +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef __pfi_h -#define __pfi_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. - */ - -/** - * @file pfi.h - * - * @author Oliver Lohmann - * Andreas Arnez - * Joern Engel - * Frank Haverkamp - * - * @brief libpfi will hold all code to create and process pfi - * images. Definitions made in this file are equaly usable for the - * development host and the target system. - * - * @note This header additionally holds the official definitions for - * the pfi headers. - */ - -#include /* FILE */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Definitions. */ - -#define PFI_HDRVERSION 1 /* current header version */ - -#define PFI_ENOVERSION 1 /* unknown version */ -#define PFI_ENOHEADER 2 /* not a pfi header */ -#define PFI_EINSUFF 3 /* insufficient information */ -#define PFI_EUNDEF 4 /* key not defined */ -#define PFI_ENOMEM 5 /* out of memory */ -#define PFI_EBADTYPE 6 /* bad data type */ -#define PFI_EFILE 7 /* file I/O error: see errno */ -#define PFI_EFILEINVAL 8 /* file format not valid */ -#define PFI_EINVAL 9 /* invalid parameter */ -#define PFI_ERANGE 10 /* invalid range */ -#define PFI_EMODE 11 /* expecting other mode in this header */ -#define PFI_DATA_START 12 /* data section starts */ -#define PFI_EMAX 13 /* should be always larger as the largest - error code */ - -#define PFI_LABEL_LEN 64 /* This is the maximum length for a - PFI header label */ -#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an - entry in the mode and type fields */ - -#define PFI_UBI_MAX_VOLUMES 128 -#define PFI_UBI_VOL_NAME_LEN 127 - -/** - * @brief The pfi header allows to set flags which influence the flashing - * behaviour. - */ -#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; - - -/** - * @brief Initialize a pfi header object. - * - * @param head Pointer to handle. This function allocates memory - * for this data structure. - * @return 0 on success, otherwise: - * PFI_ENOMEM : no memory available for the handle. - */ -int pfi_header_init (pfi_header *head); - - -/** - * @brief Destroy a pfi header object. - * - * @param head handle. head is invalid after calling this function. - * @return 0 always. - */ -int pfi_header_destroy (pfi_header *head); - - -/** - * @brief Add a key/value pair to a pfi header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value string. Must be 0 terminated. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_ENOMEM : no memory available for the handle. - * PFI_EBADTYPE : value is not an hex string. This happens - * when the key stores an integer and the - * new value is not convertable e.g. not in - * 0xXXXXXXXX format. - */ -int pfi_header_setvalue (pfi_header head, - const char *key, const char *value); - - -/** - * @brief Add a key/value pair to a pfi header object. Provide the - * value as a number. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value value to set. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : value is not a string. This happens - * when the key stores a string. - */ -int pfi_header_setnumber (pfi_header head, - const char *key, uint32_t value); - - -/** - * @brief For a given key, return the numerical value stored in a - * pfi header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : stored value is not an integer but a string. - */ -int pfi_header_getnumber (pfi_header head, - const char *key, uint32_t *value); - - -static inline uint32_t -pfi_getnumber(pfi_header head, const char *key) -{ - uint32_t value; - pfi_header_getnumber(head, key, &value); - return value; -} - -/** - * @brief For a given key, return the string value stored in a pfi - * header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value string. Memory must be allocated by the user. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : stored value is not a string but an integer. - */ -int pfi_header_getstring (pfi_header head, - const char *key, char *value, size_t size); - - -/** - * @brief Write a pfi header object into a given file. - * - * @param out output stream. - * @param head handle. - * @return 0 on success, error values otherwise: - * PFI_EINSUFF : not all mandatory fields are filled. - * PFI_ENOHEADER : wrong header version or magic number. - * -E* : see . - */ -int pfi_header_write (FILE *out, pfi_header head); - - -/** - * @brief Read a pfi header object from a given file. - * - * @param in input stream. - * @param head handle. - * @return 0 on success, error values otherwise: - * PFI_ENOVERSION: unknown header version. - * PFI_EFILE : cannot read enough data. - * PFI_ENOHEADER : wrong header version or magic number. - * -E* : see . - * - * If the header verification returned success the user can assume that - * all mandatory fields for a particular version are accessible. Checking - * the return code when calling the get-function for those keys is not - * required in those cases. For optional fields the checking must still be - * done. - */ -int pfi_header_read (FILE *in, pfi_header head); - - -/** - * @brief Display a pfi header in human-readable form. - * - * @param out output stream. - * @param head handle. - * @return always 0. - * - * @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); - - -/* - * @brief Iterates over a stream of pfi files. The iterator function - * must advance the file pointer in FILE *in to the next pfi - * header. Function exists on feof(in). - * - * @param in input file descriptor, must be open and valid. - * @param func iterator function called when pfi header could be - * read and was validated. The function must return 0 on - * success. - * @return See pfi_header_init and pfi_header_read. - * PFI_EINVAL : func is not valid - * 0 ok. - */ -typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data); - -int pfi_read (FILE *in, pfi_read_func func, void *priv_data); - - -#ifdef __cplusplus -} -#endif - -#endif /* __pfi_h */ diff --git a/ubi-utils/inc/pfiflash.h b/ubi-utils/inc/pfiflash.h deleted file mode 100644 index fc2eede..0000000 --- a/ubi-utils/inc/pfiflash.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef __PFIFLASH_H__ -#define __PFIFLASH_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. - */ - -/** - * - * @file pfi.h - * - * @author Oliver Lohmann - * - * @brief The pfiflash library offers an interface for using the - * pfiflash * utility. - */ - -#include /* FILE */ - -#define PFIFLASH_MAX_ERR_BUF_SIZE 1024 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum pdd_handling_t -{ - PDD_KEEP = 0, - PDD_MERGE, - PDD_OVERWRITE, - PDD_HANDLING_NUM, /* always the last item */ -} pdd_handling_t; /**< Possible PDD handle algorithms. */ - -/** - * @brief Flashes a PFI file to UBI Device 0. - * @param complete [0|1] Do a complete system update. - * @param seqnum Index in a redundant group. - * @param pdd_handling The PDD handling algorithm. - * @param err_buf An error buffer. - * @param err_buf_size Size of the error buffer. - */ -int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, - char *err_buf, size_t err_buf_size); - -#ifdef __cplusplus -} -#endif - -#endif /* __PFIFLASH_H__ */ diff --git a/ubi-utils/inc/reader.h b/ubi-utils/inc/reader.h deleted file mode 100644 index 93c15e3..0000000 --- a/ubi-utils/inc/reader.h +++ /dev/null @@ -1,84 +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 -#include - -#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 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; -}; - -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) */ -}; - -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/inc/ubigen.h b/ubi-utils/inc/ubigen.h deleted file mode 100644 index 9e9e8ec..0000000 --- a/ubi-utils/inc/ubigen.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef __UBIGEN_H__ -#define __UBIGEN_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: Frank Haverkamp - * - * An utility to update UBI volumes. - */ - -#include /* FILE */ -#include -#include - -#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_vol_tbl_record *lvol_rec); - -#ifdef __cplusplus -} -#endif - -#endif /* __UBIGEN_H__ */ diff --git a/ubi-utils/inc/ubimirror.h b/ubi-utils/inc/ubimirror.h deleted file mode 100644 index 893f5ce..0000000 --- a/ubi-utils/inc/ubimirror.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __UBIMIRROR_H__ -#define __UBIMIRROR_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 - * - * An utility to mirror UBI volumes. - */ - -#include - -/** - * @def EUBIMIRROR_SRC_EQ_DST - * @brief Given source volume is also in the set of destination volumes. - */ -#define EUBIMIRROR_SRC_EQ_DST 20 - -/** - * @def EUBIMIRROR_NO_SRC - * @brief The given source volume does not exist. - */ -#define EUBIMIRROR_NO_SRC 21 - -/** - * @def EUBIMIRROR_NO_DST - * @brief One of the given destination volumes does not exist. - */ -#define EUBIMIRROR_NO_DST 22 - -/** - * @brief Mirrors UBI devices from a source device (specified by seqnum) - * to n target devices. - * @param devno Device number used by the UBI operations. - * @param seqnum An index into ids (defines the src_id). - * @param ids An array of ids. - * @param ids_size The number of entries in the ids array. - * @param err_buf A buffer to store verbose error messages. - * @param err_buf_size The size of the error buffer. - * - * @note A seqnum of value < 0 defaults to a seqnum of 0. - * @note A seqnum exceeding the range of ids_size defaults to 0. - * @note An empty ids list results in a empty stmt. - * @pre The UBI volume which shall be used as source volume exists. - * @pre The UBI volumes which are defined as destination volumes exist. - * @post The content of the UBI volume which was defined as source volume - * equals the content of the volumes which were defined as destination. - */ -int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, size_t ids_size, - char *err_buf, size_t err_buf_size); - -#endif /* __UBIMIRROR_H__ */ diff --git a/ubi-utils/perl/f128_nand_sample.cfg b/ubi-utils/perl/f128_nand_sample.cfg new file mode 100644 index 0000000..e468d9d --- /dev/null +++ b/ubi-utils/perl/f128_nand_sample.cfg @@ -0,0 +1,38 @@ +[targets] +complete=ipl,spl,bootenv,kernel,rootfs +bootcode=spl,bootenv + +# Build sections +[ipl] +image=ipl.bin +raw_starts=0x00000000 +raw_total_size=128kiB + +[spl] +image=u-boot.bin +ubi_ids=2,3 +ubi_size=2MiB +ubi_type=static +ubi_names=spl_0,spl_1 + +[bootenv] +bootenv_file=bootenv_complete.txt +ubi_ids=4,5 +ubi_size=128kiB +ubi_type=static +ubi_names=bootenv_0,bootenv_1 + +[kernel] +image=vmlinux.bin +ubi_ids=6,7 +ubi_size=6MiB +ubi_type=static +ubi_names=kernel_0,kernel_1 + +[rootfs] +image=rootfs.bin +ubi_ids=8,9 +ubi_alignment=2kiB +ubi_size=16MiB +ubi_type=dynamic +ubi_names=rootfs_0,rootfs_1 diff --git a/ubi-utils/perl/f64_nor_sample.cfg b/ubi-utils/perl/f64_nor_sample.cfg new file mode 100644 index 0000000..fd44e27 --- /dev/null +++ b/ubi-utils/perl/f64_nor_sample.cfg @@ -0,0 +1,39 @@ +[targets] +complete=ipl,spl,bootenv,kernel,rootfs +bootcode=spl,bootenv +rootfs=rootfs + +# Build sections +[ipl] +image=ipl.bin +raw_starts=0x02FE0000, 0x03FE0000 +raw_total_size=128kiB + +[spl] +image=u-boot.bin +ubi_ids=2,3 +ubi_size=2MiB +ubi_type=static +ubi_names=spl_0,spl_1 + +[bootenv] +bootenv_file=bootenv_complete.txt +ubi_ids=4,5 +ubi_size=128kiB +ubi_type=static +ubi_names=bootenv_0,bootenv_1 + +[kernel] +image=vmlinux.bin +ubi_ids=6,7 +ubi_size=6MiB +ubi_type=static +ubi_names=kernel_0,kernel_1 + +[rootfs] +image=rootfs.bin +ubi_ids=8,9 +ubi_alignment=2kiB +ubi_size=16128kiB +ubi_type=dynamic +ubi_names=rootfs_0,rootfs_1 diff --git a/ubi-utils/perl/mkpfi b/ubi-utils/perl/mkpfi new file mode 100755 index 0000000..2cce587 --- /dev/null +++ b/ubi-utils/perl/mkpfi @@ -0,0 +1,723 @@ +#!/usr/bin/perl +# +# 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. +# + +# +# mkpfi +# +# This perl program is assembles PFI files from a config file. +# +# Author: Oliver Lohmann (oliloh@de.ibm.com) +# +use warnings; +use strict; +use lib "/usr/lib/perl5"; # Please change this path as you need it, or + # make a proposal how this could be done + # nicer. +use Getopt::Long; +use Pod::Usage; +use Config::IniFiles; +use File::Temp; + +# ---------------------------------------------------------------------------- +# Versions +our $version : unique = "0.1"; +our $pfi_version : unique = "0x1"; + +# ---------------------------------------------------------------------------- +# Globals +my $verbose = 0; +my $cfg; + +my %opts = (); +my %files = (config => ""); +my @tmp_files; + +my %tools = (ubicrc32 => "ubicrc32"); + +# ---------------------------------------------------------------------------- +# Processing the input sections +# +# The idea is to combine each section entry with a function +# in order to allow some kind of preprocessing for the values +# before they are written into the PFI file. +# This is especially useful to be more verbose and +# user-friendly in the layout file. +# +# All key-function hashes are applied after the general +# validation of the configuration file. +# If any mandatory key is missing in a section the user +# will be informed and the PFI creation process is aborted. +# +# Default keys will be checked for their presence inside the config +# file. If they are missing, they will be generated with appr. values. + +# Mandatory keys for UBI volumes. +my %ubi_keys = ("ubi_ids" => \&check_id_list, + "ubi_size" => \&replace_num, + "ubi_type" => \&replace_type, + "ubi_names" => \&remove_spaces, + "ubi_alignment" => \&replace_num); + +# Mandatory keys for RAW sections. +my %raw_keys = ("raw_starts" => \&expand_starts, + "raw_total_size" => \&replace_num); + +# Common default keys for documentation and control purposes. +my %common_keys = ("flags" => \&replace_num, + "label" => \&do_nothing); + +# Define any defaults here. Values which maintained in this default +# region need not to be specified by the user explicitly. +my %def_ubi_keys = ("ubi_alignment" => [\&set_default, "0x1"]); +my %def_raw_keys = (); +my %def_common_keys = ("flags" => [\&set_default, "0x0"], + "label" => [\&generate_label, ""]); + +# ---------------------------------------------------------------------------- +# Input keys, actually the path to the input data. + +my %input_keys = ("image" => \&do_nothing); + +# Placeholder keys allow the replacement via a special +# purpose function. E.g. the bootenv_file key will be used +# to generate bootenv binary data from an text file and +# replace the bootenv_file key with an image key to handle it +# in the same way in the further creation process. +my %input_placeholder_keys = ("bootenv_file" => \&create_bootenv_image); + +# ---------------------------------------------------------------------------- +# Helper + +# @brief Get current time string. +sub get_date { + my $tmp = scalar localtime; + $tmp =~ s/ /_/g; + return $tmp; +} + +# @brief Print an info message to stdout. +sub INFO($) { + my $str = shift; + + if (!$verbose) { + return; + } + + print STDOUT $str; +} + +# @brief Print an error message to stderr. +sub ERR($) { + my $str = shift; + print STDERR $str; +} + +# @brief Print a warning message to stderr. +sub WARN($) { + my $str = shift; + print STDERR $str; +} + +sub parse_command_line($) { + my $opt = shift; + my $result = GetOptions( "help" => \$$opt{'help'}, + "man" => \$$opt{'man'}, + "config=s" => \$$opt{'config'}, + "verbose" => \$$opt{'verbose'}, + ) or pod2usage(2); + pod2usage(1) if defined ($$opt{help}); + pod2usage(-verbose => 2) if defined ($$opt{man}); + + $verbose = $$opt{verbose} if defined $$opt{verbose}; + + if (!defined $$opt{config}) { + ERR("[ ERROR: No config file specified. Aborting...\n"); + exit 1; + } + +} + +# @brief Check if all needed tools are in PATH. +sub check_tools { + my $err = 0; + my $key; + + foreach $key (keys %tools) { + if (`which $tools{$key}` eq "") { + ERR("\n") if ($err == 0); + ERR("! Please add the tool \'$tools{$key}\' " . + "to your path!\n"); + $err = 1; + } + } + die "[ ERROR: Did not find all needed tools!\n" if $err; +} + +sub open_cfg_file($) { + my $fname = shift; + my $res = new Config::IniFiles( -file => $fname ); + + die "[ ERROR: Cannot load your config file!\n" if (!defined $res); + return $res; +} + +sub set_default($$$$) { + my ($cfg, $section, $parameter, $def_value) = @_; + $cfg->newval($section, $parameter, $def_value); + return; +} + +sub generate_label($$$$) { + my ($cfg, $section, $parameter, $def_value) = @_; + my $new_label = $def_value . $section; + $new_label .= "_" . get_date; + $cfg->newval($section, $parameter, $new_label); + return; +} + +# @brief Converts any num to a unified hex string, i.e the resulting value +# always starts with "0x" and is aligned to 8 hexdigits. +# @return Returns 0 on success, otherwise an error occured. +# +sub any_num_to_hex($$) { + my $val = shift; + my $res = shift; + + # M(iB) + if ($val =~ m/([0-9]+)[Mm][i]?[Bb]?/g) { + $$res = sprintf("0x%08x", $1 * 1024 * 1024); + } + # k(iB) + elsif ($val =~ m/([0-9]+)[kK][i]?[Bb]?/g) { + $$res = sprintf("0x%08x", $1 * 1024); + } + # hex + elsif ($val =~ m/0x?([0-9a-fA-F]+)/g) { + $$res = sprintf("0x%08x", hex $1); + } + # decimal + elsif ($val =~ m/^([0-9]+)$/g) { + $$res = sprintf("0x%08x", $1); + } + else { + $$res = ""; + return -1; + } + + return 0; +} + +sub remove_spaces($$$) { + my ($cfg, $section, $parameter) = @_; + my ($start, @starts, @new_starts); + my $val = $cfg->val($section, $parameter); + my $res; + + $val =~ s/ //g; # spaces + $cfg->newval($section, $parameter, $val); +} + +sub expand_starts($$$) { + my ($cfg, $section, $parameter) = @_; + my ($start, @starts, @new_starts); + my $val = $cfg->val($section, $parameter); + my $res; + + $val =~ s/ //g; # spaces + @starts = split(/,/, $val); + + foreach $start (@starts) { + if (any_num_to_hex($start, \$res) != 0) { + ERR("[ ERROR: [$section]\n"); + ERR("[ Expecting a list of numeric " . + "values for parameter: $parameter\n"); + exit 1; + } + push (@new_starts, $res); + } + $res = join(',', @starts); + + $cfg->newval($section, $parameter, $res); +} + +sub check_id_list($$$) { + my ($cfg, $section, $parameter) = @_; + my $val = $cfg->val($section, $parameter); + my $res; + + if (!($val =~ m/^[0-9]+[,0-9]*/)) { + ERR("[ ERROR: Syntax error in 'ubi_ids' in " . + "section '$section': $val\n"); + ERR("[ Aborting... "); + exit 1; + } +} + +sub replace_type($$$) { + my ($cfg, $section, $parameter) = @_; + my $val = $cfg->val($section, $parameter); + my $res; + + $res = lc($val); + grep {$res eq $_} ('static', 'dynamic') + or die "[ ERROR: Unknown UBI Volume Type in " . + "section '$section': $val\n"; + + $cfg->newval($section, $parameter, $res); +} + + +sub replace_num($$$) { + my ($cfg, $section, $parameter) = @_; + my $val = $cfg->val($section, $parameter); + my $res = ""; + + if (any_num_to_hex($val, \$res) != 0) { + ERR("[ ERROR: [$section]\n"); + ERR("[ Expecting a numeric value " . + "for parameter: $parameter\n"); + exit 1; + } + $cfg->newval($section, $parameter, $res); +} + +sub do_nothing($$$) { + my ($cfg, $section, $parameter) = @_; + return; +} + +sub bootenv_sanity_check($) { + my $env = shift; # hash array containing bootenv + my %pdd = (); + + defined($$env{'pdd'}) or return "'pdd' not defined"; + foreach (split /,/, $$env{'pdd'}) { + defined($$env{$_}) or return "undefined '$_' in pdd"; + $pdd{$_} = 1; + } + + defined $$env{'pdd_preserve'} or + return ""; + foreach (split /,/, $$env{'pdd_preserve'}) { + defined($pdd{$_}) + or return "pdd_preserve field '$_' not in pdd"; + } + return ""; +} + +sub create_bootenv_image($$$) { + my ($cfg, $section, $parameter) = @_; + my $txt_fn = $cfg->val($section, "bootenv_file"); + my $in; + + my %value = (); + my @key = (); + + open $in, "<", $txt_fn + or die "[ ERROR: can't open bootenv file '$txt_fn'.\n"; + while (<$in>) { + next if (/^\s*(\#.*)?$/); # Skip comments/whitespace. + + if (/^(\S+?)\+\=(.*)$/) { + defined($value{$1}) or + die "$txt_fn:$.: error: appending to" . + " non-existent '$1'\n"; + $value{$1} .= $2; + } elsif (/^(\S+?)\=(.*)$/) { + not defined($value{$1}) or + die "$txt_fn:$.: error: trying to" . + " redefine '$1'\n"; + push @key, $1; + $value{$1} = $2; + } else { + die "$txt_fn:$.: error: unrecognized syntax\n"; + } + } + close $in; + + $_ = &bootenv_sanity_check(\%value) + and die "$txt_fn: error: $_\n"; + + my $tmp_file = new File::Temp(); + push (@tmp_files, $tmp_file); + + foreach (@key) { + print $tmp_file "$_=", $value{$_}, "\0"; + } + close $tmp_file; + + $cfg->newval($section, "image", $tmp_file-> filename); +} + +sub process_keys($$$) { + my ($cfg, $section, $keys) = @_; + my @parameters = $cfg->Parameters($section); + my $i; + + for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { + if (defined($$keys{$parameters[$i]})) { + $$keys{$parameters[$i]}->($cfg, $section, + $parameters[$i]); + } + } + +} + +sub is_in_keylist($$) { + my ($key, $keys) = @_; + my $i; + + for ($i = 0; $i < scalar(@$keys); $i++) { + if ($$keys[$i] eq $key) { + return 1; + } + } + + return 0; +} + +sub check_default_keys($$$) { + my ($cfg, $section, $keys) = @_; + my @parameters = $cfg->Parameters($section); + my $key; + + foreach $key (keys %$keys) { + if (!is_in_keylist($key, \@parameters)) { + $$keys{$key}[0]-> + ($cfg, $section, $key, $$keys{$key}[1]); + } + } + +} + + + +sub check_keys($$$) { + my ($cfg, $section, $keys) = @_; + my @parameters = $cfg->Parameters($section); + my ($i, $key, $err); + + $err = 0; + for ($i = 0 ; $i < scalar(@$keys) ; $i++ ) { + if (!is_in_keylist($$keys[$i], \@parameters)) { + ERR("[ ERROR: [$section]\n") if $err == 0; + $err = 1; + ERR("[ Missing key '$$keys[$i]'\n"); + } + } + + if ($err) { + ERR("[ Aborting...\n"); + exit 1; + } +} + +sub push_pfi_data($$$$$) { + my ($cfg, $section, $pfi_infos, $keys, $mode) = @_; + my ($tmp, $i, $hdr); + + my %pfi_info = (); + $pfi_info{'mode'} = $mode; + $pfi_info{'image'} = $cfg->val($section, "image"); + + # Build the PFI header + $hdr = sprintf("PFI!\n"); + $hdr .= sprintf("version=0x%08x\n", hex $pfi_version); + $hdr .= sprintf("mode=$mode\n"); + + # calculate the size of the binary data part + $tmp = -s $cfg->val($section, "image"); + if (!defined $tmp) { + ERR("[ ERROR: [$section]\n"); + ERR("[ Missing input image: " + . $cfg->val($section, "image") . "\n"); + exit 1; + } + # Check for the image to fit into the given space + my $quota; + if ($mode eq 'raw') { + $quota = oct $cfg->val($section, "raw_total_size"); + } elsif ($mode eq 'ubi') { + $quota = oct $cfg->val($section, "ubi_size"); + } + $tmp <= $quota + or die "[ERROR: image file too big: " . + $cfg->val($section, "image") . "\n"; + $pfi_info{'size'} = $tmp; + + $hdr .= sprintf("size=0x%08x\n", $tmp); + + my $img_file = $cfg->val($section, "image"); + my $crc32 = `$tools{'ubicrc32'} $img_file 2>&1`; + if (any_num_to_hex($crc32, \$tmp) != 0) { + die "[ ERROR: $tools{'ubicrc32'} returned with errors"; + } + $hdr .= sprintf("crc=$tmp\n"); + + + # Process all remaining keys + for ($i = 0; $i < scalar (@$keys); $i++) { + if ($$keys[$i] eq "image") { # special case image input file + if (! -e ($tmp = $cfg->val($section, "image"))) { + ERR("[ ERROR: [$section]\n"); + ERR("[ Cannot find input file $tmp\n"); + exit 1; + } + next; + } + $hdr .= sprintf("%s=%s\n", $$keys[$i], + $cfg->val($section, $$keys[$i])); + } + + $hdr .= sprintf("\n"); # end marker for PFI-header + + $pfi_info{'header'} = $hdr; + + # store in the header list + push @$pfi_infos, \%pfi_info; +} + +sub process_section($$$$$$) { + my ($cfg, $section, $pfi_infos, $custom_keys, + $def_custom_keys, $mode) = @_; + my @keys = (keys %common_keys, keys %$custom_keys); + my @complete_keys = (@keys, keys %input_keys); + + # set defaults if necessary + check_default_keys($cfg, $section, $def_custom_keys); + check_default_keys($cfg, $section, \%def_common_keys); + + # check for placeholders... + process_keys($cfg, $section, \%input_placeholder_keys); + + # VALIDATE layout.cfg entries + check_keys($cfg, $section, \@complete_keys); + + # execute linked functions (if any) + process_keys($cfg, $section, \%common_keys); + process_keys($cfg, $section, $custom_keys); + + push_pfi_data($cfg, $section, $pfi_infos, \@keys, $mode); +} + +sub get_section_info($$) { + my ($cfg, $section) = @_; + my @parameters = $cfg->Parameters($section); + my ($ubi, $raw, $i, @res); + + $ubi = $raw = 0; + for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { + if ($parameters[$i] =~ m/ubi_/gi) { + $ubi = 1; + @res = (\%ubi_keys, \%def_ubi_keys, "ubi"); + } + if ($parameters[$i] =~ m/raw_/gi) { + $raw = 1; + @res = (\%raw_keys, \%def_raw_keys, "raw"); + } + } + + if (($ubi + $raw) != 1) { # double definition in section + ERR("[ ERROR: Layout error in section '$section'\n"); + exit 1; + } + + return @res; +} + +sub mk_target_list($$) { + my $val = shift; + my $tmp = shift; + my $complete = 0; + + if ($val =~ m/\((.*)\)/g) { + $val = $1; + $complete = 1; + } + $val =~ s/ //g; # spaces + + @$tmp = split(/,/, $val); + + return $complete; +} + +sub copy_bytes($$$) { + my ($in, $out, $to_copy) = @_; + + while ($to_copy) { + my $buf; + my $bufsize = 1024*1024; + + $bufsize < $to_copy or $bufsize = $to_copy; + read($in, $buf, $bufsize) == $bufsize + or die "[ ERROR: Image file shrunk during operation\n"; + print $out $buf; + $to_copy -= $bufsize; + } +} + +sub write_target($$) { + my ($pfi_infos, $target) = @_; + my ($pfi_info); + + INFO("[ Writting target pfi file: '$target.pfi'...\n"); + if (-e "$target.pfi") { + WARN("! Replaced old pfi...\n"); + `rm -f $target.pfi`; + } + open(FILE, ">", "$target.pfi") + or die "[ ERROR: Cannot create output file: $target.pfi\n"; + binmode(FILE); + + # @FIXME sort by mode (first raw, then ubi) + # Currently this ordering is based on a string comparism. :-) + @$pfi_infos = sort {(lc $$a{'mode'}) cmp (lc $$b{'mode'})} @$pfi_infos; + + # Print all headers first + foreach $pfi_info (@$pfi_infos) { + print FILE $$pfi_info{'header'}; + + } + # Print the linked data sections + print FILE "DATA\n"; + foreach $pfi_info (@$pfi_infos) { + open(IMAGE, "<", $$pfi_info{'image'}) + or die "[ ERROR: Cannot open input image: " . + "$$pfi_info{'image'}" . "\n"; + binmode(IMAGE); + ©_bytes(\*IMAGE, \*FILE, $$pfi_info{'size'}); + close(IMAGE) or die "[ ERROR: Cannot close input image: " . + "$$pfi_info{'image'}" . "\n"; + } + close(FILE) or die "[ ERROR: Cannot close output file: $target.pfi\n"; +} + +sub process_config($) { + my $cfg = shift; + my @sections = $cfg->Sections; + my ($i, $j, $keylist, $def_keylist, $mode, $tmp, + @tlist, $complete,@pfi_infos); + + my @parameters = $cfg->Parameters("targets") or + die "[ ERROR: Config file has no 'targets' section!\n"; + + for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { + INFO("[ Processing target '$parameters[$i]'...\n"); + @pfi_infos = (); + + # get a list of subtargets + $complete = mk_target_list($cfg->val("targets", + $parameters[$i]), \@tlist); + # build all subtargets + for ($j = 0 ; $j < scalar(@tlist) ; $j++ ) { + ($keylist, $def_keylist, $mode) + = get_section_info($cfg, $tlist[$j]); + process_section($cfg, $tlist[$j], + \@pfi_infos, + $keylist, $def_keylist, $mode); + } + + write_target(\@pfi_infos, $parameters[$i]); + } + + INFO("[ Success.\n"); + + +} + +sub clear_files() { + # @FIXME: + # Works implicitly and Fedora seems to have removed + # the cleanup call. Thus for now, inactive. + # File::Temp::cleanup(); +} + +require 5.008_000; # Tested with version 5.8.0. +select STDOUT; $| = 1; # make STDOUT output unbuffered +select STDERR; $| = 1; # make STDERR output unbuffered + +parse_command_line(\%opts); +check_tools; +$cfg = open_cfg_file($opts{config}); +process_config($cfg); +clear_files; + +__END__ + + +=head1 NAME + +mkpfi - Using GetOpt::Long, Pod::Usage, Config::IniFiles + + +=head1 SYNOPSIS + +mkpfi [OPTIONS ...] + + + OPTION + + [--config] [--help] [--man] + + +=head1 ABSTRACT + +Perl script for generating pdd pfi files from given config files. + +=head1 OPTIONS + +=over + +=item B<--help> + +Print out brief help message. + +=item B<--usage> + +Print usage. + +=item B<--config> + +Config input file. + +=item B<--man> + +Print manual page, same as 'perldoc mkpfi'. + +=item B<--verbose> + +Be verbose! + +=back + +=head1 BUGS + +Report via MTD mailing list + + +=head1 SEE ALSO + +http://www.linux-mtd.infradead.org/ + + +=head1 AUTHOR + +Oliver Lohmann (oliloh@de.ibm.com) + +=cut diff --git a/ubi-utils/perl/ubicrc32.pl b/ubi-utils/perl/ubicrc32.pl new file mode 100755 index 0000000..add5f9d --- /dev/null +++ b/ubi-utils/perl/ubicrc32.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl -w + +# Subroutine crc32(): Calculates the CRC on a given string. + +{ + my @table = (); + + # @brief Calculate CRC32 for a given string. + sub crc32 + { + unless (@table) { + # Initialize the CRC table + my $poly = 0xEDB88320; + @table = (); + + for my $i (0..255) { + my $c = $i; + + for my $j (0..7) { + $c = ($c & 1) ? (($c >> 1) ^ $poly) : ($c >> 1); + } + $table[$i] = $c; + } + } + my $s = shift; # string to calculate the CRC for + my $crc = shift; # CRC start value + + defined($crc) + or $crc = 0xffffffff; # Default CRC start value + + for (my $i = 0; $i < length($s); $i++) { + $crc = $table[($crc ^ ord(substr($s, $i, 1))) & 0xff] + ^ ($crc >> 8); + } + return $crc; + } +} + +sub crc32_on_file +{ + my $file = shift; + + my $crc32 = crc32(''); + my $buf = ''; + my $ret = 0; + + while ($ret = read($file, $buf, 8192)) { + $crc32 = crc32($buf, $crc32); + } + defined($ret) + or return undef; + printf("0x%x\n", $crc32); +} + + +# Main routine: Calculate the CRCs on the given files and print the +# results. + +{ + if (@ARGV) { + while (my $path = shift) { + my $file; + open $file, "<", $path + or die "Error opening '$path'.\n"; + + &crc32_on_file($file) + or die "Error reading from '$path'.\n"; + close $file; + } + } else { + &crc32_on_file(\*STDIN) + or die "Error reading from stdin.\n"; + } +} diff --git a/ubi-utils/scripts/ubi_test.sh b/ubi-utils/scripts/ubi_test.sh index 9017148..622ec7e 100755 --- a/ubi-utils/scripts/ubi_test.sh +++ b/ubi-utils/scripts/ubi_test.sh @@ -10,7 +10,7 @@ export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashut UBIMKVOL=ubimkvol UBIRMVOL=ubirmvol -UBIWRITEVOL=ubiwritevol +UBIWRITEVOL=ubiupdateevol # 128 KiB 131072 # 256 KiB 262144 diff --git a/ubi-utils/scripts/ubi_tools_test.sh b/ubi-utils/scripts/ubi_tools_test.sh index 43fc2bb..9163e0c 100755 --- a/ubi-utils/scripts/ubi_tools_test.sh +++ b/ubi-utils/scripts/ubi_tools_test.sh @@ -12,7 +12,7 @@ export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashut UBIMKVOL=ubimkvol UBIRMVOL=ubirmvol -UBIWRITEVOL=ubiwritevol +UBIWRITEVOL=ubiupdatevol PFIFLASH=pfiflash CMP=cmp diff --git a/ubi-utils/src/bin2nand.c b/ubi-utils/src/bin2nand.c new file mode 100644 index 0000000..168f7dd --- /dev/null +++ b/ubi-utils/src/bin2nand.c @@ -0,0 +1,356 @@ +/* + * 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 + */ + +/* + * Create a flashable NAND image from a binary image + * + * History: + * 1.0: Initial release (tglx) + * 1.1: Understands hex and dec input parameters (tglx) + * 1.2: Generates separated OOB data, if needed. (oloh) + * 1.3: Padds data/oob to a given size. (oloh) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "error.h" +#include "config.h" +#include "nandecc.h" + +#define CHECK_ENDP(option, endp) do { \ + if (*endp) { \ + fprintf(stderr, \ + "Parse error option \'%s\'. " \ + "No correct numeric value.\n" \ + , option); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +typedef enum action_t { + ACT_NORMAL = 0x00000001, +} action_t; + +#define PAGESIZE 2048 +#define PADDING 0 /* 0 means, do not adjust anything */ +#define BUFSIZE 4096 + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "bin2nand - a tool for adding OOB information to a " + "binary input file.\n"; + +static const char copyright [] __attribute__((unused)) = + "FIXME: insert license type."; /* FIXME */ + +static struct argp_option options[] = { + { .name = "copyright", + .key = 'c', + .arg = NULL, + .flags = 0, + .doc = "Print copyright information.", + .group = 1 }, + + { .name = "pagesize", + .key = 'p', + .arg = "", + .flags = 0, + .doc = "Pagesize in Byte/Mi/ki. Default = 2048", + .group = 1 }, + + { .name = "padding", + .key = 'j', + .arg = "", + .flags = 0, + .doc = "Padding in Byte/Mi/ki. Default = no padding", + .group = 1 }, + + { .name = "output", + .key = 'o', + .arg = "", + .flags = 0, + .doc = "Output filename. Interleaved Data/OOB if output-oob not " + "specified.", + .group = 2 }, + + { .name = "output-oob", + .key = 'q', + .arg = "", + .flags = 0, + .doc = "Write OOB data in separate file.", + .group = 2 }, + + { .name = NULL, + .key = 0, + .arg = NULL, + .flags = 0, + .doc = NULL, + .group = 0 }, +}; + +typedef struct myargs { + action_t action; + + size_t pagesize; + size_t padding; + + FILE* fp_in; + char *file_out_data; /* Either: Data and OOB interleaved + or plain data */ + char *file_out_oob; /* OOB Data only. */ + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +} myargs; + + +static int ustrtoull(const char *cp, char **endp, unsigned int base) +{ + unsigned long long res = strtoull(cp, endp, base); + + switch (**endp) { + case 'G': + res *= 1024; + case 'M': + res *= 1024; + case 'k': + case 'K': + res *= 1024; + /* "Ki", "ki", "Mi" or "Gi" are to be used. */ + if ((*endp)[1] == 'i') + (*endp) += 2; + } + return res; +} + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + int err = 0; + char* endp; + + myargs *args = state->input; + + switch (key) { + case 'p': /* pagesize */ + args->pagesize = (size_t) ustrtoull(arg, &endp, 0); + CHECK_ENDP("p", endp); + break; + case 'j': /* padding */ + args->padding = (size_t) ustrtoull(arg, &endp, 0); + CHECK_ENDP("j", endp); + break; + case 'o': /* output */ + args->file_out_data = arg; + break; + case 'q': /* output oob */ + args->file_out_oob = arg; + break; + case ARGP_KEY_ARG: /* input file */ + args->fp_in = fopen(arg, "rb"); + if ((args->fp_in) == NULL) { + err_quit("Cannot open file %s for input\n", arg); + } + args->arg1 = arg; + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + case ARGP_KEY_END: + if (err) { + err_msg("\n"); + argp_usage(state); + exit(EXIT_FAILURE); + } + break; + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: 0, + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + +static int +process_page(uint8_t* buf, size_t pagesize, + FILE *fp_data, FILE* fp_oob, size_t* written) +{ + int eccpoi, oobsize; + size_t i; + uint8_t oobbuf[64]; + + memset(oobbuf, 0xff, sizeof(oobbuf)); + + switch(pagesize) { + case 2048: oobsize = 64; eccpoi = 64 / 2; break; + case 512: oobsize = 16; eccpoi = 16 / 2; break; + default: + err_msg("Unsupported page size: %d\n", pagesize); + return -EINVAL; + } + + for (i = 0; i < pagesize; i += 256, eccpoi += 3) { + oobbuf[eccpoi++] = 0x0; + /* Calculate ECC */ + nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); + } + + /* write data */ + *written += fwrite(buf, 1, pagesize, fp_data); + + /* either separate oob or interleave with data */ + if (fp_oob) { + fwrite(oobbuf, 1, oobsize, fp_oob); + if (ferror(fp_oob)) { + err_msg("IO error\n"); + return -EIO; + } + } + else { + fwrite(oobbuf, 1, oobsize, fp_data); + if (ferror(fp_data)) { + err_msg("IO error\n"); + return -EIO; + } + } + + return 0; +} + +int main (int argc, char** argv) +{ + int rc = -1; + int res = 0; + size_t written, read; + myargs args = { + .action = ACT_NORMAL, + .pagesize = PAGESIZE, + .padding = PADDING, + .fp_in = NULL, + .file_out_data = NULL, + .file_out_oob = NULL, + }; + + FILE* fp_out_data = stdout; + FILE* fp_out_oob = NULL; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + + uint8_t* buf = calloc(1, BUFSIZE); + if (!buf) { + err_quit("Cannot allocate page buffer.\n"); + } + + if (!args.fp_in) { + err_msg("No input image specified!\n"); + goto err; + } + + if (strcmp(args.file_out_data, "") != 0) { + fp_out_data = fopen(args.file_out_data, "wb"); + if (fp_out_data == NULL) { + err_sys("Cannot open file %s for output\n", + args.file_out_data); + goto err; + } + } + + if (strcmp(args.file_out_oob, "") != 0) { + fp_out_oob = fopen(args.file_out_oob, "wb"); + if (fp_out_oob == NULL) { + err_sys("Cannot open file %s for output\n", + args.file_out_oob); + goto err; + } + } + + + while(1) { + read = fread(buf, 1, args.pagesize, args.fp_in); + if (feof(args.fp_in) && read == 0) + break; + + if (read < args.pagesize) { + err_msg("Image not page aligned\n"); + goto err; + } + + if (ferror(args.fp_in)) { + err_msg("Read error\n"); + goto err; + } + + res = process_page(buf, args.pagesize, fp_out_data, + fp_out_oob, &written); + if (res != 0) + goto err; + } + + while (written < args.padding) { + memset(buf, 0xff, args.pagesize); + res = process_page(buf, args.pagesize, fp_out_data, + fp_out_oob, &written); + if (res != 0) + goto err; + } + + rc = 0; +err: + free(buf); + + if (args.fp_in) + fclose(args.fp_in); + + if (fp_out_oob) + fclose(fp_out_oob); + + if (fp_out_data && fp_out_data != stdout) + fclose(fp_out_data); + + if (rc != 0) { + err_msg("Error during conversion. rc: %d\n", rc); + remove(args.file_out_data); + remove(args.file_out_oob); + } + return rc; +} diff --git a/ubi-utils/src/bin2nand/bin2nand.c b/ubi-utils/src/bin2nand/bin2nand.c deleted file mode 100644 index 5224e3b..0000000 --- a/ubi-utils/src/bin2nand/bin2nand.c +++ /dev/null @@ -1,343 +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 - */ - -/* - * Create a flashable NAND image from a binary image - * - * History: - * 1.0: Initial release (tglx) - * - * 1.1: Understands hex and dec input parameters (tglx) - * 1.2: Generates separated OOB data, if needed. (oloh) - * 1.3: Padds data/oob to a given size. (oloh) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "error.h" -#include "config.h" -#include "nandecc.h" - -#define CHECK_ENDP(option, endp) do { \ - if (*endp) { \ - fprintf(stderr, \ - "Parse error option \'%s\'. " \ - "No correct numeric value.\n" \ - , option); \ - exit(EXIT_FAILURE); \ - } \ -} while(0) - -typedef enum action_t { - ACT_NORMAL = 0x00000001, -} action_t; - -#define PAGESIZE 2048 -#define PADDING 0 /* 0 means, do not adjust anything */ -#define BUFSIZE 4096 - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "bin2nand - a tool for adding OOB information to a " - "binary input file.\n"; - -static const char copyright [] __attribute__((unused)) = - "FIXME: insert license type."; /* FIXME */ - -static struct argp_option options[] = { - { name: "copyright", key: 'c', arg: NULL, flags: 0, - doc: "Print copyright information.", - group: 1 }, - - { name: "pagesize", key: 'p', arg: "", flags: 0, - doc: "Pagesize in Byte/Mi/ki. Default: 2048", - group: 1 }, - - { name: "padding", key: 'j', arg: "", flags: 0, - doc: "Padding in Byte/Mi/ki. Default: no padding", - group: 1 }, - - /* Output options */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Output settings:", - group: 2 }, - - { name: "output", key: 'o', arg: "", flags: 0, - doc: "Output filename. Interleaved Data/OOB if output-oob not " - "specified.", - group: 2 }, - - { name: "output-oob", key: 'q', arg: "", flags: 0, - doc: "Write OOB data in separate file.", - group: 2 }, - - { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, -}; - -typedef struct myargs { - action_t action; - - size_t pagesize; - size_t padding; - - FILE* fp_in; - char *file_out_data; /* Either: Data and OOB interleaved - or plain data */ - char *file_out_oob; /* OOB Data only. */ - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - - -static int ustrtoull(const char *cp, char **endp, unsigned int base) -{ - unsigned long long res = strtoull(cp, endp, base); - - switch (**endp) { - case 'G': - res *= 1024; - case 'M': - res *= 1024; - case 'k': - case 'K': - res *= 1024; - /* "Ki", "ki", "Mi" or "Gi" are to be used. */ - if ((*endp)[1] == 'i') - (*endp) += 2; - } - return res; -} - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - int err = 0; - char* endp; - - myargs *args = state->input; - - switch (key) { - case 'p': /* pagesize */ - args->pagesize = (size_t) ustrtoull(arg, &endp, 0); - CHECK_ENDP("p", endp); - break; - case 'j': /* padding */ - args->padding = (size_t) ustrtoull(arg, &endp, 0); - CHECK_ENDP("j", endp); - break; - case 'o': /* output */ - args->file_out_data = arg; - break; - case 'q': /* output oob */ - args->file_out_oob = arg; - break; - case ARGP_KEY_ARG: /* input file */ - args->fp_in = fopen(arg, "rb"); - if ((args->fp_in) == NULL) { - err_quit("Cannot open file %s for input\n", arg); - } - args->arg1 = arg; - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - case ARGP_KEY_END: - if (err) { - err_msg("\n"); - argp_usage(state); - exit(EXIT_FAILURE); - } - break; - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: 0, - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - -static int -process_page(uint8_t* buf, size_t pagesize, - FILE *fp_data, FILE* fp_oob, size_t* written) -{ - int eccpoi, oobsize; - size_t i; - uint8_t oobbuf[64]; - - memset(oobbuf, 0xff, sizeof(oobbuf)); - - switch(pagesize) { - case 2048: oobsize = 64; eccpoi = 64 / 2; break; - case 512: oobsize = 16; eccpoi = 16 / 2; break; - default: - err_msg("Unsupported page size: %d\n", pagesize); - return -EINVAL; - } - - for (i = 0; i < pagesize; i += 256, eccpoi += 3) { - oobbuf[eccpoi++] = 0x0; - /* Calculate ECC */ - nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); - } - - /* write data */ - *written += fwrite(buf, 1, pagesize, fp_data); - - /* either separate oob or interleave with data */ - if (fp_oob) { - fwrite(oobbuf, 1, oobsize, fp_oob); - if (ferror(fp_oob)) { - err_msg("IO error\n"); - return -EIO; - } - } - else { - fwrite(oobbuf, 1, oobsize, fp_data); - if (ferror(fp_data)) { - err_msg("IO error\n"); - return -EIO; - } - } - - return 0; -} - -int main (int argc, char** argv) -{ - int rc = -1; - int res = 0; - size_t written, read; - myargs args = { - .action = ACT_NORMAL, - .pagesize = PAGESIZE, - .padding = PADDING, - .fp_in = NULL, - .file_out_data = "", - .file_out_oob = "", - }; - - FILE* fp_out_data = stdout; - FILE* fp_out_oob = NULL; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - - uint8_t* buf = calloc(1, BUFSIZE); - if (!buf) { - err_quit("Cannot allocate page buffer.\n"); - } - - if (!args.fp_in) { - err_msg("No input image specified!\n"); - goto err; - } - - if (strcmp(args.file_out_data, "") != 0) { - fp_out_data = fopen(args.file_out_data, "wb"); - if (fp_out_data == NULL) { - err_sys("Cannot open file %s for output\n", - args.file_out_data); - goto err; - } - } - - if (strcmp(args.file_out_oob, "") != 0) { - fp_out_oob = fopen(args.file_out_oob, "wb"); - if (fp_out_oob == NULL) { - err_sys("Cannot open file %s for output\n", - args.file_out_oob); - goto err; - } - } - - - while(1) { - read = fread(buf, 1, args.pagesize, args.fp_in); - if (feof(args.fp_in) && read == 0) - break; - - if (read < args.pagesize) { - err_msg("Image not page aligned\n"); - goto err; - } - - if (ferror(args.fp_in)) { - err_msg("Read error\n"); - goto err; - } - - res = process_page(buf, args.pagesize, fp_out_data, - fp_out_oob, &written); - if (res != 0) - goto err; - } - - while (written < args.padding) { - memset(buf, 0xff, args.pagesize); - res = process_page(buf, args.pagesize, fp_out_data, - fp_out_oob, &written); - if (res != 0) - goto err; - } - - rc = 0; -err: - free(buf); - - if (args.fp_in) - fclose(args.fp_in); - - if (fp_out_oob) - fclose(fp_out_oob); - - if (fp_out_data && fp_out_data != stdout) - fclose(fp_out_data); - - if (rc != 0) { - err_msg("Error during conversion. rc: %d\n", rc); - remove(args.file_out_data); - remove(args.file_out_oob); - } - return rc; -} diff --git a/ubi-utils/src/bin2nand/nandecc.c b/ubi-utils/src/bin2nand/nandecc.c deleted file mode 100644 index 71660ef..0000000 --- a/ubi-utils/src/bin2nand/nandecc.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file contains an ECC algorithm from Toshiba that detects and - * corrects 1 bit errors in a 256 byte block of data. - * - * drivers/mtd/nand/nand_ecc.c - * - * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) - * Toshiba America Electronics Components, Inc. - * - * This file 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 or (at your option) any - * later version. - * - * This file 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 file; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * As a special exception, if other files instantiate templates or use - * macros or inline functions from these files, or you compile these - * files and link them with other works to produce a work based on these - * files, these files do not by themselves cause the resulting work to be - * covered by the GNU General Public License. However the source code for - * these files must still be made available in accordance with section (3) - * of the GNU General Public License. - * - * This exception does not invalidate any other reasons why a work based on - * this file might be covered by the GNU General Public License. - */ - -#include "nandecc.h" - -/* - * Pre-calculated 256-way 1 byte column parity - */ -static const uint8_t nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, - 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, - 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, - 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, - 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, - 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, - 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, - 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, - 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, - 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, - 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, - 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, - 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, - 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, - 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, - 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, - 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -}; - -/** - * nand_trans_result - [GENERIC] create non-inverted ECC - * @reg2: line parity reg 2 - * @reg3: line parity reg 3 - * @ecc_code: ecc - * - * Creates non-inverted ECC code from line parity - */ -static void nand_trans_result(uint8_t reg2, uint8_t reg3, - uint8_t *ecc_code) -{ - uint8_t a, b, i, tmp1, tmp2; - - /* Initialize variables */ - a = b = 0x80; - tmp1 = tmp2 = 0; - - /* Calculate first ECC byte */ - for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ - tmp1 |= b; - b >>= 1; - if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ - tmp1 |= b; - b >>= 1; - a >>= 1; - } - - /* Calculate second ECC byte */ - b = 0x80; - for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ - tmp2 |= b; - b >>= 1; - if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ - tmp2 |= b; - b >>= 1; - a >>= 1; - } - - /* Store two of the ECC bytes */ - ecc_code[1] = tmp1; - ecc_code[0] = tmp2; -} - -/** - * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for - * 256 byte block - * - * @dat: raw data - * @ecc_code: buffer for ECC - */ -int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code) -{ - uint8_t idx, reg1, reg2, reg3; - int j; - - /* Initialize variables */ - reg1 = reg2 = reg3 = 0; - ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; - - /* Build up column parity */ - for(j = 0; j < 256; j++) { - - /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[dat[j]]; - reg1 ^= (idx & 0x3f); - - /* All bit XOR = 1 ? */ - if (idx & 0x40) { - reg3 ^= (uint8_t) j; - reg2 ^= ~((uint8_t) j); - } - } - - /* Create non-inverted ECC code from line parity */ - nand_trans_result(reg2, reg3, ecc_code); - - /* Calculate final ECC code */ - ecc_code[0] = ~ecc_code[0]; - ecc_code[1] = ~ecc_code[1]; - ecc_code[2] = ((~reg1) << 2) | 0x03; - return 0; -} diff --git a/ubi-utils/src/bin2nand/nandecc.h b/ubi-utils/src/bin2nand/nandecc.h deleted file mode 100644 index 8ae8a66..0000000 --- a/ubi-utils/src/bin2nand/nandecc.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * NAND ecc functions - */ -#ifndef _NAND_ECC_H -#define _NAND_ECC_H - -#include - -extern int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code); - -#endif diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c new file mode 100644 index 0000000..8871d90 --- /dev/null +++ b/ubi-utils/src/bootenv.c @@ -0,0 +1,961 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "hashmap.h" +#include "error.h" + +#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */ + +/* Structures */ +struct bootenv { + hashmap_t map; ///< Pointer to hashmap which holds data structure. +}; + +struct bootenv_list { + hashmap_t head; ///< Pointer to list which holds the data structure. +}; + +/** + * @brief Remove the '\n' from a given line. + * @param line Input/Output line. + * @param size Size of the line. + * @param fp File Pointer. + * @return 0 + * @return or error + */ +static int +remove_lf(char *line, size_t size, FILE* fp) +{ + size_t i; + + for (i = 0; i < size; i++) { + if (line[i] == '\n') { + line[i] = '\0'; + return 0; + } + } + + if (!feof(fp)) { + return BOOTENV_EINVAL; + } + + return 0; +} + +/** + * @brief Determine if a line contains only WS. + * @param line The line to process. + * @param size Size of input line. + * @return 1 Yes, only WS. + * @return 0 No, contains data. + */ +static int +is_ws(const char *line, size_t size) +{ + size_t i = 0; + + while (i < size) { + switch (line[i]) { + case '\n': + return 1; + case '#': + return 1; + case ' ': + i++; + continue; + case '\t': + i++; + continue; + default: /* any other char -> no cmnt */ + return 0; + } + } + + return 0; +} + + +/* ------------------------------------------------------------------------- */ + +/** + * @brief Build a list from a comma seperated value string. + * @param list Pointer to hashmap structure which shall store + * the list. + * @param value Comma seperated value string. + * @return 0 + * @return or error. + */ +static int +build_list_definition(hashmap_t list, const char *value) +{ + int rc = 0; + char *str = NULL; + char *ptr = NULL; + size_t len, i, j; + + /* str: val1,val2 , val4,...,valN */ + len = strlen(value); + str = (char*) malloc((len+1) * sizeof(char)); + + /* 1. reformat string: remove spaces */ + for (i = 0, j = 0; i < len; i++) { + if (value[i] == ' ') + continue; + + str[j] = value[i]; + j++; + } + str[j] = '\0'; + + /* str: val1,val2,val4,...,valN\0*/ + /* 2. replace ',' seperator with '\0' */ + len = strlen(str); + for (i = 0; i < len; i++) { + if (str[i] == ',') { + str[i] = '\0'; + } + } + + /* str: val1\0val2\0val4\0...\0valN\0*/ + /* 3. insert definitions into a hash map, using it like a list */ + i = j = 0; + ptr = str; + while (((i = strlen(ptr)) > 0) && (j < len)) { + rc = hashmap_add(list, ptr, ""); + if (rc != 0) { + free(str); + return rc; + } + j += i+1; + if (j < len) + ptr += i+1; + } + + free(str); + return rc; +} + +/** + * @brief Extract a key value pair and add it to a hashmap + * @param str Input string which contains a key value pair. + * @param env The updated handle which contains the new pair. + * @return 0 + * @return or error + * @note The input string format is: "key=value" + */ +static int +extract_pair(const char *str, bootenv_t env) +{ + int rc = 0; + char *key = NULL; + char *val = NULL; + + key = strdup(str); + if (key == NULL) + return -ENOMEM; + + val = strstr(key, "="); + if (val == NULL) { + rc = BOOTENV_EBADENTRY; + goto err; + } + + *val = '\0'; /* split strings */ + val++; + rc = bootenv_set(env, key, val); + +err: + free(key); + return rc; +} + +int +bootenv_destroy(bootenv_t* env) +{ + int rc = 0; + + if (env == NULL || *env == NULL) + return -EINVAL; + + bootenv_t tmp = *env; + + rc = hashmap_free(tmp->map); + if (rc != 0) + return rc; + + free(tmp); + return rc; +} + +int +bootenv_create(bootenv_t* env) +{ + bootenv_t res; + res = (bootenv_t) calloc(1, sizeof(struct bootenv)); + + if (res == NULL) + return -ENOMEM; + + res->map = hashmap_new(); + + if (res->map == NULL) { + free(res); + return -ENOMEM; + } + + *env = res; + + return 0; +} + + +/** + * @brief Read a formatted buffer and scan it for valid bootenv + * key/value pairs. Add those pairs into a hashmap. + * @param env Hashmap which shall be used to hold the data. + * @param buf Formatted buffer. + * @param size Size of the buffer. + * @return 0 + * @return or error + */ +static int +rd_buffer(bootenv_t env, const char *buf, size_t size) +{ + const char *curr = buf; /* ptr to current key/value pair */ + uint32_t i = 0; /* current length */ + uint32_t j = 0; /* processed chars */ + uint32_t items = 0; /* processed items */ + int rc = 0; + + if (buf[size-1] != '\0') { + return BOOTENV_EFMT; + } + + while ((i = strlen(curr)) != 0) { + /* there is a key value pair remaining */ + rc = extract_pair(curr, env); + if (rc != 0) { + rc = BOOTENV_EINVAL; + return rc; + } + items++; + + j += i; + if (j >= size) + return 0; /* finished, end of buffer */ + curr += i + 1; + } + + return 0; +} + +/** + * If we have a single file containing the boot-parameter size should + * be specified either as the size of the file or as BOOTENV_MAXSIZE. + * If the bootparameter are in the middle of a file we need the exact + * length of the data. + */ +int +bootenv_read(FILE* fp, bootenv_t env, size_t size) +{ + int rc; + char *buf = NULL; + size_t i = 0; + + if ((fp == NULL) || (env == NULL)) + return -EINVAL; + + /* allocate temp buffer */ + buf = (char*) calloc(1, size * sizeof(char)); + if (buf == NULL) + return -ENOMEM; + + /* FIXME Andreas, please review this I removed size-1 and + * replaced it by just size, I saw the kernel image starting + * with a 0x0060.... and not with the 0x60.... what it should + * be. Is this a tools problem or is it a problem here where + * fp is moved not to the right place due to the former size-1 + * here. + */ + while((i < size) && (!feof(fp))) { + int c = fgetc(fp); + + if (c == EOF) { + buf[i++] = '\0'; + break; /* we have enough */ + } + + /* log_msg("%c", c); */ /* FIXME DBG */ + + buf[i++] = c; + if (ferror(fp)) { + rc = -EIO; + goto err; + } + } + + /* transfer to hashmap */ + rc = rd_buffer(env, buf, size); + + /* FIXME DBG */ + /* log_msg("\n%s:%d rc=%d\n", __func__, __LINE__, rc); */ + +err: + free(buf); + return rc; +} + + + +int +bootenv_read_txt(FILE* fp, bootenv_t env) +{ + int rc = 0; + char *buf = NULL; + char *line = NULL; + char *lstart = NULL; + char *curr = NULL; + size_t len; + size_t size; + + if ((fp == NULL) || (env == NULL)) + return -EINVAL; + + size = BOOTENV_MAXSIZE; + + /* allocate temp buffers */ + buf = (char*) calloc(1, size * sizeof(char)); + lstart = line = (char*) calloc(1, size * sizeof(char)); + if ((buf == NULL) || (line == NULL)) { + rc = -ENOMEM; + goto err; + } + + curr = buf; + while ((line = fgets(line, size, fp)) != NULL) { + if (is_ws(line, size)) { + continue; + } + rc = remove_lf(line, BOOTENV_MAXSIZE, fp); + if (rc != 0) { + goto err; + } + + /* copy new line to binary buffer */ + len = strlen(line); + if (len > size) { + rc = -EFBIG; + goto err; + } + size -= len; /* track remaining space */ + + memcpy(curr, line, len); + curr += len + 1; /* for \0 seperator */ + } + + rc = rd_buffer(env, buf, BOOTENV_MAXSIZE); +err: + if (buf != NULL) + free(buf); + if (lstart != NULL) + free(lstart); + return rc; +} + +static int +fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max, + size_t *written) +{ + int rc = 0; + size_t keys_size, i; + size_t wr = 0; + const char **keys = NULL; + const char *val = NULL; + + rc = bootenv_get_key_vector(env, &keys_size, 1, &keys); + if (rc != 0) + goto err; + + for (i = 0; i < keys_size; i++) { + if (wr > buf_size_max) { + rc = -ENOSPC; + goto err; + } + + rc = bootenv_get(env, keys[i], &val); + if (rc != 0) + goto err; + + wr += snprintf(buf + wr, buf_size_max - wr, + "%s=%s", keys[i], val); + wr++; /* for \0 */ + } + + *written = wr; + +err: + if (keys != NULL) + free(keys); + + return rc; +} + +int +bootenv_write(FILE* fp, bootenv_t env) +{ + int rc = 0; + size_t size = 0; + char *buf = NULL; + + if ((fp == NULL) || (env == NULL)) + return -EINVAL; + + buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); + if (buf == NULL) + return -ENOMEM; + + rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size); + if (rc != 0) + goto err; + + if (fwrite(buf, size, 1, fp) != 1) { + rc = -EIO; + goto err; + } + +err: + if (buf != NULL) + free(buf); + return rc; +} + +int +bootenv_size(bootenv_t env, size_t *size) +{ + int rc = 0; + char *buf = NULL; + + if (env == NULL) + return -EINVAL; + + buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); + if (buf == NULL) + return -ENOMEM; + + rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size); + if (rc != 0) + goto err; + +err: + if (buf != NULL) + free(buf); + return rc; +} + +int +bootenv_write_txt(FILE* fp, bootenv_t env) +{ + int rc = 0; + size_t size, wr, i; + const char **keys = NULL; + const char *key = NULL; + const char *val = NULL; + + if ((fp == NULL) || (env == NULL)) + return -EINVAL; + + rc = bootenv_get_key_vector(env, &size, 1, &keys); + if (rc != 0) + goto err; + + for (i = 0; i < size; i++) { + key = keys[i]; + rc = bootenv_get(env, key, &val); + if (rc != 0) + goto err; + + wr = fprintf(fp, "%s=%s\n", key, val); + if (wr != strlen(key) + strlen(val) + 2) { + rc = -EIO; + goto err; + } + } + +err: + if (keys != NULL) + free(keys); + return rc; +} + +int +bootenv_valid(bootenv_t env __unused) +{ + /* @FIXME No sanity check implemented. */ + return 0; +} + +int +bootenv_copy_bootenv(bootenv_t in, bootenv_t *out) +{ + int rc = 0; + const char *tmp = NULL; + const char **keys = NULL; + size_t vec_size, i; + + if ((in == NULL) || (out == NULL)) + return -EINVAL; + + /* purge output var for sure... */ + rc = bootenv_destroy(out); + if (rc != 0) + return rc; + + /* create the new map */ + rc = bootenv_create(out); + if (rc != 0) + goto err; + + /* get the key list from the input map */ + rc = bootenv_get_key_vector(in, &vec_size, 0, &keys); + if (rc != 0) + goto err; + + if (vec_size != hashmap_size(in->map)) { + rc = BOOTENV_ECOPY; + goto err; + } + + /* make a deep copy of the hashmap */ + for (i = 0; i < vec_size; i++) { + rc = bootenv_get(in, keys[i], &tmp); + if (rc != 0) + goto err; + + rc = bootenv_set(*out, keys[i], tmp); + if (rc != 0) + goto err; + } + +err: + if (keys != NULL) + free(keys); + + return rc; +} + +/* ------------------------------------------------------------------------- */ + + +int +bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, + int *warnings, char *err_buf __unused, + size_t err_buf_size __unused) +{ + bootenv_list_t l_old = NULL; + bootenv_list_t l_new = NULL; + const char *pdd_old = NULL; + const char *pdd_new = NULL; + const char *tmp = NULL; + const char **vec_old = NULL; + const char **vec_new = NULL; + const char **pdd_up_vec = NULL; + size_t vec_old_size, vec_new_size, pdd_up_vec_size, i; + int rc = 0; + + if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) + return -EINVAL; + + /* get the pdd strings, e.g.: + * pdd_old=a,b,c + * pdd_new=a,c,d,e */ + rc = bootenv_get(env_old, "pdd", &pdd_old); + if (rc != 0) + goto err; + rc = bootenv_get(env_new, "pdd", &pdd_new); + if (rc != 0) + goto err; + + /* put it into a list and then convert it to an vector */ + rc = bootenv_list_create(&l_old); + if (rc != 0) + goto err; + rc = bootenv_list_create(&l_new); + if (rc != 0) + goto err; + + rc = bootenv_list_import(l_old, pdd_old); + if (rc != 0) + goto err; + + rc = bootenv_list_import(l_new, pdd_new); + if (rc != 0) + goto err; + + rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old); + if (rc != 0) + goto err; + + rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new); + if (rc != 0) + goto err; + + rc = bootenv_copy_bootenv(env_new, env_res); + if (rc != 0) + goto err; + + /* calculate the update vector between the old and new pdd */ + pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size, + vec_new, vec_new_size, &pdd_up_vec_size); + + if (pdd_up_vec == NULL) { + rc = -ENOMEM; + goto err; + } + + if (pdd_up_vec_size != 0) { + /* need to warn the user about the unset of + * some pdd/bootenv values */ + *warnings = BOOTENV_WPDD_STRING_DIFFERS; + + /* remove all entries in the new bootenv load */ + for (i = 0; i < pdd_up_vec_size; i++) { + bootenv_unset(*env_res, pdd_up_vec[i]); + } + } + + /* generate the keep array and copy old pdd values to new bootenv */ + for (i = 0; i < vec_old_size; i++) { + rc = bootenv_get(env_old, vec_old[i], &tmp); + if (rc != 0) { + rc = BOOTENV_EPDDINVAL; + goto err; + } + rc = bootenv_set(*env_res, vec_old[i], tmp); + if (rc != 0) { + goto err; + } + } + /* put the old pdd string into the result map */ + rc = bootenv_set(*env_res, "pdd", pdd_old); + if (rc != 0) { + goto err; + } + + +err: + if (vec_old != NULL) + free(vec_old); + if (vec_new != NULL) + free(vec_new); + if (pdd_up_vec != NULL) + free(pdd_up_vec); + + bootenv_list_destroy(&l_old); + bootenv_list_destroy(&l_new); + return rc; +} + + +int +bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new, + bootenv_t *env_res, int *warnings __unused, + char *err_buf __unused, size_t err_buf_size __unused) +{ + if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) + return -EINVAL; + + return bootenv_copy_bootenv(env_new, env_res); +} + +int +bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, + int *warnings __unused, char *err_buf, size_t err_buf_size) +{ + if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) + return -EINVAL; + + snprintf(err_buf, err_buf_size, "The PDD merge operation is not " + "implemented. Contact: "); + + return BOOTENV_ENOTIMPL; +} + +/* ------------------------------------------------------------------------- */ + +int +bootenv_get(bootenv_t env, const char *key, const char **value) +{ + if (env == NULL) + return -EINVAL; + + *value = hashmap_lookup(env->map, key); + if (*value == NULL) + return BOOTENV_ENOTFOUND; + + return 0; +} + +int +bootenv_get_num(bootenv_t env, const char *key, uint32_t *value) +{ + char *endptr = NULL; + const char *str; + + if (env == NULL) + return 0; + + str = hashmap_lookup(env->map, key); + if (!str) + return -EINVAL; + + *value = strtoul(str, &endptr, 0); + + if (*endptr == '\0') { + return 0; + } + + return -EINVAL; +} + +int +bootenv_set(bootenv_t env, const char *key, const char *value) +{ + if (env == NULL) + return -EINVAL; + + return hashmap_add(env->map, key, value); +} + +int +bootenv_unset(bootenv_t env, const char *key) +{ + if (env == NULL) + return -EINVAL; + + return hashmap_remove(env->map, key); +} + +int +bootenv_get_key_vector(bootenv_t env, size_t* size, int sort, + const char ***vector) +{ + if ((env == NULL) || (size == NULL)) + return -EINVAL; + + *vector = hashmap_get_key_vector(env->map, size, sort); + + if (*vector == NULL) + return -EINVAL; + + return 0; +} + +int +bootenv_dump(bootenv_t env) +{ + if (env == NULL) + return -EINVAL; + + return hashmap_dump(env->map); +} + +int +bootenv_list_create(bootenv_list_t *list) +{ + bootenv_list_t res; + res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list)); + + if (res == NULL) + return -ENOMEM; + + res->head = hashmap_new(); + + if (res->head == NULL) { + free(res); + return -ENOMEM; + } + + *list = res; + return 0; +} + +int +bootenv_list_destroy(bootenv_list_t *list) +{ + int rc = 0; + + if (list == NULL) + return -EINVAL; + + bootenv_list_t tmp = *list; + if (tmp == 0) + return 0; + + rc = hashmap_free(tmp->head); + if (rc != 0) + return rc; + + free(tmp); + *list = NULL; + return 0; +} + +int +bootenv_list_import(bootenv_list_t list, const char *str) +{ + if (list == NULL) + return -EINVAL; + + return build_list_definition(list->head, str); +} + +int +bootenv_list_export(bootenv_list_t list, char **string) +{ + size_t size, i, j, bufsize, tmp, rc = 0; + const char **items; + + if (list == NULL) + return -EINVAL; + + bufsize = BOOTENV_MAXLINE; + char *res = (char*) malloc(bufsize * sizeof(char)); + if (res == NULL) + return -ENOMEM; + + rc = bootenv_list_to_vector(list, &size, &items); + if (rc != 0) { + goto err; + } + + j = 0; + for (i = 0; i < size; i++) { + tmp = strlen(items[i]); + if (j >= bufsize) { + bufsize += BOOTENV_MAXLINE; + res = (char*) realloc(res, bufsize * sizeof(char)); + if (res == NULL) { + rc = -ENOMEM; + goto err; + } + } + memcpy(res + j, items[i], tmp); + j += tmp; + if (i < (size - 1)) { + res[j] = ','; + j++; + } + } + j++; + res[j] = '\0'; + free(items); + *string = res; + return 0; +err: + free(items); + return rc; +} + +int +bootenv_list_add(bootenv_list_t list, const char *item) +{ + if ((list == NULL) || (item == NULL)) + return -EINVAL; + + return hashmap_add(list->head, item, ""); +} + +int +bootenv_list_remove(bootenv_list_t list, const char *item) +{ + if ((list == NULL) || (item == NULL)) + return -EINVAL; + + return hashmap_remove(list->head, item); +} + +int +bootenv_list_is_in(bootenv_list_t list, const char *item) +{ + if ((list == NULL) || (item == NULL)) + return -EINVAL; + + return hashmap_lookup(list->head, item) != NULL ? 1 : 0; +} + +int +bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector) +{ + if ((list == NULL) || (size == NULL)) + return -EINVAL; + + *vector = hashmap_get_key_vector(list->head, size, 1); + if (*vector == NULL) + return -ENOMEM; + + return 0; +} + +int +bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, + uint32_t **vector) +{ + int rc = 0; + size_t i; + uint32_t* res = NULL; + char *endptr = NULL; + const char **a = NULL; + + rc = bootenv_list_to_vector(list, size, &a); + if (rc != 0) + goto err; + + res = (uint32_t*) malloc (*size * sizeof(uint32_t)); + if (!res) + goto err; + + for (i = 0; i < *size; i++) { + res[i] = strtoul(a[i], &endptr, 0); + if (*endptr != '\0') + goto err; + } + + if (a) + free(a); + *vector = res; + return 0; + +err: + if (a) + free(a); + if (res) + free(res); + return rc; +} diff --git a/ubi-utils/src/bootenv.h b/ubi-utils/src/bootenv.h new file mode 100644 index 0000000..86743ed --- /dev/null +++ b/ubi-utils/src/bootenv.h @@ -0,0 +1,415 @@ +#ifndef __BOOTENV_H__ +#define __BOOTENV_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. + */ + +#include /* FILE */ +#include +#include + +/* DOXYGEN DOCUMENTATION */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file bootenv.h + * @author oliloh@de.ibm.com + * @version 1.3 + * + * 1.3 Some renaming + */ + +/** + * @mainpage Usage + * + * @section intro Introduction + * This library provides all functionality to handle with the so-called + * platform description data (PDD) and the bootparameters defined in + * U-Boot. It is able to apply the defined PDD operations in PDD update + * scenarios. For more information about the PDD and bootparameter + * environment "bootenv" confer the PDD documentation. + * + * @section ret Return codes + * This library defines some return codes which will be delivered classified + * as warnings or errors. See the "Defines" section for details and numeric + * values. + * + * @section benv Bootenv format description + * There are two different input formats: + * - text files + * - binary files + * + * @subsection txt Text Files + * Text files have to be specified like: + * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim + * + * @subsection bin Binary files + * Binary files have to be specified like: + * @verbatimkey1=value1,value2,value7\0key2=value55,value1\0... @endverbatim + * You can confer the U-Boot documentation for more details. + * + * @section benvlists Bootenv lists format description. + * Values referenced in the preceeding subsection can be + * defined like lists: + * @verbatim value1,value2,value3 @endverbatim + * There are some situation where a conversion of a comma + * seperated list can be useful, e.g. to get a list + * of defined PDD entries. + */ + +#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */ + +/** + * @def BOOTENV_ECRC + * @brief Given binary file is to large. + * @def BOOTENV_EFMT + * @brief Given bootenv section has an invalid format + * @def BOOTENV_EBADENTRY + * @brief Bad entry in the bootenv section. + * @def BOOTENV_EINVAL + * @brief Invalid bootenv defintion. + * @def BOOTENV_ENOPDD + * @brief Given bootenv sectoin has no PDD defintion string (pdd=...). + * @def BOOTENV_EPDDINVAL + * @brief Given bootenv section has an invalid PDD defintion. + * @def BOOTENV_ENOTIMPL + * @brief Functionality not implemented. + * @def BOOTENV_ECOPY + * @brief Bootenv memory copy error + * @def BOOTENV_ENOTFOUND + * @brief Given key has has no value. + * @def BOOTENV_EMAX + * @brief Highest error value. + */ +#define BOOTENV_ETOOBIG 1 +#define BOOTENV_EFMT 2 +#define BOOTENV_EBADENTRY 3 +#define BOOTENV_EINVAL 4 +#define BOOTENV_ENOPDD 5 +#define BOOTENV_EPDDINVAL 6 +#define BOOTENV_ENOTIMPL 7 +#define BOOTENV_ECOPY 8 +#define BOOTENV_ENOTFOUND 9 +#define BOOTENV_EMAX 10 + +/** + * @def BOOTENV_W + * @brief A warning which is handled internally as an error + * but can be recovered by manual effort. + * @def BOOTENV_WPDD_STRING_DIFFERS + * @brief The PDD strings of old and new PDD differ and + * can cause update problems, because new PDD values + * are removed from the bootenv section completely. + */ +#define BOOTENV_W 20 +#define BOOTENV_WPDD_STRING_DIFFERS 21 +#define BOOTENV_WMAX 22 /* highest warning value */ + + +typedef struct bootenv *bootenv_t; + /**< A bootenv library handle. */ + +typedef struct bootenv_list *bootenv_list_t; + /**< A handle for a value list. */ + +typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*, + int*, char*, size_t); + + +/** + * @brief Get a new handle. + * @return 0 + * @return or error + * */ +int bootenv_create(bootenv_t *env); + +/** + * @brief Cleanup structure. + * @param env Bootenv structure which shall be destroyed. + * @return 0 + * @return or error + */ +int bootenv_destroy(bootenv_t *env); + +/** + * @brief Copy a bootenv handle. + * @param in The input bootenv. + * @param out The copied output bootenv. Discards old data. + * @return 0 + * @return or error + */ +int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out); + +/** + * @brief Looks for a value inside the bootenv data. + * @param env Handle to a bootenv structure. + * @param key The key. + * @return NULL key not found + * @return !NULL ptr to value + */ +int bootenv_get(bootenv_t env, const char *key, const char **value); + + +/** + * @brief Looks for a value inside the bootenv data and converts it to num. + * @param env Handle to a bootenv structure. + * @param key The key. + * @param value A pointer to the resulting numerical value + * @return NULL key not found + * @return !NULL ptr to value + */ +int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value); + +/** + * @brief Set a bootenv value by key. + * @param env Handle to a bootenv structure. + * @param key Key. + * @param value Value to set. + * @return 0 + * @return or error + */ +int bootenv_set(bootenv_t env, const char *key, const char *value); + +/** + * @brief Remove the given key (and its value) from a bootenv structure. + * @param env Handle to a bootenv structure. + * @param key Key. + * @return 0 + * @return or error + */ +int bootenv_unset(bootenv_t env, const char *key); + + +/** + * @brief Get a vector of all keys which are currently set + * within a bootenv handle. + * @param env Handle to a bootenv structure. + * @param size The size of the allocated array structure. + * @param sort Flag, if set the vector is sorted ascending. + * @return NULL on error. + * @return !NULL a pointer to the first element the allocated vector. + * @warning Free the allocate memory yourself! + */ +int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort, + const char ***vector); + +/** + * @brief Calculate the size in bytes which are necessary to write the + * current bootenv section in a *binary file. + * @param env bootenv handle. + * @param size The size in bytes of the bootenv handle. + * @return 0 + * @return or ERROR. + */ +int bootenv_size(bootenv_t env, size_t *size); + +/** + * @brief Read a binary bootenv file. + * @param fp File pointer to input stream. + * @param env bootenv handle. + * @param size maximum data size. + * @return 0 + * @return or ERROR. + */ +int bootenv_read(FILE* fp, bootenv_t env, size_t size); + + +/** + * @brief Read bootenv data from an text/ascii file. + * @param fp File pointer to ascii PDD file. + * @param env bootenv handle + * @return 0 + * @return or ERROR. + */ +int bootenv_read_txt(FILE* fp, bootenv_t env); + +/** + * @brief Write a bootenv structure to the given location (binary). + * @param fp Filepointer to binary file. + * @param env Bootenv structure which shall be written. + * @return 0 + * @return or error + */ +int bootenv_write(FILE* fp, bootenv_t env); + +/** + * @brief Write a bootenv structure to the given location (text). + * @param fp Filepointer to text file. + * @param env Bootenv structure which shall be written. + * @return 0 + * @return or error + */ +int bootenv_write_txt(FILE* fp, bootenv_t env); + +/** + * @brief Prototype for a PDD handling funtion + */ + +/** + * @brief The PDD keep operation. + * @param env_old The old bootenv structure. + * @param env_new The new bootenv structure. + * @param env_res The result of PDD keep. + * @param warnings A flag which marks any warnings. + * @return 0 + * @return or error + * @note For a complete documentation about the algorithm confer the + * PDD documentation. + */ +int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, + bootenv_t *env_res, int *warnings, + char *err_buf, size_t err_buf_size); + + +/** + * @brief The PDD merge operation. + * @param env_old The old bootenv structure. + * @param env_new The new bootenv structure. + * @param env_res The result of merge-pdd. + * @param warnings A flag which marks any warnings. + * @return 0 + * @return or error + * @note For a complete documentation about the algorithm confer the + * PDD documentation. + */ +int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, + bootenv_t *env_res, int *warnings, + char *err_buf, size_t err_buf_size); + +/** + * @brief The PDD overwrite operation. + * @param env_old The old bootenv structure. + * @param env_new The new bootenv structure. + * @param env_res The result of overwrite-pdd. + * @param warnings A flag which marks any warnings. + * @return 0 + * @return or error + * @note For a complete documentation about the algorithm confer the + * PDD documentation. + */ +int bootenv_pdd_overwrite(bootenv_t env_new, + bootenv_t env_old, bootenv_t *env_res, int *warnings, + char *err_buf, size_t err_buf_size); + +/** + * @brief Dump a bootenv structure to stdout. (Debug) + * @param env Handle to a bootenv structure. + * @return 0 + * @return or error + */ +int bootenv_dump(bootenv_t env); + +/** + * @brief Validate a bootenv structure. + * @param env Handle to a bootenv structure. + * @return 0 + * @return or error + */ +int bootenv_valid(bootenv_t env); + +/** + * @brief Create a new bootenv list structure. + * @return NULL on error + * @return or a new list handle. + * @note This structure is used to store values in a list. + * A useful addition when handling PDD strings. + */ +int bootenv_list_create(bootenv_list_t *list); + +/** + * @brief Destroy a bootenv list structure + * @param list Handle to a bootenv list structure. + * @return 0 + * @return or error + */ +int bootenv_list_destroy(bootenv_list_t *list); + +/** + * @brief Import a list from a comma seperated string + * @param list Handle to a bootenv list structure. + * @param str Comma seperated string list. + * @return 0 + * @return or error + */ +int bootenv_list_import(bootenv_list_t list, const char *str); + +/** + * @brief Export a list to a string of comma seperated values. + * @param list Handle to a bootenv list structure. + * @return NULL one error + * @return or pointer to a newly allocated string. + * @warning Free the allocated memory by yourself! + */ +int bootenv_list_export(bootenv_list_t list, char **string); + +/** + * @brief Add an item to the list. + * @param list A handle of a list structure. + * @param item An item. + * @return 0 + * @return or error + */ +int bootenv_list_add(bootenv_list_t list, const char *item); + +/** + * @brief Remove an item from the list. + * @param list A handle of a list structure. + * @param item An item. + * @return 0 + * @return or error + */ +int bootenv_list_remove(bootenv_list_t list, const char *item); + +/** + * @brief Check if a given item is in a given list. + * @param list A handle of a list structure. + * @param item An item. + * @return 1 Item is in list. + * @return 0 Item is not in list. + */ +int bootenv_list_is_in(bootenv_list_t list, const char *item); + + +/** + * @brief Convert a list into a vector of all values inside the list. + * @param list Handle to a bootenv structure. + * @param size The size of the allocated vector structure. + * @return 0 + * @return or error + * @warning Free the allocate memory yourself! + */ +int bootenv_list_to_vector(bootenv_list_t list, size_t *size, + const char ***vector); + +/** + * @brief Convert a list into a vector of all values inside the list. + * @param list Handle to a bootenv structure. + * @param size The size of the allocated vector structure. + * @return 0 + * @return or error + * @warning Free the allocate memory yourself! + */ +int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, + uint32_t **vector); + +#ifdef __cplusplus +} +#endif +#endif /*__BOOTENV_H__ */ diff --git a/ubi-utils/src/config.h b/ubi-utils/src/config.h new file mode 100644 index 0000000..746fa3c --- /dev/null +++ b/ubi-utils/src/config.h @@ -0,0 +1,28 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_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: Frank Haverkamp + */ + +#define PACKAGE_VERSION "1.0" +#define PACKAGE_BUGREPORT "dedekind@oktetlabs.ru, haver@vnet.ibm.com, or tglx@linutronix.de" + +#define __unused __attribute__((unused)) + +#endif diff --git a/ubi-utils/src/crc32.c b/ubi-utils/src/crc32.c new file mode 100644 index 0000000..666e217 --- /dev/null +++ b/ubi-utils/src/crc32.c @@ -0,0 +1,83 @@ +/* + * 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: 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 +#include + +/* 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; +} diff --git a/ubi-utils/src/crc32.h b/ubi-utils/src/crc32.h new file mode 100644 index 0000000..31362b0 --- /dev/null +++ b/ubi-utils/src/crc32.h @@ -0,0 +1,36 @@ +#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. + */ + +/* + * 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 + +void init_crc32_table(uint32_t *table); +uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len); + +#endif /* __CRC32_H__ */ diff --git a/ubi-utils/src/error.c b/ubi-utils/src/error.c new file mode 100644 index 0000000..c8c623c --- /dev/null +++ b/ubi-utils/src/error.c @@ -0,0 +1,177 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include "error.h" + +#define MAXLINE 4096 + +static FILE *logfp = NULL; + +static void err_doit(int, int, const char *, va_list); + +int +read_procfile(FILE *fp_out, const char *procfile) +{ + FILE *fp; + + fp = fopen(procfile, "r"); + if (!fp) + return -ENOENT; + + while(!feof(fp)) { + int c = fgetc(fp); + + if (c == EOF) + return 0; + + if (putc(c, fp_out) == EOF) + return -EIO; + + if (ferror(fp)) + return -EIO; + } + return fclose(fp); +} + +void +error_initlog(const char *logfile) +{ + logfp = fopen(logfile, "a+"); + read_procfile(logfp, "/proc/cpuinfo"); +} + +void +info_msg(const char *fmt, ...) +{ + FILE* fpout; + char buf[MAXLINE + 1]; + va_list ap; + int n; + + fpout = stdout; + + va_start(ap, fmt); + vsnprintf(buf, MAXLINE, fmt, ap); + n = strlen(buf); + strcat(buf, "\n"); + + fputs(buf, fpout); + fflush(fpout); + if (fpout != stdout) + fclose(fpout); + + va_end(ap); + return; +} + +void +__err_ret(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(1, LOG_INFO, fmt, ap); + va_end(ap); + return; +} + +void +__err_sys(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(1, LOG_ERR, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + + +void +__err_msg(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(0, LOG_INFO, fmt, ap); + va_end(ap); + + return; +} + +void +__err_quit(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(0, LOG_ERR, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +void +__err_dump(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(1, LOG_ERR, fmt, ap); + va_end(ap); + abort(); /* dump core and terminate */ + exit(EXIT_FAILURE); /* shouldn't get here */ +} + + +static void +err_doit(int errnoflag, int level __attribute__((unused)), + const char *fmt, va_list ap) +{ + FILE* fpout; + int errno_save, n; + char buf[MAXLINE + 1]; + fpout = stderr; + + errno_save = errno; /* value caller might want printed */ + + vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ + + n = strlen(buf); + + if (errnoflag) + snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); + strcat(buf, "\n"); + + if (logfp) { + fputs(buf, logfp); + fflush(logfp); + } + + fputs(buf, fpout); + fflush(fpout); + if (fpout != stderr) + fclose(fpout); + + return; +} diff --git a/ubi-utils/src/error.h b/ubi-utils/src/error.h new file mode 100644 index 0000000..e8d7137 --- /dev/null +++ b/ubi-utils/src/error.h @@ -0,0 +1,84 @@ +#ifndef __ERROR_H__ +#define __ERROR_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. + */ + +#include + +void error_initlog(const char *logfile); +int read_procfile(FILE *fp_out, const char *procfile); + +void __err_ret(const char *fmt, ...); +void __err_sys(const char *fmt, ...); +void __err_msg(const char *fmt, ...); +void __err_quit(const char *fmt, ...); +void __err_dump(const char *fmt, ...); + +void info_msg(const char *fmt, ...); + +#ifdef DEBUG +#define __loc_msg(str) do { \ + __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \ + str, __FILE__, __FUNCTION__, __LINE__); \ +} while (0) +#else +#define __loc_msg(str) +#endif + + +#define err_dump(fmt, ...) do { \ + __loc_msg("ErrDump"); \ + __err_dump(fmt, ##__VA_ARGS__); \ +} while (0) + +#define err_quit(fmt, ...) do { \ + __loc_msg("ErrQuit"); \ + __err_quit(fmt, ##__VA_ARGS__); \ +} while (0) + + +#define err_ret(fmt, ...) do { \ + __loc_msg("ErrRet"); \ + __err_ret(fmt, ##__VA_ARGS__); \ +} while (0) + +#define err_sys(fmt, ...) do { \ + __loc_msg("ErrSys"); \ + __err_sys(fmt, ##__VA_ARGS__); \ +} while (0) + +#define err_msg(fmt, ...) do { \ + __loc_msg("ErrMsg"); \ + __err_msg(fmt, ##__VA_ARGS__); \ +} while (0) + +#define log_msg(fmt, ...) do { \ + /* __loc_msg("LogMsg"); */ \ + __err_msg(fmt, ##__VA_ARGS__); \ +} while (0) + +#ifdef DEBUG +#define dbg_msg(fmt, ...) do { \ + __loc_msg("DbgMsg"); \ + __err_msg(fmt, ##__VA_ARGS__); \ +} while (0) +#else +#define dbg_msg(fmt, ...) +#endif + +#endif /* __ERROR_H__ */ diff --git a/ubi-utils/src/example_ubi.h b/ubi-utils/src/example_ubi.h new file mode 100644 index 0000000..23c7b54 --- /dev/null +++ b/ubi-utils/src/example_ubi.h @@ -0,0 +1,28 @@ +#ifndef __EXAMPLE_UBI_H__ +#define __EXAMPLE_UBI_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. + */ + +/** + * Defaults for our cards. + */ +#define EXAMPLE_UBI_DEVICE 0 +#define EXAMPLE_BOOTENV_VOL_ID_1 4 +#define EXAMPLE_BOOTENV_VOL_ID_2 5 + +#endif /* __EXAMPLE_UBI_H__ */ diff --git a/ubi-utils/src/hashmap.c b/ubi-utils/src/hashmap.c new file mode 100644 index 0000000..250f71f --- /dev/null +++ b/ubi-utils/src/hashmap.c @@ -0,0 +1,412 @@ +/* + * 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 +#include +#include +#include +#include "error.h" +#include "hashmap.h" +#define DEFAULT_BUCKETS 4096 + +#if 0 +#define INFO_MSG(fmt...) do { \ + info_msg(fmt); \ +} while (0) +#else +#define INFO_MSG(fmt...) +#endif + +struct hashentry { + char* key; /* key '0' term. str */ + char* value; /* payload '0' term. str */ + + hashentry_t next; +}; + +struct hashmap { + size_t entries; /* current #entries */ + size_t maxsize; /* no. of hash buckets */ + hashentry_t* data; /* array of buckets */ +}; + +static int +is_empty(hashentry_t l) +{ + return l == NULL ? 1 : 0; +} + +hashmap_t +hashmap_new(void) +{ + hashmap_t res; + res = (hashmap_t) calloc(1, sizeof(struct hashmap)); + + if (res == NULL) + return NULL; + + res->maxsize = DEFAULT_BUCKETS; + res->entries = 0; + + res->data = (hashentry_t*) + calloc(1, res->maxsize * sizeof(struct hashentry)); + + if (res->data == NULL) + return NULL; + + return res; +} + +static hashentry_t +new_entry(const char* key, const char* value) +{ + hashentry_t res; + + res = (hashentry_t) calloc(1, sizeof(struct hashentry)); + + if (res == NULL) + return NULL; + + /* allocate key and value and copy them */ + res->key = strdup(key); + if (res->key == NULL) { + free(res); + return NULL; + } + + res->value = strdup(value); + if (res->value == NULL) { + free(res->key); + free(res); + return NULL; + } + + res->next = NULL; + + return res; +} + +static hashentry_t +free_entry(hashentry_t e) +{ + if (!is_empty(e)) { + if(e->key != NULL) { + free(e->key); + } + if(e->value != NULL) + free(e->value); + free(e); + } + + return NULL; +} + +static hashentry_t +remove_entry(hashentry_t l, const char* key, size_t* entries) +{ + hashentry_t lnext; + if (is_empty(l)) + return NULL; + + if(strcmp(l->key,key) == 0) { + lnext = l->next; + l = free_entry(l); + (*entries)--; + return lnext; + } + + l->next = remove_entry(l->next, key, entries); + + return l; +} + +static hashentry_t +insert_entry(hashentry_t l, hashentry_t e, size_t* entries) +{ + if (is_empty(l)) { + (*entries)++; + return e; + } + + /* check for update */ + if (strcmp(l->key, e->key) == 0) { + e->next = l->next; + l = free_entry(l); + return e; + } + + l->next = insert_entry(l->next, e, entries); + return l; +} + +static hashentry_t +remove_all(hashentry_t l, size_t* entries) +{ + hashentry_t lnext; + if (is_empty(l)) + return NULL; + + lnext = l->next; + free_entry(l); + (*entries)--; + + return remove_all(lnext, entries); +} + +static const char* +value_lookup(hashentry_t l, const char* key) +{ + if (is_empty(l)) + return NULL; + + if (strcmp(l->key, key) == 0) + return l->value; + + return value_lookup(l->next, key); +} + +static void +print_all(hashentry_t l) +{ + if (is_empty(l)) { + printf("\n"); + return; + } + + printf("%s=%s", l->key, l->value); + if (!is_empty(l->next)) { + printf(","); + } + + print_all(l->next); +} + +static void +keys_to_array(hashentry_t l, const char** a, size_t* i) +{ + if (is_empty(l)) + return; + + a[*i] = l->key; + (*i)++; + + keys_to_array(l->next, a, i); +} + +uint32_t +hash_str(const char* str, uint32_t mapsize) +{ + uint32_t hash = 0; + uint32_t x = 0; + uint32_t i = 0; + size_t len = strlen(str); + + for(i = 0; i < len; str++, i++) { + hash = (hash << 4) + (*str); + if((x = hash & 0xF0000000L) != 0) { + hash ^= (x >> 24); + hash &= ~x; + } + } + + return (hash & 0x7FFFFFFF) % mapsize; +} + + +int +hashmap_is_empty(hashmap_t map) +{ + if (map == NULL) + return -EINVAL; + + return map->entries > 0 ? 1 : 0; +} + +const char* +hashmap_lookup(hashmap_t map, const char* key) +{ + uint32_t i; + + if ((map == NULL) || (key == NULL)) + return NULL; + + i = hash_str(key, map->maxsize); + + return value_lookup(map->data[i], key); +} + +int +hashmap_add(hashmap_t map, const char* key, const char* value) +{ + uint32_t i; + hashentry_t entry; + + if ((map == NULL) || (key == NULL) || (value == NULL)) + return -EINVAL; + + i = hash_str(key, map->maxsize); + entry = new_entry(key, value); + if (entry == NULL) + return -ENOMEM; + + map->data[i] = insert_entry(map->data[i], + entry, &map->entries); + + INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value); + return 0; +} + +int +hashmap_remove(hashmap_t map, const char* key) +{ + uint32_t i; + + if ((map == NULL) || (key == NULL)) + return -EINVAL; + + i = hash_str(key, map->maxsize); + map->data[i] = remove_entry(map->data[i], key, &map->entries); + + return 0; +} + +size_t +hashmap_size(hashmap_t map) +{ + if (map != NULL) + return map->entries; + else + return 0; +} + +int +hashmap_free(hashmap_t map) +{ + size_t i; + + if (map == NULL) + return -EINVAL; + + /* "children" first */ + for(i = 0; i < map->maxsize; i++) { + map->data[i] = remove_all(map->data[i], &map->entries); + } + free(map->data); + free(map); + + return 0; +} + +int +hashmap_dump(hashmap_t map) +{ + size_t i; + if (map == NULL) + return -EINVAL; + + for(i = 0; i < map->maxsize; i++) { + if (map->data[i] != NULL) { + printf("[%d]: ", i); + print_all(map->data[i]); + } + } + + return 0; +} + +static const char** +sort_key_vector(const char** a, size_t size) +{ + /* uses bubblesort */ + size_t i, j; + const char* tmp; + + if (size <= 0) + return a; + + for (i = size - 1; i > 0; i--) { + for (j = 0; j < i; j++) { + if (strcmp(a[j], a[j+1]) > 0) { + tmp = a[j]; + a[j] = a[j+1]; + a[j+1] = tmp; + } + } + } + return a; +} + +const char** +hashmap_get_key_vector(hashmap_t map, size_t* size, int sort) +{ + const char** res; + size_t i, j; + *size = map->entries; + + res = (const char**) malloc(*size * sizeof(char*)); + if (res == NULL) + return NULL; + + j = 0; + for(i=0; i < map->maxsize; i++) { + keys_to_array(map->data[i], res, &j); + } + + if (sort) + res = sort_key_vector(res, *size); + + return res; +} + +int +hashmap_key_is_in_vector(const char** vec, size_t size, const char* key) +{ + size_t i; + for (i = 0; i < size; i++) { + if (strcmp(vec[i], key) == 0) /* found */ + return 1; + } + + return 0; +} + +const char** +hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, + const char** vec2, size_t vec2_size, size_t* res_size) +{ + const char** res; + size_t i, j; + + *res_size = vec2_size; + + res = (const char**) malloc(*res_size * sizeof(char*)); + if (res == NULL) + return NULL; + + /* get all keys from vec2 which are not set in vec1 */ + j = 0; + for (i = 0; i < vec2_size; i++) { + if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i])) + res[j++] = vec2[i]; + } + + *res_size = j; + return res; +} diff --git a/ubi-utils/src/hashmap.h b/ubi-utils/src/hashmap.h new file mode 100644 index 0000000..1b13e95 --- /dev/null +++ b/ubi-utils/src/hashmap.h @@ -0,0 +1,49 @@ +#ifndef __HASHMAP_H__ +#define __HASHMAP_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 +#include + +typedef struct hashentry *hashentry_t; +typedef struct hashmap *hashmap_t; + +hashmap_t hashmap_new(void); +int hashmap_free(hashmap_t map); + +int hashmap_add(hashmap_t map, const char* key, const char* value); +int hashmap_update(hashmap_t map, const char* key, const char* value); +int hashmap_remove(hashmap_t map, const char* key); +const char* hashmap_lookup(hashmap_t map, const char* key); + +const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort); +int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key); +const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, + const char** vec2, size_t vec2_size, size_t* res_size); + +int hashmap_dump(hashmap_t map); + +int hashmap_is_empty(hashmap_t map); +size_t hashmap_size(hashmap_t map); + +uint32_t hash_str(const char* str, uint32_t mapsize); + +#endif /* __HASHMAP_H__ */ diff --git a/ubi-utils/src/libbootenv/bootenv.c b/ubi-utils/src/libbootenv/bootenv.c deleted file mode 100644 index b6a1191..0000000 --- a/ubi-utils/src/libbootenv/bootenv.c +++ /dev/null @@ -1,959 +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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hashmap.h" -#include "error.h" - -#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */ - -/* Structures */ -struct bootenv { - hashmap_t map; ///< Pointer to hashmap which holds data structure. -}; - -struct bootenv_list { - hashmap_t head; ///< Pointer to list which holds the data structure. -}; - -/** - * @brief Remove the '\n' from a given line. - * @param line Input/Output line. - * @param size Size of the line. - * @param fp File Pointer. - * @return 0 - * @return or error - */ -static int -remove_lf(char *line, size_t size, FILE* fp) -{ - size_t i; - - for (i = 0; i < size; i++) { - if (line[i] == '\n') { - line[i] = '\0'; - return 0; - } - } - - if (!feof(fp)) { - return BOOTENV_EINVAL; - } - - return 0; -} - -/** - * @brief Determine if a line contains only WS. - * @param line The line to process. - * @param size Size of input line. - * @return 1 Yes, only WS. - * @return 0 No, contains data. - */ -static int -is_ws(const char *line, size_t size) -{ - size_t i = 0; - - while (i < size) { - switch (line[i]) { - case '\n': - return 1; - case '#': - return 1; - case ' ': - i++; - continue; - case '\t': - i++; - continue; - default: /* any other char -> no cmnt */ - return 0; - } - } - - return 0; -} - - -/* ------------------------------------------------------------------------- */ - -/** - * @brief Build a list from a comma seperated value string. - * @param list Pointer to hashmap structure which shall store - * the list. - * @param value Comma seperated value string. - * @return 0 - * @return or error. - */ -static int -build_list_definition(hashmap_t list, const char *value) -{ - int rc = 0; - char *str = NULL; - char *ptr = NULL; - size_t len, i, j; - - /* str: val1,val2 , val4,...,valN */ - len = strlen(value); - str = (char*) malloc((len+1) * sizeof(char)); - - /* 1. reformat string: remove spaces */ - for (i = 0, j = 0; i < len; i++) { - if (value[i] == ' ') - continue; - - str[j] = value[i]; - j++; - } - str[j] = '\0'; - - /* str: val1,val2,val4,...,valN\0*/ - /* 2. replace ',' seperator with '\0' */ - len = strlen(str); - for (i = 0; i < len; i++) { - if (str[i] == ',') { - str[i] = '\0'; - } - } - - /* str: val1\0val2\0val4\0...\0valN\0*/ - /* 3. insert definitions into a hash map, using it like a list */ - i = j = 0; - ptr = str; - while (((i = strlen(ptr)) > 0) && (j < len)) { - rc = hashmap_add(list, ptr, ""); - if (rc != 0) { - free(str); - return rc; - } - j += i+1; - if (j < len) - ptr += i+1; - } - - free(str); - return rc; -} - -/** - * @brief Extract a key value pair and add it to a hashmap - * @param str Input string which contains a key value pair. - * @param env The updated handle which contains the new pair. - * @return 0 - * @return or error - * @note The input string format is: "key=value" - */ -static int -extract_pair(const char *str, bootenv_t env) -{ - int rc = 0; - char *key = NULL; - char *val = NULL; - - key = strdup(str); - if (key == NULL) - return -ENOMEM; - - val = strstr(key, "="); - if (val == NULL) { - rc = BOOTENV_EBADENTRY; - goto err; - } - - *val = '\0'; /* split strings */ - val++; - rc = bootenv_set(env, key, val); - -err: - free(key); - return rc; -} - -int -bootenv_destroy(bootenv_t* env) -{ - int rc = 0; - - if (env == NULL || *env == NULL) - return -EINVAL; - - bootenv_t tmp = *env; - - rc = hashmap_free(tmp->map); - if (rc != 0) - return rc; - - free(tmp); - return rc; -} - -int -bootenv_create(bootenv_t* env) -{ - bootenv_t res; - res = (bootenv_t) calloc(1, sizeof(struct bootenv)); - - if (res == NULL) - return -ENOMEM; - - res->map = hashmap_new(); - - if (res->map == NULL) { - free(res); - return -ENOMEM; - } - - *env = res; - - return 0; -} - - -/** - * @brief Read a formatted buffer and scan it for valid bootenv - * key/value pairs. Add those pairs into a hashmap. - * @param env Hashmap which shall be used to hold the data. - * @param buf Formatted buffer. - * @param size Size of the buffer. - * @return 0 - * @return or error - */ -static int -rd_buffer(bootenv_t env, const char *buf, size_t size) -{ - const char *curr = buf; /* ptr to current key/value pair */ - uint32_t i = 0; /* current length */ - uint32_t j = 0; /* processed chars */ - uint32_t items = 0; /* processed items */ - int rc = 0; - - if (buf[size-1] != '\0') { - return BOOTENV_EFMT; - } - - while ((i = strlen(curr)) != 0) { - /* there is a key value pair remaining */ - rc = extract_pair(curr, env); - if (rc != 0) { - rc = BOOTENV_EINVAL; - return rc; - } - items++; - - j += i; - if (j >= size) - return 0; /* finished, end of buffer */ - curr += i + 1; - } - - return 0; -} - -/** - * If we have a single file containing the boot-parameter size should - * be specified either as the size of the file or as BOOTENV_MAXSIZE. - * If the bootparameter are in the middle of a file we need the exact - * length of the data. - */ -int -bootenv_read(FILE* fp, bootenv_t env, size_t size) -{ - int rc; - char *buf = NULL; - size_t i = 0; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - /* allocate temp buffer */ - buf = (char*) calloc(1, size * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - /* FIXME Andreas, please review this I removed size-1 and - * replaced it by just size, I saw the kernel image starting - * with a 0x0060.... and not with the 0x60.... what it should - * be. Is this a tools problem or is it a problem here where - * fp is moved not to the right place due to the former size-1 - * here. - */ - while((i < size) && (!feof(fp))) { - int c = fgetc(fp); - - if (c == EOF) { - buf[i++] = '\0'; - break; /* we have enough */ - } - - /* log_msg("%c", c); */ /* FIXME DBG */ - - buf[i++] = c; - if (ferror(fp)) { - rc = -EIO; - goto err; - } - } - - /* transfer to hashmap */ - rc = rd_buffer(env, buf, size); - - /* FIXME DBG */ - /* log_msg("\n%s:%d rc=%d\n", __func__, __LINE__, rc); */ - -err: - free(buf); - return rc; -} - - - -int -bootenv_read_txt(FILE* fp, bootenv_t env) -{ - int rc = 0; - char *buf = NULL; - char *line = NULL; - char *lstart = NULL; - char *curr = NULL; - size_t len; - size_t size; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - size = BOOTENV_MAXSIZE; - - /* allocate temp buffers */ - buf = (char*) calloc(1, size * sizeof(char)); - lstart = line = (char*) calloc(1, size * sizeof(char)); - if ((buf == NULL) || (line == NULL)) { - rc = -ENOMEM; - goto err; - } - - curr = buf; - while ((line = fgets(line, size, fp)) != NULL) { - if (is_ws(line, size)) { - continue; - } - rc = remove_lf(line, BOOTENV_MAXSIZE, fp); - if (rc != 0) { - goto err; - } - - /* copy new line to binary buffer */ - len = strlen(line); - if (len > size) { - rc = -EFBIG; - goto err; - } - size -= len; /* track remaining space */ - - memcpy(curr, line, len); - curr += len + 1; /* for \0 seperator */ - } - - rc = rd_buffer(env, buf, BOOTENV_MAXSIZE); -err: - if (buf != NULL) - free(buf); - if (lstart != NULL) - free(lstart); - return rc; -} - -static int -fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max, - size_t *written) -{ - int rc = 0; - size_t keys_size, i; - size_t wr = 0; - const char **keys = NULL; - const char *val = NULL; - - rc = bootenv_get_key_vector(env, &keys_size, 1, &keys); - if (rc != 0) - goto err; - - for (i = 0; i < keys_size; i++) { - if (wr > BOOTENV_MAXSIZE) { - rc = -ENOSPC; - goto err; - } - - rc = bootenv_get(env, keys[i], &val); - if (rc != 0) - goto err; - - wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr, - "%s=%s", keys[i], val); - wr++; /* for \0 */ - } - - *written = wr; - -err: - if (keys != NULL) - free(keys); - - return rc; -} - -int -bootenv_write(FILE* fp, bootenv_t env) -{ - int rc = 0; - size_t size = 0; - char *buf = NULL; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size); - if (rc != 0) - goto err; - - if (fwrite(buf, size, 1, fp) != 1) { - rc = -EIO; - goto err; - } - -err: - if (buf != NULL) - free(buf); - return rc; -} - -int -bootenv_size(bootenv_t env, size_t *size) -{ - int rc = 0; - char *buf = NULL; - - if (env == NULL) - return -EINVAL; - - buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size); - if (rc != 0) - goto err; - -err: - if (buf != NULL) - free(buf); - return rc; -} - -int -bootenv_write_txt(FILE* fp, bootenv_t env) -{ - int rc = 0; - size_t size, wr, i; - const char **keys = NULL; - const char *key = NULL; - const char *val = NULL; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - rc = bootenv_get_key_vector(env, &size, 1, &keys); - if (rc != 0) - goto err; - - for (i = 0; i < size; i++) { - key = keys[i]; - rc = bootenv_get(env, key, &val); - if (rc != 0) - goto err; - - wr = fprintf(fp, "%s=%s\n", key, val); - if (wr != strlen(key) + strlen(val) + 2) { - rc = -EIO; - goto err; - } - } - -err: - if (keys != NULL) - free(keys); - return rc; -} - -int -bootenv_valid(bootenv_t env) -{ - /* @FIXME No sanity check implemented. */ - return 0; -} - -int -bootenv_copy_bootenv(bootenv_t in, bootenv_t *out) -{ - int rc = 0; - const char *tmp = NULL; - const char **keys = NULL; - size_t vec_size, i; - - if ((in == NULL) || (out == NULL)) - return -EINVAL; - - /* purge output var for sure... */ - rc = bootenv_destroy(out); - if (rc != 0) - return rc; - - /* create the new map */ - rc = bootenv_create(out); - if (rc != 0) - goto err; - - /* get the key list from the input map */ - rc = bootenv_get_key_vector(in, &vec_size, 0, &keys); - if (rc != 0) - goto err; - - if (vec_size != hashmap_size(in->map)) { - rc = BOOTENV_ECOPY; - goto err; - } - - /* make a deep copy of the hashmap */ - for (i = 0; i < vec_size; i++) { - rc = bootenv_get(in, keys[i], &tmp); - if (rc != 0) - goto err; - - rc = bootenv_set(*out, keys[i], tmp); - if (rc != 0) - goto err; - } - -err: - if (keys != NULL) - free(keys); - - return rc; -} - -/* ------------------------------------------------------------------------- */ - - -int -bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, - int *warnings, char *err_buf, size_t err_buf_size) -{ - bootenv_list_t l_old = NULL; - bootenv_list_t l_new = NULL; - const char *pdd_old = NULL; - const char *pdd_new = NULL; - const char *tmp = NULL; - const char **vec_old = NULL; - const char **vec_new = NULL; - const char **pdd_up_vec = NULL; - size_t vec_old_size, vec_new_size, pdd_up_vec_size, i; - int rc = 0; - - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - /* get the pdd strings, e.g.: - * pdd_old=a,b,c - * pdd_new=a,c,d,e */ - rc = bootenv_get(env_old, "pdd", &pdd_old); - if (rc != 0) - goto err; - rc = bootenv_get(env_new, "pdd", &pdd_new); - if (rc != 0) - goto err; - - /* put it into a list and then convert it to an vector */ - rc = bootenv_list_create(&l_old); - if (rc != 0) - goto err; - rc = bootenv_list_create(&l_new); - if (rc != 0) - goto err; - - rc = bootenv_list_import(l_old, pdd_old); - if (rc != 0) - goto err; - - rc = bootenv_list_import(l_new, pdd_new); - if (rc != 0) - goto err; - - rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old); - if (rc != 0) - goto err; - - rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new); - if (rc != 0) - goto err; - - rc = bootenv_copy_bootenv(env_new, env_res); - if (rc != 0) - goto err; - - /* calculate the update vector between the old and new pdd */ - pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size, - vec_new, vec_new_size, &pdd_up_vec_size); - - if (pdd_up_vec == NULL) { - rc = -ENOMEM; - goto err; - } - - if (pdd_up_vec_size != 0) { - /* need to warn the user about the unset of - * some pdd/bootenv values */ - *warnings = BOOTENV_WPDD_STRING_DIFFERS; - - /* remove all entries in the new bootenv load */ - for (i = 0; i < pdd_up_vec_size; i++) { - bootenv_unset(*env_res, pdd_up_vec[i]); - } - } - - /* generate the keep array and copy old pdd values to new bootenv */ - for (i = 0; i < vec_old_size; i++) { - rc = bootenv_get(env_old, vec_old[i], &tmp); - if (rc != 0) { - rc = BOOTENV_EPDDINVAL; - goto err; - } - rc = bootenv_set(*env_res, vec_old[i], tmp); - if (rc != 0) { - goto err; - } - } - /* put the old pdd string into the result map */ - rc = bootenv_set(*env_res, "pdd", pdd_old); - if (rc != 0) { - goto err; - } - - -err: - if (vec_old != NULL) - free(vec_old); - if (vec_new != NULL) - free(vec_new); - if (pdd_up_vec != NULL) - free(pdd_up_vec); - - bootenv_list_destroy(&l_old); - bootenv_list_destroy(&l_new); - return rc; -} - - -int -bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size) -{ - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - return bootenv_copy_bootenv(env_new, env_res); -} - -int -bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, - int *warnings, char *err_buf, size_t err_buf_size) -{ - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - snprintf(err_buf, err_buf_size, "The PDD merge operation is not " - "implemented. Contact: "); - - return BOOTENV_ENOTIMPL; -} - -/* ------------------------------------------------------------------------- */ - -int -bootenv_get(bootenv_t env, const char *key, const char **value) -{ - if (env == NULL) - return -EINVAL; - - *value = hashmap_lookup(env->map, key); - if (*value == NULL) - return BOOTENV_ENOTFOUND; - - return 0; -} - -int -bootenv_get_num(bootenv_t env, const char *key, uint32_t *value) -{ - char *endptr = NULL; - const char *str; - - if (env == NULL) - return 0; - - str = hashmap_lookup(env->map, key); - if (!str) - return -EINVAL; - - *value = strtoul(str, &endptr, 0); - - if (*endptr == '\0') { - return 0; - } - - return -EINVAL; -} - -int -bootenv_set(bootenv_t env, const char *key, const char *value) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_add(env->map, key, value); -} - -int -bootenv_unset(bootenv_t env, const char *key) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_remove(env->map, key); -} - -int -bootenv_get_key_vector(bootenv_t env, size_t* size, int sort, - const char ***vector) -{ - if ((env == NULL) || (size == NULL)) - return -EINVAL; - - *vector = hashmap_get_key_vector(env->map, size, sort); - - if (*vector == NULL) - return -EINVAL; - - return 0; -} - -int -bootenv_dump(bootenv_t env) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_dump(env->map); -} - -int -bootenv_list_create(bootenv_list_t *list) -{ - bootenv_list_t res; - res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list)); - - if (res == NULL) - return -ENOMEM; - - res->head = hashmap_new(); - - if (res->head == NULL) { - free(res); - return -ENOMEM; - } - - *list = res; - return 0; -} - -int -bootenv_list_destroy(bootenv_list_t *list) -{ - int rc = 0; - - if (list == NULL) - return -EINVAL; - - bootenv_list_t tmp = *list; - if (tmp == 0) - return 0; - - rc = hashmap_free(tmp->head); - if (rc != 0) - return rc; - - free(tmp); - *list = NULL; - return 0; -} - -int -bootenv_list_import(bootenv_list_t list, const char *str) -{ - if (list == NULL) - return -EINVAL; - - return build_list_definition(list->head, str); -} - -int -bootenv_list_export(bootenv_list_t list, char **string) -{ - size_t size, i, j, bufsize, tmp, rc = 0; - const char **items; - - if (list == NULL) - return -EINVAL; - - bufsize = BOOTENV_MAXLINE; - char *res = (char*) malloc(bufsize * sizeof(char)); - if (res == NULL) - return -ENOMEM; - - rc = bootenv_list_to_vector(list, &size, &items); - if (rc != 0) { - goto err; - } - - j = 0; - for (i = 0; i < size; i++) { - tmp = strlen(items[i]); - if (j >= bufsize) { - bufsize += BOOTENV_MAXLINE; - res = (char*) realloc(res, bufsize * sizeof(char)); - if (res == NULL) { - rc = -ENOMEM; - goto err; - } - } - memcpy(res + j, items[i], tmp); - j += tmp; - if (i < (size - 1)) { - res[j] = ','; - j++; - } - } - j++; - res[j] = '\0'; - free(items); - *string = res; - return 0; -err: - free(items); - return rc; -} - -int -bootenv_list_add(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_add(list->head, item, ""); -} - -int -bootenv_list_remove(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_remove(list->head, item); -} - -int -bootenv_list_is_in(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_lookup(list->head, item) != NULL ? 1 : 0; -} - -int -bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector) -{ - if ((list == NULL) || (size == NULL)) - return -EINVAL; - - *vector = hashmap_get_key_vector(list->head, size, 1); - if (*vector == NULL) - return -ENOMEM; - - return 0; -} - -int -bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, - uint32_t **vector) -{ - int rc = 0; - size_t i; - uint32_t* res = NULL; - char *endptr = NULL; - const char **a = NULL; - - rc = bootenv_list_to_vector(list, size, &a); - if (rc != 0) - goto err; - - res = (uint32_t*) malloc (*size * sizeof(uint32_t)); - if (!res) - goto err; - - for (i = 0; i < *size; i++) { - res[i] = strtoul(a[i], &endptr, 0); - if (*endptr != '\0') - goto err; - } - - if (a) - free(a); - *vector = res; - return 0; - -err: - if (a) - free(a); - if (res) - free(res); - return rc; -} diff --git a/ubi-utils/src/libbootenv/hashmap.c b/ubi-utils/src/libbootenv/hashmap.c deleted file mode 100644 index 250f71f..0000000 --- a/ubi-utils/src/libbootenv/hashmap.c +++ /dev/null @@ -1,412 +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 - */ - -#include -#include -#include -#include -#include "error.h" -#include "hashmap.h" -#define DEFAULT_BUCKETS 4096 - -#if 0 -#define INFO_MSG(fmt...) do { \ - info_msg(fmt); \ -} while (0) -#else -#define INFO_MSG(fmt...) -#endif - -struct hashentry { - char* key; /* key '0' term. str */ - char* value; /* payload '0' term. str */ - - hashentry_t next; -}; - -struct hashmap { - size_t entries; /* current #entries */ - size_t maxsize; /* no. of hash buckets */ - hashentry_t* data; /* array of buckets */ -}; - -static int -is_empty(hashentry_t l) -{ - return l == NULL ? 1 : 0; -} - -hashmap_t -hashmap_new(void) -{ - hashmap_t res; - res = (hashmap_t) calloc(1, sizeof(struct hashmap)); - - if (res == NULL) - return NULL; - - res->maxsize = DEFAULT_BUCKETS; - res->entries = 0; - - res->data = (hashentry_t*) - calloc(1, res->maxsize * sizeof(struct hashentry)); - - if (res->data == NULL) - return NULL; - - return res; -} - -static hashentry_t -new_entry(const char* key, const char* value) -{ - hashentry_t res; - - res = (hashentry_t) calloc(1, sizeof(struct hashentry)); - - if (res == NULL) - return NULL; - - /* allocate key and value and copy them */ - res->key = strdup(key); - if (res->key == NULL) { - free(res); - return NULL; - } - - res->value = strdup(value); - if (res->value == NULL) { - free(res->key); - free(res); - return NULL; - } - - res->next = NULL; - - return res; -} - -static hashentry_t -free_entry(hashentry_t e) -{ - if (!is_empty(e)) { - if(e->key != NULL) { - free(e->key); - } - if(e->value != NULL) - free(e->value); - free(e); - } - - return NULL; -} - -static hashentry_t -remove_entry(hashentry_t l, const char* key, size_t* entries) -{ - hashentry_t lnext; - if (is_empty(l)) - return NULL; - - if(strcmp(l->key,key) == 0) { - lnext = l->next; - l = free_entry(l); - (*entries)--; - return lnext; - } - - l->next = remove_entry(l->next, key, entries); - - return l; -} - -static hashentry_t -insert_entry(hashentry_t l, hashentry_t e, size_t* entries) -{ - if (is_empty(l)) { - (*entries)++; - return e; - } - - /* check for update */ - if (strcmp(l->key, e->key) == 0) { - e->next = l->next; - l = free_entry(l); - return e; - } - - l->next = insert_entry(l->next, e, entries); - return l; -} - -static hashentry_t -remove_all(hashentry_t l, size_t* entries) -{ - hashentry_t lnext; - if (is_empty(l)) - return NULL; - - lnext = l->next; - free_entry(l); - (*entries)--; - - return remove_all(lnext, entries); -} - -static const char* -value_lookup(hashentry_t l, const char* key) -{ - if (is_empty(l)) - return NULL; - - if (strcmp(l->key, key) == 0) - return l->value; - - return value_lookup(l->next, key); -} - -static void -print_all(hashentry_t l) -{ - if (is_empty(l)) { - printf("\n"); - return; - } - - printf("%s=%s", l->key, l->value); - if (!is_empty(l->next)) { - printf(","); - } - - print_all(l->next); -} - -static void -keys_to_array(hashentry_t l, const char** a, size_t* i) -{ - if (is_empty(l)) - return; - - a[*i] = l->key; - (*i)++; - - keys_to_array(l->next, a, i); -} - -uint32_t -hash_str(const char* str, uint32_t mapsize) -{ - uint32_t hash = 0; - uint32_t x = 0; - uint32_t i = 0; - size_t len = strlen(str); - - for(i = 0; i < len; str++, i++) { - hash = (hash << 4) + (*str); - if((x = hash & 0xF0000000L) != 0) { - hash ^= (x >> 24); - hash &= ~x; - } - } - - return (hash & 0x7FFFFFFF) % mapsize; -} - - -int -hashmap_is_empty(hashmap_t map) -{ - if (map == NULL) - return -EINVAL; - - return map->entries > 0 ? 1 : 0; -} - -const char* -hashmap_lookup(hashmap_t map, const char* key) -{ - uint32_t i; - - if ((map == NULL) || (key == NULL)) - return NULL; - - i = hash_str(key, map->maxsize); - - return value_lookup(map->data[i], key); -} - -int -hashmap_add(hashmap_t map, const char* key, const char* value) -{ - uint32_t i; - hashentry_t entry; - - if ((map == NULL) || (key == NULL) || (value == NULL)) - return -EINVAL; - - i = hash_str(key, map->maxsize); - entry = new_entry(key, value); - if (entry == NULL) - return -ENOMEM; - - map->data[i] = insert_entry(map->data[i], - entry, &map->entries); - - INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value); - return 0; -} - -int -hashmap_remove(hashmap_t map, const char* key) -{ - uint32_t i; - - if ((map == NULL) || (key == NULL)) - return -EINVAL; - - i = hash_str(key, map->maxsize); - map->data[i] = remove_entry(map->data[i], key, &map->entries); - - return 0; -} - -size_t -hashmap_size(hashmap_t map) -{ - if (map != NULL) - return map->entries; - else - return 0; -} - -int -hashmap_free(hashmap_t map) -{ - size_t i; - - if (map == NULL) - return -EINVAL; - - /* "children" first */ - for(i = 0; i < map->maxsize; i++) { - map->data[i] = remove_all(map->data[i], &map->entries); - } - free(map->data); - free(map); - - return 0; -} - -int -hashmap_dump(hashmap_t map) -{ - size_t i; - if (map == NULL) - return -EINVAL; - - for(i = 0; i < map->maxsize; i++) { - if (map->data[i] != NULL) { - printf("[%d]: ", i); - print_all(map->data[i]); - } - } - - return 0; -} - -static const char** -sort_key_vector(const char** a, size_t size) -{ - /* uses bubblesort */ - size_t i, j; - const char* tmp; - - if (size <= 0) - return a; - - for (i = size - 1; i > 0; i--) { - for (j = 0; j < i; j++) { - if (strcmp(a[j], a[j+1]) > 0) { - tmp = a[j]; - a[j] = a[j+1]; - a[j+1] = tmp; - } - } - } - return a; -} - -const char** -hashmap_get_key_vector(hashmap_t map, size_t* size, int sort) -{ - const char** res; - size_t i, j; - *size = map->entries; - - res = (const char**) malloc(*size * sizeof(char*)); - if (res == NULL) - return NULL; - - j = 0; - for(i=0; i < map->maxsize; i++) { - keys_to_array(map->data[i], res, &j); - } - - if (sort) - res = sort_key_vector(res, *size); - - return res; -} - -int -hashmap_key_is_in_vector(const char** vec, size_t size, const char* key) -{ - size_t i; - for (i = 0; i < size; i++) { - if (strcmp(vec[i], key) == 0) /* found */ - return 1; - } - - return 0; -} - -const char** -hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, - const char** vec2, size_t vec2_size, size_t* res_size) -{ - const char** res; - size_t i, j; - - *res_size = vec2_size; - - res = (const char**) malloc(*res_size * sizeof(char*)); - if (res == NULL) - return NULL; - - /* get all keys from vec2 which are not set in vec1 */ - j = 0; - for (i = 0; i < vec2_size; i++) { - if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i])) - res[j++] = vec2[i]; - } - - *res_size = j; - return res; -} diff --git a/ubi-utils/src/libbootenv/hashmap.h b/ubi-utils/src/libbootenv/hashmap.h deleted file mode 100644 index 1b13e95..0000000 --- a/ubi-utils/src/libbootenv/hashmap.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __HASHMAP_H__ -#define __HASHMAP_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 -#include - -typedef struct hashentry *hashentry_t; -typedef struct hashmap *hashmap_t; - -hashmap_t hashmap_new(void); -int hashmap_free(hashmap_t map); - -int hashmap_add(hashmap_t map, const char* key, const char* value); -int hashmap_update(hashmap_t map, const char* key, const char* value); -int hashmap_remove(hashmap_t map, const char* key); -const char* hashmap_lookup(hashmap_t map, const char* key); - -const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort); -int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key); -const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, - const char** vec2, size_t vec2_size, size_t* res_size); - -int hashmap_dump(hashmap_t map); - -int hashmap_is_empty(hashmap_t map); -size_t hashmap_size(hashmap_t map); - -uint32_t hash_str(const char* str, uint32_t mapsize); - -#endif /* __HASHMAP_H__ */ diff --git a/ubi-utils/src/libcrc32/crc32.c b/ubi-utils/src/libcrc32/crc32.c deleted file mode 100644 index 666e217..0000000 --- a/ubi-utils/src/libcrc32/crc32.c +++ /dev/null @@ -1,83 +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: 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 -#include - -/* 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; -} diff --git a/ubi-utils/src/liberror/error.c b/ubi-utils/src/liberror/error.c deleted file mode 100644 index c8c623c..0000000 --- a/ubi-utils/src/liberror/error.c +++ /dev/null @@ -1,177 +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 -#include -#include -#include -#include -#include -#include "error.h" - -#define MAXLINE 4096 - -static FILE *logfp = NULL; - -static void err_doit(int, int, const char *, va_list); - -int -read_procfile(FILE *fp_out, const char *procfile) -{ - FILE *fp; - - fp = fopen(procfile, "r"); - if (!fp) - return -ENOENT; - - while(!feof(fp)) { - int c = fgetc(fp); - - if (c == EOF) - return 0; - - if (putc(c, fp_out) == EOF) - return -EIO; - - if (ferror(fp)) - return -EIO; - } - return fclose(fp); -} - -void -error_initlog(const char *logfile) -{ - logfp = fopen(logfile, "a+"); - read_procfile(logfp, "/proc/cpuinfo"); -} - -void -info_msg(const char *fmt, ...) -{ - FILE* fpout; - char buf[MAXLINE + 1]; - va_list ap; - int n; - - fpout = stdout; - - va_start(ap, fmt); - vsnprintf(buf, MAXLINE, fmt, ap); - n = strlen(buf); - strcat(buf, "\n"); - - fputs(buf, fpout); - fflush(fpout); - if (fpout != stdout) - fclose(fpout); - - va_end(ap); - return; -} - -void -__err_ret(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_INFO, fmt, ap); - va_end(ap); - return; -} - -void -__err_sys(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_ERR, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - - -void -__err_msg(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(0, LOG_INFO, fmt, ap); - va_end(ap); - - return; -} - -void -__err_quit(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(0, LOG_ERR, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -void -__err_dump(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_ERR, fmt, ap); - va_end(ap); - abort(); /* dump core and terminate */ - exit(EXIT_FAILURE); /* shouldn't get here */ -} - - -static void -err_doit(int errnoflag, int level __attribute__((unused)), - const char *fmt, va_list ap) -{ - FILE* fpout; - int errno_save, n; - char buf[MAXLINE + 1]; - fpout = stderr; - - errno_save = errno; /* value caller might want printed */ - - vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ - - n = strlen(buf); - - if (errnoflag) - snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); - strcat(buf, "\n"); - - if (logfp) { - fputs(buf, logfp); - fflush(logfp); - } - - fputs(buf, fpout); - fflush(fpout); - if (fpout != stderr) - fclose(fpout); - - return; -} diff --git a/ubi-utils/src/liblist/list.c b/ubi-utils/src/liblist/list.c deleted file mode 100644 index 6eb716b..0000000 --- a/ubi-utils/src/liblist/list.c +++ /dev/null @@ -1,149 +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 - */ - -#include -#include -#include - -#include "list.h" - -list_t -mk_empty(void) -{ - return (list_t) NULL; -} - -int -is_empty(list_t l) -{ - return l == NULL; -} - -info_t -head(list_t l) -{ - assert(!is_empty(l)); - return l->info; -} - -list_t -tail(list_t l) -{ - assert(!is_empty(l)); - return l->next; -} - -list_t -remove_head(list_t l) -{ - list_t res; - assert(!is_empty(l)); - - res = l->next; - free(l); - return res; -} - -list_t -cons(info_t e, list_t l) -{ - list_t res = malloc(sizeof(*l)); - if (!res) - return NULL; - res->info = e; - res->next = l; - - return res; -} - -list_t -prepend_elem(info_t e, list_t l) -{ - return cons(e,l); -} - -list_t -append_elem(info_t e, list_t l) -{ - if (is_empty(l)) { - return cons(e,l); - } - l->next = append_elem(e, l->next); - - return l; -} - -list_t -insert_sorted(cmp_func_t cmp, info_t e, list_t l) -{ - if (is_empty(l)) - return cons(e, l); - - switch (cmp(e, l->info)) { - case -1: - case 0: - return l; - break; - case 1: - l->next = insert_sorted(cmp, e, l); - break; - default: - break; - } - - /* never reached */ - return NULL; -} - -list_t -remove_all(free_func_t free_func, list_t l) -{ - if (is_empty(l)) - return l; - list_t lnext = l->next; - - if (free_func && l->info) { - free_func(&(l->info)); - } - free(l); - - return remove_all(free_func, lnext); -} - - -info_t -is_in(cmp_func_t cmp, info_t e, list_t l) -{ - return - (is_empty(l)) - ? NULL - : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next); -} - - -void -apply(process_func_t process_func, list_t l) -{ - list_t ptr; - void *i; - foreach(i, ptr, l) { - process_func(i); - } -} diff --git a/ubi-utils/src/libpeb/peb.c b/ubi-utils/src/libpeb/peb.c deleted file mode 100644 index 08b770f..0000000 --- a/ubi-utils/src/libpeb/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 -#include -#include -#include -#include -#include - -#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 eb_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 = eb_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/libpfi/pfi.c b/ubi-utils/src/libpfi/pfi.c deleted file mode 100644 index c8d5ee4..0000000 --- a/ubi-utils/src/libpfi/pfi.c +++ /dev/null @@ -1,461 +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. - * - * Wed Feb 8 11:38:22 CET 2006: Initial creation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#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 */ -}; - -static const char* modes[] = {"raw", "ubi", NULL}; /* 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) -{ - const char* ptr = modes[0]; - int i = 0; - while (ptr != NULL) { - if(strcmp(ptr, mode) == 0) { - return i; - } - ptr++; - 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 ((uint32_t)value == (uint32_t)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/libpfiflash.c b/ubi-utils/src/libpfiflash.c new file mode 100644 index 0000000..ed2af3c --- /dev/null +++ b/ubi-utils/src/libpfiflash.c @@ -0,0 +1,619 @@ +/* + * 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 pfiflash.c + * + * @author Oliver Lohmann + * + * @brief This library is provides an interface to the pfiflash utility. + * + * Wed Mar 15 11:39:19 CET 2006 Initial creation. + * + * @TODO Comare data before writing it. This implies that the volume + * parameters are compared first: size, alignment, name, type, ..., + * this is the same, compare the data. Volume deletion is deffered + * until the difference has been found out. + */ + +#include +#include +#include +#define __USE_GNU +#include + +#include +#include + +//#include /* FIXME Is this ok here!!?? */ + +#include "config.h" +#include "ubimirror.h" +#include "error.h" +#include "reader.h" +#include "example_ubi.h" +#include "bootenv.h" + +static const char copyright [] __attribute__((unused)) = + "Copyright (c) International Business Machines Corp., 2006"; + +#define EBUF(fmt...) do { \ + snprintf(err_buf, err_buf_size, fmt); \ + } while (0) + +static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = + { + &bootenv_pdd_keep, + &bootenv_pdd_merge, + &bootenv_pdd_overwrite + }; +/**< An array of PDD function pointers indexed by the algorithm. */ + + +typedef enum ubi_update_process_t { + UBI_REMOVE = 0, + UBI_WRITE, +} ubi_update_process_t; + +static int +skip_raw_sections(FILE* pfi, list_t pfi_raws, + char* err_buf, size_t err_buf_size) +{ + int rc = 0; + + void *i; + list_t ptr; + size_t j, skip_size; + + if (is_empty(pfi_raws)) + return 0; + + foreach(i, ptr, pfi_raws) { + skip_size = ((pfi_raw_t)i)->data_size; + for(j = 0; j < skip_size; j++) { + fgetc(pfi); + if (ferror(pfi)) { + EBUF("Cannot skip raw section in PFI."); + rc = -EIO; + goto err; + } + } + } + err: + return rc; +} + +/** + * @brief Wraps the ubi_mkvol functions and implements a hook for the bootenv + * update. + * @param devno UBI device number. + * @param s Current seqnum. + * @param u Information about the UBI volume from the PFI. + * @param err_buf An error buffer. + * @param err_buf_size The size of the error buffer. + * @return 0 On Sucess. + * @return else Error. + */ +static int +my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size) +{ + int rc = 0; + int type; + ubi_lib_t ulib = NULL; + + log_msg("%s(vol_id=%d, size=%d, data_size=%d, type=%d, " + "alig=%d, nlen=%d, name=%s)", __func__, + u->ids[s], u->size, u->data_size, u->type, u->alignment, + strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); + + rc = ubi_open(&ulib); + if (rc != 0) { + goto err; + } + + switch (u->type) { + case pfi_ubi_static: + type = UBI_STATIC_VOLUME; break; + case pfi_ubi_dynamic: + type = UBI_DYNAMIC_VOLUME; break; + default: + type = UBI_DYNAMIC_VOLUME; + } + + rc = ubi_mkvol(ulib, devno, u->ids[s], type, u->size, u->alignment, + u->names[s]); + if (rc != 0) { + EBUF("Cannot create volume: %d", u->ids[s]); + goto err; + } + + err: + if (ulib != NULL) + ubi_close(&ulib); + return rc; +} + +/** + * @brief A wrapper around the UBI library function ubi_rmvol. + * @param devno UBI device number. + * @param s Current seqnum. + * @param u Information about the UBI volume from the PFI. + * @param err_buf An error buffer. + * @param err_buf_size The size of the error buffer. + * + * If the volume does not exist, the function will return success. + */ +static int +my_ubi_rmvol(int devno, uint32_t id, + char *err_buf __unused, size_t err_buf_size __unused) +{ + int rc = 0; + ubi_lib_t ulib = NULL; + int fd; + + log_msg("%s(id=%d)", __func__, id); + + rc = ubi_open(&ulib); + if (rc != 0) + goto err; + + /** + * Truncate if it exist or not. + */ + fd = ubi_vol_open(ulib, devno, id, O_RDWR); + if (fd == -1) + return 0; /* not existent, return */ + + rc = ubi_vol_update(fd, 0); + if (rc < 0) { + fprintf(stderr, "update failed rc=%d errno=%d\n", rc, errno); + ubi_vol_close(fd); + goto err; /* if EBUSY than empty device, continue */ + } + ubi_vol_close(fd); + + rc = ubi_rmvol(ulib, devno, id); + if (rc != 0) { + /* @TODO Define a ubi_rmvol return value which says + * sth like EUBI_NOSUCHDEV. In this case, a failed + * operation is acceptable. Everything else has to be + * classified as real error. But talk to Andreas Arnez + * before defining something odd... + */ + /* if ((errno == EINVAL) || (errno == ENODEV)) + return 0; */ /* currently it is EINVAL or ENODEV */ + + dbg_msg("Remove UBI volume %d returned with error: %d " + "errno=%d", id, rc, errno); + goto err; + } + err: + if (ulib != NULL) + ubi_close(&ulib); + return rc; +} + +static int +read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + ubi_lib_t ulib = NULL; + FILE* fp_in = NULL; + + rc = ubi_open(&ulib); + if (rc) + return rc; + + fp_in = ubi_vol_fopen_read(ulib, devno, id); + if (!fp_in) { + EBUF("Cannot open bootenv volume"); + rc = -EIO; + goto err; + } + + log_msg("%s reading old bootenvs", __func__); + + /* Save old bootenvs for reference */ + rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); + if (rc) + EBUF("Cannot read bootenv_old"); + err: + if (fp_in) + fclose(fp_in); + if (ulib) + ubi_close(&ulib); + return rc; +} + +static int +write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, + pdd_func_t pdd_f, + FILE* fp_in, /* new pdd data contained in pfi */ + size_t fp_in_size, /* data size of new pdd data in pfi */ + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + int warnings = 0; + ubi_lib_t ulib = NULL; + bootenv_t bootenv_new = NULL; + bootenv_t bootenv_res = NULL; + size_t update_size = 0; + FILE *fp_out = NULL; + + log_msg("%s(id=%d, fp_in=%p)", __func__, id, fp_in); + + /* Workflow: + * 1. Apply PDD operation and get the size of the returning + * bootenv_res section. Without the correct size it wouldn't + * be possible to call UBI update vol. + * 2. Call UBI update vol + * 3. Get FILE* to vol dev + * 4. Write to FILE* + */ + + rc = ubi_open(&ulib); + if (rc != 0) { + goto err; + } + + rc = bootenv_create(&bootenv_new); + if (rc != 0) + goto err; + rc = bootenv_create(&bootenv_res); + if (rc != 0) + goto err; + + rc = bootenv_read(fp_in, bootenv_new, fp_in_size); + if (rc != 0) + goto err; + + rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, + err_buf, err_buf_size); + if (rc != 0) + goto err; + if (warnings) { + /* @TODO Do sth with the warning */ + dbg_msg("A warning in the PDD operation occured: %d", + warnings); + } + log_msg("... (2)"); + + rc = bootenv_size(bootenv_res, &update_size); + if (rc != 0) + goto err; + + fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); + if (fp_out == NULL) + goto err; + + rc = bootenv_write(fp_out, bootenv_res); + if (rc != 0) { + EBUF("Write operation on ubi%d_%d failed.", devno, id); + rc = -EIO; + goto err; + } + + err: + if (ulib != NULL) + ubi_close(&ulib); + if (bootenv_new != NULL) + bootenv_destroy(&bootenv_new); + if (bootenv_res != NULL) + bootenv_destroy(&bootenv_res); + if (fp_out) + fclose(fp_out); + return rc; +} + +static int +write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, + char *err_buf __unused, size_t err_buf_size __unused) +{ + int rc = 0; + ubi_lib_t ulib = NULL; + FILE* fp_out = NULL; + int c; + size_t i; + + log_msg("%s(id=%d, update_size=%d fp_in=%p)", + __func__, id, update_size, fp_in); + + rc = ubi_open(&ulib); + if (rc) + return rc; + + fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); + if (fp_out == NULL) { + rc = -1; + goto err; + } + + log_msg("starting the update ... "); /* FIXME DBG */ + for (i = 0; i < update_size; i++) { + c = getc(fp_in); + if (c == EOF && ferror(fp_in)) { + rc = -EIO; + goto err; + } + if (putc(c, fp_out) == EOF) { + rc = -EIO; + goto err; + } + /* FIXME DBG */ + /* if ((i & 0xFFF) == 0xFFF) log_msg("."); */ + } + /* log_msg("\n"); */ /* FIXME DBG */ + err: + if (fp_out) + fclose(fp_out); + if (ulib) + ubi_close(&ulib); + return rc; +} + + +/** + * @brief ... + * @precondition The PFI file contains at least one ubi_id entry. + * This is assured by the PFI read process. + * @postcondition The used seqnum number is set in the UBI PFI + * header list. + * The UBI volumes specified by seqnum are processed. + */ +static int +process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, + bootenv_t bootenv_old, pdd_func_t pdd_f, + ubi_update_process_t ubi_update_process, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + pfi_ubi_t u; + list_t ptr; + + foreach(u, ptr, pfi_ubis) { + int s = seqnum; + if (seqnum > ((int)u->ids_size - 1)) { + s = 0; /* per default use the first */ + } + u->curr_seqnum = s; + + switch (ubi_update_process) { + case UBI_REMOVE: + if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || + (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { + rc =read_bootenv_volume(EXAMPLE_UBI_DEVICE, + u->ids[s], + bootenv_old, err_buf, + err_buf_size); + if (rc != 0) + goto err; + } + rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], + err_buf, err_buf_size); + if (rc != 0) + goto err; + break; + case UBI_WRITE: + rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, + err_buf, err_buf_size); + if (rc != 0) + goto err; + if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || + (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { + rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, + u->ids[s], + bootenv_old, pdd_f, + pfi, + u->data_size, + err_buf, + err_buf_size); + } + else { + rc = write_normal_volume(EXAMPLE_UBI_DEVICE, + u->ids[s], + u->data_size, pfi, + err_buf, + err_buf_size); + } + if (rc != 0) + goto err; + break; + default: + EBUF("Invoked unknown UBI operation."); + rc = -1; + goto err; + + } + if (rc != 0) { + goto err; + } + } + err: + return rc; + +} + +static int +erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + list_t ptr; + pfi_ubi_t u; + size_t i; + uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; + + for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { + ubi_volumes[i] = 1; + } + + foreach(u, ptr, pfi_ubis) { + /* iterate over each vol_id */ + for(i = 0; i < u->ids_size; i++) { + if (u->ids[i] > PFI_UBI_MAX_VOLUMES) { + EBUF("PFI file contains an invalid " + "volume id: %d", u->ids[i]); + goto err; + } + /* remove from removal list */ + ubi_volumes[u->ids[i]] = 0; + } + } + + for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { + if (ubi_volumes[i]) { + rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); + if (rc != 0) + goto err; + } + } + err: + return rc; +} + +static int +mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + list_t ptr; + uint32_t j; + pfi_ubi_t i; + ubi_lib_t ulib = NULL; + + log_msg("%s(...)", __func__); + + rc = ubi_open(&ulib); + if (rc != 0) + goto err; + + /** + * Execute all mirror operations on redundant groups. + * Create a volume within a redundant group if it does + * not exist already (this is a precondition of + * ubimirror). + */ + foreach(i, ptr, pfi_ubis) { + for(j = 0; j < i->ids_size; j++) { + /* skip self-match */ + if (i->ids[j] == i->ids[i->curr_seqnum]) + continue; + + rc = my_ubi_rmvol(devno, i->ids[j], err_buf, + err_buf_size); + if (rc != 0) + goto err; + + rc = my_ubi_mkvol(devno, j, i, err_buf, err_buf_size); + if (rc != 0) + goto err; + } + } + + foreach(i, ptr, pfi_ubis) { + rc = ubimirror(devno, i->curr_seqnum, i->ids, + i->ids_size, err_buf, err_buf_size); + if (rc != 0) + goto err; + } + + + err: + if (ulib != NULL) + ubi_close(&ulib); + return rc; +} + +int +pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + pdd_func_t pdd_f = NULL; + + if (pfi == NULL) + return -EINVAL; + + /** + * If the user didnt specify a seqnum we start per default + * with the index 0 + */ + int curr_seqnum = seqnum < 0 ? 0 : seqnum; + + 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 */ + + bootenv_t bootenv; + rc = bootenv_create(&bootenv); + if (rc != 0) { + EBUF("Cannot create bootenv variable"); + } + + rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, + err_buf, err_buf_size); + if (rc != 0) { + EBUF("Cannot read PFI headers."); + goto err; + } + + /* @TODO: If you want to implement an IPL update - start here. */ + rc = skip_raw_sections(pfi, pfi_raws, err_buf, err_buf_size); + if (rc != 0) { + goto err; + } + + if (complete) { + rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, + err_buf, err_buf_size); + if (rc != 0) { + EBUF("Cannot delete unmapped UBI volumes."); + goto err; + } + } + + if (((int)pdd_handling >= 0) && (pdd_handling < PDD_HANDLING_NUM)) { + pdd_f = pdd_funcs[pdd_handling]; + } + else { + EBUF("Used unknown PDD handling algorithm (pdd_handling)"); + } + + rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, + UBI_REMOVE, err_buf, err_buf_size); + if (rc != 0) { + goto err; + } + rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, + UBI_WRITE, err_buf, err_buf_size); + if (rc != 0) { + goto err; + } + if (seqnum < 0) { /* mirror redundant pairs */ + rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, + err_buf, err_buf_size); + if (rc != 0) + goto err; + } + + 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); + bootenv_destroy(&bootenv); + return rc; +} diff --git a/ubi-utils/src/libpfiflash/pfiflash.c b/ubi-utils/src/libpfiflash/pfiflash.c deleted file mode 100644 index 0859a22..0000000 --- a/ubi-utils/src/libpfiflash/pfiflash.c +++ /dev/null @@ -1,617 +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 pfiflash.c - * - * @author Oliver Lohmann - * - * @brief This library is provides an interface to the pfiflash utility. - * - * Wed Mar 15 11:39:19 CET 2006 Initial creation. - * - * @TODO Comare data before writing it. This implies that the volume - * parameters are compared first: size, alignment, name, type, ..., - * this is the same, compare the data. Volume deletion is deffered - * until the difference has been found out. - */ - -#include -#include -#include -#define __USE_GNU -#include - -#include -#include - -#include /* FIXME Is this ok here!!?? */ - -#include "ubimirror.h" -#include "error.h" -#include "reader.h" -#include "example_ubi.h" -#include "bootenv.h" - -static const char copyright [] __attribute__((unused)) = - "Copyright (c) International Business Machines Corp., 2006"; - -#define EBUF(fmt...) do { \ - snprintf(err_buf, err_buf_size, fmt); \ - } while (0) - -static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = - { - &bootenv_pdd_keep, - &bootenv_pdd_merge, - &bootenv_pdd_overwrite - }; -/**< An array of PDD function pointers indexed by the algorithm. */ - - -typedef enum ubi_update_process_t { - UBI_REMOVE = 0, - UBI_WRITE, -} ubi_update_process_t; - -static int -skip_raw_sections(FILE* pfi, list_t pfi_raws, - char* err_buf, size_t err_buf_size) -{ - int rc = 0; - - void *i; - list_t ptr; - size_t j, skip_size; - - if (is_empty(pfi_raws)) - return 0; - - foreach(i, ptr, pfi_raws) { - skip_size = ((pfi_raw_t)i)->data_size; - for(j = 0; j < skip_size; j++) { - fgetc(pfi); - if (ferror(pfi)) { - EBUF("Cannot skip raw section in PFI."); - rc = -EIO; - goto err; - } - } - } - err: - return rc; -} - -/** - * @brief Wraps the ubi_mkvol functions and implements a hook for the bootenv - * update. - * @param devno UBI device number. - * @param s Current seqnum. - * @param u Information about the UBI volume from the PFI. - * @param err_buf An error buffer. - * @param err_buf_size The size of the error buffer. - * @return 0 On Sucess. - * @return else Error. - */ -static int -my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size) -{ - int rc = 0; - int type; - ubi_lib_t ulib = NULL; - - log_msg("%s(vol_id=%d, size=%d, data_size=%d, type=%d, " - "alig=%d, nlen=%d, name=%s)", __func__, - u->ids[s], u->size, u->data_size, u->type, u->alignment, - strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); - - rc = ubi_open(&ulib); - if (rc != 0) { - goto err; - } - - switch (u->type) { - case pfi_ubi_static: - type = UBI_STATIC_VOLUME; break; - case pfi_ubi_dynamic: - type = UBI_DYNAMIC_VOLUME; break; - default: - type = UBI_DYNAMIC_VOLUME; - } - - rc = ubi_mkvol(ulib, devno, u->ids[s], type, u->size, u->alignment, - u->names[s]); - if (rc != 0) { - EBUF("Cannot create volume: %d", u->ids[s]); - goto err; - } - - err: - if (ulib != NULL) - ubi_close(&ulib); - return rc; -} - -/** - * @brief A wrapper around the UBI library function ubi_rmvol. - * @param devno UBI device number. - * @param s Current seqnum. - * @param u Information about the UBI volume from the PFI. - * @param err_buf An error buffer. - * @param err_buf_size The size of the error buffer. - * - * If the volume does not exist, the function will return success. - */ -static int -my_ubi_rmvol(int devno, uint32_t id, char *err_buf, size_t err_buf_size) -{ - int rc = 0; - ubi_lib_t ulib = NULL; - int fd; - - log_msg("%s(id=%d)", __func__, id); - - rc = ubi_open(&ulib); - if (rc != 0) - goto err; - - /** - * Truncate if it exist or not. - */ - fd = ubi_vol_open(ulib, devno, id, O_RDWR); - if (fd == -1) - return 0; /* not existent, return */ - - rc = ubi_vol_update(fd, 0); - if (rc < 0) { - fprintf(stderr, "update failed rc=%d errno=%d\n", rc, errno); - ubi_vol_close(fd); - goto err; /* if EBUSY than empty device, continue */ - } - ubi_vol_close(fd); - - rc = ubi_rmvol(ulib, devno, id); - if (rc != 0) { - /* @TODO Define a ubi_rmvol return value which says - * sth like EUBI_NOSUCHDEV. In this case, a failed - * operation is acceptable. Everything else has to be - * classified as real error. But talk to Andreas Arnez - * before defining something odd... - */ - /* if ((errno == EINVAL) || (errno == ENODEV)) - return 0; */ /* currently it is EINVAL or ENODEV */ - - dbg_msg("Remove UBI volume %d returned with error: %d " - "errno=%d", id, rc, errno); - goto err; - } - err: - if (ulib != NULL) - ubi_close(&ulib); - return rc; -} - -static int -read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - ubi_lib_t ulib = NULL; - FILE* fp_in = NULL; - - rc = ubi_open(&ulib); - if (rc) - return rc; - - fp_in = ubi_vol_fopen_read(ulib, devno, id); - if (!fp_in) { - EBUF("Cannot open bootenv volume"); - rc = -EIO; - goto err; - } - - log_msg("%s reading old bootenvs", __func__); - - /* Save old bootenvs for reference */ - rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); - if (rc) - EBUF("Cannot read bootenv_old"); - err: - if (fp_in) - fclose(fp_in); - if (ulib) - ubi_close(&ulib); - return rc; -} - -static int -write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, - pdd_func_t pdd_f, - FILE* fp_in, /* new pdd data contained in pfi */ - size_t fp_in_size, /* data size of new pdd data in pfi */ - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - int warnings = 0; - ubi_lib_t ulib = NULL; - bootenv_t bootenv_new = NULL; - bootenv_t bootenv_res = NULL; - size_t update_size = 0; - FILE *fp_out = NULL; - - log_msg("%s(id=%d, fp_in=%p)", __func__, id, fp_in); - - /* Workflow: - * 1. Apply PDD operation and get the size of the returning - * bootenv_res section. Without the correct size it wouldn't - * be possible to call UBI update vol. - * 2. Call UBI update vol - * 3. Get FILE* to vol dev - * 4. Write to FILE* - */ - - rc = ubi_open(&ulib); - if (rc != 0) { - goto err; - } - - rc = bootenv_create(&bootenv_new); - if (rc != 0) - goto err; - rc = bootenv_create(&bootenv_res); - if (rc != 0) - goto err; - - rc = bootenv_read(fp_in, bootenv_new, fp_in_size); - if (rc != 0) - goto err; - - rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, - err_buf, err_buf_size); - if (rc != 0) - goto err; - if (warnings) { - /* @TODO Do sth with the warning */ - dbg_msg("A warning in the PDD operation occured: %d", - warnings); - } - log_msg("... (2)"); - - rc = bootenv_size(bootenv_res, &update_size); - if (rc != 0) - goto err; - - fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); - if (fp_out == NULL) - goto err; - - rc = bootenv_write(fp_out, bootenv_res); - if (rc != 0) { - EBUF("Write operation on ubi%d_%d failed.", devno, id); - rc = -EIO; - goto err; - } - - err: - if (ulib != NULL) - ubi_close(&ulib); - if (bootenv_new != NULL) - bootenv_destroy(&bootenv_new); - if (bootenv_res != NULL) - bootenv_destroy(&bootenv_res); - if (fp_out) - fclose(fp_out); - return rc; -} - -static int -write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - ubi_lib_t ulib = NULL; - FILE* fp_out = NULL; - int c; - size_t i; - - log_msg("%s(id=%d, update_size=%d fp_in=%p)", - __func__, id, update_size, fp_in); - - rc = ubi_open(&ulib); - if (rc) - return rc; - - fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); - if (fp_out == NULL) { - rc = -1; - goto err; - } - - log_msg("starting the update ... "); /* FIXME DBG */ - for (i = 0; i < update_size; i++) { - c = getc(fp_in); - if (c == EOF && ferror(fp_in)) { - rc = -EIO; - goto err; - } - if (putc(c, fp_out) == EOF) { - rc = -EIO; - goto err; - } - /* FIXME DBG */ - /* if ((i & 0xFFF) == 0xFFF) log_msg("."); */ - } - /* log_msg("\n"); */ /* FIXME DBG */ - err: - if (fp_out) - fclose(fp_out); - if (ulib) - ubi_close(&ulib); - return rc; -} - - -/** - * @brief ... - * @precondition The PFI file contains at least one ubi_id entry. - * This is assured by the PFI read process. - * @postcondition The used seqnum number is set in the UBI PFI - * header list. - * The UBI volumes specified by seqnum are processed. - */ -static int -process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, - bootenv_t bootenv_old, pdd_func_t pdd_f, - ubi_update_process_t ubi_update_process, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - pfi_ubi_t u; - list_t ptr; - - foreach(u, ptr, pfi_ubis) { - int s = seqnum; - if (seqnum > (u->ids_size - 1)) { - s = 0; /* per default use the first */ - } - u->curr_seqnum = s; - - switch (ubi_update_process) { - case UBI_REMOVE: - if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || - (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { - rc =read_bootenv_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - bootenv_old, err_buf, - err_buf_size); - if (rc != 0) - goto err; - } - rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], - err_buf, err_buf_size); - if (rc != 0) - goto err; - break; - case UBI_WRITE: - rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, - err_buf, err_buf_size); - if (rc != 0) - goto err; - if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || - (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { - rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - bootenv_old, pdd_f, - pfi, - u->data_size, - err_buf, - err_buf_size); - } - else { - rc = write_normal_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - u->data_size, pfi, - err_buf, - err_buf_size); - } - if (rc != 0) - goto err; - break; - default: - EBUF("Invoked unknown UBI operation."); - rc = -1; - goto err; - - } - if (rc != 0) { - goto err; - } - } - err: - return rc; - -} - -static int -erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - list_t ptr; - pfi_ubi_t u; - size_t i; - uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; - - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { - ubi_volumes[i] = 1; - } - - foreach(u, ptr, pfi_ubis) { - /* iterate over each vol_id */ - for(i = 0; i < u->ids_size; i++) { - if (u->ids[i] > PFI_UBI_MAX_VOLUMES) { - EBUF("PFI file contains an invalid " - "volume id: %d", u->ids[i]); - goto err; - } - /* remove from removal list */ - ubi_volumes[u->ids[i]] = 0; - } - } - - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { - if (ubi_volumes[i]) { - rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); - if (rc != 0) - goto err; - } - } - err: - return rc; -} - -static int -mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - list_t ptr; - uint32_t j; - pfi_ubi_t i; - ubi_lib_t ulib = NULL; - - log_msg("%s(...)", __func__); - - rc = ubi_open(&ulib); - if (rc != 0) - goto err; - - /** - * Execute all mirror operations on redundant groups. - * Create a volume within a redundant group if it does - * not exist already (this is a precondition of - * ubimirror). - */ - foreach(i, ptr, pfi_ubis) { - for(j = 0; j < i->ids_size; j++) { - /* skip self-match */ - if (i->ids[j] == i->ids[i->curr_seqnum]) - continue; - - rc = my_ubi_rmvol(devno, i->ids[j], err_buf, - err_buf_size); - if (rc != 0) - goto err; - - rc = my_ubi_mkvol(devno, j, i, err_buf, err_buf_size); - if (rc != 0) - goto err; - } - } - - foreach(i, ptr, pfi_ubis) { - rc = ubimirror(devno, i->curr_seqnum, i->ids, - i->ids_size, err_buf, err_buf_size); - if (rc != 0) - goto err; - } - - - err: - if (ulib != NULL) - ubi_close(&ulib); - return rc; -} - -int -pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - pdd_func_t pdd_f = NULL; - - if (pfi == NULL) - return -EINVAL; - - /** - * If the user didnt specify a seqnum we start per default - * with the index 0 - */ - int curr_seqnum = seqnum < 0 ? 0 : seqnum; - - 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 */ - - bootenv_t bootenv; - rc = bootenv_create(&bootenv); - if (rc != 0) { - EBUF("Cannot create bootenv variable"); - } - - rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, - err_buf, err_buf_size); - if (rc != 0) { - EBUF("Cannot read PFI headers."); - goto err; - } - - /* @TODO: If you want to implement an IPL update - start here. */ - rc = skip_raw_sections(pfi, pfi_raws, err_buf, err_buf_size); - if (rc != 0) { - goto err; - } - - if (complete) { - rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, - err_buf, err_buf_size); - if (rc != 0) { - EBUF("Cannot delete unmapped UBI volumes."); - goto err; - } - } - - if ((pdd_handling >= 0) && (pdd_handling < PDD_HANDLING_NUM)) { - pdd_f = pdd_funcs[pdd_handling]; - } - else { - EBUF("Used unknown PDD handling algorithm (pdd_handling)"); - } - - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, - UBI_REMOVE, err_buf, err_buf_size); - if (rc != 0) { - goto err; - } - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, - UBI_WRITE, err_buf, err_buf_size); - if (rc != 0) { - goto err; - } - if (seqnum < 0) { /* mirror redundant pairs */ - rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, - err_buf, err_buf_size); - if (rc != 0) - goto err; - } - - 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); - bootenv_destroy(&bootenv); - return rc; -} diff --git a/ubi-utils/src/libreader/reader.c b/ubi-utils/src/libreader/reader.c deleted file mode 100644 index c8242df..0000000 --- a/ubi-utils/src/libreader/reader.c +++ /dev/null @@ -1,442 +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 -#include -#include -#include -#include - -#include "bootenv.h" -#include "reader.h" - -/* @FIXME hard coded offsets right now - get them from Artem? */ -#define NAND_DEFAULT_VID_HDR_OFF 1984 -#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) { - res->flash_type = NAND_FLASH; - res->vid_hdr_offset = NAND_DEFAULT_VID_HDR_OFF; - } - 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, 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; - - 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_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, - &(res->starts_size), &(res->starts)); - 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, 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; - - 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_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, &(res->ids_size), - &(res->ids)); - 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, &(res->names_size), - &(tmp_names)); - 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/libubi.c b/ubi-utils/src/libubi.c new file mode 100644 index 0000000..9b9a793 --- /dev/null +++ b/ubi-utils/src/libubi.c @@ -0,0 +1,773 @@ +/* + * 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. + */ + +/* + * UBI (Unsorted Block Images) library. + * + * Author: Artem B. Bityutskiy + * Oliver Lohmann + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libubi.h" +#include "libubi_int.h" +#include "libubi_sysfs.h" + +/** + * struct ubi_lib - UBI library descriptor. + * + * @ubi general UBI information + * + * @sysfs_root sysfs root directory + * @ubi_root UBI root directory in sysfs + * + * @nlen_max full path to the "maximum volume name length" sysfs file + * @version full path to the "UBI version" sysfs file + * + * @cdev_path path pattern to UBI character devices + * @cdev_path_len maximum length of the @cdev_path string after substitution + * @udev_path path to sysfs directories corresponding to UBI devices + * @wear_path path to sysfs file containing UBI wear information + * @vol_count_path path to sysfs file containing the number of volumes in an + * UBI device + * @tot_ebs_path path to sysfs file containing the total number of + * eraseblock on an UBI device + * @avail_ebs_path path to sysfs file containing the number of unused + * eraseblocks on an UBI device, available for new volumes + * @eb_size_path path to sysfs file containing size of UBI eraseblocks + * @nums_path path to sysfs file containing major and minor number of an + * UBI device + * @vol_cdev_path path to UBI volume character devices + * @vdev_path path to sysfs directories corresponding to UBI volume + * devices + * @vol_nums_path path to sysfs file containing major and minor number of an + * UBI volume device + * @vol_bytes_path path to sysfs file containing size of an UBI volume device + * in bytes + * @vol_ebs_path path to sysfs file containing the number of eraseblocks in + * an UBI volume device + * @vol_type_path path to sysfs file containing type of an UBI volume + * @vol_name_path @FIXME: Describe me. + * + * This structure is created and initialized by 'ubi_init()' and is passed to + * all UBI library calls. + */ +struct ubi_lib +{ + struct ubi_info ubi; + + char *sysfs_root; + char *ubi_root; + + char *nlen_max; + char *version; + char *cdev_path; + int cdev_path_len; + char *udev_path; + char *wear_path; + char *vol_count_path; + char *tot_ebs_path; + char *avail_ebs_path; + char *eb_size_path; + char *nums_path; + int vol_cdev_path_len; + char *vol_cdev_path; + char *vdev_path; + char *vol_nums_path; + char *vol_bytes_path; + char *vol_ebs_path; + char *vol_type_path; + char *vol_name_path; +}; + + +/** + * mkpath - compose full path from 2 given components. + * + * @path first component @name second component + * + * Returns the resulting path in case of success and %NULL in case of failure. + * Callers have to take care the resulting path is freed. + */ +static char* +mkpath(const char *path, const char *name) +{ + char *n; + int len1 = strlen(path); + int len2 = strlen(name); + + n = malloc(len1 + len2 + 2); + if (!n) + return NULL; + + memcpy(n, path, len1); + if (n[len1 - 1] != '/') + n[len1++] = '/'; + + memcpy(n + len1, name, len2 + 1); + return n; +} + + +static int +get_ubi_info(ubi_lib_t desc, struct ubi_info *ubi) +{ + int err; + int n = 1; + char *path; + struct stat stat; + + err = sysfs_read_int(desc->version, (int*) &ubi->version); + if (err) + return -1; + + err = sysfs_read_int(desc->nlen_max, (int*) &ubi->nlen_max); + if (err) + return -1; + + /* Calculate number of UBI devices */ + do { + char dir[20]; + + sprintf(&dir[0], "ubi%d", n); + path = mkpath(desc->sysfs_root, dir); + if (!path) + return ENOMEM; + + err = lstat(path, &stat); + if (err == 0) + n += 1; + free(path); + } while (err == 0); + + if (errno != ENOENT) + return -1; + + if (n == 0) { + ubi_err("no UBI devices found"); + errno = EINVAL; + return -1; + } + + errno = 0; + ubi->dev_count = n; + return 0; +} + +void +ubi_dump_handler(ubi_lib_t desc) +{ + ubi_lib_t d = desc; + printf( "UBI Library Descriptor:\n" + "ubi_root: %s\n" + "nlen_max: %s\n" + "version: %s\n" + "cdev_path: %s\n" + "udev_path: %s\n" + "wear_path: %s\n" + "vol_count_path: %s\n" + "tot_ebs_path: %s\n" + "avail_ebs_path: %s\n" + "eb_size_path: %s\n" + "nums_path: %s\n" + "vol_cdev_path: %s\n" + "vdev_path: %s\n" + "vol_nums_path: %s\n" + "vol_bytes_path: %s\n" + "vol_ebs_path: %s\n" + "vol_type_path: %s\n" + "vol_name_path: %s\n" + "cdev_path_len: %d\n\n", + d->ubi_root, d->nlen_max, d->version, d->cdev_path, + d->udev_path, d->wear_path, d->vol_count_path, + d->tot_ebs_path, d->avail_ebs_path, d->eb_size_path, + d->nums_path, d->vol_cdev_path, d->vdev_path, + d->vol_nums_path, d->vol_bytes_path, d->vol_ebs_path, + d->vol_type_path, d->vol_name_path, d->cdev_path_len); +} + +int +ubi_set_cdev_pattern(ubi_lib_t desc, const char *pattern) +{ + char *patt; + + patt = strdup(pattern); + if (!patt) { + ubi_err("cannot allocate memory"); + return -1; + } + + if (desc->cdev_path) + free(desc->cdev_path); + + desc->cdev_path = patt; + desc->cdev_path_len = strlen(patt) + 1 + UBI_MAX_ID_SIZE; + + ubi_dbg("ubi dev pattern is now \"%s\"", patt); + + return 0; +} + +int +ubi_set_vol_cdev_pattern(ubi_lib_t desc, const char *pattern) +{ + char *patt; + + patt = strdup(pattern); + if (!patt) { + ubi_err("cannot allocate memory"); + return -1; + } + + free(desc->vol_cdev_path); + desc->vol_cdev_path = patt; + desc->vol_cdev_path_len = strlen(patt) + 1 + 2 * UBI_MAX_ID_SIZE; + + ubi_dbg("ubi volume dev pattern is now \"%s\"", patt); + + return 0; +} + +int +ubi_open(ubi_lib_t *desc) +{ + int err = -1; + ubi_lib_t res; + struct stat stat; + + res = calloc(1, sizeof(struct ubi_lib)); + if (!res) { + ubi_err("cannot allocate memory"); + return -1; + } + + res->cdev_path = NULL; + err = ubi_set_cdev_pattern(res, UBI_CDEV_PATH); + if (err) + goto error; + + /* TODO: this actually has to be discovered */ + res->sysfs_root = strdup(UBI_SYSFS_ROOT); + if (!res->sysfs_root) + goto error; + + res->ubi_root = mkpath(res->sysfs_root, UBI_ROOT); + if (!res->ubi_root) + goto error; + + res->nlen_max = mkpath(res->ubi_root, UBI_NLEN_MAX); + if (!res->nlen_max) + goto error; + + res->version = mkpath(res->ubi_root, UBI_VERSION); + if (!res->version) + goto error; + + res->udev_path = mkpath(res->ubi_root, "ubi%d/"); + if (!res->udev_path) + goto error; + + res->wear_path = mkpath(res->udev_path, UBI_WEAR); + if (!res->wear_path) + goto error; + + res->vol_count_path = mkpath(res->udev_path, UBI_VOL_COUNT); + if (!res->vol_count_path) + goto error; + + res->tot_ebs_path = mkpath(res->udev_path, UBI_AVAIL_EBS); + if (!res->tot_ebs_path) + goto error; + + res->avail_ebs_path = mkpath(res->udev_path, UBI_TOT_EBS); + if (!res->avail_ebs_path) + goto error; + + res->eb_size_path = mkpath(res->udev_path, UBI_EB_SIZE); + if (!res->eb_size_path) + goto error; + + res->nums_path = mkpath(res->udev_path, UBI_NUMS); + if (!res->nums_path) + goto error; + + err = ubi_set_vol_cdev_pattern(res, UBI_VOL_CDEV_PATH); + if (err) + goto error; + + res->vdev_path = mkpath(res->udev_path, "%d/"); + if (!res->vdev_path) + goto error; + + res->vol_nums_path = mkpath(res->vdev_path, UBI_NUMS); + if (!res->vol_nums_path) + goto error; + + res->vol_bytes_path = mkpath(res->vdev_path, UBI_VBYTES); + if (!res->vol_bytes_path) + goto error; + + res->vol_ebs_path = mkpath(res->vdev_path, UBI_VEBS); + if (!res->vol_ebs_path) + goto error; + + res->vol_type_path = mkpath(res->vdev_path, UBI_VTYPE); + if (!res->vol_type_path) + goto error; + + res->vol_name_path = mkpath(res->vdev_path, UBI_VNAME); + if (!res->vol_name_path) + goto error; + + /* Check if UBI exists in the system */ + err = lstat(res->ubi_root, &stat); + if (err) { + perror("lstat"); + fprintf(stderr, "%s\n", res->ubi_root); + err = UBI_ENOTFOUND; + goto error; + } + + err = get_ubi_info(res, &res->ubi); + if (err) + goto error; + + *desc = res; + + ubi_dbg("opened library successfully."); + + return 0; + +error: + ubi_close(&res); + + if (err == -1 && errno == ENOMEM) + ubi_err("Cannot allocate memory"); + + return err; +} + +int +ubi_close(ubi_lib_t *desc) +{ + ubi_lib_t tmp = *desc; + + free(tmp->vol_name_path); + free(tmp->vol_type_path); + free(tmp->vol_ebs_path); + free(tmp->vol_bytes_path); + free(tmp->vol_nums_path); + free(tmp->vdev_path); + free(tmp->vol_cdev_path); + free(tmp->nums_path); + free(tmp->eb_size_path); + free(tmp->avail_ebs_path); + free(tmp->tot_ebs_path); + free(tmp->vol_count_path); + free(tmp->wear_path); + free(tmp->udev_path); + free(tmp->cdev_path); + free(tmp->version); + free(tmp->nlen_max); + free(tmp->ubi_root); + free(tmp->sysfs_root); + free(tmp); + + *desc = NULL; + + return 0; +} + +void +ubi_perror(const char *prefix, int code) +{ + if (code == 0) + return; + + fprintf(stderr, "%s: ", prefix); + + switch (code) { + case UBI_ENOTFOUND: + fprintf(stderr, "UBI was not found in system\n"); + break; + case UBI_EBUG: + fprintf(stderr, "an UBI or UBI library bug\n"); + break; + case UBI_EINVAL: + fprintf(stderr, "invalid parameter\n"); + break; + case -1: + perror(prefix); + break; + default: + ubi_err("unknown error code %d", code); + break; + } +} + +int +ubi_get_dev_info(ubi_lib_t desc, unsigned int devn, struct ubi_dev_info *di) +{ + int err; + + if (devn >= desc->ubi.dev_count) { + ubi_err("bad device number, max is %d\n", + desc->ubi.dev_count - 1); + return UBI_EINVAL; + } + + err = sysfs_read_dev_subst(desc->nums_path, &di->major, + &di->minor, 1, devn); + if (err) + return -1; + + err = sysfs_read_ull_subst(desc->wear_path, &di->wear, 1, devn); + if (err) + return -1; + + err = sysfs_read_uint_subst(desc->vol_count_path, + &di->vol_count, 1, devn); + if (err) + return -1; + + err = sysfs_read_uint_subst(desc->eb_size_path, &di->eb_size, 1, devn); + if (err) + return -1; + + err = sysfs_read_uint_subst(desc->tot_ebs_path, &di->total_ebs, 1, devn); + if (err) + return -1; + + err = sysfs_read_uint_subst(desc->avail_ebs_path, + &di->avail_ebs, 1, devn); + if (err) + return -1; + +#if 0 + ubi_dbg("major:minor %d:%d, wear %llu, EB size %d, " + "vol. count %d, tot. EBs %d, avail. EBs %d", + di->major, di->minor, di->wear, di->eb_size, + di->vol_count, di->total_ebs, di->avail_ebs); +#endif + + return err; +} + +int +ubi_get_vol_info(ubi_lib_t desc, unsigned int devn, unsigned int vol_id, + struct ubi_vol_info *req) +{ + int err; + int len; + char buf1[10]; + char buf2[desc->ubi.nlen_max]; + + err = sysfs_read_dev_subst(desc->vol_nums_path, &req->major, + &req->minor, 2, devn, vol_id); + if (err) + return -1; + + err = sysfs_read_ull_subst(desc->vol_bytes_path, + &req->bytes, 2, devn, vol_id); + if (err) + return -1; + + err = sysfs_read_uint_subst(desc->vol_ebs_path, + &req->eraseblocks, 2, devn, vol_id); + if (err) + return -1; + + len = sysfs_read_data_subst(desc->vol_type_path, &buf1[0], + 10, 2, devn, vol_id); + if (len == -1) + return -1; + + if (buf1[len - 1] != '\n') { + ubi_err("bad volume type"); + return UBI_EBUG; + } + + if (!strncmp(&buf1[0], "static", sizeof("static") - 1)) { + req->type = UBI_STATIC_VOLUME; + } else if (!strncmp(&buf1[0], "dynamic", sizeof("dynamic") - 1)) { + req->type = UBI_DYNAMIC_VOLUME; + } else { + ubi_err("bad type %s", &buf1[0]); + return -1; + } + + len = sysfs_read_data_subst(desc->vol_name_path, &buf2[0], + desc->ubi.nlen_max, 2, devn, vol_id); + if (len == -1) + return -1; + + if (buf2[len - 1] != '\n') { + ubi_err("bad volume name"); + return UBI_EBUG; + } + + req->name = malloc(len); + if (!req->name) { + ubi_err("cannot allocate memory"); + return -1; + } + + memcpy(req->name, &buf2[0], len - 1); + req->name[len - 1] = '\0'; + + return 0; +} + +/** + * ubi_cdev_open - open a UBI device + * + * @desc UBI library descriptor + * @devn Number of UBI device to open + * @flags Flags to pass to open() + * + * This function opens a UBI device by number and returns a file + * descriptor. In case of an error %-1 is returned and errno is set + * appropriately. + */ +static int +ubi_cdev_open(ubi_lib_t desc, int devn, int flags) +{ + char *buf; + int fd; + + ubi_dbg("desc=%p, devn=%d, flags=%08x\n", desc, devn, flags); + + if (desc == NULL) { + ubi_err("desc is NULL\n"); + return -1; + } + if (desc->vol_cdev_path_len == 0) { + ubi_err("path_len == 0\n"); + return -1; + } + buf = malloc(desc->cdev_path_len); + + sprintf(buf, desc->cdev_path, devn); + + fd = open(buf, flags); + if (fd == -1) + ubi_dbg("cannot open %s", buf); + + free(buf); + return fd; +} + +/** + * ubi_cdev_close - close a UBI device + * + * @dev_fd file descriptor of UBI device to close + * + * This function closes the given UBI device. + */ +static int +ubi_cdev_close(int dev_fd) +{ + return close(dev_fd); +} + +/** + * @size is now in bytes. + */ +int +ubi_mkvol(ubi_lib_t desc, int devn, int vol_id, int vol_type, + long long bytes, int alignment, const char *name) +{ + int fd; + int err; + struct ubi_mkvol_req req; + + if ((fd = ubi_cdev_open(desc, devn, O_RDWR)) == -1) + return -1; + + req.vol_id = vol_id; + req.bytes = bytes; + req.vol_type = vol_type; + req.alignment = alignment; + req.name_len = strlen(name); + req.name = name; + + /* printf("DBG: %s(vol_id=%d, bytes=%lld, type=%d, alig=%d, nlen=%d, " + "name=%s)\n", __func__, vol_id, bytes, vol_type, alignment, + strlen(name), name);*/ + + err = ioctl(fd, UBI_IOCMKVOL, &req); + if (err < 0) { + ubi_err("ioctl returned %d errno=%d\n", err, errno); + goto out_close; + } + + ubi_dbg("created volume %d, size %lld, name \"%s\" " + "at UBI dev %d\n", vol_id, bytes, name, devn); + + close(fd); + return err; + out_close: + ubi_cdev_close(fd); + return err; +} + +int +ubi_rmvol(ubi_lib_t desc, int devn, int vol_id) +{ + int fd; + int err; + + if ((fd = ubi_cdev_open(desc, devn, O_RDWR)) == -1) + return -1; + + err = ioctl(fd, UBI_IOCRMVOL, &vol_id); + if (err < 0) + goto out_close; + + ubi_dbg("removed volume %d", vol_id); + + out_close: + ubi_cdev_close(fd); + return err; +} + +int +ubi_get_info(ubi_lib_t desc, struct ubi_info *ubi) +{ + memcpy(ubi, &desc->ubi, sizeof(struct ubi_info)); + return 0; +} + + +int +ubi_vol_open(ubi_lib_t desc, int devn, int vol_id, int flags) +{ + char *buf; + int fd; + + ubi_dbg("desc=%p, devn=%d, vol_id=%d, flags=%08x\n", + desc, devn, vol_id, flags); + + if (desc == NULL) { + ubi_err("desc is NULL\n"); + return -1; + } + if (desc->vol_cdev_path_len == 0) { + ubi_err("path_len == 0\n"); + return -1; + } + buf = malloc(desc->cdev_path_len); + + sprintf(buf, desc->vol_cdev_path, devn, vol_id); + + fd = open(buf, flags); + if (fd == -1) + ubi_dbg("cannot open %s", buf); + + free(buf); + return fd; +} + +int +ubi_vol_close(int vol_fd) +{ + return close(vol_fd); +} + + +int +ubi_vol_update(int vol_fd, unsigned long long bytes) +{ + int err; + + err = ioctl(vol_fd, UBI_IOCVOLUP, &bytes); + if (err) { + ubi_err("%s failure calling update ioctl\n" + " IOCTL(%08x) err=%d errno=%d\n", + __func__, UBI_IOCVOLUP, err, errno); + } + return err; +} + +FILE * +ubi_vol_fopen_read(ubi_lib_t desc, int devn, uint32_t vol_id) +{ + FILE *fp; + int fd; + + fd = ubi_vol_open(desc, devn, vol_id, O_RDONLY); + if (fd == -1) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + ubi_vol_close(fd); + + return fp; +} + +FILE * +ubi_vol_fopen_update(ubi_lib_t desc, int devn, uint32_t vol_id, + unsigned long long bytes) +{ + FILE *fp; + int fd; + int err; + + fd = ubi_vol_open(desc, devn, vol_id, O_RDWR); + if (fd == -1) + return NULL; + + fp = fdopen(fd, "r+"); + if (fp == NULL) { + printf("DBG: %s(errno=%d)\n", __func__, errno); + ubi_vol_close(fd); + return NULL; + } + err = ubi_vol_update(fd, bytes); + if (err < 0) { + printf("DBG: %s() fd=%d err=%d\n", __func__, fd, err); + fclose(fp); + return NULL; + } + return fp; +} + +int +ubi_vol_get_used_bytes(int vol_fd, unsigned long long *bytes) +{ + off_t res; + + res = lseek(vol_fd, 0, SEEK_END); + if (res == (off_t)-1) + return -1; + *bytes = (unsigned long long) res; + res = lseek(vol_fd, 0, SEEK_SET); + return res == (off_t)-1 ? -1 : 0; +} diff --git a/ubi-utils/src/libubi/libubi.c b/ubi-utils/src/libubi/libubi.c deleted file mode 100644 index 9b9a793..0000000 --- a/ubi-utils/src/libubi/libubi.c +++ /dev/null @@ -1,773 +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. - */ - -/* - * UBI (Unsorted Block Images) library. - * - * Author: Artem B. Bityutskiy - * Oliver Lohmann - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libubi.h" -#include "libubi_int.h" -#include "libubi_sysfs.h" - -/** - * struct ubi_lib - UBI library descriptor. - * - * @ubi general UBI information - * - * @sysfs_root sysfs root directory - * @ubi_root UBI root directory in sysfs - * - * @nlen_max full path to the "maximum volume name length" sysfs file - * @version full path to the "UBI version" sysfs file - * - * @cdev_path path pattern to UBI character devices - * @cdev_path_len maximum length of the @cdev_path string after substitution - * @udev_path path to sysfs directories corresponding to UBI devices - * @wear_path path to sysfs file containing UBI wear information - * @vol_count_path path to sysfs file containing the number of volumes in an - * UBI device - * @tot_ebs_path path to sysfs file containing the total number of - * eraseblock on an UBI device - * @avail_ebs_path path to sysfs file containing the number of unused - * eraseblocks on an UBI device, available for new volumes - * @eb_size_path path to sysfs file containing size of UBI eraseblocks - * @nums_path path to sysfs file containing major and minor number of an - * UBI device - * @vol_cdev_path path to UBI volume character devices - * @vdev_path path to sysfs directories corresponding to UBI volume - * devices - * @vol_nums_path path to sysfs file containing major and minor number of an - * UBI volume device - * @vol_bytes_path path to sysfs file containing size of an UBI volume device - * in bytes - * @vol_ebs_path path to sysfs file containing the number of eraseblocks in - * an UBI volume device - * @vol_type_path path to sysfs file containing type of an UBI volume - * @vol_name_path @FIXME: Describe me. - * - * This structure is created and initialized by 'ubi_init()' and is passed to - * all UBI library calls. - */ -struct ubi_lib -{ - struct ubi_info ubi; - - char *sysfs_root; - char *ubi_root; - - char *nlen_max; - char *version; - char *cdev_path; - int cdev_path_len; - char *udev_path; - char *wear_path; - char *vol_count_path; - char *tot_ebs_path; - char *avail_ebs_path; - char *eb_size_path; - char *nums_path; - int vol_cdev_path_len; - char *vol_cdev_path; - char *vdev_path; - char *vol_nums_path; - char *vol_bytes_path; - char *vol_ebs_path; - char *vol_type_path; - char *vol_name_path; -}; - - -/** - * mkpath - compose full path from 2 given components. - * - * @path first component @name second component - * - * Returns the resulting path in case of success and %NULL in case of failure. - * Callers have to take care the resulting path is freed. - */ -static char* -mkpath(const char *path, const char *name) -{ - char *n; - int len1 = strlen(path); - int len2 = strlen(name); - - n = malloc(len1 + len2 + 2); - if (!n) - return NULL; - - memcpy(n, path, len1); - if (n[len1 - 1] != '/') - n[len1++] = '/'; - - memcpy(n + len1, name, len2 + 1); - return n; -} - - -static int -get_ubi_info(ubi_lib_t desc, struct ubi_info *ubi) -{ - int err; - int n = 1; - char *path; - struct stat stat; - - err = sysfs_read_int(desc->version, (int*) &ubi->version); - if (err) - return -1; - - err = sysfs_read_int(desc->nlen_max, (int*) &ubi->nlen_max); - if (err) - return -1; - - /* Calculate number of UBI devices */ - do { - char dir[20]; - - sprintf(&dir[0], "ubi%d", n); - path = mkpath(desc->sysfs_root, dir); - if (!path) - return ENOMEM; - - err = lstat(path, &stat); - if (err == 0) - n += 1; - free(path); - } while (err == 0); - - if (errno != ENOENT) - return -1; - - if (n == 0) { - ubi_err("no UBI devices found"); - errno = EINVAL; - return -1; - } - - errno = 0; - ubi->dev_count = n; - return 0; -} - -void -ubi_dump_handler(ubi_lib_t desc) -{ - ubi_lib_t d = desc; - printf( "UBI Library Descriptor:\n" - "ubi_root: %s\n" - "nlen_max: %s\n" - "version: %s\n" - "cdev_path: %s\n" - "udev_path: %s\n" - "wear_path: %s\n" - "vol_count_path: %s\n" - "tot_ebs_path: %s\n" - "avail_ebs_path: %s\n" - "eb_size_path: %s\n" - "nums_path: %s\n" - "vol_cdev_path: %s\n" - "vdev_path: %s\n" - "vol_nums_path: %s\n" - "vol_bytes_path: %s\n" - "vol_ebs_path: %s\n" - "vol_type_path: %s\n" - "vol_name_path: %s\n" - "cdev_path_len: %d\n\n", - d->ubi_root, d->nlen_max, d->version, d->cdev_path, - d->udev_path, d->wear_path, d->vol_count_path, - d->tot_ebs_path, d->avail_ebs_path, d->eb_size_path, - d->nums_path, d->vol_cdev_path, d->vdev_path, - d->vol_nums_path, d->vol_bytes_path, d->vol_ebs_path, - d->vol_type_path, d->vol_name_path, d->cdev_path_len); -} - -int -ubi_set_cdev_pattern(ubi_lib_t desc, const char *pattern) -{ - char *patt; - - patt = strdup(pattern); - if (!patt) { - ubi_err("cannot allocate memory"); - return -1; - } - - if (desc->cdev_path) - free(desc->cdev_path); - - desc->cdev_path = patt; - desc->cdev_path_len = strlen(patt) + 1 + UBI_MAX_ID_SIZE; - - ubi_dbg("ubi dev pattern is now \"%s\"", patt); - - return 0; -} - -int -ubi_set_vol_cdev_pattern(ubi_lib_t desc, const char *pattern) -{ - char *patt; - - patt = strdup(pattern); - if (!patt) { - ubi_err("cannot allocate memory"); - return -1; - } - - free(desc->vol_cdev_path); - desc->vol_cdev_path = patt; - desc->vol_cdev_path_len = strlen(patt) + 1 + 2 * UBI_MAX_ID_SIZE; - - ubi_dbg("ubi volume dev pattern is now \"%s\"", patt); - - return 0; -} - -int -ubi_open(ubi_lib_t *desc) -{ - int err = -1; - ubi_lib_t res; - struct stat stat; - - res = calloc(1, sizeof(struct ubi_lib)); - if (!res) { - ubi_err("cannot allocate memory"); - return -1; - } - - res->cdev_path = NULL; - err = ubi_set_cdev_pattern(res, UBI_CDEV_PATH); - if (err) - goto error; - - /* TODO: this actually has to be discovered */ - res->sysfs_root = strdup(UBI_SYSFS_ROOT); - if (!res->sysfs_root) - goto error; - - res->ubi_root = mkpath(res->sysfs_root, UBI_ROOT); - if (!res->ubi_root) - goto error; - - res->nlen_max = mkpath(res->ubi_root, UBI_NLEN_MAX); - if (!res->nlen_max) - goto error; - - res->version = mkpath(res->ubi_root, UBI_VERSION); - if (!res->version) - goto error; - - res->udev_path = mkpath(res->ubi_root, "ubi%d/"); - if (!res->udev_path) - goto error; - - res->wear_path = mkpath(res->udev_path, UBI_WEAR); - if (!res->wear_path) - goto error; - - res->vol_count_path = mkpath(res->udev_path, UBI_VOL_COUNT); - if (!res->vol_count_path) - goto error; - - res->tot_ebs_path = mkpath(res->udev_path, UBI_AVAIL_EBS); - if (!res->tot_ebs_path) - goto error; - - res->avail_ebs_path = mkpath(res->udev_path, UBI_TOT_EBS); - if (!res->avail_ebs_path) - goto error; - - res->eb_size_path = mkpath(res->udev_path, UBI_EB_SIZE); - if (!res->eb_size_path) - goto error; - - res->nums_path = mkpath(res->udev_path, UBI_NUMS); - if (!res->nums_path) - goto error; - - err = ubi_set_vol_cdev_pattern(res, UBI_VOL_CDEV_PATH); - if (err) - goto error; - - res->vdev_path = mkpath(res->udev_path, "%d/"); - if (!res->vdev_path) - goto error; - - res->vol_nums_path = mkpath(res->vdev_path, UBI_NUMS); - if (!res->vol_nums_path) - goto error; - - res->vol_bytes_path = mkpath(res->vdev_path, UBI_VBYTES); - if (!res->vol_bytes_path) - goto error; - - res->vol_ebs_path = mkpath(res->vdev_path, UBI_VEBS); - if (!res->vol_ebs_path) - goto error; - - res->vol_type_path = mkpath(res->vdev_path, UBI_VTYPE); - if (!res->vol_type_path) - goto error; - - res->vol_name_path = mkpath(res->vdev_path, UBI_VNAME); - if (!res->vol_name_path) - goto error; - - /* Check if UBI exists in the system */ - err = lstat(res->ubi_root, &stat); - if (err) { - perror("lstat"); - fprintf(stderr, "%s\n", res->ubi_root); - err = UBI_ENOTFOUND; - goto error; - } - - err = get_ubi_info(res, &res->ubi); - if (err) - goto error; - - *desc = res; - - ubi_dbg("opened library successfully."); - - return 0; - -error: - ubi_close(&res); - - if (err == -1 && errno == ENOMEM) - ubi_err("Cannot allocate memory"); - - return err; -} - -int -ubi_close(ubi_lib_t *desc) -{ - ubi_lib_t tmp = *desc; - - free(tmp->vol_name_path); - free(tmp->vol_type_path); - free(tmp->vol_ebs_path); - free(tmp->vol_bytes_path); - free(tmp->vol_nums_path); - free(tmp->vdev_path); - free(tmp->vol_cdev_path); - free(tmp->nums_path); - free(tmp->eb_size_path); - free(tmp->avail_ebs_path); - free(tmp->tot_ebs_path); - free(tmp->vol_count_path); - free(tmp->wear_path); - free(tmp->udev_path); - free(tmp->cdev_path); - free(tmp->version); - free(tmp->nlen_max); - free(tmp->ubi_root); - free(tmp->sysfs_root); - free(tmp); - - *desc = NULL; - - return 0; -} - -void -ubi_perror(const char *prefix, int code) -{ - if (code == 0) - return; - - fprintf(stderr, "%s: ", prefix); - - switch (code) { - case UBI_ENOTFOUND: - fprintf(stderr, "UBI was not found in system\n"); - break; - case UBI_EBUG: - fprintf(stderr, "an UBI or UBI library bug\n"); - break; - case UBI_EINVAL: - fprintf(stderr, "invalid parameter\n"); - break; - case -1: - perror(prefix); - break; - default: - ubi_err("unknown error code %d", code); - break; - } -} - -int -ubi_get_dev_info(ubi_lib_t desc, unsigned int devn, struct ubi_dev_info *di) -{ - int err; - - if (devn >= desc->ubi.dev_count) { - ubi_err("bad device number, max is %d\n", - desc->ubi.dev_count - 1); - return UBI_EINVAL; - } - - err = sysfs_read_dev_subst(desc->nums_path, &di->major, - &di->minor, 1, devn); - if (err) - return -1; - - err = sysfs_read_ull_subst(desc->wear_path, &di->wear, 1, devn); - if (err) - return -1; - - err = sysfs_read_uint_subst(desc->vol_count_path, - &di->vol_count, 1, devn); - if (err) - return -1; - - err = sysfs_read_uint_subst(desc->eb_size_path, &di->eb_size, 1, devn); - if (err) - return -1; - - err = sysfs_read_uint_subst(desc->tot_ebs_path, &di->total_ebs, 1, devn); - if (err) - return -1; - - err = sysfs_read_uint_subst(desc->avail_ebs_path, - &di->avail_ebs, 1, devn); - if (err) - return -1; - -#if 0 - ubi_dbg("major:minor %d:%d, wear %llu, EB size %d, " - "vol. count %d, tot. EBs %d, avail. EBs %d", - di->major, di->minor, di->wear, di->eb_size, - di->vol_count, di->total_ebs, di->avail_ebs); -#endif - - return err; -} - -int -ubi_get_vol_info(ubi_lib_t desc, unsigned int devn, unsigned int vol_id, - struct ubi_vol_info *req) -{ - int err; - int len; - char buf1[10]; - char buf2[desc->ubi.nlen_max]; - - err = sysfs_read_dev_subst(desc->vol_nums_path, &req->major, - &req->minor, 2, devn, vol_id); - if (err) - return -1; - - err = sysfs_read_ull_subst(desc->vol_bytes_path, - &req->bytes, 2, devn, vol_id); - if (err) - return -1; - - err = sysfs_read_uint_subst(desc->vol_ebs_path, - &req->eraseblocks, 2, devn, vol_id); - if (err) - return -1; - - len = sysfs_read_data_subst(desc->vol_type_path, &buf1[0], - 10, 2, devn, vol_id); - if (len == -1) - return -1; - - if (buf1[len - 1] != '\n') { - ubi_err("bad volume type"); - return UBI_EBUG; - } - - if (!strncmp(&buf1[0], "static", sizeof("static") - 1)) { - req->type = UBI_STATIC_VOLUME; - } else if (!strncmp(&buf1[0], "dynamic", sizeof("dynamic") - 1)) { - req->type = UBI_DYNAMIC_VOLUME; - } else { - ubi_err("bad type %s", &buf1[0]); - return -1; - } - - len = sysfs_read_data_subst(desc->vol_name_path, &buf2[0], - desc->ubi.nlen_max, 2, devn, vol_id); - if (len == -1) - return -1; - - if (buf2[len - 1] != '\n') { - ubi_err("bad volume name"); - return UBI_EBUG; - } - - req->name = malloc(len); - if (!req->name) { - ubi_err("cannot allocate memory"); - return -1; - } - - memcpy(req->name, &buf2[0], len - 1); - req->name[len - 1] = '\0'; - - return 0; -} - -/** - * ubi_cdev_open - open a UBI device - * - * @desc UBI library descriptor - * @devn Number of UBI device to open - * @flags Flags to pass to open() - * - * This function opens a UBI device by number and returns a file - * descriptor. In case of an error %-1 is returned and errno is set - * appropriately. - */ -static int -ubi_cdev_open(ubi_lib_t desc, int devn, int flags) -{ - char *buf; - int fd; - - ubi_dbg("desc=%p, devn=%d, flags=%08x\n", desc, devn, flags); - - if (desc == NULL) { - ubi_err("desc is NULL\n"); - return -1; - } - if (desc->vol_cdev_path_len == 0) { - ubi_err("path_len == 0\n"); - return -1; - } - buf = malloc(desc->cdev_path_len); - - sprintf(buf, desc->cdev_path, devn); - - fd = open(buf, flags); - if (fd == -1) - ubi_dbg("cannot open %s", buf); - - free(buf); - return fd; -} - -/** - * ubi_cdev_close - close a UBI device - * - * @dev_fd file descriptor of UBI device to close - * - * This function closes the given UBI device. - */ -static int -ubi_cdev_close(int dev_fd) -{ - return close(dev_fd); -} - -/** - * @size is now in bytes. - */ -int -ubi_mkvol(ubi_lib_t desc, int devn, int vol_id, int vol_type, - long long bytes, int alignment, const char *name) -{ - int fd; - int err; - struct ubi_mkvol_req req; - - if ((fd = ubi_cdev_open(desc, devn, O_RDWR)) == -1) - return -1; - - req.vol_id = vol_id; - req.bytes = bytes; - req.vol_type = vol_type; - req.alignment = alignment; - req.name_len = strlen(name); - req.name = name; - - /* printf("DBG: %s(vol_id=%d, bytes=%lld, type=%d, alig=%d, nlen=%d, " - "name=%s)\n", __func__, vol_id, bytes, vol_type, alignment, - strlen(name), name);*/ - - err = ioctl(fd, UBI_IOCMKVOL, &req); - if (err < 0) { - ubi_err("ioctl returned %d errno=%d\n", err, errno); - goto out_close; - } - - ubi_dbg("created volume %d, size %lld, name \"%s\" " - "at UBI dev %d\n", vol_id, bytes, name, devn); - - close(fd); - return err; - out_close: - ubi_cdev_close(fd); - return err; -} - -int -ubi_rmvol(ubi_lib_t desc, int devn, int vol_id) -{ - int fd; - int err; - - if ((fd = ubi_cdev_open(desc, devn, O_RDWR)) == -1) - return -1; - - err = ioctl(fd, UBI_IOCRMVOL, &vol_id); - if (err < 0) - goto out_close; - - ubi_dbg("removed volume %d", vol_id); - - out_close: - ubi_cdev_close(fd); - return err; -} - -int -ubi_get_info(ubi_lib_t desc, struct ubi_info *ubi) -{ - memcpy(ubi, &desc->ubi, sizeof(struct ubi_info)); - return 0; -} - - -int -ubi_vol_open(ubi_lib_t desc, int devn, int vol_id, int flags) -{ - char *buf; - int fd; - - ubi_dbg("desc=%p, devn=%d, vol_id=%d, flags=%08x\n", - desc, devn, vol_id, flags); - - if (desc == NULL) { - ubi_err("desc is NULL\n"); - return -1; - } - if (desc->vol_cdev_path_len == 0) { - ubi_err("path_len == 0\n"); - return -1; - } - buf = malloc(desc->cdev_path_len); - - sprintf(buf, desc->vol_cdev_path, devn, vol_id); - - fd = open(buf, flags); - if (fd == -1) - ubi_dbg("cannot open %s", buf); - - free(buf); - return fd; -} - -int -ubi_vol_close(int vol_fd) -{ - return close(vol_fd); -} - - -int -ubi_vol_update(int vol_fd, unsigned long long bytes) -{ - int err; - - err = ioctl(vol_fd, UBI_IOCVOLUP, &bytes); - if (err) { - ubi_err("%s failure calling update ioctl\n" - " IOCTL(%08x) err=%d errno=%d\n", - __func__, UBI_IOCVOLUP, err, errno); - } - return err; -} - -FILE * -ubi_vol_fopen_read(ubi_lib_t desc, int devn, uint32_t vol_id) -{ - FILE *fp; - int fd; - - fd = ubi_vol_open(desc, devn, vol_id, O_RDONLY); - if (fd == -1) - return NULL; - - fp = fdopen(fd, "r"); - if (fp == NULL) - ubi_vol_close(fd); - - return fp; -} - -FILE * -ubi_vol_fopen_update(ubi_lib_t desc, int devn, uint32_t vol_id, - unsigned long long bytes) -{ - FILE *fp; - int fd; - int err; - - fd = ubi_vol_open(desc, devn, vol_id, O_RDWR); - if (fd == -1) - return NULL; - - fp = fdopen(fd, "r+"); - if (fp == NULL) { - printf("DBG: %s(errno=%d)\n", __func__, errno); - ubi_vol_close(fd); - return NULL; - } - err = ubi_vol_update(fd, bytes); - if (err < 0) { - printf("DBG: %s() fd=%d err=%d\n", __func__, fd, err); - fclose(fp); - return NULL; - } - return fp; -} - -int -ubi_vol_get_used_bytes(int vol_fd, unsigned long long *bytes) -{ - off_t res; - - res = lseek(vol_fd, 0, SEEK_END); - if (res == (off_t)-1) - return -1; - *bytes = (unsigned long long) res; - res = lseek(vol_fd, 0, SEEK_SET); - return res == (off_t)-1 ? -1 : 0; -} diff --git a/ubi-utils/src/libubi/libubi_int.h b/ubi-utils/src/libubi/libubi_int.h deleted file mode 100644 index 1640010..0000000 --- a/ubi-utils/src/libubi/libubi_int.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef __UBI_INT_H__ -#define __UBI_INT_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. - */ - -/* - * UBI (Unsorted Block Images) library. - * - * Author: Artem B. Bityutskiy - */ - -/* - * Enable/disable UBI library debugging messages. - */ -#undef UBILIB_DEBUG - -/* - * UBI library error message. - */ -#define ubi_err(fmt, ...) do { \ - fprintf(stderr, "UBI Library Error at %s: ", __func__); \ - fprintf(stderr, fmt, ##__VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } while(0) - -#ifdef UBILIB_DEBUG -#define ubi_dbg(fmt, ...) do { \ - fprintf(stderr, "UBI Debug: %s: ", __func__); \ - fprintf(stderr, fmt, ##__VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } while(0) - -#else -#define ubi_dbg(fmt, ...) -#endif - -/** - * SYSFS Entries. - * - * @def UBI_ROOT - * @brief Name of the root UBI directory in sysfs. - * - * @def UBI_NLEN_MAX - * @brief Name of syfs file containing the maximum UBI volume name length. - * - * @def UBI_VERSION - * @brief Name of sysfs file containing UBI version. - * - * @def UBI_WEAR - * @brief Name of sysfs file containing wear level of an UBI device. - * - * @def UBI_VOL_COUNT - * @brief Name of sysfs file contaning the of volume on an UBI device - * - * @def UBI_TOT_EBS - * @brief Name of sysfs file contaning the total number of - * eraseblocks on an UBI device. - * - * @def UBI_AVAIL_EBS - * @brief Name of sysfs file contaning the number of unused eraseblocks on - * an UBI device. - * - * @def UBI_EB_SIZE - * @brief Name of sysfs file containing size of UBI eraseblocks. - * - * @def UBI_NUMS - * @brief Name of sysfs file containing major and minor numbers - * of an UBI device or an UBI volume device. - * - * @def UBI_VBYTES - * @brief Name of sysfs file containing size of an UBI volume device in - * bytes. - * - * @def UBI_VEBS - * @brief Name of sysfs file containing size of an UBI volume device in - * eraseblocks. - * - * @def UBI_VTYPE - * @brief Name of sysfs file containing type of an UBI volume device. - * - * @def UBI_VNAME - * @brief Name of sysfs file containing name of an UBI volume device. - **/ -#define UBI_ROOT "ubi" -#define UBI_NLEN_MAX "volume_name_max" -#define UBI_VERSION "version" -#define UBI_WEAR "wear" -#define UBI_VOL_COUNT "volumes_count" -#define UBI_TOT_EBS "total_eraseblocks" -#define UBI_AVAIL_EBS "avail_eraseblocks" -#define UBI_EB_SIZE "eraseblock_size" -#define UBI_NUMS "dev" -#define UBI_VBYTES "bytes" -#define UBI_VEBS "eraseblocks" -#define UBI_VTYPE "type" -#define UBI_VNAME "name" - -#define UBI_CDEV_PATH "/dev/ubi%d" -#define UBI_VOL_CDEV_PATH "/dev/ubi%d_%d" -#define UBI_SYSFS_ROOT "/sys/class" - -#define UBI_MAX_ID_SIZE 9 - -#endif /* !__UBI_INT_H__ */ diff --git a/ubi-utils/src/libubi/libubi_sysfs.c b/ubi-utils/src/libubi/libubi_sysfs.c deleted file mode 100644 index f7ecebc..0000000 --- a/ubi-utils/src/libubi/libubi_sysfs.c +++ /dev/null @@ -1,231 +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. - */ - -/* - * UBI (Unsorted Block Images) library. - * - * Author: Artem B. Bityutskiy - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libubi_int.h" - -int -sysfs_read_data(const char *file, void *buf, int len) -{ - int fd; - ssize_t rd; - - fd = open(file, O_RDONLY); - if (fd == -1) { - ubi_err("cannot open file %s", file); - return -1; - } - - rd = read(fd, buf, len); - if (rd == -1) - ubi_err("cannot read file %s", file); - - close(fd); - - return rd; -} - -int -sysfs_read_data_subst(const char *patt, void *buf, int len, int n, ...) -{ - va_list args; - char buf1[strlen(patt) + 20 * n]; - - va_start(args, n); - vsprintf(&buf1[0], patt, args); - va_end(args); - - return sysfs_read_data(&buf1[0], buf, len); -} - -int -sysfs_read_dev(const char *file, unsigned int *major, unsigned int *minor) -{ - int fd; - int ret; - ssize_t rd; - int err = -1; - char buf[40]; - - fd = open(file, O_RDONLY); - if (fd == -1) { - ubi_err("cannot open file %s", file); - return -1; - } - - rd = read(fd, &buf[0], 20); - if (rd == -1) { - ubi_err("cannot read file %s", file); - goto error; - } - if (rd < 4) { - ubi_err("bad contents of file %s:", file); - goto error; - } - - err = -1; - if (buf[rd -1] != '\n') { - ubi_err("bad contents of file %s", file); - goto error; - } - - ret = sscanf(&buf[0], "%d:%d\n", major, minor); - if (ret != 2) { - ubi_err("bad contents of file %s", file); - goto error; - } - - err = 0; - -error: - close(fd); - - return err; -} - -int -sysfs_read_dev_subst(const char *patt, unsigned int *major, - unsigned int *minor, int n, ...) -{ - va_list args; - char buf[strlen(patt) + 20 * n]; - - va_start(args, n); - vsprintf(&buf[0], patt, args); - va_end(args); - - return sysfs_read_dev(&buf[0], major, minor); -} - -static int -sysfs_read_ull(const char *file, unsigned long long *num) -{ - return 0; -} - -int -sysfs_read_ull_subst(const char *patt, unsigned long long *num, int n, ...) -{ - va_list args; - char buf[strlen(patt) + 20 * n]; - - va_start(args, n); - vsprintf(&buf[0], patt, args); - va_end(args); - - return sysfs_read_ull(&buf[0], num); -} - -static int -sysfs_read_uint(const char *file, unsigned int *num) -{ - return 0; -} - -int -sysfs_read_uint_subst(const char *patt, unsigned int *num, int n, ...) -{ - va_list args; - char buf[strlen(patt) + 20 * n]; - - va_start(args, n); - vsprintf(&buf[0], patt, args); - va_end(args); - - return sysfs_read_uint(&buf[0], num); -} - -int -sysfs_read_ll(const char *file, long long *num) -{ - int fd; - ssize_t rd; - int err = -1; - char buf[20]; - char *endptr; - - fd = open(file, O_RDONLY); - if (fd == -1) - return -1; - - rd = read(fd, &buf[0], 20); - if (rd == -1) - goto out; - - if (rd < 2) { - ubi_err("bad contents in file %s: \"%c%c...\"", - file, buf[0], buf[1]); - goto out_errno; - } - - *num = strtoll(&buf[0], &endptr, 10); - if (endptr == &buf[0] || *endptr != '\n') { - ubi_err("bad contents in file %s: \"%c%c...\"", - file, buf[0], buf[1]); - goto out_errno; - } - - if (*num < 0) { - ubi_err("bad number in file %s: %lld", file, *num); - goto out_errno; - } - - err = 0; - -out_errno: - errno = EINVAL; - -out: - close(fd); - return err; -} - -int -sysfs_read_int(const char *file, int *num) -{ - int err; - long long res = 0; - - err = sysfs_read_ll(file, &res); - if (err) - return err; - - if (res < 0 || res > INT_MAX) { - ubi_err("bad number in file %s: %lld", file, res); - errno = EINVAL; - return -1; - } - - *num = res; - return 0; -} diff --git a/ubi-utils/src/libubi/libubi_sysfs.h b/ubi-utils/src/libubi/libubi_sysfs.h deleted file mode 100644 index 2fb6072..0000000 --- a/ubi-utils/src/libubi/libubi_sysfs.h +++ /dev/null @@ -1,109 +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. - */ - -/* - * UBI (Unsorted Block Images) library. - * - * Author: Artem B. Bityutskiy - */ - -/** - * sysfs_read_data - read data from a sysfs file. - * - * @file path to the file to read from - * @buf furrer where to store read data - * @len length of provided buffer @buf - * - * This function returns the number of read bytes or -1 in case of error. - */ -int sysfs_read_data(const char *file, void *buf, int len); - -/** - * sysfs_read_data_subst - form path to a sysfs file and read data from it. - * - * @patt path to the file to read from - * @buf furrer where to store read data - * @len length of provided buffer @buf - * @n number of parameters to substitute to @patt - * - * This function forms path to a sysfs file by means of substituting parameters - * to @patt and then reads @len bytes from this file and stores the read data - * to @buf. This function returns the number of read bytes or -1 in case of - * error. - */ -int sysfs_read_data_subst(const char *patt, void *buf, int len, int n, ...); - -/** - * sysfs_read_dev - read major and minor number from a sysfs file. - * - * @file path to the file to read from - * @major major number is returned here - * @minor minor number is returned here - */ -int sysfs_read_dev(const char *file, unsigned int *major, - unsigned int *minor); -/** - * sysfs_read_dev_subst - for path to a file and read major and minor number - * from it. - * - * @patt pattern of the path to the file to read from - * @major major number is returned here - * @minor minor number is returned here - * @n number of arguments to substitute - * - * This function substitures arguments to the @patt file path pattern and reads - * major and minor numbers from the resulting file. - */ -int sysfs_read_dev_subst(const char *patt, unsigned int *major, - unsigned int *minor, int n, ...); - -/** - * sysfs_read_ull_subst - form path to a sysfs file and read an unsigned long - * long value from there. - * - * @patt pattern of file path - * @num the read value is returned here - * @n number of parameters to substitute - * - * - * This function first forms the path to a sysfs file by means of substituting - * passed parameters to the @patt string, and then read an 'unsigned long long' - * value from this file. - */ -int sysfs_read_ull_subst(const char *patt, unsigned long long *num, - int n, ...); - -/** - * sysfs_read_uint_subst - the same as 'sysfs_read_uint_subst()' but reads an - * unsigned int value. - */ -int sysfs_read_uint_subst(const char *patt, unsigned int *num, - int n, ...); - -/** - * sysfs_read_ll - read a long long integer from an UBI sysfs file. - * - * @file file name from where to read - * @num the result is returned here - */ -int sysfs_read_ll(const char *file, long long *num); - -/** - * sysfs_read_int - the same as 'sysfs_read_ll()' but reads an 'int' value. - */ -int sysfs_read_int(const char *file, int *num); diff --git a/ubi-utils/src/libubi_int.h b/ubi-utils/src/libubi_int.h new file mode 100644 index 0000000..ab387f5 --- /dev/null +++ b/ubi-utils/src/libubi_int.h @@ -0,0 +1,119 @@ +#ifndef __UBI_INT_H__ +#define __UBI_INT_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. + */ + +/* + * UBI (Unsorted Block Images) library. + * + * Author: Artem B. Bityutskiy + */ + +/* + * Enable/disable UBI library debugging messages. + */ +#undef UBILIB_DEBUG + +/* + * UBI library error message. + */ +#define ubi_err(fmt, ...) do { \ + fprintf(stderr, "UBI Library Error at %s: ", __func__); \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } while (0) + +#ifdef UBILIB_DEBUG +#define ubi_dbg(fmt, ...) do { \ + fprintf(stderr, "UBI Debug: %s: ", __func__); \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } while (0) + +#else +#define ubi_dbg(fmt, ...) do { } while (0) +#endif + +/** + * SYSFS Entries. + * + * @def UBI_ROOT + * @brief Name of the root UBI directory in sysfs. + * + * @def UBI_NLEN_MAX + * @brief Name of syfs file containing the maximum UBI volume name length. + * + * @def UBI_VERSION + * @brief Name of sysfs file containing UBI version. + * + * @def UBI_WEAR + * @brief Name of sysfs file containing wear level of an UBI device. + * + * @def UBI_VOL_COUNT + * @brief Name of sysfs file contaning the of volume on an UBI device + * + * @def UBI_TOT_EBS + * @brief Name of sysfs file contaning the total number of + * eraseblocks on an UBI device. + * + * @def UBI_AVAIL_EBS + * @brief Name of sysfs file contaning the number of unused eraseblocks on + * an UBI device. + * + * @def UBI_EB_SIZE + * @brief Name of sysfs file containing size of UBI eraseblocks. + * + * @def UBI_NUMS + * @brief Name of sysfs file containing major and minor numbers + * of an UBI device or an UBI volume device. + * + * @def UBI_VBYTES + * @brief Name of sysfs file containing size of an UBI volume device in + * bytes. + * + * @def UBI_VEBS + * @brief Name of sysfs file containing size of an UBI volume device in + * eraseblocks. + * + * @def UBI_VTYPE + * @brief Name of sysfs file containing type of an UBI volume device. + * + * @def UBI_VNAME + * @brief Name of sysfs file containing name of an UBI volume device. + **/ +#define UBI_ROOT "ubi" +#define UBI_NLEN_MAX "volume_name_max" +#define UBI_VERSION "version" +#define UBI_WEAR "wear" +#define UBI_VOL_COUNT "volumes_count" +#define UBI_TOT_EBS "total_eraseblocks" +#define UBI_AVAIL_EBS "avail_eraseblocks" +#define UBI_EB_SIZE "eraseblock_size" +#define UBI_NUMS "dev" +#define UBI_VBYTES "bytes" +#define UBI_VEBS "eraseblocks" +#define UBI_VTYPE "type" +#define UBI_VNAME "name" + +#define UBI_CDEV_PATH "/dev/ubi%d" +#define UBI_VOL_CDEV_PATH "/dev/ubi%d_%d" +#define UBI_SYSFS_ROOT "/sys/class" + +#define UBI_MAX_ID_SIZE 9 + +#endif /* !__UBI_INT_H__ */ diff --git a/ubi-utils/src/libubi_sysfs.c b/ubi-utils/src/libubi_sysfs.c new file mode 100644 index 0000000..95fd3de --- /dev/null +++ b/ubi-utils/src/libubi_sysfs.c @@ -0,0 +1,232 @@ +/* + * 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. + */ + +/* + * UBI (Unsorted Block Images) library. + * + * Author: Artem B. Bityutskiy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "libubi_int.h" + +int +sysfs_read_data(const char *file, void *buf, int len) +{ + int fd; + ssize_t rd; + + fd = open(file, O_RDONLY); + if (fd == -1) { + ubi_err("cannot open file %s", file); + return -1; + } + + rd = read(fd, buf, len); + if (rd == -1) + ubi_err("cannot read file %s", file); + + close(fd); + + return rd; +} + +int +sysfs_read_data_subst(const char *patt, void *buf, int len, int n, ...) +{ + va_list args; + char buf1[strlen(patt) + 20 * n]; + + va_start(args, n); + vsprintf(&buf1[0], patt, args); + va_end(args); + + return sysfs_read_data(&buf1[0], buf, len); +} + +int +sysfs_read_dev(const char *file, unsigned int *major, unsigned int *minor) +{ + int fd; + int ret; + ssize_t rd; + int err = -1; + char buf[40]; + + fd = open(file, O_RDONLY); + if (fd == -1) { + ubi_err("cannot open file %s", file); + return -1; + } + + rd = read(fd, &buf[0], 20); + if (rd == -1) { + ubi_err("cannot read file %s", file); + goto error; + } + if (rd < 4) { + ubi_err("bad contents of file %s:", file); + goto error; + } + + err = -1; + if (buf[rd -1] != '\n') { + ubi_err("bad contents of file %s", file); + goto error; + } + + ret = sscanf(&buf[0], "%d:%d\n", major, minor); + if (ret != 2) { + ubi_err("bad contents of file %s", file); + goto error; + } + + err = 0; + +error: + close(fd); + + return err; +} + +int +sysfs_read_dev_subst(const char *patt, unsigned int *major, + unsigned int *minor, int n, ...) +{ + va_list args; + char buf[strlen(patt) + 20 * n]; + + va_start(args, n); + vsprintf(&buf[0], patt, args); + va_end(args); + + return sysfs_read_dev(&buf[0], major, minor); +} + +static int +sysfs_read_ull(const char *file __unused, unsigned long long *num __unused) +{ + return 0; +} + +int +sysfs_read_ull_subst(const char *patt, unsigned long long *num, int n, ...) +{ + va_list args; + char buf[strlen(patt) + 20 * n]; + + va_start(args, n); + vsprintf(&buf[0], patt, args); + va_end(args); + + return sysfs_read_ull(&buf[0], num); +} + +static int +sysfs_read_uint(const char *file __unused, unsigned int *num __unused) +{ + return 0; +} + +int +sysfs_read_uint_subst(const char *patt, unsigned int *num, int n, ...) +{ + va_list args; + char buf[strlen(patt) + 20 * n]; + + va_start(args, n); + vsprintf(&buf[0], patt, args); + va_end(args); + + return sysfs_read_uint(&buf[0], num); +} + +int +sysfs_read_ll(const char *file, long long *num) +{ + int fd; + ssize_t rd; + int err = -1; + char buf[20]; + char *endptr; + + fd = open(file, O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, &buf[0], 20); + if (rd == -1) + goto out; + + if (rd < 2) { + ubi_err("bad contents in file %s: \"%c%c...\"", + file, buf[0], buf[1]); + goto out_errno; + } + + *num = strtoll(&buf[0], &endptr, 10); + if (endptr == &buf[0] || *endptr != '\n') { + ubi_err("bad contents in file %s: \"%c%c...\"", + file, buf[0], buf[1]); + goto out_errno; + } + + if (*num < 0) { + ubi_err("bad number in file %s: %lld", file, *num); + goto out_errno; + } + + err = 0; + +out_errno: + errno = EINVAL; + +out: + close(fd); + return err; +} + +int +sysfs_read_int(const char *file, int *num) +{ + int err; + long long res = 0; + + err = sysfs_read_ll(file, &res); + if (err) + return err; + + if (res < 0 || res > INT_MAX) { + ubi_err("bad number in file %s: %lld", file, res); + errno = EINVAL; + return -1; + } + + *num = res; + return 0; +} diff --git a/ubi-utils/src/libubi_sysfs.h b/ubi-utils/src/libubi_sysfs.h new file mode 100644 index 0000000..2fb6072 --- /dev/null +++ b/ubi-utils/src/libubi_sysfs.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/* + * UBI (Unsorted Block Images) library. + * + * Author: Artem B. Bityutskiy + */ + +/** + * sysfs_read_data - read data from a sysfs file. + * + * @file path to the file to read from + * @buf furrer where to store read data + * @len length of provided buffer @buf + * + * This function returns the number of read bytes or -1 in case of error. + */ +int sysfs_read_data(const char *file, void *buf, int len); + +/** + * sysfs_read_data_subst - form path to a sysfs file and read data from it. + * + * @patt path to the file to read from + * @buf furrer where to store read data + * @len length of provided buffer @buf + * @n number of parameters to substitute to @patt + * + * This function forms path to a sysfs file by means of substituting parameters + * to @patt and then reads @len bytes from this file and stores the read data + * to @buf. This function returns the number of read bytes or -1 in case of + * error. + */ +int sysfs_read_data_subst(const char *patt, void *buf, int len, int n, ...); + +/** + * sysfs_read_dev - read major and minor number from a sysfs file. + * + * @file path to the file to read from + * @major major number is returned here + * @minor minor number is returned here + */ +int sysfs_read_dev(const char *file, unsigned int *major, + unsigned int *minor); +/** + * sysfs_read_dev_subst - for path to a file and read major and minor number + * from it. + * + * @patt pattern of the path to the file to read from + * @major major number is returned here + * @minor minor number is returned here + * @n number of arguments to substitute + * + * This function substitures arguments to the @patt file path pattern and reads + * major and minor numbers from the resulting file. + */ +int sysfs_read_dev_subst(const char *patt, unsigned int *major, + unsigned int *minor, int n, ...); + +/** + * sysfs_read_ull_subst - form path to a sysfs file and read an unsigned long + * long value from there. + * + * @patt pattern of file path + * @num the read value is returned here + * @n number of parameters to substitute + * + * + * This function first forms the path to a sysfs file by means of substituting + * passed parameters to the @patt string, and then read an 'unsigned long long' + * value from this file. + */ +int sysfs_read_ull_subst(const char *patt, unsigned long long *num, + int n, ...); + +/** + * sysfs_read_uint_subst - the same as 'sysfs_read_uint_subst()' but reads an + * unsigned int value. + */ +int sysfs_read_uint_subst(const char *patt, unsigned int *num, + int n, ...); + +/** + * sysfs_read_ll - read a long long integer from an UBI sysfs file. + * + * @file file name from where to read + * @num the result is returned here + */ +int sysfs_read_ll(const char *file, long long *num); + +/** + * sysfs_read_int - the same as 'sysfs_read_ll()' but reads an 'int' value. + */ +int sysfs_read_int(const char *file, int *num); diff --git a/ubi-utils/src/libubigen.c b/ubi-utils/src/libubigen.c new file mode 100644 index 0000000..258e555 --- /dev/null +++ b/ubi-utils/src/libubigen.c @@ -0,0 +1,486 @@ +/* + * 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 + * + * Add UBI headers to binary data. + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "ubigen.h" +#include "crc32.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 eb_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 eb_size) +{ + return (byte % eb_size) == 0 + ? (byte / eb_size) + : (byte / eb_size) + 1; +} + +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 (ubi32_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->eb_size); +} + +static void +write_ec_hdr(ubi_info_t u) +{ + memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE); +} + +static int +fill_data_buffer_from_file(ubi_info_t u, size_t* read) +{ + size_t to_read = 0; + + if (u-> fp_in == NULL) + return -EIO; + + 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; + } + 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_ubi32(data_size); + u->v->data_crc = cpu_to_ubi32(crc); + + if (action & BROKEN_DATA_CRC) { + u->v->data_crc = + cpu_to_ubi32(ubi32_to_cpu(u->v->data_crc) + 1); + } + if (action & BROKEN_DATA_SIZE) { + u->v->data_size = + cpu_to_ubi32(ubi32_to_cpu(u->v->data_size) + 1); + } +} + +static void +write_vid_hdr(ubi_info_t u, ubigen_action_t action) +{ + 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_ubi32(crc); + if (action & BROKEN_HDR_CRC) { + u->v->hdr_crc = cpu_to_ubi32(ubi32_to_cpu(u->v->hdr_crc) + 1); + } + memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE); +} + +static int +write_to_output_stream(ubi_info_t u) +{ + size_t written; + + written = fwrite(u->buf, 1, u->eb_size, u->fp_out); + if (written != u->eb_size) { + return -EIO; + } + return 0; +} + +int +ubigen_write_leb(ubi_info_t u, ubigen_action_t action) +{ + 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); + } + + u->v->lnum = cpu_to_ubi32(u->blks_written); + + if (action & MARK_AS_UPDATE) { + u->v->copy_flag = (u->v->copy_flag)++; + } + + write_vid_hdr(u, action); + rc = write_to_output_stream(u); + if (rc != 0) + return rc; + + /* Update current handle */ + u->bytes_read += read; + u->blks_written++; + return 0; +} + +int +ubigen_write_complete(ubi_info_t u) +{ + size_t i; + int rc = 0; + + for (i = 0; i < u->leb_total; i++) { + rc = ubigen_write_leb(u, NO_ERROR); + if (rc != 0) + return rc; + } + + return 0; +} + +int +ubigen_write_broken_update(ubi_info_t u, uint32_t blk) +{ + 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; +} + +void +dump_info(ubi_info_t u __unused) +{ +#ifdef DEBUG + int err = 0; + if (!u) { + fprintf(stderr, ""); + return; + } + if (!u->ec) { + fprintf(stderr, ""); + err = 1; + } + if (!u->v) { + fprintf(stderr, ""); + err = 1; + } + if (err) return; + + fprintf(stderr, "ubi volume\n"); + fprintf(stderr, "version : %8d\n", u->v->version); + fprintf(stderr, "vol_id : %8d\n", ubi32_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", + ubi32_to_cpu(u->v->used_ebs)); + fprintf(stderr, "eb_size : 0x%08x\n", u->eb_size); + fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size); + fprintf(stderr, "data_pad : 0x%08x\n", + ubi32_to_cpu(u->v->data_pad)); + fprintf(stderr, "leb_total : %8d\n", u->leb_total); + fprintf(stderr, "header offs : 0x%08x\n", + ubi32_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 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) +{ + 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->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE; + res->data_pad = (res->eb_size - data_offset) % alignment; + res->leb_size = res->eb_size - data_offset - res->data_pad; + res->leb_total = byte_to_blk(data_size, res->leb_size); + res->alignment = alignment; + + if ((res->eb_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_ubi32(UBI_VID_HDR_MAGIC); + res->v->version = version ? version : UBI_VERSION; + res->v->vol_type = vol_type; + res->v->vol_id = cpu_to_ubi32(vol_id); + res->v->compat = compat_flag; + res->v->data_pad = cpu_to_ubi32(res->data_pad); + + /* static only: used_ebs */ + if (res->v->vol_type == UBI_VID_STATIC) { + res->v->used_ebs = cpu_to_ubi32(byte_to_blk + (res->bytes_total, + res->leb_size)); + } + + /* ec hdr (fixed, doesn't change) */ + res->ec->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC); + res->ec->version = version ? version : UBI_VERSION; + res->ec->ec = cpu_to_ubi64(ec); + res->ec->vid_hdr_offset = cpu_to_ubi32(vid_hdr_offset); + + res->ec->data_offset = cpu_to_ubi32(data_offset); + + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec, + UBI_EC_HDR_SIZE_CRC); + res->ec->hdr_crc = cpu_to_ubi32(crc); + + /* prepare a read buffer */ + res->buf = (uint8_t*) malloc (res->eb_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 + ubi32_to_cpu(res->ec->vid_hdr_offset); + res->ptr_data = res->buf + ubi32_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); + } + *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_vol_tbl_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_ubi32(byte_to_blk(reserved_bytes, u->leb_size)); + lvol_rec->alignment = cpu_to_ubi32(u->alignment); + lvol_rec->data_pad = u->v->data_pad; + lvol_rec->vol_type = u->v->vol_type; + + lvol_rec->name_len = + cpu_to_ubi16((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_ubi32(crc); + + return 0; +} diff --git a/ubi-utils/src/libubigen/ubigen.c b/ubi-utils/src/libubigen/ubigen.c deleted file mode 100644 index 0cfa687..0000000 --- a/ubi-utils/src/libubigen/ubigen.c +++ /dev/null @@ -1,486 +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 - * - * Add UBI headers to binary data. - */ - -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "ubigen.h" -#include "crc32.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 eb_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 eb_size) -{ - return (byte % eb_size) == 0 - ? (byte / eb_size) - : (byte / eb_size) + 1; -} - -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 (ubi32_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->eb_size); -} - -static void -write_ec_hdr(ubi_info_t u) -{ - memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE); -} - -static int -fill_data_buffer_from_file(ubi_info_t u, size_t* read) -{ - size_t to_read = 0; - - if (u-> fp_in == NULL) - return -EIO; - - 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; - } - 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_ubi32(data_size); - u->v->data_crc = cpu_to_ubi32(crc); - - if (action & BROKEN_DATA_CRC) { - u->v->data_crc = - cpu_to_ubi32(ubi32_to_cpu(u->v->data_crc) + 1); - } - if (action & BROKEN_DATA_SIZE) { - u->v->data_size = - cpu_to_ubi32(ubi32_to_cpu(u->v->data_size) + 1); - } -} - -static void -write_vid_hdr(ubi_info_t u, ubigen_action_t action) -{ - 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_ubi32(crc); - if (action & BROKEN_HDR_CRC) { - u->v->hdr_crc = cpu_to_ubi32(ubi32_to_cpu(u->v->hdr_crc) + 1); - } - memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE); -} - -static int -write_to_output_stream(ubi_info_t u) -{ - size_t written; - - written = fwrite(u->buf, 1, u->eb_size, u->fp_out); - if (written != u->eb_size) { - return -EIO; - } - return 0; -} - -int -ubigen_write_leb(ubi_info_t u, ubigen_action_t action) -{ - 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); - } - - u->v->lnum = cpu_to_ubi32(u->blks_written); - - if (action & MARK_AS_UPDATE) { - u->v->copy_flag = (u->v->copy_flag)++; - } - - write_vid_hdr(u, action); - rc = write_to_output_stream(u); - if (rc != 0) - return rc; - - /* Update current handle */ - u->bytes_read += read; - u->blks_written++; - return 0; -} - -int -ubigen_write_complete(ubi_info_t u) -{ - size_t i; - int rc = 0; - - for (i = 0; i < u->leb_total; i++) { - rc = ubigen_write_leb(u, NO_ERROR); - if (rc != 0) - return rc; - } - - return 0; -} - -int -ubigen_write_broken_update(ubi_info_t u, uint32_t blk) -{ - 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; -} - -void -dump_info(ubi_info_t u) -{ -#ifdef DEBUG - int err = 0; - if (!u) { - fprintf(stderr, ""); - return; - } - if (!u->ec) { - fprintf(stderr, ""); - err = 1; - } - if (!u->v) { - fprintf(stderr, ""); - err = 1; - } - if (err) return; - - fprintf(stderr, "ubi volume\n"); - fprintf(stderr, "version : %8d\n", u->v->version); - fprintf(stderr, "vol_id : %8d\n", ubi32_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", - ubi32_to_cpu(u->v->used_ebs)); - fprintf(stderr, "eb_size : 0x%08x\n", u->eb_size); - fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size); - fprintf(stderr, "data_pad : 0x%08x\n", - ubi32_to_cpu(u->v->data_pad)); - fprintf(stderr, "leb_total : %8d\n", u->leb_total); - fprintf(stderr, "header offs : 0x%08x\n", - ubi32_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 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) -{ - 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->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE; - res->data_pad = (res->eb_size - data_offset) % alignment; - res->leb_size = res->eb_size - data_offset - res->data_pad; - res->leb_total = byte_to_blk(data_size, res->leb_size); - res->alignment = alignment; - - if ((res->eb_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_ubi32(UBI_VID_HDR_MAGIC); - res->v->version = version ? version : UBI_VERSION; - res->v->vol_type = vol_type; - res->v->vol_id = cpu_to_ubi32(vol_id); - res->v->compat = compat_flag; - res->v->data_pad = cpu_to_ubi32(res->data_pad); - - /* static only: used_ebs */ - if (res->v->vol_type == UBI_VID_STATIC) { - res->v->used_ebs = cpu_to_ubi32(byte_to_blk - (res->bytes_total, - res->leb_size)); - } - - /* ec hdr (fixed, doesn't change) */ - res->ec->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC); - res->ec->version = version ? version : UBI_VERSION; - res->ec->ec = cpu_to_ubi64(ec); - res->ec->vid_hdr_offset = cpu_to_ubi32(vid_hdr_offset); - - res->ec->data_offset = cpu_to_ubi32(data_offset); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec, - UBI_EC_HDR_SIZE_CRC); - res->ec->hdr_crc = cpu_to_ubi32(crc); - - /* prepare a read buffer */ - res->buf = (uint8_t*) malloc (res->eb_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 + ubi32_to_cpu(res->ec->vid_hdr_offset); - res->ptr_data = res->buf + ubi32_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); - } - *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_vol_tbl_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_ubi32(byte_to_blk(reserved_bytes, u->leb_size)); - lvol_rec->alignment = cpu_to_ubi32(u->alignment); - lvol_rec->data_pad = u->v->data_pad; - lvol_rec->vol_type = u->v->vol_type; - - lvol_rec->name_len = - cpu_to_ubi16((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_ubi32(crc); - - return 0; -} diff --git a/ubi-utils/src/libubimirror.c b/ubi-utils/src/libubimirror.c new file mode 100644 index 0000000..e5715fc --- /dev/null +++ b/ubi-utils/src/libubimirror.c @@ -0,0 +1,217 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include "ubimirror.h" + +#define COMPARE_BUF_SIZE (128 * 1024) + +#define EBUF(fmt...) do { \ + snprintf(err_buf, err_buf_size, fmt); \ +} while (0) + +enum { + compare_error = -1, + seek_error = -2, + write_error = -3, + read_error = -4, + update_error = -5, + ubi_error = -6, + open_error = -7, + close_error = -8, + compare_equal = 0, + compare_different = 1 +}; + +/* + * Read len number of bytes from fd. + * Return 0 on EOF, -1 on error. + */ +static ssize_t fill_buffer(int fd, unsigned char *buf, ssize_t len) +{ + ssize_t got, have = 0; + + do { + got = read(fd, buf + have, len - have); + if( got == -1 && errno != EINTR ) + return -1; + have += got; + } while ( got > 0 && have < len); + return have; +} + +/* + * Write len number of bytes to fd. + * Return bytes written (>= 0), -1 on error. + */ +static ssize_t flush_buffer(int fd, unsigned char *buf, ssize_t len) +{ + ssize_t done, have = 0; + + do { + done = write(fd, buf + have, len - have); + if( done == -1 && errno != EINTR ) + return -1; + have += done; + } while ( done > 0 && have < len); + return have; +} + +/* + * Compare two files. Return 0, 1, or -1, depending on whether the + * files are equal, different, or an error occured. + * Return compare-different when target volume can not be read. Might be + * an interrupted volume update and then the target device returns -EIO but + * can be updated. + * + * fd_a is source + * fd_b is destination + */ +static int +compare_files(int fd_a, int fd_b) +{ + unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE]; + ssize_t len_a, len_b; + int rc; + + for (;;) { + len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a)); + if (len_a == -1){ + rc = compare_error; + break; + } + len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b)); + if (len_b == -1){ + rc = compare_different; + break; + } + if( len_a != len_b ){ + rc = compare_different; + break; + } + if( len_a == 0 ){ /* Size on both filies equal and EOF */ + rc = compare_equal; + break; + } + if( memcmp(buf_a, buf_b, len_a) != 0 ){ + rc = compare_different; + break; + } + } + /* Position both files at the beginning */ + if( lseek(fd_a, 0, SEEK_SET) == -1 || + lseek(fd_b, 0, SEEK_SET) == -1 ) + rc = seek_error; + return rc; +} + +static int +copy_files(int fd_in, int fd_out) +{ + unsigned char buf_a[COMPARE_BUF_SIZE]; + ssize_t len_a, len_b; + unsigned long long update_size, copied; + + if( ubi_vol_get_used_bytes(fd_in, &update_size) == -1 || + ubi_vol_update(fd_out, update_size) == -1 ) + return update_error; + for( copied = 0; copied < update_size; copied += len_b ){ + len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a)); + if (len_a == -1) + return read_error; + if (len_a == 0) /* Reach EOF */ + return 0; + len_b = flush_buffer(fd_out, buf_a, len_a); + if( len_b != len_a ) + return write_error; + } + return 0; +} + +int +ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + uint32_t src_id; + ubi_lib_t ulib = NULL; + int fd_in = -1, i = 0, fd_out = -1; + + if (ids_size == 0) + return 0; + else { + if ((seqnum < 0) || (seqnum > (ids_size - 1))) { + EBUF("volume id %d out of range", seqnum); + return EUBIMIRROR_NO_SRC; + } + src_id = ids[seqnum]; + } + + rc = ubi_open(&ulib); + if (rc != 0) + return ubi_error; + + fd_in = ubi_vol_open(ulib, devno, src_id, O_RDONLY); + if (fd_in == -1){ + EBUF("open error source volume %d", ids[i]); + rc = open_error; + goto err; + } + + for (i = 0; i < ids_size; i++) { + if (ids[i] == src_id) /* skip self-mirror */ + continue; + + fd_out = ubi_vol_open(ulib, devno, ids[i], O_RDWR); + if (fd_out == -1){ + EBUF("open error destination volume %d", ids[i]); + rc = open_error; + goto err; + } + rc = compare_files(fd_in, fd_out); + if (rc < 0 ){ + EBUF("compare error volume %d and %d", src_id, ids[i]); + goto err; + } + rc = copy_files(fd_in, fd_out); + if (rc != 0) { + EBUF("mirror error volume %d to %d", src_id, ids[i]); + goto err; + } + if( (rc = ubi_vol_close(fd_out)) == -1 ){ + EBUF("close error volume %d", ids[i]); + rc = close_error; + goto err; + }else + fd_out = -1; + } +err: + if (ulib != NULL) + ubi_close(&ulib); + if (fd_in != -1) + ubi_vol_close(fd_in); + if (fd_out != -1) + ubi_vol_close(fd_out); + return rc; +} diff --git a/ubi-utils/src/libubimirror/ubimirror.c b/ubi-utils/src/libubimirror/ubimirror.c deleted file mode 100644 index bf6b37c..0000000 --- a/ubi-utils/src/libubimirror/ubimirror.c +++ /dev/null @@ -1,217 +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 -#include -#include -#include -#include - -#include -#include "ubimirror.h" - -#define COMPARE_BUF_SIZE (128 * 1024) - -#define EBUF(fmt...) do { \ - snprintf(err_buf, err_buf_size, fmt); \ -} while (0) - -enum { - compare_error = -1, - seek_error = -2, - write_error = -3, - read_error = -4, - update_error = -5, - ubi_error = -6, - open_error = -7, - close_error = -8, - compare_equal = 0, - compare_different = 1 -}; - -/* - * Read len number of bytes from fd. - * Return 0 on EOF, -1 on error. - */ -static ssize_t fill_buffer(int fd, unsigned char *buf, size_t len) -{ - ssize_t got, have = 0; - - do { - got = read(fd, buf + have, len - have); - if( got == -1 && errno != EINTR ) - return -1; - have += got; - } while ( got > 0 && have < len); - return have; -} - -/* - * Write len number of bytes to fd. - * Return bytes written (>= 0), -1 on error. - */ -static ssize_t flush_buffer(int fd, unsigned char *buf, size_t len) -{ - ssize_t done, have = 0; - - do { - done = write(fd, buf + have, len - have); - if( done == -1 && errno != EINTR ) - return -1; - have += done; - } while ( done > 0 && have < len); - return have; -} - -/* - * Compare two files. Return 0, 1, or -1, depending on whether the - * files are equal, different, or an error occured. - * Return compare-different when target volume can not be read. Might be - * an interrupted volume update and then the target device returns -EIO but - * can be updated. - * - * fd_a is source - * fd_b is destination - */ -static int -compare_files(int fd_a, int fd_b) -{ - unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE]; - ssize_t len_a, len_b; - int rc; - - for (;;) { - len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a)); - if (len_a == -1){ - rc = compare_error; - break; - } - len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b)); - if (len_b == -1){ - rc = compare_different; - break; - } - if( len_a != len_b ){ - rc = compare_different; - break; - } - if( len_a == 0 ){ /* Size on both filies equal and EOF */ - rc = compare_equal; - break; - } - if( memcmp(buf_a, buf_b, len_a) != 0 ){ - rc = compare_different; - break; - } - } - /* Position both files at the beginning */ - if( lseek(fd_a, 0, SEEK_SET) == -1 || - lseek(fd_b, 0, SEEK_SET) == -1 ) - rc = seek_error; - return rc; -} - -static int -copy_files(int fd_in, int fd_out) -{ - unsigned char buf_a[COMPARE_BUF_SIZE]; - ssize_t len_a, len_b; - unsigned long long update_size, copied; - - if( ubi_vol_get_used_bytes(fd_in, &update_size) == -1 || - ubi_vol_update(fd_out, update_size) == -1 ) - return update_error; - for( copied = 0; copied < update_size; copied += len_b ){ - len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a)); - if (len_a == -1) - return read_error; - if (len_a == 0) /* Reach EOF */ - return 0; - len_b = flush_buffer(fd_out, buf_a, len_a); - if( len_b != len_a ) - return write_error; - } - return 0; -} - -int -ubimirror(uint32_t devno, int seqnum, uint32_t *ids, size_t ids_size, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - uint32_t src_id; - ubi_lib_t ulib = NULL; - int fd_in = -1, i = 0, fd_out = -1; - - if (ids_size == 0) - return 0; - else { - if ((seqnum < 0) || (seqnum > (ids_size - 1))) { - EBUF("volume id %d out of range", seqnum); - return EUBIMIRROR_NO_SRC; - } - src_id = ids[seqnum]; - } - - rc = ubi_open(&ulib); - if (rc != 0) - return ubi_error; - - fd_in = ubi_vol_open(ulib, devno, src_id, O_RDONLY); - if (fd_in == -1){ - EBUF("open error source volume %d", ids[i]); - rc = open_error; - goto err; - } - - for (i = 0; i < ids_size; i++) { - if (ids[i] == src_id) /* skip self-mirror */ - continue; - - fd_out = ubi_vol_open(ulib, devno, ids[i], O_RDWR); - if (fd_out == -1){ - EBUF("open error destination volume %d", ids[i]); - rc = open_error; - goto err; - } - rc = compare_files(fd_in, fd_out); - if (rc < 0 ){ - EBUF("compare error volume %d and %d", src_id, ids[i]); - goto err; - } - rc = copy_files(fd_in, fd_out); - if (rc != 0) { - EBUF("mirror error volume %d to %d", src_id, ids[i]); - goto err; - } - if( (rc = ubi_vol_close(fd_out)) == -1 ){ - EBUF("close error volume %d", ids[i]); - rc = close_error; - goto err; - }else - fd_out = -1; - } -err: - if (ulib != NULL) - ubi_close(&ulib); - if (fd_in != -1) - ubi_vol_close(fd_in); - if (fd_out != -1) - ubi_vol_close(fd_out); - return rc; -} diff --git a/ubi-utils/src/list.c b/ubi-utils/src/list.c new file mode 100644 index 0000000..6eb716b --- /dev/null +++ b/ubi-utils/src/list.c @@ -0,0 +1,149 @@ +/* + * 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 +#include +#include + +#include "list.h" + +list_t +mk_empty(void) +{ + return (list_t) NULL; +} + +int +is_empty(list_t l) +{ + return l == NULL; +} + +info_t +head(list_t l) +{ + assert(!is_empty(l)); + return l->info; +} + +list_t +tail(list_t l) +{ + assert(!is_empty(l)); + return l->next; +} + +list_t +remove_head(list_t l) +{ + list_t res; + assert(!is_empty(l)); + + res = l->next; + free(l); + return res; +} + +list_t +cons(info_t e, list_t l) +{ + list_t res = malloc(sizeof(*l)); + if (!res) + return NULL; + res->info = e; + res->next = l; + + return res; +} + +list_t +prepend_elem(info_t e, list_t l) +{ + return cons(e,l); +} + +list_t +append_elem(info_t e, list_t l) +{ + if (is_empty(l)) { + return cons(e,l); + } + l->next = append_elem(e, l->next); + + return l; +} + +list_t +insert_sorted(cmp_func_t cmp, info_t e, list_t l) +{ + if (is_empty(l)) + return cons(e, l); + + switch (cmp(e, l->info)) { + case -1: + case 0: + return l; + break; + case 1: + l->next = insert_sorted(cmp, e, l); + break; + default: + break; + } + + /* never reached */ + return NULL; +} + +list_t +remove_all(free_func_t free_func, list_t l) +{ + if (is_empty(l)) + return l; + list_t lnext = l->next; + + if (free_func && l->info) { + free_func(&(l->info)); + } + free(l); + + return remove_all(free_func, lnext); +} + + +info_t +is_in(cmp_func_t cmp, info_t e, list_t l) +{ + return + (is_empty(l)) + ? NULL + : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next); +} + + +void +apply(process_func_t process_func, list_t l) +{ + list_t ptr; + void *i; + foreach(i, ptr, l) { + process_func(i); + } +} diff --git a/ubi-utils/src/list.h b/ubi-utils/src/list.h new file mode 100644 index 0000000..e8452a2 --- /dev/null +++ b/ubi-utils/src/list.h @@ -0,0 +1,56 @@ +#ifndef __LIST_H__ +#define __LIST_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 + +#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) + +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; + 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__ */ diff --git a/ubi-utils/src/mkbootenv.c b/ubi-utils/src/mkbootenv.c new file mode 100644 index 0000000..49ce597 --- /dev/null +++ b/ubi-utils/src/mkbootenv.c @@ -0,0 +1,173 @@ +/* + * 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 + * + * Create boot-parameter/pdd data from an ASCII-text input file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "bootenv.h" +#include "error.h" + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "mkbootenv - processes bootenv text files and convertes " + "them into a binary format.\n"; + +static const char copyright [] __attribute__((unused)) = + "Copyright (c) International Business Machines Corp., 2006"; + +static struct argp_option options[] = { + { .name = "copyright", + .key = 'c', + .arg = NULL, + .flags = 0, + .doc = "Print copyright information.", + .group = 1 }, + { .name = "output", + .key = 'o', + .arg = "", + .flags = 0, + .doc = "Write the the output data to instead of stdout.", + .group = 1 }, + { .name = NULL, + .key = 0, + .arg = NULL, + .flags = 0, + .doc = NULL, + .group = 0 }, +}; + +typedef struct myargs { + FILE* fp_in; + FILE* fp_out; + + char *arg1; + char **options; /* [STRING...] */ +} myargs; + + + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + int err = 0; + + myargs *args = state->input; + + switch (key) { + case 'c': + fprintf(stderr, "%s\n", copyright); + exit(0); + break; + case 'o': + args->fp_out = fopen(arg, "wb"); + if ((args->fp_out) == NULL) { + fprintf(stderr, + "Cannot open file %s for output\n", arg); + exit(1); + } + break; + case ARGP_KEY_ARG: + args->fp_in = fopen(arg, "rb"); + if ((args->fp_in) == NULL) { + fprintf(stderr, + "Cannot open file %s for input\n", arg); + exit(1); + } + args->arg1 = arg; + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + case ARGP_KEY_END: + if (err) { + fprintf(stderr, "\n"); + argp_usage(state); + exit(1); + } + break; + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static struct argp argp = { + .options = options, + .parser = parse_opt, + .args_doc = "[bootenv-txt-file]", + .doc = doc, + .children = NULL, + .help_filter = NULL, + .argp_domain = NULL, +}; + +int +main(int argc, char **argv) { + int rc = 0; + bootenv_t env; + + myargs args = { + .fp_in = stdin, + .fp_out = stdout, + .arg1 = NULL, + .options = NULL, + }; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + + rc = bootenv_create(&env); + if (rc != 0) { + err_msg("Cannot create bootenv handle."); + goto err; + } + rc = bootenv_read_txt(args.fp_in, env); + if (rc != 0) { + err_msg("Cannot read bootenv from input file."); + goto err; + } + rc = bootenv_write(args.fp_out, env); + if (rc != 0) { + err_msg("Cannot write bootenv to output file."); + goto err; + } + + if (args.fp_in != stdin) { + fclose(args.fp_in); + } + if (args.fp_out != stdout) { + fclose(args.fp_out); + } + +err: + bootenv_destroy(&env); + return rc; +} diff --git a/ubi-utils/src/mkbootenv/mkbootenv.c b/ubi-utils/src/mkbootenv/mkbootenv.c deleted file mode 100644 index 49ce597..0000000 --- a/ubi-utils/src/mkbootenv/mkbootenv.c +++ /dev/null @@ -1,173 +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 - * - * Create boot-parameter/pdd data from an ASCII-text input file. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "bootenv.h" -#include "error.h" - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "mkbootenv - processes bootenv text files and convertes " - "them into a binary format.\n"; - -static const char copyright [] __attribute__((unused)) = - "Copyright (c) International Business Machines Corp., 2006"; - -static struct argp_option options[] = { - { .name = "copyright", - .key = 'c', - .arg = NULL, - .flags = 0, - .doc = "Print copyright information.", - .group = 1 }, - { .name = "output", - .key = 'o', - .arg = "", - .flags = 0, - .doc = "Write the the output data to instead of stdout.", - .group = 1 }, - { .name = NULL, - .key = 0, - .arg = NULL, - .flags = 0, - .doc = NULL, - .group = 0 }, -}; - -typedef struct myargs { - FILE* fp_in; - FILE* fp_out; - - char *arg1; - char **options; /* [STRING...] */ -} myargs; - - - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - int err = 0; - - myargs *args = state->input; - - switch (key) { - case 'c': - fprintf(stderr, "%s\n", copyright); - exit(0); - break; - case 'o': - args->fp_out = fopen(arg, "wb"); - if ((args->fp_out) == NULL) { - fprintf(stderr, - "Cannot open file %s for output\n", arg); - exit(1); - } - break; - case ARGP_KEY_ARG: - args->fp_in = fopen(arg, "rb"); - if ((args->fp_in) == NULL) { - fprintf(stderr, - "Cannot open file %s for input\n", arg); - exit(1); - } - args->arg1 = arg; - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - case ARGP_KEY_END: - if (err) { - fprintf(stderr, "\n"); - argp_usage(state); - exit(1); - } - break; - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static struct argp argp = { - .options = options, - .parser = parse_opt, - .args_doc = "[bootenv-txt-file]", - .doc = doc, - .children = NULL, - .help_filter = NULL, - .argp_domain = NULL, -}; - -int -main(int argc, char **argv) { - int rc = 0; - bootenv_t env; - - myargs args = { - .fp_in = stdin, - .fp_out = stdout, - .arg1 = NULL, - .options = NULL, - }; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - - rc = bootenv_create(&env); - if (rc != 0) { - err_msg("Cannot create bootenv handle."); - goto err; - } - rc = bootenv_read_txt(args.fp_in, env); - if (rc != 0) { - err_msg("Cannot read bootenv from input file."); - goto err; - } - rc = bootenv_write(args.fp_out, env); - if (rc != 0) { - err_msg("Cannot write bootenv to output file."); - goto err; - } - - if (args.fp_in != stdin) { - fclose(args.fp_in); - } - if (args.fp_out != stdout) { - fclose(args.fp_out); - } - -err: - bootenv_destroy(&env); - return rc; -} diff --git a/ubi-utils/src/mkpfi/f128_nand_sample.cfg b/ubi-utils/src/mkpfi/f128_nand_sample.cfg deleted file mode 100644 index e468d9d..0000000 --- a/ubi-utils/src/mkpfi/f128_nand_sample.cfg +++ /dev/null @@ -1,38 +0,0 @@ -[targets] -complete=ipl,spl,bootenv,kernel,rootfs -bootcode=spl,bootenv - -# Build sections -[ipl] -image=ipl.bin -raw_starts=0x00000000 -raw_total_size=128kiB - -[spl] -image=u-boot.bin -ubi_ids=2,3 -ubi_size=2MiB -ubi_type=static -ubi_names=spl_0,spl_1 - -[bootenv] -bootenv_file=bootenv_complete.txt -ubi_ids=4,5 -ubi_size=128kiB -ubi_type=static -ubi_names=bootenv_0,bootenv_1 - -[kernel] -image=vmlinux.bin -ubi_ids=6,7 -ubi_size=6MiB -ubi_type=static -ubi_names=kernel_0,kernel_1 - -[rootfs] -image=rootfs.bin -ubi_ids=8,9 -ubi_alignment=2kiB -ubi_size=16MiB -ubi_type=dynamic -ubi_names=rootfs_0,rootfs_1 diff --git a/ubi-utils/src/mkpfi/f64_nor_sample.cfg b/ubi-utils/src/mkpfi/f64_nor_sample.cfg deleted file mode 100644 index fd44e27..0000000 --- a/ubi-utils/src/mkpfi/f64_nor_sample.cfg +++ /dev/null @@ -1,39 +0,0 @@ -[targets] -complete=ipl,spl,bootenv,kernel,rootfs -bootcode=spl,bootenv -rootfs=rootfs - -# Build sections -[ipl] -image=ipl.bin -raw_starts=0x02FE0000, 0x03FE0000 -raw_total_size=128kiB - -[spl] -image=u-boot.bin -ubi_ids=2,3 -ubi_size=2MiB -ubi_type=static -ubi_names=spl_0,spl_1 - -[bootenv] -bootenv_file=bootenv_complete.txt -ubi_ids=4,5 -ubi_size=128kiB -ubi_type=static -ubi_names=bootenv_0,bootenv_1 - -[kernel] -image=vmlinux.bin -ubi_ids=6,7 -ubi_size=6MiB -ubi_type=static -ubi_names=kernel_0,kernel_1 - -[rootfs] -image=rootfs.bin -ubi_ids=8,9 -ubi_alignment=2kiB -ubi_size=16128kiB -ubi_type=dynamic -ubi_names=rootfs_0,rootfs_1 diff --git a/ubi-utils/src/mkpfi/mkpfi b/ubi-utils/src/mkpfi/mkpfi deleted file mode 100755 index 2cce587..0000000 --- a/ubi-utils/src/mkpfi/mkpfi +++ /dev/null @@ -1,723 +0,0 @@ -#!/usr/bin/perl -# -# 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. -# - -# -# mkpfi -# -# This perl program is assembles PFI files from a config file. -# -# Author: Oliver Lohmann (oliloh@de.ibm.com) -# -use warnings; -use strict; -use lib "/usr/lib/perl5"; # Please change this path as you need it, or - # make a proposal how this could be done - # nicer. -use Getopt::Long; -use Pod::Usage; -use Config::IniFiles; -use File::Temp; - -# ---------------------------------------------------------------------------- -# Versions -our $version : unique = "0.1"; -our $pfi_version : unique = "0x1"; - -# ---------------------------------------------------------------------------- -# Globals -my $verbose = 0; -my $cfg; - -my %opts = (); -my %files = (config => ""); -my @tmp_files; - -my %tools = (ubicrc32 => "ubicrc32"); - -# ---------------------------------------------------------------------------- -# Processing the input sections -# -# The idea is to combine each section entry with a function -# in order to allow some kind of preprocessing for the values -# before they are written into the PFI file. -# This is especially useful to be more verbose and -# user-friendly in the layout file. -# -# All key-function hashes are applied after the general -# validation of the configuration file. -# If any mandatory key is missing in a section the user -# will be informed and the PFI creation process is aborted. -# -# Default keys will be checked for their presence inside the config -# file. If they are missing, they will be generated with appr. values. - -# Mandatory keys for UBI volumes. -my %ubi_keys = ("ubi_ids" => \&check_id_list, - "ubi_size" => \&replace_num, - "ubi_type" => \&replace_type, - "ubi_names" => \&remove_spaces, - "ubi_alignment" => \&replace_num); - -# Mandatory keys for RAW sections. -my %raw_keys = ("raw_starts" => \&expand_starts, - "raw_total_size" => \&replace_num); - -# Common default keys for documentation and control purposes. -my %common_keys = ("flags" => \&replace_num, - "label" => \&do_nothing); - -# Define any defaults here. Values which maintained in this default -# region need not to be specified by the user explicitly. -my %def_ubi_keys = ("ubi_alignment" => [\&set_default, "0x1"]); -my %def_raw_keys = (); -my %def_common_keys = ("flags" => [\&set_default, "0x0"], - "label" => [\&generate_label, ""]); - -# ---------------------------------------------------------------------------- -# Input keys, actually the path to the input data. - -my %input_keys = ("image" => \&do_nothing); - -# Placeholder keys allow the replacement via a special -# purpose function. E.g. the bootenv_file key will be used -# to generate bootenv binary data from an text file and -# replace the bootenv_file key with an image key to handle it -# in the same way in the further creation process. -my %input_placeholder_keys = ("bootenv_file" => \&create_bootenv_image); - -# ---------------------------------------------------------------------------- -# Helper - -# @brief Get current time string. -sub get_date { - my $tmp = scalar localtime; - $tmp =~ s/ /_/g; - return $tmp; -} - -# @brief Print an info message to stdout. -sub INFO($) { - my $str = shift; - - if (!$verbose) { - return; - } - - print STDOUT $str; -} - -# @brief Print an error message to stderr. -sub ERR($) { - my $str = shift; - print STDERR $str; -} - -# @brief Print a warning message to stderr. -sub WARN($) { - my $str = shift; - print STDERR $str; -} - -sub parse_command_line($) { - my $opt = shift; - my $result = GetOptions( "help" => \$$opt{'help'}, - "man" => \$$opt{'man'}, - "config=s" => \$$opt{'config'}, - "verbose" => \$$opt{'verbose'}, - ) or pod2usage(2); - pod2usage(1) if defined ($$opt{help}); - pod2usage(-verbose => 2) if defined ($$opt{man}); - - $verbose = $$opt{verbose} if defined $$opt{verbose}; - - if (!defined $$opt{config}) { - ERR("[ ERROR: No config file specified. Aborting...\n"); - exit 1; - } - -} - -# @brief Check if all needed tools are in PATH. -sub check_tools { - my $err = 0; - my $key; - - foreach $key (keys %tools) { - if (`which $tools{$key}` eq "") { - ERR("\n") if ($err == 0); - ERR("! Please add the tool \'$tools{$key}\' " . - "to your path!\n"); - $err = 1; - } - } - die "[ ERROR: Did not find all needed tools!\n" if $err; -} - -sub open_cfg_file($) { - my $fname = shift; - my $res = new Config::IniFiles( -file => $fname ); - - die "[ ERROR: Cannot load your config file!\n" if (!defined $res); - return $res; -} - -sub set_default($$$$) { - my ($cfg, $section, $parameter, $def_value) = @_; - $cfg->newval($section, $parameter, $def_value); - return; -} - -sub generate_label($$$$) { - my ($cfg, $section, $parameter, $def_value) = @_; - my $new_label = $def_value . $section; - $new_label .= "_" . get_date; - $cfg->newval($section, $parameter, $new_label); - return; -} - -# @brief Converts any num to a unified hex string, i.e the resulting value -# always starts with "0x" and is aligned to 8 hexdigits. -# @return Returns 0 on success, otherwise an error occured. -# -sub any_num_to_hex($$) { - my $val = shift; - my $res = shift; - - # M(iB) - if ($val =~ m/([0-9]+)[Mm][i]?[Bb]?/g) { - $$res = sprintf("0x%08x", $1 * 1024 * 1024); - } - # k(iB) - elsif ($val =~ m/([0-9]+)[kK][i]?[Bb]?/g) { - $$res = sprintf("0x%08x", $1 * 1024); - } - # hex - elsif ($val =~ m/0x?([0-9a-fA-F]+)/g) { - $$res = sprintf("0x%08x", hex $1); - } - # decimal - elsif ($val =~ m/^([0-9]+)$/g) { - $$res = sprintf("0x%08x", $1); - } - else { - $$res = ""; - return -1; - } - - return 0; -} - -sub remove_spaces($$$) { - my ($cfg, $section, $parameter) = @_; - my ($start, @starts, @new_starts); - my $val = $cfg->val($section, $parameter); - my $res; - - $val =~ s/ //g; # spaces - $cfg->newval($section, $parameter, $val); -} - -sub expand_starts($$$) { - my ($cfg, $section, $parameter) = @_; - my ($start, @starts, @new_starts); - my $val = $cfg->val($section, $parameter); - my $res; - - $val =~ s/ //g; # spaces - @starts = split(/,/, $val); - - foreach $start (@starts) { - if (any_num_to_hex($start, \$res) != 0) { - ERR("[ ERROR: [$section]\n"); - ERR("[ Expecting a list of numeric " . - "values for parameter: $parameter\n"); - exit 1; - } - push (@new_starts, $res); - } - $res = join(',', @starts); - - $cfg->newval($section, $parameter, $res); -} - -sub check_id_list($$$) { - my ($cfg, $section, $parameter) = @_; - my $val = $cfg->val($section, $parameter); - my $res; - - if (!($val =~ m/^[0-9]+[,0-9]*/)) { - ERR("[ ERROR: Syntax error in 'ubi_ids' in " . - "section '$section': $val\n"); - ERR("[ Aborting... "); - exit 1; - } -} - -sub replace_type($$$) { - my ($cfg, $section, $parameter) = @_; - my $val = $cfg->val($section, $parameter); - my $res; - - $res = lc($val); - grep {$res eq $_} ('static', 'dynamic') - or die "[ ERROR: Unknown UBI Volume Type in " . - "section '$section': $val\n"; - - $cfg->newval($section, $parameter, $res); -} - - -sub replace_num($$$) { - my ($cfg, $section, $parameter) = @_; - my $val = $cfg->val($section, $parameter); - my $res = ""; - - if (any_num_to_hex($val, \$res) != 0) { - ERR("[ ERROR: [$section]\n"); - ERR("[ Expecting a numeric value " . - "for parameter: $parameter\n"); - exit 1; - } - $cfg->newval($section, $parameter, $res); -} - -sub do_nothing($$$) { - my ($cfg, $section, $parameter) = @_; - return; -} - -sub bootenv_sanity_check($) { - my $env = shift; # hash array containing bootenv - my %pdd = (); - - defined($$env{'pdd'}) or return "'pdd' not defined"; - foreach (split /,/, $$env{'pdd'}) { - defined($$env{$_}) or return "undefined '$_' in pdd"; - $pdd{$_} = 1; - } - - defined $$env{'pdd_preserve'} or - return ""; - foreach (split /,/, $$env{'pdd_preserve'}) { - defined($pdd{$_}) - or return "pdd_preserve field '$_' not in pdd"; - } - return ""; -} - -sub create_bootenv_image($$$) { - my ($cfg, $section, $parameter) = @_; - my $txt_fn = $cfg->val($section, "bootenv_file"); - my $in; - - my %value = (); - my @key = (); - - open $in, "<", $txt_fn - or die "[ ERROR: can't open bootenv file '$txt_fn'.\n"; - while (<$in>) { - next if (/^\s*(\#.*)?$/); # Skip comments/whitespace. - - if (/^(\S+?)\+\=(.*)$/) { - defined($value{$1}) or - die "$txt_fn:$.: error: appending to" . - " non-existent '$1'\n"; - $value{$1} .= $2; - } elsif (/^(\S+?)\=(.*)$/) { - not defined($value{$1}) or - die "$txt_fn:$.: error: trying to" . - " redefine '$1'\n"; - push @key, $1; - $value{$1} = $2; - } else { - die "$txt_fn:$.: error: unrecognized syntax\n"; - } - } - close $in; - - $_ = &bootenv_sanity_check(\%value) - and die "$txt_fn: error: $_\n"; - - my $tmp_file = new File::Temp(); - push (@tmp_files, $tmp_file); - - foreach (@key) { - print $tmp_file "$_=", $value{$_}, "\0"; - } - close $tmp_file; - - $cfg->newval($section, "image", $tmp_file-> filename); -} - -sub process_keys($$$) { - my ($cfg, $section, $keys) = @_; - my @parameters = $cfg->Parameters($section); - my $i; - - for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { - if (defined($$keys{$parameters[$i]})) { - $$keys{$parameters[$i]}->($cfg, $section, - $parameters[$i]); - } - } - -} - -sub is_in_keylist($$) { - my ($key, $keys) = @_; - my $i; - - for ($i = 0; $i < scalar(@$keys); $i++) { - if ($$keys[$i] eq $key) { - return 1; - } - } - - return 0; -} - -sub check_default_keys($$$) { - my ($cfg, $section, $keys) = @_; - my @parameters = $cfg->Parameters($section); - my $key; - - foreach $key (keys %$keys) { - if (!is_in_keylist($key, \@parameters)) { - $$keys{$key}[0]-> - ($cfg, $section, $key, $$keys{$key}[1]); - } - } - -} - - - -sub check_keys($$$) { - my ($cfg, $section, $keys) = @_; - my @parameters = $cfg->Parameters($section); - my ($i, $key, $err); - - $err = 0; - for ($i = 0 ; $i < scalar(@$keys) ; $i++ ) { - if (!is_in_keylist($$keys[$i], \@parameters)) { - ERR("[ ERROR: [$section]\n") if $err == 0; - $err = 1; - ERR("[ Missing key '$$keys[$i]'\n"); - } - } - - if ($err) { - ERR("[ Aborting...\n"); - exit 1; - } -} - -sub push_pfi_data($$$$$) { - my ($cfg, $section, $pfi_infos, $keys, $mode) = @_; - my ($tmp, $i, $hdr); - - my %pfi_info = (); - $pfi_info{'mode'} = $mode; - $pfi_info{'image'} = $cfg->val($section, "image"); - - # Build the PFI header - $hdr = sprintf("PFI!\n"); - $hdr .= sprintf("version=0x%08x\n", hex $pfi_version); - $hdr .= sprintf("mode=$mode\n"); - - # calculate the size of the binary data part - $tmp = -s $cfg->val($section, "image"); - if (!defined $tmp) { - ERR("[ ERROR: [$section]\n"); - ERR("[ Missing input image: " - . $cfg->val($section, "image") . "\n"); - exit 1; - } - # Check for the image to fit into the given space - my $quota; - if ($mode eq 'raw') { - $quota = oct $cfg->val($section, "raw_total_size"); - } elsif ($mode eq 'ubi') { - $quota = oct $cfg->val($section, "ubi_size"); - } - $tmp <= $quota - or die "[ERROR: image file too big: " . - $cfg->val($section, "image") . "\n"; - $pfi_info{'size'} = $tmp; - - $hdr .= sprintf("size=0x%08x\n", $tmp); - - my $img_file = $cfg->val($section, "image"); - my $crc32 = `$tools{'ubicrc32'} $img_file 2>&1`; - if (any_num_to_hex($crc32, \$tmp) != 0) { - die "[ ERROR: $tools{'ubicrc32'} returned with errors"; - } - $hdr .= sprintf("crc=$tmp\n"); - - - # Process all remaining keys - for ($i = 0; $i < scalar (@$keys); $i++) { - if ($$keys[$i] eq "image") { # special case image input file - if (! -e ($tmp = $cfg->val($section, "image"))) { - ERR("[ ERROR: [$section]\n"); - ERR("[ Cannot find input file $tmp\n"); - exit 1; - } - next; - } - $hdr .= sprintf("%s=%s\n", $$keys[$i], - $cfg->val($section, $$keys[$i])); - } - - $hdr .= sprintf("\n"); # end marker for PFI-header - - $pfi_info{'header'} = $hdr; - - # store in the header list - push @$pfi_infos, \%pfi_info; -} - -sub process_section($$$$$$) { - my ($cfg, $section, $pfi_infos, $custom_keys, - $def_custom_keys, $mode) = @_; - my @keys = (keys %common_keys, keys %$custom_keys); - my @complete_keys = (@keys, keys %input_keys); - - # set defaults if necessary - check_default_keys($cfg, $section, $def_custom_keys); - check_default_keys($cfg, $section, \%def_common_keys); - - # check for placeholders... - process_keys($cfg, $section, \%input_placeholder_keys); - - # VALIDATE layout.cfg entries - check_keys($cfg, $section, \@complete_keys); - - # execute linked functions (if any) - process_keys($cfg, $section, \%common_keys); - process_keys($cfg, $section, $custom_keys); - - push_pfi_data($cfg, $section, $pfi_infos, \@keys, $mode); -} - -sub get_section_info($$) { - my ($cfg, $section) = @_; - my @parameters = $cfg->Parameters($section); - my ($ubi, $raw, $i, @res); - - $ubi = $raw = 0; - for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { - if ($parameters[$i] =~ m/ubi_/gi) { - $ubi = 1; - @res = (\%ubi_keys, \%def_ubi_keys, "ubi"); - } - if ($parameters[$i] =~ m/raw_/gi) { - $raw = 1; - @res = (\%raw_keys, \%def_raw_keys, "raw"); - } - } - - if (($ubi + $raw) != 1) { # double definition in section - ERR("[ ERROR: Layout error in section '$section'\n"); - exit 1; - } - - return @res; -} - -sub mk_target_list($$) { - my $val = shift; - my $tmp = shift; - my $complete = 0; - - if ($val =~ m/\((.*)\)/g) { - $val = $1; - $complete = 1; - } - $val =~ s/ //g; # spaces - - @$tmp = split(/,/, $val); - - return $complete; -} - -sub copy_bytes($$$) { - my ($in, $out, $to_copy) = @_; - - while ($to_copy) { - my $buf; - my $bufsize = 1024*1024; - - $bufsize < $to_copy or $bufsize = $to_copy; - read($in, $buf, $bufsize) == $bufsize - or die "[ ERROR: Image file shrunk during operation\n"; - print $out $buf; - $to_copy -= $bufsize; - } -} - -sub write_target($$) { - my ($pfi_infos, $target) = @_; - my ($pfi_info); - - INFO("[ Writting target pfi file: '$target.pfi'...\n"); - if (-e "$target.pfi") { - WARN("! Replaced old pfi...\n"); - `rm -f $target.pfi`; - } - open(FILE, ">", "$target.pfi") - or die "[ ERROR: Cannot create output file: $target.pfi\n"; - binmode(FILE); - - # @FIXME sort by mode (first raw, then ubi) - # Currently this ordering is based on a string comparism. :-) - @$pfi_infos = sort {(lc $$a{'mode'}) cmp (lc $$b{'mode'})} @$pfi_infos; - - # Print all headers first - foreach $pfi_info (@$pfi_infos) { - print FILE $$pfi_info{'header'}; - - } - # Print the linked data sections - print FILE "DATA\n"; - foreach $pfi_info (@$pfi_infos) { - open(IMAGE, "<", $$pfi_info{'image'}) - or die "[ ERROR: Cannot open input image: " . - "$$pfi_info{'image'}" . "\n"; - binmode(IMAGE); - ©_bytes(\*IMAGE, \*FILE, $$pfi_info{'size'}); - close(IMAGE) or die "[ ERROR: Cannot close input image: " . - "$$pfi_info{'image'}" . "\n"; - } - close(FILE) or die "[ ERROR: Cannot close output file: $target.pfi\n"; -} - -sub process_config($) { - my $cfg = shift; - my @sections = $cfg->Sections; - my ($i, $j, $keylist, $def_keylist, $mode, $tmp, - @tlist, $complete,@pfi_infos); - - my @parameters = $cfg->Parameters("targets") or - die "[ ERROR: Config file has no 'targets' section!\n"; - - for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { - INFO("[ Processing target '$parameters[$i]'...\n"); - @pfi_infos = (); - - # get a list of subtargets - $complete = mk_target_list($cfg->val("targets", - $parameters[$i]), \@tlist); - # build all subtargets - for ($j = 0 ; $j < scalar(@tlist) ; $j++ ) { - ($keylist, $def_keylist, $mode) - = get_section_info($cfg, $tlist[$j]); - process_section($cfg, $tlist[$j], - \@pfi_infos, - $keylist, $def_keylist, $mode); - } - - write_target(\@pfi_infos, $parameters[$i]); - } - - INFO("[ Success.\n"); - - -} - -sub clear_files() { - # @FIXME: - # Works implicitly and Fedora seems to have removed - # the cleanup call. Thus for now, inactive. - # File::Temp::cleanup(); -} - -require 5.008_000; # Tested with version 5.8.0. -select STDOUT; $| = 1; # make STDOUT output unbuffered -select STDERR; $| = 1; # make STDERR output unbuffered - -parse_command_line(\%opts); -check_tools; -$cfg = open_cfg_file($opts{config}); -process_config($cfg); -clear_files; - -__END__ - - -=head1 NAME - -mkpfi - Using GetOpt::Long, Pod::Usage, Config::IniFiles - - -=head1 SYNOPSIS - -mkpfi [OPTIONS ...] - - - OPTION - - [--config] [--help] [--man] - - -=head1 ABSTRACT - -Perl script for generating pdd pfi files from given config files. - -=head1 OPTIONS - -=over - -=item B<--help> - -Print out brief help message. - -=item B<--usage> - -Print usage. - -=item B<--config> - -Config input file. - -=item B<--man> - -Print manual page, same as 'perldoc mkpfi'. - -=item B<--verbose> - -Be verbose! - -=back - -=head1 BUGS - -Report via MTD mailing list - - -=head1 SEE ALSO - -http://www.linux-mtd.infradead.org/ - - -=head1 AUTHOR - -Oliver Lohmann (oliloh@de.ibm.com) - -=cut diff --git a/ubi-utils/src/nand2bin.c b/ubi-utils/src/nand2bin.c new file mode 100644 index 0000000..a5e8bca --- /dev/null +++ b/ubi-utils/src/nand2bin.c @@ -0,0 +1,328 @@ +/* + * 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 decompose NAND images and strip OOB off. Not yet finished ... + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "nandecc.h" + +#define MAXPATH 1024 +#define MIN(x,y) ((x)<(y)?(x):(y)) + +struct args { + const char *oob_file; + const char *output_file; + size_t pagesize; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +}; + +static struct args myargs = { + .output_file = "data.bin", + .oob_file = "oob.bin", + .pagesize = 2048, + .arg1 = NULL, + .options = NULL, +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\t" + BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" + "\nSplit data and OOB.\n"; + +static struct argp_option options[] = { + { .name = "pagesize", + .key = 'p', + .arg = "", + .flags = 0, + .doc = "NAND pagesize", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "output", + .key = 'o', + .arg = "", + .flags = 0, + .doc = "Data output file", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "oob", + .key = 'O', + .arg = "", + .flags = 0, + .doc = "OOB output file", + .group = OPTION_ARG_OPTIONAL }, + + { .name = NULL, .key = 0, .arg = NULL, .flags = 0, + .doc = NULL, .group = 0 }, +}; + +static struct argp argp = { + .options = options, + .parser = parse_opt, + .args_doc = "input.mif", + .doc = doc, + .children = NULL, + .help_filter = NULL, + .argp_domain = NULL, +}; + +/* + * str_to_num - Convert string into number and cope with endings like + * k, K, kib, KiB for kilobyte + * m, M, mib, MiB for megabyte + */ +uint32_t str_to_num(char *str) +{ + char *s = str; + ulong num = strtoul(s, &s, 0); + + if (*s != '\0') { + if (strcmp(s, "KiB") == 0) + num *= 1024; + else if (strcmp(s, "MiB") == 0) + num *= 1024*1024; + else { + fprintf(stderr, "WARNING: Wrong number format " + "\"%s\", check your paramters!\n", str); + } + } + return num; +} + +/* + * @brief Parse the arguments passed into the test case. + * + * @param key The parameter. + * @param arg Argument passed to parameter. + * @param state Location to put information on parameters. + * + * @return error + * + * Get the `input' argument from `argp_parse', which we know is a + * pointer to our arguments structure. + */ +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + struct args *args = state->input; + + switch (key) { + case 'p': /* --pagesize */ + args->pagesize = str_to_num(arg); break; + + case 'o': /* --output= */ + args->output_file = arg; + break; + + case 'O': /* --oob= */ + args->output_file = arg; + break; + + case ARGP_KEY_NO_ARGS: + /* argp_usage(state); */ + break; + + case ARGP_KEY_ARG: + args->arg1 = arg; + /* Now we consume all the rest of the arguments. + `state->next' is the index in `state->argv' of the + next argument to be parsed, which is the first STRING + we're interested in, so we can just use + `&state->argv[state->next]' as the value for + arguments->strings. + + _In addition_, by setting `state->next' to the end + of the arguments, we can force argp to stop parsing here and + return. */ + + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + + case ARGP_KEY_END: + /* argp_usage(state); */ + break; + + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static int calc_oobsize(size_t pagesize) +{ + switch (pagesize) { + case 512: return 16; + case 2048: return 64; + default: + exit(EXIT_FAILURE); + } + return 0; +} + +static inline void +hexdump(FILE *fp, const uint8_t *buf, ssize_t size) +{ + int k; + + for (k = 0; k < size; k++) { + fprintf(fp, "%02x ", buf[k]); + if ((k & 15) == 15) + fprintf(fp, "\n"); + } +} + +static int +process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize) +{ + int eccpoi, oobsize; + size_t i; + + switch (pagesize) { + case 2048: oobsize = 64; eccpoi = 64 / 2; break; + case 512: oobsize = 16; eccpoi = 16 / 2; break; + default: + fprintf(stderr, "Unsupported page size: %d\n", pagesize); + return -EINVAL; + } + memset(oobbuf, 0xff, oobsize); + + for (i = 0; i < pagesize; i += 256, eccpoi += 3) { + oobbuf[eccpoi++] = 0x0; + /* Calculate ECC */ + nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); + } + return 0; +} + +static int decompose_image(FILE *in_fp, FILE *bin_fp, FILE *oob_fp, + size_t pagesize) +{ + int read, rc, page = 0; + size_t oobsize = calc_oobsize(pagesize); + uint8_t *buf = malloc(pagesize); + uint8_t *oob = malloc(oobsize); + uint8_t *calc_oob = malloc(oobsize); + uint8_t *calc_buf = malloc(pagesize); + + if (!buf) + exit(EXIT_FAILURE); + if (!oob) + exit(EXIT_FAILURE); + if (!calc_oob) + exit(EXIT_FAILURE); + if (!calc_buf) + exit(EXIT_FAILURE); + + while (!feof(in_fp)) { + read = fread(buf, 1, pagesize, in_fp); + if (ferror(in_fp)) { + fprintf(stderr, "I/O Error."); + exit(EXIT_FAILURE); + } + rc = fwrite(buf, 1, pagesize, bin_fp); + if (ferror(bin_fp)) { + fprintf(stderr, "I/O Error."); + exit(EXIT_FAILURE); + } + read = fread(oob, 1, oobsize, in_fp); + if (ferror(in_fp)) { + fprintf(stderr, "I/O Error."); + exit(EXIT_FAILURE); + } + rc = fwrite(oob, 1, oobsize, oob_fp); + if (ferror(bin_fp)) { + fprintf(stderr, "I/O Error."); + exit(EXIT_FAILURE); + } + process_page(buf, calc_oob, pagesize); + + memcpy(calc_buf, buf, pagesize); + + rc = nand_correct_data(calc_buf, oob); + if ((rc != -1) || (memcmp(buf, calc_buf, pagesize) != 0)) { + fprintf(stdout, "Page %d: data does not match!\n", + page); + } + page++; + } + free(calc_buf); + free(calc_oob); + free(oob); + free(buf); + return 0; +} + +int +main(int argc, char *argv[]) +{ + FILE *in, *bin, *oob; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); + + if (!myargs.arg1) { + fprintf(stderr, "Please specify input file!\n"); + exit(EXIT_FAILURE); + } + + in = fopen(myargs.arg1, "r"); + if (!in) { + perror("Cannot open file"); + exit(EXIT_FAILURE); + } + bin = fopen(myargs.output_file, "w+"); + if (!bin) { + perror("Cannot open file"); + exit(EXIT_FAILURE); + } + oob = fopen(myargs.oob_file, "w+"); + if (!oob) { + perror("Cannot open file"); + exit(EXIT_FAILURE); + } + + decompose_image(in, bin, oob, myargs.pagesize); + + fclose(in); + fclose(bin); + fclose(oob); + + exit(EXIT_SUCCESS); +} diff --git a/ubi-utils/src/nand2bin/nand2bin.c b/ubi-utils/src/nand2bin/nand2bin.c deleted file mode 100644 index a728fb5..0000000 --- a/ubi-utils/src/nand2bin/nand2bin.c +++ /dev/null @@ -1,327 +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 decompose NAND images and strip OOB off. Not yet finished ... - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nandecc.h" - -#define MAXPATH 1024 -#define MIN(x,y) ((x)<(y)?(x):(y)) - -struct args { - const char *oob_file; - const char *output_file; - size_t pagesize; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -}; - -static struct args myargs = { - .output_file = "data.bin", - .oob_file = "oob.bin", - .pagesize = 2048, - .arg1 = NULL, - .options = NULL, -}; - -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -const char *argp_program_bug_address = ""; - -static char doc[] = "\nVersion: " VERSION "\n\t" - HOST_OS" "HOST_CPU" at "__DATE__" "__TIME__"\n" - "\nSplit data and OOB.\n"; - -static struct argp_option options[] = { - { .name = "pagesize", - .key = 'p', - .arg = "", - .flags = 0, - .doc = "NAND pagesize", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "output", - .key = 'o', - .arg = "", - .flags = 0, - .doc = "Data output file", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "oob", - .key = 'O', - .arg = "", - .flags = 0, - .doc = "OOB output file", - .group = OPTION_ARG_OPTIONAL }, - - { .name = NULL, .key = 0, .arg = NULL, .flags = 0, - .doc = NULL, .group = 0 }, -}; - -static struct argp argp = { - .options = options, - .parser = parse_opt, - .args_doc = "input.mif", - .doc = doc, - .children = NULL, - .help_filter = NULL, - .argp_domain = NULL, -}; - -/* - * str_to_num - Convert string into number and cope with endings like - * k, K, kib, KiB for kilobyte - * m, M, mib, MiB for megabyte - */ -uint32_t str_to_num(char *str) -{ - char *s = str; - ulong num = strtoul(s, &s, 0); - - if (*s != '\0') { - if (strcmp(s, "KiB") == 0) - num *= 1024; - else if (strcmp(s, "MiB") == 0) - num *= 1024*1024; - else { - fprintf(stderr, "WARNING: Wrong number format " - "\"%s\", check your paramters!\n", str); - } - } - return num; -} - -/* - * @brief Parse the arguments passed into the test case. - * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. - * - * @return error - * - * Get the `input' argument from `argp_parse', which we know is a - * pointer to our arguments structure. - */ -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - struct args *args = state->input; - - switch (key) { - case 'p': /* --pagesize */ - args->pagesize = str_to_num(arg); break; - - case 'o': /* --output= */ - args->output_file = arg; - break; - - case 'O': /* --oob= */ - args->output_file = arg; - break; - - case ARGP_KEY_NO_ARGS: - /* argp_usage(state); */ - break; - - case ARGP_KEY_ARG: - args->arg1 = arg; - /* Now we consume all the rest of the arguments. - `state->next' is the index in `state->argv' of the - next argument to be parsed, which is the first STRING - we're interested in, so we can just use - `&state->argv[state->next]' as the value for - arguments->strings. - - _In addition_, by setting `state->next' to the end - of the arguments, we can force argp to stop parsing here and - return. */ - - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - - case ARGP_KEY_END: - /* argp_usage(state); */ - break; - - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static int calc_oobsize(size_t pagesize) -{ - switch (pagesize) { - case 512: return 16; - case 2048: return 64; - default: - exit(EXIT_FAILURE); - } - return 0; -} - -static inline void -hexdump(FILE *fp, const uint8_t *buf, size_t size) -{ - int k; - - for (k = 0; k < size; k++) { - fprintf(fp, "%02x ", buf[k]); - if ((k & 15) == 15) - fprintf(fp, "\n"); - } -} - -static int -process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize) -{ - int eccpoi, oobsize; - size_t i; - - switch (pagesize) { - case 2048: oobsize = 64; eccpoi = 64 / 2; break; - case 512: oobsize = 16; eccpoi = 16 / 2; break; - default: - fprintf(stderr, "Unsupported page size: %d\n", pagesize); - return -EINVAL; - } - memset(oobbuf, 0xff, oobsize); - - for (i = 0; i < pagesize; i += 256, eccpoi += 3) { - oobbuf[eccpoi++] = 0x0; - /* Calculate ECC */ - nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); - } - return 0; -} - -static int decompose_image(FILE *in_fp, FILE *bin_fp, FILE *oob_fp, - size_t pagesize) -{ - int read, rc, page = 0; - size_t oobsize = calc_oobsize(pagesize); - uint8_t *buf = malloc(pagesize); - uint8_t *oob = malloc(oobsize); - uint8_t *calc_oob = malloc(oobsize); - uint8_t *calc_buf = malloc(pagesize); - - if (!buf) - exit(EXIT_FAILURE); - if (!oob) - exit(EXIT_FAILURE); - if (!calc_oob) - exit(EXIT_FAILURE); - if (!calc_buf) - exit(EXIT_FAILURE); - - while (!feof(in_fp)) { - read = fread(buf, 1, pagesize, in_fp); - if (ferror(in_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - rc = fwrite(buf, 1, pagesize, bin_fp); - if (ferror(bin_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - read = fread(oob, 1, oobsize, in_fp); - if (ferror(in_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - rc = fwrite(oob, 1, oobsize, oob_fp); - if (ferror(bin_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - process_page(buf, calc_oob, pagesize); - - memcpy(calc_buf, buf, pagesize); - - rc = nand_correct_data(calc_buf, oob); - if ((rc != -1) || (memcmp(buf, calc_buf, pagesize) != 0)) { - fprintf(stdout, "Page %d: data does not match!\n", - page); - } - page++; - } - free(calc_buf); - free(calc_oob); - free(oob); - free(buf); - return 0; -} - -int -main(int argc, char *argv[]) -{ - FILE *in, *bin, *oob; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); - - if (!myargs.arg1) { - fprintf(stderr, "Please specify input file!\n"); - exit(EXIT_FAILURE); - } - - in = fopen(myargs.arg1, "r"); - if (!in) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - bin = fopen(myargs.output_file, "w+"); - if (!bin) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - oob = fopen(myargs.oob_file, "w+"); - if (!oob) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - - decompose_image(in, bin, oob, myargs.pagesize); - - fclose(in); - fclose(bin); - fclose(oob); - - exit(EXIT_SUCCESS); -} diff --git a/ubi-utils/src/nand2bin/nandcorr.c b/ubi-utils/src/nand2bin/nandcorr.c deleted file mode 100644 index 7f1a547..0000000 --- a/ubi-utils/src/nand2bin/nandcorr.c +++ /dev/null @@ -1,85 +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. - */ - -/* - * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in - * a 256 bytes of data. - * - * Reimplement by Thomas Gleixner after staring long enough at the - * mess in drivers/mtd/nand/nandecc.c - * - */ - -#include "nandecc.h" - -static int countbits(uint32_t byte) -{ - int res = 0; - - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; -} - -int nand_correct_data(uint8_t *dat, const uint8_t *fail_ecc) - -{ - uint8_t s0, s1, s2; - - /* - * Do error detection - * - * Be careful, the index magic is due to a pointer to a - * uint32_t. - */ - s0 = fail_ecc[1]; - s1 = fail_ecc[2]; - s2 = fail_ecc[3]; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - - uint32_t byteoffs, bitnum; - - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; - - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; - - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; - - dat[byteoffs] ^= (1 << bitnum); - - return 1; - } - - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; - - return -1; -} - diff --git a/ubi-utils/src/nandcorr.c b/ubi-utils/src/nandcorr.c new file mode 100644 index 0000000..7f1a547 --- /dev/null +++ b/ubi-utils/src/nandcorr.c @@ -0,0 +1,85 @@ +/* + * 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. + */ + +/* + * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in + * a 256 bytes of data. + * + * Reimplement by Thomas Gleixner after staring long enough at the + * mess in drivers/mtd/nand/nandecc.c + * + */ + +#include "nandecc.h" + +static int countbits(uint32_t byte) +{ + int res = 0; + + for (;byte; byte >>= 1) + res += byte & 0x01; + return res; +} + +int nand_correct_data(uint8_t *dat, const uint8_t *fail_ecc) + +{ + uint8_t s0, s1, s2; + + /* + * Do error detection + * + * Be careful, the index magic is due to a pointer to a + * uint32_t. + */ + s0 = fail_ecc[1]; + s1 = fail_ecc[2]; + s2 = fail_ecc[3]; + + /* Check for a single bit error */ + if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && + ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && + ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { + + uint32_t byteoffs, bitnum; + + byteoffs = (s1 << 0) & 0x80; + byteoffs |= (s1 << 1) & 0x40; + byteoffs |= (s1 << 2) & 0x20; + byteoffs |= (s1 << 3) & 0x10; + + byteoffs |= (s0 >> 4) & 0x08; + byteoffs |= (s0 >> 3) & 0x04; + byteoffs |= (s0 >> 2) & 0x02; + byteoffs |= (s0 >> 1) & 0x01; + + bitnum = (s2 >> 5) & 0x04; + bitnum |= (s2 >> 4) & 0x02; + bitnum |= (s2 >> 3) & 0x01; + + dat[byteoffs] ^= (1 << bitnum); + + return 1; + } + + if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) + return 1; + + return -1; +} + diff --git a/ubi-utils/src/nandecc.c b/ubi-utils/src/nandecc.c new file mode 100644 index 0000000..71660ef --- /dev/null +++ b/ubi-utils/src/nandecc.c @@ -0,0 +1,159 @@ +/* + * This file contains an ECC algorithm from Toshiba that detects and + * corrects 1 bit errors in a 256 byte block of data. + * + * drivers/mtd/nand/nand_ecc.c + * + * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) + * Toshiba America Electronics Components, Inc. + * + * This file 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 or (at your option) any + * later version. + * + * This file 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 file; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or use + * macros or inline functions from these files, or you compile these + * files and link them with other works to produce a work based on these + * files, these files do not by themselves cause the resulting work to be + * covered by the GNU General Public License. However the source code for + * these files must still be made available in accordance with section (3) + * of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + */ + +#include "nandecc.h" + +/* + * Pre-calculated 256-way 1 byte column parity + */ +static const uint8_t nand_ecc_precalc_table[] = { + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, + 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, + 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, + 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, + 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, + 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, + 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, + 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, + 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 +}; + +/** + * nand_trans_result - [GENERIC] create non-inverted ECC + * @reg2: line parity reg 2 + * @reg3: line parity reg 3 + * @ecc_code: ecc + * + * Creates non-inverted ECC code from line parity + */ +static void nand_trans_result(uint8_t reg2, uint8_t reg3, + uint8_t *ecc_code) +{ + uint8_t a, b, i, tmp1, tmp2; + + /* Initialize variables */ + a = b = 0x80; + tmp1 = tmp2 = 0; + + /* Calculate first ECC byte */ + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + a >>= 1; + } + + /* Calculate second ECC byte */ + b = 0x80; + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + a >>= 1; + } + + /* Store two of the ECC bytes */ + ecc_code[1] = tmp1; + ecc_code[0] = tmp2; +} + +/** + * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for + * 256 byte block + * + * @dat: raw data + * @ecc_code: buffer for ECC + */ +int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code) +{ + uint8_t idx, reg1, reg2, reg3; + int j; + + /* Initialize variables */ + reg1 = reg2 = reg3 = 0; + ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; + + /* Build up column parity */ + for(j = 0; j < 256; j++) { + + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[dat[j]]; + reg1 ^= (idx & 0x3f); + + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (uint8_t) j; + reg2 ^= ~((uint8_t) j); + } + } + + /* Create non-inverted ECC code from line parity */ + nand_trans_result(reg2, reg3, ecc_code); + + /* Calculate final ECC code */ + ecc_code[0] = ~ecc_code[0]; + ecc_code[1] = ~ecc_code[1]; + ecc_code[2] = ((~reg1) << 2) | 0x03; + return 0; +} diff --git a/ubi-utils/src/nandecc.h b/ubi-utils/src/nandecc.h new file mode 100644 index 0000000..fb5d529 --- /dev/null +++ b/ubi-utils/src/nandecc.h @@ -0,0 +1,28 @@ +#ifndef _NAND_ECC_H +#define _NAND_ECC_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. + * + * NAND ecc functions + */ + +#include + +extern int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code); +extern int nand_correct_data(uint8_t *dat, const uint8_t *fail_ecc); + +#endif diff --git a/ubi-utils/src/pddcustomize.c b/ubi-utils/src/pddcustomize.c new file mode 100644 index 0000000..f71d916 --- /dev/null +++ b/ubi-utils/src/pddcustomize.c @@ -0,0 +1,496 @@ +/* + * 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 + * + * PDD (platform description data) contains a set of system specific + * boot-parameters. Some of those parameters need to be handled + * special on updates, e.g. the MAC addresses. They must also be kept + * if the system is updated and one must be able to modify them when + * the system has booted the first time. This tool is intended to do + * PDD modification. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "bootenv.h" +#include "error.h" +#include "example_ubi.h" +#include "libubi.h" +#include "ubimirror.h" + +typedef enum action_t { + ACT_NORMAL = 0, + ACT_LIST, + ACT_ARGP_ABORT, + ACT_ARGP_ERR, +} action_t; + +#define ABORT_ARGP do { \ + state->next = state->argc; \ + args->action = ACT_ARGP_ABORT; \ +} while (0) + +#define ERR_ARGP do { \ + state->next = state->argc; \ + args->action = ACT_ARGP_ERR; \ +} while (0) + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "pddcustomize - customize bootenv and pdd values.\n"; + +static const char copyright [] __attribute__((unused)) = + "FIXME: insert license type"; /* FIXME */ + +static struct argp_option options[] = { + { name: "copyright", key: 'c', arg: NULL, flags: 0, + doc: "Print copyright information.", + group: 1 }, + + { name: "input", key: 'i', arg: "", flags: 0, + doc: "Binary input file. For debug purposes.", + group: 1 }, + + { name: "output", key: 'o', arg: "", flags: 0, + doc: "Binary output file. For debug purposes.", + group: 1 }, + + { name: "list", key: 'l', arg: NULL, flags: 0, + doc: "List card bootenv/pdd values.", + group: 1 }, + + { name: "both", key: 'b', arg: NULL, flags: 0, + doc: "Mirror updated PDD to redundand copy.", + group: 1 }, + + { name: "side", key: 's', arg: "", flags: 0, + doc: "The side/seqnum to update.", + group: 1 }, + + { name: "host", key: 'x', arg: NULL, flags: 0, + doc: "use x86 platform for debugging.", + group: 1 }, + + { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, +}; + +typedef struct myargs { + action_t action; + const char* file_in; + const char* file_out; + int both; + int side; + int x86; /* X86 host, use files for testing */ + bootenv_t env_in; + + char *arg1; + char **options; /* [STRING...] */ +} myargs; + +static int +get_update_side(const char* str) +{ + uint32_t i = strtoul(str, NULL, 0); + + if ((i != 0) && (i != 1)) { + return -1; + } + + return i; +} + +static int +extract_pair(bootenv_t env, const char* str) +{ + int rc = 0; + char* key; + char* val; + + key = strdup(str); + if (key == NULL) + return -ENOMEM; + + val = strstr(key, "="); + if (val == NULL) { + err_msg("Wrong argument: %s\n" + "Expecting key=value pair.\n", str); + rc = -1; + goto err; + } + + *val = '\0'; /* split strings */ + val++; + rc = bootenv_set(env, key, val); + +err: + free(key); + return rc; +} + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + int rc = 0; + int err = 0; + + myargs *args = state->input; + + switch (key) { + case 'c': + err_msg("%s\n", copyright); + ABORT_ARGP; + break; + case 'l': + args->action = ACT_LIST; + break; + case 'b': + args->both = 1; + break; + case 'x': + args->x86 = 1; + break; + case 's': + args->side = get_update_side(arg); + if (args->side < 0) { + err_msg("Unsupported seqnum: %d.\n" + "Supported seqnums are '0' and '1'\n", + args->side, arg); + ERR_ARGP; + } + break; + case 'i': + args->file_in = arg; + break; + case 'o': + args->file_out = arg; + break; + case ARGP_KEY_ARG: + rc = extract_pair(args->env_in, arg); + if (rc != 0) + ERR_ARGP; + break; + case ARGP_KEY_END: + if (err) { + err_msg("\n"); + argp_usage(state); + ERR_ARGP; + } + break; + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: "[key=value] [...]", + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + + +static int +list_bootenv(bootenv_t env) +{ + int rc = 0; + rc = bootenv_write_txt(stdout, env); + if (rc != 0) { + err_msg("Cannot list bootenv/pdd. rc: %d\n", rc); + goto err; + } +err: + return rc; +} + +static int +process_key_value(bootenv_t env_in, bootenv_t env) +{ + int rc = 0; + size_t size, i; + const char* tmp; + const char** key_vec = NULL; + + rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec); + if (rc != 0) + goto err; + + for (i = 0; i < size; i++) { + rc = bootenv_get(env_in, key_vec[i], &tmp); + if (rc != 0) { + err_msg("Cannot read value to input key: %s. rc: %d\n", + key_vec[i], rc); + goto err; + } + rc = bootenv_set(env, key_vec[i], tmp); + if (rc != 0) { + err_msg("Cannot set value key: %s. rc: %d\n", + key_vec[i], rc); + goto err; + } + } + +err: + if (key_vec != NULL) + free(key_vec); + return rc; +} + +static int +read_bootenv(const char* file, bootenv_t env) +{ + int rc = 0; + FILE* fp_in = NULL; + + fp_in = fopen(file, "rb"); + if (fp_in == NULL) { + err_msg("Cannot open file: %s\n", file); + return -EIO; + } + + rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); + if (rc != 0) { + err_msg("Cannot read bootenv from file %s. rc: %d\n", + file, rc); + goto err; + } + +err: + fclose(fp_in); + return rc; +} + +/* + * Read bootenv from ubi volume + */ +static int +ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env) +{ + ubi_lib_t ulib = NULL; + int rc = 0; + FILE* fp_in = NULL; + + rc = ubi_open(&ulib); + if( rc ){ + err_msg("Cannot allocate ubi structure\n"); + return rc; + } + + fp_in = ubi_vol_fopen_read(ulib, devno, id); + if (fp_in == NULL) { + err_msg("Cannot open volume:%d number:%d\n", devno, id); + goto err; + } + + rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); + if (rc != 0) { + err_msg("Cannot read volume:%d number:%d\n", devno, id); + goto err; + } + +err: + if( fp_in ) + fclose(fp_in); + ubi_close(&ulib); + return rc; +} + +static int +write_bootenv(const char* file, bootenv_t env) +{ + int rc = 0; + FILE* fp_out; + + fp_out = fopen(file, "wb"); + if (fp_out == NULL) { + err_msg("Cannot open file: %s\n", file); + return -EIO; + } + + rc = bootenv_write(fp_out, env); + if (rc != 0) { + err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc); + goto err; + } + +err: + fclose(fp_out); + return rc; +} + +/* + * Read bootenv from ubi volume + */ +static int +ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env) +{ + ubi_lib_t ulib = NULL; + int rc = 0; + FILE* fp_out; + size_t nbytes ; + + rc = bootenv_size(env, &nbytes); + if( rc ){ + err_msg("Cannot determine size of bootenv structure\n"); + return rc; + } + rc = ubi_open(&ulib); + if( rc ){ + err_msg("Cannot allocate ubi structure\n"); + return rc; + } + fp_out = ubi_vol_fopen_update(ulib, devno, id, + (unsigned long long)nbytes); + if (fp_out == NULL) { + err_msg("Cannot open volume:%d number:%d\n", devno, id); + goto err; + } + + rc = bootenv_write(fp_out, env); + if (rc != 0) { + err_msg("Cannot write bootenv to volume %d number:%d\n", + devno, id); + goto err; + } + +err: + if( fp_out ) + fclose(fp_out); + ubi_close(&ulib); + return rc; +} + +static int +do_mirror(int volno) +{ + char errbuf[1024]; + uint32_t ids[2]; + int rc; + int src_volno_idx = 0; + + ids[0] = EXAMPLE_BOOTENV_VOL_ID_1; + ids[1] = EXAMPLE_BOOTENV_VOL_ID_2; + + if (volno == EXAMPLE_BOOTENV_VOL_ID_2) + src_volno_idx = 1; + + rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf, + sizeof errbuf); + if( rc ) + err_msg(errbuf); + return rc; +} + +int +main(int argc, char **argv) { + int rc = 0; + bootenv_t env = NULL; + uint32_t boot_volno; + myargs args = { + .action = ACT_NORMAL, + .file_in = NULL, + .file_out = NULL, + .side = -1, + .x86 = 0, + .both = 0, + .env_in = NULL, + + .arg1 = NULL, + .options = NULL, + }; + + rc = bootenv_create(&env); + if (rc != 0) { + err_msg("Cannot create bootenv handle. rc: %d", rc); + goto err; + } + + rc = bootenv_create(&(args.env_in)); + if (rc != 0) { + err_msg("Cannot create bootenv handle. rc: %d", rc); + goto err; + } + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + if (args.action == ACT_ARGP_ERR) { + rc = -1; + goto err; + } + if (args.action == ACT_ARGP_ABORT) { + rc = 0; + goto out; + } + + if ((args.side == 0) || (args.side == -1)) + boot_volno = EXAMPLE_BOOTENV_VOL_ID_1; + else + boot_volno = EXAMPLE_BOOTENV_VOL_ID_2; + + if( args.x86 ) + rc = read_bootenv(args.file_in, env); + else + rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); + if (rc != 0) { + goto err; + } + + if (args.action == ACT_LIST) { + rc = list_bootenv(env); + if (rc != 0) { + goto err; + } + goto out; + } + + rc = process_key_value(args.env_in, env); + if (rc != 0) { + goto err; + } + + if( args.x86 ) + rc = write_bootenv(args.file_in, env); + else + rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); + if (rc != 0) { + goto err; + } + if( args.both ) /* No side specified, update both */ + rc = do_mirror(boot_volno); + + out: + err: + bootenv_destroy(&env); + bootenv_destroy(&(args.env_in)); + return rc; +} diff --git a/ubi-utils/src/pddcustomize/pddcustomize.c b/ubi-utils/src/pddcustomize/pddcustomize.c deleted file mode 100644 index f71d916..0000000 --- a/ubi-utils/src/pddcustomize/pddcustomize.c +++ /dev/null @@ -1,496 +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 - * - * PDD (platform description data) contains a set of system specific - * boot-parameters. Some of those parameters need to be handled - * special on updates, e.g. the MAC addresses. They must also be kept - * if the system is updated and one must be able to modify them when - * the system has booted the first time. This tool is intended to do - * PDD modification. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "bootenv.h" -#include "error.h" -#include "example_ubi.h" -#include "libubi.h" -#include "ubimirror.h" - -typedef enum action_t { - ACT_NORMAL = 0, - ACT_LIST, - ACT_ARGP_ABORT, - ACT_ARGP_ERR, -} action_t; - -#define ABORT_ARGP do { \ - state->next = state->argc; \ - args->action = ACT_ARGP_ABORT; \ -} while (0) - -#define ERR_ARGP do { \ - state->next = state->argc; \ - args->action = ACT_ARGP_ERR; \ -} while (0) - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "pddcustomize - customize bootenv and pdd values.\n"; - -static const char copyright [] __attribute__((unused)) = - "FIXME: insert license type"; /* FIXME */ - -static struct argp_option options[] = { - { name: "copyright", key: 'c', arg: NULL, flags: 0, - doc: "Print copyright information.", - group: 1 }, - - { name: "input", key: 'i', arg: "", flags: 0, - doc: "Binary input file. For debug purposes.", - group: 1 }, - - { name: "output", key: 'o', arg: "", flags: 0, - doc: "Binary output file. For debug purposes.", - group: 1 }, - - { name: "list", key: 'l', arg: NULL, flags: 0, - doc: "List card bootenv/pdd values.", - group: 1 }, - - { name: "both", key: 'b', arg: NULL, flags: 0, - doc: "Mirror updated PDD to redundand copy.", - group: 1 }, - - { name: "side", key: 's', arg: "", flags: 0, - doc: "The side/seqnum to update.", - group: 1 }, - - { name: "host", key: 'x', arg: NULL, flags: 0, - doc: "use x86 platform for debugging.", - group: 1 }, - - { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, -}; - -typedef struct myargs { - action_t action; - const char* file_in; - const char* file_out; - int both; - int side; - int x86; /* X86 host, use files for testing */ - bootenv_t env_in; - - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static int -get_update_side(const char* str) -{ - uint32_t i = strtoul(str, NULL, 0); - - if ((i != 0) && (i != 1)) { - return -1; - } - - return i; -} - -static int -extract_pair(bootenv_t env, const char* str) -{ - int rc = 0; - char* key; - char* val; - - key = strdup(str); - if (key == NULL) - return -ENOMEM; - - val = strstr(key, "="); - if (val == NULL) { - err_msg("Wrong argument: %s\n" - "Expecting key=value pair.\n", str); - rc = -1; - goto err; - } - - *val = '\0'; /* split strings */ - val++; - rc = bootenv_set(env, key, val); - -err: - free(key); - return rc; -} - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - int rc = 0; - int err = 0; - - myargs *args = state->input; - - switch (key) { - case 'c': - err_msg("%s\n", copyright); - ABORT_ARGP; - break; - case 'l': - args->action = ACT_LIST; - break; - case 'b': - args->both = 1; - break; - case 'x': - args->x86 = 1; - break; - case 's': - args->side = get_update_side(arg); - if (args->side < 0) { - err_msg("Unsupported seqnum: %d.\n" - "Supported seqnums are '0' and '1'\n", - args->side, arg); - ERR_ARGP; - } - break; - case 'i': - args->file_in = arg; - break; - case 'o': - args->file_out = arg; - break; - case ARGP_KEY_ARG: - rc = extract_pair(args->env_in, arg); - if (rc != 0) - ERR_ARGP; - break; - case ARGP_KEY_END: - if (err) { - err_msg("\n"); - argp_usage(state); - ERR_ARGP; - } - break; - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: "[key=value] [...]", - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - - -static int -list_bootenv(bootenv_t env) -{ - int rc = 0; - rc = bootenv_write_txt(stdout, env); - if (rc != 0) { - err_msg("Cannot list bootenv/pdd. rc: %d\n", rc); - goto err; - } -err: - return rc; -} - -static int -process_key_value(bootenv_t env_in, bootenv_t env) -{ - int rc = 0; - size_t size, i; - const char* tmp; - const char** key_vec = NULL; - - rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec); - if (rc != 0) - goto err; - - for (i = 0; i < size; i++) { - rc = bootenv_get(env_in, key_vec[i], &tmp); - if (rc != 0) { - err_msg("Cannot read value to input key: %s. rc: %d\n", - key_vec[i], rc); - goto err; - } - rc = bootenv_set(env, key_vec[i], tmp); - if (rc != 0) { - err_msg("Cannot set value key: %s. rc: %d\n", - key_vec[i], rc); - goto err; - } - } - -err: - if (key_vec != NULL) - free(key_vec); - return rc; -} - -static int -read_bootenv(const char* file, bootenv_t env) -{ - int rc = 0; - FILE* fp_in = NULL; - - fp_in = fopen(file, "rb"); - if (fp_in == NULL) { - err_msg("Cannot open file: %s\n", file); - return -EIO; - } - - rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); - if (rc != 0) { - err_msg("Cannot read bootenv from file %s. rc: %d\n", - file, rc); - goto err; - } - -err: - fclose(fp_in); - return rc; -} - -/* - * Read bootenv from ubi volume - */ -static int -ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -{ - ubi_lib_t ulib = NULL; - int rc = 0; - FILE* fp_in = NULL; - - rc = ubi_open(&ulib); - if( rc ){ - err_msg("Cannot allocate ubi structure\n"); - return rc; - } - - fp_in = ubi_vol_fopen_read(ulib, devno, id); - if (fp_in == NULL) { - err_msg("Cannot open volume:%d number:%d\n", devno, id); - goto err; - } - - rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); - if (rc != 0) { - err_msg("Cannot read volume:%d number:%d\n", devno, id); - goto err; - } - -err: - if( fp_in ) - fclose(fp_in); - ubi_close(&ulib); - return rc; -} - -static int -write_bootenv(const char* file, bootenv_t env) -{ - int rc = 0; - FILE* fp_out; - - fp_out = fopen(file, "wb"); - if (fp_out == NULL) { - err_msg("Cannot open file: %s\n", file); - return -EIO; - } - - rc = bootenv_write(fp_out, env); - if (rc != 0) { - err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc); - goto err; - } - -err: - fclose(fp_out); - return rc; -} - -/* - * Read bootenv from ubi volume - */ -static int -ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -{ - ubi_lib_t ulib = NULL; - int rc = 0; - FILE* fp_out; - size_t nbytes ; - - rc = bootenv_size(env, &nbytes); - if( rc ){ - err_msg("Cannot determine size of bootenv structure\n"); - return rc; - } - rc = ubi_open(&ulib); - if( rc ){ - err_msg("Cannot allocate ubi structure\n"); - return rc; - } - fp_out = ubi_vol_fopen_update(ulib, devno, id, - (unsigned long long)nbytes); - if (fp_out == NULL) { - err_msg("Cannot open volume:%d number:%d\n", devno, id); - goto err; - } - - rc = bootenv_write(fp_out, env); - if (rc != 0) { - err_msg("Cannot write bootenv to volume %d number:%d\n", - devno, id); - goto err; - } - -err: - if( fp_out ) - fclose(fp_out); - ubi_close(&ulib); - return rc; -} - -static int -do_mirror(int volno) -{ - char errbuf[1024]; - uint32_t ids[2]; - int rc; - int src_volno_idx = 0; - - ids[0] = EXAMPLE_BOOTENV_VOL_ID_1; - ids[1] = EXAMPLE_BOOTENV_VOL_ID_2; - - if (volno == EXAMPLE_BOOTENV_VOL_ID_2) - src_volno_idx = 1; - - rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf, - sizeof errbuf); - if( rc ) - err_msg(errbuf); - return rc; -} - -int -main(int argc, char **argv) { - int rc = 0; - bootenv_t env = NULL; - uint32_t boot_volno; - myargs args = { - .action = ACT_NORMAL, - .file_in = NULL, - .file_out = NULL, - .side = -1, - .x86 = 0, - .both = 0, - .env_in = NULL, - - .arg1 = NULL, - .options = NULL, - }; - - rc = bootenv_create(&env); - if (rc != 0) { - err_msg("Cannot create bootenv handle. rc: %d", rc); - goto err; - } - - rc = bootenv_create(&(args.env_in)); - if (rc != 0) { - err_msg("Cannot create bootenv handle. rc: %d", rc); - goto err; - } - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - if (args.action == ACT_ARGP_ERR) { - rc = -1; - goto err; - } - if (args.action == ACT_ARGP_ABORT) { - rc = 0; - goto out; - } - - if ((args.side == 0) || (args.side == -1)) - boot_volno = EXAMPLE_BOOTENV_VOL_ID_1; - else - boot_volno = EXAMPLE_BOOTENV_VOL_ID_2; - - if( args.x86 ) - rc = read_bootenv(args.file_in, env); - else - rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); - if (rc != 0) { - goto err; - } - - if (args.action == ACT_LIST) { - rc = list_bootenv(env); - if (rc != 0) { - goto err; - } - goto out; - } - - rc = process_key_value(args.env_in, env); - if (rc != 0) { - goto err; - } - - if( args.x86 ) - rc = write_bootenv(args.file_in, env); - else - rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); - if (rc != 0) { - goto err; - } - if( args.both ) /* No side specified, update both */ - rc = do_mirror(boot_volno); - - out: - err: - bootenv_destroy(&env); - bootenv_destroy(&(args.env_in)); - return rc; -} diff --git a/ubi-utils/src/peb.c b/ubi-utils/src/peb.c new file mode 100644 index 0000000..08b770f --- /dev/null +++ b/ubi-utils/src/peb.c @@ -0,0 +1,116 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#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 eb_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 = eb_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 new file mode 100644 index 0000000..246bce8 --- /dev/null +++ b/ubi-utils/src/peb.h @@ -0,0 +1,41 @@ +#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 +#include + +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 new file mode 100644 index 0000000..c8d5ee4 --- /dev/null +++ b/ubi-utils/src/pfi.c @@ -0,0 +1,461 @@ +/* + * 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. + * + * Wed Feb 8 11:38:22 CET 2006: Initial creation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 */ +}; + +static const char* modes[] = {"raw", "ubi", NULL}; /* 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) +{ + const char* ptr = modes[0]; + int i = 0; + while (ptr != NULL) { + if(strcmp(ptr, mode) == 0) { + return i; + } + ptr++; + 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 ((uint32_t)value == (uint32_t)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/pfi.h b/ubi-utils/src/pfi.h new file mode 100644 index 0000000..8c5cc07 --- /dev/null +++ b/ubi-utils/src/pfi.h @@ -0,0 +1,244 @@ +#ifndef __pfi_h +#define __pfi_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. + */ + +/** + * @file pfi.h + * + * @author Oliver Lohmann + * Andreas Arnez + * Joern Engel + * Frank Haverkamp + * + * @brief libpfi will hold all code to create and process pfi + * images. Definitions made in this file are equaly usable for the + * development host and the target system. + * + * @note This header additionally holds the official definitions for + * the pfi headers. + */ + +#include /* FILE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions. */ + +#define PFI_HDRVERSION 1 /* current header version */ + +#define PFI_ENOVERSION 1 /* unknown version */ +#define PFI_ENOHEADER 2 /* not a pfi header */ +#define PFI_EINSUFF 3 /* insufficient information */ +#define PFI_EUNDEF 4 /* key not defined */ +#define PFI_ENOMEM 5 /* out of memory */ +#define PFI_EBADTYPE 6 /* bad data type */ +#define PFI_EFILE 7 /* file I/O error: see errno */ +#define PFI_EFILEINVAL 8 /* file format not valid */ +#define PFI_EINVAL 9 /* invalid parameter */ +#define PFI_ERANGE 10 /* invalid range */ +#define PFI_EMODE 11 /* expecting other mode in this header */ +#define PFI_DATA_START 12 /* data section starts */ +#define PFI_EMAX 13 /* should be always larger as the largest + error code */ + +#define PFI_LABEL_LEN 64 /* This is the maximum length for a + PFI header label */ +#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an + entry in the mode and type fields */ + +#define PFI_UBI_MAX_VOLUMES 128 +#define PFI_UBI_VOL_NAME_LEN 127 + +/** + * @brief The pfi header allows to set flags which influence the flashing + * behaviour. + */ +#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; + + +/** + * @brief Initialize a pfi header object. + * + * @param head Pointer to handle. This function allocates memory + * for this data structure. + * @return 0 on success, otherwise: + * PFI_ENOMEM : no memory available for the handle. + */ +int pfi_header_init (pfi_header *head); + + +/** + * @brief Destroy a pfi header object. + * + * @param head handle. head is invalid after calling this function. + * @return 0 always. + */ +int pfi_header_destroy (pfi_header *head); + + +/** + * @brief Add a key/value pair to a pfi header object. + * + * @param head handle. + * @param key pointer to key string. Must be 0 terminated. + * @param value pointer to value string. Must be 0 terminated. + * @return 0 on success, otherwise: + * PFI_EUNDEF : key was not found. + * PFI_ENOMEM : no memory available for the handle. + * PFI_EBADTYPE : value is not an hex string. This happens + * when the key stores an integer and the + * new value is not convertable e.g. not in + * 0xXXXXXXXX format. + */ +int pfi_header_setvalue (pfi_header head, + const char *key, const char *value); + + +/** + * @brief Add a key/value pair to a pfi header object. Provide the + * value as a number. + * + * @param head handle. + * @param key pointer to key string. Must be 0 terminated. + * @param value value to set. + * @return 0 on success, otherwise: + * PFI_EUNDEF : key was not found. + * PFI_EBADTYPE : value is not a string. This happens + * when the key stores a string. + */ +int pfi_header_setnumber (pfi_header head, + const char *key, uint32_t value); + + +/** + * @brief For a given key, return the numerical value stored in a + * pfi header object. + * + * @param head handle. + * @param key pointer to key string. Must be 0 terminated. + * @param value pointer to value. + * @return 0 on success, otherwise: + * PFI_EUNDEF : key was not found. + * PFI_EBADTYPE : stored value is not an integer but a string. + */ +int pfi_header_getnumber (pfi_header head, + const char *key, uint32_t *value); + + +static inline uint32_t +pfi_getnumber(pfi_header head, const char *key) +{ + uint32_t value; + pfi_header_getnumber(head, key, &value); + return value; +} + +/** + * @brief For a given key, return the string value stored in a pfi + * header object. + * + * @param head handle. + * @param key pointer to key string. Must be 0 terminated. + * @param value pointer to value string. Memory must be allocated by the user. + * @return 0 on success, otherwise: + * PFI_EUNDEF : key was not found. + * PFI_EBADTYPE : stored value is not a string but an integer. + */ +int pfi_header_getstring (pfi_header head, + const char *key, char *value, size_t size); + + +/** + * @brief Write a pfi header object into a given file. + * + * @param out output stream. + * @param head handle. + * @return 0 on success, error values otherwise: + * PFI_EINSUFF : not all mandatory fields are filled. + * PFI_ENOHEADER : wrong header version or magic number. + * -E* : see . + */ +int pfi_header_write (FILE *out, pfi_header head); + + +/** + * @brief Read a pfi header object from a given file. + * + * @param in input stream. + * @param head handle. + * @return 0 on success, error values otherwise: + * PFI_ENOVERSION: unknown header version. + * PFI_EFILE : cannot read enough data. + * PFI_ENOHEADER : wrong header version or magic number. + * -E* : see . + * + * If the header verification returned success the user can assume that + * all mandatory fields for a particular version are accessible. Checking + * the return code when calling the get-function for those keys is not + * required in those cases. For optional fields the checking must still be + * done. + */ +int pfi_header_read (FILE *in, pfi_header head); + + +/** + * @brief Display a pfi header in human-readable form. + * + * @param out output stream. + * @param head handle. + * @return always 0. + * + * @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); + + +/* + * @brief Iterates over a stream of pfi files. The iterator function + * must advance the file pointer in FILE *in to the next pfi + * header. Function exists on feof(in). + * + * @param in input file descriptor, must be open and valid. + * @param func iterator function called when pfi header could be + * read and was validated. The function must return 0 on + * success. + * @return See pfi_header_init and pfi_header_read. + * PFI_EINVAL : func is not valid + * 0 ok. + */ +typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data); + +int pfi_read (FILE *in, pfi_read_func func, void *priv_data); + + +#ifdef __cplusplus +} +#endif + +#endif /* __pfi_h */ diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c new file mode 100644 index 0000000..6536c19 --- /dev/null +++ b/ubi-utils/src/pfi2bin.c @@ -0,0 +1,678 @@ +/* + * 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 + * + * Convert a PFI file (partial flash image) into a plain binary file. + * This tool can be used to prepare the data to be burned into flash + * chips in a manufacturing step where the flashes are written before + * being soldered onto the hardware. For NAND images another step is + * required to add the right OOB data to the binary image. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "config.h" +#include "list.h" +#include "error.h" +#include "reader.h" +#include "peb.h" +#include "crc32.h" + +#define MAX_FNAME 255 +#define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ +#define ERR_BUF_SIZE 1024 + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +static uint32_t crc32_table[256]; +static char err_buf[ERR_BUF_SIZE]; + +/* + * Data used to buffer raw blocks which have to be + * located at a specific point inside the generated RAW file + */ + +typedef enum action_t { + ACT_NOTHING = 0x00000000, + ACT_RAW = 0x00000001, +} action_t; + +static const char copyright [] __attribute__((unused)) = + "Licensed Materials - Property of IBM\n" + "IBM Flexible Support Processor Licensed Material\n" + "(c) Copyright IBM Corp 2006 All Rights Reserved.\n" + "US Government Users Restricted Rights - Use, duplication\n" + "or disclosure restricted by GSA ADP Schedule Contract\n" + "with IBM Corp."; + +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "pfi2bin - a tool to convert PFI files into binary images.\n"; + +static struct argp_option options[] = { + /* COMMON */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Common settings:", + group: OPTION_ARG_OPTIONAL}, + + { name: "verbose", key: 'v', arg: NULL, flags: 0, + doc: "Print more information.", + group: OPTION_ARG_OPTIONAL }, + + { name: "copyright", key: 'c', arg: NULL, flags: 0, + group: OPTION_ARG_OPTIONAL }, + + + /* INPUT */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Input:", + group: 4}, + + { name: "platform", key: 'j', arg: "pdd-file", flags: 0, + doc: "PDD information which contains the card settings.", + group: 4 }, + + /* OUTPUT */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Output:", + group: 5}, + + { name: "output", key: 'o', arg: "filename", flags: 0, + doc: "Outputfile, default: stdout.", + group: 5 }, + + { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, +}; + +typedef struct io { + FILE* fp_pdd; /* a FilePointer to the PDD data */ + FILE* fp_pfi; /* a FilePointer to the PFI input stream */ + FILE* fp_out; /* a FilePointer to the output stream */ +} *io_t; + +typedef struct myargs { + /* common settings */ + action_t action; + int verbose; + const char *f_in_pfi; + const char *f_in_pdd; + const char *f_out; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +} myargs; + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: "pfifile", + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + myargs *args = state->input; + + switch (key) { + /* common settings */ + case 'v': /* --verbose= */ + args->verbose = 1; + break; + + case 'c': /* --copyright */ + fprintf(stderr, "%s\n", copyright); + exit(0); + break; + + case 'j': /* --platform */ + args->f_in_pdd = arg; + break; + + case 'o': /* --output */ + args->f_out = arg; + break; + + case ARGP_KEY_ARG: + args->f_in_pfi = arg; + /* args->arg1 = arg; */ + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + + case ARGP_KEY_END: + if (args->action == ACT_NOTHING) { + argp_usage(state); + exit(1); + } + break; + + default: + return(ARGP_ERR_UNKNOWN); + } + + 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. + */ +static int +memorize_raw_eb(pfi_raw_t pfi_raw, pdd_data_t pdd, list_t *raw_pebs, + io_t io) +{ + int rc = 0; + uint32_t i; + + size_t read, to_read, eb_num; + size_t bytes_left; + list_t pebs = *raw_pebs; + peb_t peb = NULL; + + long old_file_pos = ftell(io->fp_pfi); + for (i = 0; i < pfi_raw->starts_size; i++) { + bytes_left = pfi_raw->data_size; + rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); + if (rc != 0) + goto err; + + eb_num = byte_to_blk(pfi_raw->starts[i], pdd->eb_size); + while (bytes_left) { + to_read = MIN(bytes_left, pdd->eb_size); + rc = peb_new(eb_num++, pdd->eb_size, &peb); + if (rc != 0) + goto err; + read = fread(peb->data, 1, to_read, io->fp_pfi); + if (read != to_read) { + rc = -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 rc; +} + +static int +convert_ubi_volume(pfi_ubi_t ubi, pdd_data_t pdd, list_t raw_pebs, + struct ubi_vol_tbl_record *vol_tab, + size_t *ebs_written, io_t io) +{ + int rc = 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; + } + + rc = peb_new(0, 0, &cmp_peb); + if (rc != 0) + goto err; + + long old_file_pos = ftell(io->fp_pfi); + for (i = 0; i < ubi->ids_size; i++) { + rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); + if (rc != 0) + goto err; + rc = ubigen_create(&u, ubi->ids[i], vol_type, + pdd->eb_size, DEFAULT_ERASE_COUNT, + ubi->alignment, UBI_VERSION, + pdd->vid_hdr_offset, 0, ubi->data_size, + io->fp_pfi, io->fp_out); + if (rc != 0) + goto err; + + rc = ubigen_get_leb_total(u, &leb_total); + if (rc != 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) { + rc = peb_write(io->fp_out, raw_peb); + } + else { + rc = ubigen_write_leb(u, NO_ERROR); + j++; + } + if (rc != 0) + goto err; + (*ebs_written)++; + } + /* memorize volume table entry */ + rc = ubigen_set_lvol_rec(u, ubi->size, + ubi->names[i], + (void*) &vol_tab[ubi->ids[i]]); + if (rc != 0) + goto err; + ubigen_destroy(&u); + } + + peb_free(&cmp_peb); + return 0; + +err: + peb_free(&cmp_peb); + ubigen_destroy(&u); + return rc; +} + + +static FILE* +my_fmemopen (void *buf, size_t size, const char *opentype) +{ + FILE* f; + + assert(strcmp(opentype, "r") == 0); + + f = tmpfile(); + fwrite(buf, 1, size, f); + rewind(f); + + return f; +} + +/** + * @brief Builds a UBI volume table from a volume entry list. + * @return 0 On success. + * else Error. + */ +static int +write_ubi_volume_table(pdd_data_t pdd, list_t raw_pebs, + struct ubi_vol_tbl_record *vol_tab, size_t vol_tab_size, + size_t *ebs_written, io_t io) +{ + int rc = 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; + + rc = peb_new(0, 0, &cmp_peb); + if (rc != 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. + */ + rc = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, + pdd->eb_size, DEFAULT_ERASE_COUNT, + 1, UBI_VERSION, + pdd->vid_hdr_offset, UBI_COMPAT_REJECT, + vol_tab_size, stdin, io->fp_out); + /* @FIXME stdin for fp_in is a hack */ + if (rc != 0) + goto err; + rc = ubigen_get_leb_size(u, &leb_size); + if (rc != 0) + goto err; + ubigen_destroy(&u); + + 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); + fp_leb = my_fmemopen(ptr, leb_size, "r"); + + rc = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, + pdd->eb_size, DEFAULT_ERASE_COUNT, + 1, UBI_VERSION, pdd->vid_hdr_offset, + UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS, + fp_leb, io->fp_out); + if (rc != 0) + goto err; + rc = ubigen_get_leb_total(u, &leb_total); + if (rc != 0) + goto err; + + long old_file_pos = ftell(fp_leb); + while(j < leb_total) { + rc = fseek(fp_leb, old_file_pos, SEEK_SET); + if (rc != 0) + goto err; + + cmp_peb->num = *ebs_written; + raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, + raw_pebs); + if (raw_peb) { + rc = peb_write(io->fp_out, raw_peb); + } + else { + rc = ubigen_write_leb(u, NO_ERROR); + j++; + } + + if (rc != 0) + goto err; + (*ebs_written)++; + } + +err: + free(ptr); + peb_free(&cmp_peb); + ubigen_destroy(&u); + fclose(fp_leb); + return rc; +} + +static int +write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written, + FILE* fp_out) +{ + int rc = 0; + uint32_t j, delta; + list_t ptr; + peb_t empty_eb, peb; + + /* create an empty 0xff EB (for padding) */ + rc = peb_new(0, pdd->eb_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) { + err_msg("eb_num: %d\n", peb->num); + err_msg("Bug: This should never happen. %d %s", + __LINE__, __FILE__); + goto err; + } + + delta = peb->num - *ebs_written; + if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) { + err_msg("RAW block outside of flash_size."); + goto err; + } + for (j = 0; j < delta; j++) { + rc = peb_write(fp_out, empty_eb); + if (rc != 0) + goto err; + (*ebs_written)++; + } + rc = peb_write(fp_out, peb); + if (rc != 0) + goto err; + (*ebs_written)++; + } + +err: + peb_free(&empty_eb); + return rc; +} + +static int +init_vol_tab(struct ubi_vol_tbl_record **vol_tab, size_t *vol_tab_size) +{ + uint32_t crc; + size_t i; + struct ubi_vol_tbl_record* res = NULL; + + *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; + + res = (struct ubi_vol_tbl_record*) calloc(1, *vol_tab_size); + if (vol_tab == NULL) { + return -ENOMEM; + } + + 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_ubi32(crc); + } + + *vol_tab = res; + return 0; +} + +static int +create_raw(io_t io) +{ + int rc = 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_vol_tbl_record *vol_tab = NULL; + pdd_data_t pdd = NULL; + + rc = init_vol_tab (&vol_tab, &vol_tab_size); + if (rc != 0) { + err_msg("Cannot initialize volume table."); + goto err; + } + + rc = read_pdd_data(io->fp_pdd, &pdd, + err_buf, ERR_BUF_SIZE); + if (rc != 0) { + err_msg("Cannot read necessary pdd_data: %s rc: %d", + err_buf, rc); + goto err; + } + + rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi, + err_buf, ERR_BUF_SIZE); + if (rc != 0) { + err_msg("Cannot read pfi header: %s rc: %d", + err_buf, rc); + goto err; + } + + pfi_raw_t pfi_raw; + foreach(pfi_raw, ptr, pfi_raws) { + rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs, + io); + if (rc != 0) { + err_msg("Cannot create raw_block in mem. rc: %d\n", + rc); + goto err; + } + } + + pfi_ubi_t pfi_ubi; + foreach(pfi_ubi, ptr, pfi_ubis) { + rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs, + vol_tab, &ebs_written, io); + if (rc != 0) { + err_msg("Cannot convert UBI volume. rc: %d\n", rc); + goto err; + } + } + + rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size, + &ebs_written, io); + if (rc != 0) { + err_msg("Cannot write UBI volume table. rc: %d\n", rc); + goto err; + } + + rc = write_remaining_raw_ebs(pdd, raw_pebs, &ebs_written, io->fp_out); + if (rc != 0) + goto err; + + if (io->fp_out != stdout) + info_msg("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); + free_pdd_data(&pdd); + return rc; +} + + +/* ------------------------------------------------------------------------- */ +static void +open_io_handle(myargs *args, io_t io) +{ + /* set PDD input */ + io->fp_pdd = fopen(args->f_in_pdd, "r"); + if (io->fp_pdd == NULL) { + err_sys("Cannot open: %s", args->f_in_pdd); + } + + /* set PFI input */ + io->fp_pfi = fopen(args->f_in_pfi, "r"); + if (io->fp_pfi == NULL) { + err_sys("Cannot open PFI input file: %s", args->f_in_pfi); + } + + /* set output prefix */ + if (strcmp(args->f_out,"") == 0) + io->fp_out = stdout; + else { + io->fp_out = fopen(args->f_out, "wb"); + if (io->fp_out == NULL) { + err_sys("Cannot open output file: %s", args->f_out); + } + } +} + +static void +close_io_handle(io_t io) +{ + if (fclose(io->fp_pdd) != 0) { + err_sys("Cannot close PDD file."); + } + if (fclose(io->fp_pfi) != 0) { + err_sys("Cannot close PFI file."); + } + if (io->fp_out != stdout) { + if (fclose(io->fp_out) != 0) { + err_sys("Cannot close output file."); + } + } + + io->fp_pdd = NULL; + io->fp_pfi = NULL; + io->fp_out = NULL; +} + +int +main(int argc, char *argv[]) +{ + int rc = 0; + + ubigen_init(); + init_crc32_table(crc32_table); + + struct io io = {NULL, NULL, NULL}; + myargs args = { + .action = ACT_RAW, + .verbose = 0, + + .f_in_pfi = "", + .f_in_pdd = "", + .f_out = "", + + /* arguments */ + .arg1 = NULL, + .options = NULL, + }; + + /* parse arguments */ + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + + if (strcmp(args.f_in_pfi, "") == 0) { + err_quit("No PFI input file specified!"); + } + + if (strcmp(args.f_in_pdd, "") == 0) { + err_quit("No PDD input file specified!"); + } + + open_io_handle(&args, &io); + + info_msg("[ Creating RAW..."); + rc = create_raw(&io); + if (rc != 0) { + err_msg("Creating RAW failed."); + goto err; + } + +err: + close_io_handle(&io); + if (rc != 0) { + remove(args.f_out); + } + + return rc; +} diff --git a/ubi-utils/src/pfi2bin/pfi2bin.c b/ubi-utils/src/pfi2bin/pfi2bin.c deleted file mode 100644 index 6536c19..0000000 --- a/ubi-utils/src/pfi2bin/pfi2bin.c +++ /dev/null @@ -1,678 +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 - * - * Convert a PFI file (partial flash image) into a plain binary file. - * This tool can be used to prepare the data to be burned into flash - * chips in a manufacturing step where the flashes are written before - * being soldered onto the hardware. For NAND images another step is - * required to add the right OOB data to the binary image. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "config.h" -#include "list.h" -#include "error.h" -#include "reader.h" -#include "peb.h" -#include "crc32.h" - -#define MAX_FNAME 255 -#define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ -#define ERR_BUF_SIZE 1024 - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -static uint32_t crc32_table[256]; -static char err_buf[ERR_BUF_SIZE]; - -/* - * Data used to buffer raw blocks which have to be - * located at a specific point inside the generated RAW file - */ - -typedef enum action_t { - ACT_NOTHING = 0x00000000, - ACT_RAW = 0x00000001, -} action_t; - -static const char copyright [] __attribute__((unused)) = - "Licensed Materials - Property of IBM\n" - "IBM Flexible Support Processor Licensed Material\n" - "(c) Copyright IBM Corp 2006 All Rights Reserved.\n" - "US Government Users Restricted Rights - Use, duplication\n" - "or disclosure restricted by GSA ADP Schedule Contract\n" - "with IBM Corp."; - -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "pfi2bin - a tool to convert PFI files into binary images.\n"; - -static struct argp_option options[] = { - /* COMMON */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Common settings:", - group: OPTION_ARG_OPTIONAL}, - - { name: "verbose", key: 'v', arg: NULL, flags: 0, - doc: "Print more information.", - group: OPTION_ARG_OPTIONAL }, - - { name: "copyright", key: 'c', arg: NULL, flags: 0, - group: OPTION_ARG_OPTIONAL }, - - - /* INPUT */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Input:", - group: 4}, - - { name: "platform", key: 'j', arg: "pdd-file", flags: 0, - doc: "PDD information which contains the card settings.", - group: 4 }, - - /* OUTPUT */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Output:", - group: 5}, - - { name: "output", key: 'o', arg: "filename", flags: 0, - doc: "Outputfile, default: stdout.", - group: 5 }, - - { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, -}; - -typedef struct io { - FILE* fp_pdd; /* a FilePointer to the PDD data */ - FILE* fp_pfi; /* a FilePointer to the PFI input stream */ - FILE* fp_out; /* a FilePointer to the output stream */ -} *io_t; - -typedef struct myargs { - /* common settings */ - action_t action; - int verbose; - const char *f_in_pfi; - const char *f_in_pdd; - const char *f_out; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: "pfifile", - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - myargs *args = state->input; - - switch (key) { - /* common settings */ - case 'v': /* --verbose= */ - args->verbose = 1; - break; - - case 'c': /* --copyright */ - fprintf(stderr, "%s\n", copyright); - exit(0); - break; - - case 'j': /* --platform */ - args->f_in_pdd = arg; - break; - - case 'o': /* --output */ - args->f_out = arg; - break; - - case ARGP_KEY_ARG: - args->f_in_pfi = arg; - /* args->arg1 = arg; */ - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - - case ARGP_KEY_END: - if (args->action == ACT_NOTHING) { - argp_usage(state); - exit(1); - } - break; - - default: - return(ARGP_ERR_UNKNOWN); - } - - 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. - */ -static int -memorize_raw_eb(pfi_raw_t pfi_raw, pdd_data_t pdd, list_t *raw_pebs, - io_t io) -{ - int rc = 0; - uint32_t i; - - size_t read, to_read, eb_num; - size_t bytes_left; - list_t pebs = *raw_pebs; - peb_t peb = NULL; - - long old_file_pos = ftell(io->fp_pfi); - for (i = 0; i < pfi_raw->starts_size; i++) { - bytes_left = pfi_raw->data_size; - rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); - if (rc != 0) - goto err; - - eb_num = byte_to_blk(pfi_raw->starts[i], pdd->eb_size); - while (bytes_left) { - to_read = MIN(bytes_left, pdd->eb_size); - rc = peb_new(eb_num++, pdd->eb_size, &peb); - if (rc != 0) - goto err; - read = fread(peb->data, 1, to_read, io->fp_pfi); - if (read != to_read) { - rc = -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 rc; -} - -static int -convert_ubi_volume(pfi_ubi_t ubi, pdd_data_t pdd, list_t raw_pebs, - struct ubi_vol_tbl_record *vol_tab, - size_t *ebs_written, io_t io) -{ - int rc = 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; - } - - rc = peb_new(0, 0, &cmp_peb); - if (rc != 0) - goto err; - - long old_file_pos = ftell(io->fp_pfi); - for (i = 0; i < ubi->ids_size; i++) { - rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); - if (rc != 0) - goto err; - rc = ubigen_create(&u, ubi->ids[i], vol_type, - pdd->eb_size, DEFAULT_ERASE_COUNT, - ubi->alignment, UBI_VERSION, - pdd->vid_hdr_offset, 0, ubi->data_size, - io->fp_pfi, io->fp_out); - if (rc != 0) - goto err; - - rc = ubigen_get_leb_total(u, &leb_total); - if (rc != 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) { - rc = peb_write(io->fp_out, raw_peb); - } - else { - rc = ubigen_write_leb(u, NO_ERROR); - j++; - } - if (rc != 0) - goto err; - (*ebs_written)++; - } - /* memorize volume table entry */ - rc = ubigen_set_lvol_rec(u, ubi->size, - ubi->names[i], - (void*) &vol_tab[ubi->ids[i]]); - if (rc != 0) - goto err; - ubigen_destroy(&u); - } - - peb_free(&cmp_peb); - return 0; - -err: - peb_free(&cmp_peb); - ubigen_destroy(&u); - return rc; -} - - -static FILE* -my_fmemopen (void *buf, size_t size, const char *opentype) -{ - FILE* f; - - assert(strcmp(opentype, "r") == 0); - - f = tmpfile(); - fwrite(buf, 1, size, f); - rewind(f); - - return f; -} - -/** - * @brief Builds a UBI volume table from a volume entry list. - * @return 0 On success. - * else Error. - */ -static int -write_ubi_volume_table(pdd_data_t pdd, list_t raw_pebs, - struct ubi_vol_tbl_record *vol_tab, size_t vol_tab_size, - size_t *ebs_written, io_t io) -{ - int rc = 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; - - rc = peb_new(0, 0, &cmp_peb); - if (rc != 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. - */ - rc = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, - pdd->eb_size, DEFAULT_ERASE_COUNT, - 1, UBI_VERSION, - pdd->vid_hdr_offset, UBI_COMPAT_REJECT, - vol_tab_size, stdin, io->fp_out); - /* @FIXME stdin for fp_in is a hack */ - if (rc != 0) - goto err; - rc = ubigen_get_leb_size(u, &leb_size); - if (rc != 0) - goto err; - ubigen_destroy(&u); - - 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); - fp_leb = my_fmemopen(ptr, leb_size, "r"); - - rc = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, - pdd->eb_size, DEFAULT_ERASE_COUNT, - 1, UBI_VERSION, pdd->vid_hdr_offset, - UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS, - fp_leb, io->fp_out); - if (rc != 0) - goto err; - rc = ubigen_get_leb_total(u, &leb_total); - if (rc != 0) - goto err; - - long old_file_pos = ftell(fp_leb); - while(j < leb_total) { - rc = fseek(fp_leb, old_file_pos, SEEK_SET); - if (rc != 0) - goto err; - - cmp_peb->num = *ebs_written; - raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, - raw_pebs); - if (raw_peb) { - rc = peb_write(io->fp_out, raw_peb); - } - else { - rc = ubigen_write_leb(u, NO_ERROR); - j++; - } - - if (rc != 0) - goto err; - (*ebs_written)++; - } - -err: - free(ptr); - peb_free(&cmp_peb); - ubigen_destroy(&u); - fclose(fp_leb); - return rc; -} - -static int -write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written, - FILE* fp_out) -{ - int rc = 0; - uint32_t j, delta; - list_t ptr; - peb_t empty_eb, peb; - - /* create an empty 0xff EB (for padding) */ - rc = peb_new(0, pdd->eb_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) { - err_msg("eb_num: %d\n", peb->num); - err_msg("Bug: This should never happen. %d %s", - __LINE__, __FILE__); - goto err; - } - - delta = peb->num - *ebs_written; - if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) { - err_msg("RAW block outside of flash_size."); - goto err; - } - for (j = 0; j < delta; j++) { - rc = peb_write(fp_out, empty_eb); - if (rc != 0) - goto err; - (*ebs_written)++; - } - rc = peb_write(fp_out, peb); - if (rc != 0) - goto err; - (*ebs_written)++; - } - -err: - peb_free(&empty_eb); - return rc; -} - -static int -init_vol_tab(struct ubi_vol_tbl_record **vol_tab, size_t *vol_tab_size) -{ - uint32_t crc; - size_t i; - struct ubi_vol_tbl_record* res = NULL; - - *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; - - res = (struct ubi_vol_tbl_record*) calloc(1, *vol_tab_size); - if (vol_tab == NULL) { - return -ENOMEM; - } - - 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_ubi32(crc); - } - - *vol_tab = res; - return 0; -} - -static int -create_raw(io_t io) -{ - int rc = 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_vol_tbl_record *vol_tab = NULL; - pdd_data_t pdd = NULL; - - rc = init_vol_tab (&vol_tab, &vol_tab_size); - if (rc != 0) { - err_msg("Cannot initialize volume table."); - goto err; - } - - rc = read_pdd_data(io->fp_pdd, &pdd, - err_buf, ERR_BUF_SIZE); - if (rc != 0) { - err_msg("Cannot read necessary pdd_data: %s rc: %d", - err_buf, rc); - goto err; - } - - rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi, - err_buf, ERR_BUF_SIZE); - if (rc != 0) { - err_msg("Cannot read pfi header: %s rc: %d", - err_buf, rc); - goto err; - } - - pfi_raw_t pfi_raw; - foreach(pfi_raw, ptr, pfi_raws) { - rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs, - io); - if (rc != 0) { - err_msg("Cannot create raw_block in mem. rc: %d\n", - rc); - goto err; - } - } - - pfi_ubi_t pfi_ubi; - foreach(pfi_ubi, ptr, pfi_ubis) { - rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs, - vol_tab, &ebs_written, io); - if (rc != 0) { - err_msg("Cannot convert UBI volume. rc: %d\n", rc); - goto err; - } - } - - rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size, - &ebs_written, io); - if (rc != 0) { - err_msg("Cannot write UBI volume table. rc: %d\n", rc); - goto err; - } - - rc = write_remaining_raw_ebs(pdd, raw_pebs, &ebs_written, io->fp_out); - if (rc != 0) - goto err; - - if (io->fp_out != stdout) - info_msg("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); - free_pdd_data(&pdd); - return rc; -} - - -/* ------------------------------------------------------------------------- */ -static void -open_io_handle(myargs *args, io_t io) -{ - /* set PDD input */ - io->fp_pdd = fopen(args->f_in_pdd, "r"); - if (io->fp_pdd == NULL) { - err_sys("Cannot open: %s", args->f_in_pdd); - } - - /* set PFI input */ - io->fp_pfi = fopen(args->f_in_pfi, "r"); - if (io->fp_pfi == NULL) { - err_sys("Cannot open PFI input file: %s", args->f_in_pfi); - } - - /* set output prefix */ - if (strcmp(args->f_out,"") == 0) - io->fp_out = stdout; - else { - io->fp_out = fopen(args->f_out, "wb"); - if (io->fp_out == NULL) { - err_sys("Cannot open output file: %s", args->f_out); - } - } -} - -static void -close_io_handle(io_t io) -{ - if (fclose(io->fp_pdd) != 0) { - err_sys("Cannot close PDD file."); - } - if (fclose(io->fp_pfi) != 0) { - err_sys("Cannot close PFI file."); - } - if (io->fp_out != stdout) { - if (fclose(io->fp_out) != 0) { - err_sys("Cannot close output file."); - } - } - - io->fp_pdd = NULL; - io->fp_pfi = NULL; - io->fp_out = NULL; -} - -int -main(int argc, char *argv[]) -{ - int rc = 0; - - ubigen_init(); - init_crc32_table(crc32_table); - - struct io io = {NULL, NULL, NULL}; - myargs args = { - .action = ACT_RAW, - .verbose = 0, - - .f_in_pfi = "", - .f_in_pdd = "", - .f_out = "", - - /* arguments */ - .arg1 = NULL, - .options = NULL, - }; - - /* parse arguments */ - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - - if (strcmp(args.f_in_pfi, "") == 0) { - err_quit("No PFI input file specified!"); - } - - if (strcmp(args.f_in_pdd, "") == 0) { - err_quit("No PDD input file specified!"); - } - - open_io_handle(&args, &io); - - info_msg("[ Creating RAW..."); - rc = create_raw(&io); - if (rc != 0) { - err_msg("Creating RAW failed."); - goto err; - } - -err: - close_io_handle(&io); - if (rc != 0) { - remove(args.f_out); - } - - return rc; -} diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c new file mode 100644 index 0000000..04f62df --- /dev/null +++ b/ubi-utils/src/pfiflash.c @@ -0,0 +1,243 @@ +/* + * 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 + * Frank Haverkamp + * + * Process a PFI (partial flash image) and write the data to the + * specified UBI volumes. This tool is intended to be used for system + * update using PFI files. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "error.h" +#include "config.h" + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "pfiflash - a tool for updating a controller with PFI files.\n"; + +static const char copyright [] __attribute__((unused)) = + "FIXME: insert license type."; /* FIXME */ + +static struct argp_option options[] = { + /* Output options */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Standard options:", + group: 1 }, + + { name: "copyright", key: 'c', arg: NULL, flags: 0, + doc: "Print copyright information.", + group: 1 }, + + { name: "verbose", key: 'v', arg: NULL, flags: 0, + doc: "Be verbose during program execution.", + group: 1 }, + + { name: "logfile", key: 'l', arg: "", flags: 0, + doc: "Write a logfile to .", + group: 1 }, + + /* Output options */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Process options:", + group: 2 }, + + { name: "complete", key: 'C', arg: NULL, flags: 0, + doc: "Execute a complete system update. Updates both sides.", + group: 2 }, + + { name: "side", key: 's', arg: "", flags: 0, + doc: "Select the side which shall be updated.", + group: 2 }, + + { name: "pdd-update", key: 'p', arg: "", flags: 0, + doc: "Specify the pdd-update algorithm. is either " + "'keep', 'merge' or 'overwrite'.", + group: 2 }, + + { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, +}; + +typedef struct myargs { + int verbose; + const char *logfile; + + pdd_handling_t pdd_handling; + int seqnum; + int complete; + + FILE* fp_in; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +} myargs; + +static pdd_handling_t +get_pdd_handling(const char* str) +{ + if (strcmp(str, "keep") == 0) { + return PDD_KEEP; + } + if (strcmp(str, "merge") == 0) { + return PDD_MERGE; + } + if (strcmp(str, "overwrite") == 0) { + return PDD_OVERWRITE; + } + + return -1; +} + +static int +get_update_seqnum(const char* str) +{ + uint32_t i = strtoul(str, NULL, 0); + + if ((i != 0) && (i != 1)) { + return -1; + } + + return i; +} + + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + int err = 0; + + myargs *args = state->input; + + switch (key) { + /* standard options */ + case 'c': + err_msg("%s\n", copyright); + exit(0); + break; + case 'v': + args->verbose = 1; + break; + case 'l': + args->logfile = arg; + break; + /* process options */ + case 'C': + args->complete = 1; + break; + case 'p': + args->pdd_handling = get_pdd_handling(arg); + if ((int)args->pdd_handling < 0) { + err_quit("Unknown PDD handling: %s.\n" + "Please use either 'keep', 'merge' or" + "'overwrite'.\n'"); + } + break; + case 's': + args->seqnum = get_update_seqnum(arg); + if (args->seqnum < 0) { + err_quit("Unsupported side: %s.\n" + "Supported sides are '0' and '1'\n", arg); + } + break; + + case ARGP_KEY_ARG: /* input file */ + args->fp_in = fopen(arg, "r"); + if ((args->fp_in) == NULL) { + err_sys("Cannot open PFI file %s for input", arg); + } + args->arg1 = arg; + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + case ARGP_KEY_END: + if (err) { + err_msg("\n"); + argp_usage(state); + exit(1); + } + break; + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: "[pfifile]", + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + +int main (int argc, char** argv) +{ + int rc = 0; + char err_buf[PFIFLASH_MAX_ERR_BUF_SIZE]; + memset(err_buf, '\0', PFIFLASH_MAX_ERR_BUF_SIZE); + + myargs args = { + .verbose = 0, + .seqnum = -1, + .complete = 0, + .logfile = "/tmp/pfiflash.log", + .pdd_handling = PDD_KEEP, + .fp_in = stdin, + }; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + error_initlog(args.logfile); + + if (!args.fp_in) { + rc = -1; + snprintf(err_buf, PFIFLASH_MAX_ERR_BUF_SIZE, + "No PFI input file specified!\n"); + goto err; + } + + rc = pfiflash(args.fp_in, args.complete, args.seqnum, + args.pdd_handling, err_buf, PFIFLASH_MAX_ERR_BUF_SIZE); + if (rc != 0) { + goto err_fp; + } + + err_fp: + if (args.fp_in != stdin) + fclose(args.fp_in); + err: + if (rc != 0) + err_msg("Error: %s\nrc: %d\n", err_buf, rc); + return rc; +} diff --git a/ubi-utils/src/pfiflash.h b/ubi-utils/src/pfiflash.h new file mode 100644 index 0000000..fc2eede --- /dev/null +++ b/ubi-utils/src/pfiflash.h @@ -0,0 +1,62 @@ +#ifndef __PFIFLASH_H__ +#define __PFIFLASH_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. + */ + +/** + * + * @file pfi.h + * + * @author Oliver Lohmann + * + * @brief The pfiflash library offers an interface for using the + * pfiflash * utility. + */ + +#include /* FILE */ + +#define PFIFLASH_MAX_ERR_BUF_SIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum pdd_handling_t +{ + PDD_KEEP = 0, + PDD_MERGE, + PDD_OVERWRITE, + PDD_HANDLING_NUM, /* always the last item */ +} pdd_handling_t; /**< Possible PDD handle algorithms. */ + +/** + * @brief Flashes a PFI file to UBI Device 0. + * @param complete [0|1] Do a complete system update. + * @param seqnum Index in a redundant group. + * @param pdd_handling The PDD handling algorithm. + * @param err_buf An error buffer. + * @param err_buf_size Size of the error buffer. + */ +int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, + char *err_buf, size_t err_buf_size); + +#ifdef __cplusplus +} +#endif + +#endif /* __PFIFLASH_H__ */ diff --git a/ubi-utils/src/pfiflash/pfiflash.c b/ubi-utils/src/pfiflash/pfiflash.c deleted file mode 100644 index 18b3aa2..0000000 --- a/ubi-utils/src/pfiflash/pfiflash.c +++ /dev/null @@ -1,243 +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 - * Frank Haverkamp - * - * Process a PFI (partial flash image) and write the data to the - * specified UBI volumes. This tool is intended to be used for system - * update using PFI files. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "error.h" -#include "config.h" - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "pfiflash - a tool for updating a controller with PFI files.\n"; - -static const char copyright [] __attribute__((unused)) = - "FIXME: insert license type."; /* FIXME */ - -static struct argp_option options[] = { - /* Output options */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Standard options:", - group: 1 }, - - { name: "copyright", key: 'c', arg: NULL, flags: 0, - doc: "Print copyright information.", - group: 1 }, - - { name: "verbose", key: 'v', arg: NULL, flags: 0, - doc: "Be verbose during program execution.", - group: 1 }, - - { name: "logfile", key: 'l', arg: "", flags: 0, - doc: "Write a logfile to .", - group: 1 }, - - /* Output options */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Process options:", - group: 2 }, - - { name: "complete", key: 'C', arg: NULL, flags: 0, - doc: "Execute a complete system update. Updates both sides.", - group: 2 }, - - { name: "side", key: 's', arg: "", flags: 0, - doc: "Select the side which shall be updated.", - group: 2 }, - - { name: "pdd-update", key: 'p', arg: "", flags: 0, - doc: "Specify the pdd-update algorithm. is either " - "'keep', 'merge' or 'overwrite'.", - group: 2 }, - - { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, -}; - -typedef struct myargs { - int verbose; - const char *logfile; - - pdd_handling_t pdd_handling; - int seqnum; - int complete; - - FILE* fp_in; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static pdd_handling_t -get_pdd_handling(const char* str) -{ - if (strcmp(str, "keep") == 0) { - return PDD_KEEP; - } - if (strcmp(str, "merge") == 0) { - return PDD_MERGE; - } - if (strcmp(str, "overwrite") == 0) { - return PDD_OVERWRITE; - } - - return -1; -} - -static int -get_update_seqnum(const char* str) -{ - uint32_t i = strtoul(str, NULL, 0); - - if ((i != 0) && (i != 1)) { - return -1; - } - - return i; -} - - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - int err = 0; - - myargs *args = state->input; - - switch (key) { - /* standard options */ - case 'c': - err_msg("%s\n", copyright); - exit(0); - break; - case 'v': - args->verbose = 1; - break; - case 'l': - args->logfile = arg; - break; - /* process options */ - case 'C': - args->complete = 1; - break; - case 'p': - args->pdd_handling = get_pdd_handling(arg); - if (args->pdd_handling < 0) { - err_quit("Unknown PDD handling: %s.\n" - "Please use either 'keep', 'merge' or" - "'overwrite'.\n'"); - } - break; - case 's': - args->seqnum = get_update_seqnum(arg); - if (args->seqnum < 0) { - err_quit("Unsupported side: %s.\n" - "Supported sides are '0' and '1'\n", arg); - } - break; - - case ARGP_KEY_ARG: /* input file */ - args->fp_in = fopen(arg, "r"); - if ((args->fp_in) == NULL) { - err_sys("Cannot open PFI file %s for input", arg); - } - args->arg1 = arg; - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - case ARGP_KEY_END: - if (err) { - err_msg("\n"); - argp_usage(state); - exit(1); - } - break; - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: "[pfifile]", - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - -int main (int argc, char** argv) -{ - int rc = 0; - char err_buf[PFIFLASH_MAX_ERR_BUF_SIZE]; - memset(err_buf, '\0', PFIFLASH_MAX_ERR_BUF_SIZE); - - myargs args = { - .verbose = 0, - .seqnum = -1, - .complete = 0, - .logfile = "/tmp/pfiflash.log", - .pdd_handling = PDD_KEEP, - .fp_in = stdin, - }; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - error_initlog(args.logfile); - - if (!args.fp_in) { - rc = -1; - snprintf(err_buf, PFIFLASH_MAX_ERR_BUF_SIZE, - "No PFI input file specified!\n"); - goto err; - } - - rc = pfiflash(args.fp_in, args.complete, args.seqnum, - args.pdd_handling, err_buf, PFIFLASH_MAX_ERR_BUF_SIZE); - if (rc != 0) { - goto err_fp; - } - - err_fp: - if (args.fp_in != stdin) - fclose(args.fp_in); - err: - if (rc != 0) - err_msg("Error: %s\nrc: %d\n", err_buf, rc); - return rc; -} diff --git a/ubi-utils/src/reader.c b/ubi-utils/src/reader.c new file mode 100644 index 0000000..e4a8ceb --- /dev/null +++ b/ubi-utils/src/reader.c @@ -0,0 +1,452 @@ +/* + * 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 +#include +#include +#include +#include + +#include "config.h" +#include "bootenv.h" +#include "reader.h" + +/* @FIXME hard coded offsets right now - get them from Artem? */ +#define NAND_DEFAULT_VID_HDR_OFF 1984 +#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) { + res->flash_type = NAND_FLASH; + res->vid_hdr_offset = NAND_DEFAULT_VID_HDR_OFF; + } + 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; +} + +/** + * FIXME enhance flasing raw PFI content e.g. IPLs for NAND and NOR. + * Here is one of the only places where the flash type and its special + * handling is exposed to the users. + */ +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; + + 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_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, + &(res->starts_size), &(res->starts)); + 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; +} + +/** + * FIXME Enhance reading raw PFI sections, e.g. IPL. See comment at + * write_pfi_ubi. + */ +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; + + 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_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, &(res->ids_size), + &(res->ids)); + 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, &(res->names_size), + &(tmp_names)); + 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 new file mode 100644 index 0000000..93c15e3 --- /dev/null +++ b/ubi-utils/src/reader.h @@ -0,0 +1,84 @@ +#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 +#include + +#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 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; +}; + +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) */ +}; + +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 new file mode 100644 index 0000000..fb4ef49 --- /dev/null +++ b/ubi-utils/src/ubicrc32.c @@ -0,0 +1,143 @@ +/* + * 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 + * + * Calculate CRC32 with UBI start value for a given binary image. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "crc32.h" + +#define BUFSIZE 4096 + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "ubicrc32 - calculates the UBI CRC32 value and prints it to stdout.\n"; + +static const char copyright [] __attribute__((unused)) = + "FIXME: insert license type"; /* FIXME */ + + +static struct argp_option options[] = { + { name: "copyright", key: 'c', arg: NULL, flags: 0, + doc: "Print copyright information.", + group: 1 }, + + { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, +}; + +typedef struct myargs { + FILE* fp_in; + + char *arg1; + char **options; /* [STRING...] */ +} myargs; + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + int err = 0; + + myargs *args = state->input; + + switch (key) { + case 'c': + fprintf(stderr, "%s\n", copyright); + exit(0); + break; + case ARGP_KEY_ARG: + args->fp_in = fopen(arg, "rb"); + if ((args->fp_in) == NULL) { + fprintf(stderr, + "Cannot open file %s for input\n", arg); + exit(1); + } + args->arg1 = arg; + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + case ARGP_KEY_END: + if (err) { + fprintf(stderr, "\n"); + argp_usage(state); + exit(1); + } + break; + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: "[file]", + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + +int +main(int argc, char **argv) { + int rc = 0; + uint32_t crc32_table[256]; + uint8_t buf[BUFSIZE]; + size_t read; + uint32_t crc32; + + myargs args = { + .fp_in = stdin, + .arg1 = NULL, + .options = NULL, + }; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + + init_crc32_table(crc32_table); + crc32 = UBI_CRC32_INIT; + while (!feof(args.fp_in)) { + read = fread(buf, 1, BUFSIZE, args.fp_in); + if (ferror(args.fp_in)) { + fprintf(stderr, "I/O Error."); + exit(EXIT_FAILURE); + } + crc32 = clc_crc32(crc32_table, crc32, buf, read); + } + + if (args.fp_in != stdin) { + fclose(args.fp_in); + } + + fprintf(stdout, "0x%08x\n", crc32); + return rc; +} diff --git a/ubi-utils/src/ubicrc32/ubicrc32.c b/ubi-utils/src/ubicrc32/ubicrc32.c deleted file mode 100644 index fb4ef49..0000000 --- a/ubi-utils/src/ubicrc32/ubicrc32.c +++ /dev/null @@ -1,143 +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 - * - * Calculate CRC32 with UBI start value for a given binary image. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "crc32.h" - -#define BUFSIZE 4096 - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "ubicrc32 - calculates the UBI CRC32 value and prints it to stdout.\n"; - -static const char copyright [] __attribute__((unused)) = - "FIXME: insert license type"; /* FIXME */ - - -static struct argp_option options[] = { - { name: "copyright", key: 'c', arg: NULL, flags: 0, - doc: "Print copyright information.", - group: 1 }, - - { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, -}; - -typedef struct myargs { - FILE* fp_in; - - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - int err = 0; - - myargs *args = state->input; - - switch (key) { - case 'c': - fprintf(stderr, "%s\n", copyright); - exit(0); - break; - case ARGP_KEY_ARG: - args->fp_in = fopen(arg, "rb"); - if ((args->fp_in) == NULL) { - fprintf(stderr, - "Cannot open file %s for input\n", arg); - exit(1); - } - args->arg1 = arg; - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - case ARGP_KEY_END: - if (err) { - fprintf(stderr, "\n"); - argp_usage(state); - exit(1); - } - break; - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: "[file]", - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - -int -main(int argc, char **argv) { - int rc = 0; - uint32_t crc32_table[256]; - uint8_t buf[BUFSIZE]; - size_t read; - uint32_t crc32; - - myargs args = { - .fp_in = stdin, - .arg1 = NULL, - .options = NULL, - }; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - - init_crc32_table(crc32_table); - crc32 = UBI_CRC32_INIT; - while (!feof(args.fp_in)) { - read = fread(buf, 1, BUFSIZE, args.fp_in); - if (ferror(args.fp_in)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - crc32 = clc_crc32(crc32_table, crc32, buf, read); - } - - if (args.fp_in != stdin) { - fclose(args.fp_in); - } - - fprintf(stdout, "0x%08x\n", crc32); - return rc; -} diff --git a/ubi-utils/src/ubicrc32/ubicrc32.pl b/ubi-utils/src/ubicrc32/ubicrc32.pl deleted file mode 100755 index add5f9d..0000000 --- a/ubi-utils/src/ubicrc32/ubicrc32.pl +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/perl -w - -# Subroutine crc32(): Calculates the CRC on a given string. - -{ - my @table = (); - - # @brief Calculate CRC32 for a given string. - sub crc32 - { - unless (@table) { - # Initialize the CRC table - my $poly = 0xEDB88320; - @table = (); - - for my $i (0..255) { - my $c = $i; - - for my $j (0..7) { - $c = ($c & 1) ? (($c >> 1) ^ $poly) : ($c >> 1); - } - $table[$i] = $c; - } - } - my $s = shift; # string to calculate the CRC for - my $crc = shift; # CRC start value - - defined($crc) - or $crc = 0xffffffff; # Default CRC start value - - for (my $i = 0; $i < length($s); $i++) { - $crc = $table[($crc ^ ord(substr($s, $i, 1))) & 0xff] - ^ ($crc >> 8); - } - return $crc; - } -} - -sub crc32_on_file -{ - my $file = shift; - - my $crc32 = crc32(''); - my $buf = ''; - my $ret = 0; - - while ($ret = read($file, $buf, 8192)) { - $crc32 = crc32($buf, $crc32); - } - defined($ret) - or return undef; - printf("0x%x\n", $crc32); -} - - -# Main routine: Calculate the CRCs on the given files and print the -# results. - -{ - if (@ARGV) { - while (my $path = shift) { - my $file; - open $file, "<", $path - or die "Error opening '$path'.\n"; - - &crc32_on_file($file) - or die "Error reading from '$path'.\n"; - close $file; - } - } else { - &crc32_on_file(\*STDIN) - or die "Error reading from stdin.\n"; - } -} diff --git a/ubi-utils/src/ubigen.c b/ubi-utils/src/ubigen.c new file mode 100644 index 0000000..8a464dd --- /dev/null +++ b/ubi-utils/src/ubigen.c @@ -0,0 +1,369 @@ +/* + * 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 + * + * Tool to add UBI headers to binary images. + * + * 1.0 Initial version + * 1.1 Different CRC32 start value + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ubigen.h" +#include "config.h" + +typedef enum action_t { + ACT_NORMAL = 0x00000001, + ACT_BROKEN_UPDATE = 0x00000002, +} action_t; + + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "ubigen - a tool for adding UBI information to a binary input file.\n"; + +static const char copyright [] __attribute__((unused)) = + "FIXME: insert license type"; /* FIXME */ + +#define CHECK_ENDP(option, endp) do { \ + if (*endp) { \ + fprintf(stderr, \ + "Parse error option \'%s\'. " \ + "No correct numeric value.\n" \ + , option); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +static struct argp_option options[] = { + /* COMMON */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Common settings:", + group: 1}, + + { name: "copyright", key: 'c', arg: NULL, flags: 0, + doc: "Print copyright information.", + group: 1 }, + + { name: "verbose", key: 'v', arg: NULL, flags: 0, + doc: "Print more progress information.", + group: 1 }, + + { name: "debug", key: 'd', arg: NULL, flags: 0, + group: 1 }, + + + /* INPUT */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "UBI Settings:", + group: 4}, + + { name: "alignment", key: 'A', arg: "", flags: 0, + doc: "Set the alignment size to (default 1).\n" + "Values can be specified as bytes, 'ki' or 'Mi'.", + group: 4 }, + + { name: "blocksize", key: 'B', arg: "", flags: 0, + doc: "Set the eraseblock size to (default 128 KiB).\n" + "Values can be specified as bytes, 'ki' or 'Mi'.", + group: 4 }, + + { name: "erasecount", key: 'E', arg: "", flags: 0, + doc: "Set the erase count to (default 0)", + group: 4 }, + + { name: "setver", key: 'X', arg: "", flags: 0, + doc: "Set UBI version number to (default 1)", + group: 4 }, + + { name: "id", key: 'I', arg: "", flags: 0, + doc: "The UBI volume id.", + group: 4 }, + + + { name: "offset", key: 'O', arg: "", flags: 0, + doc: "Offset from start of an erase block to the UBI volume header.", + group: 4 }, + + { name: "type", key: 'T', arg: "", flags: 0, + doc: "The UBI volume type:\n1 = dynamic, 2 = static", + group: 4 }, + + /* INPUT/OUTPUT */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Input/Output:", + group: 5 }, + + { name: "infile", key: 'i', arg: "", flags: 0, + doc: "Read input from file.", + group: 5 }, + + { name: "outfile", key: 'o', arg: "", flags: 0, + doc: "Write output to file (default is stdout).", + group: 5 }, + + /* Special options */ + { name: NULL, key: 0, arg: NULL, flags: 0, + doc: "Special options:", + group: 6 }, + + { name: "broken-update", key: 'U', arg: "", flags: 0, + doc: "Create an ubi image which simulates a broken update.\n" + " specifies the logical eraseblock number to update.\n", + group: 6 }, + + { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, +}; + +typedef struct myargs { + /* common settings */ + action_t action; + int verbose; + + int32_t id; + uint8_t type; + uint32_t eb_size; + uint64_t ec; + uint8_t version; + uint32_t hdr_offset; + uint32_t update_block; + uint32_t alignment; + + FILE* fp_in; + FILE* fp_out; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +} myargs; + + +static int ustrtoul(const char *cp, char **endp, unsigned int base) +{ + unsigned long result = strtoul(cp, endp, base); + + switch (**endp) { + case 'G': + result *= 1024; + case 'M': + result *= 1024; + case 'k': + case 'K': + result *= 1024; + /* "Ki", "ki", "Mi" or "Gi" are to be used. */ + if ((*endp)[1] == 'i') + (*endp) += 2; + } + return result; +} + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + int err = 0; + char* endp; + + myargs *args = state->input; + + switch (key) { + case 'c': + fprintf(stderr, "%s\n", copyright); + exit(0); + break; + case 'o': /* output */ + args->fp_out = fopen(arg, "wb"); + if ((args->fp_out) == NULL) { + fprintf(stderr, "Cannot open file %s for output\n", + arg); + exit(1); + } + break; + case 'i': /* input */ + args->fp_in = fopen(arg, "rb"); + if ((args->fp_in) == NULL) { + fprintf(stderr, "Cannot open file %s for input\n", + arg); + exit(1); + } + break; + case 'v': /* verbose */ + args->verbose = 1; + break; + + case 'B': /* eb_size */ + args->eb_size = (uint32_t) ustrtoul(arg, &endp, 0); + CHECK_ENDP("B", endp); + break; + case 'E': /* erasecount */ + args->ec = (uint64_t) strtoul(arg, &endp, 0); + CHECK_ENDP("E", endp); + break; + case 'I': /* id */ + args->id = (uint16_t) strtoul(arg, &endp, 0); + CHECK_ENDP("I", endp); + break; + case 'T': /* type */ + args->type = (uint16_t) strtoul(arg, &endp, 0); + CHECK_ENDP("T", endp); + break; + case 'X': /* versionnr */ + args->version = (uint8_t) strtoul(arg, &endp, 0); + CHECK_ENDP("X", endp); + break; + case 'O': /* offset for volume hdr */ + args->hdr_offset = + (uint32_t) strtoul(arg, &endp, 0); + CHECK_ENDP("O", endp); + break; + + case 'U': /* broken update */ + args->action = ACT_BROKEN_UPDATE; + args->update_block = + (uint32_t) strtoul(arg, &endp, 0); + CHECK_ENDP("U", endp); + break; + + case ARGP_KEY_ARG: + if (!args->fp_in) { + args->fp_in = fopen(arg, "rb"); + if ((args->fp_in) == NULL) { + fprintf(stderr, + "Cannot open file %s for input\n", arg); + exit(1); + } + } + args->arg1 = arg; + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + case ARGP_KEY_END: + + if (args->id < 0) { + err = 1; + fprintf(stderr, + "Please specify an UBI Volume ID.\n"); + } + if (args->type == 0) { + err = 1; + fprintf(stderr, + "Please specify an UBI Volume type.\n"); + } + if (err) { + fprintf(stderr, "\n"); + argp_usage(state); + exit(1); + } + break; + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: 0, + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + + +int +main(int argc, char **argv) +{ + int rc = 0; + ubi_info_t u; + struct stat file_info; + off_t input_len = 0; /* only used in static volumes */ + + myargs args = { + .action = ACT_NORMAL, + .verbose = 0, + + .id = -1, + .type = 0, + .eb_size = 0, + .update_block = 0, + .ec = 0, + .version = 0, + .hdr_offset = (DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE), + .alignment = 1, + + .fp_in = NULL, + .fp_out = stdout, + /* arguments */ + .arg1 = NULL, + .options = NULL, + }; + + ubigen_init(); /* Init CRC32 table in ubigen */ + + /* parse arguments */ + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + + if (fstat(fileno(args.fp_in), &file_info) != 0) { + fprintf(stderr, "Cannot fetch file size " + "from input file.\n"); + } + input_len = file_info.st_size; + + rc = ubigen_create(&u, (uint32_t)args.id, args.type, + args.eb_size, args.ec, args.alignment, + args.version, args.hdr_offset, 0 ,input_len, + args.fp_in, args.fp_out); + + if (rc != 0) { + fprintf(stderr, "Cannot create UBI info handler rc: %d\n", rc); + exit(EXIT_FAILURE); + } + + if (!args.fp_in || !args.fp_out) { + fprintf(stderr, "Input/Output error.\n"); + exit(EXIT_FAILURE); + + } + + if (args.action & ACT_NORMAL) { + rc = ubigen_write_complete(u); + } + else if (args.action & ACT_BROKEN_UPDATE) { + rc = ubigen_write_broken_update(u, args.update_block); + } + if (rc != 0) { + fprintf(stderr, "Error converting input data.\n"); + exit(EXIT_FAILURE); + } + + rc = ubigen_destroy(&u); + return rc; +} diff --git a/ubi-utils/src/ubigen.h b/ubi-utils/src/ubigen.h new file mode 100644 index 0000000..9e9e8ec --- /dev/null +++ b/ubi-utils/src/ubigen.h @@ -0,0 +1,149 @@ +#ifndef __UBIGEN_H__ +#define __UBIGEN_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: Frank Haverkamp + * + * An utility to update UBI volumes. + */ + +#include /* FILE */ +#include +#include + +#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_vol_tbl_record *lvol_rec); + +#ifdef __cplusplus +} +#endif + +#endif /* __UBIGEN_H__ */ diff --git a/ubi-utils/src/ubigen/ubigen_main.c b/ubi-utils/src/ubigen/ubigen_main.c deleted file mode 100644 index 8a464dd..0000000 --- a/ubi-utils/src/ubigen/ubigen_main.c +++ /dev/null @@ -1,369 +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 - * - * Tool to add UBI headers to binary images. - * - * 1.0 Initial version - * 1.1 Different CRC32 start value - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ubigen.h" -#include "config.h" - -typedef enum action_t { - ACT_NORMAL = 0x00000001, - ACT_BROKEN_UPDATE = 0x00000002, -} action_t; - - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "ubigen - a tool for adding UBI information to a binary input file.\n"; - -static const char copyright [] __attribute__((unused)) = - "FIXME: insert license type"; /* FIXME */ - -#define CHECK_ENDP(option, endp) do { \ - if (*endp) { \ - fprintf(stderr, \ - "Parse error option \'%s\'. " \ - "No correct numeric value.\n" \ - , option); \ - exit(EXIT_FAILURE); \ - } \ -} while(0) - -static struct argp_option options[] = { - /* COMMON */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Common settings:", - group: 1}, - - { name: "copyright", key: 'c', arg: NULL, flags: 0, - doc: "Print copyright information.", - group: 1 }, - - { name: "verbose", key: 'v', arg: NULL, flags: 0, - doc: "Print more progress information.", - group: 1 }, - - { name: "debug", key: 'd', arg: NULL, flags: 0, - group: 1 }, - - - /* INPUT */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "UBI Settings:", - group: 4}, - - { name: "alignment", key: 'A', arg: "", flags: 0, - doc: "Set the alignment size to (default 1).\n" - "Values can be specified as bytes, 'ki' or 'Mi'.", - group: 4 }, - - { name: "blocksize", key: 'B', arg: "", flags: 0, - doc: "Set the eraseblock size to (default 128 KiB).\n" - "Values can be specified as bytes, 'ki' or 'Mi'.", - group: 4 }, - - { name: "erasecount", key: 'E', arg: "", flags: 0, - doc: "Set the erase count to (default 0)", - group: 4 }, - - { name: "setver", key: 'X', arg: "", flags: 0, - doc: "Set UBI version number to (default 1)", - group: 4 }, - - { name: "id", key: 'I', arg: "", flags: 0, - doc: "The UBI volume id.", - group: 4 }, - - - { name: "offset", key: 'O', arg: "", flags: 0, - doc: "Offset from start of an erase block to the UBI volume header.", - group: 4 }, - - { name: "type", key: 'T', arg: "", flags: 0, - doc: "The UBI volume type:\n1 = dynamic, 2 = static", - group: 4 }, - - /* INPUT/OUTPUT */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Input/Output:", - group: 5 }, - - { name: "infile", key: 'i', arg: "", flags: 0, - doc: "Read input from file.", - group: 5 }, - - { name: "outfile", key: 'o', arg: "", flags: 0, - doc: "Write output to file (default is stdout).", - group: 5 }, - - /* Special options */ - { name: NULL, key: 0, arg: NULL, flags: 0, - doc: "Special options:", - group: 6 }, - - { name: "broken-update", key: 'U', arg: "", flags: 0, - doc: "Create an ubi image which simulates a broken update.\n" - " specifies the logical eraseblock number to update.\n", - group: 6 }, - - { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, -}; - -typedef struct myargs { - /* common settings */ - action_t action; - int verbose; - - int32_t id; - uint8_t type; - uint32_t eb_size; - uint64_t ec; - uint8_t version; - uint32_t hdr_offset; - uint32_t update_block; - uint32_t alignment; - - FILE* fp_in; - FILE* fp_out; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - - -static int ustrtoul(const char *cp, char **endp, unsigned int base) -{ - unsigned long result = strtoul(cp, endp, base); - - switch (**endp) { - case 'G': - result *= 1024; - case 'M': - result *= 1024; - case 'k': - case 'K': - result *= 1024; - /* "Ki", "ki", "Mi" or "Gi" are to be used. */ - if ((*endp)[1] == 'i') - (*endp) += 2; - } - return result; -} - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - int err = 0; - char* endp; - - myargs *args = state->input; - - switch (key) { - case 'c': - fprintf(stderr, "%s\n", copyright); - exit(0); - break; - case 'o': /* output */ - args->fp_out = fopen(arg, "wb"); - if ((args->fp_out) == NULL) { - fprintf(stderr, "Cannot open file %s for output\n", - arg); - exit(1); - } - break; - case 'i': /* input */ - args->fp_in = fopen(arg, "rb"); - if ((args->fp_in) == NULL) { - fprintf(stderr, "Cannot open file %s for input\n", - arg); - exit(1); - } - break; - case 'v': /* verbose */ - args->verbose = 1; - break; - - case 'B': /* eb_size */ - args->eb_size = (uint32_t) ustrtoul(arg, &endp, 0); - CHECK_ENDP("B", endp); - break; - case 'E': /* erasecount */ - args->ec = (uint64_t) strtoul(arg, &endp, 0); - CHECK_ENDP("E", endp); - break; - case 'I': /* id */ - args->id = (uint16_t) strtoul(arg, &endp, 0); - CHECK_ENDP("I", endp); - break; - case 'T': /* type */ - args->type = (uint16_t) strtoul(arg, &endp, 0); - CHECK_ENDP("T", endp); - break; - case 'X': /* versionnr */ - args->version = (uint8_t) strtoul(arg, &endp, 0); - CHECK_ENDP("X", endp); - break; - case 'O': /* offset for volume hdr */ - args->hdr_offset = - (uint32_t) strtoul(arg, &endp, 0); - CHECK_ENDP("O", endp); - break; - - case 'U': /* broken update */ - args->action = ACT_BROKEN_UPDATE; - args->update_block = - (uint32_t) strtoul(arg, &endp, 0); - CHECK_ENDP("U", endp); - break; - - case ARGP_KEY_ARG: - if (!args->fp_in) { - args->fp_in = fopen(arg, "rb"); - if ((args->fp_in) == NULL) { - fprintf(stderr, - "Cannot open file %s for input\n", arg); - exit(1); - } - } - args->arg1 = arg; - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - case ARGP_KEY_END: - - if (args->id < 0) { - err = 1; - fprintf(stderr, - "Please specify an UBI Volume ID.\n"); - } - if (args->type == 0) { - err = 1; - fprintf(stderr, - "Please specify an UBI Volume type.\n"); - } - if (err) { - fprintf(stderr, "\n"); - argp_usage(state); - exit(1); - } - break; - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: 0, - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - - -int -main(int argc, char **argv) -{ - int rc = 0; - ubi_info_t u; - struct stat file_info; - off_t input_len = 0; /* only used in static volumes */ - - myargs args = { - .action = ACT_NORMAL, - .verbose = 0, - - .id = -1, - .type = 0, - .eb_size = 0, - .update_block = 0, - .ec = 0, - .version = 0, - .hdr_offset = (DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE), - .alignment = 1, - - .fp_in = NULL, - .fp_out = stdout, - /* arguments */ - .arg1 = NULL, - .options = NULL, - }; - - ubigen_init(); /* Init CRC32 table in ubigen */ - - /* parse arguments */ - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - - if (fstat(fileno(args.fp_in), &file_info) != 0) { - fprintf(stderr, "Cannot fetch file size " - "from input file.\n"); - } - input_len = file_info.st_size; - - rc = ubigen_create(&u, (uint32_t)args.id, args.type, - args.eb_size, args.ec, args.alignment, - args.version, args.hdr_offset, 0 ,input_len, - args.fp_in, args.fp_out); - - if (rc != 0) { - fprintf(stderr, "Cannot create UBI info handler rc: %d\n", rc); - exit(EXIT_FAILURE); - } - - if (!args.fp_in || !args.fp_out) { - fprintf(stderr, "Input/Output error.\n"); - exit(EXIT_FAILURE); - - } - - if (args.action & ACT_NORMAL) { - rc = ubigen_write_complete(u); - } - else if (args.action & ACT_BROKEN_UPDATE) { - rc = ubigen_write_broken_update(u, args.update_block); - } - if (rc != 0) { - fprintf(stderr, "Error converting input data.\n"); - exit(EXIT_FAILURE); - } - - rc = ubigen_destroy(&u); - return rc; -} diff --git a/ubi-utils/src/ubiinfo/ubiflash.h b/ubi-utils/src/ubiinfo/ubiflash.h deleted file mode 100644 index 6883879..0000000 --- a/ubi-utils/src/ubiinfo/ubiflash.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef _UBI_FLASH_H -#define _UBI_FLASH_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. - */ - -/* - * FLASH related data structures and constants for UBI. - * UBI scan analysis. - * - * IPL Initial Program Loader - * SPL Secondary Program Loader - */ - -#include -#include -#include - -#define UBI_BLOCK_IDENT_MAX 16 - -/* Block status information constants */ -enum blockstat { - /* IO Error */ - STAT_IO_FAILED = 1, /* 0xffffffff */ - /* Block is bad */ - STAT_BLOCK_BAD = 2, /* 0xfffffffe */ - /* ECC unrecoverable error */ - STAT_ECC_ERROR = 3, /* 0xfffffffd */ - /* CRC checksum failed */ - STAT_CRC_ERROR = 4, /* 0xfffffffc */ - /* Magic number not available */ - STAT_NO_MAGIC = 5, /* 0xfffffffb */ - /* No image available */ - STAT_NO_IMAGE = 6, - /* Image is invalid */ - STAT_INVALID_IMAGE = 7, - /* Image is defect */ - STAT_DEFECT_IMAGE = 8, -}; - -/* - * Flash types - */ -enum flashtypes { - FLASH_TYPE_NAND = 1, - FLASH_TYPE_NOR, -}; - -/* Nand read buffer size: 2KiB + 64byte spare */ -#define NAND_READ_BUF_SIZE (2048 + 64) - -/* Size of the CRC table */ -#define CRC32_TABLE_SIZE 256 - -/* Image is not available marker for image offs */ -#define UBI_IMAGE_NOT_AVAILABLE 0xFFFFFFFF - -/* Increment this number, whenever you change the structure */ -#define UBI_SCAN_INFO_VERSION 2 - -/* Time measurement as far as the code size allows us to do this */ -#define UBI_TIMESTAMPS 16 - -/** - * struct ubi_scan_info - RAM table filled by IPL scan - * - * @version: Version of the structure - * @bootstatus: Boot status of the current boot - * @flashtype: Flash type (NAND/NOR) - * @flashid: ID of the flash chip - * @flashmfr: Manufacturer ID of the flash chip - * @flashsize: Size of the FLASH - * @blocksize: Eraseblock size - * @blockshift: Shift count to calc block number from offset - * @nrblocks: Number of erase blocks on flash - * @pagesize: Pagesize (NAND) - * @blockinfo: Pointer to an array of block status information - * filled by FLASH scan - * @images: Pointer to FLASH block translation table sorted - * by image type and load order - * @imageblocks: Number of blocks found per image - * @imageoffs: Offset per imagetype to the first - * block in the translation table - * @imagedups duplicate blocks (max. one per volume) - * @imagelen: Length of the loaded image - * @crc32_table: CRC32 table buffer - * @page_buf: Page buffer for NAND FLASH - */ -struct ubi_scan_info { - int version; - unsigned int bootstatus; - unsigned int flashtype; - unsigned int flashid; - unsigned int flashmfr; - unsigned int flashsize; - unsigned int blocksize; - unsigned int blockshift; - unsigned int nrblocks; - unsigned int pagesize; - - struct ubi_vid_hdr *blockinfo; - struct ubi_vid_hdr **images; - unsigned int imageblocks[UBI_BLOCK_IDENT_MAX]; - unsigned int imageoffs[UBI_BLOCK_IDENT_MAX]; - struct ubi_vid_hdr *imagedups[UBI_BLOCK_IDENT_MAX]; - unsigned int imagelen; - uint32_t crc32_table[CRC32_TABLE_SIZE]; - uint8_t page_buf[NAND_READ_BUF_SIZE]; - unsigned int times[UBI_TIMESTAMPS]; -}; - -/* External function definition */ -extern int flash_read(void *buf, unsigned int offs, int len); -extern int flash_read_slice(struct ubi_scan_info *fi, void *buf, - unsigned int offs, int len); -extern void ipl_main(struct ubi_scan_info *fi); - -#ifndef CFG_EXAMPLE_IPL -extern int ipl_scan(struct ubi_scan_info *fi); -extern int ipl_load(struct ubi_scan_info *fi, int nr, uint8_t *loadaddr); - -#define IPL_STATIC - -#else -#define IPL_STATIC static -#endif - -/** - * get_boot_status - get the boot status register - * - * Shift the lower 16 bit into the upper 16 bit and return - * the result. - */ -uint32_t get_boot_status(void); - -/** - * set_boot_status - Set the boot status register - * - * @status: The status value to set - * - */ -void set_boot_status(uint32_t status); - -static inline unsigned int ubi_vid_offset(struct ubi_scan_info *fi) -{ - if (fi->flashtype == FLASH_TYPE_NOR) - return UBI_EC_HDR_SIZE; - else - return fi->pagesize - UBI_VID_HDR_SIZE; -} - -static inline unsigned int ubi_data_offset(struct ubi_scan_info *fi) -{ - if (fi->flashtype == FLASH_TYPE_NOR) - return UBI_EC_HDR_SIZE + UBI_VID_HDR_SIZE; - else - return fi->pagesize; -} - -/** - * IPL checkpoints - */ -#define CHKP_HWINIT 0x3030 -#define CHKP_IPLSCAN_FAILED 0x3034 -#define CHKP_SPL_START 0x3037 -#define CHKP_SPLLOAD_STATUS 0x3130 - -extern void checkpoint(uint32_t cpoint); -extern void switch_watchdog(void); - -#endif diff --git a/ubi-utils/src/ubiinfo/ubiinfo.c b/ubi-utils/src/ubiinfo/ubiinfo.c deleted file mode 100644 index 6f7443b..0000000 --- a/ubi-utils/src/ubiinfo/ubiinfo.c +++ /dev/null @@ -1,406 +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. - */ - -/* - * Print out information about the UBI table this IPL is using. This - * can be used afterwards to analyze misbehavior of the IPL code. The - * input this program requires is the last 1 MiB DDRAM of our system - * where the scanning table is placed into. - * - * Author: Frank Haverkamp - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __unused __attribute__((unused)) - -/* This should hopefully be constant and the same in all - * configurations. - */ -#define CFG_IPLSIZE 512 -#define CFG_SPLCODE 512 -#define MEMTOP 0x06600000 /* Sunray 102 MiB */ -#define MEMSIZE 0x00100000 /* 1 MiB */ -#define CODE_SIZE (64 * 1024) - -/* FIXME Except of the memory size this should be defined via - * parameters - * - * CFG_MEMTOP_BAMBOO 0x02000000 - * CFG_MEMTOP_SUNRAY 0x06600000 - */ - -#include "ubiipl.h" -#include "ubiflash.h" - -#define MIN(x,y) ((x)<(y)?(x):(y)) - -#define ERR_RET(rc) { \ - fprintf(stderr, "%s:%d failed rc=%d\n", __func__, \ - __LINE__, (rc)); \ - return (rc); \ - } - -#define VERSION "1.3" - -static error_t parse_opt (int key, char *arg, struct argp_state *state); -const char *argp_program_version = VERSION; -const char *argp_program_bug_address = ""; - -static char doc[] = "\nVersion: " VERSION "\n\t" - " at "__DATE__" "__TIME__"\n" - "\n" - "Test program\n"; - -static struct argp_option options[] = { - /* common settings */ - { .name = "verbose", - .key = 'v', - .arg = "", - .flags = 0, - .doc = "Set verbosity level to ", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "memtop", - .key = 'm', - .arg = "", - .flags = 0, - .doc = "Set top of memory, 102 MiB for Sunray and 16 MiB for Bamboo", - .group = OPTION_ARG_OPTIONAL }, - - { .name = NULL, - .key = 0, - .arg = NULL, - .flags = 0, - .doc = NULL, - .group = 0 }, -}; - -typedef struct test_args { - int verbose; - unsigned long memtop; - char *arg1; - char **options; -} test_args; - -static struct test_args g_args = { - .memtop = MEMTOP, - .verbose = 0, - .arg1 = NULL, - .options = NULL, -}; - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: "[last_1MiB_memory.bin]", - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - -static int verbose = 0; - -/** - * @brief Parse the arguments passed into the test case. - * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. - * - * @return error_t - */ -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - /* Get the `input' argument from `argp_parse', which we - know is a pointer to our arguments structure. */ - test_args *args = state->input; - - switch (key) { - /* common settings */ - case 'v': /* --verbose= */ - verbose = args->verbose = strtoul(arg, (char **)NULL, 0); - break; - - case 'm': /* --memtop */ - args->memtop = strtoul(arg, (char **)NULL, 0); - break; - - case ARGP_KEY_NO_ARGS: - /* argp_usage(state); */ - break; - - case ARGP_KEY_ARG: - args->arg1 = arg; - /* Now we consume all the rest of the arguments. - `state->next' is the index in `state->argv' of the - next argument to be parsed, which is the first STRING - we're interested in, so we can just use - `&state->argv[state->next]' as the value for - arguments->strings. - - _In addition_, by setting `state->next' to the end - of the arguments, we can force argp to stop parsing - here and return. */ - - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - - case ARGP_KEY_END: - /* print out message if no arguments are given but PFI - write should be done */ - break; - - default: - return(ARGP_ERR_UNKNOWN); - } - return 0; -} - -static void -hexdump(const char *buf, int len) -{ - char line[16]; - char str[256]; - char dummy[256]; - int j = 0; - - while (len > 0) { - int i; - - strcpy(str, " "); - - for (j = 0; j < MIN(16, len); j++) - line[j] = *buf++; - - for (i = 0; i < j; i++) { - if (!(i & 3)) { - sprintf(dummy, " %.2x", line[i] & 0xff); - strcat(str, dummy); - } else { - sprintf(dummy, "%.2x", line[i] & 0xff); - strcat(str, dummy); - } - } - - /* Print empty space */ - for (; i < 16; i++) - if (!(i & 1)) - strcat(str, " "); - else - strcat(str, " "); - - strcat(str, " "); - for (i = 0; i < j; i++) { - if (isprint(line[i])) { - sprintf(dummy, "%c", line[i]); - strcat(str, dummy); - } else { - strcat(str, "."); - } - } - printf("%s\n", str); - len -= 16; - } -} - -static void -print_status_help(void) -{ - printf("Error Codes from IPL\n"); - printf(" IO Error %d\n", STAT_IO_FAILED); - printf(" Block is bad %d\n", STAT_BLOCK_BAD); - printf(" ECC unrec error %d\n", STAT_ECC_ERROR); - printf(" CRC csum failed %d\n", STAT_CRC_ERROR); - printf(" Magic not avail %d\n", STAT_NO_MAGIC); - printf(" No image avail %d\n", STAT_NO_IMAGE); - printf(" Image is invalid %d\n", STAT_INVALID_IMAGE); - printf(" Image is defect %d\n\n", STAT_DEFECT_IMAGE); - -} - -static void -print_ubi_scan_info(struct ubi_scan_info *fi) -{ - int i; - - printf("ubi_scan_info\n"); - printf(" version %08x\n", ntohl(fi->version)); - printf(" bootstatus %08x\n", ntohl(fi->bootstatus)); - printf(" flashtype %08x\n", ntohl(fi->flashtype)); - printf(" flashid %08x\n", ntohl(fi->flashid)); - printf(" flashmfgr %08x\n", ntohl(fi->flashmfr)); - printf(" flashsize %d bytes (%dM)\n", - ntohl(fi->flashsize), ntohl(fi->flashsize) / (1024 * 1024)); - printf(" blocksize %d bytes\n", ntohl(fi->blocksize)); - printf(" blockshift %d\n", ntohl(fi->blockshift)); - printf(" nrblocks %d\n", ntohl(fi->nrblocks)); - printf(" pagesize %d\n", ntohl(fi->pagesize)); - printf(" imagelen %d\n", ntohl(fi->imagelen)); - printf(" blockinfo %08x\n", ntohl((int)fi->blockinfo)); - - printf(" nr imageblocks imageoffs\n"); - for (i = 0; i < UBI_BLOCK_IDENT_MAX; i++) - printf(" [%2d] %08x %08x\n", i, - ntohl(fi->imageblocks[i]), - ntohl(fi->imageoffs[i])); - - for (i = 0; i < UBI_TIMESTAMPS; i++) { - if (!ntohl(fi->times[i])) - continue; - printf("time[%3d] = %08x %.3f sec\n", i, ntohl(fi->times[i]), - (double)ntohl(fi->times[i]) / 500000000.0); - } - - printf("crc32_table\n"); - hexdump((char *)&fi->crc32_table, sizeof(fi->crc32_table)); - printf("\npage_buf\n"); - hexdump((char *)&fi->page_buf, sizeof(fi->page_buf)); - - printf("\n"); - -} - -static void -print_ubi_block_info(struct ubi_scan_info *fi, - struct ubi_vid_hdr *bi, int nr) -{ - int i; - int unknown = 0; - - printf("\nBINFO\n"); - - for (i = 0; i < nr; i++) { - if ((int)ubi32_to_cpu(bi[i].magic) != UBI_VID_HDR_MAGIC) { - printf("block=%d %08x\n", - i, i * ntohl(fi->blocksize)); -#if 0 - printf("."); - if ((unknown & 0x3f) == 0x3f) - printf("\n"); - unknown++; -#else - hexdump((char *)&bi[i], - sizeof(struct ubi_vid_hdr)); -#endif - } else { - if (unknown) - printf("\n"); - printf("block=%d %08x\n" - " leb_ver=0x%x data_size=%d " - "lnum=%d used_ebs=0x%x\n" - " data_crc=%08x hdr_crc=%08x\n", - i, i * ntohl(fi->blocksize), - ubi32_to_cpu(bi[i].leb_ver), - ubi32_to_cpu(bi[i].data_size), - ubi32_to_cpu(bi[i].lnum), - ubi32_to_cpu(bi[i].used_ebs), - ubi32_to_cpu(bi[i].data_crc), - ubi32_to_cpu(bi[i].hdr_crc)); - hexdump((char *)&bi[i], - sizeof(struct ubi_vid_hdr)); - unknown = 0; - } - } -} - -static int do_read(unsigned int memtop, char *buf, int buf_len __unused) -{ - unsigned long finfo_addr; - unsigned long binfo_addr; - unsigned long images_addr; - unsigned long nrblocks; - unsigned long bi_size; - unsigned long images_size; - struct ubi_scan_info *fi; - struct ubi_vid_hdr *bi; - char *images; - unsigned long memaddr = memtop - MEMSIZE; - - print_status_help(); - - /* Read and print FINFO */ - finfo_addr = MEMSIZE - CFG_IPLSIZE * 1024; - - printf("read info at addr %08lx\n", finfo_addr); - fi = (struct ubi_scan_info *)(buf + finfo_addr); - - binfo_addr = ntohl((unsigned long)fi->blockinfo) - memaddr; - images_addr = ntohl((unsigned long)fi->images) - memaddr; - nrblocks = ntohl(fi->nrblocks); - - printf("BINFO %08lx\n", binfo_addr); - - bi_size = nrblocks * sizeof(struct ubi_vid_hdr); - images_size = nrblocks * sizeof(unsigned int); - - printf("FINFO\n"); - print_ubi_scan_info(fi); - /* hexdump((char *)fi, sizeof(*fi)); */ - - /* Read and print BINFO */ - bi = (struct ubi_vid_hdr *)(buf + binfo_addr); - print_ubi_block_info(fi, bi, nrblocks); - - /* Read and print IMAGES */ - images = buf + images_addr; - printf("\nIMAGES\n"); - hexdump(images, images_size); - - return 0; -} - -int main(int argc, char *argv[]) -{ - char buf[MEMSIZE]; - FILE *fp; - int rc; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &g_args); - - if (!g_args.arg1) { - fprintf(stderr, "Please specify a file " - "name for memory dump!\n"); - exit(EXIT_FAILURE); - } - - memset(buf, 0xAB, sizeof(buf)); - - fp = fopen(g_args.arg1, "r"); - if (!fp) - exit(EXIT_FAILURE); - rc = fread(buf, 1, sizeof(buf), fp); - if (rc != sizeof(buf)) - exit(EXIT_FAILURE); - fclose(fp); - do_read(g_args.memtop, buf, sizeof(buf)); - - exit(EXIT_SUCCESS); -} diff --git a/ubi-utils/src/ubiinfo/ubiipl.h b/ubi-utils/src/ubiinfo/ubiipl.h deleted file mode 100644 index 3a8b900..0000000 --- a/ubi-utils/src/ubiinfo/ubiipl.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _UBI_IPL_H -#define _UBI_IPL_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. - */ - -/* - * Constants calculated from the CFG_XXX defines - * - * Declaration of the loader function which is invoked by the - * assembler part of the IPL - */ - -/* Size of IPL - is 4K for NAND and can also be 4K for NOR */ -#define IPL_SIZE 4096 - -/* Needed in asm code to upload the data, needed in C-code for CRC32 */ -#define IPL_RAMADDR (CFG_MEMTOP - IPL_SIZE) - -#if !defined(__ASSEMBLY__) - -#include -#include - -/* Address of the flash info structure */ -#define FINFO_ADDR (struct ubi_scan_info *) (CFG_MEMTOP - CFG_IPLSIZE * 1024) - -/* Size of the flash info structure */ -#define FINFO_SIZE sizeof(struct ubi_scan_info) - -/* Blockinfo array address */ -#define BINFO_ADDR (struct ubi_vid_hdr *) ((void *)FINFO_ADDR + FINFO_SIZE) - -/* Number of erase blocks */ -#define NR_ERASE_BLOCKS ((CFG_FLASHSIZE * 1024) / CFG_BLOCKSIZE) - -/* Blockinfo size */ -#define BINFO_SIZE (NR_ERASE_BLOCKS * sizeof(struct ubi_vid_hdr)) - -/* Images array address */ -#define IMAGES_ADDR (struct ubi_vid_hdr **) ((void *)BINFO_ADDR + BINFO_SIZE) - -/* Images array size */ -#define IMAGES_SIZE (NR_ERASE_BLOCKS * sizeof(unsigned int)) - -/* Total size of flash info + blockinfo + images */ -#define INFO_SIZE ((FINFO_SIZE + BINFO_SIZE + IMAGES_SIZE) / sizeof(uint32_t)) - -/* Load address of the SPL */ -#define SPL_ADDR (void *) ((void *)FINFO_ADDR - CFG_SPLCODE * 1024) - -#define IPL_SIZE_CRC32 (IPL_SIZE - sizeof(uint32_t)) -#define IPL_RAMADDR_CRC32 ((void *)(IPL_RAMADDR + sizeof(uint32_t))) - -/* - * Linker script magic to ensure that load_spl() is linked to the - * right place - */ -#define __crc32 __attribute__((__section__(".crc32"))) -#define __entry __attribute__((__section__(".entry.text"))) -#define __unused __attribute__((unused)) - -#define MIN(x,y) ((x)<(y)?(x):(y)) - -#define stop_on_error(x) \ - { while (1); } - -void __entry load_spl(void); -void hardware_init(void); - -#endif /* __ASSEMBLY__ */ - -#endif diff --git a/ubi-utils/src/ubimirror.c b/ubi-utils/src/ubimirror.c new file mode 100644 index 0000000..e43ba10 --- /dev/null +++ b/ubi-utils/src/ubimirror.c @@ -0,0 +1,206 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "error.h" +#include "example_ubi.h" +#include "ubimirror.h" + +typedef enum action_t { + ACT_NORMAL = 0, + ACT_ARGP_ABORT, + ACT_ARGP_ERR, +} action_t; + +#define ABORT_ARGP do { \ + state->next = state->argc; \ + args->action = ACT_ARGP_ABORT; \ +} while (0) + +#define ERR_ARGP do { \ + state->next = state->argc; \ + args->action = ACT_ARGP_ERR; \ +} while (0) + +#define VOL_ARGS_MAX 2 + + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " + BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" + "\n" + "ubimirror - mirrors ubi volumes.\n"; + +static const char copyright [] __attribute__((unused)) = + "(C) IBM Coorporation 2007"; + + +static struct argp_option options[] = { + { name: "copyright", key: 'c', arg: NULL, flags: 0, + doc: "Print copyright information.", + group: 1 }, + + { name: "side", key: 's', arg: "", flags: 0, + doc: "Use the side as source.", + group: 1 }, + + { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, +}; + +typedef struct myargs { + action_t action; + int side; + int vol_no; /* index of current volume */ + /* @FIXME replace by bootenv_list, makes live easier */ + /* @FIXME remove the constraint of two entries in the array */ + const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst + volumes */ + char *arg1; + char **options; /* [STRING...] */ +} myargs; + +static int +get_update_side(const char* str) +{ + uint32_t i = strtoul(str, NULL, 0); + + if ((i != 0) && (i != 1)) { + return -1; + } + return i; +} + + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + int err = 0; + + myargs *args = state->input; + + switch (key) { + case 'c': + err_msg("%s\n", copyright); + ABORT_ARGP; + break; + case 's': + args->side = get_update_side(arg); + if (args->side < 0) { + err_msg("Unsupported seqnum: %s.\n" + "Supported seqnums are '0' and '1'\n", arg); + ERR_ARGP; + } + break; + case ARGP_KEY_ARG: + /* only two entries allowed */ + if (args->vol_no >= VOL_ARGS_MAX) { + err_msg("\n"); + argp_usage(state); + ERR_ARGP; + } + args->vol[(args->vol_no)++] = arg; + break; + case ARGP_KEY_END: + if (err) { + err_msg("\n"); + argp_usage(state); + ERR_ARGP; + } + break; + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: " ", + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + + +int +main(int argc, char **argv) { + int rc = 0; + unsigned int ids[VOL_ARGS_MAX]; + char err_buf[1024]; + + myargs args = { + .action = ACT_NORMAL, + .side = -1, + .vol_no = 0, + .vol = {"", ""}, + .options = NULL, + }; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); + if (args.action == ACT_ARGP_ERR) { + rc = 127; + goto err; + } + if (args.action == ACT_ARGP_ABORT) { + rc = 126; + goto out; + } + if (args.vol_no < VOL_ARGS_MAX) { + fprintf(stderr, "missing volume number for %s\n", + args.vol_no == 0 ? "source and target" : "target"); + rc = 125; + goto out; + } + for( rc = 0; rc < args.vol_no; ++rc){ + char *endp; + ids[rc] = strtoul(args.vol[rc], &endp, 0); + if( *endp != '\0' ){ + fprintf(stderr, "invalid volume number %s\n", + args.vol[rc]); + rc = 125; + goto out; + } + } + rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no, + err_buf, sizeof(err_buf)); + if( rc ){ + err_buf[sizeof err_buf - 1] = '\0'; + fprintf(stderr, err_buf); + if( rc < 0 ) + rc = -rc; + } + out: + err: + return rc; +} diff --git a/ubi-utils/src/ubimirror.h b/ubi-utils/src/ubimirror.h new file mode 100644 index 0000000..d7ae2ad --- /dev/null +++ b/ubi-utils/src/ubimirror.h @@ -0,0 +1,66 @@ +#ifndef __UBIMIRROR_H__ +#define __UBIMIRROR_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 + * + * An utility to mirror UBI volumes. + */ + +#include + +/** + * @def EUBIMIRROR_SRC_EQ_DST + * @brief Given source volume is also in the set of destination volumes. + */ +#define EUBIMIRROR_SRC_EQ_DST 20 + +/** + * @def EUBIMIRROR_NO_SRC + * @brief The given source volume does not exist. + */ +#define EUBIMIRROR_NO_SRC 21 + +/** + * @def EUBIMIRROR_NO_DST + * @brief One of the given destination volumes does not exist. + */ +#define EUBIMIRROR_NO_DST 22 + +/** + * @brief Mirrors UBI devices from a source device (specified by seqnum) + * to n target devices. + * @param devno Device number used by the UBI operations. + * @param seqnum An index into ids (defines the src_id). + * @param ids An array of ids. + * @param ids_size The number of entries in the ids array. + * @param err_buf A buffer to store verbose error messages. + * @param err_buf_size The size of the error buffer. + * + * @note A seqnum of value < 0 defaults to a seqnum of 0. + * @note A seqnum exceeding the range of ids_size defaults to 0. + * @note An empty ids list results in a empty stmt. + * @pre The UBI volume which shall be used as source volume exists. + * @pre The UBI volumes which are defined as destination volumes exist. + * @post The content of the UBI volume which was defined as source volume + * equals the content of the volumes which were defined as destination. + */ +int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, ssize_t ids_size, + char *err_buf, size_t err_buf_size); + +#endif /* __UBIMIRROR_H__ */ diff --git a/ubi-utils/src/ubimirror/ubimirror.c b/ubi-utils/src/ubimirror/ubimirror.c deleted file mode 100644 index e43ba10..0000000 --- a/ubi-utils/src/ubimirror/ubimirror.c +++ /dev/null @@ -1,206 +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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "error.h" -#include "example_ubi.h" -#include "ubimirror.h" - -typedef enum action_t { - ACT_NORMAL = 0, - ACT_ARGP_ABORT, - ACT_ARGP_ERR, -} action_t; - -#define ABORT_ARGP do { \ - state->next = state->argc; \ - args->action = ACT_ARGP_ABORT; \ -} while (0) - -#define ERR_ARGP do { \ - state->next = state->argc; \ - args->action = ACT_ARGP_ERR; \ -} while (0) - -#define VOL_ARGS_MAX 2 - - -const char *argp_program_version = PACKAGE_VERSION; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " - BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" - "\n" - "ubimirror - mirrors ubi volumes.\n"; - -static const char copyright [] __attribute__((unused)) = - "(C) IBM Coorporation 2007"; - - -static struct argp_option options[] = { - { name: "copyright", key: 'c', arg: NULL, flags: 0, - doc: "Print copyright information.", - group: 1 }, - - { name: "side", key: 's', arg: "", flags: 0, - doc: "Use the side as source.", - group: 1 }, - - { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, -}; - -typedef struct myargs { - action_t action; - int side; - int vol_no; /* index of current volume */ - /* @FIXME replace by bootenv_list, makes live easier */ - /* @FIXME remove the constraint of two entries in the array */ - const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst - volumes */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static int -get_update_side(const char* str) -{ - uint32_t i = strtoul(str, NULL, 0); - - if ((i != 0) && (i != 1)) { - return -1; - } - return i; -} - - -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - int err = 0; - - myargs *args = state->input; - - switch (key) { - case 'c': - err_msg("%s\n", copyright); - ABORT_ARGP; - break; - case 's': - args->side = get_update_side(arg); - if (args->side < 0) { - err_msg("Unsupported seqnum: %s.\n" - "Supported seqnums are '0' and '1'\n", arg); - ERR_ARGP; - } - break; - case ARGP_KEY_ARG: - /* only two entries allowed */ - if (args->vol_no >= VOL_ARGS_MAX) { - err_msg("\n"); - argp_usage(state); - ERR_ARGP; - } - args->vol[(args->vol_no)++] = arg; - break; - case ARGP_KEY_END: - if (err) { - err_msg("\n"); - argp_usage(state); - ERR_ARGP; - } - break; - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static struct argp argp = { - options: options, - parser: parse_opt, - args_doc: " ", - doc: doc, - children: NULL, - help_filter: NULL, - argp_domain: NULL, -}; - - -int -main(int argc, char **argv) { - int rc = 0; - unsigned int ids[VOL_ARGS_MAX]; - char err_buf[1024]; - - myargs args = { - .action = ACT_NORMAL, - .side = -1, - .vol_no = 0, - .vol = {"", ""}, - .options = NULL, - }; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); - if (args.action == ACT_ARGP_ERR) { - rc = 127; - goto err; - } - if (args.action == ACT_ARGP_ABORT) { - rc = 126; - goto out; - } - if (args.vol_no < VOL_ARGS_MAX) { - fprintf(stderr, "missing volume number for %s\n", - args.vol_no == 0 ? "source and target" : "target"); - rc = 125; - goto out; - } - for( rc = 0; rc < args.vol_no; ++rc){ - char *endp; - ids[rc] = strtoul(args.vol[rc], &endp, 0); - if( *endp != '\0' ){ - fprintf(stderr, "invalid volume number %s\n", - args.vol[rc]); - rc = 125; - goto out; - } - } - rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no, - err_buf, sizeof(err_buf)); - if( rc ){ - err_buf[sizeof err_buf - 1] = '\0'; - fprintf(stderr, err_buf); - if( rc < 0 ) - rc = -rc; - } - out: - err: - return rc; -} diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c new file mode 100644 index 0000000..30c569c --- /dev/null +++ b/ubi-utils/src/ubimkvol.c @@ -0,0 +1,251 @@ +/* + * 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. + */ + +/* + * An utility to create UBI volumes. + * + * Author: Artem B. Bityutskiy + * + * 1.0 Initial release + * 1.1 Does not support erase blocks anymore. This is replaced by + * the number of bytes. + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include + +static void usage(void); +static int param_sanity_check(ubi_lib_t lib); +static int parse_options(int argc, char * const argv[]); + +/* + * The variables below are set by command line arguments. + */ +static int vol_type = UBI_DYNAMIC_VOLUME; +static int devn = -1; +static long long bytes = 0; +static int alignment = 1; +static int vol_id = UBI_VOL_NUM_AUTO; +static char *name = NULL; +static int nlen = 0; + +int main(int argc, char * const argv[]) +{ + int err; + ubi_lib_t lib; + + err = parse_options(argc, argv); + if (err) { + fprintf(stderr, "Wrong options ...\n"); + return err == 1 ? 0 : -1; + } + + if (devn == -1) { + fprintf(stderr, "Device number was not specified\n"); + fprintf(stderr, "Use -h option for help\n"); + return -1; + } + + err = ubi_open(&lib); + if (err) { + perror("Cannot open libubi"); + return -1; + } + + err = param_sanity_check(lib); + if (err) { + perror("Input parameters check"); + fprintf(stderr, "Use -h option for help\n"); + goto out_libubi; + } + + err = ubi_mkvol(lib, devn, vol_id, vol_type, bytes, alignment, name); + if (err < 0) { + perror("Cannot create volume"); + fprintf(stderr, " err=%d\n", err); + goto out_libubi; + } + + /* printf("Created volume %d, %lld bytes, type %s, name %s\n", + vol_id, bytes, vol_type == UBI_DYNAMIC_VOLUME ? + "dynamic" : "static", name); */ + + vol_id = err; + ubi_close(&lib); + return 0; + +out_libubi: + ubi_close(&lib); + return -1; +} + +/* 'getopt()' option string */ +static const char *optstring = "ht:s:n:N:d:a:"; + +static int parse_options(int argc, char * const argv[]) +{ + int opt = 0; + + while (opt != -1) { + char *endp; + + opt = getopt(argc, argv, optstring); + + switch (opt) { + case 'h': + usage(); + return 1; + case 't': + if (!strcmp(optarg, "dynamic")) + vol_type = UBI_DYNAMIC_VOLUME; + else if (!strcmp(optarg, "static")) + vol_type = UBI_STATIC_VOLUME; + else { + fprintf(stderr, "Bad volume type: \"%s\"\n", + optarg); + goto out; + } + break; + case 's': + bytes = strtoull(optarg, &endp, 0); + if (endp == optarg || bytes < 0) { + fprintf(stderr, "Bad volume size: \"%s\"\n", + optarg); + goto out; + } + if (endp != '\0') { + if (strcmp(endp, "KiB") == 0) + bytes *= 1024; + else if (strcmp(endp, "MiB") == 0) + bytes *= 1024*1024; + } + break; + case 'a': + alignment = strtoul(optarg, &endp, 0); + if (*endp != '\0' || endp == optarg || + alignment <= 0) { + fprintf(stderr, "Bad volume alignment: " + "\"%s\"\n", optarg); + goto out; + } + break; + case 'd': + devn = strtoul(optarg, &endp, 0); + if (*endp != '\0' || endp == optarg || devn < 0) { + fprintf(stderr, "Bad UBI device number: " + "\"%s\"\n", optarg); + goto out; + } + break; + case 'n': + vol_id = strtoul(optarg, &endp, 0); + if (*endp != '\0' || endp == optarg || + (vol_id < 0 && vol_id != UBI_DYNAMIC_VOLUME)) { + fprintf(stderr, "Bad volume ID: " + "\"%s\"\n", optarg); + goto out; + } + break; + case 'N': + name = optarg; + nlen = strlen(name); + break; + + case ':': + fprintf(stderr, "Parameter is missing\n"); + goto out; + case '?': + fprintf(stderr, "Unknown parameter\n"); + goto out; + case -1: + break; + default: + fprintf(stderr, "Internal error\n"); + goto out; + } + } + + return 0; + + out: + errno = EINVAL; + return -1; +} + +static int param_sanity_check(ubi_lib_t lib) +{ + int err, len; + struct ubi_info ubi; + + if (bytes == 0) { + fprintf(stderr, "Volume size was not specified\n"); + goto out; + } + + if (name == NULL) { + fprintf(stderr, "Volume name was not specified\n"); + goto out; + } + + err = ubi_get_info(lib, &ubi); + if (err) + return -1; + + if (devn >= (int)ubi.dev_count) { + fprintf(stderr, "Device %d does not exist\n", devn); + goto out; + } + + len = strlen(name); + if (len > (int)ubi.nlen_max) { + fprintf(stderr, "Too long name (%d symbols), max is %d\n", + len, ubi.nlen_max); + goto out; + } + + return 0; + +out: + errno = EINVAL; + return -1; +} + +static void usage(void) +{ + printf("Usage: ubi_mkvol OPTIONS\n" + "Version: " PACKAGE_VERSION "\n" + "The command line options:\n" + "\t-h - this help message\n" + "\t-d - UBI device number\n" + "\t-t TYPE - volume type (dynamic, static) " + "(default is dynamic)\n" + "\t-n VOLID - volume ID to assign to the new volume. If not" + "specified, \n" + "\t the volume ID will be assigned automatically\n" + "\t-s BYTES - volume size in bytes, " + "kilobytes (KiB) or megabytes (MiB)\n" + "\t-N NAME - volume name\n" + "\t-a ALIGNMENT - volume alignment (default is 1)\n"); +} diff --git a/ubi-utils/src/ubimkvol/ubimkvol.c b/ubi-utils/src/ubimkvol/ubimkvol.c deleted file mode 100644 index f929252..0000000 --- a/ubi-utils/src/ubimkvol/ubimkvol.c +++ /dev/null @@ -1,252 +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. - */ - -/* - * An utility to create UBI volumes. - * - * Author: Artem B. Bityutskiy - * - * 1.0 Initial release - * 1.1 Does not support erase blocks anymore. This is replaced by - * the number of bytes. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#define VERSION "1.1" - -static void usage(void); -static int param_sanity_check(ubi_lib_t lib); -static int parse_options(int argc, char * const argv[]); - -/* - * The variables below are set by command line arguments. - */ -static int vol_type = UBI_DYNAMIC_VOLUME; -static int devn = -1; -static long long bytes = 0; -static int alignment = 1; -static int vol_id = UBI_VOL_NUM_AUTO; -static char *name = NULL; -static int nlen = 0; - -int main(int argc, char * const argv[]) -{ - int err; - ubi_lib_t lib; - - err = parse_options(argc, argv); - if (err) { - fprintf(stderr, "Wrong options ...\n"); - return err == 1 ? 0 : -1; - } - - if (devn == -1) { - fprintf(stderr, "Device number was not specified\n"); - fprintf(stderr, "Use -h option for help\n"); - return -1; - } - - err = ubi_open(&lib); - if (err) { - perror("Cannot open libubi"); - return -1; - } - - err = param_sanity_check(lib); - if (err) { - perror("Input parameters check"); - fprintf(stderr, "Use -h option for help\n"); - goto out_libubi; - } - - err = ubi_mkvol(lib, devn, vol_id, vol_type, bytes, alignment, name); - if (err < 0) { - perror("Cannot create volume"); - fprintf(stderr, " err=%d\n", err); - goto out_libubi; - } - - /* printf("Created volume %d, %lld bytes, type %s, name %s\n", - vol_id, bytes, vol_type == UBI_DYNAMIC_VOLUME ? - "dynamic" : "static", name); */ - - vol_id = err; - ubi_close(&lib); - return 0; - -out_libubi: - ubi_close(&lib); - return -1; -} - -/* 'getopt()' option string */ -static const char *optstring = "ht:s:n:N:d:a:"; - -static int parse_options(int argc, char * const argv[]) -{ - int opt = 0; - - while (opt != -1) { - char *endp; - - opt = getopt(argc, argv, optstring); - - switch (opt) { - case 'h': - usage(); - return 1; - case 't': - if (!strcmp(optarg, "dynamic")) - vol_type = UBI_DYNAMIC_VOLUME; - else if (!strcmp(optarg, "static")) - vol_type = UBI_STATIC_VOLUME; - else { - fprintf(stderr, "Bad volume type: \"%s\"\n", - optarg); - goto out; - } - break; - case 's': - bytes = strtoull(optarg, &endp, 0); - if (endp == optarg || bytes < 0) { - fprintf(stderr, "Bad volume size: \"%s\"\n", - optarg); - goto out; - } - if (endp != '\0') { - if (strcmp(endp, "KiB") == 0) - bytes *= 1024; - else if (strcmp(endp, "MiB") == 0) - bytes *= 1024*1024; - } - break; - case 'a': - alignment = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - alignment <= 0) { - fprintf(stderr, "Bad volume alignment: " - "\"%s\"\n", optarg); - goto out; - } - break; - case 'd': - devn = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || devn < 0) { - fprintf(stderr, "Bad UBI device number: " - "\"%s\"\n", optarg); - goto out; - } - break; - case 'n': - vol_id = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - (vol_id < 0 && vol_id != UBI_DYNAMIC_VOLUME)) { - fprintf(stderr, "Bad volume ID: " - "\"%s\"\n", optarg); - goto out; - } - break; - case 'N': - name = optarg; - nlen = strlen(name); - break; - - case ':': - fprintf(stderr, "Parameter is missing\n"); - goto out; - case '?': - fprintf(stderr, "Unknown parameter\n"); - goto out; - case -1: - break; - default: - fprintf(stderr, "Internal error\n"); - goto out; - } - } - - return 0; - - out: - errno = EINVAL; - return -1; -} - -static int param_sanity_check(ubi_lib_t lib) -{ - int err, len; - struct ubi_info ubi; - - if (bytes == 0) { - fprintf(stderr, "Volume size was not specified\n"); - goto out; - } - - if (name == NULL) { - fprintf(stderr, "Volume name was not specified\n"); - goto out; - } - - err = ubi_get_info(lib, &ubi); - if (err) - return -1; - - if (devn >= ubi.dev_count) { - fprintf(stderr, "Device %d does not exist\n", devn); - goto out; - } - - len = strlen(name); - if (len > ubi.nlen_max) { - fprintf(stderr, "Too long name (%d symbols), max is %d\n", - len, ubi.nlen_max); - goto out; - } - - return 0; - -out: - errno = EINVAL; - return -1; -} - -static void usage(void) -{ - printf("Usage: ubi_mkvol OPTIONS\n" - "Version: " VERSION "\n" - "The command line options:\n" - "\t-h - this help message\n" - "\t-d - UBI device number\n" - "\t-t TYPE - volume type (dynamic, static) " - "(default is dynamic)\n" - "\t-n VOLID - volume ID to assign to the new volume. If not" - "specified, \n" - "\t the volume ID will be assigned automatically\n" - "\t-s BYTES - volume size in bytes, " - "kilobytes (KiB) or megabytes (MiB)\n" - "\t-N NAME - volume name\n" - "\t-a ALIGNMENT - volume alignment (default is 1)\n"); -} diff --git a/ubi-utils/src/ubirmvol.c b/ubi-utils/src/ubirmvol.c new file mode 100644 index 0000000..cb47b6c --- /dev/null +++ b/ubi-utils/src/ubirmvol.c @@ -0,0 +1,174 @@ +/* + * 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. + */ + +/* + * An utility to create UBI volumes. + * + * Autor: Artem B. Bityutskiy + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include + +static void usage(void); +static int param_sanity_check(ubi_lib_t lib); +static int parse_options(int argc, char * const argv[]); + +/* + * The below variables are set by command line options. + */ +static int vol_id = -1; +static int devn = -1; + +int main(int argc, char * const argv[]) +{ + int err, old_errno; + ubi_lib_t lib; + + err = parse_options(argc, argv); + if (err) + return err == 1 ? 0 : -1; + + if (devn == -1) { + fprintf(stderr, "Device number was not specified\n"); + fprintf(stderr, "Use -h option for help\n"); + return -1; + } + + err = ubi_open(&lib); + if (err) { + perror("Cannot open libubi"); + return -1; + } + + err = param_sanity_check(lib); + if (err) { + perror("Input parameters check"); + fprintf(stderr, "Use -h option for help\n"); + goto out_libubi; + } + + err = ubi_rmvol(lib, devn, vol_id); + old_errno = errno; + if (err < 0) { + perror("Cannot remove volume"); + fprintf(stderr, " err=%d errno=%d\n", err, old_errno); + goto out_libubi; + } + + return 0; + +out_libubi: + ubi_close(&lib); + return -1; +} + +/* 'getopt()' option string */ +static const char *optstring = "hd:n:"; + +static int parse_options(int argc, char * const argv[]) +{ + int opt = 0; + + while (opt != -1) { + char *endp; + + opt = getopt(argc, argv, optstring); + + switch (opt) { + case 'h': + usage(); + return 1; + case 'n': + vol_id = strtoul(optarg, &endp, 0); + if (*endp != '\0' || endp == optarg || vol_id < 0) { + fprintf(stderr, "Bad volume " + "number: \"%s\"\n", optarg); + goto out; + } + break; + case 'd': + devn = strtoul(optarg, &endp, 0); + if (*endp != '\0' || endp == optarg || devn < 0) { + fprintf(stderr, "Bad UBI device " + "number: \"%s\"\n", optarg); + goto out; + } + break; + case ':': + fprintf(stderr, "Parameter is missing\n"); + goto out; + case '?': + fprintf(stderr, "Unknown parameter\n"); + goto out; + case -1: + break; + default: + fprintf(stderr, "Internal error\n"); + goto out; + } + } + + return 0; + +out: + errno = EINVAL; + return -1; +} + +static int param_sanity_check(ubi_lib_t lib) +{ + int err; + struct ubi_info ubi; + + if (vol_id == -1) { + fprintf(stderr, "Volume ID was not specified\n"); + goto out; + } + + err = ubi_get_info(lib, &ubi); + if (err) + return -1; + + if (devn >= (int)ubi.dev_count) { + fprintf(stderr, "Device %d does not exist\n", devn); + goto out; + } + + return 0; + +out: + errno = EINVAL; + return -1; +} + +static void usage(void) +{ + printf("Usage: ubi_rmvol OPTIONS\n" + "Command line options:\n" + "\t-h - this help message\n" + "\t-d - UBI device number\n" + "\t-n VOLNUM - volume number to remove\n"); +} diff --git a/ubi-utils/src/ubirmvol/ubirmvol.c b/ubi-utils/src/ubirmvol/ubirmvol.c deleted file mode 100644 index fc5ada5..0000000 --- a/ubi-utils/src/ubirmvol/ubirmvol.c +++ /dev/null @@ -1,172 +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. - */ - -/* - * An utility to create UBI volumes. - * - * Autor: Artem B. Bityutskiy - */ - -#include -#include -#include -#include -#include -#include -#include - -static void usage(void); -static int param_sanity_check(ubi_lib_t lib); -static int parse_options(int argc, char * const argv[]); - -/* - * The below variables are set by command line options. - */ -static int vol_id = -1; -static int devn = -1; - -int main(int argc, char * const argv[]) -{ - int err, old_errno; - ubi_lib_t lib; - - err = parse_options(argc, argv); - if (err) - return err == 1 ? 0 : -1; - - if (devn == -1) { - fprintf(stderr, "Device number was not specified\n"); - fprintf(stderr, "Use -h option for help\n"); - return -1; - } - - err = ubi_open(&lib); - if (err) { - perror("Cannot open libubi"); - return -1; - } - - err = param_sanity_check(lib); - if (err) { - perror("Input parameters check"); - fprintf(stderr, "Use -h option for help\n"); - goto out_libubi; - } - - err = ubi_rmvol(lib, devn, vol_id); - old_errno = errno; - if (err < 0) { - perror("Cannot remove volume"); - fprintf(stderr, " err=%d errno=%d\n", err, old_errno); - goto out_libubi; - } - - return 0; - -out_libubi: - ubi_close(&lib); - return -1; -} - -/* 'getopt()' option string */ -static const char *optstring = "hd:n:"; - -static int parse_options(int argc, char * const argv[]) -{ - int opt = 0; - - while (opt != -1) { - char *endp; - - opt = getopt(argc, argv, optstring); - - switch (opt) { - case 'h': - usage(); - return 1; - case 'n': - vol_id = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || vol_id < 0) { - fprintf(stderr, "Bad volume " - "number: \"%s\"\n", optarg); - goto out; - } - break; - case 'd': - devn = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || devn < 0) { - fprintf(stderr, "Bad UBI device " - "number: \"%s\"\n", optarg); - goto out; - } - break; - case ':': - fprintf(stderr, "Parameter is missing\n"); - goto out; - case '?': - fprintf(stderr, "Unknown parameter\n"); - goto out; - case -1: - break; - default: - fprintf(stderr, "Internal error\n"); - goto out; - } - } - - return 0; - -out: - errno = EINVAL; - return -1; -} - -static int param_sanity_check(ubi_lib_t lib) -{ - int err; - struct ubi_info ubi; - - if (vol_id == -1) { - fprintf(stderr, "Volume ID was not specified\n"); - goto out; - } - - err = ubi_get_info(lib, &ubi); - if (err) - return -1; - - if (devn >= ubi.dev_count) { - fprintf(stderr, "Device %d does not exist\n", devn); - goto out; - } - - return 0; - -out: - errno = EINVAL; - return -1; -} - -static void usage(void) -{ - printf("Usage: ubi_rmvol OPTIONS\n" - "Command line options:\n" - "\t-h - this help message\n" - "\t-d - UBI device number\n" - "\t-n VOLNUM - volume number to remove\n"); -} diff --git a/ubi-utils/src/ubiupdatevol.c b/ubi-utils/src/ubiupdatevol.c new file mode 100644 index 0000000..28e1e8f --- /dev/null +++ b/ubi-utils/src/ubiupdatevol.c @@ -0,0 +1,352 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAXPATH 1024 +#define BUFSIZE 128 * 1024 +#define MIN(x,y) ((x)<(y)?(x):(y)) + +struct args { + int device; + int volume; + int truncate; + int broken_update; + int bufsize; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +}; + +static struct args myargs = { + .device = -1, + .volume = -1, + .truncate = 0, + .broken_update = 0, + .bufsize = BUFSIZE, + .arg1 = NULL, + .options = NULL, +}; + +static int verbose = 0; + +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\t" + BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" + "\nWrite to UBI Volume.\n"; + +static struct argp_option options[] = { + { .name = "device", + .key = 'd', + .arg = "", + .flags = 0, + .doc = "UBI device", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "volume", + .key = 'n', + .arg = "", + .flags = 0, + .doc = "UBI volume id", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "truncate", + .key = 't', + .arg = NULL, + .flags = 0, + .doc = "truncate volume", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "broken-update", + .key = 'B', + .arg = NULL, + .flags = 0, + .doc = "broken update, this is for testing", + .group = OPTION_ARG_OPTIONAL }, + + { .name = NULL, .key = 0, .arg = NULL, .flags = 0, + .doc = NULL, .group = 0 }, +}; + +static struct argp argp = { + .options = options, + .parser = parse_opt, + .args_doc = 0, + .doc = doc, + .children = NULL, + .help_filter = NULL, + .argp_domain = NULL, +}; + +/* + * @brief Parse the arguments passed into the test case. + * + * @param key The parameter. + * @param arg Argument passed to parameter. + * @param state Location to put information on parameters. + * + * @return error + * + * Get the `input' argument from `argp_parse', which we know is a + * pointer to our arguments structure. + */ +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + struct args *args = state->input; + + switch (key) { + case 'v': /* --verbose= */ + verbose = strtoul(arg, (char **)NULL, 0); + break; + + case 'd': /* --device= */ + args->device = strtol(arg, (char **)NULL, 0); + break; + + case 'b': /* --bufsize= */ + args->bufsize = strtol(arg, (char **)NULL, 0); + if (args->bufsize <= 0) + args->bufsize = BUFSIZE; + break; + + case 't': /* --truncate */ + args->truncate = 1; + break; + + case 'B': /* --broken-update */ + args->broken_update = 1; + break; + + case 'n': /* --volume= */ + args->volume = strtol(arg, (char **)NULL, 0); + break; + + case ARGP_KEY_NO_ARGS: + /* argp_usage(state); */ + break; + + case ARGP_KEY_ARG: + args->arg1 = arg; + /* Now we consume all the rest of the arguments. + `state->next' is the index in `state->argv' of the + next argument to be parsed, which is the first STRING + we're interested in, so we can just use + `&state->argv[state->next]' as the value for + arguments->strings. + + _In addition_, by setting `state->next' to the end + of the arguments, we can force argp to stop parsing here and + return. */ + + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + + case ARGP_KEY_END: + /* argp_usage(state); */ + break; + + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +/** + * @bytes bytes must be always 0, if not 0 this is a testcase for a + * broken volume update where data is promissed to be written, but for + * some reason nothing is written. The volume is unusable after this. + */ +static int +ubi_truncate_volume(struct args *args, int64_t bytes) +{ + int rc, ofd; + char path[MAXPATH]; + int old_errno; + + snprintf(path, MAXPATH-1, "/dev/ubi%d_%d", args->device, args->volume); + path[MAXPATH-1] = '\0'; + + ofd = open(path, O_RDWR); + if (ofd < 0) { + fprintf(stderr, "Cannot open volume %s\n", path); + exit(EXIT_FAILURE); + } + rc = ioctl(ofd, UBI_IOCVOLUP, &bytes); + old_errno = errno; + if (rc < 0) { + perror("UBI volume update ioctl"); + fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); + exit(EXIT_FAILURE); + } + close(ofd); + return 0; +} + +static ssize_t ubi_write(int fd, const void *buf, size_t count) +{ + int rc; + int len = count; + + while (len) { + rc = write(fd, buf, len); + if (rc == -1) { + if (errno == EINTR) + continue; /* try again */ + perror("write error"); + return rc; + } + + len -= rc; + buf += rc; + } + return count; +} + +static int +ubi_update_volume(struct args *args) +{ + int rc, ofd; + FILE *ifp = NULL; + struct stat st; + int size = 0; + char *fname = args->arg1; + char path[MAXPATH]; + char *buf; + int64_t bytes = 0; + int old_errno; + + buf = malloc(args->bufsize); + if (!buf) { + perror("Out of memory"); + exit(EXIT_FAILURE); + } + + if (fname == NULL) { + fprintf(stderr, "Please specify an existing file.\n"); + exit(EXIT_FAILURE); + } + + rc = stat(fname, &st); + if (rc < 0) { + fprintf(stderr, "Cannot stat input file %s\n", fname); + exit(EXIT_FAILURE); + } + bytes = size = st.st_size; + + ifp = fopen(fname, "r"); + if (!ifp) + exit(EXIT_FAILURE); + + snprintf(path, MAXPATH-1, "/dev/ubi%d_%d", args->device, args->volume); + path[MAXPATH-1] = '\0'; + + ofd = open(path, O_RDWR); + if (ofd < 0) { + fprintf(stderr, "Cannot open UBI volume %s\n", path); + exit(EXIT_FAILURE); + } + + rc = ioctl(ofd, UBI_IOCVOLUP, &bytes); + old_errno = errno; + if (rc < 0) { + perror("UBI volume update ioctl"); + fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); + exit(EXIT_FAILURE); + } + + while (size > 0) { + ssize_t tocopy = MIN(args->bufsize, size); + + rc = fread(buf, tocopy, 1, ifp); + if (rc != 1) { + perror("Could not read everything."); + exit(EXIT_FAILURE); + } + + rc = ubi_write(ofd, buf, tocopy); + old_errno = errno; + if (rc != tocopy) { + perror("Could not write to device"); + fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); + exit(EXIT_FAILURE); + } + size -= tocopy; + } + + free(buf); + fclose(ifp); + rc = close(ofd); + if (rc != 0) { + perror("UBI volume close failed"); + exit(EXIT_FAILURE); + } + return 0; +} + +int +main(int argc, char *argv[]) +{ + int rc; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); + + if (myargs.truncate) { + rc = ubi_truncate_volume(&myargs, 0LL); + if (rc < 0) + exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); + } + if (myargs.broken_update) { + rc = ubi_truncate_volume(&myargs, 1LL); + if (rc < 0) + exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); + } + rc = ubi_update_volume(&myargs); + if (rc < 0) + exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); +} diff --git a/ubi-utils/src/ubiwritevol/ubiwritevol.c b/ubi-utils/src/ubiwritevol/ubiwritevol.c deleted file mode 100644 index 8fdbe37..0000000 --- a/ubi-utils/src/ubiwritevol/ubiwritevol.c +++ /dev/null @@ -1,352 +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. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAXPATH 1024 -#define BUFSIZE 128 * 1024 -#define MIN(x,y) ((x)<(y)?(x):(y)) - -struct args { - int device; - int volume; - int truncate; - int broken_update; - int bufsize; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -}; - -static struct args myargs = { - .device = -1, - .volume = -1, - .truncate = 0, - .broken_update = 0, - .bufsize = BUFSIZE, - .arg1 = NULL, - .options = NULL, -}; - -static int verbose = 0; - -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -const char *argp_program_bug_address = ""; - -static char doc[] = "\nVersion: " VERSION "\n\t" - HOST_OS" "HOST_CPU" at "__DATE__" "__TIME__"\n" - "\nWrite to UBI Volume.\n"; - -static struct argp_option options[] = { - { .name = "device", - .key = 'd', - .arg = "", - .flags = 0, - .doc = "UBI device", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "volume", - .key = 'n', - .arg = "", - .flags = 0, - .doc = "UBI volume id", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "truncate", - .key = 't', - .arg = NULL, - .flags = 0, - .doc = "truncate volume", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "broken-update", - .key = 'B', - .arg = NULL, - .flags = 0, - .doc = "broken update, this is for testing", - .group = OPTION_ARG_OPTIONAL }, - - { .name = NULL, .key = 0, .arg = NULL, .flags = 0, - .doc = NULL, .group = 0 }, -}; - -static struct argp argp = { - .options = options, - .parser = parse_opt, - .args_doc = 0, - .doc = doc, - .children = NULL, - .help_filter = NULL, - .argp_domain = NULL, -}; - -/* - * @brief Parse the arguments passed into the test case. - * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. - * - * @return error - * - * Get the `input' argument from `argp_parse', which we know is a - * pointer to our arguments structure. - */ -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - struct args *args = state->input; - - switch (key) { - case 'v': /* --verbose= */ - verbose = strtoul(arg, (char **)NULL, 0); - break; - - case 'd': /* --device= */ - args->device = strtol(arg, (char **)NULL, 0); - break; - - case 'b': /* --bufsize= */ - args->bufsize = strtol(arg, (char **)NULL, 0); - if (args->bufsize <= 0) - args->bufsize = BUFSIZE; - break; - - case 't': /* --truncate */ - args->truncate = 1; - break; - - case 'B': /* --broken-update */ - args->broken_update = 1; - break; - - case 'n': /* --volume= */ - args->volume = strtol(arg, (char **)NULL, 0); - break; - - case ARGP_KEY_NO_ARGS: - /* argp_usage(state); */ - break; - - case ARGP_KEY_ARG: - args->arg1 = arg; - /* Now we consume all the rest of the arguments. - `state->next' is the index in `state->argv' of the - next argument to be parsed, which is the first STRING - we're interested in, so we can just use - `&state->argv[state->next]' as the value for - arguments->strings. - - _In addition_, by setting `state->next' to the end - of the arguments, we can force argp to stop parsing here and - return. */ - - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - - case ARGP_KEY_END: - /* argp_usage(state); */ - break; - - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -/** - * @bytes bytes must be always 0, if not 0 this is a testcase for a - * broken volume update where data is promissed to be written, but for - * some reason nothing is written. The volume is unusable after this. - */ -static int -ubi_truncate_volume(struct args *args, int64_t bytes) -{ - int rc, ofd; - char path[MAXPATH]; - int old_errno; - - snprintf(path, MAXPATH-1, "/dev/ubi%d_%d", args->device, args->volume); - path[MAXPATH-1] = '\0'; - - ofd = open(path, O_RDWR); - if (ofd < 0) { - fprintf(stderr, "Cannot open volume %s\n", path); - exit(EXIT_FAILURE); - } - rc = ioctl(ofd, UBI_IOCVOLUP, &bytes); - old_errno = errno; - if (rc < 0) { - perror("UBI volume update ioctl"); - fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); - exit(EXIT_FAILURE); - } - close(ofd); - return 0; -} - -static ssize_t ubi_write(int fd, const void *buf, size_t count) -{ - int rc; - int len = count; - - while (len) { - rc = write(fd, buf, len); - if (rc == -1) { - if (errno == EINTR) - continue; /* try again */ - perror("write error"); - return rc; - } - - len -= rc; - buf += rc; - } - return count; -} - -static int -ubi_update_volume(struct args *args) -{ - int rc, ofd; - FILE *ifp = NULL; - struct stat st; - int size = 0; - char *fname = args->arg1; - char path[MAXPATH]; - char *buf; - int64_t bytes = 0; - int old_errno; - - buf = malloc(args->bufsize); - if (!buf) { - perror("Out of memory"); - exit(EXIT_FAILURE); - } - - if (fname == NULL) { - fprintf(stderr, "Please specify an existing file.\n"); - exit(EXIT_FAILURE); - } - - rc = stat(fname, &st); - if (rc < 0) { - fprintf(stderr, "Cannot stat input file %s\n", fname); - exit(EXIT_FAILURE); - } - bytes = size = st.st_size; - - ifp = fopen(fname, "r"); - if (!ifp) - exit(EXIT_FAILURE); - - snprintf(path, MAXPATH-1, "/dev/ubi%d_%d", args->device, args->volume); - path[MAXPATH-1] = '\0'; - - ofd = open(path, O_RDWR); - if (ofd < 0) { - fprintf(stderr, "Cannot open UBI volume %s\n", path); - exit(EXIT_FAILURE); - } - - rc = ioctl(ofd, UBI_IOCVOLUP, &bytes); - old_errno = errno; - if (rc < 0) { - perror("UBI volume update ioctl"); - fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); - exit(EXIT_FAILURE); - } - - while (size > 0) { - ssize_t tocopy = MIN(args->bufsize, size); - - rc = fread(buf, tocopy, 1, ifp); - if (rc != 1) { - perror("Could not read everything."); - exit(EXIT_FAILURE); - } - - rc = ubi_write(ofd, buf, tocopy); - old_errno = errno; - if (rc != tocopy) { - perror("Could not write to device"); - fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); - exit(EXIT_FAILURE); - } - size -= tocopy; - } - - free(buf); - fclose(ifp); - rc = close(ofd); - if (rc != 0) { - perror("UBI volume close failed"); - exit(EXIT_FAILURE); - } - return 0; -} - -int -main(int argc, char *argv[]) -{ - int rc; - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); - - if (myargs.truncate) { - rc = ubi_truncate_volume(&myargs, 0LL); - if (rc < 0) - exit(EXIT_FAILURE); - exit(EXIT_SUCCESS); - } - if (myargs.broken_update) { - rc = ubi_truncate_volume(&myargs, 1LL); - if (rc < 0) - exit(EXIT_FAILURE); - exit(EXIT_SUCCESS); - } - rc = ubi_update_volume(&myargs); - if (rc < 0) - exit(EXIT_FAILURE); - - exit(EXIT_SUCCESS); -} diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c new file mode 100644 index 0000000..6d877e7 --- /dev/null +++ b/ubi-utils/src/unubi.c @@ -0,0 +1,392 @@ +/* + * 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 decompose UBI images. Not yet finished ... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crc32.h" +#include + +#define MAXPATH 1024 +#define MIN(x,y) ((x)<(y)?(x):(y)) + +static uint32_t crc32_table[256]; + +struct args { + const char *output_dir; + uint32_t hdr_offs; + uint32_t data_offs; + uint32_t blocksize; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +}; + +static struct args myargs = { + .output_dir = "unubi", + .hdr_offs = 64, + .data_offs = 128, + .blocksize = 128 * 1024, + .arg1 = NULL, + .options = NULL, +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +const char *argp_program_bug_address = + "... uuuh, lets wait until it looks nicer"; + +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\t" + BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" + "\nWrite to UBI Volume.\n"; + +static struct argp_option options[] = { + { .name = "dir", + .key = 'd', + .arg = "", + .flags = 0, + .doc = "output directory", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "blocksize", + .key = 'b', + .arg = "", + .flags = 0, + .doc = "blocksize", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "data-offs", + .key = 'x', + .arg = "", + .flags = 0, + .doc = "data offset", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "hdr-offs", + .key = 'x', + .arg = "", + .flags = 0, + .doc = "hdr offset", + .group = OPTION_ARG_OPTIONAL }, + + { .name = NULL, .key = 0, .arg = NULL, .flags = 0, + .doc = NULL, .group = 0 }, +}; + +static struct argp argp = { + .options = options, + .parser = parse_opt, + .args_doc = "image-file", + .doc = doc, + .children = NULL, + .help_filter = NULL, + .argp_domain = NULL, +}; + +/* + * str_to_num - Convert string into number and cope with endings like + * k, K, kib, KiB for kilobyte + * m, M, mib, MiB for megabyte + */ +uint32_t str_to_num(char *str) +{ + char *s = str; + ulong num = strtoul(s, &s, 0); + + if (*s != '\0') { + if (strcmp(s, "KiB") == 0) + num *= 1024; + else if (strcmp(s, "MiB") == 0) + num *= 1024*1024; + else { + fprintf(stderr, "WARNING: Wrong number format " + "\"%s\", check your paramters!\n", str); + } + } + return num; +} + +/* + * @brief Parse the arguments passed into the test case. + * + * @param key The parameter. + * @param arg Argument passed to parameter. + * @param state Location to put information on parameters. + * + * @return error + * + * Get the `input' argument from `argp_parse', which we know is a + * pointer to our arguments structure. + */ +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + struct args *args = state->input; + + switch (key) { + case 'b': /* --blocksize */ + args->blocksize = str_to_num(arg); + break; + + case 'x': /* --data-offs= */ + args->data_offs = str_to_num(arg); + break; + + case 'y': /* --hdr-offs= */ + args->hdr_offs = str_to_num(arg); + break; + + case 'd': /* --dir= */ + args->output_dir = arg; + break; + + case ARGP_KEY_NO_ARGS: + /* argp_usage(state); */ + break; + + case ARGP_KEY_ARG: + args->arg1 = arg; + /* Now we consume all the rest of the arguments. + `state->next' is the index in `state->argv' of the + next argument to be parsed, which is the first STRING + we're interested in, so we can just use + `&state->argv[state->next]' as the value for + arguments->strings. + + _In addition_, by setting `state->next' to the end + of the arguments, we can force argp to stop parsing + here and return. */ + + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + + case ARGP_KEY_END: + /* argp_usage(state); */ + break; + + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static inline void +hexdump(FILE *fp, const void *p, ssize_t size) +{ + int k; + const uint8_t *buf = p; + + for (k = 0; k < size; k++) { + fprintf(fp, "%02x ", buf[k]); + if ((k & 15) == 15) + fprintf(fp, "\n"); + } +} + +/* + * This was put together in 1.5 hours and this is exactly how it looks + * like! FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME! + */ +static int extract_volume(struct args *args, const uint8_t *buf, + int len, int volume, FILE *fp) +{ + int i, rc; + int nrblocks = len / args->blocksize; + int max_lnum = -1, lnum = 0; + const uint8_t *ptr; + uint8_t **vol_tab; + int *vol_len; + + vol_tab = calloc(nrblocks, sizeof(uint8_t *)); + vol_len = calloc(nrblocks, sizeof(int)); + + if (!buf || !vol_tab || !vol_len) + exit(EXIT_FAILURE); + + for (i = 0, ptr = buf; i < nrblocks; i++, ptr += args->blocksize) { + uint32_t crc; + struct ubi_ec_hdr *ec_hdr = (struct ubi_ec_hdr *)ptr; + struct ubi_vid_hdr *vid_hdr = NULL; + uint8_t *data; + + /* default */ + vol_len[lnum] = args->blocksize - (2 * 1024); + + /* Check UBI EC header */ + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, ec_hdr, + UBI_EC_HDR_SIZE_CRC); + if (crc != ubi32_to_cpu(ec_hdr->hdr_crc)) + continue; + + vid_hdr = (struct ubi_vid_hdr *) + (ptr + ubi32_to_cpu(ec_hdr->vid_hdr_offset)); + data = (uint8_t *)(ptr + ubi32_to_cpu(ec_hdr->data_offset)); + + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, vid_hdr, + UBI_VID_HDR_SIZE_CRC); + if (crc != ubi32_to_cpu(vid_hdr->hdr_crc)) + continue; + + if (volume == (int)ubi32_to_cpu(vid_hdr->vol_id)) { + + printf("****** block %4d volume %2d **********\n", + i, volume); + + hexdump(stdout, ptr, 64); + + printf("--- vid_hdr\n"); + hexdump(stdout, vid_hdr, 64); + + printf("--- data\n"); + hexdump(stdout, data, 64); + + lnum = ubi32_to_cpu(vid_hdr->lnum); + vol_tab[lnum] = data; + if (max_lnum < lnum) + max_lnum = lnum; + if (vid_hdr->vol_type == UBI_VID_STATIC) + vol_len[lnum] = + ubi32_to_cpu(vid_hdr->data_size); + + } + } + + for (lnum = 0; lnum <= max_lnum; lnum++) { + if (vol_tab[lnum]) { + rc = fwrite(vol_tab[lnum], 1, vol_len[lnum], fp); + if (ferror(fp) || (vol_len[lnum] != rc)) { + perror("could not write file"); + exit(EXIT_FAILURE); + } + } else { + /* Fill up empty areas by 0xff, for static + * volumes this means they are broken! + */ + for (i = 0; i < vol_len[lnum]; i++) { + if (fputc(0xff, fp) == EOF) { + perror("could not write char"); + exit(EXIT_FAILURE); + } + } + } + } + + free(vol_tab); + free(vol_len); + return 0; +} + +int +main(int argc, char *argv[]) +{ + int len, rc; + FILE *fp; + struct stat file_info; + uint8_t *buf; + int i; + + init_crc32_table(crc32_table); + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); + + if (!myargs.arg1) { + fprintf(stderr, "Please specify input file!\n"); + exit(EXIT_FAILURE); + } + + fp = fopen(myargs.arg1, "r"); + if (!fp) { + perror("Cannot open file"); + exit(EXIT_FAILURE); + } + if (fstat(fileno(fp), &file_info) != 0) { + fprintf(stderr, "Cannot fetch file size " + "from input file.\n"); + } + len = file_info.st_size; + buf = malloc(len); + if (!buf) { + perror("out of memory!"); + exit(EXIT_FAILURE); + } + rc = fread(buf, 1, len, fp); + if (ferror(fp) || (len != rc)) { + perror("could not read file"); + exit(EXIT_FAILURE); + } + if (!myargs.output_dir) { + fprintf(stderr, "No output directory specified!\n"); + exit(EXIT_FAILURE); + } + + rc = mkdir(myargs.output_dir, 0777); + if (rc && errno != EEXIST) { + perror("Cannot create output directory"); + exit(EXIT_FAILURE); + } + for (i = 0; i < 32; i++) { + char fname[1024]; + FILE *fpout; + + printf("######### VOLUME %d ############################\n", + i); + + sprintf(fname, "%s/ubivol_%d.bin", myargs.output_dir, i); + fpout = fopen(fname, "w+"); + if (!fpout) { + perror("Cannot open file"); + exit(EXIT_FAILURE); + } + extract_volume(&myargs, buf, len, i, fpout); + fclose(fpout); + } + + fclose(fp); + free(buf); + exit(EXIT_SUCCESS); +} diff --git a/ubi-utils/src/unubi/unubi.c b/ubi-utils/src/unubi/unubi.c deleted file mode 100644 index 9cb1354..0000000 --- a/ubi-utils/src/unubi/unubi.c +++ /dev/null @@ -1,391 +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 decompose UBI images. Not yet finished ... - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "crc32.h" -#include - -#define MAXPATH 1024 -#define MIN(x,y) ((x)<(y)?(x):(y)) - -static uint32_t crc32_table[256]; - -struct args { - const char *output_dir; - uint32_t hdr_offs; - uint32_t data_offs; - uint32_t blocksize; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -}; - -static struct args myargs = { - .output_dir = "unubi", - .hdr_offs = 64, - .data_offs = 128, - .blocksize = 128 * 1024, - .arg1 = NULL, - .options = NULL, -}; - -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -const char *argp_program_bug_address = ""; - -static char doc[] = "\nVersion: " VERSION "\n\t" - HOST_OS" "HOST_CPU" at "__DATE__" "__TIME__"\n" - "\nWrite to UBI Volume.\n"; - -static struct argp_option options[] = { - { .name = "dir", - .key = 'd', - .arg = "", - .flags = 0, - .doc = "output directory", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "blocksize", - .key = 'b', - .arg = "", - .flags = 0, - .doc = "blocksize", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "data-offs", - .key = 'x', - .arg = "", - .flags = 0, - .doc = "data offset", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "hdr-offs", - .key = 'x', - .arg = "", - .flags = 0, - .doc = "hdr offset", - .group = OPTION_ARG_OPTIONAL }, - - { .name = NULL, .key = 0, .arg = NULL, .flags = 0, - .doc = NULL, .group = 0 }, -}; - -static struct argp argp = { - .options = options, - .parser = parse_opt, - .args_doc = "image-file", - .doc = doc, - .children = NULL, - .help_filter = NULL, - .argp_domain = NULL, -}; - -/* - * str_to_num - Convert string into number and cope with endings like - * k, K, kib, KiB for kilobyte - * m, M, mib, MiB for megabyte - */ -uint32_t str_to_num(char *str) -{ - char *s = str; - ulong num = strtoul(s, &s, 0); - - if (*s != '\0') { - if (strcmp(s, "KiB") == 0) - num *= 1024; - else if (strcmp(s, "MiB") == 0) - num *= 1024*1024; - else { - fprintf(stderr, "WARNING: Wrong number format " - "\"%s\", check your paramters!\n", str); - } - } - return num; -} - -/* - * @brief Parse the arguments passed into the test case. - * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. - * - * @return error - * - * Get the `input' argument from `argp_parse', which we know is a - * pointer to our arguments structure. - */ -static error_t -parse_opt(int key, char *arg, struct argp_state *state) -{ - struct args *args = state->input; - - switch (key) { - case 'b': /* --blocksize */ - args->blocksize = str_to_num(arg); - break; - - case 'x': /* --data-offs= */ - args->data_offs = str_to_num(arg); - break; - - case 'y': /* --hdr-offs= */ - args->hdr_offs = str_to_num(arg); - break; - - case 'd': /* --dir= */ - args->output_dir = arg; - break; - - case ARGP_KEY_NO_ARGS: - /* argp_usage(state); */ - break; - - case ARGP_KEY_ARG: - args->arg1 = arg; - /* Now we consume all the rest of the arguments. - `state->next' is the index in `state->argv' of the - next argument to be parsed, which is the first STRING - we're interested in, so we can just use - `&state->argv[state->next]' as the value for - arguments->strings. - - _In addition_, by setting `state->next' to the end - of the arguments, we can force argp to stop parsing - here and return. */ - - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - - case ARGP_KEY_END: - /* argp_usage(state); */ - break; - - default: - return(ARGP_ERR_UNKNOWN); - } - - return 0; -} - -static inline void -hexdump(FILE *fp, const void *p, size_t size) -{ - int k; - const uint8_t *buf = p; - - for (k = 0; k < size; k++) { - fprintf(fp, "%02x ", buf[k]); - if ((k & 15) == 15) - fprintf(fp, "\n"); - } -} - -/* - * This was put together in 1.5 hours and this is exactly how it looks - * like! FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME! - */ -static int extract_volume(struct args *args, const uint8_t *buf, - int len, int volume, FILE *fp) -{ - int i, rc; - int nrblocks = len / args->blocksize; - int max_lnum = -1, lnum = 0; - const uint8_t *ptr; - uint8_t **vol_tab; - int *vol_len; - - vol_tab = calloc(nrblocks, sizeof(uint8_t *)); - vol_len = calloc(nrblocks, sizeof(int)); - - if (!buf || !vol_tab || !vol_len) - exit(EXIT_FAILURE); - - for (i = 0, ptr = buf; i < nrblocks; i++, ptr += args->blocksize) { - uint32_t crc; - struct ubi_ec_hdr *ec_hdr = (struct ubi_ec_hdr *)ptr; - struct ubi_vid_hdr *vid_hdr = NULL; - uint8_t *data; - - /* default */ - vol_len[lnum] = args->blocksize - (2 * 1024); - - /* Check UBI EC header */ - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, ec_hdr, - UBI_EC_HDR_SIZE_CRC); - if (crc != ubi32_to_cpu(ec_hdr->hdr_crc)) - continue; - - vid_hdr = (struct ubi_vid_hdr *) - (ptr + ubi32_to_cpu(ec_hdr->vid_hdr_offset)); - data = (uint8_t *)(ptr + ubi32_to_cpu(ec_hdr->data_offset)); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, vid_hdr, - UBI_VID_HDR_SIZE_CRC); - if (crc != ubi32_to_cpu(vid_hdr->hdr_crc)) - continue; - - if (volume == ubi32_to_cpu(vid_hdr->vol_id)) { - - printf("****** block %4d volume %2d **********\n", - i, volume); - - hexdump(stdout, ptr, 64); - - printf("--- vid_hdr\n"); - hexdump(stdout, vid_hdr, 64); - - printf("--- data\n"); - hexdump(stdout, data, 64); - - lnum = ubi32_to_cpu(vid_hdr->lnum); - vol_tab[lnum] = data; - if (max_lnum < lnum) - max_lnum = lnum; - if (vid_hdr->vol_type == UBI_VID_STATIC) - vol_len[lnum] = - ubi32_to_cpu(vid_hdr->data_size); - - } - } - - for (lnum = 0; lnum <= max_lnum; lnum++) { - if (vol_tab[lnum]) { - rc = fwrite(vol_tab[lnum], 1, vol_len[lnum], fp); - if (ferror(fp) || (vol_len[lnum] != rc)) { - perror("could not write file"); - exit(EXIT_FAILURE); - } - } else { - /* Fill up empty areas by 0xff, for static - * volumes this means they are broken! - */ - for (i = 0; i < vol_len[lnum]; i++) { - if (fputc(0xff, fp) == EOF) { - perror("could not write char"); - exit(EXIT_FAILURE); - } - } - } - } - - free(vol_tab); - free(vol_len); - return 0; -} - -int -main(int argc, char *argv[]) -{ - int len, rc; - FILE *fp; - struct stat file_info; - uint8_t *buf; - int i; - - init_crc32_table(crc32_table); - - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); - - if (!myargs.arg1) { - fprintf(stderr, "Please specify input file!\n"); - exit(EXIT_FAILURE); - } - - fp = fopen(myargs.arg1, "r"); - if (!fp) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - if (fstat(fileno(fp), &file_info) != 0) { - fprintf(stderr, "Cannot fetch file size " - "from input file.\n"); - } - len = file_info.st_size; - buf = malloc(len); - if (!buf) { - perror("out of memory!"); - exit(EXIT_FAILURE); - } - rc = fread(buf, 1, len, fp); - if (ferror(fp) || (len != rc)) { - perror("could not read file"); - exit(EXIT_FAILURE); - } - if (!myargs.output_dir) { - fprintf(stderr, "No output directory specified!\n"); - exit(EXIT_FAILURE); - } - - rc = mkdir(myargs.output_dir, 0777); - if (rc && errno != EEXIST) { - perror("Cannot create output directory"); - exit(EXIT_FAILURE); - } - for (i = 0; i < 32; i++) { - char fname[1024]; - FILE *fpout; - - printf("######### VOLUME %d ############################\n", - i); - - sprintf(fname, "%s/ubivol_%d.bin", myargs.output_dir, i); - fpout = fopen(fname, "w+"); - if (!fpout) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - extract_volume(&myargs, buf, len, i, fpout); - fclose(fpout); - } - - fclose(fp); - free(buf); - exit(EXIT_SUCCESS); -} -- cgit v1.2.3