Compiling and installing mainline kernel alongside vendor/stock kernel on Odroid C2

Introduction

NOTE: This guide is a copy of something I kept locally for a long time and may be slightly outdated, as we’ve now reached linux kernel 5.x serie. Still, it should be usable regardless, although some steps could differ slightly.

This guide will help you into compiling and installing latest mainline kernel on your Odroid C2, keeping the vendor kernel in case of emergency. Note that this installation is what is called a vanilla installation, and does not base itself on the modified kernel for ArchLinux, nor the one for ArchLinux-ARM.
WARNING ! WARNING ! \
If you plan on following the steps to get your RTC working with this
kernel, it is strongly advised to avoid booting the 3.14 kernel ever
again. The fact the RTC driver is not compiled as built-in in 3.14
kernel nor mainline by default makes it so that if you are working on
things that depend on them, (i.e: mysql databases), they will be
confused at the sudden change of time when booting up the older kernel
which has RTC as module. Hence, it is strongly advised to remove the
3.14 kernel alltogether.

What is in this guide ?

  1. Getting the kernel tarball
  2. Decompressing the tarball
  3. Make defconfig, what’s that all about ?
  4. Make menuconfig
    1. Enabling snd_usb_audio as a module
    2. [Optional] Enabling speakup and speakup_soft
    3. Enabling the RTC driver as built-in
    4. [Recommended] Compress the modules when installing
    5. [Recommended] Trim unused exported kernel symbols
    6. Enabling CONFIG_EXT4_FS_SECURITY and extended attributes for tmpfs
  5. Make, oof, you can take a break, it’s your odroid’s turn to have fun
  6. Make modules_install dtbs_install
  7. Creating a preset file for mkinitcpio and making a new initramfs
  8. [Optional] Add the RTC shield to the device tree blob
  9. Wrapping the kernel, what in the world does that mean ?
  10. Creating a U-Boot configuration from scratch
    1. With hardkernel’s specific U-Boot
    2. With mainline U-Boot

Getting the kernel tarball

First things first, let’s go on the Linux kernel’s website, and grab the latest tarball for mainline, which is 4.12.0 at the time of this writing. No need to go in their git repository as there’s a direct link to the latest mainline kernel directly available from there.

Decompressing the tarball

Once you’ve got the kernel downloaded, next thing to do is to decompress it. The following command will do it:

tar -xvJf linux-4.12.tar.xz

Where 4.12 is the version number of the kernel, yours may differ. Once that is taken care of, go in the newly created directory:

cd linux-4.12/

It is also necessary to install a few packages in order to compile the kernel successfully:

  • xmlto
  • docbook-xsl
  • kmod
  • inetutils
  • bc

Make defconfig, what’s that all about ?

Make defconfig is actually something really easy. It is used to generate the default configuration for the kernel — it’s better like this or you’d be designing your own configuration by hand or via make menuconfig, from botum to top. So now, type the following and let it work a bit:

make defconfig

Make menuconfig

Now it’s fun time ! You have a basic but working configuration for your kernel. It is still missing three things, though:

  • RTC driver for pcf8563 built-in.
  • The snd_usb_audio module to get most usb sound cards working out of the box.
  • Optionally, speakup and speakup_soft modules to get console speech.
  • And anything else you’d like to enable.

Type the following, you will end up in a nice menu with all sorts of options:

make menuconfig

Enabling snd_usb_audio

By default, the kernel configuration does not include the snd_usb_audio module which allows you to plug most driverless sound card and get them working instantly. So, we’re going to enable it, because if you plan on getting console speech without it, it won’t work for sure. Uses the arrow keys to navigate in the menu:

  • Device Drivers
    • Sound card support
      • Advanced Linux Sound Architecture
        • USB sound devices

Once there, make sure USB Audio/MIDI driver is selected and press ‘m’ to modularize it into the kernel. Press ‘x’ as many times as necessary to go back in the Device Drivers submenu.

[Optional] Enabling speakup and speakup_soft modules

Navigate with the arrow keys up to the Staging Drivers submenu. You’ll notice the brackets in front of it are empty, so press ‘y’ on your keyboard to enable this into the kernel as built-in. Press enter on this menu item, and navigate to Speakup Console Speech. Press enter on this item, and now press ‘m’ on the first and only available item at this point, speakup. Other items are unlocked when this is done so, find speakup userspace soft driver and press ‘m’. Press ‘x’ twice to get back to Device Drivers.

