6. Compilation of Linux kernel

6.1. Why compile the Kernel yourself?

Although the kernel we provide already supports most functions, some customers who need customized functions may not necessarily have the functional configuration they need. So this chapter will explain how to configure and compile the kernel.

6.2. Get kernel

6.2.1. Download source code

There are three ways to obtain the Kernel source code, one is the official Kernel source code, the other is the official RockChip kernel source code, and the other is the kernel source code that we have modified to adapt to our board. We use the source code we provide as an example here. Friends who are interested in the official source code can also download it to learn configuration.

Our kernel is customized based on the kernel officially provided by Rockchip. Rockchip’s kernel is chip adapted based on the official LTS (long-term support) version of the kernel. As embedded developers, we generally only need to use the kernel adapted by the chip manufacturer for development. This is what chip manufacturers do to download new versions from the official kernel to adapt.

Currently LubanCat-RK356x-Linux-SDK uses kernel version 4.19. LubanCat-RK3588-Linux-SDK uses kernel version 5.10.

Since the launch of rk356x/rk3588 was not very long ago, Rockchip has submitted fewer official adaptations to the kernel. As a result, many functions of the chip have not been implemented, so currently we can only use Rockchip’s older kernel version.

Kernel official kernel source code: https://www.kernel.org/

Rockchip kernel source code: https://github.com/rockchip-linux/kernel/

LubanCat kernel source code: https://github.com/LubanCat/kernel

Use what we provide

1
2
3
4
5
# LubanCat-RK356x
git clone -b stable-4.19-rk356x https://github.com/LubanCat/kernel

# LubanCat-RK3588
git clone -b develop-5.10 https://github.com/LubanCat/kernel

6.3. Kernel engineering structure analysis

To learn a software, especially open source software, you should first start by analyzing the engineering structure of the software. A good software has a good engineering structure, which is very helpful for readers to learn and understand the software’s architecture and workflow.

The kernel source code directory is as follows:

arch         COPYING        drivers   init     kernel       make_deb.sh  README    sound
block        CREDITS        firmware  ipc      lib          Makefile     samples   tools
build_image  crypto         fs        Kbuild   LICENSES     mm           scripts   usr
certs        Documentation  include   Kconfig  MAINTAINERS  net          security  virt

We can see that there are many directories in the Linux kernel source code directory, and there are also many files in the directories. Let’s briefly analyze the main functions of these directories.

arch : Mainly contains code related to hardware architecture, such as arm, x86, MIPS, and PPC. Each CPU platform occupies a corresponding directory. Stored in the arch directory are the support for Linux kernel process scheduling, memory management, interrupts, etc. of each platform and chip on each platform, as well as the board-level support code for each specific SoC and circuit board.

block : In Linux, block represents a block device (accessed as a whole in units of blocks (a whole composed of multiple bytes, similar to sectors)). For example, SD cards, Nands, hard disks, etc. are all block devices. The block directory contains some code for block device management in the Linux storage system.

crypto : This directory stores commonly used encryption and hashing algorithms (such as md5, AES, SHA, etc.), as well as some compression and CRC verification algorithms.

Documentation: Document description of each part of the kernel.

drivers : Device driver, which lists the driver source codes of all hardware devices supported by the Linux kernel. Each different driver occupies a subdirectory, such as char, block, net, mtd, i2c, etc.

fs : fs is file system, which contains various file systems supported by Linux, such as EXT, FAT, NTFS, JFFS2, etc.

include : The directory includes most of the header files needed to compile the core. For example, platform-independent header files are in the include/linux subdirectory, and header files related to the CPU architecture are in the corresponding subdirectory of the include directory.

init : Kernel initialization code. The code in this directory is the code that initializes the kernel when the Linux kernel starts.

ipc : ipc is inter process communication. This directory contains codes for linux inter-process communication.

kernel : Kernel is the Linux kernel, which is the core part of Linux, including process scheduling, timers, etc., and some code related to the platform is placed in the arch/*/kernel directory.

lib :lib means library. The lib directory stores some commonly used and useful library functions. Note that the library functions here are different from the C language library functions, because the C language standard library functions cannot be used in kernel programming. Therefore, you need to use library functions in lib. In addition, the library function codes related to the processor structure are placed in the arch/*/lib/ directory.

