summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/ubi/Kconfig2
-rw-r--r--drivers/mtd/ubi/io.c2
-rw-r--r--drivers/mtd/ubispl/ubispl.c215
-rw-r--r--drivers/mtd/ubispl/ubispl.h9
4 files changed, 224 insertions, 4 deletions
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 2b17eae947..a78fd51ba7 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -1,6 +1,6 @@
menu "UBI support"
-config CONFIG_UBI_SILENCE_MSG
+config UBI_SILENCE_MSG
bool "UBI silence verbose messages"
default ENV_IS_IN_UBI
help
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 8ef7823b37..688fb509d2 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -1351,6 +1351,7 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
ubi_err(ubi, "self-check failed for PEB %d:%d, len %d",
pnum, offset, len);
+#if !defined(CONFIG_UBI_SILENCE_MSG)
ubi_msg(ubi, "data differ at position %d", i);
ubi_msg(ubi, "hex dump of the original buffer from %d to %d",
i, i + dump_len);
@@ -1360,6 +1361,7 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
i, i + dump_len);
print_hex_dump("", DUMP_PREFIX_OFFSET, 32, 1,
buf1 + i, dump_len, 1);
+#endif
dump_stack();
err = -EINVAL;
goto out_free;
diff --git a/drivers/mtd/ubispl/ubispl.c b/drivers/mtd/ubispl/ubispl.c
index eeb1cbefb7..3f3b9b4367 100644
--- a/drivers/mtd/ubispl/ubispl.c
+++ b/drivers/mtd/ubispl/ubispl.c
@@ -45,6 +45,187 @@ static int ubi_io_is_bad(struct ubi_scan_info *ubi, int peb)
return peb >= ubi->peb_count || peb < 0;
}
+#ifdef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
+
+/**
+ * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
+ * @r: the object to dump
+ * @idx: volume table index
+ */
+void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
+{
+ int name_len = be16_to_cpu(r->name_len);
+
+ ubi_dbg("Volume table record %d dump: size: %d",
+ idx, sizeof(struct ubi_vtbl_record));
+ ubi_dbg("\treserved_pebs %d", be32_to_cpu(r->reserved_pebs));
+ ubi_dbg("\talignment %d", be32_to_cpu(r->alignment));
+ ubi_dbg("\tdata_pad %d", be32_to_cpu(r->data_pad));
+ ubi_dbg("\tvol_type %d", (int)r->vol_type);
+ ubi_dbg("\tupd_marker %d", (int)r->upd_marker);
+ ubi_dbg("\tname_len %d", name_len);
+
+ if (r->name[0] == '\0') {
+ ubi_dbg("\tname NULL");
+ return;
+ }
+
+ if (name_len <= UBI_VOL_NAME_MAX &&
+ strnlen(&r->name[0], name_len + 1) == name_len) {
+ ubi_dbg("\tname %s", &r->name[0]);
+ } else {
+ ubi_dbg("\t1st 5 characters of name: %c%c%c%c%c",
+ r->name[0], r->name[1], r->name[2], r->name[3],
+ r->name[4]);
+ }
+ ubi_dbg("\tcrc %#08x", be32_to_cpu(r->crc));
+}
+
+/* Empty volume table record */
+static struct ubi_vtbl_record empty_vtbl_record;
+
+/**
+ * vtbl_check - check if volume table is not corrupted and sensible.
+ * @ubi: UBI device description object
+ * @vtbl: volume table
+ *
+ * This function returns zero if @vtbl is all right, %1 if CRC is incorrect,
+ * and %-EINVAL if it contains inconsistent data.
+ */
+static int vtbl_check(struct ubi_scan_info *ubi,
+ struct ubi_vtbl_record *vtbl)
+{
+ int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len;
+ int upd_marker, err;
+ uint32_t crc;
+ const char *name;
+
+ for (i = 0; i < UBI_SPL_VOL_IDS; i++) {
+ reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ alignment = be32_to_cpu(vtbl[i].alignment);
+ data_pad = be32_to_cpu(vtbl[i].data_pad);
+ upd_marker = vtbl[i].upd_marker;
+ vol_type = vtbl[i].vol_type;
+ name_len = be16_to_cpu(vtbl[i].name_len);
+ name = &vtbl[i].name[0];
+
+ crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
+ if (be32_to_cpu(vtbl[i].crc) != crc) {
+ ubi_err("bad CRC at record %u: %#08x, not %#08x",
+ i, crc, be32_to_cpu(vtbl[i].crc));
+ ubi_dump_vtbl_record(&vtbl[i], i);
+ return 1;
+ }
+
+ if (reserved_pebs == 0) {
+ if (memcmp(&vtbl[i], &empty_vtbl_record,
+ UBI_VTBL_RECORD_SIZE)) {
+ err = 2;
+ goto bad;
+ }
+ continue;
+ }
+
+ if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 ||
+ name_len < 0) {
+ err = 3;
+ goto bad;
+ }
+
+ if (alignment > ubi->leb_size || alignment == 0) {
+ err = 4;
+ goto bad;
+ }
+
+ n = alignment & (CONFIG_SPL_UBI_VID_OFFSET - 1);
+ if (alignment != 1 && n) {
+ err = 5;
+ goto bad;
+ }
+
+ n = ubi->leb_size % alignment;
+ if (data_pad != n) {
+ ubi_err("bad data_pad, has to be %d", n);
+ err = 6;
+ goto bad;
+ }
+
+ if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
+ err = 7;
+ goto bad;
+ }
+
+ if (upd_marker != 0 && upd_marker != 1) {
+ err = 8;
+ goto bad;
+ }
+
+ if (name_len > UBI_VOL_NAME_MAX) {
+ err = 10;
+ goto bad;
+ }
+
+ if (name[0] == '\0') {
+ err = 11;
+ goto bad;
+ }
+
+ if (name_len != strnlen(name, name_len + 1)) {
+ err = 12;
+ goto bad;
+ }
+
+ ubi_dump_vtbl_record(&vtbl[i], i);
+ }
+
+ /* Checks that all names are unique */
+ for (i = 0; i < UBI_SPL_VOL_IDS - 1; i++) {
+ for (n = i + 1; n < UBI_SPL_VOL_IDS; n++) {
+ int len1 = be16_to_cpu(vtbl[i].name_len);
+ int len2 = be16_to_cpu(vtbl[n].name_len);
+
+ if (len1 > 0 && len1 == len2 &&
+ !strncmp(vtbl[i].name, vtbl[n].name, len1)) {
+ ubi_err("volumes %d and %d have the same name \"%s\"",
+ i, n, vtbl[i].name);
+ ubi_dump_vtbl_record(&vtbl[i], i);
+ ubi_dump_vtbl_record(&vtbl[n], n);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+
+bad:
+ ubi_err("volume table check failed: record %d, error %d", i, err);
+ ubi_dump_vtbl_record(&vtbl[i], i);
+ return -EINVAL;
+}
+
+static int ubi_read_volume_table(struct ubi_scan_info *ubi, u32 pnum)
+{
+ int err = -EINVAL;
+
+ empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
+
+ err = ubi_io_read(ubi, &ubi->vtbl, pnum, ubi->leb_start,
+ sizeof(struct ubi_vtbl_record) * UBI_SPL_VOL_IDS);
+ if (err && err != UBI_IO_BITFLIPS) {
+ ubi_err("unable to read volume table");
+ goto out;
+ }
+
+ if (!vtbl_check(ubi, ubi->vtbl)) {
+ ubi->vtbl_valid = 1;
+ err = 0;
+ }
+out:
+ return err;
+}
+
+#endif /* CONFIG_SPL_UBI_LOAD_BY_VOLNAME */
+
static int ubi_io_read_vid_hdr(struct ubi_scan_info *ubi, int pnum,
struct ubi_vid_hdr *vh, int unused)
{
@@ -210,14 +391,23 @@ static int ubi_scan_vid_hdr(struct ubi_scan_info *ubi, struct ubi_vid_hdr *vh,
if (vol_id == UBI_FM_SB_VOLUME_ID)
return ubi->fm_enabled ? UBI_FASTMAP_ANCHOR : 0;
+#ifdef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
+ /* If this is a UBI volume table, read it and return */
+ if (vol_id == UBI_LAYOUT_VOLUME_ID && !ubi->vtbl_valid) {
+ res = ubi_read_volume_table(ubi, pnum);
+ return res;
+ }
+#endif
+
/* We only care about static volumes with an id < UBI_SPL_VOL_IDS */
if (vol_id >= UBI_SPL_VOL_IDS || vh->vol_type != UBI_VID_STATIC)
return 0;
+#ifndef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
/* We are only interested in the volumes to load */
if (!test_bit(vol_id, ubi->toload))
return 0;
-
+#endif
lnum = be32_to_cpu(vh->lnum);
return ubi_add_peb_to_vol(ubi, vh, vol_id, pnum, lnum);
}
@@ -232,13 +422,14 @@ static int assign_aeb_to_av(struct ubi_scan_info *ubi, u32 pnum, u32 lnum,
ubi->fastmap_pebs++;
+#ifndef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
if (vol_id >= UBI_SPL_VOL_IDS || vol_type != UBI_STATIC_VOLUME)
return 0;
/* We are only interested in the volumes to load */
if (!test_bit(vol_id, ubi->toload))
return 0;
-
+#endif
vh = ubi->blockinfo + pnum;
return ubi_scan_vid_hdr(ubi, vh, pnum);
@@ -892,6 +1083,10 @@ retry:
ubi->peb_count = info->peb_count;
ubi->peb_offset = info->peb_offset;
+#ifdef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
+ ubi->vtbl_valid = 0;
+#endif
+
fsize = info->peb_size * info->peb_count;
ubi->fsize_mb = fsize >> 20;
@@ -910,7 +1105,23 @@ retry:
for (i = 0; i < nrvols; i++) {
struct ubispl_load *lv = lvols + i;
+#ifdef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
+ if (lv->vol_id == -1) {
+ for (int j = 0; j < UBI_SPL_VOL_IDS; j++) {
+ int len = be16_to_cpu(ubi->vtbl[j].name_len);
+
+ if (strncmp(lv->name,
+ ubi->vtbl[j].name,
+ len) == 0) {
+ lv->vol_id = j;
+ break;
+ }
+ }
+ }
+ ubi_msg("Loading VolName %s (VolId #%d)", lv->name, lv->vol_id);
+#else
ubi_msg("Loading VolId #%d", lv->vol_id);
+#endif
res = ipl_load(ubi, lv->vol_id, lv->load_addr);
if (res < 0) {
if (fastmap) {
diff --git a/drivers/mtd/ubispl/ubispl.h b/drivers/mtd/ubispl/ubispl.h
index 9e40b46eac..b7cb7fc941 100644
--- a/drivers/mtd/ubispl/ubispl.h
+++ b/drivers/mtd/ubispl/ubispl.h
@@ -77,6 +77,8 @@ struct ubi_vol_info {
* @blockinfo: The vid headers of the scanned blocks
* @volinfo: The volume information of the interesting (toload)
* volumes
+ * @vtbl_corrupted: Flag to indicate status of volume table
+ * @vtbl: Volume table
*
* @fm_buf: The large fastmap attach buffer
*/
@@ -112,6 +114,11 @@ struct ubi_scan_info {
struct ubi_vol_info volinfo[UBI_SPL_VOL_IDS];
struct ubi_vid_hdr blockinfo[CONFIG_SPL_UBI_MAX_PEBS];
+#ifdef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
+ /* Volume table */
+ int vtbl_valid;
+ struct ubi_vtbl_record vtbl[UBI_SPL_VOL_IDS];
+#endif
/* The large buffer for the fastmap */
uint8_t fm_buf[UBI_FM_BUF_SIZE];
};
@@ -122,7 +129,7 @@ struct ubi_scan_info {
#define ubi_dbg(fmt, ...)
#endif
-#ifdef CONFIG_UBI_SILENCE_MSG
+#ifdef CONFIG_UBI_SPL_SILENCE_MSG
#define ubi_msg(fmt, ...)
#else
#define ubi_msg(fmt, ...) printf("UBI: " fmt "\n", ##__VA_ARGS__)