Flash Management and JFFS2 File System in QSPI Flash Print

 

Linux provides management of the QSPI Flash, including the ability to partition the physical Flash onto separate logical partitions and mount a JFFS2 flash filesystem on a Flash partition.

The Flash management and JFFS2 filesystem require enabling appropriate kernel options in the kernel configuration and adding certain device nodes and Linux tools to the target file system. The networking project included in the Emcraft distribution at projects/networking provides a sample Linux configuration that has the QSPI Flash management and JFFS2 functionality fully enabled. The examples in the text below make use of the networking project.

Linux splits the external Flash onto several partitions. Even though the partitioning is purely logical in the software, the user view is that each Flash partition can be accessed as a separate "Flash disk" device, independent of the other Flash partitions. Each Flash partitioned can be accessed as a "raw" disk or, alternatively, a Flash file system can be mounted on a partition.

The Flash partitioning is defined in the following kernel platform file:
linux/arch/arm/mach-lpc18xx/flash.c. There are certain C data structures that define the number, offset and size of the configured Flash partitions, specifically:

#if 1
/*
* On the EA LPC4357 Dev Kit, SPIFI is only 2MB
* A JFFS2 partition doesn't fit in
*/
{
.name = "flash_linux_image",
.offset = FLASH_IMAGE_OFFSET,
},
#else
{
.name = "flash_jffs2",
.offset = FLASH_IMAGE_OFFSET,
},
#endif
};

flash.c included in the distribution defines two partitions for the QSPI Flash. The first partition is reserved for the U-Boot environment (refer to Running U-Boot). The second partition is allocated to the bootable Linux image (refer to Installing Linux images to Flash). As remarked in the comment in the source file, the QSPI Flash is limited to only 2 MBytes so there is no room for a JFFS2 partition.

When Linux boots on the target, there will be the following messages in the kernel print-out indicating that the Flash driver is enabled and then describing the specific partitions created by the kernel:

m25p80_spifi m25p80_spifi: s25fl016k (2048 Kbytes)
Creating 2 MTD partitions on "m25p80_spifi":
0x000000000000-0x000000001000 : "flash_uboot_env"
0x000000001000-0x000000200000 : "flash_linux_image"

Let's update the Linux uImage in the second partition from a host directory mounted over NFS. This provides a simple demonstration of a possible software upgrade sequence using a Linux image pulled from the network.

First step is to mount the host directory over NFS and copy a prebuilt uImage to the Flash. In this example, we install the Linux image for the hello project (available at projects/hello in the distribution):

~ # mount -o nolock,rsize=1024 172.17.0.1:/home/vlad/ /mnt
~ # ls -lt /mnt/hello.uImage
-rw-r--r-- 1 19270 19270 549632 May 18 2015 /mnt/hello.uImage
~ # flashcp /mnt/hello.uImage /dev/mtd1
~ #

Now, we are ready to reboot and validate the target is indeed running the newly installed Linux project:

~ # reboot -f
Restarting system.

U-Boot 2010.03-00073-1.14.0 (May 14 2015 - 12:51:52)

CPU : LPC43xx series (Cortex-M4/M0)
Freqs: SYSTICK=144MHz,CCLK=144MHz
Board: Embedded Artists LPC4357 Dev Kit Rev A1
DRAM: 32 MB
In: serial
Out: serial
Err: serial
Net: LPC18XX_MAC
Hit any key to stop autoboot: 0
## Booting kernel from Legacy Image at 14001000 ...
Image Name: Linux-2.6.33-arm1
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 549568 Bytes = 536.7 kB
Load Address: 28008000
Entry Point: 28008001
Verifying Checksum ... OK
Loading Kernel Image ... OK
OK

Starting kernel ...
...
Freeing init memory: 64K
Mounting /proc..
Reading /proc/meminfo:
MemTotal:          31976 kB
MemFree:           31548 kB
Buffers:               0 kB
Cached:               32 kB
SwapCached:            0 kB
Active:                0 kB
Inactive:              0 kB
Active(anon):          0 kB
Inactive(anon):        0 kB
Active(file):          0 kB
Inactive(file):        0 kB
Unevictable:           0 kB
Mlocked:               0 kB
MmapCopy:             72 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:             0 kB
Mapped:                0 kB
Shmem:                 0 kB
Slab:                244 kB
SReclaimable:         24 kB
SUnreclaim:          220 kB
KernelStack:          72 kB
PageTables:            0 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:       15988 kB
Committed_AS:          0 kB
VmallocTotal:          0 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB 
Done
Hello, A2F-Linux!
Hello, A2F-Linux!
Hello, A2F-Linux!

At this point, you will have to use the U-Boot command interface to install a different uImage to the Flash. Refer to Installing Linux images to Flash for detailed instructions on how to do that.

Let's experiment with creating a JFFS2 partition. As noted above, both the Linux image and a JFFS2 parition wouldn't fit into the 2 MBytes QSPI Flash so it is either one or another. Update the Flash partitioning information in the kernel to allocate the Flash space to a JFFS2 partition instead of the bootable Linux image:

#if 0
/* * On the EA LPC4357 Dev Kit, SPIFI is only 2MB
* A JFFS2 partition doesn't fit in
*/
{
.name = "flash_linux_image",
.offset = FLASH_IMAGE_OFFSET,
},
#else
{
.name = "flash_jffs2",
.offset = FLASH_IMAGE_OFFSET,
},
#endif
};

Build the updated kernel (make from the project directory) and load the built uImage to the kernel. The Flash partitioning now looks as follows:

m25p80_spifi m25p80_spifi: s25fl016k (2048 Kbytes)
Creating 2 MTD partitions on "m25p80_spifi":
0x000000000000-0x000000001000 : "flash_uboot_env"
0x000000001000-0x000000200000 : "flash_jffs2"

Let's create a JFFS2 file system on the second partition. The following command erases the Flash partition and marks it up as a JFFS2 file system. JFFS2 provides transparent management of bad blocks and Flash wearing capabilities ensuring the robustness and longevity of the file system in Flash. Notice use of the -j flag as the indication to flash_eraseall that the partition must not only be erased by also marked up for JFFS2:

~ # flash_eraseall -j /dev/mtd1
Erasing 4 Kibyte @ 1ff000 - 100% complete.Cleanmarker written at 1fe000.
~ #

Now everything is ready to mount a JFFS2 file system on that partition. As expected, the initial file system is empty:

~ # mount -t jffs2 /dev/mtdblock1 /mnt
~ # ls -lt /mnt
~ #

Let's add some files to the JFFS2 file system and validate that they are correct. In the example below, we copy the busybox binary from the initramfs root file system to Flash and then run it from Flash:

~ # cp /bin/busybox /mnt/
~ # /mnt/busybox echo Hello from Flash
Hello from Flash
~ #

Now, let's reboot the system and make sure that any updates we make in the JFFS2 are indeed persistent. Note that we have replaced the bootable Linux image with a JFFS2 partition in the QSPI Flash so the only option to boot at this point is from TFTP:

~ # reboot -f
Restarting system.

U-Boot 2010.03-00073-1.14.0 (May 14 2015 - 12:51:52)
...
EA-LPC4357> run netboot
..
init started: BusyBox v1.17.0 (2015-05-18 10:43:53 +0400)
~ # mount -t jffs2 /dev/mtdblock1 /mnt
~ # /mnt/busybox echo Hello from JFFS2 after reboot
Hello from JFFS2 after reboot
~ #

Don't forget to update flash.c in the kernel sources to allocate the second Flash partition to a bootable Linux image, rebuild Linux and re-install the uImage to Flash.