Building Linux Kernel

Here we'll discuss working with the Linux kernel and Timesys tools. The focus of this document is to familiarize you with how to build the Linux kernel for your embedded system within Timesys' Desktop Factory buildsystem (Building the Linux kernel with Desktop Factory). You can also find information here on Building the Linux kernel with TimeStorm (Timesys' Eclipse-based IDE), as well as general steps for Building the Linux kernel manually with a Timesys-provided cross-toolchain.

Typically, building the Linux kernel for an embedded board involves the following:
  1. Setting a Cross-Toolchain
  2. Obtaining and patching sources
  3. Configuring kernel
  4. Building the kernel
    1. Cross-compiling kernel image
    2. Cross-compiling kernel modules
    3. Installing modules
    4. Generating dtb (if necessary)

To complete these tasks, three things are necessary: patched Linux kernel sources, Linux kernel configuration file, and cross-compilation toolchain (or cross-toolchain). These three items can be obtained/generated by Factory directly, provided by a Factory-generated SDK installer, or obtained elsewhere.

Building Linux kernel as part of the BSP/SDK

The following (run from the top-level of your configured Factory directory) will build the BSP/SDK defined in the Factory workorder, completing the steps outlined above:

make

With this, Factory builds the entire BSP/SDK (or whichever portions of it have not been completed), including the Linux kernel (see Building the Linux kernel with Desktop Factory for more info).

For more on what happens during the kernel build process, continue on with Setting a Cross-Toolchain.

Setting a Cross-Toolchain

The use of a cross-compilation toolchain (cross-toolchain) is necessary when compiling source code (i.e. Linux kernel) on one system (host machine) to be executed on another (target machine). This is commonly the case with embedded development, where native compilation (compiling code on the same embedded machine) can be difficult due to processing power and/or storage restrictions. Quite often, an x86 host machine is used with a cross-toolchain to produce code that is executed on the target machine, which can be one of many supported architectures — ARM, PowerPC, MIPS, etc.

The location of the various build tools included in the cross-toolchain (linker, assembler, compiler, etc.) needs to be known to the host system at the time these tools are needed during the kernel build. If a BSP/SDK build has already been completed, then Factory already has this cross-toolchain generated and properly provides the appropriate values during the kernel build process. If a BSP/SDK build has not been completed yet, Factory can generate the cross-toolchain to provide the necessary components to cross-compile the Linux kernel.

In order to build the toolchain, Factory needs to be configured with the appropriate target board selected. Ensure this is the case by running the following from the top-level Factory directory:

make menuconfig

Also check Target Configuration > Board is set to your board.

Once this is set, the cross-toolchain can then be generated by executing the following from the top-level Factory directory:

make toolchain

The resulting cross-toolchain (built for the selected target board) will automatically be used in subsequent Factory operations described throughout this document.

Note: At this point, Factory is able to produce the Linux kernel for your target board. Issuing the following from the top-level Factory directory will build the kernel with the Timesys-provided defaults for the selected board (steps 2 through 4-4, as needed):

make kernel

The resulting kernel image and device tree binary (if applicable) can be found in the build_[arch]-timesys-linux-[libc]/images/ directory. Also be sure to check build_[arch]-timesys-linux-[libc]/rfs/ for the boot/ (kernel image, kernel configuration file, system map symbol table) and lib/ (for installed kernel modules) directories which are intended for use in the target board's RFS.

Setting a Cross-Toolchain (Factory)
Setting a Cross-Toolchain (TimeStorm)
Setting a Cross-Toolchain (Manual Cross-Compile)

Obtaining and patching sources

Obtaining Linux kernel source files

While the mainline Linux kernel is widely available from kernel.org, support for the myriad of embedded target boards (and components found therein) is not commonly included here due to the strict standards and review process for having code committed to mainline kernel. Due to this, kernels for embedded target boards are often maintained and/or provided by the Semiconductor Vendor, SoC/SoM/board manufacturers, or third parties such as Timesys.

Timesys provides Linux kernel sources along with necessary kernel patchwork for the embedded target boards currently supported (more information on supported processor families and kernel/board pairs can be found here).

Once the target board is selected, Factory provides a recommended (verified) version of the Linux kernel, defines the kernel archive and patches needed, and automatically downloads them from the Timesys Source Repository here. These source files are obtained during the kernel fetch stage of the BSP/SDK build. Note: If a BSP/SDK build has already been completed, or the toolchain has been built as described above, the kernel source files have already been downloaded and can be found under src/dl/k/kernel/kernel-<version>/.

While we recommend obtaining kernel source files and patches through Factory's own fetch facility, links to kernel source downloads can generally be found through Semiconductor or SoC/SoM/board vendor websites for a particular board.

Patching Linux kernel source files

Once the kernel source tree has been obtained it may need to be patched, as is the case with the Timesys-provided kernel. Timesys provides a vanilla kernel source tree (in tar archive format) along with a series of patches to enable support for a particular embedded target board. These patches need to be applied to the extracted kernel source tree in the proper order (this is defined in the Factory workorder).

The kernel source archive is extracted into the Factory-created build_[arch]-timesys-linux-[libc] directory, under linux-<version>/. This is the kernel working directory where all other Factory kernel operations are carried out. The series of patches necessary to add target board support to the vanilla kernel source tree are applied to the kernel in the kernel working directory. The order of these patch are applied is important here, and is described in the Factory workorder's Kernel Patches entry.

These kernel source archive unpacking and patching operations are carried out automatically by Factory during the kernel unpack and kernel patch stages of the BSP/SDK build. Note: If a BSP/SDK build has already been completed, or the toolchain has been built as described above, the kernel source files have already been unpacked and patched, and can be found under build_[arch]-timesys-linux-[libc]/linux-<version>/

Obtaining and patching source (Factory)
Obtaining and patching source (TimeStorm)
Obtaining and patching source (Manual Cross-Compile)

Now that the kernel source tree is patched for the particular embedded target board, it needs to be configured.

Configuring kernel

The Linux kernel requires a kernel configuration file (named .config) in the root of the kernel source tree. This file describes Linux kernel, providing the machine architecture to build for, which device drivers, options, and features are needed, and how they are to be built. For selected drivers, features, and options, the kernel .config dictates what gets built into the kernel (included in the binary kernel image and always loaded into RAM) versus what is built as a module (compiled module code is located on a storage medium and loaded to RAM on demand).

Factory provides validated default (version-specific) kernel .config files to be used in building the kernel for the selected target board (found in /target/configs/kernel/<board>/). Factory automatically copies this default kernel .config to src/dl/k/kernel/kernel-<version>/ during the kernel fetch stage of the BSP/SDK build process. It is from the src/dl/k/kernel/kernel-<version>/ directory that the kernel .config is copied to the kernel working directory, which occurs during the kernel unpack stage of the BSP/SDK build process.

Note: If a BSP/SDK build has already been completed, the kernel .config has already been fetched and copied kernel working directory (build_[arch]-timesys-linux-[libc]/). This is the kernel configuration file Factory uses to build the Linux kernel.

While the default kernel .config provided by Timesys will produce a working kernel image, you may wish to further configure it to better suit the needs of a project or custom hardware/peripherals used with your target board.

Further configuring your kernel

The kernel configuration file is typically managed via the kernel's menuconfig interface. By default, the kernel buildsystem assumes the machine configuring the kernel is the machine that will run the kernel. In a cross-compiling environment, this would result in the kernel being configured for the incorrect machine architecture. Using Factory's kernel-specific make targets, the proper architecture is automatically set based on the target board selection the workorder. To further configure the kernel, simply run the following from the top-level Factory directory:

make kernel-menuconfig

Within the kernel's menuconfig interface, the following conventions are followed:

[ ] indicates option can be built in, or left out of the kernel
< > indicates option can be built in, built as a module, or left out of the kernel
{ } indicates option can be built in, or built as a module
- - indicates option is selected by another feature selection

Where within the brackets, *, M, or whitespace indicates build in, build as a module, or exclude the feature from the kernel.

Built in (*) features or options means the option, feature, or driver is compiled into the kernel image itself. Compiled code for these particular features, options, or drivers is intermingled with the core kernel and as such, is loaded into RAM when the kernel is. This makes for a more efficiently running kernel, as whenever these features, options, or drivers are needed, they are easily accessed within the contiguous region of RAM occupied by the kernel image. The downside to this is that in order to remove an unused feature, option, or driver, the entire kernel image needs to be recompiled and redeployed. Additionally, a larger amount of code needs to be loaded in RAM at system start-up, which could slow down the start-up process.

Kernel modules (M) allow for the insertion of a small bit of compiled code into a running kernel. This is useful for having components (or drivers, for example) that are not required at boot time, but may be needed later. There is an option in the kernel .config that enables support for loadable kernel modules (CONFIG_MODULES=y), which needs to be enabled if this functionality is desired (kernel .configs provided by Timesys have this enabled by default). Some benefits of building kernel features as modules include faster system boot time and the ability to load a module into RAM if/when it's needed.

whitespace ( ) indicates that an option, feature, or driver is not set to be compiled at all. This results in the particular options/feature/driver being left out of the kernel altogether.

Configuring kernel (Factory)
Configuring kernel (TimeStorm)
Configuring kernel (Manually Cross-Compile)

With the kernel configured for the target board, cross-compilation can proceed.

Building the Kernel

Building the Linux kernel consists of several steps to generate and further prepare various elements of the kernel for deployment.

Cross-compiling kernel image

First we'll cross-compile the binary kernel image. This kernel image provides kernel support for all options set to be "built-in," (indicated by * in kernel menuconfig or =y in the kernel .config file). During system start-up, the bootloader loads this binary kernel image into RAM and passes control of the running system to it.

With the proper cross-toolchain set, the kernel image is cross-compiled. There are a number of different kernel image files/formats that can be generated when compiling the kernel. Listed here are a few of the possible kernel image files/formats that can be generated. Note: The kernel image file/format is dependent on a number of factors, and as such, not all kernel image files/formats will be generated for every target board.
  • vmlinux
    The vmlinux file is the raw ELF kernel image. This is generated during the kernel image generation, but is typically an intermediate step in the process of building the kernel.
  • Image
    The Image file is a stripped version of vmlinux, used in the generation of the compressed kernel image files.
  • zImage
    The zImage file is the compressed, bootable version of the Image file. In addition to the compressed Image file, a very small decompression tool is also included in the zImage file, thus making it self-extracting, with no need for external decompression.
  • bzImage
    The bzImage file is the more recent version of the zImage, which allows additional (better) compression algorithms to be used.
  • uImage
    The uImage file is the bzImage with a u-boot specific wrapper (additional header information), calling out the kernel size, load address, md5 checksum and other information required by u-boot.

Factory automatically determines which of these are necessary based on your selections in the workorder (board, bootloader, kernel, etc). Once the appropriate kernel image files are generated (during the kernel image build stage of the BSP/SDK build), they are then neatly organized within build_[arch]-timesys-linux-[libc]/images/ directory for easy access (during the kernel host install stage of the BSP/SDK build).

Cross-compiling kernel image (Factory)
Cross-compiling kernel image (TimeStorm)
Cross-compiling kernel image (Manually Cross-Compile)

Now that the binary kernel image is created, the kernel modules need to be cross-compiled.

Cross-compiling kernel modules

As mentioned earlier, some device drivers, options, and features can be built as kernel modules. Since these modules are not included in the kernel image (by the very nature of being selected as modules), they are not compiled along with the kernel image, but need to be built separately. Factory automatically cross-compiles the kernel modules in a manner similar to the kernel image, having set the appropriate cross-toolchain and passing any necessary variables to the kernel's buildsystem. This is completed during the kernel module build stage of the BSP/SDK build.

The result of this cross-compilation is a series of loadable kernel module binaries (kernel object — .ko files) corresponding to the kernel features set to "M" in the kernel's menuconfig interface (or =m in the kernel .config). The cross-compilation occurs throughout the kernel source tree and leaves the .ko files littered about where compiled. It is not until the install step that these kernel modules are collected and placed in the proper location for use by the running kernel.

Cross-compiling kernel modules (Factory)
Cross-compiling kernel modules (TimeStorm)
Cross-compiling kernel modules (Manually Cross-Compile)

The next step is to install these kernel modules to a location to be included in the embedded target system's RFS for use with the running kernel.

Installing modules

After building the kernel modules, the resulting .ko files need to be organized in a location that can be deployed to the embedded target's RFS for use with the running kernel. This is done by installing the modules to a particular directory which the kernel checks (/lib/modules/[KERNEL RELEASE]/). In a cross-compiling environment, it is important to prefix this location with the path to another directory to ensure the cross-compiled kernel modules do not overwrite those of the host machine.

Factory automatically collects and installs these cross-compiled kernel modules to the target board's RFS working directory for you. The kernel modules are installed to build_[arch]-timesys-linux-[libc]/rfs/lib/modules/[KERNEL RELEASE]/ during the kernel RFS install stage of the BSP/SDK build.

Installing modules (Factory)
Installing modules (TimeStorm)
Installing modules (Manually Cross-Compile)

Generating dtb (if necessary)

The device tree is a description of the hardware in the form of a data structure that is passed to the kernel at boot time. This helps to alleviate the need for the large (and ever-growing) number of board-specific C source files (board files) used to define hardware for the various boards supported by the Linux kernel. That is to say, a single compiled kernel may be able to support a variety of different hardware configurations (for example, different i.MX6 SoCs) with nothing more than a different device tree binary passed to it at boot time to describe the hardware layout. While many recent kernels utilize device trees, device tree support may or may not be present depending on the embedded target system and kernel version.

For the device tree to be useful to the kernel, it must to be compiled in a fashion that the kernel understands. This is the Device Tree Blob (or Device Tree Binary, Flattened Device Tree) which is passed to the kernel at boot time. A few good sources of general information on Device Trees can be found here:

Factory includes a set of default kernel device tree source (dts) files for the target board and kernel version selection combinations that support it. Based on these selections, Factory automatically fetches the appropriate device tree source (dts) file, cross-compiles the device tree blob, and installs it to both the host (build_[arch]-timesys-linux-[libc]/images/ — for use in the SDK) and the target board's RFS (build_[arch]-timesys-linux-[libc]/rfs/boot/ — for reference on the target system).

Factory completes these device tree-related steps during the kernel host install stage or kernel rfs install stage of the BSP/SDK build (if necessary).

Generating dtb (Factory)
Generating dtb (TimeStorm)
Generating dtb (Manually Cross-Compile)


Building the Linux kernel with Desktop Factory

During the basic configuration of the Timesys Factory build system, a target board is set, and based on this board selection, a default Linux kernel version, along with a kernel .config and set of default patches is defined. Unaltered, these settings will produce a functioning kernel image for use on the selected target board.

The Linux kernel can be cross-compiled for the embedded target in a number of ways, but the easiest method is allowing Factory to generate the entire BSP/SDK for the embedded target system. During the BSP/SDK build process, Factory fetches, patches, and builds the Linux kernel, LKMs, and device tree binary. When the BSP/SDK generation completes, the kernel image and device tree (if applicable) can be found within the build_[arch]-timesys-linux-[libc]/images/ directory. Additionally, the loadable kernel modules are compiled and installed to the target's RFS at the appropriate lib/modules/ location within the target RFS working directory (build_[arch]-timesys-linux-[libc]/rfs/).

The Factory make system has a series of kernel* targets to assist with the many common tasks associated with the kernel development.

After selecting the target board, executing make from the top-level Factory directory kicks off the BSP/SDK build process, during which the kernel is cross-compiled, along with any loadable kernel modules and device tree binary files (if necessary). Following this kernel cross-compilation, Factory installs the kernel image, kernel modules, and device tree files to the target system's RFS staging directory. The kernel-specific portion of the BSP/SDK build looks like this:

  1. Fetching kernel source
  2. Extracting kernel source to build_[arch]-timesys-linux-[libc]/linux-[version]/
  3. Unpacking kernel-headers (completed early on during toolchain creation)
  4. Installing kernel-headers for host (completed early on during toolchain creation)
  5. Fetching kernel config
  6. Configuring linux-[version]
  7. Building linux-[version] image
  8. Building kernel device tree blob
  9. Install linux-[version] to the RFS
  10. Installing kernel-headers into RFS
  11. Installing kernel device tree blob to the host
  12. Packaging kernel
  13. Packaging kernel-source
  14. Packaging kernel-headers

Note: steps 12 - 14 are not necessary for a functioning kernel build. Factory automatically creates these kernel packages (kernel-[version]-[arch]-timesys-linux-[libc].tgz, kernel-source-[version]-[arch]-timesys-linux-[libc].tgz, and kernel-headers-[version]-[arch]-timesys-linux-[libc].tgz) for convenience and distribution.

Building Linux kernel as part of the BSP/SDK

As mentioned above, the building a BSP/SDK in turn builds the Linux kernel. This is the easiest method of building the Linux kernel for your embedded target board, and is the recommended method when first starting out building the kernel with Desktop Factory. The following (run from the top-level of your configured Factory directory) will build the BSP/SDK defined in the Factory workorder, completing the steps outlined above:

make

With this, Factory builds the entire BSP/SDK (or whichever portions of it have not been completed), including the Linux kernel.

Setting Cross-Toolchain

Factory is able to generate the cross-toolchain which is used throughout the remainder of the build process. This is built (or extracted in the event of a fetched cross-toolchain) early on during the course of the BSP/SDK build.

To reproduce this, run the following from the top-level Factory directory:

make toolchain

Obtaining and patching sources

Factory can utilize a set of default values for a particular board to generate a bootable kernel without any additional configuration needed. These defaults, which represent Timesys' recommendations for a given board, include the Linux kernel version source archive, kernel patches, and kernel configuration file (kernel .config) as well as applicable device tree source (dts) files when necessary. When Factory is set to manage these items automatically, it is known as an Internal Kernel. This is set by default in Factory.

As part of the BSP/SDK build, if the kernel source files are not present, Factory automatically fetches the necessary sources and subsequently extracts and patches as appropriate for the hardware selected in the Factory workorder.

When it comes to the Linux Kernel source files, most are fetched from the Timesys Source Repository (by default). A few notable exceptions:
  • initial kernel configuration file
    This file is fetched from within Factory's target/configs/kernel/[board]/ directory, named config-[kernel_version]
  • device tree source file (dts)
    This file (if applicable to target board/kernel selection) is stored within factory and can be found here: target/configs/kernel/[board]/dts-[kernel_version]
    Due to limited availability of device tree support in the Linux kernel, the dts file fetch is postponed to the kernel build portion of the BSP/SDK generation.

As they are fetched, the kernel source files are initially placed into the common downloaded sources directory (src/dl), specifically src/dl/k/kernel/kernel-[kernel_version]/. It is from here that these files are eventually pulled into the kernel working directory for use building the kernel.

The kernel fetch step can be reproduced with the following command issued from the top-level Factory directory:

make kernel-fetch

The fetched kernel source is stored in the src/dl as a tar archive along with a series of patches that must be applied. It isn't until the kernel-unpacking stage that the sources are moved into the kernel working directory (build_[arch]-timesys-linux-[libc]/linux-[version]) where the extraction takes place. This kernel working directory is where the remaining kernel work is completed by factory.

The kernel unpack step can be reproduced with the following command issued from the top-level Factory directory:

make kernel-unpack

After extraction of the kernel source tree from the tar archive, Factory patches the Linux kernel in the kernel working directory. The order of the patch application is listed in the Factory workorder under Target Software > Kernel > Kernel Patches. The patches listed here are sequentially applied to the kernel source tree to provide the proper support for the selected target board.

The kernel patch step can be reproduced with the following command issued from the top-level Factory directory:

make kernel-patch

Note: Factory also allows for user-management of the Linux kernel source tree. In Factory, this is known as an External Kernel (as opposed to the Internal Kernel described above).

Obtaining and patching sources — External Kernel

The External Kernel facility in Factory allows for user-management of the kernel source tree. It is assumed that the kernel source tree is already obtained and patched appropriately for the selected target board. The Factory option to enable use of an External Kernel is found in the workorder under Target Software > Kernel > Build an internal kernel or use an external kernel?. Once "external" is selected, the location of the patched kernel source tree can be provided in the Factory workorder under Target Software > Kernel > Kernel Source Path. Additionally, an option indicating where the kernel configuration file can be found (in the kernel source tree, or at a specified location) becomes available and needs to be defined (configuring external kernel).

In the event an External Kernel is being used, the directory listed as the Kernel Source Path in the Factory workorder becomes the kernel working directory. This is where all subsequent kernel operations are carried out.

Configuring kernel

The default (minimal) kernel configuration file (kernel_config) is copied from the fetched sources location in src/dl/ to kernel working directory in build_[arch]-timesys-linux-[libc]/ in preparation for the kernel configuration. Factory then completes the kernel configuration accepting the defaults for the various kernel configuration options not already defined by the default (minimal) configuration file. The result of the kernel configuration step is the fully populated kernel .config file in the root of the Linux kernel source tree.

The kernel configure step can be reproduced with the following command issued from the top-level Factory directory:

make kernel-configure

Configuring kernel — External Kernel

The user-supplied configuration file for the External Kernel can either be fetched from location specified in the workorder (Use an external configuration file), or simply placed within the kernel source tree (Already configured). This option is set in the Factory workorder under Target Software > Kernel > External Kernel Configuration.

If "Already configured," the kernel configuration file is expected to be placed in the root of the kernel source tree, named .config. When the "Use an external configuration file" option is employed, the path to the kernel configuration file is specified at Target Software > Kernel > External Kernel Configuration Path by the user. Similar to the Internal Kernel case, the kernel configuration file is not copied to the kernel working directory until the kernel-configure step is run.

Beyond the kernel source management and initial configuration, using either Internal Kernel or External Kernel methods proceed similarly.

Further configuring your kernel

The Linux kernel can be configured further (i.e. select which drivers/features/options to include in the kernel image, build as modules, or remove altogether). This can be accomplished with the following from the top-level Factory directory:

make kernel-menuconfig

Note: Be sure to save the kernel configuration upon exiting the menuconfig interface.

Building the kernel

Cross-compiling kernel image

Factory automatically passes the correct target board-specific variables to the kernel build system to properly cross-compile the necessary kernel image. The kernel image build step can be reproduced with the following command issued from the top-level Factory directory:

make kernel-build-image

The result of these commands is the binary kernel image located in the kernel source tree at arch/[kern_arch]/boot/, commonly an uncompressed binary kernel image (Image) and a self-extracting compressed binary kernel image (zImage). Additionally, a binary kernel image contained within a U-Boot wrapper containing kernel image size, load address, among other information (uImage) is automatically created with the help the mkimage utility for those boards utilizing the U-Boot bootloader.

Cross-compiling kernel modules

The kernel modules are cross-compiled separately from the kernel image. Factory automatically passes the correct target board-specific variables to the kernel build system to properly cross-compile the selected kernel modules. The kernel module build step can be reproduced with the following command issued from the top-level Factory directory:

make kernel-build-modules

The resulting kernel module binaries (or kernel objects — *.ko files) are compiled in tree. To view the kernel modules that have been compiled, you can run the following from the root of the kernel source tree:

find ./ -name '*.ko'

Installing modules

The kernel modules that are compiled throughout the kernel source tree are collected and installed to the target system's RFS staging directory during the kernel's rfs install stage of the BPS/SDK build. At this stage, the kernel .config is parsed and the kernel's build system ensures that items selected to be installed as modules are indeed compiled (and properly cross-compiles them if they are not), and installs them to the appropriate locations within the target system's RFS staging directory under lib/usr/[kernel-version].

The kernel rfs install step can be reproduced with the following command issued from the top-level Factory directory:

make kernel-rfs-install

The resulting directory structure under @lib/usr/[kernel-version]/ in the target system's RFS staging directory (build_[arch]-timesys-linux-[libc]/) is intended to be used on the target system and provide the necessary kernel module binaries as defined in the kernel configuration.

Generating dtb (if necessary)

The Device Tree Blob (also known as dtb, device tree binary, or flattened device tree) is created near the end of the kernel build portion of the BSP/SDK build. There are a few steps which Factory automatically completes during the generation of this file:
  • Device tree source fetch
    • This copies the appropriate device tree source (dts) file from target/configs/kernel/[board]/ to the kernel working directory in build_[arch]-timesys-linux-[libc]/linux-[version]/.
  • Device tree build
    • This generates the device tree blob. Note: Any helper scripts needed to generate the dtb are also built at this time.
  • Device tree install to RFS
    • This copies the device tree blob to the target system's RFS staging directory under boot/.
  • Device tree install to host
    • This copies the device tree blob to the Factory's build_[arch]-timesys-linux-[libc]/images/ directory.

These steps are reproducible with the following:

make kernel_devicetree-fetch
make kernel_devicetree-build
make kernel_devicetree-rfs-install
make kernel_devicetree-host-install

The resulting dtb file can be found in the kernel source tree root, arch/[arch]/boot/dts/ or arch/[arch]/boot/ or in the directories listed above (build_[arc]-timesys-linux-[libc]/images/ or build_[arch]-timesys-linux-[libc]/rfs/boot/).


Building the Linux kernel with TimeStorm IDE

Please refer to the TimeStorm User manual for information regarding the use of TimeStorm to build the Linux kernel.


Building the Linux kernel manually

This outlines the necessary steps to build the Linux kernel for an embedded target board with the use of a cross-toolchain.

Setting Cross-Toolchain

Simply prepend the location of cross-toolchain's uncompressed tools (linker, assembler, compiler, etc) to your PATH environment variable (via the export command). Using a Timesys-provided cross-toolchain, this would look like:

export PATH=/path/to/[arch]-timesys-linux-[libc]/ccache:/path/to/[arch]-timesys-linux-[libc]/bin:$PATH

Exporting the location of cross-toolchain's tools (linker, assembler, compiler, etc) to your PATH environment variable directs your host to look for the various build tools in the locations sequentially as listed in the PATH environment variable. Since the cross-toolchain ccache and bin directories are listed before the host system's /usr/sbin, /usr/bin, the host system will check the cross-toolchain locations first for the build tools. When used in conjunction with the CROSS_COMPILE= argument, the result is cross-compiled code that can be executed on the target system for which the cross-toolchain was created.

For example, exporting the cross-toolchain components from a Nitrogen6x Factory build would look something like:

export PATH=/home/timesys/timesys/nitrogen6x/toolchain/ccache:/home/timesys/timesys/nitrogen6x/toolchain/bin:$PATH

Obtaining and patching sources

It is assumed that the kernel source and any necessary patches are already obtained from the Semiconductor, SoC/SoM/board vendor. In the event that patches need to be applied to a vanilla kernel source tree (as is the case when kernel sources are obtained from Timesys), the method is as follows:

cd linux-[version]
patch -p1 < /path/to/patch/file

*repeat for each patch*

Configuring kernel

The kernel .config is not necessarily included with in the kernel source tree by default (though may be provided as a convenience by the Semiconductor, SoC/SoM/board vendor), and may need to be created from scratch.

When configuring the Linux kernel for an embedded target board, the ARCH=[kern_arch] variable needs to be passed to the menuconfig make target in order to ensure the kernel is configured for the embedded system architecture as opposed to the development host from which the command is run. It is through this that the Linux kernel can be further configured (i.e. select which drivers/features/options to include in the kernel image, build as modules, or remove altogether). This can be executed directly from the root of the kernel source tree ([kern_arch] being one of the architectures listed in arch/) as such:

make ARCH=[kern_arch] menuconfig

Note: Be sure to save the kernel configuration upon exiting the menuconfig interface.

Generating default kernel configuration for a particular architecture

If starting without a kernel configuration file, default kernel configurations (called defconfigs) are available in the kernel source tree at arch/[kern_arch]/configs/ and can be used to seed a basic kernel configuration file. To build the default kernel configuration, run the following from the root of the kernel source tree:

make ARCH=[kern_arch] [board]_defconfig

The resulting kernel .config found in the root of the kernel source tree can then be further configured using the method explained above.

Building the kernel

Cross-compiling kernel image

The use of a cross-toolchain along with the ARCH and CROSS_COMPILE variables passed to the kernel build system allows for the kernel image to be built according to the kernel .config for the necessary target board. The following can be run from the root of the kernel source tree:

make ARCH=[kern_arch] CROSS_COMPILE=[arch]-timesys-linux-[libc]- [kernel image] 

Note: Here it is important to know the bootloader used on the hardware, as different bootloaders may require different kernel image files/formats. Additionally please note certain kernel image files require additional variables at compile time.

For example cross-compiling for a Nitrogen6x might look like this:

make ARCH=arm CROSS_COMPILE=armv7l-timesys-linux-gnueabi- LOADADDR=0x10008000 uImage

Note: In this case, the U-Boot bootloader is utilized, and the uImage generation requires the LOADADDR variable during compilation (to be included in the U-Boot header information).

The compiled kernel image can be found in arch/[kern_arch]/boot/ within the kernel source tree.

Cross-compiling kernel modules

The use of a cross-toolchain along with the ARCH and CROSS_COMPILE variables passed to the kernel build system allows for the kernel modules to be built according to the kernel .config for the necessary target board. The following can be run from the root of the kernel source tree:

make ARCH=[kern_arch] CROSS_COMPILE=[arch]-timesys-linux-[libc]- modules

Note: To view the cross-compiled kernel modules, you can run the following from the root of the kernel source tree:

find ./ -name '*.ko'

This simply returns the all kernel object files (.ko) found in the kernel source tree. Note: All existing kernel modules may not be included when installing modules — the modules that are installed are dictated by the kernel configuration file.

Installing modules

The use of a cross-toolchain along with the ARCH, CROSS_COMPILE, and INSTALL_MOD_PATH variables passed to the kernel build system allows for the kernel modules to be installed to an appropriate location for the necessary target board. The following can be run from the root of the kernel source tree:

make ARCH=[kern_arch] CROSS_COMPILE=[arch]-timesys-linux-[libc]- INSTALL_MOD_PATH=/path/to/deployable/modules/ modules

for example:

make ARCH=arm CROSS_COMPILE=armv7l-timesys-linux-gnueabi- INSTALL_MOD_PATH=/home/timesys/kernel_modules install_modules

would result in a directory structure of:

linux-3.10$ ls /home/timesys/kernel_modules/lib/modules/3.10.17-ts-armv7l/
build  kernel  modules.builtin  modules.order  source
linux-3.10$ ls /home/timesys/kernel_modules/lib/modules/3.10.17-ts-armv7l/kernel/
crypto  drivers  fs  lib  net

The contents of this /home/timesys/kernel_modules/ can be copied to the embedded target board's RFS for use with that system's running kernel.

Generating dtb (if necessary)

There are some helper scripts that first need to be built in order to properly build the device tree binary. This is done through the following command, run from the root of the kernel source tree:

make ARCH=[kern_arch] CROSS_COMPILE=[arch]-timesys-linux-[libc]- scripts

Once completed, the device tree binary can be built by running the following from the root of the kernel source tree:

make ARCH=[kern_arch] CROSS_COMPILE=[arch]-timesys-linux-[libc]- [base-dts-filename].dtb

Here, the [base-dts-filename] is simply the name of the device tree source (dts) file for a particular board (found in arch/[kern_arch]/boot/dts/) without the '.dts' — which is replaced with the .dtb as indicated in the command above.

This compiles the device tree source files to generate the device tree binary — which can be found in the same arch/[kern_arch]/boot/dts/ directory named [base-dts-filename].dtb.