Booting uClinux on SmartFusion2 in 0.5 Seconds Print

 

Fast-booting Linux on SmartFusion2

This application note demonstrates how Linux (uClinux) boots up on SmartFusion2 from power-up to the interactive shell in about 0.5 seconds.

The hardware platform is Microsemi's SF2-DEV-KIT board. The Cortex-M3 is configured to run at 166 MHz. PCLK0 is set to a 1/2 of the main clock (83 MHz), allowing to run SPI_0 and access the SPI Flash at up to 41.5 MHz. The on-chip cache is enabled by software for DDR3.

The Linux configuration used in this demo targets a typical "data harvesting" device. Support for 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-board SPI Flash. It takes uClinux only 0.5 seconds from power-up / reset to the point where data harvesting can commence.

Linux Bootstrap Sequence

The Linux bootstrap 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 DDR3 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, 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.11.0. 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-linux-cortexm-1.10.0 (May 17 2013 - 16:09:15)

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=166MHz,PCLK0=83MHz,PCLK1=83MHz
Board: SF2-DEV-KIT Rev 1.0, Microsemi
DRAM: 256 MB
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0

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 DDR3:

8192 KiB AT25DF641 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: 942560 Bytes = 920.5 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 (psl @ocean.emcraft.com) (gcc version 4.4.1 (Sourcery G++ Lite 2010q1-189) ) #12 Mon May 20 18:32:43 +0400 2013
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=sf2-dev-kit console=ttyS1,115200 panic=10
ip=172.17.4.219:172.17.0.1:::sf2-dev-kit:eth0:off ethaddr=C0:B1:3C:83:83:83
...

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

Memory: 256MB = 256MB total
Memory: 258940k/258940k available, 3204k reserved, 0K highmem
Virtual kernel memory layout:
vector : 0x00000000 - 0x00001000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0x00000000 - 0xffffffff (4095 MB)
lowmem : 0xa0000000 - 0xb0000000 ( 256 MB)
modules : 0xa0000000 - 0x01000000 (1552 MB)
.init : 0xa0008000 - 0xa0047000 ( 252 kB)
.text : 0xa00cdee0 - 0xa00e4000 ( 89 kB)
.data : 0xa00e4000 - 0xa00ee1e0 ( 41 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... 155.23 BogoMIPS (lpj=776192)
...

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
serial8250.1: ttyS1 at MMIO 0x40010000 (irq = 11) is a 16550A
console [ttyS1] 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: at25df641 (8192 Kbytes)
Creating 3 MTD partitions on "at25df641":
0x000000000000-0x000000010000 : "spi_flash_uboot_env"
0x000000010000-0x000000400000 : "spi_flash_linux_image"
0x000000400000-0x000000800000 : "spi_flash_jffs2"
spi_m2s spi_m2s.0: SPI Controller 0 at 40001000,clk=83000000

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, 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. SF2-DEV-KIT> set verify no

  3. Add lpj=776192 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. SF2-DEV-KIT> set bootargs m2s_platform=sf2-dev-kit console=ttyS1,115200 panic=10 lpj=776192

  5. Add quiet=quiet to bootargs in U-Boot. This tells the kernel to suppress printing information messages onto the serial console.
  6. SF2-DEV-KIT> set bootargs m2s_platform=sf2-dev-kit console=ttyS1,115200 panic=10 lpj=776192 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. SF2-DEV-KIT> 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. SF2-DEV-KIT> 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. 8192 KiB AT25DF641 at 0:0 is now current device
    ## Booting kernel from Legacy Image at a0007fc0 ...
    Image Name: Linux-2.6.33-arm1
    Image Type: ARM Linux Kernel Image (uncompressed)
    Data Size: 942560 Bytes = 920.5 kB
    Load Address: a0008000
    Entry Point: a0008001
    Verifying Checksum ... OK
    Loading Kernel Image ... OK
    OK

    Starting kernel ...

    init started: BusyBox v1.17.0 (2013-05-17 18:42:56 +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 board. This will bring you to the U-Boot prompt:
  2. U-Boot 2010.03-linux-cortexm-1.10.0 (May 17 2013 - 16:09:15)

    CPU : SmartFusion®2 SoC (Cortex-M3 Hard IP)
    Freqs: CORTEX-M3=166MHz,PCLK0=83MHz,PCLK1=83MHz
    Board: SF2-DEV-KIT Rev 1.0, Microsemi
    DRAM: 256 MB
    In: serial
    Out: serial
    Err: serial
    Hit any key to stop autoboot: 0
    SF2-DEV-KIT>
    SF2-DEV-KIT>

  3. Roll back the changes we've made:
  4. SF2-DEV-KIT> print bootargs
    bootargs=m2s_platform=sf2-dev-kit console=ttyS1,115200 panic=10 lpj=776192 quiet=quiet
    SF2-DEV-KIT> setenv bootargs m2s_platform=sf2-dev-kit console=ttyS1,115200 panic=10
    SF2-DEV-KIT> setenv bootdelay 3
    SF2-DEV-KIT> setenv verify
    SF2-DEV-KIT> savee
    Saving Environment to SPI Flash...
    Erasing SPI flash...Writing to SPI flash...done
    SF2-DEV-KIT>