Booting uClinux on SmartFusion2 in 0.5 Seconds Print

 

Fast-booting Linux on SmartFusion2

Watch this video to see how Linux (uClinux) boots up on SmartFusion2 from power-up to the interactive shell in about 0.5 seconds.

The hardware platform is Emcraft Systems' M2S-FG484 system-on-module (SOM) plugged into the SOM-BSB-EXT baseboard. Both Cortex-M3 and LPDDR are configured to run at 142 MHz. PCLK0 is set to a 1/2 of the main clock (71 MHz), allowing to run SPI_0 and access the SPI Flash at up to 35.5 MHz. The on-chip cache is enabled by software for LPDDR.

The Linux configuration used in this demo targets a typical "data harvesting" device. Support for the SPI controller, SPI Flash, Flash partitioning and JFFS2 are all enabled in the kernel. As soon as Linux comes up to the shell, a data harvesting application (or any number of such applications) can be started from the /etc/rc start-up script, collecting data from various sensors and logging collected data into the on-module SPI Flash. As can be seen from the above video, it takes uClinux only 0.5 seconds from power-up / reset to the point where data harvesting can commence.

Linux Bootstrap Sequence

The Linux boostrap can be described by the following sequence:

  1. On reset, U-Boot firmware runs from the on-chip eNVM / eSRAM. U-boot performs SmartFusion2 initialization from power-on / reset, including setting up the DDR controller and enabling access to the SPI Flash.
  2. U-Boot copies the Linux bootable image from the SPI Flash to the LPDDR and then passes control to the kernel entry point.
  3. Linux proceeds to boot up in LPPDR. A RAM-based filesystem initramfs is mounted as a root filesystem. initramfs is populated with required files and directories and is then simply linked into the Linux bootable image at build time on a cross-development host.
  4. As a part of the boot-up sequence, the SPI controller, SPI Flash device drivers, and the JFFS2 sub-system are initialized by the kernel.
  5. Having mounted the root filesystem, Linux starts the init application, which in turn spawns the first shell and runs a start-up command sequence defined in the /etc/rc script.
  6. /etc/rc can do, generally speaking, whatever. In this demo, it is assumed that /etc/rc will be defined to start a data harvesting application as soon as possible. To emulate this, we run an echo "Data harvesting can commence" command from the start-up script.

Installing the Demo

The procedure described here explains how to install the bootable Linux image (fastboot.uImage) to the target.

Here is how you can build and install the bootable Linux image from the project sources (fastboot.tgz), having installed them on top of the Emcraft Systems SmartFusion2 uClinux distribution.

Note: The Linux image and the sample project have been built and validated in context of the Emcraft Systems Release 1.14.3. If you are using a different release, some porting changes may be needed.

Understanding the Demo

Here is a detailed description of the demo.

The first message printed by U-Boot after power-up/reset is as follows:

U-Boot 2010.03-cortexm-1.14.3 (Nov 04 2015 - 13:06:17)

U-Boot proceeds with initialization of the target and reports various characteristics of the hardware platform:

CPU : SmartFusion®2 SoC (Cortex-M3 Hard IP)
Freqs: CORTEX-M3=142MHz,PCLK0=71MHz,PCLK1=71MHz
Board: M2S-FG484-SOM Rev 1A, www.emcraft.com
DRAM: 64 MB
In: serial
Out: serial
Err: serial
Net: M2S_MAC

U-Boot then waits for the number of seconds defined by the bootdelay environment variable before proceeding to execute a bootup sequence defined by the bootcmd variable. If the user presses any key while in the bootdelay loop, U-Boot interrupts the boot-up sequence and enters the interactive command monitor. Initially we set bootdelay to 3.

Hit any key to stop autoboot: 0

Now, this is the point when the bootdelay loop has expired and the bootcmd commands sequence is being executed. On SmartFusion2, the first action bootcmd performs is loading a bootable Linux image from the SPI Flash to the LPDDR:

16384 KiB S25FL128S_64K at 0:0 is now current device

