Android, IT

Compile an Android kernel module outside the kernel source tree.

I’ve decided to make a short tutorial and present the way I compile kernel modules (outside the kernel sources).

I’ve built few kernel modules (mainly governors – ineractive and smartass, but also cifs / nls-utf8, etc) and I started receiving private messages asking how I did it.

For kernel modules that come with the kernel itself – cifs / tun for example – they just work if you compile the kernel and activate correct config parameters.
Some other modules (such as the smartass governor that doesn’t come with the kernel) you compile outside the kernel source. However they require changes since kernel does not export the symbols the module needs to use – so you have to know what k_all_syms are needed, grab them from the phone and update the kernel module.

So there will be changes there. However, the main steps are:

a) follow tutorials to get the kernel / android ndk to compile. People seem able to do this.
b) then take the module you want (For example cpufreq_smartass.c from here: http://pastebin.com/rR4QUCrk ) and copy it in a new folder on the disk.
c) create a Makefile like the one below, but with your paths of course:

KERNEL_DIR=/home/viulian/android_platform/kernel-2.1.A.0.435/kernel

obj-m := cpufreq_smartass.o
PWD := $(shell pwd)
default:
        $(MAKE) ARCH=arm CROSS_COMPILE=/home/viulian/android_platform/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
clean:
        $(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) clean

d) execute make

Of course, the module source code needs to be adjusted as you need to put in the CPU frequencies, and also update the k_all_syms pointers .. But you can retrieve them from /proc/kallsyms on the device itself – just look for the method name, and use the address you see in the log.

If you still can’t get it to compile, try to compile a very basic hello_world kernel module. I used the code below when testing:

#include   /* Needed by all modules */
#include   /* Needed for KERN_ALERT */
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("viulian, 2011");
MODULE_DESCRIPTION("Demo module for X10i");
 
int init_module(void)
{
   printk("<1>Hello world\n");

   // A non 0 return means init_module failed; module can't be loaded.
   return 0;
}

void cleanup_module(void)
{
  printk(KERN_ALERT "Goodbye world 1.\n");
}

It is not perfect, but if you manage to insmod and then check dmesg, you will see “Hello world” written there.

One more thing, Linux kernel is fussy about the module versions. Even if nothing is changed between two kernel versions related to what a module needs, is enough a small difference in module’s modinfo value to make the kernel to refuse the module.

For this, you need to trick your local kernel and adjust EXTRAVERSION value in kernel’s main Makefile to have the exact version of the one on the device:

In X10 stock kernel (GB 2.3.3 release), the kernel version is 2.6.29-00054-g5f01537 visible in phone settings.

This means that the kernel on the phone will only accept modules that are compiled for that exact version. But the kernel version is just a string in the module .ko, so is a string comparison – the module might work perfectly, but is not loaded.
There is luck though, the string value comes from a define in kernel’s Makefile, which you can change before you compile!

The Makefile in the kernel you are going to use to build the module will have to include these lines at the top:

VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 29
EXTRAVERSION = -00054-g5f01537

Other than that, it should work ..

Expect phone reboots and difficulty to debug if stuff goes wrong. Android kernel doesn’t come with syslog functionality, kernel printk output is found in /proc/kmsg. Dmesg works, but you can’t execute if if phone reboots.
I usually had to keep another adb shell opening with ‘cat /proc/kmsg’ which showed as much as possible from the module’s outputs.

Happy compiling on your risk!

PS: I’ve posted the same tutorial on XDA’s website here: http://forum.xda-developers.com/showthread.php?p=17020258#post17020258

8 Comments

  1. cHUCK

    Any takers to do a video status? Come on people it would be good for newbies like me and many that tme around. When teaching the community grows. Please friend do a video tutorial will help a lot please

  2. Comment by post author

    Trouble is that is very lenghtly process to compile the kernel and MANY things might go wrong.

    You need some knowledge about how to compile, how to configure stuff as your Linux distribution might not have the same stuff installed and then errors might creep up from everywhere.
    A video can’t show all possible configuration issues .. it would just show that for me it works, for example.

    So better try to follow instructions, learn along the way 🙂 and post errors or whatever you encounter.

  3. creezalird

    i am just learning regarding kernel compiling, and would like to insert governor as module into the initramfs.

    ” But you can retrieve them from /proc/kallsyms on the device itself – just look for the method name, and use the address you see in the log.”

    what u meant by method name? as i try to compare kallsyms list with the c code, but you know, the kallsyms list is quite large. thanks

  4. Comment by post author

    @creezalird -> Please check here: http://pastebin.com/rR4QUCrk

    If you want to call the method “default_idle” defined in the Kernel, if is not exported, you have two choices:

    a) look it up in k_all_syms and hardcode the address (then use the trick shown above for kallsyms_lookup_name_ax to make a function pointer to point at that addres)

    b) only hardcode the address of kallsyms_lookup_name (which is another method from the kernel) which gives you runtime address of all the other methods by only having their names (again, please check the code above to see how to make a function pointer to the address of kallsyms_lookup_name which you grab from k_all_syms, then you can detect the address of all other functions just by using this one which does the lookup). I believe is cleaner like this and makes it easier to port across devices.

    I did not find this method, but reused it from the code I found online ..

  5. creezalird

    thanks for the information. i am trying to absorb it, could u please do me one more favor?
    could u provide the original non-modded c-code for the smartass so that i can do comparison and if possible also kallsyms list from x10, thanks very much

  6. Algarues

    Could you put something about recompiling single system binaries?
    Or point me somewhere where I could get such infos
    For example if I would recompile only /system/bin/mediaserver…
    Thanks a lot

  7. sam

    Hi,
    Thanks for this article, it is really interesting.
    I am doing research which requires me to build my own module. It seems like you have good experience in this area, therefore, if you allow me, I would like to ask few questions.

    The restriction I have is that I can’t use a custom kernel (i.e. built by third party like us), instead, I need to add the module to the stock kernel that ships with the device. So do I need to get exactly the same kernel as in the device ??
    I’ve seen some tutorial that allows you to do that but I get stuck when I need to get /proc/config.gz from the device since it is not there. So my question is your way to compile the module overcomes this issue ?? also when I transfer the new module to the device (.ko), can I install it without the root access (su) ?? lastly, what is the KERNEL_DIR exactly, (i.e. to which kernel it should point to) ??

    Thank you

  8. Comment by post author

    1. While you technically don’t need the exact source version (since you can fake the module kernel version just by changing the Makefile) you can avoid many issues if you use the source code with the same version as the installed one.
    2. If you don’t need an existing functionality in the device kernel (where it would be helpful to have the configuration file) then you could get away of just building a minimal set of things that get your module up and running. Then you hope for the best 🙂
    3. You will need root. Users can’t load modules, the modules could be ‘evil’.
    4. KERNEL_DIR is where you unpacked the kernel source code.

    I think is better if you read some advanced tutorials about the kernel / module and start writing a small kernel module that runs on a Linux machine, before moving onto Android. That’s how I did it anyway 🙂 and you will learn many things just by doing it.

Leave a Reply