mm : Directory contains all memory management code that is independent of the CPU architecture, such as page storage management memory allocation and release, etc. The memory management code related to the specific hardware architecture is located in the arch/*/mm directory, such as arch/arm/mm/fault.c.

net : Network protocol stack related codes, implementing various common network protocols in the net directory.

scripts : All script files in this directory are not used when the Linux kernel works, but are used to configure and compile the Linux kernel.

security : Code related to the kernel security model, such as the most famous SELINUX.

sound : Driver core code and common device drivers for ALSA and OSS audio devices.

usr : Implement cpio for packaging and compression, etc.

Just some common directories are listed here.

6.4. Kernel configuration options

提示

This section requires entering commands, which must be performed in the kernel directory.

6.4.1. Configure kernel options and use LubanCat board configuration

The configuration files used in different versions of the kernel and different series of Lubancat boards are saved in arch/arm64/configs in the kernel directory. The specific configuration files used are as follows:

  • Kernel 4.19: LubanCat-RK356x series boards are usedlubancat2_defconfig

  • Kernel 5.10: LubanCat-RK356x series boards are usedlubancat_rk356x_linux_defconfig

  • Kernel 5.10: LubanCat-RK3588 series boards are usedlubancat_rk3588_linux_defconfig

The following uses the LubanCat-2 board as an example for explanation.

The Linux kernel configuration system consists of three parts, namely:

  • Makefile: distributed in the Linux kernel source code root directory and directories at each level, defining the compilation rules of the Linux kernel;

  • Configuration file: Provides users with the function of configuration selection. For example, the Kconfig file defines configuration items. When compiling, use the arch/arm64/configs/lubancat2_defconfig file to assign values to configuration items;

Configuration tools: including configuration command interpreter (interprets the configuration commands used in the configuration script) and configuration user interface (Linux provides character-based interface, Ncurses-based graphical interface and user configuration interface based on the Xwindows graphical interface, corresponding to make config, make menuconfig and make xconfig respectively).

注意

If you customize the configuration file, you must modify the definition of RK_KERNEL_DEFCONFIG in the device/rockchip/rk356x/BoardConfig.mk file corresponding to the board when compiling.

We can view our configuration through the make menuconfig KCONFIG_CONFIG=arch/arm64/configs/lubancat2_defconfig ARCH=arm64 command. “make menuconfig” is a configuration interface based on text selection and is recommended for use in a character terminal. And this configuration file is lubancat2_defconfig. At this point you can see the configuration selection in lubancat2_defconfig. You can select and configure through the keyboard’s “up”, “down”, “left”, “right”, “enter”, “space”, “?”, “ESC” and other keys. For details, see:

1
2
3
4
5
# Using the graphical interface configuration requires additional installation of libncurses-dev
sudo apt install libncurses-dev

# Excuting an order
make menuconfig KCONFIG_CONFIG=arch/arm64/configs/lubancat2_defconfig ARCH=arm64
building_kernel002

For example, we choose to configure the ov5648 camera driver of the board: ov5648. If you cannot find this configuration option, you can use the search function in make menuconfig. Press “/” in the English input method state. Then you can enter “ov5648” to find the location of configuration options. When typing a mistake, you can use Ctrl+Backspace to delete the input. For details :

building_kernel003
building_kernel004

From the picture, it is obvious that the configuration options of ov5648 are located in -> Device Drivers ~ -> Multimedia support (MEDIA_SUPPORT [=y])``~-> I2C Encoders, decoders , sensors and other helper chips`` In fact, you can also press "1" to directly navigate to the corresponding option. Then select the following content, see the picture for details:

building_kernel005

You can use the y, n, m keys to change the configuration of the ov5648 driver. Among them, y means compiled into the kernel, m means compiled into a module, and n means not compiled. You can also use spaces to select configuration options for the ov5648 driver.

The same goes for configuring other drivers.

After the modification is completed, we save and exit, and then use the following command to save the defconfig file and overwrite the original configuration file

1
2
3
4
5
# Save defconfig file
make savedefconfig ARCH=arm64

# Overwrite the original configuration file
cp defconfig arch/arm64/configs/lubancat2_defconfig

6.5. Kernel compilation

提示

The operations that require entering commands in this section must be performed in the root directory of the SDK.

In LubanCat-SDK, automatic compilation scripts are basically stored in build.sh, which is the main function entrance of the SDK.

There are two ways to compile the kernel. One is the rk standard boot partition, called the rkboot partition, and the other is the Embedfire-modified extboot partition.

The rkboot partition is packaged in binary form, and the addresses stored in each part are strictly defined. When reading a file, the binary file header is used to determine the type of file. Currently, the LubanCat board has stopped supporting it.

The extboot partition we modified stores files in ext4 format, which is readable and modifiable in the system, greatly increasing convenience. Based on this, we added the functions of online updating the kernel version, modifying the device tree plug-in, and switching the main device tree to the extboot partition system. Finally, we realized a mirror function that can be used for all LubanCat boards using the same model of processor.

6.5.1. extboot partition compilation

Because when packaging the extboot partition, the kernel deb package will be packaged. Therefore, before building the extboot partition image, we must first proceed to the next step to build the kernel deb package.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
function build_extboot(){
    check_config RK_KERNEL_DTS RK_KERNEL_DEFCONFIG || return 0

    echo "============Start building kernel============"
    echo "TARGET_ARCH          =$RK_ARCH"
    echo "TARGET_KERNEL_CONFIG =$RK_KERNEL_DEFCONFIG"
    echo "TARGET_KERNEL_DTS    =$RK_KERNEL_DTS"
    echo "TARGET_KERNEL_CONFIG_FRAGMENT =$RK_KERNEL_DEFCONFIG_FRAGMENT"
    echo "=========================================="
    pwd

    build_check_cross_compile

    cd kernel
    make ARCH=$RK_ARCH $RK_KERNEL_DEFCONFIG $RK_KERNEL_DEFCONFIG_FRAGMENT
    make ARCH=$RK_ARCH $RK_KERNEL_DTS.img -j$RK_JOBS
    make ARCH=$RK_ARCH dtbs -j$RK_JOBS

    echo -e "\e[36m Generate extLinuxBoot image start\e[0m"

    KERNEL_VERSION=$(cat $TOP_DIR/kernel/include/config/kernel.release)

    EXTBOOT_IMG=${TOP_DIR}/kernel/extboot.img
    EXTBOOT_DIR=${TOP_DIR}/kernel/extboot
    EXTBOOT_DTB=${EXTBOOT_DIR}/dtb/

    rm -rf $EXTBOOT_DIR
    mkdir -p $EXTBOOT_DTB/overlay
    mkdir -p $EXTBOOT_DIR/uEnv
    mkdir -p $EXTBOOT_DIR/kerneldeb

    cp ${TOP_DIR}/$RK_KERNEL_IMG $EXTBOOT_DIR/Image-$KERNEL_VERSION

    if [ "$RK_ARCH" == "arm64" ];then
        cp ${TOP_DIR}/kernel/arch/${RK_ARCH}/boot/dts/rockchip/*.dtb $EXTBOOT_DTB
        cp ${TOP_DIR}/kernel/arch/${RK_ARCH}/boot/dts/rockchip/overlay/*.dtbo $EXTBOOT_DTB/overlay
        cp ${TOP_DIR}/kernel/arch/${RK_ARCH}/boot/dts/rockchip/uEnv/uEnv*.txt $EXTBOOT_DIR/uEnv
    else
        cp ${TOP_DIR}/kernel/arch/${RK_ARCH}/boot/dts/*.dtb $EXTBOOT_DTB
        cp ${TOP_DIR}/kernel/arch/${RK_ARCH}/boot/dts/overlay/*.dtbo $EXTBOOT_DTB/overlay
    fi
    cp -f $EXTBOOT_DTB/${RK_KERNEL_DTS}.dtb $EXTBOOT_DIR/rk-kernel.dtb

    if [[ -e ${TOP_DIR}/kernel/ramdisk.img ]]; then
        cp ${TOP_DIR}/kernel/ramdisk.img $EXTBOOT_DIR/initrd-$KERNEL_VERSION
        echo -e "\tinitrd /initrd-$KERNEL_VERSION" >> $EXTBOOT_DIR/extlinux/extlinux.conf
    fi

    cp ${TOP_DIR}/kernel/.config $EXTBOOT_DIR/config-$KERNEL_VERSION
    cp ${TOP_DIR}/kernel/System.map $EXTBOOT_DIR/System.map-$KERNEL_VERSION
    cp ${TOP_DIR}/kernel/logo.bmp $EXTBOOT_DIR/

    cp ${TOP_DIR}/linux-headers-"$KERNEL_VERSION"_"$KERNEL_VERSION"-*.deb $EXTBOOT_DIR/kerneldeb
    cp ${TOP_DIR}/linux-image-"$KERNEL_VERSION"_"$KERNEL_VERSION"-*.deb $EXTBOOT_DIR/kerneldeb

    rm -rf $EXTBOOT_IMG && truncate -s 128M $EXTBOOT_IMG
    fakeroot mkfs.ext4 -F -L "boot" -d $EXTBOOT_DIR $EXTBOOT_IMG

    finish_build
}
  1. check_config checks whether the configuration file exists

  2. build_check_cross_compile sets cross-compilation parameters

  3. Application-defined kernel configuration file

  4. Compile the kernel image

  5. Compile device tree

  6. Create the EXTBOOT_DIR temporary folder to store the files used to generate the boot partition

  7. Copy the kernel image, device tree file, device tree plug-in, and uEnv environment variable file

  8. Determine whether to add ramdisk image

  9. Copy the startup logo, kernel configuration file, System.map, and kernel deb package

  10. Package the files in the EXTBOOT_DIR folder to extboot.img in ext4 format

In the subsequent steps, extboot.img will be soft linked to rockdev/boot.img

6.6. Build kernel deb package

When we run make bindeb-pkg in the kernel, up to 5 Debian software packages will be generated. In LubanCat-SDK, we can directly use the following commands to build them.

1
./build.sh kerneldeb

Its build script is as follows

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
./build.sh kerneldeb

function build_kerneldeb(){
    check_config RK_KERNEL_DTS RK_KERNEL_DEFCONFIG || return 0

    build_check_cross_compile

    echo "============Start building kernel deb============"
    echo "TARGET_ARCH          =$RK_ARCH"
    echo "TARGET_KERNEL_CONFIG =$RK_KERNEL_DEFCONFIG"
    echo "TARGET_KERNEL_DTS    =$RK_KERNEL_DTS"
    echo "TARGET_KERNEL_CONFIG_FRAGMENT =$RK_KERNEL_DEFCONFIG_FRAGMENT"
    echo "=========================================="
    pwd
    cd kernel
    make ARCH=$RK_ARCH $RK_KERNEL_DEFCONFIG $RK_KERNEL_DEFCONFIG_FRAGMENT
    make ARCH=$RK_ARCH bindeb-pkg RK_KERNEL_DTS=$RK_KERNEL_DTS -j$RK_JOBS
    finish_build
}
  1. Check_config checks whether the configuration file exists

  2. Build_check_cross_compile sets cross-compilation parameters

  3. Application-defined kernel configuration file

  4. Compile the kernel deb package

The generated software package is as follows:

  • linux-image-version: Generally includes kernel image and kernel module, we also added device tree and device tree plug-in

  • linux-headers-version: includes header files required to create external modules

  • linux-firmware-image-version: includes firmware required by some drivers (not generated here)

  • linux-image-version-dbg: adds debug symbols based on linux-image-version

  • linux-libc-dev: includes headers related to user libraries such as GNU glibc

提示

version is the kernel version

Among them, the most important ones we use are linux-image and linux-headers, and linux-firmware can be installed through the network.

By installing linux-headers, we can install the gcc compiler directly on the board for local compilation. Please see the application deployment chapter for specific usage methods.

By installing linux-image, you can update the kernel image, device tree, device tree plug-in, and kernel module.

6.6.1. Installation of kernel deb package

We copy the generated deb package to the board running Ubuntu or Debian image through a USB storage device or network, and use the following command to install the package.

错误

Be careful not to cut off the power during the update, otherwise the system may be damaged and unable to start.

1
2
3
4
5
6
7
# The kernel is version 4.19
sudo dpkg -i linux-headers-4.19.xxx_4.19.xxx-xxx_arm64.deb
sudo dpkg -i linux-image-4.19.xxx_4.19.xxx-xxx_arm64.deb

# The kernel is version 5.10
sudo dpkg -i linux-headers-5.10.xxx_5.10.xxx-xxx_arm64.deb
sudo dpkg -i linux-image-5.10.xxx_5.10.xxx-xxx_arm64.deb

注解

When installing a local deb package, run the above command in the directory where the deb package is located. xxx is the actual number corresponding to the deb package.

Wait for the deb package to be installed and then restart to complete the kernel update.

In addition to using the deb package directly for local updates, you can also use the Embedfire software source for online updates.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
sudo apt update

# Update all packages to be updated
sudo apt upgrade

# Only update linux-image and linux-headers
# The kernel is version 4.19.232
sudo apt install linux-image-4.19.232
sudo apt install linux-headers-4.19.232

# The kernel is version 5.10.160
sudo apt install linux-image-5.10.160
sudo apt install linux-headers-5.10.160

After the upgrade is completed, restart the board to complete the kernel update.