* [PATCH V3 01/11] mtd: drop custom is_power_of_2()
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 02/11] lib: misc: add 'iB' suffixes to strtoull_suffix Wolfram Sang
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
We have proper version in log2.h these days.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/mtd/ubi/ubi-barebox.h | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/mtd/ubi/ubi-barebox.h b/drivers/mtd/ubi/ubi-barebox.h
index 72f29a6..7574607 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 <linux/log2.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
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V3 02/11] lib: misc: add 'iB' suffixes to strtoull_suffix
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 01/11] mtd: drop custom is_power_of_2() Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 03/11] lib: update size_human_readable to latest version Wolfram Sang
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Since this is the 'official' notation, we should support it.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
lib/misc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/misc.c b/lib/misc.c
index 1a08502..0f3eb9a 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -47,8 +47,11 @@ unsigned long long strtoull_suffix(const char *str, char **endp, int base)
break;
}
+ if (strncmp(end, "iB", 2) == 0)
+ end += 2;
+
if (endp)
- *endp = (char *)end;
+ *endp = end;
return val;
}
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V3 03/11] lib: update size_human_readable to latest version
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 01/11] mtd: drop custom is_power_of_2() Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 02/11] lib: misc: add 'iB' suffixes to strtoull_suffix Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 04/11] ubi: consolidate ubi-media.h Wolfram Sang
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 UTC (permalink / raw)
To: barebox; +Cc: Wolfram Sang
Copy over the latest version from u-boot which handles bigger sizes now
and does arithmetic with shifts instead of divisions.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/common.h | 2 +-
lib/display_options.c | 47 +++++++++++++++++++++++++++++++----------------
2 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/include/common.h b/include/common.h
index e30774a..1939427 100644
--- a/include/common.h
+++ b/include/common.h
@@ -105,7 +105,7 @@ void reginfo(void);
void __noreturn hang (void);
void __noreturn panic(const char *fmt, ...);
-char *size_human_readable(ulong size);
+char *size_human_readable(unsigned long long size);
/* common/main.c */
int run_command (const char *cmd, int flag);
diff --git a/lib/display_options.c b/lib/display_options.c
index a6050cb..0871552 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -21,35 +21,50 @@
/*
* return a pointer to a string containing the size
- * as "xxx kB", "xxx.y kB", "xxx MB" or "xxx.y MB" as needed;
+ *"as xxx KiB", "xxx.y KiB", "xxx MiB", "xxx.y MiB",
+ * xxx GiB, xxx.y GiB, etc as needed;
*/
-char *size_human_readable(ulong size)
+char *size_human_readable(unsigned long long size)
{
static char buf[20];
- ulong m, n;
- ulong d = 1 << 20; /* 1 MB */
- char c = 'M';
+ unsigned long m = 0, n;
+ unsigned long long f;
+ static const char names[] = {'E', 'P', 'T', 'G', 'M', 'K'};
+ unsigned long d = 10 * ARRAY_SIZE(names);
+ char c = 0;
+ unsigned int i;
char *ptr = buf;
- if (size < d) { /* print in kB */
- c = 'k';
- d = 1 << 10;
+ for (i = 0; i < ARRAY_SIZE(names); i++, d -= 10) {
+ if (size >> d) {
+ c = names[i];
+ break;
+ }
}
- n = size / d;
+ if (!c) {
+ sprintf(buf, "%llu Bytes", size);
+ return buf;
+ }
+
+ n = size >> d;
+ f = size & ((1ULL << d) - 1);
- m = (10 * (size - (n * d)) + (d / 2) ) / d;
+ /* If there's a remainder, deal with it */
+ if (f) {
+ m = (10ULL * f + (1ULL << (d - 1))) >> d;
- if (m >= 10) {
- m -= 10;
- n += 1;
+ if (m >= 10) {
+ m -= 10;
+ n += 1;
+ }
}
- ptr += sprintf(buf, "%2ld", n);
+ ptr += sprintf(buf, "%lu", n);
if (m) {
- ptr += sprintf (ptr,".%ld", m);
+ ptr += sprintf(ptr, ".%ld", m);
}
- sprintf(ptr, " %cB", c);
+ sprintf(ptr, " %ciB", c);
return buf;
}
--
1.7.10.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V3 04/11] ubi: consolidate ubi-media.h
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (2 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 03/11] lib: update size_human_readable to latest version Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 05/11] ubi: bump ubi-media.h to newest version Wolfram Sang
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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-media.h | 369 ------------------------------------------
drivers/mtd/ubi/ubi.h | 3 +-
include/mtd/ubi-media.h | 369 ++++++++++++++++++++++++++++++++++++++++++
include/ubi-media.h | 370 -------------------------------------------
5 files changed, 372 insertions(+), 741 deletions(-)
delete mode 100644 drivers/mtd/ubi/ubi-media.h
create mode 100644 include/mtd/ubi-media.h
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-media.h b/drivers/mtd/ubi/ubi-media.h
deleted file mode 100644
index cd1bd8e..0000000
--- a/drivers/mtd/ubi/ubi-media.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- *
- * 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__
-
-#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 unit 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 then 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
- * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
- * removed, kept only for not breaking older UBI users)
- * @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
- * @padding1: reserved for future, zeroes
- * @sqnum: sequence number
- * @padding2: 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 then 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.
- *
- * 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
- * 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 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.
- *
- * 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; /* obsolete, to be removed, don't use */
- __be32 data_size;
- __be32 used_ebs;
- __be32 data_pad;
- __be32 data_crc;
- __u8 padding1[4];
- __be64 sqnum;
- __u8 padding2[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 /* !__UBI_MEDIA_H__ */
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/include/mtd/ubi-media.h b/include/mtd/ubi-media.h
new file mode 100644
index 0000000..cd1bd8e
--- /dev/null
+++ b/include/mtd/ubi-media.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ *
+ * 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__
+
+#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 unit 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 then 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
+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
+ * removed, kept only for not breaking older UBI users)
+ * @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
+ * @padding1: reserved for future, zeroes
+ * @sqnum: sequence number
+ * @padding2: 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 then 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.
+ *
+ * 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
+ * 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 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.
+ *
+ * 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; /* obsolete, to be removed, don't use */
+ __be32 data_size;
+ __be32 used_ebs;
+ __be32 data_pad;
+ __be32 data_crc;
+ __u8 padding1[4];
+ __be64 sqnum;
+ __u8 padding2[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 /* !__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] 13+ messages in thread
* [PATCH V3 05/11] ubi: bump ubi-media.h to newest version
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (3 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 04/11] ubi: consolidate ubi-media.h Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 06/11] devfs & mtd: add MEMERASE ioctl support Wolfram Sang
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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 | 55 ++++++++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 25 deletions(-)
diff --git a/include/mtd/ubi-media.h b/include/mtd/ubi-media.h
index cd1bd8e..d552db8 100644
--- a/include/mtd/ubi-media.h
+++ b/include/mtd/ubi-media.h
@@ -11,7 +11,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
- *
* Authors: Artem Bityutskiy (Битюцкий Артём)
* Thomas Gleixner
* Frank Haverkamp
@@ -95,10 +94,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 +120,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 +141,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 +157,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 +166,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 +193,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 +230,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 +250,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 +279,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] 13+ messages in thread
* [PATCH V3 06/11] devfs & mtd: add MEMERASE ioctl support
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (4 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 05/11] ubi: bump ubi-media.h to newest version Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 07/11] mtd: utils: apply macros for message printouts Wolfram Sang
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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 8601787..83e1a39 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -123,7 +123,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)
{
@@ -134,6 +164,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) {
@@ -146,6 +177,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;
@@ -183,38 +217,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] 13+ messages in thread
* [PATCH V3 07/11] mtd: utils: apply macros for message printouts
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (5 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 06/11] devfs & mtd: add MEMERASE ioctl support Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 08/11] lib: add libscan Wolfram Sang
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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 | 47 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 include/mtd/utils.h
diff --git a/include/mtd/utils.h b/include/mtd/utils.h
new file mode 100644
index 0000000..fca64ab
--- /dev/null
+++ b/include/mtd/utils.h
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+/* 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)
+
+#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] 13+ messages in thread
* [PATCH V3 08/11] lib: add libscan
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (6 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 07/11] mtd: utils: apply macros for message printouts Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 09/11] lib: add libubigen Wolfram Sang
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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 | 101 +++++++++++++++++++++++
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/libscan.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 324 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..bb01482
--- /dev/null
+++ b/include/mtd/libscan.h
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ * 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 13ecab0..8aa6f7d 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -41,6 +41,9 @@ config QSORT
config XYMODEM
bool
+config LIBSCAN
+ bool
+
source lib/gui/Kconfig
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index eb0af92..20d96dd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -34,5 +34,6 @@ obj-$(CONFIG_UNCOMPRESS) += uncompress.o
obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
+obj-$(CONFIG_LIBSCAN) += libscan.o
obj-y += gui/
obj-$(CONFIG_XYMODEM) += xymodem.o
diff --git a/lib/libscan.c b/lib/libscan.c
new file mode 100644
index 0000000..af55269
--- /dev/null
+++ b/lib/libscan.c
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ *
+ * 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] 13+ messages in thread
* [PATCH V3 09/11] lib: add libubigen
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (7 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 08/11] lib: add libscan Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 10/11] lib: add barebox version of libmtd Wolfram Sang
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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 | 182 +++++++++++++++++++++++++++
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/libubigen.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 498 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..f05978b
--- /dev/null
+++ b/include/mtd/libubigen.h
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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 8aa6f7d..5dbf069 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -44,6 +44,9 @@ config XYMODEM
config LIBSCAN
bool
+config LIBUBIGEN
+ bool
+
source lib/gui/Kconfig
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 20d96dd..2125af2 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -35,5 +35,6 @@ obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_LIBSCAN) += libscan.o
+obj-$(CONFIG_LIBUBIGEN) += libubigen.o
obj-y += gui/
obj-$(CONFIG_XYMODEM) += xymodem.o
diff --git a/lib/libubigen.c b/lib/libubigen.c
new file mode 100644
index 0000000..4026f1d
--- /dev/null
+++ b/lib/libubigen.c
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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] 13+ messages in thread
* [PATCH V3 10/11] lib: add barebox version of libmtd
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (8 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 09/11] lib: add libubigen Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-17 15:48 ` [PATCH V3 11/11] commands: add ubiformat Wolfram Sang
2012-12-19 11:50 ` [PATCH V3 00/11] ubiformat for barebox Sascha Hauer
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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 | 149 ++++++++++++++++++++
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/libmtd.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 521 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..e88a9a2
--- /dev/null
+++ b/include/mtd/libmtd.h
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ * 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 5dbf069..b97c828 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 2125af2..82e578f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -36,5 +36,6 @@ obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_LIBSCAN) += libscan.o
obj-$(CONFIG_LIBUBIGEN) += libubigen.o
+obj-$(CONFIG_LIBMTD) += libmtd.o
obj-y += gui/
obj-$(CONFIG_XYMODEM) += xymodem.o
diff --git a/lib/libmtd.c b/lib/libmtd.c
new file mode 100644
index 0000000..8c4152e
--- /dev/null
+++ b/lib/libmtd.c
@@ -0,0 +1,368 @@
+/*
+ * 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.
+ *
+ * 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.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 < 0)
+ 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] 13+ messages in thread
* [PATCH V3 11/11] commands: add ubiformat
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (9 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 10/11] lib: add barebox version of libmtd Wolfram Sang
@ 2012-12-17 15:48 ` Wolfram Sang
2012-12-19 11:50 ` [PATCH V3 00/11] ubiformat for barebox Sascha Hauer
11 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2012-12-17 15:48 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 | 8 +
commands/Makefile | 1 +
commands/ubiformat.c | 784 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 793 insertions(+)
create mode 100644 commands/ubiformat.c
diff --git a/commands/Kconfig b/commands/Kconfig
index ac9b797..82c3223 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -347,6 +347,14 @@ config CMD_UBI
depends on UBI
prompt "ubimkvol, ubirmvol, ubiattach"
+config CMD_UBIFORMAT
+ tristate
+ depends on UBI
+ select LIBMTD
+ select LIBSCAN
+ select LIBUBIGEN
+ prompt "ubiformat"
+
endmenu
diff --git a/commands/Makefile b/commands/Makefile
index effc91b..359f566 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_CMD_UNCOMPRESS) += uncompress.o
obj-$(CONFIG_CMD_I2C) += i2c.o
obj-$(CONFIG_CMD_SPI) += spi.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..3bb2c9a
--- /dev/null
+++ b/commands/ubiformat.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix
+ *
+ * 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.
+ */
+
+/*
+ * 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_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 <libbb.h>
+#include <linux/mtd/mtd.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/log2.h>
+#include <linux/mtd/mtd-abi.h>
+#include <mtd/libmtd.h>
+#include <mtd/libscan.h>
+#include <mtd/libubigen.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 yes:1;
+ 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, "nyyqve:x:s:O:f:S:");
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 's':
+ args.subpage_size = strtoull_suffix(optarg, NULL, 0);
+ 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 'y':
+ args.yes = 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;
+
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ 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");
+ else if (optind != argc - 1)
+ return errmsg("more then one MTD device specified");
+
+ 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_RDWR);
+ if (fd < 0)
+ return sys_errmsg("cannot open \"%s\"", args.image);
+
+ return fd;
+}
+
+/*
+ * 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\n", eb);
+
+ 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_full(fd, buf, mtd->eb_size);
+ if (err < 0) {
+ 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)
+ return err;
+
+ 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_mtd;
+ }
+
+ 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_mtd;
+ }
+
+ if (mtd.min_io_size % args.subpage_size) {
+ errmsg("min. I/O unit size should be multiple of "
+ "sub-page size");
+ goto out_close_mtd;
+ }
+ }
+
+ args.node_fd = open(args.node, O_RDWR);
+ if (args.node_fd < 0) {
+ 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 %lld bytes (%s)", mtd.node, mtd.type_str,
+ mtd.size, size_human_readable(mtd.size));
+ printf(", %d eraseblocks of %d bytes (%s)", mtd.eb_cnt,
+ mtd.eb_size, size_human_readable(mtd.eb_size));
+ 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);
+ if (!args.yes && !args.quiet)
+ warnmsg("use '-y' to force erasing");
+ if (!args.yes)
+ 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);
+ if (args.yes) {
+ normsg("erase counter 0 will be used for all eraseblocks");
+ normsg("note, arbitrary erase counter value may be specified using -e option");
+
+ } else {
+ warnmsg("use '-y' to force erase counters");
+ }
+ }
+
+ if (!args.yes)
+ goto out_free;
+
+ 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);
+ if (args.yes)
+ normsg("mean erase counter %lld will be used for the rest of eraseblock",
+ si->mean_ec);
+ else
+ warnmsg("use '-y' to force erase counters");
+ }
+
+ if (!args.yes)
+ goto out_free;
+
+ 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("using 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;
+}
+
+BAREBOX_CMD_HELP_START(ubiformat)
+BAREBOX_CMD_HELP_USAGE(PROGRAM_NAME " <MTD device file name> [-s <bytes>] [-O <offs>] [-n]\n"
+ "\t[-f <file>] [-e <value>] [-x <num>] [-Q <num>] [-y] [-q] [-v]\n")
+BAREBOX_CMD_HELP_SHORT("A tool to format MTD devices and flash UBI images\n")
+BAREBOX_CMD_HELP_OPT("-s <bytes>", "minimum input/output unit used for UBI headers, "
+"e.g. sub-page size in case of NAND flash (equivalent to the minimum input/output "
+"unit size by default)\n")
+BAREBOX_CMD_HELP_OPT("-O <offs>", "offset if the VID header from start of the "
+"physical eraseblock (default is the next minimum I/O unit or sub-page after the EC "
+"header)\n")
+BAREBOX_CMD_HELP_OPT("-n", "only erase all eraseblock and preserve erase "
+"counters, do not write empty volume table\n")
+BAREBOX_CMD_HELP_OPT("-f <file>", "flash image file\n")
+BAREBOX_CMD_HELP_OPT("-e <value>", "use <value> as the erase counter value for all eraseblocks\n")
+BAREBOX_CMD_HELP_OPT("-x <num>", "UBI version number to put to EC headers "
+"(default is 1)\n")
+BAREBOX_CMD_HELP_OPT("-Q <num>", "32-bit UBI image sequence number to use "
+"(by default a random number is picked)\n")
+BAREBOX_CMD_HELP_OPT("-q", "suppress progress percentage information\n")
+BAREBOX_CMD_HELP_OPT("-v", "be verbose\n")
+BAREBOX_CMD_HELP_TEXT(
+"Example 1: " PROGRAM_NAME " /dev/nand0 -y - format nand0 and assume yes\n"
+"Example 2: " PROGRAM_NAME " /dev/nand0 -q -e 0 - format nand0,\n"
+" be quiet and force erase counter value 0.\n";
+)
+BAREBOX_CMD_HELP_END
+
+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] 13+ messages in thread
* Re: [PATCH V3 00/11] ubiformat for barebox
2012-12-17 15:48 [PATCH V3 00/11] ubiformat for barebox Wolfram Sang
` (10 preceding siblings ...)
2012-12-17 15:48 ` [PATCH V3 11/11] commands: add ubiformat Wolfram Sang
@ 2012-12-19 11:50 ` Sascha Hauer
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2012-12-19 11:50 UTC (permalink / raw)
To: Wolfram Sang; +Cc: barebox
On Mon, Dec 17, 2012 at 04:48:22PM +0100, Wolfram Sang wrote:
> Another round of ubiformat for barebox. Tested on various MX28 based hardware.
> I could create and attach empty UBIs or flashed files successfully. I also
> tried flashing /dev/mem and /dev/c64 which failed correctly.
>
> Changes since V1 (V2 was only internal):
>
> * update strtoull_suffix() and size_human_readable()
> * use those and get rid of libubiutils completely \o/
> * use read_full instead of custom read_all
> * dropped all long commandline options and references
> * reworked the help to BAREBOX_CMD_HELP_* usage
> * dropped FSF addresses all over
> * simply quit in dubious situations instead of doing something
> * add '-y' to do something in dubious situations :)
> * quite some bugfixes
> (* verified subpage-size handling, found a bug in nand_mxs driver)
>
> Please test, comment, apply...
Applied, thanks
Sascha
>
> Thanks,
>
> Wolfram
>
>
> Wolfram Sang (11):
> mtd: drop custom is_power_of_2()
> lib: misc: add 'iB' suffixes to strtoull_suffix
> lib: update size_human_readable to latest version
> ubi: consolidate ubi-media.h
> ubi: bump ubi-media.h to newest version
> devfs & mtd: add MEMERASE ioctl support
> mtd: utils: apply macros for message printouts
> lib: add libscan
> lib: add libubigen
> lib: add barebox version of libmtd
> commands: add ubiformat
>
> commands/Kconfig | 8 +
> commands/Makefile | 1 +
> commands/ubi.c | 2 +-
> commands/ubiformat.c | 784 +++++++++++++++++++++++++++++++++++++++++
> drivers/mtd/core.c | 68 ++--
> drivers/mtd/ubi/ubi-barebox.h | 5 +-
> drivers/mtd/ubi/ubi-media.h | 369 -------------------
> drivers/mtd/ubi/ubi.h | 3 +-
> fs/devfs-core.c | 3 +-
> include/common.h | 2 +-
> include/mtd/libmtd.h | 149 ++++++++
> include/mtd/libscan.h | 101 ++++++
> include/mtd/libubigen.h | 182 ++++++++++
> include/mtd/ubi-media.h | 374 ++++++++++++++++++++
> include/mtd/utils.h | 47 +++
> include/ubi-media.h | 370 -------------------
> lib/Kconfig | 9 +
> lib/Makefile | 3 +
> lib/display_options.c | 47 ++-
> lib/libmtd.c | 368 +++++++++++++++++++
> lib/libscan.c | 219 ++++++++++++
> lib/libubigen.c | 312 ++++++++++++++++
> lib/misc.c | 5 +-
> 23 files changed, 2634 insertions(+), 797 deletions(-)
> create mode 100644 commands/ubiformat.c
> delete mode 100644 drivers/mtd/ubi/ubi-media.h
> create mode 100644 include/mtd/libmtd.h
> create mode 100644 include/mtd/libscan.h
> create mode 100644 include/mtd/libubigen.h
> create mode 100644 include/mtd/ubi-media.h
> create mode 100644 include/mtd/utils.h
> delete mode 100644 include/ubi-media.h
> create mode 100644 lib/libmtd.c
> create mode 100644 lib/libscan.c
> create mode 100644 lib/libubigen.c
>
> --
> 1.7.10.4
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
--
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] 13+ messages in thread