[U-Boot] [PATCH] [UBI] UBI command support (take #2)

It supports basic operation such as create, remove, read, and write.
Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- diff --git a/common/Makefile b/common/Makefile index f00cbd9..b02a541 100644 --- a/common/Makefile +++ b/common/Makefile @@ -139,6 +139,7 @@ COBJS-$(CONFIG_CMD_SETEXPR) += cmd_setexpr.o COBJS-$(CONFIG_CMD_SPI) += cmd_spi.o COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o +COBJS-$(CONFIG_CMD_UBI) += cmd_ubi.o COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o ifdef CONFIG_CMD_USB COBJS-y += cmd_usb.o diff --git a/common/cmd_ubi.c b/common/cmd_ubi.c new file mode 100644 index 0000000..657003e --- /dev/null +++ b/common/cmd_ubi.c @@ -0,0 +1,516 @@ +/* + * Unsorted Block Image commands + * + * Copyright (C) 2008 Samsung Electronics + * Kyungmin Park kyungmin.park@samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> +#include <command.h> +#include <exports.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <ubi_uboot.h> +#include <asm/errno.h> + +/* Private own data */ +static struct ubi_device *ubi; +static int ubi_initialized; + +static void ubi_dump_vol_info(const struct ubi_volume *vol) +{ + ubi_msg("volume information dump:"); + ubi_msg("vol_id %d", vol->vol_id); + ubi_msg("reserved_pebs %d", vol->reserved_pebs); + ubi_msg("alignment %d", vol->alignment); + ubi_msg("data_pad %d", vol->data_pad); + ubi_msg("vol_type %d", vol->vol_type); + ubi_msg("name_len %d", vol->name_len); + ubi_msg("usable_leb_size %d", vol->usable_leb_size); + ubi_msg("used_ebs %d", vol->used_ebs); + ubi_msg("used_bytes %lld", vol->used_bytes); + ubi_msg("last_eb_bytes %d", vol->last_eb_bytes); + ubi_msg("corrupted %d", vol->corrupted); + ubi_msg("upd_marker %d", vol->upd_marker); + + if (vol->name_len <= UBI_VOL_NAME_MAX && + strnlen(vol->name, vol->name_len + 1) == vol->name_len) { + ubi_msg("name %s", vol->name); + } else { + ubi_msg("the 1st 5 characters of the name: %c%c%c%c%c", + vol->name[0], vol->name[1], vol->name[2], + vol->name[3], vol->name[4]); + } + printf("\n"); +} + +static void display_volume_info(struct ubi_device *ubi) +{ + int i; + + for (i = 0; i < (ubi->vtbl_slots + 1); i++) { + if (!ubi->volumes[i]) + continue; /* Empty record */ + ubi_dump_vol_info(ubi->volumes[i]); + } +} + +static void display_ubi_info(struct ubi_device *ubi) +{ + ubi_msg("MTD device name: "%s"", ubi->mtd->name); + ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); + ubi_msg("physical eraseblock size: %d bytes (%d KiB)", + ubi->peb_size, ubi->peb_size >> 10); + ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); + ubi_msg("number of good PEBs: %d", ubi->good_peb_count); + ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); + ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); + ubi_msg("VID header offset: %d (aligned %d)", + ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); + ubi_msg("data offset: %d", ubi->leb_start); + ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); + ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); + ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); + ubi_msg("number of user volumes: %d", + ubi->vol_count - UBI_INT_VOL_COUNT); + ubi_msg("available PEBs: %d", ubi->avail_pebs); + ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs); + ubi_msg("number of PEBs reserved for bad PEB handling: %d", + ubi->beb_rsvd_pebs); + ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); +} + +static int ubi_info(int layout) +{ + if (layout) + display_volume_info(ubi); + else + display_ubi_info(ubi); + + return 0; +} + +static int parse_num(size_t *num, const char *token) +{ + char *endp; + size_t n; + + n = (size_t) ustrtoul(token, &endp, 0); + if (*endp) + return -EINVAL; + + *num = n; + return 0; +} + +static int verify_mkvol_req(const struct ubi_device *ubi, + const struct ubi_mkvol_req *req) +{ + int n, err = -EINVAL; + + if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 || + req->name_len < 0) + goto bad; + + if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) && + req->vol_id != UBI_VOL_NUM_AUTO) + goto bad; + + if (req->alignment == 0) + goto bad; + + if (req->bytes == 0) + goto bad; + + if (req->vol_type != UBI_DYNAMIC_VOLUME && + req->vol_type != UBI_STATIC_VOLUME) + goto bad; + + if (req->alignment > ubi->leb_size) + goto bad; + + n = req->alignment % ubi->min_io_size; + if (req->alignment != 1 && n) + goto bad; + + if (req->name_len > UBI_VOL_NAME_MAX) { + err = -ENAMETOOLONG; + goto bad; + } + + return 0; +bad: + printf("bad volume creation request"); + return err; +} + +static int ubi_create_vol(char *volume, int size, int dynamic) +{ + struct ubi_mkvol_req req; + int err; + + if (dynamic) + req.vol_type = UBI_DYNAMIC_VOLUME; + else + req.vol_type = UBI_STATIC_VOLUME; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = size; + + strcpy(req.name, volume); + req.name_len = strlen(volume); + req.name[req.name_len] = '\0'; + req.padding1 = 0; + /* It's duplicated at drivers/mtd/ubi/cdev.c */ + err = verify_mkvol_req(ubi, &req); + if (err) { + printf("verify_mkvol_req failed %d\n", err); + return err; + } + printf("Creating %s volume %s of size %d\n", + dynamic ? "dynamic" : "static", volume, size); + /* Call real ubi create volume */ + return ubi_create_volume(ubi, &req); +} + +static int ubi_remove_vol(char *volume) +{ + int i, err, reserved_pebs; + int found = 0, vol_id = 0; + struct ubi_volume *vol; + + for (i = 0; i < ubi->vtbl_slots; i++) { + vol = ubi->volumes[i]; + if (vol && !strcmp(vol->name, volume)) { + printf("Volume %s found at valid %d\n", volume, i); + vol_id = i; + found = 1; + break; + } + } + if (!found) { + printf("%s volume not found\n", volume); + return -ENODEV; + } + printf("remove UBI volume %s (id %d)\n", vol->name, vol->vol_id); + + if (ubi->ro_mode) { + printf("It's read-only mode\n"); + err = -EROFS; + goto out_err; + } + + err = ubi_change_vtbl_record(ubi, vol_id, NULL); + if (err) { + printf("Error changing Vol tabel record err=%x\n", err); + goto out_err; + } + reserved_pebs = vol->reserved_pebs; + for (i = 0; i < vol->reserved_pebs; i++) { + err = ubi_eba_unmap_leb(ubi, vol, i); + if (err) + goto out_err; + } + + kfree(vol->eba_tbl); + ubi->volumes[vol_id]->eba_tbl = NULL; + ubi->volumes[vol_id] = NULL; + + ubi->rsvd_pebs -= reserved_pebs; + ubi->avail_pebs += reserved_pebs; + i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; + if (i > 0) { + i = ubi->avail_pebs >= i ? i : ubi->avail_pebs; + ubi->avail_pebs -= i; + ubi->rsvd_pebs += i; + ubi->beb_rsvd_pebs += i; + if (i > 0) + ubi_msg("reserve more %d PEBs", i); + } + ubi->vol_count -= 1; + + return 0; +out_err: + ubi_err("cannot remove volume %d, error %d", vol_id, err); + return err; +} + +static int ubi_volume_write(char *volume, void *buf, size_t size) +{ + int i = 0, err = -1; + int rsvd_bytes = 0; + int found = 0; + struct ubi_volume *vol; + + for (i = 0; i < ubi->vtbl_slots; i++) { + vol = ubi->volumes[i]; + if (vol && !strcmp(vol->name, volume)) { + printf("Volume "%s" found at volume id %d\n", + volume, i); + found = 1; + break; + } + } + if (!found) { + printf("%s voume not found\n", volume); + return 1; + } + rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad); + if (size < 0 || size > rsvd_bytes) { + printf("rsvd_bytes=%d vol->reserved_pebs=%d ubi->leb_size=%d\n", + rsvd_bytes, vol->reserved_pebs, ubi->leb_size); + printf("vol->data_pad=%d\n", vol->data_pad); + printf("Size > volume size !!\n"); + return 1; + } + + err = ubi_start_update(ubi, vol, size); + if (err < 0) { + printf("Cannot start volume update\n"); + return err; + } + + err = ubi_more_update_data(ubi, vol, buf, size); + if (err < 0) { + printf("Couldnt or partially wrote data \n"); + return err; + } + + if (err) { + size = err; + + err = ubi_check_volume(ubi, vol->vol_id); + if (err < 0) + return err; + + if (err) { + ubi_warn("volume %d on UBI device %d is corrupted", + vol->vol_id, ubi->ubi_num); + vol->corrupted = 1; + } + + vol->checked = 1; + ubi_gluebi_updated(vol); + } + + return 0; +} + +static int ubi_volume_read(char *volume, char *buf, size_t size) +{ + int err, lnum, off, len, tbuf_size, i = 0; + size_t count_save = size; + void *tbuf; + unsigned long long tmp; + struct ubi_volume *vol = NULL; + loff_t offp = 0; + + for (i = 0; i < ubi->vtbl_slots; i++) { + vol = ubi->volumes[i]; + if (vol && !strcmp(vol->name, volume)) { + printf("Volume %s found at volume id %d\n", + volume, vol->vol_id); + break; + } + } + if (i == ubi->vtbl_slots) { + printf("%s voume not found\n", volume); + return 0; + } + + printf("read %i bytes from volume %d to %x(buf address)\n", + (int) size, vol->vol_id, (unsigned)buf); + + if (vol->updating) { + printf("updating"); + return -EBUSY; + } + if (vol->upd_marker) { + printf("damaged volume, update marker is set"); + return -EBADF; + } + if (offp == vol->used_bytes) + return 0; + + if (size == 0) { + printf("Read [%lu] bytes\n", (unsigned long) vol->used_bytes); + size = vol->used_bytes; + } + + if (vol->corrupted) + printf("read from corrupted volume %d", vol->vol_id); + if (offp + size > vol->used_bytes) + count_save = size = vol->used_bytes - offp; + + tbuf_size = vol->usable_leb_size; + if (size < tbuf_size) + tbuf_size = ALIGN(size, ubi->min_io_size); + tbuf = malloc(tbuf_size); + if (!tbuf) { + printf("NO MEM\n"); + return -ENOMEM; + } + len = size > tbuf_size ? tbuf_size : size; + + tmp = offp; + off = do_div(tmp, vol->usable_leb_size); + lnum = tmp; + printf("off=%d lnum=%d\n", off, lnum); + do { + if (off + len >= vol->usable_leb_size) + len = vol->usable_leb_size - off; + + err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0); + if (err) { + printf("read err %x\n", err); + break; + } + off += len; + if (off == vol->usable_leb_size) { + lnum += 1; + off -= vol->usable_leb_size; + } + + size -= len; + offp += len; + + printf("buf = %x\n", (unsigned)buf); + memcpy(buf, tbuf, len); + printf("buf[0] = %x\n", buf[0]); + + buf += len; + len = size > tbuf_size ? tbuf_size : size; + } while (size); + + free(tbuf); + return err ? err : count_save - size; +} + +static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + size_t size = 0; + ulong addr = 0; + int err = 0; + + if (!ubi_initialized) { + err = ubi_board_scan(); + if (err) { + printf("UBI init error %d\n", err); + return err; + } + ubi = ubi_devices[0]; + ubi_initialized = 1; + } + + if (argc < 2) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + if (strcmp(argv[1], "info") == 0) { + int layout = 0; + if (argc > 2 && !strncmp(argv[2], "l", 1)) + layout = 1; + return ubi_info(layout); + } + if (strncmp(argv[1], "create", 6) == 0) { + int dynamic = 1; /* default: dynamic volume */ + + /* Use maximum available size */ + size = 0; + + /* E.g., create volume size type */ + if (argc == 5) { + if (strncmp(argv[4], "s", 1) == 0) + dynamic = 0; + else if (strncmp(argv[4], "d", 1) != 0) { + printf("Incorrect type\n"); + return 1; + } + argc--; + } + /* E.g., create volume size */ + if (argc == 4) { + err = parse_num(&size, argv[3]); + if (err) { + printf("Incorrect type\n"); + return err; + } + argc--; + } + /* Use maximum available size */ + if (!size) + size = ubi->avail_pebs * ubi->leb_size; + /* E.g., create volume */ + if (argc == 3) + return ubi_create_vol(argv[2], size, dynamic); + } + if (strncmp(argv[1], "remove", 6) == 0) { + /* E.g., remove volume */ + if (argc == 3) + return ubi_remove_vol(argv[2]); + } + if (strncmp(argv[1], "write", 5) == 0) { + if (argc < 5) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + addr = simple_strtoul(argv[2], NULL, 16); + err = parse_num(&size, argv[4]); + if (err) { + printf("Usage:\n%s\n", cmdtp->usage); + return err; + } + + return ubi_volume_write(argv[3], (void *)addr, size); + } + if (strncmp(argv[1], "read", 4) == 0) { + size = 0; + + /* E.g., read volume size */ + if (argc == 5) { + err = parse_num(&size, argv[4]); + if (err) { + printf("Usage:\n%s\n", cmdtp->usage); + return err; + } + argc--; + } + + /* E.g., read volume */ + if (argc == 4) { + addr = simple_strtoul(argv[2], NULL, 16); + argc--; + } + + if (argc == 3) + return ubi_volume_read(argv[3], (char *)addr, size); + } + + printf("Usage:\n%s\n", cmdtp->usage); + return 0; +} + +U_BOOT_CMD(ubi, 6, 1, do_ubi, + "ubi - ubi create, remove, read, and write commands\n", + "info [l[ayout]]" + " - Display volume and ubi layout information\n" + "ubi create[vol] volume [size] [type]" + " - create volume name with size\n" + "ubi write[vol] address volume size" + " - Write volume from address with size\n" + "ubi read[vol] address volume [size]" + " - Read volume to address with size\n" + "ubi remove[vol] volume" + " - Remove volume\n" + "[Legends]\n" + " volume: charater name\n" + " size: KiB, MiB, GiB, and bytes\n" + " type: s[tatic] or d[ynamic] (default=dynamic)\n" +); diff --git a/include/exports.h b/include/exports.h index 6377875..0620e9e 100644 --- a/include/exports.h +++ b/include/exports.h @@ -25,6 +25,7 @@ char *getenv (char *name); int setenv (char *varname, char *varvalue); long simple_strtol(const char *cp,char **endp,unsigned int base); int strcmp(const char * cs,const char * ct); +int ustrtoul(const char *cp, char **endp, unsigned int base); #ifdef CONFIG_HAS_UID void forceenv (char *varname, char *varvalue); #endif diff --git a/include/jffs2/load_kernel.h b/include/jffs2/load_kernel.h index 551fd0c..e9b7d6e 100644 --- a/include/jffs2/load_kernel.h +++ b/include/jffs2/load_kernel.h @@ -73,4 +73,9 @@ struct mtdids { #define putLabeledWord(x, y) printf("%s %08x\n", x, (unsigned int)y) #define led_blink(x, y, z, a)
+/* common/cmd_jffs2.c */ +extern int mtdparts_init(void); +extern int find_dev_and_part(const char *id, struct mtd_device **dev, + u8 *part_num, struct part_info **part); + #endif /* load_kernel_h */ diff --git a/lib_generic/vsprintf.c b/lib_generic/vsprintf.c index 6e903db..767dde1 100644 --- a/lib_generic/vsprintf.c +++ b/lib_generic/vsprintf.c @@ -55,6 +55,29 @@ long simple_strtol(const char *cp,char **endp,unsigned int base) return simple_strtoul(cp,endp,base); }
+int ustrtoul(const char *cp, char **endp, unsigned int base) +{ + unsigned long result = simple_strtoul(cp, endp, base); + switch (**endp) { + case 'G' : + result *= 1024; + /* fall through */ + case 'M': + result *= 1024; + /* fall through */ + case 'K': + case 'k': + result *= 1024; + if ((*endp)[1] == 'i') { + if ((*endp)[2] == 'B') + (*endp) += 3; + else + (*endp) += 2; + } + } + return result; +} + #ifdef CONFIG_SYS_64BIT_STRTOUL unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base) {

