This is the second part of a series of posts, so before start reading, check the first part here.
In this part we'll compile the Linux Kernel and generate a root filesystem to boot up our SoC with a complete system. Until this step, we just create hardware/boot files and nothing refers about the Linux exactly. Now we'll use a recipe with buildroot to create a complete rootfs that'll be loaded by our kernel.
The Linux (Kernel)
The Kernel Linux mainline has a lot of different options to set up but as we're using a embedded device, we wouldn't need to enable all kind of features and if we disable we can save space in the SD card. As we're using an ARM processor as our target, Altera has created a special blend of features directly for the SoC so, we'll get the official repository with the major changes for its targets.
cd ~/ex_codesign/sw/linux git clone https://github.com/altera-opensource/linux-socfpga.git kernel #This can take some time... cd kernel
Now, find the tag of the latest releases so we can checkout for a stable version of the kernel:
git tag -l rel_socfpga* git checkout rel_socfpga-4.9.78-ltsi_18.07.02_pr #Check your repository for the latest, in my case I went with this one
To check the default options set for the Cyclone V devices go into:
To start configuring the kernel follow the commands below:
export CROSS_COMPILE=arm-linux-gnueabihf- make ARCH=arm socfpga_defconfig make ARCH=arm menuconfig
Set all the options as the images below to enable loadup of different kernel modules and support for ext4 fs. More details check this link. Enter in General Setup sub-menu and uncheck the option Automatically append version.... and enable the uselib syscall:
Enter in the the block layer sub-menu and enable the option Support for large (.....:
Remember to save the configurations before leave, once up it's done, compile the Kernel (it'll take some time to finish). TIP: If you had some problems to configure exactly you could check this link that has my .config file for the Kernel Linux.
make ARCH=arm LOCALVERSION= zImage #There's a blank space between the LOCALVERSION variable because we don't want to make anything that we've been set wrong in the sources goes with our image
The zImage argument specifies that we want the compressed version of the Kernel that's self-extracting. All the procedure takes thirty minutes to finishing depending your computer configuration.
Now backup the file in our folder structure with:
cp arch/arm/boot/zImage ../../../sd/fat32/
The root filesystem (BusyBox)
The BusyBox is a software that has a lot of different UNIX utilities (GNU fileutils, shellutils, etc) compressed into one piece of software for small and embedded devices. It provides a complete environment for embedded devices with constrained resources like RAM memory and small footprint processors.
BusyBox has been written with size-optimization and limited resources in mind. It is also extremely modular so you can easily include or exclude commands (or features) at compile time. This makes it easy to customize your embedded systems.
Ubuntu rootfs alternative
If you want to use a ready rootfs compiled for our target, check this version of ubuntu 18.04 ready to be deployed in a ARM A9 target. This skip the next procedures of generation of rootfs with buildroot/busybox.
The master tool (BuildRoot)
Buildroot is a tool that simplifies and automates the process of building a complete Linux system for an embedded system, using cross-compilation.
These are words from the official manual of Builroot, so you can easily understand that this set of tools help us to construct the rootfs. With Buildroot we can generate a cross-compilation toolchain, a root filesystem, a Linux kernel image and also the bootloader for our target. Also it's recommend for users that works with embedded system with different set of processors such as ARM, RISC-V, PowerPC, etc...
According to the this link you build the rootfs by three different ways:
- Create along a well-know distro like debian, fedora based;
- Build each component of the rootfs handmade;
- Automated build systems like BuildRoot, OpenEmbedded, Yocto and BitBake;
To create our rootfs we'll the third option, using BuildRoot as our guide to the system. We could also generate the cross-toolchain, bootloader and other things with automated tools, but as we want to make it simple, we'll build just the rootfs.
cd ~/ex_codesign/sw/linux git clone git://git.buildroot.net/buildroot git checkout 2018.05.1 #Check which is your latest version to checkout (git tag -l)
Now, locate where you have been installed the arm-linux cross toolchain to pass it as an argument to the buildroot makefile.
Open the menu to configure:
cd buildroot make nconfig
Once up the menu appears, set the following options as:
- Target Architecture: ARM (little endian)
- Target Architecture Variant: cortex-A9
- Enable NEON SIMD extension support (NEW): Enable
- Enable VFP extension support (NEW): Enable
- Target ABI: EABIhf
- Floating point strategy: NEON
In the toolchain path option, set the path for the cross toolchain:
- Toolchain type: External toolchain
- Toolchain path: PATH OF arm-linux-gnueabihf
- Toolchain prefix: arm-linux-gnueabihf
- External toolchain gcc version: 6.x (check yours)
- External toolchain kernel headers series: 4.6 (check yours)
- External toolchain C library: glibc/eglibc
- Enable MMU support: Enable
- Copy gdb server to the Target (NEW): Enable
Go to the System configuration tab and define a root password like me (ex.:helloworld):
Also, insert the ethernet adapter eth0 of your device to enable DHCP service automatically when it boot it up. Press F6 to save the configurations and exit. TIP: If you had some problems to configure exactly you could check this link that has my .config file for the BuildRoot. I didn't uploaded the BusyBox configuration because it's the default mode.
If you want to customize the set of UNIX tools of busybox just type:
Then start the build process of the rootfs with the following commands:
export CROSS_COMPILE=arm-linux-gnueabihf- make #wait zzzzzZZZZZ...
The process should take no longer than 30 to 45 minutes to end, so grab a cup of coffee and wait for it. Once up it's finished just copy to the correspondent folder:
cp output/images/rootfs.tar ../../../sd/ext3/
Now you should have the following files in each folder:
Some file missing? Type in the comments section that I'll try to find what happened. With everything ok, go ahead with the creation of our SD card.
Now we need to create the SD card with all the files that we've been generating until this momment. First, select the SD card and insert it into the Linux host PC for the creation of the partition table.
sudo dmesg | tail #Check the correct unit of your SD card usually it's sdb sudo dd if=/dev/zero of=/dev/sdb bs=512 count=1 #Clean the SD card sudo fdisk /dev/sdb #Type each option in the order and press ENTER n p 3 <default> 4095 t a2 n p 1 <default> +32M t 1 b n p 2 <default> +512M t 2 83 w sudo mkfs.vfat /dev/sdb1 sudo mkfs.ext3 -F /dev/sdb2
You must have now a device like this:
By now, copy back each set of files to the correspondent folder:
cd ~/ex_codesign/sd sudo dd if=a2/preloader-mkpimage.bin of=/dev/sdb3 bs=64K cp fat32/* /media/$USER/FAT32_MOUNTED_PARTITION/ sudo tar -xvf ext3/rootfs.tar -C /media/$USER/EXT3_MOUNTED_PARTITION/ sync
Testing into the hardware
To observe the output of the system, connect a mini-usb cable at the connector J4 (UART) then open the terminal with the configuration of 8-N-1, you can use any serial-term that you're comfortable with.
In the end you must have the SPL booting, then the u-boot bootloader that'll load the Linux Kernel and then the rootfs, as in the image below:
And in the DE10 board you'll see just the first LED blinking at 2Hz as we expect from the first part post.
Do not forget to share/subscribe if you liked this post and check the third part of this series of posts in the blog page =).
Bash script for SD Card
#!/bin/bash sdcard="/dev/sdb" sdcard_fat32="/dev/sdb1" sdcard_ext3="/dev/sdb2" sdcard_a2="/dev/sdb3" pathsd="/home/anderson/projects/ex_codesign" echo "FORMATTING SD CARD...." sudo dd if=/dev/zero of=$sdcard bs=512 count=3 (echo n; echo p; echo 3; echo ; echo 4095; echo t; echo a2; \ echo n; echo p; echo 1; echo ; echo +32M; echo t; echo 1; echo b; \ echo n; echo p; echo 2; echo ; echo +512M; echo t; echo 2; echo 83; echo w;) | sudo fdisk $sdcard; sudo mkfs.vfat $sdcard_fat32; sudo mkfs.ext3 -F $sdcard_ext3; sync echo "COPYING SOURCES..." sudo dd if=$pathsd/sd/a2/preloader-mkpimage.bin of=$sdcard_a2 bs=64K sudo dd if=$pathsd/sd/fat32/soc_system.rbf of=$sdcard_fat32 sudo dd if=$pathsd/sd/fat32/u-boot.img of=$sdcard_fat32 sudo dd if=$pathsd/sd/fat32/u-boot.scr of=$sdcard_fat32 sudo dd if=$pathsd/sd/fat32/zImage of=$sdcard_fat32 sudo tar -xvf $pathsd/sd/ext3/rootfs.tar | sudo dd of=$sdcard_ext3 sync
- Tutorial with all the steps to generate the harware/linux distribution
- Latest post about Cyclone V
- Terasic download page for DE10-Nano
- Tutorial by bitlog of how to build a custom design
- Tutorial by EPFL university with the complete flow of development, even the bare-metal option in the HPS
- Customization of bootloader
- Buildroot Manual
- Linaro cross-toolchain