Step-by-step Native Compiling a Kernel

From odroid US
Revision as of 22:53, 25 October 2013 by Osterluk (Talk | contribs) (Unpacking the source)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search



These procedures assume you have an Debian-based distribution loaded on your odroid. The kernel building is not different between the distros, but getting ready to build is.

Debian/Ubuntu/Mint and others use "Debian packages", .deb files. They use tools like dpkg, apt, synaptic and so on to manage a package database.

RedHat, Centos, Fedora and Gentoo would not know about apt-get and friends -- so these instructions will not be of much use.

For reference, here is a link to mdrjr's kernel rebuilding thread on the forum: [1]. All kernel building involves the same steps. This tutorial is meant to help new users.

Installing tools

Depending on the distro you are running, and the packages you have installed, you might need to add the compiler and other build-related tools. For example, a minimal base Debian image would not have gcc, since an embedded Linux appliance generally has no requirement to be used as a development tool. This item shows how to install what you need: Adding Native Compiler and Tools

Grabbing the source

You can easily build the kernel on your own.

You can get the latest kernel snapshot or get a source for a specific Hardkernel released build. This link shows how to get a specific release: Use git and commit tag . If a snapshot is acceptable, use the wget step as shown next.

  1. browse to
  2. choose your branch (as of today -2013-01-12- it's odroid-3.0.y)
wget --no-check-certificate

This example gets a snapshot of the odroidxu kernel: (note: the board name is odroidxu)

wget --no-check-certificate

Unpacking the source

If you picked up a differently named source tarball, of course, substitute the names below:

sudo mkdir -p /usr/src 2>/dev/null
sudo chmod 777 /usr/src
mv /usr/src/
cd /usr/src
7z x -y > /dev/null
# add a symlink to the source tree
ln -s  linux-odroid-3.0.y linux 

Configuring the kernel

Now is the time to consider whether you want to work as root user or to logout and proceed as a normal user. Usually file permissions trip up users new to Linux. Working as root can make things easier, but there is a risk of wrecking your system. On the plus side, with odroid, we can just re-flash it and get back to work.

You might want to install the sudo package if you don't have it already. This next section is optional. You have to reboot after this step to see sudo work for the new user.

sudo apt-get install
# You need to add yourself to the "sudoers list", and how exactly that is done depends on the distribution.
# This hack works for Debian Wheezy
# as root, add normal user (named odroid) to adm group
adduser odroid adm
# configure the adm group to have no restrictions
echo "%adm ALL=(ALL) ALL" >> /etc/sudoers
# sudo will complain if it cannot resolve the hostname
echo "  $(hostname )" >> /etc/hosts

Move to the linux source tree and change ownership to the normal user named odroid. Substitute your own username, if you are not using the odroid user account.

cd /usr/src
chown -R odroid:odroid linux
cd linux

Make sure to select the correct config for your device in the next step. execute the following to get a list of odroid kernel configs:

ls arch/arm/configs/odroid*ubuntu*

You will see something like the following:

    odroidq_ubuntu_defconfig        odroidx2_ubuntu_defconfig
    odroidu2_ubuntu_defconfig       odroidx2_ubuntu_mali_defconfig
    odroidu2_ubuntu_mali_defconfig  odroidx_ubuntu_defconfig
    odroidu_ubuntu_defconfig        odroidx_ubuntu_mali_defconfig

now choose your config and copy it to /usr/src/linux/.config (I chose odroidu2_ubuntu_defconfig)

# This step prepares for building and copies the configuration from arch/arm/configs to .config
make odroidu2_ubuntu_defconfig

Now you can build the kernel according to the configuration you chose, or you and make configuration changes.

You can configure the kernel using either text mode or GUI. The results are the same. The search functions in the GUI are nice. If you only have the serial console, you will need to use text mode.

Text mode

apt-get install build-essential git libncurses5-dev
make menuconfig

Graphical mode

apt-get install build-essential git qt4-dev-tools
make xconfig

change everything to your needs (use / for searching)

Configuration Example: MALI Overclock

The odroid-u2 can work with a faster clock for the GPU, you may want to configure your kernel to overclock it. For example, edit your .config file and search for CONFIG_MALI_OVERCLOCK. Select the speed you want to try.

    # CONFIG_MALI_OVERCLOCK_533 is not set
    # CONFIG_MALI_OVERCLOCK_640 is not set
    # CONFIG_MALI_OVERCLOCK_733 is not set
    # CONFIG_MALI_OVERCLOCK_800 is not set

For example, to select 640MHz, change:

# CONFIG_MALI_OVERCLOCK_640 is not set



Only select one though! Think about it...

Building the kernel

make -j8
# If you are building as root:
make modules_install
# If you are building as user:
sudo make modules_install
make zImage

Mounting the Boot Partition

The boot partition is the section on the media, either SD-Card or eMMC, that holds the kernel image and the initial root filesystem. For the Hardkernel Ubuntu systems, the boot partition would be mounted at /media/boot. For other distros, the boot partition may not be mounted automatically and by default if might like to be mounted to a different location. For example, the Debian Wheezy distro does not currently mount it, and this and other tutorials mount it at /boot when necessary.

You can work the tutorial and substitute /boot/media for /boot if you like, although it will not cause a problem if you just use /boot. Create the /boot directory to use as a mount point if you need to.

This code snippet shows one way to mount the boot partition

    if [ ! -d /boot ]; then
        mkdir -p /boot || exit 1
    mountpoint /boot >/dev/null
    if [ $? -ne 0 ]; then
        mount -o rw /dev/mmcblk0p1 /boot || exit 1

Building the initial ram filesystem

This is not always needed -- unless you need changes in phase 1 of the Linux boot, it is best to leave this alone.

If you need a custom filesystem driver, or you want to directly mount your root file system on a thumb drive or NAS drive, this would be the area to work in. You would need to know that this is a busybox-based system completely separate from the eventual distro you intend to boot.

kernelversion=`cat ./include/config/kernel.release`
mkinitramfs -c gzip -o ./initramfs-$kernelversion $kernelversion
mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n initramfs -d ./initramfs-$kernelversion ./uInitrd
cp uInitrd /boot

Copying the kernel and initramfs to the boot partition

kernelversion=`cat ./include/config/kernel.release`
cp /boot/zImage /boot/zImage.prev
cp /boot/uInitrd /boot/uInitrd.prev
cp arch/arm/boot/zImage /boot
cp .config /boot/config-$kernelversion


cp /boot/$kernelversion


shutdown -h 0

power cycle after that.

The new kernel will show something like this:

uname -a

Linux odroidu2-1 3.0.57 #1 SMP Sun Jan 13 21:53:37 UTC 2013 armv7l GNU/Linux

The #1 came from the file: /usr/src/linux/.version. Each time you build, this number will be incremented.


Your new kernel built kernel modules that may not be compatible with other builds.

Please don't post a private kernel without giving a warning. If could break another system. If you make small changes, like select an additional module, the result will probably not segfault other systems. On the other hand, if you select some networking options (especially) you may find that structs don't quite line up and eventually someone will segfault.


This is an EXAMPLE script that shows how to update kernel modules in an EXISTING initrd. It does not quite work because the file is too large

The issue is that if you use the normal build script shown for a native initrd build on the host, you end up with binaries for your host instead of for the ARM

# filename: composite-drivers
# run this script from the kernel source top level directory
# It processes the odroid uInitrd to new-uInitrd, putting ALL the new kernel modules in the updated initial ram disk 
# the problem is that uInitrd is too large to be properly loaded by existing images (32MiB)
# This is a work in progress

mkdir $workdir >/dev/null 2>&1
mkdir $workdir/newmodules >/dev/null 2>&1
workdir=$(realpath $workdir)

kernelversion=`cat ./include/config/kernel.release`
# default the cross compiler prefix.  Used to strip binaries

step1() {
	cp uInitrd $workdir
	pushd $workdir >/dev/null
	echo stripping u-boot header
	dd if=uInitrd of=initrd skip=64 bs=1
	gunzip < initrd | cpio -i --make-directories
	rm initrd uInitrd
	popd >/dev/null

# This step doesn't actually do anything useful at this point.  Saves a list of previously used modules. 
step2() {
	echo "finding previous kernel module file names"
	pushd $workdir >/dev/null
	if [ -f $previousmodules ]; then 
		rm $previousmodules >/dev/null 2>&1
	filelist=$(find lib/modules -name '*.ko' )
	for f in $filelist; do 
		echo ${f#*/modules/*/} >> $previousmodules
	popd >/dev/null

if [ ! -f uInitrd ]; then
	echo "Error.  Cannot file uInitrd"
	exit -1

step3() {
	pushd $workdir >/dev/null
	echo "Removing existing modules"
	sudo rm -rf lib/modules
	popd >/dev/null

step4() {
	make INSTALL_MOD_PATH="$workdir/newmodules" modules_install >/dev/null
	rm $modpath/source
	rm $modpath/build

step5() {
	echo "Stripping debug symbols from kernel modules"
	find $modpath -name '*.ko' | xargs "$CROSS_COMPILE"strip -S

step6() {
	pushd $workdir >/dev/null
	previouslist=$(cat $previousmodules)
	for f in $previouslist; do
		if [ -f $modpath/$f ]; then 
			sudo mkdir -p $( dirname $destname )
			sudo cp -a $modpath/$f $destname
	popd >/dev/null	

step7() {
	pushd $workdir >/dev/null
	sudo rm -rf $modpath
	find . | cpio -H newc -o > ../$cpioname
	popd >/dev/null
	mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n initramfs -d ./$cpioname ./uInitrd-$kernelversion
	rm ./$cpioname