* [RFC 01/10] mtd: move is_power_of_2() to a public place
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-26 10:16 ` [RFC 02/10] ubi: consolidate ubi-media.h Wolfram Sang
` (8 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Will need this later for ubiformat.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/mtd/ubi/ubi-barebox.h | 5 +----
include/mtd/utils.h | 25 +++++++++++++++++++++++++
2 files changed, 26 insertions(+), 4 deletions(-)
create mode 100644 include/mtd/utils.h
diff --git a/drivers/mtd/ubi/ubi-barebox.h b/drivers/mtd/ubi/ubi-barebox.h
index 72f29a6..919dc50 100644
--- a/drivers/mtd/ubi/ubi-barebox.h
+++ b/drivers/mtd/ubi/ubi-barebox.h
@@ -25,6 +25,7 @@
#include <linux/string.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/ubi.h>
+#include <mtd/utils.h>
#define crc32(seed, data, length) crc32_no_comp(seed, (unsigned char const *)data, length)
@@ -53,10 +54,6 @@ do { \
#define put_device(...)
#define ubi_sysfs_init(...) 0
#define ubi_sysfs_close(...) do { } while (0)
-static inline int is_power_of_2(unsigned long n)
-{
- return (n != 0 && ((n & (n - 1)) == 0));
-}
/* FIXME */
#define MKDEV(...) 0
diff --git a/include/mtd/utils.h b/include/mtd/utils.h
new file mode 100644
index 0000000..229fb34
--- /dev/null
+++ b/include/mtd/utils.h
@@ -0,0 +1,25 @@
+/*
+ * mtd/utils.h - helper functions for various MTD utilities
+ *
+ * Copyright (C) 2012 by Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#ifndef INCLUDE_MTD_UTILS_H
+# define INCLUDE_MTD_UTILS_H
+
+static inline int is_power_of_2(unsigned long n)
+{
+ return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+#endif /* INCLUDE_MTD_UTILS_H */
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 02/10] ubi: consolidate ubi-media.h
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
2012-10-26 10:16 ` [RFC 01/10] mtd: move is_power_of_2() to a public place Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-26 10:16 ` [RFC 03/10] ubi: bump ubi-media.h to newest version Wolfram Sang
` (7 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
We have two versions in the tree. Use the newer one, and put it into the
mtd directory while we are at it.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
commands/ubi.c | 2 +-
drivers/mtd/ubi/ubi.h | 3 +-
{drivers/mtd/ubi => include/mtd}/ubi-media.h | 0
include/ubi-media.h | 370 --------------------------
4 files changed, 3 insertions(+), 372 deletions(-)
rename {drivers/mtd/ubi => include/mtd}/ubi-media.h (100%)
delete mode 100644 include/ubi-media.h
diff --git a/commands/ubi.c b/commands/ubi.c
index bf70071..1653eaa 100644
--- a/commands/ubi.c
+++ b/commands/ubi.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/mtd/mtd-abi.h>
#include <mtd/ubi-user.h>
-#include <ubi-media.h>
+#include <mtd/ubi-media.h>
static int do_ubimkvol(int argc, char *argv[])
{
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 97aed8f..964a3c4 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -45,7 +45,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/ubi.h>
-#include "ubi-media.h"
+#include <mtd/ubi-media.h>
+
#include "scan.h"
#include "debug.h"
diff --git a/drivers/mtd/ubi/ubi-media.h b/include/mtd/ubi-media.h
similarity index 100%
rename from drivers/mtd/ubi/ubi-media.h
rename to include/mtd/ubi-media.h
diff --git a/include/ubi-media.h b/include/ubi-media.h
deleted file mode 100644
index 4edbbb2..0000000
--- a/include/ubi-media.h
+++ /dev/null
@@ -1,370 +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.
- *
- *
- * Authors: Artem 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_MEDIA_H__
-#define __UBI_MEDIA_H__
-
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-
-#include <asm/byteorder.h>
-
-/* The version of UBI images supported by this implementation */
-#define UBI_VERSION 1
-
-/* The highest erase counter value supported by this implementation */
-#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
-
-/* The initial CRC32 value used when calculating CRC checksums */
-#define UBI_CRC32_INIT 0xFFFFFFFFU
-
-/* Erase counter header magic number (ASCII "UBI#") */
-#define UBI_EC_HDR_MAGIC 0x55424923
-/* Volume identifier header magic number (ASCII "UBI!") */
-#define UBI_VID_HDR_MAGIC 0x55424921
-
-/*
- * Volume type constants used in the volume identifier header.
- *
- * @UBI_VID_DYNAMIC: dynamic volume
- * @UBI_VID_STATIC: static volume
- */
-enum {
- UBI_VID_DYNAMIC = 1,
- UBI_VID_STATIC = 2
-};
-
-/*
- * Volume flags used in the volume table record.
- *
- * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
- *
- * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
- * table. UBI automatically re-sizes the volume which has this flag and makes
- * the volume to be of largest possible size. This means that if after the
- * initialization UBI finds out that there are available physical eraseblocks
- * present on the device, it automatically appends all of them to the volume
- * (the physical eraseblocks reserved for bad eraseblocks handling and other
- * reserved physical eraseblocks are not taken). So, if there is a volume with
- * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
- * eraseblocks will be zero after UBI is loaded, because all of them will be
- * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
- * after the volume had been initialized.
- *
- * The auto-resize feature is useful for device production purposes. For
- * example, different NAND flash chips may have different amount of initial bad
- * eraseblocks, depending of particular chip instance. Manufacturers of NAND
- * chips usually guarantee that the amount of initial bad eraseblocks does not
- * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
- * flashed to the end devices in production, he does not know the exact amount
- * of good physical eraseblocks the NAND chip on the device will have, but this
- * number is required to calculate the volume sized and put them to the volume
- * table of the UBI image. In this case, one of the volumes (e.g., the one
- * which will store the root file system) is marked as "auto-resizable", and
- * UBI will adjust its size on the first boot if needed.
- *
- * Note, first UBI reserves some amount of physical eraseblocks for bad
- * eraseblock handling, and then re-sizes the volume, not vice-versa. This
- * means that the pool of reserved physical eraseblocks will always be present.
- */
-enum {
- UBI_VTBL_AUTORESIZE_FLG = 0x01,
-};
-
-/*
- * 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_PRESERVE: preserve this internal volume - do not touch its
- * physical eraseblocks, don't allow the wear-leveling
- * sub-system to move them
- * @UBI_COMPAT_REJECT: reject this UBI image
- */
-enum {
- UBI_COMPAT_DELETE = 1,
- UBI_COMPAT_RO = 2,
- UBI_COMPAT_PRESERVE = 4,
- UBI_COMPAT_REJECT = 5
-};
-
-/* 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(__be32))
-#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
-
-/**
- * struct ubi_ec_hdr - UBI erase counter header.
- * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
- * @version: version of UBI implementation which is supposed to accept this
- * UBI image
- * @padding1: reserved for future, zeroes
- * @ec: the erase counter
- * @vid_hdr_offset: where the VID header starts
- * @data_offset: where the user data start
- * @padding2: reserved for future, zeroes
- * @hdr_crc: 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 than the current UBI
- * version, the image is rejected. 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
- * physical eraseblock. These values have to be the same for all physical
- * eraseblocks.
- */
-struct ubi_ec_hdr {
- __be32 magic;
- __u8 version;
- __u8 padding1[3];
- __be64 ec; /* Warning: the current limit is 31-bit anyway! */
- __be32 vid_hdr_offset;
- __be32 data_offset;
- __u8 padding2[36];
- __be32 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: if this logical eraseblock was copied from another physical
- * eraseblock (for wear-leveling reasons)
- * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
- * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
- * @vol_id: ID of this volume
- * @lnum: logical eraseblock number
- * @padding1: reserved for future, zeroes
- * @data_size: how many bytes of data this logical eraseblock contains
- * @used_ebs: total number of used logical eraseblocks in this volume
- * @data_pad: how many bytes at the end of this physical eraseblock are not
- * used
- * @data_crc: CRC checksum of the data stored in this logical eraseblock
- * @padding2: reserved for future, zeroes
- * @sqnum: sequence number
- * @padding3: reserved for future, zeroes
- * @hdr_crc: volume identifier header CRC checksum
- *
- * The @sqnum is the value of the global sequence counter at the time when this
- * VID header was created. The global sequence counter is incremented each time
- * UBI writes a new VID header to the flash, i.e. when it maps a logical
- * eraseblock to a new physical eraseblock. The global sequence counter is an
- * unsigned 64-bit integer and we assume it never overflows. The @sqnum
- * (sequence number) is used to distinguish between older and newer versions of
- * logical eraseblocks.
- *
- * There are 2 situations when there may be more than one physical eraseblock
- * corresponding to the same logical eraseblock, i.e., having the same @vol_id
- * and @lnum values in the volume identifier header. Suppose we have a logical
- * eraseblock L and it is mapped to the physical eraseblock P.
- *
- * 1. Because UBI may erase physical eraseblocks asynchronously, the following
- * situation is possible: L is asynchronously erased, so P is scheduled for
- * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
- * so P1 is written to, then an unclean reboot happens. Result - there are 2
- * physical eraseblocks P and P1 corresponding to the same logical eraseblock
- * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
- * flash.
- *
- * 2. From time to time UBI moves logical eraseblocks to other physical
- * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
- * to P1, and an unclean reboot happens before P is physically erased, there
- * are two physical eraseblocks P and P1 corresponding to L and UBI has to
- * select one of them when the flash is attached. The @sqnum field says which
- * PEB is the original (obviously P will have lower @sqnum) and the copy. But
- * it is not enough to select the physical eraseblock with the higher sequence
- * number, because the unclean reboot could have happen in the middle of the
- * copying process, so the data in P is corrupted. It is also not enough to
- * just select the physical eraseblock with lower sequence number, because the
- * data there may be old (consider a case if more data was added to P1 after
- * the copying). Moreover, the unclean reboot may happen when the erasure of P
- * was just started, so it result in unstable P, which is "mostly" OK, but
- * still has unstable bits.
- *
- * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
- * copy. UBI also calculates data CRC when the data is moved and stores it at
- * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
- * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
- * examined. If it is cleared, the situation* is simple and the newer one is
- * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
- * checksum is correct, this physical eraseblock is selected (P1). Otherwise
- * the older one (P) is selected.
- *
- * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
- * Internal volumes are not seen from outside and are used for various internal
- * UBI purposes. In this implementation there is only one internal volume - the
- * layout volume. Internal volumes are the main mechanism of UBI extensions.
- * For example, in future one may introduce a journal internal volume. Internal
- * volumes have their own reserved range of IDs.
- *
- * The @compat field is only used for internal volumes and contains the "degree
- * of their compatibility". It 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 a journal in
- * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
- * journal volume. And in this case, older UBI binaries, which know nothing
- * about the journal volume, would just delete this volume and work perfectly
- * fine. This is 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
- * data of the physical eraseblock was moved by the wear-leveling sub-system,
- * then the wear-leveling sub-system calculates the data CRC and stores it in
- * the @data_crc field. And of course, the @copy_flag is %in this case.
- *
- * The @data_size field is used only for static volumes because UBI has to know
- * how many bytes of data are stored in this eraseblock. For dynamic volumes,
- * this field usually contains zero. The only exception is when the data of the
- * physical eraseblock was moved to another physical eraseblock for
- * 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 data size.
- *
- * 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.
- */
-struct ubi_vid_hdr {
- __be32 magic;
- __u8 version;
- __u8 vol_type;
- __u8 copy_flag;
- __u8 compat;
- __be32 vol_id;
- __be32 lnum;
- __be32 leb_ver;
- __be32 data_size;
- __be32 used_ebs;
- __be32 data_pad;
- __be32 data_crc;
- __u8 padding2[4];
- __be64 sqnum;
- __u8 padding3[12];
- __be32 hdr_crc;
-} __attribute__ ((packed));
-
-/* Internal UBI volumes count */
-#define UBI_INT_VOL_COUNT 1
-
-/*
- * Starting ID of internal volumes. There is reserved room for 4096 internal
- * volumes.
- */
-#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
-
-/* The layout volume contains the volume table */
-
-#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
-#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
-#define UBI_LAYOUT_VOLUME_ALIGN 1
-#define UBI_LAYOUT_VOLUME_EBS 2
-#define UBI_LAYOUT_VOLUME_NAME "layout volume"
-#define UBI_LAYOUT_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 the volume table record */
-#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
-
-/* Size of the volume table record without the ending CRC */
-#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
-
-/**
- * struct ubi_vtbl_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 unused at the end of the each physical
- * eraseblock to satisfy the requested alignment
- * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @upd_marker: if volume update was started but not finished
- * @name_len: volume name length
- * @name: the volume name
- * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
- * @padding: reserved, zeroes
- * @crc: a CRC32 checksum of the record
- *
- * The volume table records are stored in the volume table, which is stored in
- * the layout volume. The layout volume consists of 2 logical eraseblock, each
- * of which contains a copy of the volume table (i.e., the volume table is
- * duplicated). The volume table is an array of &struct ubi_vtbl_record
- * objects indexed by the volume ID.
- *
- * If the size of the logical eraseblock is large enough to fit
- * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
- * records. Otherwise, it contains as many records as it can fit (i.e., size of
- * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
- *
- * The @upd_marker flag is used to implement volume update. It is set to %1
- * before update and set to %0 after the update. So if the update operation was
- * interrupted, UBI knows that the volume is corrupted.
- *
- * 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
- * the physical eraseblocks is used.
- *
- * Empty records contain all zeroes and the CRC checksum of those zeroes.
- */
-struct ubi_vtbl_record {
- __be32 reserved_pebs;
- __be32 alignment;
- __be32 data_pad;
- __u8 vol_type;
- __u8 upd_marker;
- __be16 name_len;
- __u8 name[UBI_VOL_NAME_MAX+1];
- __u8 flags;
- __u8 padding[23];
- __be32 crc;
-} __attribute__ ((packed));
-
-#endif /* DOXYGEN_SHOULD_SKIP_THIS */
-
-#endif /* !__UBI_MEDIA_H__ */
-
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 03/10] ubi: bump ubi-media.h to newest version
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
2012-10-26 10:16 ` [RFC 01/10] mtd: move is_power_of_2() to a public place Wolfram Sang
2012-10-26 10:16 ` [RFC 02/10] ubi: consolidate ubi-media.h Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-26 10:16 ` [RFC 04/10] devfs & mtd: add MEMERASE ioctl support Wolfram Sang
` (6 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Needed for ubiformat, we are interested in image_seq especially.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/mtd/ubi-media.h | 57 +++++++++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/include/mtd/ubi-media.h b/include/mtd/ubi-media.h
index cd1bd8e..08bec3e 100644
--- a/include/mtd/ubi-media.h
+++ b/include/mtd/ubi-media.h
@@ -11,6 +11,9 @@
* 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 Bityutskiy (Битюцкий Артём)
* Thomas Gleixner
@@ -95,10 +98,11 @@ enum {
* Compatibility constants used by internal volumes.
*
* @UBI_COMPAT_DELETE: delete this internal volume before anything is written
- * to the flash
+ * to the flash
* @UBI_COMPAT_RO: attach this device in read-only mode
* @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
- * physical eraseblocks, don't allow the wear-leveling unit to move them
+ * physical eraseblocks, don't allow the wear-leveling
+ * sub-system to move them
* @UBI_COMPAT_REJECT: reject this UBI image
*/
enum {
@@ -120,18 +124,19 @@ enum {
* struct ubi_ec_hdr - UBI erase counter header.
* @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
* @version: version of UBI implementation which is supposed to accept this
- * UBI image
+ * UBI image
* @padding1: reserved for future, zeroes
* @ec: the erase counter
* @vid_hdr_offset: where the VID header starts
* @data_offset: where the user data start
+ * @image_seq: image sequence number
* @padding2: reserved for future, zeroes
* @hdr_crc: 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
+ * work with this UBI image. If @version is greater than the current UBI
* version, the image is rejected. This may be useful in future if something
* is changed radically. This field is duplicated in the volume identifier
* header.
@@ -140,6 +145,14 @@ enum {
* volume identifier header and user data, relative to the beginning of the
* physical eraseblock. These values have to be the same for all physical
* eraseblocks.
+ *
+ * The @image_seq field is used to validate a UBI image that has been prepared
+ * for a UBI device. The @image_seq value can be any value, but it must be the
+ * same on all eraseblocks. UBI will ensure that all new erase counter headers
+ * also contain this value, and will check the value when scanning at start-up.
+ * One way to make use of @image_seq is to increase its value by one every time
+ * an image is flashed over an existing image, then, if the flashing does not
+ * complete, UBI will detect the error when scanning.
*/
struct ubi_ec_hdr {
__be32 magic;
@@ -148,7 +161,8 @@ struct ubi_ec_hdr {
__be64 ec; /* Warning: the current limit is 31-bit anyway! */
__be32 vid_hdr_offset;
__be32 data_offset;
- __u8 padding2[36];
+ __be32 image_seq;
+ __u8 padding2[32];
__be32 hdr_crc;
} __attribute__ ((packed));
@@ -156,24 +170,23 @@ struct ubi_ec_hdr {
* 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)
+ * image (%UBI_VERSION)
* @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
* @copy_flag: if this logical eraseblock was copied from another physical
- * eraseblock (for wear-leveling reasons)
+ * eraseblock (for wear-leveling reasons)
* @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
- * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
* @vol_id: ID of this volume
* @lnum: logical eraseblock number
- * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
- * removed, kept only for not breaking older UBI users)
+ * @padding1: reserved for future, zeroes
* @data_size: how many bytes of data this logical eraseblock contains
* @used_ebs: total number of used logical eraseblocks in this volume
* @data_pad: how many bytes at the end of this physical eraseblock are not
- * used
+ * used
* @data_crc: CRC checksum of the data stored in this logical eraseblock
- * @padding1: reserved for future, zeroes
- * @sqnum: sequence number
* @padding2: reserved for future, zeroes
+ * @sqnum: sequence number
+ * @padding3: reserved for future, zeroes
* @hdr_crc: volume identifier header CRC checksum
*
* The @sqnum is the value of the global sequence counter at the time when this
@@ -184,7 +197,7 @@ struct ubi_ec_hdr {
* (sequence number) is used to distinguish between older and newer versions of
* logical eraseblocks.
*
- * There are 2 situations when there may be more then one physical eraseblock
+ * There are 2 situations when there may be more than one physical eraseblock
* corresponding to the same logical eraseblock, i.e., having the same @vol_id
* and @lnum values in the volume identifier header. Suppose we have a logical
* eraseblock L and it is mapped to the physical eraseblock P.
@@ -221,10 +234,6 @@ struct ubi_ec_hdr {
* checksum is correct, this physical eraseblock is selected (P1). Otherwise
* the older one (P) is selected.
*
- * Note, there is an obsolete @leb_ver field which was used instead of @sqnum
- * in the past. But it is not used anymore and we keep it in order to be able
- * to deal with old UBI images. It will be removed at some point.
- *
* There are 2 sorts of volumes in UBI: user volumes and internal volumes.
* Internal volumes are not seen from outside and are used for various internal
* UBI purposes. In this implementation there is only one internal volume - the
@@ -245,9 +254,9 @@ struct ubi_ec_hdr {
* 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
- * data of the physical eraseblock was moved by the wear-leveling unit, then
- * the wear-leveling unit calculates the data CRC and stores it in the
- * @data_crc field. And of course, the @copy_flag is %in this case.
+ * data of the physical eraseblock was moved by the wear-leveling sub-system,
+ * then the wear-leveling sub-system calculates the data CRC and stores it in
+ * the @data_crc field. And of course, the @copy_flag is %in this case.
*
* The @data_size field is used only for static volumes because UBI has to know
* how many bytes of data are stored in this eraseblock. For dynamic volumes,
@@ -274,14 +283,14 @@ struct ubi_vid_hdr {
__u8 compat;
__be32 vol_id;
__be32 lnum;
- __be32 leb_ver; /* obsolete, to be removed, don't use */
+ __be32 leb_ver;
__be32 data_size;
__be32 used_ebs;
__be32 data_pad;
__be32 data_crc;
- __u8 padding1[4];
+ __u8 padding2[4];
__be64 sqnum;
- __u8 padding2[12];
+ __u8 padding3[12];
__be32 hdr_crc;
} __attribute__ ((packed));
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 04/10] devfs & mtd: add MEMERASE ioctl support
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
` (2 preceding siblings ...)
2012-10-26 10:16 ` [RFC 03/10] ubi: bump ubi-media.h to newest version Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-27 12:33 ` Sascha Hauer
2012-10-26 10:16 ` [RFC 05/10] mtd: utils: apply macros for message printouts Wolfram Sang
` (5 subsequent siblings)
9 siblings, 1 reply; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
To make that, we need to shift mtd_erase before mtd_ioctl.
ubi-utils need that, especially ubiformat.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/mtd/core.c | 68 +++++++++++++++++++++++++++-------------------------
fs/devfs-core.c | 3 ++-
2 files changed, 37 insertions(+), 34 deletions(-)
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 7c323a1..aca4f13 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -114,7 +114,37 @@ static ssize_t mtd_write(struct cdev* cdev, const void *buf, size_t _count,
out:
return ret ? ret : _count;
}
-#endif
+
+static int mtd_erase(struct cdev *cdev, size_t count, loff_t offset)
+{
+ struct mtd_info *mtd = cdev->priv;
+ struct erase_info erase;
+ int ret;
+
+ memset(&erase, 0, sizeof(erase));
+ erase.mtd = mtd;
+ erase.addr = offset;
+ erase.len = mtd->erasesize;
+
+ while (count > 0) {
+ dev_dbg(cdev->dev, "erase %d %d\n", erase.addr, erase.len);
+
+ ret = mtd->block_isbad(mtd, erase.addr);
+ if (ret > 0) {
+ printf("Skipping bad block at 0x%08x\n", erase.addr);
+ } else {
+ ret = mtd->erase(mtd, &erase);
+ if (ret)
+ return ret;
+ }
+
+ erase.addr += mtd->erasesize;
+ count -= count > mtd->erasesize ? mtd->erasesize : count;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_MTD_WRITE */
int mtd_ioctl(struct cdev *cdev, int request, void *buf)
{
@@ -125,6 +155,7 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
struct mtd_ecc_stats *ecc = buf;
#endif
struct region_info_user *reg = buf;
+ struct erase_info_user *ei = buf;
loff_t *offset = buf;
switch (request) {
@@ -137,6 +168,9 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08llx\n", *offset);
ret = mtd->block_markbad(mtd, *offset);
break;
+ case MEMERASE:
+ ret = mtd_erase(cdev, ei->length, ei->start + cdev->offset);
+ break;
#endif
case MEMGETINFO:
user->type = mtd->type;
@@ -174,38 +208,6 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
return ret;
}
-#ifdef CONFIG_MTD_WRITE
-static int mtd_erase(struct cdev *cdev, size_t count, loff_t offset)
-{
- struct mtd_info *mtd = cdev->priv;
- struct erase_info erase;
- int ret;
-
- memset(&erase, 0, sizeof(erase));
- erase.mtd = mtd;
- erase.addr = offset;
- erase.len = mtd->erasesize;
-
- while (count > 0) {
- dev_dbg(cdev->dev, "erase %d %d\n", erase.addr, erase.len);
-
- ret = mtd->block_isbad(mtd, erase.addr);
- if (ret > 0) {
- printf("Skipping bad block at 0x%08x\n", erase.addr);
- } else {
- ret = mtd->erase(mtd, &erase);
- if (ret)
- return ret;
- }
-
- erase.addr += mtd->erasesize;
- count -= count > mtd->erasesize ? mtd->erasesize : count;
- }
-
- return 0;
-}
-#endif
-
static struct file_operations mtd_ops = {
.read = mtd_read,
#ifdef CONFIG_MTD_WRITE
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 0d2f75a..262e0a2 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -152,13 +152,14 @@ static int partition_ioctl(struct cdev *cdev, int request, void *buf)
break;
#if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT))
case ECCGETSTATS:
+#endif
+ case MEMERASE:
if (!cdev->ops->ioctl) {
ret = -EINVAL;
break;
}
ret = cdev->ops->ioctl(cdev, request, buf);
break;
-#endif
#ifdef CONFIG_PARTITION
case MEMGETREGIONINFO:
if (cdev->mtd) {
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC 04/10] devfs & mtd: add MEMERASE ioctl support
2012-10-26 10:16 ` [RFC 04/10] devfs & mtd: add MEMERASE ioctl support Wolfram Sang
@ 2012-10-27 12:33 ` Sascha Hauer
2012-12-09 19:36 ` Wolfram Sang
0 siblings, 1 reply; 17+ messages in thread
From: Sascha Hauer @ 2012-10-27 12:33 UTC (permalink / raw)
To: Wolfram Sang; +Cc: barebox
On Fri, Oct 26, 2012 at 12:16:36PM +0200, Wolfram Sang wrote:
> To make that, we need to shift mtd_erase before mtd_ioctl.
> ubi-utils need that, especially ubiformat.
>
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
> ---
> drivers/mtd/core.c | 68 +++++++++++++++++++++++++++-------------------------
> fs/devfs-core.c | 3 ++-
> 2 files changed, 37 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
> index 7c323a1..aca4f13 100644
> --- a/drivers/mtd/core.c
> +++ b/drivers/mtd/core.c
> @@ -114,7 +114,37 @@ static ssize_t mtd_write(struct cdev* cdev, const void *buf, size_t _count,
> out:
> return ret ? ret : _count;
> }
> -#endif
> +
> +static int mtd_erase(struct cdev *cdev, size_t count, loff_t offset)
> +{
> + struct mtd_info *mtd = cdev->priv;
> + struct erase_info erase;
> + int ret;
> +
> + memset(&erase, 0, sizeof(erase));
> + erase.mtd = mtd;
> + erase.addr = offset;
> + erase.len = mtd->erasesize;
> +
> + while (count > 0) {
> + dev_dbg(cdev->dev, "erase %d %d\n", erase.addr, erase.len);
> +
> + ret = mtd->block_isbad(mtd, erase.addr);
> + if (ret > 0) {
> + printf("Skipping bad block at 0x%08x\n", erase.addr);
> + } else {
> + ret = mtd->erase(mtd, &erase);
> + if (ret)
> + return ret;
> + }
> +
> + erase.addr += mtd->erasesize;
> + count -= count > mtd->erasesize ? mtd->erasesize : count;
> + }
> +
> + return 0;
> +}
> +#endif /* CONFIG_MTD_WRITE */
>
> int mtd_ioctl(struct cdev *cdev, int request, void *buf)
> {
> @@ -125,6 +155,7 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
> struct mtd_ecc_stats *ecc = buf;
> #endif
> struct region_info_user *reg = buf;
> + struct erase_info_user *ei = buf;
> loff_t *offset = buf;
>
> switch (request) {
> @@ -137,6 +168,9 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
> dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08llx\n", *offset);
> ret = mtd->block_markbad(mtd, *offset);
> break;
> + case MEMERASE:
> + ret = mtd_erase(cdev, ei->length, ei->start + cdev->offset);
> + break;
Please check this compiles with CONFIG_MTD_WRITE disabled.
> #endif
> case MEMGETINFO:
> user->type = mtd->type;
> @@ -174,38 +208,6 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
> return ret;
> }
>
> -#ifdef CONFIG_MTD_WRITE
> -static int mtd_erase(struct cdev *cdev, size_t count, loff_t offset)
> -{
> - struct mtd_info *mtd = cdev->priv;
> - struct erase_info erase;
> - int ret;
> -
> - memset(&erase, 0, sizeof(erase));
> - erase.mtd = mtd;
> - erase.addr = offset;
> - erase.len = mtd->erasesize;
> -
> - while (count > 0) {
> - dev_dbg(cdev->dev, "erase %d %d\n", erase.addr, erase.len);
> -
> - ret = mtd->block_isbad(mtd, erase.addr);
> - if (ret > 0) {
> - printf("Skipping bad block at 0x%08x\n", erase.addr);
> - } else {
> - ret = mtd->erase(mtd, &erase);
> - if (ret)
> - return ret;
> - }
> -
> - erase.addr += mtd->erasesize;
> - count -= count > mtd->erasesize ? mtd->erasesize : count;
> - }
> -
> - return 0;
> -}
> -#endif
> -
> static struct file_operations mtd_ops = {
> .read = mtd_read,
> #ifdef CONFIG_MTD_WRITE
> diff --git a/fs/devfs-core.c b/fs/devfs-core.c
> index 0d2f75a..262e0a2 100644
> --- a/fs/devfs-core.c
> +++ b/fs/devfs-core.c
> @@ -152,13 +152,14 @@ static int partition_ioctl(struct cdev *cdev, int request, void *buf)
> break;
> #if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT))
> case ECCGETSTATS:
> +#endif
> + case MEMERASE:
> if (!cdev->ops->ioctl) {
> ret = -EINVAL;
> break;
> }
> ret = cdev->ops->ioctl(cdev, request, buf);
> break;
Are you sure this works for partitions? I assume you have to take
cdev->offset into account like for example the MEMGETBADBLOCK ioctl
does.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC 04/10] devfs & mtd: add MEMERASE ioctl support
2012-10-27 12:33 ` Sascha Hauer
@ 2012-12-09 19:36 ` Wolfram Sang
0 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-12-09 19:36 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
[-- Attachment #1.1: Type: text/plain, Size: 658 bytes --]
> > @@ -137,6 +168,9 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
> > dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08llx\n", *offset);
> > ret = mtd->block_markbad(mtd, *offset);
> > break;
> > + case MEMERASE:
> > + ret = mtd_erase(cdev, ei->length, ei->start + cdev->offset);
> > + break;
>
> Please check this compiles with CONFIG_MTD_WRITE disabled.
It does, since I move mtd_erase to the front. The upper block and
mtd_erase are both protected by MTD_WRITE.
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
[-- Attachment #2: Type: text/plain, Size: 149 bytes --]
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 05/10] mtd: utils: apply macros for message printouts
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
` (3 preceding siblings ...)
2012-10-26 10:16 ` [RFC 04/10] devfs & mtd: add MEMERASE ioctl support Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-26 10:16 ` [RFC 06/10] lib: add ubiutils-common Wolfram Sang
` (4 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
mtd-utils have a few macros for printouts. Provide the wrappers to make
it easier to import them.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/mtd/utils.h | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/include/mtd/utils.h b/include/mtd/utils.h
index 229fb34..05a3405 100644
--- a/include/mtd/utils.h
+++ b/include/mtd/utils.h
@@ -17,6 +17,33 @@
#ifndef INCLUDE_MTD_UTILS_H
# define INCLUDE_MTD_UTILS_H
+/* Messages as used in mtd-utils */
+
+#define bareverbose(verbose, fmt, ...) do { \
+ if (verbose) \
+ printf(fmt, ##__VA_ARGS__); \
+} while(0)
+#define verbose(verbose, fmt, ...) \
+ bareverbose(verbose, "%s: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__)
+
+#define normsg_cont(fmt, ...) do { \
+ printf("%s: " fmt, PROGRAM_NAME, ##__VA_ARGS__); \
+} while(0)
+
+#define normsg(fmt, ...) do { \
+ normsg_cont(fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+#define errmsg(fmt, ...) ({ \
+ printf("%s: error!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
+ -1; \
+})
+#define sys_errmsg errmsg
+
+#define warnmsg(fmt, ...) do { \
+ fprintf(stderr, "%s: warning!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
+} while(0)
+
static inline int is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 06/10] lib: add ubiutils-common
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
` (4 preceding siblings ...)
2012-10-26 10:16 ` [RFC 05/10] mtd: utils: apply macros for message printouts Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-26 10:16 ` [RFC 07/10] lib: add libscan Wolfram Sang
` (3 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Imported from mtd-utils and stripped down to needed functionality for
ubiformat.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/mtd/ubiutils-common.h | 26 +++++++++
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/ubiutils-common.c | 122 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 152 insertions(+)
create mode 100644 include/mtd/ubiutils-common.h
create mode 100644 lib/ubiutils-common.c
diff --git a/include/mtd/ubiutils-common.h b/include/mtd/ubiutils-common.h
new file mode 100644
index 0000000..3a16617
--- /dev/null
+++ b/include/mtd/ubiutils-common.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) Artem Bityutskiy, 2007, 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __UBI_UTILS_COMMON_H__
+#define __UBI_UTILS_COMMON_H__
+
+long long ubiutils_get_bytes(const char *str);
+void ubiutils_print_bytes(long long bytes, int bracket);
+
+#endif /* !__UBI_UTILS_COMMON_H__ */
+
diff --git a/lib/Kconfig b/lib/Kconfig
index 9882d2d..fd7a1f9 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -38,6 +38,9 @@ config BITREV
config QSORT
bool
+config UBIUTILS
+ bool
+
source lib/gui/Kconfig
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 41e6a0f..68404d1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -34,4 +34,5 @@ obj-$(CONFIG_UNCOMPRESS) += uncompress.o
obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
+obj-$(CONFIG_UBIUTILS) += ubiutils-common.o
obj-y += gui/
diff --git a/lib/ubiutils-common.c b/lib/ubiutils-common.c
new file mode 100644
index 0000000..d01e723
--- /dev/null
+++ b/lib/ubiutils-common.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007, 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file contains various common stuff used by UBI utilities.
+ *
+ * Authors: Artem Bityutskiy
+ * Adrian Hunter
+ */
+
+#include <common.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * get_multiplier - convert size specifier to an integer multiplier.
+ * @str: the size specifier string
+ *
+ * This function parses the @str size specifier, which may be one of
+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
+ * size multiplier in case of success and %-1 in case of failure.
+ */
+static int get_multiplier(const char *str)
+{
+ if (!str)
+ return 1;
+
+ /* Remove spaces before the specifier */
+ while (*str == ' ' || *str == '\t')
+ str += 1;
+
+ if (!strcmp(str, "KiB"))
+ return 1024;
+ if (!strcmp(str, "MiB"))
+ return 1024 * 1024;
+ if (!strcmp(str, "GiB"))
+ return 1024 * 1024 * 1024;
+
+ return -1;
+}
+
+/**
+ * ubiutils_get_bytes - convert a string containing amount of bytes into an
+ * integer
+ * @str: string to convert
+ *
+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB'
+ * size specifiers. Returns positive amount of bytes in case of success and %-1
+ * in case of failure.
+ */
+long long ubiutils_get_bytes(const char *str)
+{
+ char *endp;
+ long long bytes = simple_strtoull(str, &endp, 0);
+
+ if (endp == str || bytes < 0) {
+ fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str);
+ return -1;
+ }
+
+ if (*endp != '\0') {
+ int mult = get_multiplier(endp);
+
+ if (mult == -1) {
+ fprintf(stderr, "bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'\n", endp);
+ return -1;
+ }
+ bytes *= mult;
+ }
+
+ return bytes;
+}
+
+/**
+ * ubiutils_print_bytes - print bytes.
+ * @bytes: variable to print
+ * @bracket: whether brackets have to be put or not
+ *
+ * This is a helper function which prints amount of bytes in a human-readable
+ * form, i.e., it prints the exact amount of bytes following by the approximate
+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
+ * is.
+ */
+void ubiutils_print_bytes(long long bytes, int bracket)
+{
+ const char *p;
+
+ if (bracket)
+ p = " (";
+ else
+ p = ", ";
+
+ printf("%lld bytes", bytes);
+
+ if (bytes > 1024 * 1024 * 1024)
+ printf("%s%lld GiB", p, bytes / (1024 * 1024 * 1024));
+ else if (bytes > 1024 * 1024)
+ printf("%s%lld MiB", p, bytes / (1024 * 1024));
+ else if (bytes > 1024 && bytes != 0)
+ printf("%s%lld KiB", p, bytes / 1024);
+ else
+ return;
+
+ if (bracket)
+ printf(")");
+}
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 07/10] lib: add libscan
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
` (5 preceding siblings ...)
2012-10-26 10:16 ` [RFC 06/10] lib: add ubiutils-common Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-26 10:16 ` [RFC 08/10] lib: add libubigen Wolfram Sang
` (2 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Imported from mtd-utils and stripped down to needed functionality.
Add prefix to functions so we have a clean namespace.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/mtd/libscan.h | 105 +++++++++++++++++++++++
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/libscan.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 332 insertions(+)
create mode 100644 include/mtd/libscan.h
create mode 100644 lib/libscan.c
diff --git a/include/mtd/libscan.h b/include/mtd/libscan.h
new file mode 100644
index 0000000..193b07b
--- /dev/null
+++ b/include/mtd/libscan.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI scanning library.
+ */
+
+#ifndef __LIBSCAN_H__
+#define __LIBSCAN_H__
+
+#include <mtd/ubi-media.h>
+
+/*
+ * If an eraseblock does not contain an erase counter, this value is used
+ * instead of the erase counter.
+ */
+#define NO_EC 0xFFFFFFFF
+
+/*
+ * If an eraseblock contains a corrupted erase counter, this value is used
+ * instead of the erase counter.
+ */
+#define CORRUPT_EC 0xFFFFFFFE
+
+/*
+ * If an eraseblock does not contain an erase counter, one of these values is
+ * used.
+ *
+ * @EB_EMPTY: the eraseblock appeared to be empty
+ * @EB_CORRUPTED: the eraseblock contains corrupted erase counter header
+ * @EB_ALIEN: the eraseblock contains some non-UBI data
+ * @EC_MAX: maximum allowed erase counter value
+ */
+enum
+{
+ EB_EMPTY = 0xFFFFFFFF,
+ EB_CORRUPTED = 0xFFFFFFFE,
+ EB_ALIEN = 0xFFFFFFFD,
+ EB_BAD = 0xFFFFFFFC,
+ EC_MAX = UBI_MAX_ERASECOUNTER,
+};
+
+/**
+ * struct ubi_scan_info - UBI scanning information.
+ * @ec: erase counters or eraseblock status for all eraseblocks
+ * @mean_ec: mean erase counter
+ * @ok_cnt: count of eraseblock with correct erase counter header
+ * @empty_cnt: count of supposedly eraseblocks
+ * @corrupted_cnt: count of eraseblocks with corrupted erase counter header
+ * @alien_cnt: count of eraseblock containing non-ubi data
+ * @bad_cnt: count of bad eraseblocks
+ * @bad_cnt: count of non-bad eraseblocks
+ * @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means
+ * undefined)
+ * @data_offs: data offset from the found EC headers (%-1 means undefined)
+ */
+struct ubi_scan_info
+{
+ uint32_t *ec;
+ long long mean_ec;
+ int ok_cnt;
+ int empty_cnt;
+ int corrupted_cnt;
+ int alien_cnt;
+ int bad_cnt;
+ int good_cnt;
+ int vid_hdr_offs;
+ int data_offs;
+};
+
+struct mtd_dev_info;
+
+/**
+ * ubi_scan - scan an MTD device.
+ * @mtd: information about the MTD device to scan
+ * @fd: MTD device node file descriptor
+ * @info: the result of the scanning is returned here
+ * @verbose: verbose mode: %0 - be silent, %1 - output progress information,
+ * 2 - debugging output mode
+ */
+int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **info,
+ int verbose);
+
+/**
+ * ubi_scan_free - free scanning information.
+ * @si: scanning information to free
+ */
+void libscan_ubi_scan_free(struct ubi_scan_info *si);
+
+#endif /* __LIBSCAN_H__ */
diff --git a/lib/Kconfig b/lib/Kconfig
index fd7a1f9..1d4d8ad 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -41,6 +41,9 @@ config QSORT
config UBIUTILS
bool
+config LIBSCAN
+ bool
+
source lib/gui/Kconfig
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 68404d1..41583c8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -35,4 +35,5 @@ obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_UBIUTILS) += ubiutils-common.o
+obj-$(CONFIG_LIBSCAN) += libscan.o
obj-y += gui/
diff --git a/lib/libscan.c b/lib/libscan.c
new file mode 100644
index 0000000..951e0e7
--- /dev/null
+++ b/lib/libscan.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI scanning library.
+ */
+
+#define PROGRAM_NAME "libscan"
+
+#include <common.h>
+#include <fcntl.h>
+#include <crc.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/stat.h>
+#include <linux/mtd/mtd-abi.h>
+#include <mtd/libmtd.h>
+#include <mtd/libscan.h>
+#include <mtd/ubi-user.h>
+#include <mtd/utils.h>
+#include <mtd/ubi-media.h>
+#include <asm-generic/div64.h>
+
+static int all_ff(const void *buf, int len)
+{
+ int i;
+ const uint8_t *p = buf;
+
+ for (i = 0; i < len; i++)
+ if (p[i] != 0xFF)
+ return 0;
+ return 1;
+}
+
+int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **info,
+ int verbose)
+{
+ int eb, v = (verbose == 2), pr = (verbose == 1);
+ struct ubi_scan_info *si;
+ unsigned long long sum = 0;
+
+ si = calloc(1, sizeof(struct ubi_scan_info));
+ if (!si)
+ return sys_errmsg("cannot allocate %zd bytes of memory",
+ sizeof(struct ubi_scan_info));
+
+ si->ec = calloc(mtd->eb_cnt, sizeof(uint32_t));
+ if (!si->ec) {
+ sys_errmsg("cannot allocate %zd bytes of memory",
+ sizeof(struct ubi_scan_info));
+ goto out_si;
+ }
+
+ si->vid_hdr_offs = si->data_offs = -1;
+
+ verbose(v, "start scanning eraseblocks 0-%d", mtd->eb_cnt);
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ int ret;
+ uint32_t crc;
+ struct ubi_ec_hdr ech;
+ unsigned long long ec;
+
+ if (v)
+ normsg_cont("scanning eraseblock %d", eb);
+ if (pr) {
+ printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2u %% complete ",
+ eb, (eb + 1) * 100 / mtd->eb_cnt);
+ }
+
+ ret = mtd_is_bad(mtd, fd, eb);
+ if (ret == -1)
+ goto out_ec;
+ if (ret) {
+ si->bad_cnt += 1;
+ si->ec[eb] = EB_BAD;
+ if (v)
+ printf(": bad\n");
+ continue;
+ }
+
+ ret = mtd_read(mtd, fd, eb, 0, &ech, sizeof(struct ubi_ec_hdr));
+ if (ret < 0)
+ goto out_ec;
+
+ if (be32_to_cpu(ech.magic) != UBI_EC_HDR_MAGIC) {
+ if (all_ff(&ech, sizeof(struct ubi_ec_hdr))) {
+ si->empty_cnt += 1;
+ si->ec[eb] = EB_EMPTY;
+ if (v)
+ printf(": empty\n");
+ } else {
+ si->alien_cnt += 1;
+ si->ec[eb] = EB_ALIEN;
+ if (v)
+ printf(": alien\n");
+ }
+ continue;
+ }
+
+ crc = crc32_no_comp(UBI_CRC32_INIT, &ech, UBI_EC_HDR_SIZE_CRC);
+ if (be32_to_cpu(ech.hdr_crc) != crc) {
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ if (v)
+ printf(": bad CRC %#08x, should be %#08x\n",
+ crc, be32_to_cpu(ech.hdr_crc));
+ continue;
+ }
+
+ ec = be64_to_cpu(ech.ec);
+ if (ec > EC_MAX) {
+ if (pr)
+ printf("\n");
+ errmsg("erase counter in EB %d is %llu, while this "
+ "program expects them to be less than %u",
+ eb, ec, EC_MAX);
+ goto out_ec;
+ }
+
+ if (si->vid_hdr_offs == -1) {
+ si->vid_hdr_offs = be32_to_cpu(ech.vid_hdr_offset);
+ si->data_offs = be32_to_cpu(ech.data_offset);
+ if (si->data_offs % mtd->min_io_size) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("bad data offset %d at eraseblock %d (n"
+ "of multiple of min. I/O unit size %d)",
+ si->data_offs, eb, mtd->min_io_size);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+
+ }
+ } else {
+ if ((int)be32_to_cpu(ech.vid_hdr_offset) != si->vid_hdr_offs) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("inconsistent VID header offset: was "
+ "%d, but is %d in eraseblock %d",
+ si->vid_hdr_offs,
+ be32_to_cpu(ech.vid_hdr_offset), eb);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+ }
+ if ((int)be32_to_cpu(ech.data_offset) != si->data_offs) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("inconsistent data offset: was %d, but"
+ " is %d in eraseblock %d",
+ si->data_offs,
+ be32_to_cpu(ech.data_offset), eb);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+ }
+ }
+
+ si->ok_cnt += 1;
+ si->ec[eb] = ec;
+ if (v)
+ printf(": OK, erase counter %u\n", si->ec[eb]);
+ }
+
+ if (si->ok_cnt != 0) {
+ /* Calculate mean erase counter */
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ if (si->ec[eb] > EC_MAX)
+ continue;
+ sum += si->ec[eb];
+ }
+ do_div(sum, si->ok_cnt);
+ si->mean_ec = sum;
+ }
+
+ si->good_cnt = mtd->eb_cnt - si->bad_cnt;
+ verbose(v, "finished, mean EC %lld, %d OK, %d corrupted, %d empty, %d "
+ "alien, bad %d", si->mean_ec, si->ok_cnt, si->corrupted_cnt,
+ si->empty_cnt, si->alien_cnt, si->bad_cnt);
+
+ *info = si;
+ if (pr)
+ printf("\n");
+ return 0;
+
+out_ec:
+ free(si->ec);
+out_si:
+ free(si);
+ *info = NULL;
+ return -1;
+}
+
+void libscan_ubi_scan_free(struct ubi_scan_info *si)
+{
+ free(si->ec);
+ free(si);
+}
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 08/10] lib: add libubigen
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
` (6 preceding siblings ...)
2012-10-26 10:16 ` [RFC 07/10] lib: add libscan Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-26 10:16 ` [RFC 09/10] lib: add barebox version of libmtd Wolfram Sang
2012-10-26 10:16 ` [RFC 10/10] commands: add ubiformat Wolfram Sang
9 siblings, 0 replies; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Imported from mtd-utils and stripped down to needed functionality.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/mtd/libubigen.h | 186 ++++++++++++++++++++++++++++
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/libubigen.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 506 insertions(+)
create mode 100644 include/mtd/libubigen.h
create mode 100644 lib/libubigen.c
diff --git a/include/mtd/libubigen.h b/include/mtd/libubigen.h
new file mode 100644
index 0000000..5ebdb78
--- /dev/null
+++ b/include/mtd/libubigen.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Authors: Frank Haverkamp
+ * Artem Bityutskiy
+ */
+
+#ifndef __LIBUBIGEN_H__
+#define __LIBUBIGEN_H__
+
+#include <mtd/ubi-media.h>
+
+/**
+ * struct ubigen_info - libubigen information.
+ * @leb_size: logical eraseblock size
+ * @peb_size: size of the physical eraseblock
+ * @min_io_size: minimum input/output unit size
+ * @vid_hdr_offs: offset of the VID header
+ * @data_offs: data offset
+ * @ubi_ver: UBI version
+ * @vtbl_size: volume table size
+ * @max_volumes: maximum amount of volumes
+ * @image_seq: UBI image sequence number
+ */
+struct ubigen_info
+{
+ int leb_size;
+ int peb_size;
+ int min_io_size;
+ int vid_hdr_offs;
+ int data_offs;
+ int ubi_ver;
+ int vtbl_size;
+ int max_volumes;
+ uint32_t image_seq;
+};
+
+/**
+ * struct ubigen_vol_info - information about a volume.
+ * @id: volume id
+ * @type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @usable_leb_size: LEB size accessible for volume users
+ * @name: volume name
+ * @name_len: volume name length
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @used_ebs: total number of used logical eraseblocks in this volume (relevant
+ * for static volumes only)
+ * @bytes: size of the volume contents in bytes (relevant for static volumes
+ * only)
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ */
+struct ubigen_vol_info
+{
+ int id;
+ int type;
+ int alignment;
+ int data_pad;
+ int usable_leb_size;
+ const char *name;
+ int name_len;
+ int compat;
+ int used_ebs;
+ long long bytes;
+ uint8_t flags;
+};
+
+/**
+ * ubigen_info_init - initialize libubigen.
+ * @ui: libubigen information
+ * @peb_size: flash physical eraseblock size
+ * @min_io_size: flash minimum input/output unit size
+ * @subpage_size: flash sub-page, if present (has to be equivalent to
+ * @min_io_size if does not exist)
+ * @vid_hdr_offs: offset of the VID header
+ * @ubi_ver: UBI version
+ * @image_seq: UBI image sequence number
+ */
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+ int subpage_size, int vid_hdr_offs, int ubi_ver,
+ uint32_t image_seq);
+
+/**
+ * ubigen_create_empty_vtbl - creates empty volume table.
+ * @ui: libubigen information
+ *
+ * This function creates an empty volume table and returns a pointer to it in
+ * case of success and %NULL in case of failure. The returned object has to be
+ * freed with 'free()' call.
+ */
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui);
+
+/**
+ * ubigen_init_ec_hdr - initialize EC header.
+ * @ui: libubigen information
+ * @hdr: the EC header to initialize
+ * @ec: erase counter value
+ */
+void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+ struct ubi_ec_hdr *hdr, long long ec);
+
+/**
+ * ubigen_init_vid_hdr - initialize VID header.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @hdr: the VID header to initialize
+ * @lnum: logical eraseblock number
+ * @data: the contents of the LEB (static volumes only)
+ * @data_size: amount of data in this LEB (static volumes only)
+ *
+ * Note, @used_ebs, @data and @data_size are ignored in case of dynamic
+ * volumes.
+ */
+void ubigen_init_vid_hdr(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vid_hdr *hdr, int lnum,
+ const void *data, int data_size);
+
+/**
+ * ubigen_add_volume - add a volume to the volume table.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @vtbl: volume table to add to
+ *
+ * This function adds volume described by input parameters to the volume table
+ * @vtbl.
+ */
+int ubigen_add_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vtbl_record *vtbl);
+
+/**
+ * ubigen_write_volume - write UBI volume.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @ec: erase counter value to put to EC headers
+ * @bytes: volume size in bytes
+ * @in: input file descriptor (has to be properly seeked)
+ * @out: output file descriptor
+ *
+ * This function reads the contents of the volume from the input file @in and
+ * writes the UBI volume to the output file @out. Returns zero on success and
+ * %-1 on failure.
+ */
+int ubigen_write_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi, long long ec,
+ long long bytes, int in, int out);
+
+/**
+ * ubigen_write_layout_vol - write UBI layout volume
+ * @ui: libubigen information
+ * @peb1: physical eraseblock number to write the first volume table copy
+ * @peb2: physical eraseblock number to write the second volume table copy
+ * @ec1: erase counter value for @peb1
+ * @ec2: erase counter value for @peb1
+ * @vtbl: volume table
+ * @fd: output file descriptor seeked to the proper position
+ *
+ * This function creates the UBI layout volume which contains 2 copies of the
+ * volume table. Returns zero in case of success and %-1 in case of failure.
+ */
+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
+ long long ec1, long long ec2,
+ struct ubi_vtbl_record *vtbl, int fd);
+
+#endif /* !__LIBUBIGEN_H__ */
diff --git a/lib/Kconfig b/lib/Kconfig
index 1d4d8ad..e6727b3 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -44,6 +44,9 @@ config UBIUTILS
config LIBSCAN
bool
+config LIBUBIGEN
+ bool
+
source lib/gui/Kconfig
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 41583c8..e996a48 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -36,4 +36,5 @@ obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_UBIUTILS) += ubiutils-common.o
obj-$(CONFIG_LIBSCAN) += libscan.o
+obj-$(CONFIG_LIBUBIGEN) += libubigen.o
obj-y += gui/
diff --git a/lib/libubigen.c b/lib/libubigen.c
new file mode 100644
index 0000000..9001c3b
--- /dev/null
+++ b/lib/libubigen.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Generating UBI images.
+ *
+ * Authors: Oliver Lohmann
+ * Artem Bityutskiy
+ */
+
+#define PROGRAM_NAME "libubigen"
+
+#include <common.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <crc.h>
+#include <fs.h>
+
+#include <mtd/utils.h>
+#include <mtd/ubi-media.h>
+#include <mtd/libubigen.h>
+
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+ int subpage_size, int vid_hdr_offs, int ubi_ver,
+ uint32_t image_seq)
+{
+ if (!vid_hdr_offs) {
+ vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1;
+ vid_hdr_offs /= subpage_size;
+ vid_hdr_offs *= subpage_size;
+ }
+
+ ui->peb_size = peb_size;
+ ui->min_io_size = min_io_size;
+ ui->vid_hdr_offs = vid_hdr_offs;
+ ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
+ ui->data_offs /= min_io_size;
+ ui->data_offs *= min_io_size;
+ ui->leb_size = peb_size - ui->data_offs;
+ ui->ubi_ver = ubi_ver;
+ ui->image_seq = image_seq;
+
+ ui->max_volumes = ui->leb_size / UBI_VTBL_RECORD_SIZE;
+ if (ui->max_volumes > UBI_MAX_VOLUMES)
+ ui->max_volumes = UBI_MAX_VOLUMES;
+ ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE;
+}
+
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
+{
+ struct ubi_vtbl_record *vtbl;
+ int i;
+
+ vtbl = calloc(1, ui->vtbl_size);
+ if (!vtbl) {
+ sys_errmsg("cannot allocate %d bytes of memory", ui->vtbl_size);
+ return NULL;
+ }
+
+ for (i = 0; i < ui->max_volumes; i++) {
+ uint32_t crc = crc32_no_comp(UBI_CRC32_INIT, &vtbl[i],
+ UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl[i].crc = cpu_to_be32(crc);
+ }
+
+ return vtbl;
+}
+
+int ubigen_add_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vtbl_record *vtbl)
+{
+ struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
+ uint32_t tmp;
+
+ if (vi->id >= ui->max_volumes) {
+ errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (vi->alignment >= ui->leb_size) {
+ errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
+ tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size;
+ vtbl_rec->reserved_pebs = cpu_to_be32(tmp);
+ vtbl_rec->alignment = cpu_to_be32(vi->alignment);
+ vtbl_rec->vol_type = vi->type;
+ tmp = ui->leb_size % vi->alignment;
+ vtbl_rec->data_pad = cpu_to_be32(tmp);
+ vtbl_rec->flags = vi->flags;
+
+ memcpy(vtbl_rec->name, vi->name, vi->name_len);
+ vtbl_rec->name[vi->name_len] = '\0';
+ vtbl_rec->name_len = cpu_to_be16(vi->name_len);
+
+ tmp = crc32_no_comp(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl_rec->crc = cpu_to_be32(tmp);
+ return 0;
+}
+
+void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+ struct ubi_ec_hdr *hdr, long long ec)
+{
+ uint32_t crc;
+
+ memset(hdr, 0, sizeof(struct ubi_ec_hdr));
+
+ hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+ hdr->version = ui->ubi_ver;
+ hdr->ec = cpu_to_be64(ec);
+ hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
+ hdr->data_offset = cpu_to_be32(ui->data_offs);
+ hdr->image_seq = cpu_to_be32(ui->image_seq);
+
+ crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+void ubigen_init_vid_hdr(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vid_hdr *hdr, int lnum,
+ const void *data, int data_size)
+{
+ uint32_t crc;
+
+ memset(hdr, 0, sizeof(struct ubi_vid_hdr));
+
+ hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+ hdr->version = ui->ubi_ver;
+ hdr->vol_type = vi->type;
+ hdr->vol_id = cpu_to_be32(vi->id);
+ hdr->lnum = cpu_to_be32(lnum);
+ hdr->data_pad = cpu_to_be32(vi->data_pad);
+ hdr->compat = vi->compat;
+
+ if (vi->type == UBI_VID_STATIC) {
+ hdr->data_size = cpu_to_be32(data_size);
+ hdr->used_ebs = cpu_to_be32(vi->used_ebs);
+ crc = crc32_no_comp(UBI_CRC32_INIT, data, data_size);
+ hdr->data_crc = cpu_to_be32(crc);
+ }
+
+ crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+int ubigen_write_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi, long long ec,
+ long long bytes, int in, int out)
+{
+ int len = vi->usable_leb_size, rd, lnum = 0;
+ char *inbuf, *outbuf;
+
+ if (vi->id >= ui->max_volumes) {
+ errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (vi->alignment >= ui->leb_size) {
+ errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
+ errno = EINVAL;
+ return -1;
+ }
+
+ inbuf = malloc(ui->leb_size);
+ if (!inbuf)
+ return sys_errmsg("cannot allocate %d bytes of memory",
+ ui->leb_size);
+ outbuf = malloc(ui->peb_size);
+ if (!outbuf) {
+ sys_errmsg("cannot allocate %d bytes of memory", ui->peb_size);
+ goto out_free;
+ }
+
+ memset(outbuf, 0xFF, ui->data_offs);
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec);
+
+ while (bytes) {
+ int l;
+ struct ubi_vid_hdr *vid_hdr;
+
+ if (bytes < len)
+ len = bytes;
+ bytes -= len;
+
+ l = len;
+ do {
+ rd = read(in, inbuf + len - l, l);
+ if (rd != l) {
+ sys_errmsg("cannot read %d bytes from the input file", l);
+ goto out_free1;
+ }
+
+ l -= rd;
+ } while (l);
+
+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+ ubigen_init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len);
+
+ memcpy(outbuf + ui->data_offs, inbuf, len);
+ memset(outbuf + ui->data_offs + len, 0xFF,
+ ui->peb_size - ui->data_offs - len);
+
+ if (write(out, outbuf, ui->peb_size) != ui->peb_size) {
+ sys_errmsg("cannot write %d bytes to the output file", ui->peb_size);
+ goto out_free1;
+ }
+
+ lnum += 1;
+ }
+
+ free(outbuf);
+ free(inbuf);
+ return 0;
+
+out_free1:
+ free(outbuf);
+out_free:
+ free(inbuf);
+ return -1;
+}
+
+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
+ long long ec1, long long ec2,
+ struct ubi_vtbl_record *vtbl, int fd)
+{
+ int ret;
+ struct ubigen_vol_info vi;
+ char *outbuf;
+ struct ubi_vid_hdr *vid_hdr;
+ off_t seek;
+
+ vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
+ vi.id = UBI_LAYOUT_VOLUME_ID;
+ vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
+ vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
+ vi.usable_leb_size = ui->leb_size - vi.data_pad;
+ vi.data_pad = ui->leb_size - vi.usable_leb_size;
+ vi.type = UBI_LAYOUT_VOLUME_TYPE;
+ vi.name = UBI_LAYOUT_VOLUME_NAME;
+ vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
+ vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
+
+ outbuf = malloc(ui->peb_size);
+ if (!outbuf)
+ return sys_errmsg("failed to allocate %d bytes",
+ ui->peb_size);
+
+ memset(outbuf, 0xFF, ui->data_offs);
+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+ memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size);
+ memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF,
+ ui->peb_size - ui->data_offs - ui->vtbl_size);
+
+ seek = (off_t) peb1 * ui->peb_size;
+ if (lseek(fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek output file");
+ goto out_free;
+ }
+
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1);
+ ubigen_init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
+ ret = write(fd, outbuf, ui->peb_size);
+ if (ret != ui->peb_size) {
+ sys_errmsg("cannot write %d bytes", ui->peb_size);
+ goto out_free;
+ }
+
+ seek = (off_t) peb2 * ui->peb_size;
+ if (lseek(fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek output file");
+ goto out_free;
+ }
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2);
+ ubigen_init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
+ ret = write(fd, outbuf, ui->peb_size);
+ if (ret != ui->peb_size) {
+ sys_errmsg("cannot write %d bytes", ui->peb_size);
+ goto out_free;
+ }
+
+ free(outbuf);
+ return 0;
+
+out_free:
+ free(outbuf);
+ return -1;
+}
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 09/10] lib: add barebox version of libmtd
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
` (7 preceding siblings ...)
2012-10-26 10:16 ` [RFC 08/10] lib: add libubigen Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-27 20:11 ` Jean-Christophe PLAGNIOL-VILLARD
2012-10-26 10:16 ` [RFC 10/10] commands: add ubiformat Wolfram Sang
9 siblings, 1 reply; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Based on mtd-utils and stripped down to needed functionality and
reworked to barebox interfaces.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/mtd/libmtd.h | 154 +++++++++++++++++++++
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/libmtd.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 529 insertions(+)
create mode 100644 include/mtd/libmtd.h
create mode 100644 lib/libmtd.c
diff --git a/include/mtd/libmtd.h b/include/mtd/libmtd.h
new file mode 100644
index 0000000..6267dac
--- /dev/null
+++ b/include/mtd/libmtd.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008, 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#ifndef __LIBMTD_H__
+#define __LIBMTD_H__
+
+/* Maximum MTD device name length */
+#define MTD_NAME_MAX 127
+/* Maximum MTD device type string length */
+#define MTD_TYPE_MAX 64
+
+/**
+ * struct mtd_dev_info - information about an MTD device.
+ * @node: node pointing to device
+ * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
+ * @type_str: static R/O flash type string
+ * @name: device name
+ * @size: device size in bytes
+ * @eb_cnt: count of eraseblocks
+ * @eb_size: eraseblock size
+ * @min_io_size: minimum input/output unit size
+ * @subpage_size: sub-page size
+ * @oob_size: OOB size (zero if the device does not have OOB area)
+ * @region_cnt: count of additional erase regions
+ * @writable: zero if the device is read-only
+ * @bb_allowed: non-zero if the MTD device may have bad eraseblocks
+ */
+struct mtd_dev_info
+{
+ const char *node;
+ int type;
+ const char type_str[MTD_TYPE_MAX + 1];
+ long long size;
+ int eb_cnt;
+ int eb_size;
+ int min_io_size;
+ int subpage_size;
+ int oob_size;
+ int region_cnt;
+ unsigned int writable:1;
+ unsigned int bb_allowed:1;
+};
+
+/**
+ * mtd_get_dev_info - get information about an MTD device.
+ * @desc: MTD library descriptor
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function gets information about MTD device defined by the @node device
+ * node file and saves this information in the @mtd object. Returns %0 in case
+ * of success and %-1 in case of failure. If MTD subsystem is not present in the
+ * system, or the MTD device does not exist, errno is set to @ENODEV.
+ */
+int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd);
+
+/**
+ * mtd_erase - erase an eraseblock.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to erase
+ *
+ * This function erases eraseblock @eb of MTD device described by @fd. Returns
+ * %0 in case of success and %-1 in case of failure.
+ */
+int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_torture - torture an eraseblock.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to torture
+ *
+ * This function tortures eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_is_bad - check if eraseblock is bad.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to check
+ *
+ * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
+ * and %-1 in case of failure.
+ */
+int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_mark_bad - mark an eraseblock as bad.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to mark as bad
+ *
+ * This function marks eraseblock @eb as bad. Returns %0 in case of success and
+ * %-1 in case of failure.
+ */
+int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_read - read data from an MTD device.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to read from
+ * @offs: offset withing the eraseblock to read from
+ * @buf: buffer to read data to
+ * @len: how many bytes to read
+ *
+ * This function reads @len bytes of data from eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd and stores the read data at buffer @buf.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+ void *buf, int len);
+
+/**
+ * mtd_write - write data to an MTD device.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to write to
+ * @offs: offset withing the eraseblock to write to
+ * @buf: buffer to write
+ * @len: how many bytes to write
+ *
+ * This function writes @len bytes of data to eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
+ * case of failure.
+ */
+int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+ void *buf, int len);
+
+#endif /* __LIBMTD_H__ */
diff --git a/lib/Kconfig b/lib/Kconfig
index e6727b3..db5a091 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -47,6 +47,9 @@ config LIBSCAN
config LIBUBIGEN
bool
+config LIBMTD
+ bool
+
source lib/gui/Kconfig
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index e996a48..3ebb5d9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -37,4 +37,5 @@ obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_UBIUTILS) += ubiutils-common.o
obj-$(CONFIG_LIBSCAN) += libscan.o
obj-$(CONFIG_LIBUBIGEN) += libubigen.o
+obj-$(CONFIG_LIBMTD) += libmtd.o
obj-y += gui/
diff --git a/lib/libmtd.c b/lib/libmtd.c
new file mode 100644
index 0000000..78b5c8a
--- /dev/null
+++ b/lib/libmtd.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix e.K. <w.sang@pengutronix.de>
+ *
+ * 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: Artem Bityutskiy
+ * Author: Wolfram Sang
+ *
+ * This file is part of the MTD library. Based on pre-2.6.30 kernels support,
+ * now adapted to barebox.
+ *
+ * NOTE: No support for 64 bit sizes yet!
+ */
+
+#include <common.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <crc.h>
+#include <fs.h>
+#include <fcntl.h>
+#include <ioctl.h>
+#include <linux/stat.h>
+#include <linux/mtd/mtd-abi.h>
+#include <mtd/libmtd.h>
+#include <mtd/utils.h>
+
+#define PROGRAM_NAME "libmtd"
+
+static inline int mtd_ioctl_error(const struct mtd_dev_info *mtd, int eb,
+ const char *sreq)
+{
+ return sys_errmsg("%s ioctl failed for eraseblock %d (%s)",
+ sreq, eb, mtd->node);
+}
+
+static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb)
+{
+ if (eb < 0 || eb >= mtd->eb_cnt) {
+ errmsg("bad eraseblock number %d, %s has %d eraseblocks",
+ eb, mtd->node, mtd->eb_cnt);
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+ int ret;
+ struct erase_info_user ei;
+
+ ret = mtd_valid_erase_block(mtd, eb);
+ if (ret)
+ return ret;
+
+ ei.start = (__u64)eb * mtd->eb_size;
+ ei.length = mtd->eb_size;
+
+ ret = ioctl(fd, MEMERASE, &ei);
+ if (ret < 0)
+ return mtd_ioctl_error(mtd, eb, "MEMERASE");
+ return 0;
+}
+
+/* Patterns to write to a physical eraseblock when torturing it */
+static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+
+/**
+ * check_pattern - check if buffer contains only a certain byte pattern.
+ * @buf: buffer to check
+ * @patt: the pattern to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %1 in there are only @patt bytes in @buf, and %0 if
+ * something else was also found.
+ */
+static int check_pattern(const void *buf, uint8_t patt, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (((const uint8_t *)buf)[i] != patt)
+ return 0;
+ return 1;
+}
+
+int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+ int err, i, patt_count;
+ void *buf;
+
+ normsg("run torture test for PEB %d", eb);
+ patt_count = ARRAY_SIZE(patterns);
+
+ buf = xmalloc(mtd->eb_size);
+
+ for (i = 0; i < patt_count; i++) {
+ err = mtd_erase(mtd, fd, eb);
+ if (err)
+ goto out;
+
+ /* Make sure the PEB contains only 0xFF bytes */
+ err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+ if (err)
+ goto out;
+
+ err = check_pattern(buf, 0xFF, mtd->eb_size);
+ if (err == 0) {
+ errmsg("erased PEB %d, but a non-0xFF byte found", eb);
+ errno = EIO;
+ goto out;
+ }
+
+ /* Write a pattern and check it */
+ memset(buf, patterns[i], mtd->eb_size);
+ err = mtd_write(mtd, fd, eb, 0, buf, mtd->eb_size);
+ if (err)
+ goto out;
+
+ memset(buf, ~patterns[i], mtd->eb_size);
+ err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+ if (err)
+ goto out;
+
+ err = check_pattern(buf, patterns[i], mtd->eb_size);
+ if (err == 0) {
+ errmsg("pattern %x checking failed for PEB %d",
+ patterns[i], eb);
+ errno = EIO;
+ goto out;
+ }
+ }
+
+ err = 0;
+ normsg("PEB %d passed torture test, do not mark it a bad", eb);
+
+out:
+ free(buf);
+ return -1;
+}
+
+int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+ int ret;
+ loff_t seek;
+
+ ret = mtd_valid_erase_block(mtd, eb);
+ if (ret)
+ return ret;
+
+ if (!mtd->bb_allowed)
+ return 0;
+
+ seek = (loff_t)eb * mtd->eb_size;
+ ret = ioctl(fd, MEMGETBADBLOCK, &seek);
+ if (ret == -1)
+ return mtd_ioctl_error(mtd, eb, "MEMGETBADBLOCK");
+ return ret;
+}
+
+int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+ int ret;
+ loff_t seek;
+
+ if (!mtd->bb_allowed) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = mtd_valid_erase_block(mtd, eb);
+ if (ret)
+ return ret;
+
+ seek = (loff_t)eb * mtd->eb_size;
+ ret = ioctl(fd, MEMSETBADBLOCK, &seek);
+ if (ret == -1)
+ return mtd_ioctl_error(mtd, eb, "MEMSETBADBLOCK");
+ return 0;
+}
+
+int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+ void *buf, int len)
+{
+ int ret, rd = 0;
+ off_t seek;
+
+ ret = mtd_valid_erase_block(mtd, eb);
+ if (ret)
+ return ret;
+
+ if (offs < 0 || offs + len > mtd->eb_size) {
+ errmsg("bad offset %d or length %d, %s eraseblock size is %d",
+ offs, len, mtd->node, mtd->eb_size);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Seek to the beginning of the eraseblock */
+ seek = (off_t)eb * mtd->eb_size + offs;
+ if (lseek(fd, seek, SEEK_SET) != seek)
+ return sys_errmsg("cannot seek %s to offset %llu",
+ mtd->node, (unsigned long long)seek);
+
+ while (rd < len) {
+ ret = read(fd, buf, len);
+ if (ret < 0)
+ return sys_errmsg("cannot read %d bytes from %s (eraseblock %d, offset %d)",
+ len, mtd->node, eb, offs);
+ rd += ret;
+ }
+
+ return 0;
+}
+
+int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+ void *buf, int len)
+{
+ int ret;
+ off_t seek;
+
+ ret = mtd_valid_erase_block(mtd, eb);
+ if (ret)
+ return ret;
+
+ if (offs < 0 || offs + len > mtd->eb_size) {
+ errmsg("bad offset %d or length %d, %s eraseblock size is %d",
+ offs, len, mtd->node, mtd->eb_size);
+ errno = EINVAL;
+ return -1;
+ }
+ if (offs % mtd->subpage_size) {
+ errmsg("write offset %d is not aligned to %s min. I/O size %d",
+ offs, mtd->node, mtd->subpage_size);
+ errno = EINVAL;
+ return -1;
+ }
+ if (len % mtd->subpage_size) {
+ errmsg("write length %d is not aligned to %s min. I/O size %d",
+ len, mtd->node, mtd->subpage_size);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Seek to the beginning of the eraseblock */
+ seek = (off_t)eb * mtd->eb_size + offs;
+ if (lseek(fd, seek, SEEK_SET) != seek)
+ return sys_errmsg("cannot seek %s to offset %llu",
+ mtd->node, (unsigned long long)seek);
+
+ ret = write(fd, buf, len);
+ if (ret != len)
+ return sys_errmsg("cannot write %d bytes to %s (eraseblock %d, offset %d)",
+ len, mtd->node, eb, offs);
+
+ return 0;
+}
+
+/**
+ * mtd_get_dev_info - fill the mtd_dev_info structure
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ */
+int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd)
+{
+ struct mtd_info_user ui;
+ int fd, ret;
+ loff_t offs = 0;
+
+ memset(mtd, '\0', sizeof(struct mtd_dev_info));
+
+ mtd->node = node;
+
+ fd = open(node, O_RDWR);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", node);
+
+ if (ioctl(fd, MEMGETINFO, &ui)) {
+ sys_errmsg("MEMGETINFO ioctl request failed");
+ goto out_close;
+ }
+
+ ret = ioctl(fd, MEMGETBADBLOCK, &offs);
+ if (ret == -1) {
+ if (errno != EOPNOTSUPP) {
+ sys_errmsg("MEMGETBADBLOCK ioctl failed");
+ goto out_close;
+ }
+ errno = 0;
+ mtd->bb_allowed = 0;
+ } else
+ mtd->bb_allowed = 1;
+
+ mtd->type = ui.type;
+ mtd->size = ui.size;
+ mtd->eb_size = ui.erasesize;
+ mtd->min_io_size = ui.writesize;
+ mtd->oob_size = ui.oobsize;
+
+ if (mtd->min_io_size <= 0) {
+ errmsg("%s has insane min. I/O unit size %d",
+ node, mtd->min_io_size);
+ goto out_close;
+ }
+ if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
+ errmsg("%s has insane eraseblock size %d",
+ node, mtd->eb_size);
+ goto out_close;
+ }
+ if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
+ errmsg("%s has insane size %lld",
+ node, mtd->size);
+ goto out_close;
+ }
+
+ mtd->eb_cnt = ui.size / ui.erasesize;
+
+ switch(mtd->type) {
+ case MTD_ABSENT:
+ errmsg("%s (%s) is removable and is not present",
+ mtd->node, node);
+ goto out_close;
+ case MTD_RAM:
+ strcpy((char *)mtd->type_str, "ram");
+ break;
+ case MTD_ROM:
+ strcpy((char *)mtd->type_str, "rom");
+ break;
+ case MTD_NORFLASH:
+ strcpy((char *)mtd->type_str, "nor");
+ break;
+ case MTD_NANDFLASH:
+ strcpy((char *)mtd->type_str, "nand");
+ break;
+ case MTD_DATAFLASH:
+ strcpy((char *)mtd->type_str, "dataflash");
+ break;
+ case MTD_UBIVOLUME:
+ strcpy((char *)mtd->type_str, "ubi");
+ break;
+ default:
+ goto out_close;
+ }
+
+ if (ui.flags & MTD_WRITEABLE)
+ mtd->writable = 1;
+ mtd->subpage_size = mtd->min_io_size;
+
+ close(fd);
+
+ return 0;
+
+out_close:
+ close(fd);
+ return -1;
+}
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC 10/10] commands: add ubiformat
2012-10-26 10:16 [RFC 00/10] ubiformat in barebox Wolfram Sang
` (8 preceding siblings ...)
2012-10-26 10:16 ` [RFC 09/10] lib: add barebox version of libmtd Wolfram Sang
@ 2012-10-26 10:16 ` Wolfram Sang
2012-10-27 12:57 ` Sascha Hauer
9 siblings, 1 reply; 17+ messages in thread
From: Wolfram Sang @ 2012-10-26 10:16 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Imported from mtd-utils and stripped down to needed functionality.
Based on an older version (1.4.5.) since the newer do use MEMWRITE
interfaces which we don't have in barebox (yet).
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
commands/Kconfig | 9 +
commands/Makefile | 1 +
commands/ubiformat.c | 795 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 805 insertions(+)
create mode 100644 commands/ubiformat.c
diff --git a/commands/Kconfig b/commands/Kconfig
index e934f29..3aedd21 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -341,6 +341,15 @@ config CMD_UBI
depends on UBI
prompt "ubimkvol, ubirmvol, ubiattach"
+config CMD_UBIFORMAT
+ tristate
+ depends on UBI
+ select LIBMTD
+ select LIBSCAN
+ select LIBUBIGEN
+ select UBIUTILS
+ prompt "ubiformat"
+
endmenu
diff --git a/commands/Makefile b/commands/Makefile
index 610be55..25d51b7 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_CMD_GPIO) += gpio.o
obj-$(CONFIG_CMD_UNCOMPRESS) += uncompress.o
obj-$(CONFIG_CMD_I2C) += i2c.o
obj-$(CONFIG_CMD_UBI) += ubi.o
+obj-$(CONFIG_CMD_UBIFORMAT) += ubiformat.o
obj-$(CONFIG_CMD_MENU) += menu.o
obj-$(CONFIG_CMD_PASSWD) += passwd.o
obj-$(CONFIG_CMD_LOGIN) += login.o
diff --git a/commands/ubiformat.c b/commands/ubiformat.c
new file mode 100644
index 0000000..20e4a2a
--- /dev/null
+++ b/commands/ubiformat.c
@@ -0,0 +1,795 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to format MTD devices into UBI and flash UBI images.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+/*
+ * Maximum amount of consequtive eraseblocks which are considered as normal by
+ * this utility. Otherwise it is assume that something is wrong with the flash
+ * or the driver, and eraseblocks are stopped being marked as bad.
+ */
+#define MAX_CONSECUTIVE_BAD_BLOCKS 4
+
+#define PROGRAM_VERSION "1.5"
+#define PROGRAM_NAME "ubiformat"
+
+#include <common.h>
+#include <command.h>
+#include <fs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <getopt.h>
+#include <crc.h>
+#include <stdlib.h>
+#include <clock.h>
+#include <malloc.h>
+#include <ioctl.h>
+#include <linux/mtd/mtd.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/mtd/mtd-abi.h>
+#include <mtd/libmtd.h>
+#include <mtd/libscan.h>
+#include <mtd/libubigen.h>
+#include <mtd/ubiutils-common.h>
+#include <mtd/ubi-user.h>
+#include <mtd/utils.h>
+#include <mtd/ubi-media.h>
+
+/* The variables below are set by command line arguments */
+struct args {
+ unsigned int quiet:1;
+ unsigned int verbose:1;
+ unsigned int override_ec:1;
+ unsigned int novtbl:1;
+ unsigned int manual_subpage;
+ int subpage_size;
+ int vid_hdr_offs;
+ int ubi_ver;
+ uint32_t image_seq;
+ long long ec;
+ const char *image;
+ const char *node;
+ int node_fd;
+};
+
+static struct args args;
+
+static int parse_opt(int argc, char *argv[])
+{
+ srand(get_time_ns());
+ memset(&args, 0, sizeof(args));
+ args.ubi_ver = 1;
+ args.image_seq = rand();
+
+ while (1) {
+ int key;
+ unsigned long int image_seq;
+
+ key = getopt(argc, argv, "nyqve:x:s:O:f:S:");
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 's':
+ args.subpage_size = ubiutils_get_bytes(optarg);
+ if (args.subpage_size <= 0)
+ return errmsg("bad sub-page size: \"%s\"", optarg);
+ if (!is_power_of_2(args.subpage_size))
+ return errmsg("sub-page size should be power of 2");
+ break;
+
+ case 'O':
+ args.vid_hdr_offs = simple_strtoul(optarg, NULL, 0);
+ if (args.vid_hdr_offs <= 0)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+ break;
+
+ case 'e':
+ args.ec = simple_strtoull(optarg, NULL, 0);
+ if (args.ec < 0)
+ return errmsg("bad erase counter value: \"%s\"", optarg);
+ if (args.ec >= EC_MAX)
+ return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX);
+ args.override_ec = 1;
+ break;
+
+ case 'f':
+ args.image = optarg;
+ break;
+
+ case 'n':
+ args.novtbl = 1;
+ break;
+
+
+ case 'q':
+ args.quiet = 1;
+ break;
+
+ case 'x':
+ args.ubi_ver = simple_strtoul(optarg, NULL, 0);
+ if (args.ubi_ver < 0)
+ return errmsg("bad UBI version: \"%s\"", optarg);
+ break;
+
+ case 'Q':
+ image_seq = simple_strtoul(optarg, NULL, 0);
+ if (image_seq > 0xFFFFFFFF)
+ return errmsg("bad UBI image sequence number: \"%s\"", optarg);
+ args.image_seq = image_seq;
+ break;
+
+
+ case 'v':
+ args.verbose = 1;
+ break;
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (args.quiet && args.verbose)
+ return errmsg("using \"-q\" and \"-v\" at the same time does not make sense");
+
+ if (optind == argc)
+ return errmsg("MTD device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one MTD device specified (use -h for help)");
+
+ if (args.image && args.novtbl)
+ return errmsg("-n cannot be used together with -f");
+
+
+ args.node = argv[optind];
+ return 0;
+}
+
+static void print_bad_eraseblocks(const struct mtd_dev_info *mtd,
+ const struct ubi_scan_info *si)
+{
+ int first = 1, eb;
+
+ if (si->bad_cnt == 0)
+ return;
+
+ normsg_cont("%d bad eraseblocks found, numbers: ", si->bad_cnt);
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ if (si->ec[eb] != EB_BAD)
+ continue;
+ if (first) {
+ printf("%d", eb);
+ first = 0;
+ } else
+ printf(", %d", eb);
+ }
+ printf("\n");
+}
+
+static int change_ech(struct ubi_ec_hdr *hdr, uint32_t image_seq,
+ long long ec)
+{
+ uint32_t crc;
+
+ /* Check the EC header */
+ if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC)
+ return errmsg("bad UBI magic %#08x, should be %#08x",
+ be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC);
+
+ crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ if (be32_to_cpu(hdr->hdr_crc) != crc)
+ return errmsg("bad CRC %#08x, should be %#08x\n",
+ crc, be32_to_cpu(hdr->hdr_crc));
+
+ hdr->image_seq = cpu_to_be32(image_seq);
+ hdr->ec = cpu_to_be64(ec);
+ crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
+
+ return 0;
+}
+
+static int drop_ffs(const struct mtd_dev_info *mtd, const void *buf, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--)
+ if (((const uint8_t *)buf)[i] != 0xFF)
+ break;
+
+ /* The resulting length must be aligned to the minimum flash I/O size */
+ len = i + 1;
+ len = (len + mtd->min_io_size - 1) / mtd->min_io_size;
+ len *= mtd->min_io_size;
+ return len;
+}
+
+static int open_file(off_t *sz)
+{
+ int fd;
+ struct stat st;
+
+ if (stat(args.image, &st))
+ return sys_errmsg("cannot open \"%s\"", args.image);
+
+ *sz = st.st_size;
+ fd = open(args.image, O_RDONLY);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", args.image);
+
+ return fd;
+}
+
+static int read_all(int fd, void *buf, size_t len)
+{
+ while (len > 0) {
+ ssize_t l = read(fd, buf, len);
+ if (l == 0)
+ return errmsg("eof reached; %zu bytes remaining", len);
+ else if (l > 0) {
+ buf += l;
+ len -= l;
+ } else if (errno == EINTR || errno == EAGAIN)
+ continue;
+ else
+ return sys_errmsg("reading failed; %zu bytes remaining", len);
+ }
+
+ return 0;
+}
+
+/*
+ * Returns %-1 if consecutive bad blocks exceeds the
+ * MAX_CONSECUTIVE_BAD_BLOCKS and returns %0 otherwise.
+ */
+static int consecutive_bad_check(int eb)
+{
+ static int consecutive_bad_blocks = 1;
+ static int prev_bb = -1;
+
+ if (prev_bb == -1)
+ prev_bb = eb;
+
+ if (eb == prev_bb + 1)
+ consecutive_bad_blocks += 1;
+ else
+ consecutive_bad_blocks = 1;
+
+ prev_bb = eb;
+
+ if (consecutive_bad_blocks >= MAX_CONSECUTIVE_BAD_BLOCKS) {
+ if (!args.quiet)
+ printf("\n");
+ return errmsg("consecutive bad blocks exceed limit: %d, bad flash?",
+ MAX_CONSECUTIVE_BAD_BLOCKS);
+ }
+
+ return 0;
+}
+
+/* TODO: we should actually torture the PEB before marking it as bad */
+static int mark_bad(const struct mtd_dev_info *mtd, struct ubi_scan_info *si, int eb)
+{
+ int err;
+
+ if (!args.quiet)
+ normsg_cont("marking block %d bad", eb);
+
+ if (!args.quiet)
+ printf("\n");
+
+ if (!mtd->bb_allowed) {
+ if (!args.quiet)
+ printf("\n");
+ return errmsg("bad blocks not supported by this flash");
+ }
+
+ err = mtd_mark_bad(mtd, args.node_fd, eb);
+ if (err)
+ return err;
+
+ si->bad_cnt += 1;
+ si->ec[eb] = EB_BAD;
+
+ return consecutive_bad_check(eb);
+}
+
+static int flash_image(const struct mtd_dev_info *mtd,
+ const struct ubigen_info *ui, struct ubi_scan_info *si)
+{
+ int fd, img_ebs, eb, written_ebs = 0, divisor;
+ off_t st_size;
+
+ fd = open_file(&st_size);
+ if (fd < 0)
+ return fd;
+
+ img_ebs = st_size / mtd->eb_size;
+
+ if (img_ebs > si->good_cnt) {
+ sys_errmsg("file \"%s\" is too large (%lld bytes)",
+ args.image, (long long)st_size);
+ goto out_close;
+ }
+
+ if (st_size % mtd->eb_size) {
+ return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of ""eraseblock size (%d bytes)",
+ args.image, (long long)st_size, mtd->eb_size);
+ goto out_close;
+ }
+
+ verbose(args.verbose, "will write %d eraseblocks", img_ebs);
+ divisor = img_ebs;
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ int err, new_len;
+ char buf[mtd->eb_size];
+ long long ec;
+
+ if (!args.quiet && !args.verbose) {
+ printf("\r" PROGRAM_NAME ": flashing eraseblock %d -- %2u %% complete ",
+ eb, (eb + 1) * 100 / mtd->eb_cnt);
+ }
+
+ if (si->ec[eb] == EB_BAD) {
+ divisor += 1;
+ continue;
+ }
+
+ if (args.verbose) {
+ normsg_cont("eraseblock %d: erase", eb);
+ }
+
+ err = mtd_erase(mtd, args.node_fd, eb);
+ if (err) {
+ if (!args.quiet)
+ printf("\n");
+ sys_errmsg("failed to erase eraseblock %d", eb);
+
+ if (errno != EIO)
+ goto out_close;
+
+ if (mark_bad(mtd, si, eb))
+ goto out_close;
+
+ continue;
+ }
+
+ err = read_all(fd, buf, mtd->eb_size);
+ if (err) {
+ sys_errmsg("failed to read eraseblock %d from \"%s\"",
+ written_ebs, args.image);
+ goto out_close;
+ }
+
+ if (args.override_ec)
+ ec = args.ec;
+ else if (si->ec[eb] <= EC_MAX)
+ ec = si->ec[eb] + 1;
+ else
+ ec = si->mean_ec;
+
+ if (args.verbose) {
+ printf(", change EC to %lld", ec);
+ }
+
+ err = change_ech((struct ubi_ec_hdr *)buf, ui->image_seq, ec);
+ if (err) {
+ errmsg("bad EC header at eraseblock %d of \"%s\"",
+ written_ebs, args.image);
+ goto out_close;
+ }
+
+ if (args.verbose) {
+ printf(", write data\n");
+ }
+
+ new_len = drop_ffs(mtd, buf, mtd->eb_size);
+
+ err = mtd_write(mtd, args.node_fd, eb, 0, buf, new_len);
+ if (err) {
+ sys_errmsg("cannot write eraseblock %d", eb);
+
+ if (errno != EIO)
+ goto out_close;
+
+ err = mtd_torture(mtd, args.node_fd, eb);
+ if (err) {
+ if (mark_bad(mtd, si, eb))
+ goto out_close;
+ }
+ continue;
+ }
+ if (++written_ebs >= img_ebs)
+ break;
+ }
+
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+ close(fd);
+ return eb + 1;
+
+out_close:
+ close(fd);
+ return -1;
+}
+
+static int format(const struct mtd_dev_info *mtd,
+ const struct ubigen_info *ui, struct ubi_scan_info *si,
+ int start_eb, int novtbl)
+{
+ int eb, err, write_size;
+ struct ubi_ec_hdr *hdr;
+ struct ubi_vtbl_record *vtbl;
+ int eb1 = -1, eb2 = -1;
+ long long ec1 = -1, ec2 = -1;
+
+ write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1;
+ write_size /= mtd->subpage_size;
+ write_size *= mtd->subpage_size;
+ hdr = malloc(write_size);
+ if (!hdr)
+ return sys_errmsg("cannot allocate %d bytes of memory", write_size);
+ memset(hdr, 0xFF, write_size);
+
+ for (eb = start_eb; eb < mtd->eb_cnt; eb++) {
+ long long ec;
+
+ if (!args.quiet && !args.verbose) {
+ printf("\r" PROGRAM_NAME ": formatting eraseblock %d -- %2u %% complete ",
+ eb, (eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb));
+ }
+
+ if (si->ec[eb] == EB_BAD)
+ continue;
+
+ if (args.override_ec)
+ ec = args.ec;
+ else if (si->ec[eb] <= EC_MAX)
+ ec = si->ec[eb] + 1;
+ else
+ ec = si->mean_ec;
+ ubigen_init_ec_hdr(ui, hdr, ec);
+
+ if (args.verbose) {
+ normsg_cont("eraseblock %d: erase", eb);
+ }
+
+ err = mtd_erase(mtd, args.node_fd, eb);
+ if (err) {
+ if (!args.quiet)
+ printf("\n");
+
+ sys_errmsg("failed to erase eraseblock %d", eb);
+ if (errno != EIO)
+ goto out_free;
+
+ if (mark_bad(mtd, si, eb))
+ goto out_free;
+ continue;
+ }
+
+ if ((eb1 == -1 || eb2 == -1) && !novtbl) {
+ if (eb1 == -1) {
+ eb1 = eb;
+ ec1 = ec;
+ } else if (eb2 == -1) {
+ eb2 = eb;
+ ec2 = ec;
+ }
+ if (args.verbose)
+ printf(", do not write EC, leave for vtbl\n");
+ continue;
+ }
+
+ if (args.verbose) {
+ printf(", write EC %lld\n", ec);
+ }
+
+ err = mtd_write(mtd, args.node_fd, eb, 0, hdr, write_size);
+ if (err) {
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+ sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d",
+ write_size, eb);
+
+ if (errno != EIO) {
+ if (!args.subpage_size != mtd->min_io_size)
+ normsg("may be sub-page size is "
+ "incorrect?");
+ goto out_free;
+ }
+
+ err = mtd_torture(mtd, args.node_fd, eb);
+ if (err) {
+ if (mark_bad(mtd, si, eb))
+ goto out_free;
+ }
+ continue;
+
+ }
+ }
+
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+
+ if (!novtbl) {
+ if (eb1 == -1 || eb2 == -1) {
+ errmsg("no eraseblocks for volume table");
+ goto out_free;
+ }
+
+ verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2);
+ vtbl = ubigen_create_empty_vtbl(ui);
+ if (!vtbl)
+ goto out_free;
+
+ err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl,
+ args.node_fd);
+ free(vtbl);
+ if (err) {
+ errmsg("cannot write layout volume");
+ goto out_free;
+ }
+ }
+
+ free(hdr);
+ return 0;
+
+out_free:
+ free(hdr);
+ return -1;
+}
+
+int do_ubiformat(int argc, char *argv[])
+{
+ int err, verbose;
+ struct mtd_dev_info mtd;
+ struct ubigen_info ui;
+ struct ubi_scan_info *si;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ goto out_close_mtd;
+
+ err = mtd_get_dev_info(args.node, &mtd);
+ if (err) {
+ sys_errmsg("cannot get information about \"%s\"", args.node);
+ goto out_close_mtd;
+ }
+
+ if (!is_power_of_2(mtd.min_io_size)) {
+ errmsg("min. I/O size is %d, but should be power of 2",
+ mtd.min_io_size);
+ goto out_close;
+ }
+
+ if (args.subpage_size && args.subpage_size != mtd.subpage_size) {
+ mtd.subpage_size = args.subpage_size;
+ args.manual_subpage = 1;
+ }
+
+ if (args.manual_subpage) {
+ /* Do some sanity check */
+ if (args.subpage_size > mtd.min_io_size) {
+ errmsg("sub-page cannot be larger than min. I/O unit");
+ goto out_close;
+ }
+
+ if (mtd.min_io_size % args.subpage_size) {
+ errmsg("min. I/O unit size should be multiple of "
+ "sub-page size");
+ goto out_close;
+ }
+ }
+
+ args.node_fd = open(args.node, O_RDWR);
+ if (args.node_fd == -1) {
+ sys_errmsg("cannot open \"%s\"", args.node);
+ goto out_close_mtd;
+ }
+
+ /* Validate VID header offset if it was specified */
+ if (args.vid_hdr_offs != 0) {
+ if (args.vid_hdr_offs % 8) {
+ errmsg("VID header offset has to be multiple of min. I/O unit size");
+ goto out_close;
+ }
+ if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd.eb_size) {
+ errmsg("bad VID header offset");
+ goto out_close;
+ }
+ }
+
+ if (!mtd.writable) {
+ errmsg("%s (%s) is a read-only device", mtd.node, args.node);
+ goto out_close;
+ }
+
+ /* Make sure this MTD device is not attached to UBI */
+ /* FIXME! Find a proper way to do this in barebox! */
+
+ if (!args.quiet) {
+ normsg_cont("%s (%s), size ", mtd.node, mtd.type_str);
+ ubiutils_print_bytes(mtd.size, 1);
+ printf(", %d eraseblocks of ", mtd.eb_cnt);
+ ubiutils_print_bytes(mtd.eb_size, 1);
+ printf(", min. I/O size %d bytes\n", mtd.min_io_size);
+ }
+
+ if (args.quiet)
+ verbose = 0;
+ else if (args.verbose)
+ verbose = 2;
+ else
+ verbose = 1;
+ err = libscan_ubi_scan(&mtd, args.node_fd, &si, verbose);
+ if (err) {
+ errmsg("failed to scan %s (%s)", mtd.node, args.node);
+ goto out_close;
+ }
+
+ if (si->good_cnt == 0) {
+ errmsg("all %d eraseblocks are bad", si->bad_cnt);
+ goto out_free;
+ }
+
+ if (si->good_cnt < 2 && (!args.novtbl || args.image)) {
+ errmsg("too few non-bad eraseblocks (%d) on %s",
+ si->good_cnt, mtd.node);
+ goto out_free;
+ }
+
+ if (!args.quiet) {
+ if (si->ok_cnt)
+ normsg("%d eraseblocks have valid erase counter, mean value is %lld",
+ si->ok_cnt, si->mean_ec);
+ if (si->empty_cnt)
+ normsg("%d eraseblocks are supposedly empty", si->empty_cnt);
+ if (si->corrupted_cnt)
+ normsg("%d corrupted erase counters", si->corrupted_cnt);
+ print_bad_eraseblocks(&mtd, si);
+ }
+
+ if (si->alien_cnt) {
+ if (!args.quiet)
+ warnmsg("%d of %d eraseblocks contain non-ubifs data",
+ si->alien_cnt, si->good_cnt);
+ goto out_free;
+ }
+
+ if (!args.override_ec && si->empty_cnt < si->good_cnt) {
+ int percent = (si->ok_cnt * 100) / si->good_cnt;
+
+ /*
+ * Make sure the majority of eraseblocks have valid
+ * erase counters.
+ */
+ if (percent < 50) {
+ if (!args.quiet) {
+ warnmsg("only %d of %d eraseblocks have valid erase counter",
+ si->ok_cnt, si->good_cnt);
+ normsg("erase counter 0 will be used for all eraseblocks");
+ normsg("note, arbitrary erase counter value may be specified using -e option");
+ }
+ args.ec = 0;
+ args.override_ec = 1;
+ } else if (percent < 95) {
+ if (!args.quiet) {
+ warnmsg("only %d of %d eraseblocks have valid erase counter",
+ si->ok_cnt, si->good_cnt);
+ normsg("mean erase counter %lld will be used for the rest of eraseblock",
+ si->mean_ec);
+ }
+ args.ec = si->mean_ec;
+ args.override_ec = 1;
+ }
+ }
+
+ if (!args.quiet && args.override_ec)
+ normsg("use erase counter %lld for all eraseblocks", args.ec);
+
+ ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, mtd.subpage_size,
+ args.vid_hdr_offs, args.ubi_ver, args.image_seq);
+
+ if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
+ /*
+ * Hmm, what we read from flash and what we calculated using
+ * min. I/O unit size and sub-page size differs.
+ */
+ if (!args.quiet)
+ warnmsg("VID header and data offsets on flash are %d and %d, "
+ "which is different to requested offsets %d and %d",
+ si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs,
+ ui.data_offs);
+ normsg("use offsets %d and %d", ui.vid_hdr_offs, ui.data_offs);
+ }
+
+ if (args.image) {
+ err = flash_image(&mtd, &ui, si);
+ if (err < 0)
+ goto out_free;
+
+ err = format(&mtd, &ui, si, err, 1);
+ if (err)
+ goto out_free;
+ } else {
+ err = format(&mtd, &ui, si, 0, args.novtbl);
+ if (err)
+ goto out_free;
+ }
+
+ libscan_ubi_scan_free(si);
+ close(args.node_fd);
+ return 0;
+
+out_free:
+ libscan_ubi_scan_free(si);
+out_close:
+ close(args.node_fd);
+out_close_mtd:
+ return -1;
+}
+
+static const __maybe_unused char cmd_ubiformat_help[] =
+" - a tool to format MTD devices and flash UBI images\n"
+"\n"
+"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n"
+" headers, e.g. sub-page size in case of NAND\n"
+" flash (equivalent to the minimum input/output\n"
+" unit size by default)\n"
+"-O, --vid-hdr-offset=<offs> offset if the VID header from start of the\n"
+" physical eraseblock (default is the next\n"
+" minimum I/O unit or sub-page after the EC\n"
+" header)\n"
+"-n, --no-volume-table only erase all eraseblock and preserve erase\n"
+" counters, do not write empty volume table\n"
+"-f, --flash-image=<file> flash image file\n"
+"-e, --erase-counter=<value> use <value> as the erase counter value for all\n"
+" eraseblocks\n"
+"-x, --ubi-ver=<num> UBI version number to put to EC headers\n"
+" (default is 1)\n"
+"-Q, --image-seq=<num> 32-bit UBI image sequence number to use\n"
+" (by default a random number is picked)\n"
+"-q, --quiet suppress progress percentage information\n"
+"-v, --verbose be verbose\n"
+"-h, -?, --help print help message\n"
+"\n"
+"Usage: " PROGRAM_NAME " <MTD device node file name> [-s <bytes>] [-O <offs>] [-n]\n"
+"\t\t\t[-f <file>] [-e <value>] [-x <num>] [-y] [-q] [-v] [-h] [-v]\n"
+"\t\t\t[--sub-page-size=<bytes>] [--vid-hdr-offset=<offs>] [--no-volume-table]\n"
+"\t\t\t[--flash-image=<file>] [--image-size=<bytes>] [--erase-counter=<value>]\n"
+"\t\t\t[--ubi-ver=<num>] [--quiet] [--verbose]\n\n"
+"Example 1: " PROGRAM_NAME " /dev/mtd0 -y - format MTD device number 0 and do\n"
+" not ask questions.\n"
+"Example 2: " PROGRAM_NAME " /dev/mtd0 -q -e 0 - format MTD device number 0,\n"
+" be quiet and force erase counter value 0.\n";
+
+BAREBOX_CMD_START(ubiformat)
+ .cmd = do_ubiformat,
+ .usage = "format an ubi volume",
+ BAREBOX_CMD_HELP(cmd_ubiformat_help)
+BAREBOX_CMD_END
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC 10/10] commands: add ubiformat
2012-10-26 10:16 ` [RFC 10/10] commands: add ubiformat Wolfram Sang
@ 2012-10-27 12:57 ` Sascha Hauer
2012-12-09 19:40 ` Wolfram Sang
0 siblings, 1 reply; 17+ messages in thread
From: Sascha Hauer @ 2012-10-27 12:57 UTC (permalink / raw)
To: Wolfram Sang; +Cc: barebox
On Fri, Oct 26, 2012 at 12:16:42PM +0200, Wolfram Sang wrote:
> Imported from mtd-utils and stripped down to needed functionality.
> Based on an older version (1.4.5.) since the newer do use MEMWRITE
> interfaces which we don't have in barebox (yet).
>
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
> +
> + while (1) {
> + int key;
> + unsigned long int image_seq;
> +
> + key = getopt(argc, argv, "nyqve:x:s:O:f:S:");
> + if (key == -1)
> + break;
> +
> + switch (key) {
> + case 's':
> + args.subpage_size = ubiutils_get_bytes(optarg);
> + if (args.subpage_size <= 0)
> + return errmsg("bad sub-page size: \"%s\"", optarg);
> + if (!is_power_of_2(args.subpage_size))
> + return errmsg("sub-page size should be power of 2");
> + break;
> +
> + case 'O':
> + args.vid_hdr_offs = simple_strtoul(optarg, NULL, 0);
> + if (args.vid_hdr_offs <= 0)
> + return errmsg("bad VID header offset: \"%s\"", optarg);
> + break;
> +
> + case 'e':
> + args.ec = simple_strtoull(optarg, NULL, 0);
> + if (args.ec < 0)
> + return errmsg("bad erase counter value: \"%s\"", optarg);
> + if (args.ec >= EC_MAX)
> + return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX);
> + args.override_ec = 1;
> + break;
> +
> + case 'f':
> + args.image = optarg;
> + break;
> +
> + case 'n':
> + args.novtbl = 1;
> + break;
> +
> +
Please remove one empty line
> + case 'q':
> + args.quiet = 1;
> + break;
> +
> + case 'x':
> + args.ubi_ver = simple_strtoul(optarg, NULL, 0);
> + if (args.ubi_ver < 0)
> + return errmsg("bad UBI version: \"%s\"", optarg);
> + break;
> +
> + case 'Q':
> + image_seq = simple_strtoul(optarg, NULL, 0);
> + if (image_seq > 0xFFFFFFFF)
> + return errmsg("bad UBI image sequence number: \"%s\"", optarg);
> + args.image_seq = image_seq;
> + break;
> +
> +
ditto
> + case 'v':
> + args.verbose = 1;
> + break;
> +
> + case ':':
> + return errmsg("parameter is missing");
> +
> + default:
> + fprintf(stderr, "Use -h for help\n");
> + return -1;
> + }
> + }
> +
> + if (args.quiet && args.verbose)
> + return errmsg("using \"-q\" and \"-v\" at the same time does not make sense");
> +
> + if (optind == argc)
> + return errmsg("MTD device name was not specified (use -h for help)");
> + else if (optind != argc - 1)
> + return errmsg("more then one MTD device specified (use -h for help)");
> +
> + if (args.image && args.novtbl)
> + return errmsg("-n cannot be used together with -f");
> +
> +
> + args.node = argv[optind];
> + return 0;
> +}
> +
[...]
> +
> +static int drop_ffs(const struct mtd_dev_info *mtd, const void *buf, int len)
> +{
> + int i;
> +
> + for (i = len - 1; i >= 0; i--)
> + if (((const uint8_t *)buf)[i] != 0xFF)
> + break;
> +
> + /* The resulting length must be aligned to the minimum flash I/O size */
> + len = i + 1;
Indention broken here.
> + len = (len + mtd->min_io_size - 1) / mtd->min_io_size;
> + len *= mtd->min_io_size;
> + return len;
> +}
> +
> +static int open_file(off_t *sz)
> +{
> + int fd;
> + struct stat st;
> +
> + if (stat(args.image, &st))
> + return sys_errmsg("cannot open \"%s\"", args.image);
> +
> + *sz = st.st_size;
> + fd = open(args.image, O_RDONLY);
Please use O_RDWR so that nobody sees that barebox actually does not
test for it...
> + if (fd == -1)
> + return sys_errmsg("cannot open \"%s\"", args.image);
I'm afraid our open() implementation is not that standard conform. It
returns an error code instead of -1.
> +
> + return fd;
> +}
> +
> +static int read_all(int fd, void *buf, size_t len)
> +{
> + while (len > 0) {
> + ssize_t l = read(fd, buf, len);
> + if (l == 0)
> + return errmsg("eof reached; %zu bytes remaining", len);
> + else if (l > 0) {
> + buf += l;
> + len -= l;
> + } else if (errno == EINTR || errno == EAGAIN)
> + continue;
> + else
> + return sys_errmsg("reading failed; %zu bytes remaining", len);
Please use {} for all branches.
> + }
> +
> + return 0;
> +}
> +
[...]
> +
> + libscan_ubi_scan_free(si);
> + close(args.node_fd);
> + return 0;
> +
> +out_free:
> + libscan_ubi_scan_free(si);
> +out_close:
> + close(args.node_fd);
> +out_close_mtd:
> + return -1;
If you return a negative value barebox assumes it's an error code and
prints the corresponding message. So please either return an error code,
or if you do not want barebox to print an error message return 1 on
failure.
Please try and ubiformat nonexisting files and non mtd devices and see
what happens. I have the feeling these are untested right now.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread