[[PageOutline]] = Unsorted Block Images (UBI) Unsorted block images (UBI) is an erase block management layer for flash memory devices such as raw NAND devices. UBI serves two purposes: * tracking NAND flash bad blocks * providing wear leveling UBI was written specifically for UBIFS so that the filesystem does not have to deal with these issues. UBIFS is a successor to JFFS2 and a competitor to LogFS. References: * http://en.wikipedia.org/wiki/UBIFS#Unsorted_Block_Images * http://www.linux-mtd.infradead.org/faq/ubi.html * http://www.linux-mtd.infradead.org/faq/ubifs.html = FLASH chip geometry [=#flashgeometry] Because UBI takes care of bad block tracking and wear leveling, it needs to know some details about the geometry of the raw FLASH device when creating an image. The geometry data can be found in the datasheet for the specific flash device used. Gateworks uses a variety of NAND Flash devices that fall within two different unique geometries we refer to as 'normal' and 'large' which references the erase block size: ||= NAND Part =||= NAND Size =||= Page Size (Bytes) =||= Block Size =||= Logical Erase Block Size =||= Blocks =||= READ_ID Bytes =||= Gateworks Geometry Name =|| || Cypress S34ML16G202 || 2GiB || 2048 || 128KiB || 124KiB || 16384 || 0x01 0xd5 0xd2 0x95 || normal || || Micron MT29F2G08 || 256MiB || 2048 || 128KiB || 124KiB || 2048 || 0x2c 0x90 0x95 0x06 || normal || || Micron MT29F16G08 || 2GiB || 4096 || 256KiB || 248KiB || 8192 || 0x2c 0xd5 0xd1 0xa6 || large || || Micron MT29F8G08 || 1GiB || 4906 || 256KiB || 248KiB || 4096 || 0x2c 0xdc 0x00 0x15 || large || * The 'Page Size', 'Block Size', and max blocks are specified by the NAND datasheet. The Logical Erase Block size can be calculated as: (Block Size) - 2 * (Page Size) The geometry can also be determined at runtime in U-Boot using {{{nand info}}} and Linux using {{{sysfs}}}: * Cypress S34ML16G202 2GiB FLASH: - U-Boot: {{{#!bash Ventana > nand info Device 0: nand0, sector size 256 KiB Page size 4096 b OOB size 224 b Erase size 262144 b subpagesize 4096 b options 0x40000200 bbt options 0x 0 }}} * U-Boot above shows a 4096 byte page size and a 256KiB erase block size which dictates a 248KiB logical erase block size - Linux (once device is attached via 'ubiattach /dev/ubi_ctrl -m 2' or via 'root=ubi ubi=2' kernel cmdline params: {{{#!bash # cat /sys/devices/virtual/ubi/ubi0/min_io_size 4096 # cat /sys/devices/virtual/ubi/ubi0/eraseblock_size 253952 # cat /sys/devices/virtual/ubi/ubi0/total_eraseblocks 8124 }}} * above shows a 4096 byte page size, a 248KiB logical erase block size (which dictates a 256KiB physical erase block size) and a max of 8124 total erase blocks available in this ubi for a total usable space of 8124*248KiB still available for use by ubi volumes * Micron MT29F2G08 256MiB FLASH: - U-Boot: {{{#!bash Ventana > nand info Device 0: nand0, sector size 128 KiB Page size 2048 b OOB size 128 b Erase size 131072 b subpagesize 2048 b options 0x40000200 bbt options 0x 8000 }}} * U-Boot aqbove shows a 2048 byte page size and a 128KiB erase block size which dictates a 124KiB logical erase block size - Linux (once device is attached via 'ubiattach /dev/ubi_ctrl -m 2' or via 'root=ubi ubi=2' kernel cmdline params: {{{#!bash # cat /sys/devices/virtual/ubi/ubi0/min_io_size 2048 # cat /sys/devices/virtual/ubi/ubi0/eraseblock_size 126976 # cat /sys/devices/virtual/ubi/ubi0/total_eraseblocks 16248 }}} * above shows a 2048 byte page size, a 124KiB logical erase block size (which dictates a 128KiB physical erase block size) and a max of 126976 total erase blocks available in this ubi for a total usable space of 126976*124KiB still available for use by ubi volumes mkfs.ubifs important arguments: * **-r** Build file system from directory DIR * **-F** The -F option causes mkfs.ubifs to set a special flag in the superblock, which triggers a "free space fixup" procedure in the kernel the very first time the filesystem is mounted. This fixup procedure involves finding all empty pages in the UBIFS file system and re-erasing them. This ensures that NAND pages which contain all 0xFF data get fully erased, which removes any problematic non-0xFF data from their OOB areas. * **-m** Minimum I/O unit size (this is the Page Size) * **-e** Logical erase block size (UBI requires 2 minimum I/O units out of each Physical Erase Block (PEB) for overhead thus this is the 'Block Size' minus 2x the Page Size * **-c** Maximum logical erase block count (Number of Blocks; use the largest of the chips in the same geometry in order to create a ubifs that works on all the above NAND devices) * **-x** Compression type - "lzo", "favor_lzo", "zlib" or "none" (default: "lzo") * **-o** Output to FILENAME * **-h** Help, provides full list of options ubinize important arguments: * **-o** Output file * **-p** Size of the physical eraseblock of the flash in bytes, KiB, or MiB * **-m** Minimum input/output unit size of the flash in bytes (this is the Page Size) = UBI/UBIFS use on Gateworks Ventana UBI is used on the Gateworks Ventana for raw NAND storage. Other Gateworks Product families used NOR FLASH and eMMC. The Gateworks Ventana default U-Boot environment scripts make a few assumptions about booting from NAND flash: * the {{{mtdparts}}} env var partitions the NAND device into sections for uboot (16MB as this accounts for the {{{SPL}}}, {{{u-boot.img}}} and redundancy for bad blocks), u-boot env (1MB), rootfs (the remainder of the device) * the 'rootfs' partition (defined by the {{{mtdparts}}} env var) contains a UBI device/image * the UBI device/image in the rootfs partition contains a volume also called 'rootfs' * an optional bootscript may exist in {{{boot/6x_bootscript-ventana}}} (the {{{image}}} env var) and if found will be sourced * a flattened device tree blob (dtb) may exist in {{{boot/}}} (named by the automatic env vars {{{fdt_file}}}, {{{fdt_file1}}}, or {{{fdt_file2}}}) * a kernel may exist in {{{boot/uImage}}} The above assumptions are not requirements - the U-Boot env scripts can be changed to suit your needs. [=#creatingubi] == Creating a UBI/UBIFS using existing rootfs, kernel, and device-tree blobs To create a UBI image suitable for booting on a standard Gateworks Ventana bootloader (taking into account the assumptions above) you can do the following on a Linux system provided you have a root filesystem ({{{myrootfs.tar.gz}}}), kernel ({{{uImage}}}), and device-tree dtb files ({{{imx6*-gw*.dtb}}}). === 'normal' geometry FLASH devices (2048 byte page size) To create a UBI image suitable for raw NAND FLASH devices with a 2048 byte page size: 1. create a temporary directory for our rootfs and untar your filesystem to it {{{#!bash mkdir tmp sudo tar --numeric-owner -xvf myrootfs.tar.gz -C tmp }}} of files that you have in your rootfs such as root owned /dev files 2. copy your kernel files (and u-boot bootscript if you have one): {{{#!bash cd tmp/ wget http://dev.gateworks.com/ventana/images/gateworks-linux-4.20.tar.xz tar -xvf gateworks-linux-4.20.tar.xz --keep-directory-symlink depmod $(ls /lib/modules/) # create module dependencies rm gateworks-linux-4.20.tar.xz }}} 3. create a ubifs image for the 2048 byte page size 'normal' device geometry: {{{#!bash mkfs.ubifs -F -m 2048 -e 124KiB -c 16248 -x zlib -o root.ubifs -d tmp }}} * the -c parameter (max-peb-count) of 16248 assures that the filesystem can be sized up to 16248*124KiB or 1.9GiB provided there is remaining space in the ubi * the -F parameter sets the free-space-fixup flag causing the filesystem to be resized on mount not to exceed the max-peb-count argument passed with the -c parameter (assuming the volume is dynamic and has blocks remaining) 4. use {{{ubinize}}} to create a ubi image (which can be written to a suitable raw NAND device in U-Boot using {{{nand write}}} or in Linux via {{{ubiformat}}}): {{{#!bash cat < ubinize.cfg [ubifs] mode=ubi image=root.ubifs vol_id=0 vol_type=dynamic vol_name=rootfs vol_flags=autoresize EOF # create ubi suitable for 2048byte page size and 128KiB block size devices ubinize -m 2048 -p 128KiB -o image.ubi ubinize.cfg }}} === 'large' geometry FLASH devices (4096 byte page size) To create a UBI image suitable for raw NAND FLASH devices with a 4096 byte page size: 1. create a temporary directory for our rootfs and untar your filesystem to it {{{#!bash mkdir tmp sudo tar -xvf myrootfs.tar.gz -C tmp }}} 2. copy your kernel files (and u-boot bootscript if you have one): {{{#!bash cd tmp/ wget http://dev.gateworks.com/ventana/images/gateworks-linux-4.20.tar.xz tar -xvf gateworks-linux-4.20.tar.xz --keep-directory-symlink depmod $(ls /lib/modules/) # create module dependencies rm gateworks-linux-4.20.tar.xz }}} 3. create ubifs images for the 4096 byte page size 'large' device geometry: {{{#!bash sudo mkfs.ubifs -F -m 4096 -e 248KiB -c 8124 -o root.ubifs -d tmp }}} * the -c parameter (max-peb-count) of 8124 assures that the filesystem can be sized up to 8124*248KiB or 1.9GiB provided there is remaining space in the ubi * the -F parameter sets the free-space-fixup flag causing the filesystem to be resized on mount not to exceed the max-peb-count argument passed with the -c parameter (assuming the volume is dynamic and has blocks remaining) 4. use {{{ubinize}}} to create ubi image (which can be written to a suitable raw NAND device in U-Boot using {{{nand write}} or in Linux via {{{ubiformat}}}: {{{#!bash cat < ubinize.cfg [ubifs] mode=ubi image=root.ubifs #generate this image with mkfs.ubifs vol_id=0 vol_type=dynamic vol_name=rootfs vol_flags=autoresize EOF # create ubi suitable for 4096byte page size and 256KiB block size devices ubinize -m 4096 -p 256KiB -o image.ubi ubinize.cfg }}} === Bad blocks NAND flashes have a random amount of initial bad blocks. This means that different devices may have slightly different volume sizes (especially if the UBI auto-resize feature is used). == Working with a UBI in Linux OS (extracting or manipulating contents) [=#ubiinlinux] Linux has support for ubi: * mounting a ubi * creating/renaming/removing ubi volumes * reading/writing ubi volumes Working with UBI and UBIFS volumes on Linux require use of the following: * tools (from {{{mtd-utils}}} package): * {{{ubiattach}}} * {{{ubidetach}}} * {{{ubiformat}}} * {{{ubirename}}} * {{{ubiupdatevol}}} * {{{ubinfo}}} * {{{ubimkvol}}} * {{{ubirmvol}}} * kernel support: * mtd (the MTD layer) * mtdblock (the block layer over MTD) * ubi (ubi support) * ubifs (ubi filesystem support) * nandsim (if you want to simulate a NAND device on a development host) When using the above tools the MTD partition must not be mounted by your Linux OS meaning you either have to: * [#ubiondevhost use the nandsim kernel module to simulate a NAND device] * [#ubiontarget boot Linux target with NAND storage using another boot media (ramdisk, usb, mmc, sata, etc)] Note that the '''creation''' of ubifs and ubi images is covered in the [#creatingubi section above]. This section is all about extracting and / or manipulating the contents of a ubi volume. References: * http://free-electrons.com/blog/creating-flashing-ubi-ubifs-images/ * http://elinux.org/UBIFS * http://www.linux-mtd.infradead.org/faq/ubifs.html === On a (NAND-less) Linux Development Host using nandsim [=#ubiondevhost] Often you want to work with UBI and UBIFS images on a Linux Development Host which has no NAND itself. While it is not currently possible to mount a UBI or UBIFS as a loopback device (commonly used for other types of block devices) you can use the nandsim kernel module to simulate a NAND device on a NAND-less Linux development host. To create a simulated NAND device you need to know the first four bytes returned by the READ_ID flash command, which identifies the characteristics of the device. These values can be found in the datasheet of the FLASH devices. As Gateworks boards support two flash sizes, we will show both examples. To create a virtual NAND device on a NAND-less Linux development system: 1. load {{{nandsim}}} module with parameters for specific flash device simulating: * 256MiB MT29F2G08 FLASH {{{#!bash sudo rmmod nandsim sudo modprobe nandsim first_id_byte=0x2c \ second_id_byte=0xda \ third_id_byte=0x90 \ fourth_id_byte=0x95 }}} * 2GiB Cyrpess S34ML16G202 FLASH {{{#!bash sudo rmmod nandsim sudo modprobe nandsim \ first_id_byte=0x01 \ second_id_byte=0xd5 \ third_id_byte=0xd2 \ fourth_id_byte=0x95 }}} * 2GiB Micron MT29F16G08 FLASH: {{{#!bash sudo rmmod nandsim sudo modprobe nandsim \ first_id_byte=0x2c \ second_id_byte=0xd5 \ third_id_byte=0xd1 \ fourth_id_byte=0xa6 }}} * the above create a {{{/dev/mtd0}}} device on your development host * by default nandsim will use RAM backed storage which makes for much faster read/write access, however if you are cramped for RAM space and simulating a large device (ie 2GB) you can add a {{{cache_file=/tmp/nandimage}}} param to {{{nandsim}}} to tell it to use a file-backed storage instead. You can remove the file once you {{{rmmod nandsim}}}. 1. populate NAND with an existing ubi: {{{#!bash sudo modprobe mtdblock sudo dd if=image.ubi of=/dev/mtdblock0 bs=2048 }}} * the mtdblock module creates a {{{/dev/mtdblock0}}} device on your development host * Note that instead of the dd command above you could also have used {{{ubiformat /dev/mtd0}}} to wipe and format a new ubi but this section is documenting how to extract and alter contents of an existing ubi. 1. attach the UBI {{{#!bash sudo modprobe ubi sudo ubiattach /dev/ubi_ctrl -m0 -O2048 sudo ubinfo -a # optionally show info about the UBI }}} 1. mount the ubifs to host {{{#!bash sudo modprobe ubifs sudo mkdir /mnt/ubi # create a mountpoint sudo mount -t ubifs ubi0 /mnt/ubi ls /mnt/ubi # optionally list contents of mounted filesystem }}} Once you are done working with the files in {{{/mnt/ubi}}} simply unmount the device: {{{#!bash sudo umount /mnt/ubi }}} If you have altered the filesystem and wish to extract the altered UBI you can detach and use dd to copy it to a file: {{{#!bash sudo ubidetach /dev/ubi_ctrl -m0 sudo dd if=/dev/mtdblock0 of=image-updated.ubi bs=2048 }}} And when you are done working with the simulated NAND device completely, remove the {{{nandsim}}} module to free up your system memory: {{{#!bash sudo rmmod nandsim }}} References: * http://www.linux-mtd.infradead.org/faq/nand.html#L_nand_nandsim === On a target board with NAND FLASH [=#ubiontarget] To extract or manipulate the contents of a UBI within the NAND Flash of a Linux system, Linux must be booted from a secondary medium without the NAND FLASH partition being mounted. The following examples assume that UBI has been configured to use the 3rd (zero based) MTD FLASH partition ({{{ubi.mtd=2}}} kernel command line) as we typically use the {{{mtdparts=nand:16m(uboot),1m(env),-(rootfs)}}} env variable in U-Boot to dynamically modify the Linux Device-Tree to partition the NAND flash device into 3 partitions: bootloader, bootloader-env, and rootfs. Thus the bootloader is {{{/dev/mtd0}}}, the bootloader env is {{{/dev/mtd1}}}, and the rootfs is {{{/dev/mtd2}}}. Examples: * Mounting UBI NAND FLASH volume (from {{{/dev/mtd2}}}): {{{#!bash ubidetach /dev/ubi_ctrl -m 2 # Make sure /dev/mtd2 is not currently attached ubiattach /dev/ubi_ctrl -m 2 # attach /dev/mtd2 as /dev/ubi0 mount -t ubifs ubi0:rootfs /mnt/ubi #mount 'rootfs' volume from /dev/ubi0 to /mnt/ubi }}} * Updating NAND FLASH using linux target with NAND({{{/dev/mtd2}}}) with a UBI image: {{{#!bash ubidetach /dev/ubi_ctrl -m 2 # Make sure /dev/mtd2 is not currently attached sync ubiformat /dev/mtd2 -y -f image.ubi }}} * Updating NAND FLASH partition ({{{/dev/mtd2}}}) with a UBIFS image {{{#!bash ubidetach /dev/ubi_ctrl -m 2 # Make sure /dev/mtd2 is not currently attached ubiformat /dev/mtd2 -y # format (will wipe contents!) ubiattach /dev/ubi_ctrl -m 2 # attach /dev/mtd2 as /dev/ubi0 ubimkvol /dev/ubi0 -N rootfs -m # create a volume on /dev/ubi0 named 'rootfs' ubiupdatevol /dev/ubi0_0 image.ubifs }}} * Updating NAND FLASH partition ({{{/dev/mtd2}}}) with a tarball {{{#!bash ubidetach /dev/ubi_ctrl -m 2 # Make sure /dev/mtd2 is not currently attached ubiformat /dev/mtd2 -y # format (will wipe contents!) ubiattach /dev/ubi_ctrl -m 2 # attach /dev/mtd2 as /dev/ubi0 ubimkvol /dev/ubi0 -N rootfs -m # create a volume on /dev/ubi0 named 'rootfs' mkdir /mnt/ubi # create a mount-point mount -t ubifs ubi0:rootfs /mnt/ubi # mount 'rootfs' volume from /dev/ubi0 to /mnt/ubi tar xvf rootfs.tar.gz -C /mnt/ubi # extract tarball umount /mnt/ubi # unmount filesystem }}} Troubleshooting: The output beneath indicates that /dev/mtd2 is not attached and you may proceed with manipulating the NAND flash. {{{#!bash root@OpenWrt:/# ubidetach /dev/ubi_ctrl -m 2 ubidetach: error!: cannot detach mtd2 error 16 (Resource busy) }}} == Working with UBI in U-boot Bootloader == [=#ubiinuboot] The U-boot bootloader used by Ventana has support for ubi: * mounting a ubi * removing ubi volumes * creating ubi volumes * writing ubi volumes [=#BasicMethod] === Updating NAND FLASH with a UBI image === If your ubi image is on a [wiki:tftpserver tftp server] as {{{image.ubi}}} you can use the following to update the 'rootfs' NAND FLASH partition in U-Boot: Preferred method using the {{{nand_update}}} script will perform the update for you using the image name specified in the {{{image_rootfs}}} env variable. Run the following commands in the bootloader: {{{#!bash setenv ipaddr 192.168.1.1 setenv serverip 192.168.1.254 setenv image_rootfs image.ubi; run nand_update }}} The more manual method without using the {{{nand_update}}} script, if your ubi image is on a tftp server as image.ubi you can use the following to update the 'rootfs' NAND FLASH partition in U-Boot (update the ip addresses as appropriate for your network environment): {{{#!bash setenv ipaddr 192.168.1.1 setenv serverip 192.168.1.254 tftpboot ${loadaddr} image.ubi && \ nand erase.part rootfs && \ nand write ${loadaddr} rootfs ${filesize} }}} If your ubi image is on the first partition of a FAT formated MMC called {{{image.ubi}}} you can do the following: {{{#!bash mmc rescan fatload mmc 0:1 ${loadaddr} image.ubi && \ nand erase.part rootfs && \ nand write ${loadaddr} rootfs ${filesize} }}} If your ubi image is on the first partition of a ext2/3/4 formated MMC called {{{image.ubi}}} you can do the following: {{{#!bash mmc rescan ext2load mmc 0:1 ${loadaddr} image.ubi && \ nand erase.part rootfs && \ nand write ${loadaddr} rootfs ${filesize} }}} If your ubi image is on the first partition of a FAT formatted USB stick called {{{image.ubi}}} you can do the following: {{{#!bash usb start usb dev 0 fatload usb 0:1 ${loadaddr} image.ubi && \ nand erase.part rootfs && \ nand write ${loadaddr} rootfs ${filesize} }}} '''Note that operating on the ubi device as described here destroys the wear-leveling information contained in the UBI therefore it is recommended to work at the ubi volume layer to replace ubifs volumes as described below''' [=#SplitMethod] ==== Updating UBI with low RAM devices For some devices, the size of the NAND flash exceeds the size of RAM. In this scenario the instructions from the prior section would fail as you would run out of RAM space before you could finish retrieving the file to program the NAND flash with. To work around this limitation Gateworks has created an installable U-Boot script that will apply UBI files containing a single partition image. This can be particularly useful for updating the firmware of a running target. To update using a split UBI: '''1. Split your UBI In some situations the RAM of your device will be smaller than the image file required to update your system, therefore it is necessary to split the image file and apply the resulting compressed parts in a piece wise update. The below example uses the {{{split}}} command to split the input file into parts that are reasonably smaller than the RAM size of the board which will be consuming the update. {{{#!bash FILE=xenial-large.ubi # Split file every 200M with suffix ".part" and decimal increment split -d -b 200M ${FILE} ${FILE}.part # Result will be multiple files such as xenial-large.ubi.partXX that are <= 200M and # which adhere to the naming convention required by the script (ends with .partXX in sequential order) }}} '''2. Install the U-Boot script On the target machine, source the [http://trac.gateworks.com/raw-attachment/wiki/linux/ubi/nand_split_update.scr nand_split_update.scr] U-Boot script attached to this page (or copy its contents with an editor). For example via tftp: {{{#!bash setenv serverip 192.168.1.100 tftpboot nand_split_update.scr source $loadaddr }}} '''3. Configure your U-Boot environment From the script's usage: {{{ The following environment variables need to be set in order for this script to run: splitfile - full path file name prefix of the splitted files (eg file.ubi for file.ubi.part00) }}} An example configuration: {{{#!bash setenv splitfile xenial-large.ubi # ubi file from example above }}} '''4. Run the added script with {{{run nand_split_update}}} [=#uboot-ubifs] === Updating NAND FLASH with a ubifs image To update the contents of a ubi with a ubifs in U-Boot: {{{#!bash ubi part rootfs # select the 'rootfs' partition (from mtdparts env var) for ubi ubi info layout # list volumes ubi remove rootfs # remove rootfs volume ubi create rootfs a00000 static # create a 10MB volume named rootfs tftpboot ${loadaddr} ventana/root.ubifs && ubi write ${loadaddr} rootfs ${filesize} ubifsmount ubi0:rootfs # mount rootfs volume from ubi ubifsls / ubifsumount }}} Operating on a NAND device at the ubi volume layer like this preserves the wear-leveling information for your flash device and is therefore recommended, especially if you are doing this often. Use the information in the section above for examples on how to load data in uboot from various sources such as network, mmc, usb.