Wednesday, August 10, 2011

Using UBIFS with CRAMFS(1)

In this post, we are going to port Qt embedded on S3C6410 platform. The main CPU module consists of:
  • CPU: S3C6410(ARM1176
  • RAM: SRAM 256MB
  • FLASH: NAND 1GB(MLC type)
We assume that we have already u-boot and kernel running on the machine and that root file system (busybox) and Qt embedded are ready on our host (nfsroot).

Although, UBIFS is a good FLASH file system in most cases, we cannot use UBIFS as our root file system for some reasons. Most of all, the version of u-boot we can use for S3C6410 is v1.3.4, which has no UBIFS support features unlike recent ones. (I don't want to talk about the pathetic support from samsung for their products here but my recommendation is just avoid their products as far as you can.) Still we can use nfsroot to create UBI volume on the FLASH. But if we consider the (mass) production or on-site service, this is hardly a good choice.

Anyway, we take CRAMFS as our root file system and mount UBIFS on the /usr/local. Since CRAMFS is read-only file system, we put on the CRAMFS only minimum files required to load UBIFS, which would be busybox plus some mtd utils. For the rest of files we can locate under /usr/local directory including Qt embedded. I'm not going to describe the details here. But as usual, you can test your initial file system on NFS and deploy afterwards.

First we need an appropriate partition on our FLASH system, which is hard-coded in our kernel. For kernel-2.6.28.6 (with samsung modification), you can find the FLASH partition information here:

arch/arm/plat-s3c/include/plat/partition.h

and its contents would be:

struct mtd_partition s3c_partition_info[] = {

  /* u-boot : 0x0000.0000 - 0x0004.0000 */
  {
    .name = "bootloader",
    .offset = 0,
    .size = (256*SZ_1K),
    .mask_flags = MTD_CAP_NANDFLASH,
  },
  /* kernel : 0x0004.0000 - 0x0040.0000 */
  {
    .name = "kernel",
    .offset = (256*SZ_1K),
    .size = (4*SZ_1M) - (256*SZ_1K),
    .mask_flags = MTD_CAP_NANDFLASH,
  },
  /* cramfs : 0x40.0000 - 0x0080.0000 */
  {
    .name = "rootfs",
    .offset = (4*SZ_1M),
    .size = (4*SZ_1M),
  },
  /* ubifs : 0x0080.0000 - (end_of_FLASH) */
  {
    .name = "ubifs",
    .offset = MTDPART_OFS_APPEND,
    .size = MTDPART_SIZ_FULL,
  }
};

This will make 4 partitions  on your FLASH memory. You can check this on your device by

# cat /proc/mtd

dev:    size   erasesize  name
mtd0: 00040000 00040000 "bootloader"
mtd1: 003c0000 00040000 "kernel"
mtd2: 00400000 00040000 "rootfs"
mtd3: 3f800000 00040000 "ubifs"

At the same time, you can find corresponding devices under /dev

/dev/mtd0 - /dev/mtd3 : character devices
/dev/mtdblock0 - /dev/mtdblock3 : block devices

We will use the mtd3 partition for mounting /usr/local directory. Rest of them have no meaning for now. First erase the partition:

# flash_erase /dev/mtd3 0 0

Erasing 256 Kibyte @ 3f7c0000 -- 100 % complete

For the MTD utils used here, please refer to other post about how to cross-compile them. Then attach this partition(mtd3) to ubi drive 0:

# ubiattach /dev/ubi_ctrl -m 3

UBI: attaching mtd3 to ubi0
UBI: physical eraseblock size:   262144 bytes (256 KiB)
UBI: logical eraseblock size:    258048 bytes
UBI: smallest flash I/O unit:    2048
UBI: VID header offset:          2048 (aligned 2048)
UBI: data offset:                4096
UBI: empty MTD device detected
UBI: create volume table (copy #1)
UBI: create volume table (copy #2)
UBI: attached mtd3 to ubi0
UBI: MTD device name:            "ubifs"
UBI: MTD device size:            1016 MiB
UBI: number of good PEBs:        4064
UBI: number of bad PEBs:         0
UBI: max. allowed volumes:       128
UBI: wear-leveling threshold:    4096
UBI: number of internal volumes: 1
UBI: number of user volumes:     0
UBI: available PEBs:             4020
UBI: total number of reserved PEBs: 44
UBI: number of PEBs reserved for bad PEB handling: 40
UBI: max/mean erase counter: 0/0
UBI: background thread "ubi_bgt0d" started, PID 1253
UBI device number 0, total 4064 LEBs (1048707072 bytes, 1000.1 MiB), available 4020 LEB)

You can find some useful information about your FLASH memory here, which will be used later, such as:
  • physical erase block (PEB) size : 256KiB
  • logical erase block (LEB) size : 258048 bytes
  • available PEBs / LEBs : 4020 / 4020
  • minimum I/O unit size : 2048
If you want to detach  the partition from the ubi drive 0 then you can execute:

ubidetach /dev/ubi_ctrl -d 0

UBI: mtd3 is detached from ubi0

any time. But for now, let us just move on.

Next thing we have to do is create a volume on the drive

# ubimkvol /dev/ubi0 -N usrlocal -m

Set volume size to 1037352960
Volume ID 0, size 4020 LEBs (1037352960 bytes, 989.3 MiB), LEB size 258048 bytes ...

where usrlocal is the volume name. Now we can mount this volume to the point we want

# mount -t ubifs ubi0:usrlocal /usr/local

UBIFS: default file-system created
UBIFS: mounted UBI device 0, volume 0, name "usrlocal"
UBIFS: file system size:   1034514432 bytes (1010268 KiB, 986 MiB, 4009 LEBs)
UBIFS: journal size:       33546240 bytes (32760 KiB, 31 MiB, 130 LEBs)
UBIFS: media format:       4 (latest is 4)
UBIFS: default compressor: LZO
UBIFS: reserved for root:  5182151 bytes (5060 KiB)

At this point, we have additional MTD device :

# cat /proc/mtd

mtd0: 00040000 00040000 "bootloader"
mtd1: 003c0000 00040000 "kernel"
mtd2: 00400000 00040000 "rootfs"
mtd3: 3f800000 00040000 "ubifs"
mtd4: 3dd4c000 0003f000 "usrlocal"

Now, we can populate the directory with files we want. For example, we can archive the whole local directory in the host machine, copy the archive file on SD card, mount it on the device, and populate the directory.

# mount /dev/mmcblk0p1 /mnt
# cd /usr
# tar xvf /mnt/usrlocal.tgz local/

To mount this volume automatically every time the device boots up, we have to add the following line on the file /etc/init.d/rcS :

ubiattach /dev/ubi_ctrl -m 3
mount -t ubifs ubi0:usrlocal /usr/local

Be sure to remember that our root file system is CRAMFS. so all the change should be done on the host machine (NFS directory) and be prepared by mkcramfs utility:

$ cd /home/user
$ mkcramfs -v local/ /var/lib/tftpboot/cramfs.image

Then download and flash on your device with u-boot

> tftp 51000000 cramfs.image
> nand erase 400000 400000
> nand write 51000000 40000 40000
> reset

Many executables including Qt application, use /tmp directory for their temporary data storage. So it is required to mount tmpfs on /tmp since our root file system is read-only. Add the following line to /etc/init.d/rcS as well:

mount -n -t tmpfs -o size-32m tmpfs /tmp


1 comment:

  1. Do you have instructions to boot from jffs2 ?. Like the way you have illustrated ubifs booting. I am looking for jffs2.

    ReplyDelete