Dev/Embedded/FromScratch/LinuxKernel

From Embeded Linux (and more) Wiki by Nathael
Jump to navigation Jump to search

Introduction

For the Linux kernel, you usually have two (sometimes three) choices :

  • Get the official "vanilla" kernel from kernel.org
  • Get the custom kernel provided by the board manufacturer
  • Get a custom kernel from a community project when there's one available.

I try to use official kernels as much as possible, but sometimes you are stuck to a custom kernel (most of the time outdated).
If you have some time available, then you can try to port the patches from the custom kernel to the official one and have them included in the upstream official kernel, which will always be greatly appreciated, though the hardest part of this is not the technical part (effective porting of the patches) but getting them accepted upstream.

Grab the sources

When getting the source from kernel.org you can use either git, or download an archive from kernel.org (which will lack git history but be smaller, both for download and for disk space)

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

Otherwise, grab the source from whatever alternative source you identified as suitable for your board.

If you cloned a git repository, you may want to checkout a specific tag or revision in order to be in sync with a version known to run fine on your hardware.

It is also time to add any patch you received on top of your source tree in order to add any specific support which is not included in the cloned or extracted kernel sources.

Configure

It's usually a god idea to build the Linux kernel in a separate Build directory in order to keep the sources clean and allow you to run multiple builds using a single source tree, saving disk space and making it easier to spot what got compiled.

Let's suppose you have your sources in the "linux" directory then to setup the Build environment you should run the following commands (set the arch variable to the right value for your hardware) :

mkdir -p Build/linux
cd linux
arch=
make ARCH=${arch} -j8 O=../Build/linux/ allnoconfig

Note that "allnoconfig" can be replaced by "alldefconfig".

You now have a kernel "Build" directory, and should run all further commands from this build directory in order to keep the sources clean.

the .config file

The Linux Kernel configuration is stored in a file named ".config" at the root of the Build directory.

This is a text file, so it is easy to share it and store it, and look at what's included in a given kernel by looking at this file.

It is sometimes possible to use a "default" configuration provided with the kernel sources, though for for most ARM board you will not find a configuration to fit your board from the official kernel sources, only one matching your processor familly. The reasons behind this are that there are too many socs out there, and much much more boards using them, even if you only count the commercial ones, and also that the "hardware" related part of a configuration is only a fraction of a Kernel configuration, which is really specific to each user ans use case (the "get everything as modules" approach used by distributions does not fit embedded systems).

So the usual way is for the board designer to provide an example configuration which should include all the support of your hardware. For the parts which are not hardware related (IPCs, network protocols, debugging, file-systems, ...) you'll get whatever comes with the hardware configuration and you'll need to spend some time tunning the configuration to your needs.

As for the technical/practical part of how to do this : copy the config file you received from the board manufacturer as ".config" at the root of the build directory, overwriting the one generated during the previous step, and run either "oldconfig" or "olddefconfig". If you are using the same kernel version as the one the configuration file came from, then the configuration is simply checked, but if you're using a newer kernel version, then the "oldconfig" case will prompt for a choice for each new configuration option, while the "olddefconfig" case will use the default choice for each new configuration option.

cd Build/linux
make ARCH=${arch} -j8 oldconfig

You can then check and tune the configuration for your needs by running "menuconfig" (or "xconfig" for a Qt frontend, or gconfig for a GTK+ configuration frontend) :

make ARCH=${arch} -j8 menuconfig

the device tree

Compile

From the Build directory created in the configure step :

compiler_prefix=
arch=
make ARCH=${arch} -j8 CROSS_COMPILE=${compiler_prefix}
make ARCH=${arch} -j8  ROSS_COMPILE=${compiler_prefix} dtbs
make ARCH=${arch} -j8 CROSS_COMPILE=${compiler_prefix} modules_install INSTALL_MOD_PATH=../results/

Use

Linux Kernel

Compilation result is in arch/arm/boot/Image

Device tree

Use the sun8i-h2-plus-orangepi-zero.dtb device-tree (found in arch/arm/boot/dts/) or sun8i-h2-plus-orangepi-zero-ed3l.dtb from my shared ressources.

Modules

If the compilation has been performed using the above command lines you should have a directory "Build/Mods/lib/modules/***" (*** = name of the kernel you just compiled)
You must copy the whole directory (not only the content) on the SD card, in the partition holding the root filesystem (rootfs), in the /lib/modules/ directory without changing the name.