Enabling the RTC

Now, go into Real Time Clock submenu, and arrow down until you find Philips PCF8563/Epson RTC8564, and simply press ‘y’. You’re done ! Press ‘x’ twice to exit both the real time clock submenu and Device Drivers.

[Recommended] Compress the modules when installing

Quoting the Linux Kernel Driver Database:

Compresses kernel modules when ‘make modules_install’ is run; gzip or xz depending on “Compression algorithm” below.

module-init-tools MAY support gzip, and kmod MAY support gzip and xz.

Out-of-tree kernel modules installed using Kbuild will also be compressed upon installation.

Note: for modules inside an initrd or initramfs, it’s more efficient to compress the whole initrd or initramfs instead.

Note: This is fully compatible with signed modules.

To save disk space, it is recommended to set a compression method for the modules. This way, when we will install them later on, they will automatically be compressed, thus using less disk space on your eMMC/micro SD card. So, let’s do just that:

  • Enable loadable module support
    • Press y on ‘compress modules on installation’
      • Compression algorythm

Press the spacebar on the ‘XZ’ method.

[Recommended] Enable trimming of unused exported kernel symbols

From LKDDB:

The kernel and some modules make many symbols available for other modules to use via EXPORT_SYMBOL() and variants. Depending on the set of modules being selected in your kernel configuration, many of those exported symbols might never be used.

This option allows for unused exported symbols to be dropped from the build. In turn, this provides the compiler more opportunities (especially when using LTO) for optimizing the code and reducing binary size. This might have some security advantages as well.

If unsure, or if you need to build out-of-tree modules, say N.

Still in the module support menu, arrow down till you find Trim unused exported kernel symbols and press ‘y’. Then, press ‘x’ twice to exit the menu, and finally press enter when you are prompted about saving your configuration.

Enabling CONFIG_EXT4_FS_SECURITY and extended attributes for tmpfs

According to the Linux Kernel Driver Database:

Security labels support alternative access control models implemented by security modules like SELinux. This option enables an extended attribute handler for file security labels in the ext4 filesystem.

If you are not using a security module that requires using extended attributes for file security labels, say N.

In our case, this option is required because some tools such as ping(8) and tshark(1) from wireshark requires special capabilities that can’t be set otherwise. Since I do not know where exactly those options are in make menuconfig, we will do it manually. Open your .config file into your text editor like this:

nano .config

And press ctrl+w to search for ‘CONFIG_EXT4_FS_SECURITY’. You should find yourself on a line saying that this option is not set. Remove the ‘#’ symbol in front of it, also the extra space, and go at the end of the line to erase ‘is not set’. Replace it with ‘=y’, so that the line now looks like this:

CONFIG_EXT4_FS_SECURITY=y

Search for this line and repeat the same thing: CONFIG_TMPFS_XATTR.

  • Notes:
    • Enabling extended attributes for most filesystem in general is a good thing, unless you know you will never need it for a particular filesystem.

Save and close your text editor.

Make, oof, you can take a break, it’s your Odroid’s turn to have fun

Now that your kernel configuration is done, all you have to do is:

make
  • Notes:
    • The make command actually support specifying the number of thread it should allocate to compile things. So if your processor has, say, 4 cores, you can pass the following argument: -j4.

So, you’d need to type:

make -j4

You can now leave it running, it will take a while — about 40 ~50 minutes with all cores running at their best.

Make modules_install dtbs_install

I hope you are refreshed and well, it’s now time to install the modules and the dtbs your odroid just ended compiling. For now, make sure the make command didn’t give you any error and type this:

sudo make modules_install dtbs_install

This will install the modules of the compiled kernel at the right place, usually into /usr/lib/modules/kernel_version. This will also install all the device tree blob files for all the supported SoCs in /boot/dtbs/kernel_version. Once this is completed, move on to next step.

Creating a preset file for mkinitcpio and generating a new initramfs

It’s now time to generate a new initramfs for your kernel that will be put alongside the one that already exists for the vendor kernel. We will copy the existing preset file and modify it by hand:

