Build Linux Kernel from Source Code
Introduction
This article describes how to build the Linux kernel without using a higher-level build system such as the Yocto Project/OpenEmbedded. This procedure mostly makes sense during Linux development.
We provide OpenEmbedded recipes that build U-Boot and Linux as part of a complete BSP image. If you plan to build a full BSP image, follow the Build a Reference Image with Yocto Project/OpenEmbedded article.
This is the second article of a three-part series about building from source code. Check the following articles if you are looking for information about:
Prerequisites
- Understand the basic concepts of Toradex Embedded Linux offerings, such as release cycles, distributions and images. This content is available at BSP Layers and Reference Images for Yocto Project Software.
- Follow the steps described in the article Build U-Boot from Source Code (optional).
- Follow the steps in the section Install the GNU Toolchain for Hard Float Calling Convention.
- Install the necessary tools and dependencies as explained in the section Install Tools and Dependencies.
Prepare the Host Machine for Cross-Compilation
Use version 9.2 or higher of the Arm releases binary toolchains to cross-compile software for Toradex modules:
- For 32 bit Arm: arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz
- For 64 bit Arm: arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
You have to choose to download either the 32 bit or 64 bit Arm cross-toolchain, according to the architecture of your System on Module SoC. Select the correct one from the tabs below:
To install the toolchain on your host machine, download and unpack the tar.xz file. From the command-line:
$ cd ~
$ wget -O arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz "https://developer.arm.com/-/media/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz?rev=9d73bfdd64a34550b9ec38a5ead7c01a&hash=774AAE1A6D6996CFB89FD7E367C0B59B"
$ tar xvf arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz
$ ln -s arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-linux-gnueabihf gcc-linaro
Or you can download the toolchain from Arm website.
The U-Boot and Linux makefiles use the environment variables ARCH/CROSS_COMPILE to configure and call the compiler correctly. Therefore, these environment variables must be exported in any shell instance that will run configure/compile commands to build U-Boot or Linux for the target module.
$ export ARCH=arm
$ export DTC_FLAGS="-@"
$ export PATH=~/gcc-linaro/bin/:$PATH
$ export CROSS_COMPILE=arm-none-linux-gnueabihf-
You can put those commands into a file and source that file to export it more easily, e.g.:
$ echo "export ARCH=arm" >> ~/export_compiler
$ echo "export DTC_FLAGS='-@'" >> ~/export_compiler
$ echo "export PATH=~/gcc-linaro/bin/:$PATH" >> ~/export_compiler
$ echo "export CROSS_COMPILE=arm-none-linux-gnueabihf-" >> ~/export_compiler
$ source ~/export_compiler
To install the toolchain on your host machine, download and unpack the tar.xz file. From the command-line:
$ cd ~
$ wget -O arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz "https://developer.arm.com/-/media/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=cf8baa0ef2e54e9286f0409cdda4f66c&hash=4E1BA6BFC2C09EA04DBD36C393C9DD3A"
$ tar xvf arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
$ ln -s arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu gcc-linaro
Or you can download the toolchain from Arm website.
The U-Boot and Linux makefiles use the environment variables ARCH/CROSS_COMPILE to configure and call the compiler correctly. Therefore, these environment variables must be exported in any shell instance that will run configure/compile commands to build U-Boot or Linux for the target module.
$ export ARCH=arm64
$ export DTC_FLAGS="-@"
$ export PATH=~/gcc-linaro/bin/:$PATH
$ export CROSS_COMPILE=aarch64-none-linux-gnu-
You can put those commands into a file and source that file to export it more easily, E.g.:
$ echo "export ARCH=arm64" >> ~/export_compiler
$ echo "export DTC_FLAGS='-@'" >> ~/export_compiler
$ echo "export PATH=~/gcc-linaro/bin/:$PATH" >> ~/export_compiler
$ echo "export CROSS_COMPILE=aarch64-none-linux-gnu-" >> ~/export_compiler
$ source ~/export_compiler
Install Tools and Dependencies
Build Host
You need some essential build tools to compile the Kernel or DTC. Most are likely part of your distro's standard install.
$ sudo apt-get install bc build-essential git libncurses5-dev lzop perl libssl-dev bison flex
$ sudo dnf install bc gcc git ncurses-devel lzop make perl openssl-devel bison flex diffutils
U-Boot Tools
The uImage
target of the Linux kernel compilation needs a recent mkimage
tool.
One can install the u-boot-tools
package for Ubuntu or its corresponding version for Fedora, the uboot-tools
package.
Alternatively, mkimage tool is also built during the U-Boot compilation. You can follow the U-Boot building instructions as explained further in this article, and after that, include it in PATH.
Kernel Version Information
The required git branch and Linux binaries to be used depend on the module type and BSP version, as we will explain in this article.
For a high-level overview of the BSP Versions, check out our Embedded Linux Release Matrix. There, you will find the version information of the Linux kernel, U-Boot, Yocto/OpenEmbedded, the Toradex BSP, and Linux images, along with release dates.
The development of the Kernel is made in the master
branch for the upstream-based modules and the tags represent versioning checkpoints where we ensure the functioning of builds and features.
Upstream-based Kernel
SoC | Kernel Git Tag | Kernel Binary |
---|---|---|
NXP i.MX 8MM/8MP | v6.6.53 | arch/arm64/boot/Image.gz |
NXP i.MX 7 | v6.6.53 | arch/arm/boot/zImage |
NXP i.MX 6 | v6.6.53 | arch/arm/boot/zImage |
NXP i.MX 6ULL | v6.6.53 | arch/arm/boot/zImage |
Downstream-based Kernel
SoC | Kernel Git Branch | Kernel Configuration | Kernel Binary |
---|---|---|---|
NXP i.MX 8MM/8MP | toradex_6.6-2.0.x-imx | toradex_defconfig | arch/arm64/boot/Image.gz |
TI AM62x | toradex_ti-linux-6.6.y | toradex_defconfig | arch/arm64/boot/Image.gz |
TI AM69 | toradex_ti-linux-6.6.y | toradex_defconfig | arch/arm64/boot/Image.gz |
The meta-toradex-bsp-common
hashes for each BSP version to be used in the following steps are presented in the table below:
BSP Version | Hash |
---|---|
7.0.0 | 6cdf564762805ec382409a2ba23d33bcde5bec9f |
Device Tree Binaries Information
View the Device Tree information
SoC | Device Tree |
---|---|
i.MX 8/8MM/8MP | imx8qm-apalis-eval.dtb imx8qm-apalis-ixora-v1.1.dtb imx8qm-apalis-v1.1-eval.dtb imx8qm-apalis-v1.1-ixora-v1.1.dtb imx8qm-apalis-v1.1-ixora-v1.2.dtb imx8qp-apalis-v1.1-eval.dtb imx8qp-apalis-v1.1-ixora-v1.1.dtb imx8qp-apalis-v1.1-ixora-v1.2.dtb imx8mm-verdin-nonwifi-dahlia.dtb imx8mm-verdin-nonwifi-dev.dtb imx8mm-verdin-nonwifi-yavia.dtb imx8mm-verdin-wifi-dahlia.dtb imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-wifi-yavia.dtb imx8mp-verdin-nonwifi-dahlia.dtb imx8mp-verdin-nonwifi-dev.dtb imx8mp-verdin-nonwifi-yavia.dtb imx8mp-verdin-wifi-dahlia.dtb imx8mp-verdin-wifi-dev.dtb imx8mp-verdin-wifi-yavia.dtb |
i.MX 7 | imx7d-colibri-aster.dtb imx7d-colibri-emmc-aster.dtb imx7s-colibri-aster.dtb imx7d-colibri-eval-v3.dtb imx7d-colibri-emmc-eval-v3.dtb imx7s-colibri-eval-v3.dtb imx7d-colibri-iris.dtb imx7d-colibri-emmc-iris.dtb imx7s-colibri-iris.dtb imx7d-colibri-iris-v2.dtb imx7d-colibri-emmc-iris-v2.dtb imx7s-colibri-iris-v2.dtb |
i.MX 6 | imx6q-apalis-eval.dtb imx6q-apalis-ixora.dtb imx6q-apalis-ixora-v1.1.dtb imx6q-apalis-ixora-v1.2.dtb imx6dl-colibri-eval-v3.dtb imx6dl-colibri-aster.dtb imx6dl-colibri-iris.dtb imx6dl-colibri-iris-v2.dtb |
i.MX 6ULL | imx6ull-colibri-emmc-eval-v3.dtb imx6ull-colibri-eval-v3.dtb imx6ull-colibri-wifi-eval-v3.dtb imx6ull-colibri-emmc-aster.dtb imx6ull-colibri-aster.dtb imx6ull-colibri-wifi-aster.dtb imx6ull-colibri-emmc-iris.dtb imx6ull-colibri-iris.dtb imx6ull-colibri-wifi-iris.dtb imx6ull-colibri-emmc-iris-v2.dtb imx6ull-colibri-iris-v2.dtb imx6ull-colibri-wifi-iris-v2.dtb |
TI AM62 | k3-am625-verdin-wifi-dahlia.dtb k3-am625-verdin-wifi-dev.dtb k3-am625-verdin-wifi-yavia.dtb k3-am625-verdin-nonwifi-dahlia.dtb k3-am625-verdin-nonwifi-dev.dtb k3-am625-verdin-nonwifi-yavia.dtb |
TI AM69 | k3-am69-aquila-dev.dtb |
Building Linux Kernel
When building the kernel from source code for the Apalis iMX8, Colibri iMX8X, Verdin AM62, and Verdin iMX8M SoMs, the graphical driver deployed is different from the one built using the Toradex Linux BSP.
This can cause issues with graphical functionality in general. For example, Weston is likely to not work.
In order to obtain the same result as the Linux BSP, it is recommended to use the Yocto Project and the Linux BSP to build the kernel.
Download the Linux Kernel Source
Obtain the kernel source code using Git. Replace tag
or <branch>
by the Kernel Git Tag or Kernel Git Branch for specific configuration, according to your use case (upstream or downstream, respectively).
$ git clone -b <tag> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
$ cd linux
$ git clone -b <branch> git://git.toradex.com/linux-toradex.git
$ cd linux-toradex
The following section is only necessary if using an upstream-based module. If you are using a downstream-based module, please, go to the Kernel Configuration section.
Get and Apply the Patches (upstream only)
Create a
patches
folder on the linux directory. Although not mandatory, the patches directory help organize them. This directory will not show on git because it is in.gitignore
of Linux.$ mkdir ~/linux/patches
Get the patches from Toradex git in the BSP Common OE layer at meta-toradex-bsp-common.git - Toradex BSP layer - recipes common to all modules. The patches for Linux are located inside the folder meta-toradex-bsp-common/recipes-kernel/linux/linux-toradex-upstream. Fetch the layer with git and checkout it to the hash of the BSP release version and then copy the patches to Linux patches directory.
$ git clone https://git.toradex.com/cgit/meta-toradex-bsp-common.git
$ cd meta-toradex-bsp-common
$ git checkout <bsp-hash>
$ cp -r ../meta-toradex-bsp-common/recipes-kernel/linux/linux-toradex-upstream/* ../patchesApply the patches with
git am <patch files>
from patches directory. The patches must be applied in the correct order (check the TDX_PATCHES variable of this recipe) and the application should be clean (without any errors or conflicts).Note that you can apply multiple patches in a single command (keeping the correct order), as in the following example:
$ cd ~/linux/patches
$ git am [first-patch-file-name].patch \
[second-patch-file-name].patch \
[third-patch-file-name].patch \
[fourth-patch-file-name].patch \
[fifth-patch-file-name].patch \For a double check, use
git log --oneline
to see the patches commit messages.$ git log --oneline
In order to compile a device tree overlay, follow the Kernel Configuration and the Kernel Compilation section. These steps are intended to make sure the user will have the same kernel configuration as the Yocto recipes.
Kernel Configuration
The file that has all the configuration needed for Toradex SoMs is called kernel-config
and it is on the oedeploy
folder. This folder comes from the build output of a Toradex distro for a reference image. To get the correct file:
Go to the Artifacts repository: Toradex Artifact Repository Browser.
Navigate to tdxref-oe-prod-frankfurt/scarthgap-7.x.y/release. The
kernel-config
file can be downloaded directly from the Artifactory page. Just click on its name and the download button on the top right corner of the page. To find the right file:2.1 Select the specific build for the monthly/quarterly release for your BSP version.
2.2 Select your module, which might appear in a structure such as
<family>-<SoC>
(e.g.apalis-imx6
).2.3 Select the distro, which should be
tdx-xwayland-upstream
ortdx-xwayland
, for downstream-based modules.2.4 Select the reference image, which should be
tdx-reference-minimal-image
ortdx-reference-multimedia-image
.2.5 Go to
oedeploy
folder and download thekernel-config
file.As example, for BSP 7.0.0 using an apalis-imx6 module with tdx-xwayland-upstream distro and a tdx-reference-minimal-image: https://artifacts.toradex.com:443/artifactory/tdxref-oe-prod-frankfurt/scarthgap-7.x.y/release/1/apalis-imx6/tdx-xwayland-upstream/tdx-reference-minimal-image/oedeploy/kernel-config.
Go to the folder where the downloaded
kernel-config
file is located and copy it to the Linux root source folder and change its name to.config
. Also, usemake olddefconfig
to validate your configuration and let Linux set the defaults for the new configuration not on thekernel-config
file.$ cp kernel-config ~/linux && cd ~/linux
$ mv kernel-config .config
$ make olddefconfig$ cp kernel-config ~/linux-toradex && cd ~/linux-toradex
$ mv kernel-config .config
$ make olddefconfig
Kernel Compilation
Depending on the SoM, different kernel image types are used. Furthermore, some kernels require a device tree to describe the system's hardware (see Device Tree Customization for details). Our kernel configurations build some drivers as kernel modules.
To assure module compatibility, the Kernel refuses to load modules with a 'vermagic' string that does not match its own. On top of that, the modules are stored under a directory named after the version string. Thus, one usually needs to compile and deploy the kernel modules together with the Kernel in order to use them.
Follow the steps for your specific SoM to compile the kernel & device tree. Replace <device-tree>
by the Device Tree binary for your specific configuration.
$ make -j$(nproc) Image.gz 2>&1 | tee build.log
$ make DTC_FLAGS="-@" freescale/<device-tree>.dtb
$ ls ./arch/arm64/boot/Image.gz
$ ls ./arch/arm64/boot/dts/freescale/<device-tree>.dtb
$ make -j$(nproc) Image.gz 2>&1 | tee build.log
$ make DTC_FLAGS="-@" ti/<device-tree>.dtb
$ ls ./arch/arm64/boot/Image.gz
$ ls ./arch/arm64/boot/dts/ti/<device-tree>.dtb
$ make -j$(nproc) Image.gz 2>&1 | tee build.log
$ make DTC_FLAGS="-@" ti/<device-tree>.dtb
$ ls ./arch/arm64/boot/Image.gz
$ ls ./arch/arm64/boot/dts/ti/<device-tree>.dtb
$ make -j$(nproc) zImage 2>&1 | tee build.log
$ make DTC_FLAGS="-@" <device-tree>.dtb
$ ls ./arch/arm/boot/zImage
$ ls ./arch/arm/boot/dts/<device-tree>.dtb
The Linux kernel for our i.MX7 based modules can show linking issues when using the gold linker:
arm-angstrom-linux-gnueabi-ld: --pic-veneer: unknown option
arm-angstrom-linux-gnueabi-ld: use the --help option for usage information
The recommended solution is to just revert to using the regular bfd linker as follows:
$ make -j$(nproc) zImage LD=${CROSS_COMPILE}ld.bfd | tee build.log
To compile the kernel & device tree for BSP 2.8b2 or newer:
$ make -j$(nproc) zImage LOADADDR=10008000 2>&1 | tee build.log
$ make DTC_FLAGS="-@" <device-tree>.dtb
$ ls ./arch/arm/boot/zImage
$ ls ./arch/arm/boot/dts/<device-tree>.dtb
To compile the kernel & device tree:
$ make -j$(nproc) zImage 2>&1 | tee build.log
$ make DTC_FLAGS="-@" <device-tree>.dtb
$ ls ./arch/arm/boot/zImage
$ ls ./arch/arm/boot/dts/<device-tree>.dtb
To compile the kernel & device tree for BSP 2.8 or older:
The Linux kernel for our i.MX 6ULL based modules can show linking issues when using the gold linker:
arm-angstrom-linux-gnueabi-ld: --pic-veneer: unknown option
arm-angstrom-linux-gnueabi-ld: use the --help option for usage information
The recommended solution is to just revert to using the regular bfd linker as follows:
$ make -j$(nproc) zImage LD=${CROSS_COMPILE}ld.bfd | tee build.log
Deploying the Kernel to an Image
Follow the steps below to update your Kernel using Toradex Easy Installer.
Start from a Existing Sample Image: Download and extract one of the Toradex prebuilt images. Choose the appropriate image for your SoM in the Reference Images for Yocto Project Software Downloads
Integrate Artifacts: Integrate the above-built artifacts into the downloaded embedded Linux image by replacing the kernel binary (
Image.gz
) and device tree(s) (<device-tree>.dtb
) in the extracted folder from thebootfs.tar.xz
file. After doing it, make sure to select all the files inside the folder and compress them with the same name and format as the previousbootfs.tar.xz
file. Then, replace the newbootfs.tar.xz
file with the previous one.In case of using a Colibri iMX7 NAND version or a Colibri iMX6ULL NAND version, replace the
zImage
and the<device-tree>.dtb
binaries directly in the downloaded embedded Linux image folder.Adjust
image.json
: Now adjust theimage.json
to your linking (e.g., change at least the name and description for you to distinguish it from our original package). You may, of course, also change any of the other properties as documented in the Toradex Easy Installer article on our developer website.Deploy the Toradex Easy Installer Image: You may now use the above prepared Toradex Easy Installer package with the Toradex Easy Installer.
Linux Kernel Module Compilation and Deployment
To compile the kernel modules as configured in
.config
(everything withCONFIG_*=m
), run:$ make -j$(nproc) modules
Keep in mind that if you compile and/or use a new kernel, you should update the kernel modules as well because they often have strong dependencies to a specific kernel build.
Extract the kernel modules into a temporary folder, after which the kernel modules must be separately installed on the target as follows:
$ mkdir modules
$ export INSTALL_MOD_PATH=modules
$ make modules_install
$ cd modules
$ tar -czf ../modules.tar.gz .Copy the tarball into your target. You can use
scp
, such as in the example:$ scp modules.tar.gz root@<target-ip>:/home/root
In your target's Linux Terminal, extract the tarball in the rootfs as follows:
# cd ~
# tar -xzf modules.tar.gz -C /Run
depmod
on the target after the deployment of the new (or changed) kernel modules.You may also integrate your kernel modules into the root file system archive inside a Toradex Easy Installer package where applicable. The Kernel and any kernel modules must be deployed as matching versions.