Then a bootm command is called upon the image loaded into DDR. What this command does is, parse the image header, figure out the image type and size, optionally verify the checksum and pass control to the kernel entry point:

## Booting kernel from Legacy Image at a0007fc0 ...
Image Name: Linux-2.6.33-arm1
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 941920 Bytes = 919.8 kB
Load Address: a0008000
Entry Point: a0008001

This is where U-Boot is done and the Linux kernel starts running:

Starting kernel ...

The following are the first messages printed by the kernel:

Linux version 2.6.33-arm1 (vlad @ocean.emcraft.com) (gcc version 4.4.1 (Sourcery G++ Lite 2010q1-189) ) #79 Thu Dec 27 11:32:17 +0400 2012
CPU: ARMv7-M Processor [412fc231] revision 1 (ARMv7M)
CPU: NO data cache, 8K instruction cache
Machine: Actel M2S
...

Note the kernel input arguments passed by U-Boot to the kernel. This is defined by bootargs in U-Boot:

Kernel command line: m2s_platform=m2s-fg484-som console=ttyS0,115200 panic=10
ip=172.17.4.219:172.17.0.1:::m2s-fg484-som:eth0:off ethaddr=C0:B1:3C:83:83:83
...

The kernel proceeds to set the memory up. We have 64 MB of LPDDR to run Linux from:

Memory: 64MB = 64MB total
Memory: 64016k/64016k available, 1520k reserved, 0K highmem
Virtual kernel memory layout:
vector : 0x00000000 - 0x00001000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0x00000000 - 0xffffffff (4095 MB)
lowmem : 0xa0000000 - 0xa4000000 ( 64 MB)
modules : 0xa0000000 - 0x01000000 (1552 MB)
.init : 0xa0008000 - 0xa0047000 ( 252 kB)
.text : 0xa00cd7e8 - 0xa00e3000 ( 87 kB)
.data : 0xa00e4000 - 0xa00edf60 ( 40 kB)
...

Then the kernel runs the so-called "calibration loop" in order to calculate loops-in-jiffies also referred to as lpj. The lpj value is used by the kernel to implement various delays. Note that as part of the calibration loop, the kernel also calculates the BogoMIPS value, which is a Linux approximation of the MIPS (Million Instructions Per Second) metric:

Calibrating delay loop... 132.30 BogoMIPS (lpj=661504)
...

The UART device driver and the serial console are initialized:

Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0x40000000 (irq = 10) is a 16550A
console [ttyS0] enabled

The SPI device driver is started and the SPI Flash is partitioned onto 3 separate logical partitions. Each partition can be accesses as a separate logical device by user-space code:

m25p80 spi0.0: s25fl129p1 (16384 Kbytes)
Creating 3 MTD partitions on "s25fl129p1":
0x000000000000-0x000000010000 : "spi_flash_uboot_env"
0x000000010000-0x000000410000 : "spi_flash_linux_image"
0x000000410000-0x000001000000 : "spi_flash_jffs2"
spi_m2s spi_m2s.0: SPI Controller 0 at 40001000,clk=71000000
...

The initramfs root filesystem is mounted and init, which is the first user-space process, is launched:

init started: BusyBox v1.17.0 (2012-12-14 10:29:39 +0400)

init proceeds to execute a start-up command-line sequence defined by the /etc/rc script. In our application, we have /etc/rc contain a single command (echo "Data harvesting can commence"), which results in the output below:

Data harvesting can commence

And finally, init starts the interactive command shell:

/ #

Configuring for Fast-Boot

To achieve the ~0.5 seconds boot times shown in the above video, you will need to specifically configure U-Boot. Note that each of the configuration steps described below is optional, in the sense that if you don't perform a certain optimization step, the demo will still boot on the target, although slightly slower than it would otherwise.