sudo cp /etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linux-mainline.preset

Now, open the newly created file into your text editor, I personally use nano:

sudo nano /etc/mkinitcpio.d/linux-mainline.preset

Modify the file so it looks like this:

# mkinitcpio preset file for 'linux-mainline'.

ALL_config="/etc/mkinitcpio.conf"
ALL_kver="4.12.0"
PRESETS=('default')
#default_config="/etc/mkinitcpio.conf"
default_image="/boot/initramfs-linux-mainline.img"
#default_options=""
  • Notes:
    • The actual file name of your preset doesn’t matter, as long as it is something you can remember.
    • Defaut_image can be anything fore the image name, as long as it is located in the /boot directory.
    • It is better if ALL_kver matches the kernel version you are installing.

Save and exit your text editor, and run the following to generate the initramfs corresponding to your new preset:

sudo mkinitcpio -p linux-mainline

This will create a file called ‘linux-mainline.img’ in /boot. Now that this has been taken care of, let the harder part begins.

[Optional] Add the RTC to the device tree

We will use a set of tools from the dtc package, mainly fdtget and fdtput to modify the blob binary of the device tree that was placed in /boot/dtbs/kernel_version to add a new subnode in the corresponding bus controler, and set the required properties for it to be detected, allowing you to use the RTC shield of your odroid. It is recommanded that you backup the original file in case of mistakes, so let’s do just that

sudo mkdir /boot/dtb-backup
sudo cp /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /boot/dtb-backup

Now, use the fdtget tool to explore the content of the blob:

fdtget -l /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc

Sample output:

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

What interest us here is the cbus subnode:

fdtget -l /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc/cbus

Sample output:

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

Let’s check the status of [email protected]:

fdtget /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc/cbus/[email protected] status

It should report ‘okay’. Now, let’s create a subnode under this controler. It’s usually called [email protected].

sudo fdtput -c /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc/cbus/[email protected]/[email protected]

Now, let’s add the properties to that subnode:

sudo fdtput -t s /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc/cbus/[email protected]/[email protected] compatible "nxp,pcf8563"
sudo fdtput -t x /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc/cbus/[email protected]/[email protected] reg 0x51

Let’s list the properties and make sure they are right:

fdtget /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc/cbus/[email protected]/pcf8563 compatible
fdtget /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb /soc/cbus/[email protected]/pcf8563 reg

Compatible should report exactly ‘nxp,pcf8563’ and reg should report 81 which is 0x51 in hexadecimal.

Wrapping the kernel, what in the world does that mean ?

For now, your kernel is a simple raw image that doesn’t even have headers. We need to wrap it up first, in order to boot it up successfully. What does wrapping actually means ? Well, it means that we’re going to use the Image.gz file that is in your kernel source tree and ask a U-boot utility called mkimage to create a bootable image from it. So if it isn’t already installed, install the uboot-tools package. Here are the details you need to know and use:

  • Architecture is arm64.
  • OS type is linux.
  • Image type is kernel.
  • Compression method is gzip.
  • The kernel load address is 0x1080000.
  • Entry point is also 0x1080000.
  • Name can be anything you want.

So, all you have to do at this point is:

sudo mkimage -A arm64 -O linux -T kernel -C gzip -a 0x1080000 -e 0x1080000 -n linux-mainline -d arch/arm64/boot/Image.gz /boot/uImage

Sample output:

Image Name:   linux-mainline
Created:      Sun Feb 26 19:06:29 2017
Image Type:   AArch64 Linux Kernel Image (gzip compressed)
Data Size:    6431862 Bytes = 6281.12 kB = 6.13 MB
Load Address: 01080000
Entry Point:  01080000

You’re done with this step, you now have a bootable kernel image.

Creating a U-boot configuration from scratch

With hardkernel’s specific U-Boot