Dear Kyungmin, dear Stefan,
in message 20081022091707.GA16455@july you wrote:
It supports basic operation such as create, remove, read, and write.
Could you please summarize the current state of adding UBI support?
Is it correct to assume we are targetting the 2008.12 release with this stuff?
Best regards,
Wolfgang Denk

On Wed, Nov 19, 2008 at 6:17 AM, Wolfgang Denk wd@denx.de wrote:
Dear Kyungmin, dear Stefan,
in message 20081022091707.GA16455@july you wrote:
It supports basic operation such as create, remove, read, and write.
Could you please summarize the current state of adding UBI support?
Not much as before,
1. Basic UBI command support. read/write/update volume. Of course you can create & remove the volume. 2. Send ubi device from environment variables instead of hard code value.
I saw the NOR device support patch but not yet tested.
Are there the more?
Is it correct to assume we are targetting the 2008.12 release with this stuff?
Yes, I hope to merge it ASAP.
Thank you, Kyungmin Park

On Wednesday 19 November 2008, Kyungmin Park wrote:
Could you please summarize the current state of adding UBI support?
Not much as before,
- Basic UBI command support. read/write/update volume. Of course you can create & remove the volume.
- Send ubi device from environment variables instead of hard code value.
I saw the NOR device support patch but not yet tested.
Are there the more?
Is it correct to assume we are targetting the 2008.12 release with this stuff?
Yes, I hope to merge it ASAP.
I'll post some last-minute UBI fixup patches soon (this week).
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Hi,
As am I going through the MPC85xx reset.s code, I find this code snippet below. I find the Config_sys_monitor is the Text_Base Address in loaded in r3, The Start Offset is zero, I am not getting why we are subtracting the start_cont with start and that addr is loaded in the link register where we jump to.
So what does the address actually refer to? Please Explain.
/* Jump out the last 4K page and continue to 'normal' start */ #ifdef CONFIG_SYS_RAMBOOT b _start_cont #else /* Calculate absolute address in FLASH and jump there */ /*--------------------------------------------------------------*/ lis r3,CONFIG_SYS_MONITOR_BASE@h ori r3,r3,CONFIG_SYS_MONITOR_BASE@l addi r3,r3,_start_cont - _start + _START_OFFSET mtlr r3 blr #endif
_Start: .. .. .. _start_cont: .. .. ..
Thanks & Regards, Vignesh Kumar B Member Technical Staff HCL TECHNOLOGIES LTD., Mob: +91-9600015988 www.hcl.in
Disclaimer: This message and any attachment(s) contained here are information that is confidential, proprietary to HCL Technologies and its customers. Contents may be privileged or otherwise protected by law. The information is solely intended for the individual or the entity it is addressed to. If you are not the intended recipient of this message, you are not authorized to read, forward, print, retain, copy or disseminate this message or any part of it. If you have received this e-mail in error, please notify the sender immediately by return e-mail and delete it from your computer.
-----Original Message----- From: u-boot-bounces@lists.denx.de [mailto:u-boot-bounces@lists.denx.de] On Behalf Of Stefan Roese Sent: Wednesday, November 19, 2008 10:12 AM To: u-boot@lists.denx.de Subject: Re: [U-Boot] [PATCH] [UBI] UBI command support (take #2)
On Wednesday 19 November 2008, Kyungmin Park wrote:
Could you please summarize the current state of adding UBI support?
Not much as before,
- Basic UBI command support. read/write/update volume. Of course you can create & remove the
volume.
- Send ubi device from environment variables instead of hard code
value.
I saw the NOR device support patch but not yet tested.
Are there the more?
Is it correct to assume we are targetting the 2008.12 release with this stuff?
Yes, I hope to merge it ASAP.
I'll post some last-minute UBI fixup patches soon (this week).
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de ===================================================================== _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
DISCLAIMER: -----------------------------------------------------------------------------------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and intended for the named recipient(s) only. It shall not attach any liability on the originator or HCL or its affiliates. Any views or opinions presented in this email are solely those of the author and may not necessarily reflect the opinions of HCL or its affiliates. Any form of reproduction, dissemination, copying, disclosure, modification, distribution and / or publication of this message without the prior written consent of the author of this e-mail is strictly prohibited. If you have received this email in error please delete it and notify the sender immediately. Before opening any mail and attachments please check them for viruses and defect.
-----------------------------------------------------------------------------------------------------------------------
participants (4)
-
Kyungmin Park
-
Stefan Roese
-
Vignesh Kumar B
-
Wolfgang Denk