From the U-Boot prompt, do the following:

  1. Disable validation of the bootable Linux image checksum:
  2. M2S-FG484-SOM> set verify no

  3. Add lpj=661504 to bootargs. This tells the kernel to avoid running the calibration loop and instead set lpj (loops-per-jiffy) to a fixed value (pre-calculated for the specific hardware configuration):
  4. M2S-FG484-SOM> set args ${args} lpj=661504
    M2S-FG484-SOM> print args
    args=setenv bootargs m2s_platform=m2s-fg484-som console=ttyS0,115200 panic=10 lpj=661504
    M2S-FG484-SOM>

  5. Add quiet=quiet to bootargs in U-Boot. This tells the kernel to suppress printing information messages onto the serial console.
  6. M2S-FG484-SOM> set args ${args} quiet=quiet
    M2S-FG484-SOM> print args
    args=setenv bootargs m2s_platform=m2s-fg484-som console=ttyS0,115200 panic=10 lpj=661504 quiet=quiet

  7. To restore the message printing function, remove quiet=quiet from bootargs.
  8. Set bootdelay to 0. This tells U-boot to immediately proceed with running bootcmd, without waiting for user input for bootdelay seconds:
  9. M2S-FG484-SOM> set bootdelay 0

  10. To restore the bootdelay function in U-boot, press Ctrl-C at the same time as you push the reset button. This will return you to the U-Boot command monitor, where you can reset bootdelay to a non-zero value.
  11. Save the updated environment variables to the SPI Flash:
  12. M2S-FG484-SOM> saveenv
    Saving Environment to SPI Flash...
    Erasing SPI flash...Writing to SPI flash...done

  13. Push the reset button and watch the demo to boot up on SmartFusion2 in a blink of eye:
  14. U-Boot 2010.03-cortexm-1.14.3 (Nov 04 2015 - 13:06:17)

    CPU : SmartFusion®2 SoC (Cortex-M3 Hard IP)
    Freqs: CORTEX-M3=142MHz,PCLK0=71MHz,PCLK1=71MHz
    Board: M2S-FG484-SOM Rev 1A, www.emcraft.com
    DRAM: 64 MB
    In: serial
    Out: serial
    Err: serial
    Net: M2S_MAC
    Hit any key to stop autoboot: 0
    16384 KiB S25FL128S_64K at 0:0 is now current device
    ## Booting kernel from Legacy Image at a0007fc0 ...
    Image Name: Linux-2.6.33-cortexm-1.14.3
    Image Type: ARM Linux Kernel Image (uncompressed)
    Data Size: 942720 Bytes = 920.6 kB
    Load Address: a0008000
    Entry Point: a0008001
    Loading Kernel Image ... OK
    OK

    Starting kernel ...

    init started: BusyBox v1.17.0 (2015-11-11 18:27:54 +0400)
    Data harvesting can commence
    / #

Restoring Default Configuration

Please step through the following procedure to restore the default configuration:

  1. Push and hold ^C. At the same time, push the reset button on the baseboard. This will bring you to the U-Boot prompt:
  2. U-Boot 2010.03-cortexm-1.14.3 (Nov 04 2015 - 13:06:17)

    CPU : SmartFusion®2 SoC (Cortex-M3 Hard IP)
    Freqs: CORTEX-M3=142MHz,PCLK0=71MHz,PCLK1=71MHz
    Board: M2S-FG484-SOM Rev 1A, www.emcraft.com
    DRAM: 64 MB
    In: serial
    Out: serial
    Err: serial
    Net: M2S_MAC
    Hit any key to stop autoboot: 0
    M2S-FG484-SOM> <INTERRUPT>
    M2S-FG484-SOM> <INTERRUPT>
    M2S-FG484-SOM> <INTERRUPT>
    M2S-FG484-SOM>

  3. Roll back the changes we've made:
  4. M2S-FG484-SOM> print args
    args=setenv bootargs m2s_platform=m2s-fg484-som console=ttyS0,115200 panic=10 lpj=661504 quiet=quiet
    M2S-FG484-SOM> setenv args setenv bootargs m2s_platform=m2s-fg484-som console=ttyS0,115200 panic=10
    M2S-FG484-SOM> setenv bootdelay 3
    M2S-FG484-SOM> save
    Saving Environment to SPI Flash...
    Erasing SPI flash...Writing to SPI flash...done
    M2S-FG484-SOM>