The U-Boot configuration that comes with Archlinux-ARM by default is not really suitable for a kernel mainline just yet. It is better to rename /boot/boot.ini into something else to still keep it around and writing your own configuration by hand. There are some things to know, though:

  • The serial console name is no longer ttyS0. As the kernel you have compiled is a generic kernel, they had to differenciate on which platform you are running. New name for the serial console is ttyAML0.
  • Be careful when setting up bootargs. Don’t forget to set the root fs, in particular.
  • Be careful when setting up load_addr, dtb_addr and initrd_addr. DTB is small, kernel is a bit bigger and initramfs is the biggest. You can load them wherever you want, except not below 0x1000000, and not to high above as to avoid accidentally overwriting the RAM. Make sure they are all far enough from each other as to not overlap, or that will result in unexplainable crashes.
  • If you plan on using usb, for the timebeing you will have to add the command ‘usb pwren’ into your configuration, as long as it is set before the final bootm command to boot the system.

Create an empty file called boot.ini:

sudo nano /boot/boot.ini

And put something similar into it:

ODROIDC2-UBOOT-CONFIG
setenv condev "console=ttyAML0,115200n8 console=tty0"
usb pwren
setenv bootargs "root=LABEL=ArchLinuxC2 rootwait rw ${condev} no_console_suspend fsck.repair=yes net.ifnames=0"
setenv loadaddr "0x12000000"
setenv dtb_loadaddr "0x2000000"
setenv initrd_loadaddr "0x33000000"
load mmc 0:1 ${loadaddr} /boot/uImage
load mmc 0:1 ${dtb_loadaddr} /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb
fdt addr ${dtb_loadaddr}
load mmc 0:1 ${initrd_loadaddr} /boot/initramfs-linux-mainline.img
bootm ${loadaddr} ${initrd_loadaddr}:${filesize} ${dtb_loadaddr}

You’re finally done ! Now, all you have to do is reboot the board, and it should boot as expected, with your new kernel.

With mainline U-Boot

For mainline U-Boot, usb pwren is not necessary from linux 4.12 onward, due to a workaround for the usb being made to work despite mainline U-Boot not supporting any form of usb command. All in all the same rules apply like the above, but do keep in mind you now need to use one of ‘mmc 0’ if you are using a micro SD card or ‘mmc 1’ if you are using an eMMC card. Also please do keep in mind the bootm command will not work with U-Boot 2017.05-rc3 and below due to a value being not large enough to support the deflating of the initramfs.

sudo nano /boot/boot.txt

setenv condev "console=ttyAML0,115200n8 console=tty0"
setenv bootargs "root=LABEL=ArchLinuxC2 rootwait rw ${condev} no_console_suspend fsck.repair=yes net.ifnames=0"
setenv loadaddr "0x12000000"
setenv dtb_loadaddr "0x2000000"
setenv initrd_loadaddr "0x33000000"
load mmc 1 ${loadaddr} /boot/uImage
load mmc 1 ${dtb_loadaddr} /boot/dtbs/4.12.0/amlogic/meson-gxbb-odroidc2.dtb
fdt addr ${dtb_loadaddr}
load mmc 1 ${initrd_loadaddr} /boot/initramfs-linux-mainline.img
bootm ${loadaddr} ${initrd_loadaddr}:${filesize} ${dtb_loadaddr}

Then you have to go in /boot and use the mkscr to generate a wrapper around boot.txt, like so:

cd /boot && sudo ./mkscr

You’re finally done ! Now, all you have to do is reboot the board, and it should boot as expected, with your new kernel.

Final notes

  • If something bad happens, make sure to have a uart cable nearby.
  • If you get a random IP address changing at every boot, make a static IP configuration with whatever network manager you are using.
  • Alternatively, if you are using systemd-networkd (must
    be possible with other network managers), you can create
    a file containing this, as an example, assuming your interface
    name is eth0 — it should be if you added “net.ifnames=0” to
    the bootargs in boot.ini or boot.txt depending on which U-Boot you are using.

/etc/systemd/network/10-eth0.link

[Match]
OriginalName=eth0

[Link]
MACAddress=00:1e:06:33:5a:6d

Enjoy !

Credits

I would like to thank Michal Zegan Aka. Webcat on irc. Without his precious help, this guide wouldn’t exist, nor would I be running mainline kernel on my own Odroid C2. Technically the credits are all his, all I did was putting his instructions in a guide that is, I hope, easy to read.
I am not in any way responseable if something really bad happens. All I did was providing instructions that should work for you, unless there is definitely something wrong going on. As always, be careful, and remember you still have an emergency kernel.

There are no comments

Join the conversation

Your email address will not be published. Required fields are marked *