Introduction
In this series of articles I describe how you can write a Linux kernel module for an embedded Linux device. I begin with a straightforward “Hello World!” loadable kernel module (LKM) and work towards developing a module that can control GPIOs on an embedded Linux device (such as the BeagleBone) through the use of IRQs. I will add further follow-up articles as I identify suitable applications.
This is a complex topic that will take time to work through. Therefore, I have broken the discussion up over a number of articles, each providing a practical example and outcome. There are entire books written on this topic, so it will be difficult to cover absolutely every aspect. There are also other articles available on writing kernel modules; however, the examples presented here are built and tested under the Linux kernel 3.8.X+, ensuring that the material is up to date and relevant, and I have focused on interfacing to hardware on embedded systems. I have also aligned the tasks performed against my book, Exploring BeagleBone, albeit the articles are self-contained and do not require that you own a copy of the book.
This article is focused on the system configuration, tools and code required to build and deploy a “Hello World!” kernel module. The second article in this series examines the topic of writing character device drivers and how to write C/C++ programs in user space that can communicate with kernel space modules. The third article examines the use of the kernel space GPIO library code — it combines the content of the first two articles to develop interrupt-driven code that can be controlled from Linux user space. For example, Figure 1 illustrates an oscilloscope capture of an interrupt-driven kernel module that triggers an LED to light when a button is pressed (click for a larger version). Under regular embedded Linux (i.e., not a real-time variant), this code demonstrates a response time of approximately 20 microseconds (±5μs), with negligible CPU overhead.
What is a Kernel Module?
A loadable kernel module (LKM) is a mechanism for adding code to, or removing code from, the Linux kernel at run time. They are ideal for device drivers, enabling the kernel to communicate with the hardware without it having to know how the hardware works. The alternative to LKMs would be to build the code for each and every driver into the Linux kernel.
Figure 2: Linux user space and kernel space
Without this modular capability, the Linux kernel would be very large, as it would have to support every driver that would ever be needed on the BBB. You would also have to rebuild the kernel every time you wanted to add new hardware or update a device driver. The downside of LKMs is that driver files have to be maintained for each device. LKMs are loaded at run time, but they do not execute in user space — they are essentially part of the kernel.
Kernel modules run in kernel space and applications run in user space, as illustrated in Figure 2. Both kernel space and user space have their own unique memory address spaces that do not overlap. This approach ensures that applications running in user space have a consistent view of the hardware, regardless of the hardware platform. The kernel services are then made available to the user space in a controlled way through the use of system calls. The kernel also prevents individual user-space applications from conflicting with each other or from accessing restricted resources through the use of protection levels (e.g., superuser versus regular user permissions).
Why Write a Kernel Module?
When interfacing to electronics circuits under embedded Linux you are exposed to sysfs and the use of low-level file operations for interfacing to electronics circuits. This approach can appear to be inefficient (especially if you have experience of traditional embedded systems); however, these file entries are memory mapped and the performance is sufficient for many applications. I have demonstrated in my book that it is possible to achieve response times of about one third of a millisecond, with negligible CPU overhead, from within Linux user space by using pthreads, callback functions and sys/poll.h.
An alternative approach is to use kernel code, which has support for interrupts. However, kernel code is difficult to write and debug. My advice is that you should always to try to accomplish your task in Linux user space, unless you are certain that there is no other possible way!
[tagline_box backgroundcolor=”” shadow=”yes” shadowopacity=”0.7″ border=”0px” bordercolor=”” highlightposition=”top” content_alignment=”left” link=”https://github.com/derekmolloy/exploringBB/tree/master/extras/kernel/” linktarget=”_blank” modal=”” button_size=”” button_shape=”” button_type=”” buttoncolor=”” button=”Get Source Code” title=”Source Code for this Discussion” description=”” animation_type=”0″ animation_direction=”down” animation_speed=”0.1″ class=”” id=””]
All of the code for this discussion is available in the GitHub repository for the book Exploring BeagleBone. The code can be viewed publicly at: the ExploringBB GitHub Kernel Project directory, and/or you can clone the repository on your BeagleBone (or other Linux device) by typing:
1 2 |
molloyd@beaglebone:~$ sudo apt-get install git molloyd@beaglebone:~$ git clone https://github.com/derekmolloy/exploringBB.git |
The /extras/kernel/hello directory is the most important resource for this article. The auto-generated Doxygen documentation for these code examples is available in HTML format and PDF format.
[/tagline_box]
Prepare the System for Building LKMs
The system must be prepared to build kernel code, and to do this you must have the Linux headers installed on your device. On a typical Linux desktop machine you can use your package manager to locate the correct package to install. For example, under 64-bit Debian you can use:
molloyd@DebianJessieVM:~$ sudo apt-get update
molloyd@DebianJessieVM:~$ apt-cache search linux-headers-$(uname -r)
linux-headers-3.16.0-4-amd64 - Header files for Linux 3.16.0-4-amd64
molloyd@DebianJessieVM:~$ sudo apt-get install linux-headers-3.16.0-4-amd64
molloyd@DebianJessieVM:~$ cd /usr/src/linux-headers-3.16.0-4-amd64/
molloyd@DebianJessieVM:/usr/src/linux-headers-3.16.0-4-amd64$ ls
arch include Makefile Module.symvers scripts
You can complete the first two articles in this series using any flavor of desktop Linux. However, in this series of articles I build the LKM on the BeagleBone itself, which simplifies the process when compared to cross-compiling. You must install the headers for the exact version of your kernel build. Similar to the desktop installation, use uname to identify the correct installation. For example:
molloyd@beaglebone:~$ uname -a
Linux beaglebone 3.8.13-bone70 #1 SMP Fri Jan 23 02:15:42 UTC 2015 armv7l GNU/Linux
You can download the Linux headers for the BeagleBone platform from Robert Nelson’s website. For example, at: http://rcn-ee.net/deb/precise-armhf/. Choose the exact kernel build, and download and install those Linux-headers on your BeagleBone. For example:
molloyd@beaglebone:~/tmp$ wget http://rcn-ee.net/deb/precise-armhf/v3.8.13-bone70/linux-headers-3.8.13-bo
ne70_1precise_armhf.deb
100%[===========================>] 8,451,080 2.52M/s in 3.2s
2015-03-17 22:35:45 (2.52 MB/s) - 'linux-headers-3.8.13-bone70_1precise_armhf.deb' saved [8451080/8451080]
molloyd@beaglebone:~/tmp$ sudo dpkg -i ./linux-headers-3.8.13-bone70_1precise_armhf.deb
Selecting previously unselected package linux-headers-3.8.13-bone70
You can then check that the headers have installed correctly:
molloyd@beaglebone:~/tmp$ cd /usr/src/linux-headers-3.8.13-bone70/
molloyd@beaglebone:/usr/src/linux-headers-3.8.13-bone70$ ls
Documentation Module.symvers crypto fs ipc mm scripts tools
Kconfig arch drivers include kernel net security usr
Makefile block firmware init lib samples sound virt
Under the 3.8.13-bone47 Debian distribution for the BeagleBone, you may have to perform an unusual step of creating an empty file timex.h (i.e., touch timex.h) in the directory /usr/src/linux-headers-3.8.13-bone47/arch/arm/
include/mach. This step is not necessary under the bone70 build.
[tagline_box backgroundcolor=”” shadow=”yes” shadowopacity=”0.7″ border=”0px” bordercolor=”” highlightposition=”top” content_alignment=”left” link=”” linktarget=”” modal=”” button_size=”” button_shape=”” button_type=”” buttoncolor=”” button=”” title=”A Warning!” description=”” animation_type=”0″ animation_direction=”down” animation_speed=”0.1″ class=”” id=””]
It is very easy to crash the system when you are writing and testing LKMs. It is always possible that such a system crash could corrupt your file system — it is unlikely, but it is possible. Please back up your data and/or use an embedded system, such as the BeagleBone, which can easily be re-flashed. Performing a sudo reboot, or pressing the reset button on the BeagleBone will usually put everything back in order. No BeagleBones were corrupted in the writing of these articles despite many, many system crashes!
[/tagline_box]
The Module Code
The run-time life cycle of a typical computer program is reasonably straightforward. A loader allocates memory for the program, then loads the program and any required shared libraries. Instruction execution begins at some entry point (typically the main()
point in C/C++ programs), statements are executed, exceptions are thrown, dynamic memory is allocated and deallocated, and the program eventually runs to completion. On program exit, the operating system identifies any memory leaks and frees lost memory to the pool.
A kernel module is not an application — for a start there is no main()
function! Some of the key differences are that kernel modules:
- do not execute sequentially— a kernel module registers itself to handle requests using its initialization function, which runs and then terminates. The type of requests that it can handle are defined within the module code. This is quite similar to the event-driven programming model that is commonly utilized in graphical-user interface (GUI) applications.
- do not have automatic cleanup — any resources that are allocated to the module must be manually released when the module is unloaded, or they may be unavailable until a system reboots.
- do not have
printf()
functions — kernel code cannot access libraries of code that is written for the Linux user space. The kernel module lives and runs in kernel space, which has its own memory address space. The interface between kernel space and user space is clearly defined and controlled. We do however have aprintk()
function that can output information, which can be viewed from within user space. - can be interrupted — one conceptually difficult aspect of kernel modules is that they can be used by several different programs/processes at the same time. We have to carefully construct our modules so that they have a consistent and valid behavior when they are interrupted. The BeagleBone has a single-core processor (for the moment) but we still have to consider the impact of multiple processes accessing the module simultaneously.
- have a higher level of execution privilege — typically, more CPU cycles are allocated to kernel modules than to user-space programs. This sounds like an advantage, however, you have to be very careful that your module does not adversely affect the overall performance of your system.
- do not have floating-point support — it is kernel code that uses traps to transition from integer to floating-point mode for your user space applications. However, it is very difficult to perform these traps in kernel space. The alternative is to manually save and restore floating point operations — a task that is best avoided and left to your user-space code.
The concepts above are a lot to digest and it is important that they are all addressed, but not all in the first article! Listing 1 provides the code for a first example LKM. When no kernel argument is provided, the code uses the printk()
function to display “Hello world!…” in the kernel logs. If the argument “Derek” is provided, then the logs will display “Hello Derek!…” The comments in Listing 1, which are written using a Doxygen style, describe the role of each statement. Further description is available after the code listing below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/** * @file hello.c * @author Derek Molloy * @date 4 April 2015 * @version 0.1 * @brief An introductory "Hello World!" loadable kernel module (LKM) that can display a message * in the /var/log/kern.log file when the module is loaded and removed. The module can accept an * argument when it is loaded -- the name, which appears in the kernel log files. * @see http://www.derekmolloy.ie/ for a full description and follow-up descriptions. */ #include <linux/init.h> // Macros used to mark up functions e.g., __init __exit #include <linux/module.h> // Core header for loading LKMs into the kernel #include <linux/kernel.h> // Contains types, macros, functions for the kernel MODULE_LICENSE("GPL"); ///< The license type -- this affects runtime behavior MODULE_AUTHOR("Derek Molloy"); ///< The author -- visible when you use modinfo MODULE_DESCRIPTION("A simple Linux driver for the BBB."); ///< The description -- see modinfo MODULE_VERSION("0.1"); ///< The version of the module static char *name = "world"; ///< An example LKM argument -- default value is "world" module_param(name, charp, S_IRUGO); ///< Param desc. charp = char ptr, S_IRUGO can be read/not changed MODULE_PARM_DESC(name, "The name to display in /var/log/kern.log"); ///< parameter description /** @brief The LKM initialization function * The static keyword restricts the visibility of the function to within this C file. The __init * macro means that for a built-in driver (not a LKM) the function is only used at initialization * time and that it can be discarded and its memory freed up after that point. * @return returns 0 if successful */ static int __init helloBBB_init(void){ printk(KERN_INFO "EBB: Hello %s from the BBB LKM!\n", name); return 0; } /** @brief The LKM cleanup function * Similar to the initialization function, it is static. The __exit macro notifies that if this * code is used for a built-in driver (not a LKM) that this function is not required. */ static void __exit helloBBB_exit(void){ printk(KERN_INFO "EBB: Goodbye %s from the BBB LKM!\n", name); } /** @brief A module must use the module_init() module_exit() macros from linux/init.h, which * identify the initialization function at insertion time and the cleanup function (as * listed above) */ module_init(helloBBB_init); module_exit(helloBBB_exit); |
In addition to the points described by the comments in Listing 1, there are some additional points:
- Line 16: The statement
MODULE_LICENSE("GPL")
provides information (via modinfo) about the licensing terms of the module that you have developed, thus allowing users of your LKM to ensure that they are using free software. Since the kernel is released under the GPL, your license choice impacts upon the way that the kernel treats your module. You can choose"Proprietary"
for non-GPL code, but the kernel will be marked as “tainted” and a warning will appear. There are non-tainted alternatives to GPL, such as"GPL v2"
,"GPL and additional rights"
,"Dual BSD/GPL"
,"Dual MIT/GPL"
, and"Dual MPL/GPL"
. See linux/module.h for more information. - Line 21: The
name
(ptr to char) is declared asstatic
and is initialized to contain the string “hello”. You should avoid using global variables in kernel modules — it is even more important than in application programming, as global variables are shared kernel wide. You should use thestatic
keyword to restrict a variable’s scope to within the module. If you must use a global variable, add a prefix that is unique to the module that you are writing. - Line 22: The
module_param(name, type, permissions)
macro has three parameters:name
(the parameter name displayed to the user and the variable name in the module),type
(the type of the parameter — i.e., one ofbyte
,int
,uint
,long
,ulong
,short
,ushort
,bool
, an inverse Booleaninvbool
, or a char pointercharp
), andpermissions
(this is the access permissions to the the parameter when using sysfs and is covered below. A value of0
disables the entry, butS_IRUGO
allows read access for user/group/others — See the Mode Bits for Access Permissions Guide) - Line 31 and 40: The functions can have whatever names you like (e.g.,
helloBBB_init()
andhelloBBB_exit()
), however, the same names must be passed to the special macrosmodule_init()
andmodule_exit()
on lines 48 and 49. - Line 31: The
printk()
is very similar in usage to theprintf()
function that you should be familiar with, and you can call it from anywhere within the kernel module code. The only significant difference is that you should specify a log level when you call the function. The log levels are defined in linux/kern_levels.h as one ofKERN_EMERG
,KERN_ALERT
,KERN_CRIT
,KERN_ERR
,KERN_WARNING
,KERN_NOTICE
,KERN_INFO
,KERN_DEBUG
, andKERN_DEFAULT
. This header is included via thelinux/kernel.h
header file, which includes it vialinux/printk.h
.
Essentially, when this module is loaded the helloBBB_init()
function will execute, and when the module is unloaded the helloBBB_exit()
function will execute.
The next step is to build this code into a kernel module.
Building the Module Code
A Makefile is required to build the kernel module — in fact, it is a special kbuild Makefile. The kbuild Makefile required to build the kernel module in this article can be viewed in Listing 2.
1 2 3 4 5 6 |
obj-m+=hello.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean |
The first line of this Makefile is called a goal definition and it defines the module to be built (hello.o). The syntax is surprisingly intricate, for example obj-m
defines a loadable module goal, whereas obj-y
indicates a built-in object goal. The syntax becomes more complex when a module is to be built from multiple objects, but this is sufficient to build this example LKM.
The reminder of the Makefile is similar to a regular Makefile. The $(shell uname -r)
is a useful call to return the current kernel build version — this ensures a degree of portability for the Makefile. The -C
option switches the directory to the kernel directory before performing any make tasks. The M=$(PWD)
variable assignment tells the make command where the actual project files exist. The modules
target is the default target for external kernel modules. An alternative target is modules_install
which would install the module (the make command would have to be executed with superuser permissions and the module installation path is required).
All going well, the process to build the kernel module should be straightforward, provided that you have installed the Linux headers as described earlier. The steps are as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ ls -l
total 8
-rw-r--r-- 1 molloyd molloyd 154 Mar 17 17:47 Makefile
-rw-r--r-- 1 molloyd molloyd 2288 Apr 4 23:26 hello.c
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ make
make -C /lib/modules/3.8.13-bone70/build/ M=/home/molloyd/exploringBB/extras/kernel/hello modules
make[1]: Entering directory '/usr/src/linux-headers-3.8.13-bone70'
CC [M] /home/molloyd/exploringBB/extras/kernel/hello/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/molloyd/exploringBB/extras/kernel/hello/hello.mod.o
LD [M] /home/molloyd/exploringBB/extras/kernel/hello/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-3.8.13-bone70'
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ ls
Makefile Module.symvers hello.c
You can see that there is now a hello loadable kernel module in the build directory with the file extension .ko.
Testing the LKM
This module can now be loaded using the kernel module tools as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ ls -l *.ko
-rw-r--r-- 1 molloyd molloyd 4219 Apr 4 23:27 hello.ko
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ sudo insmod hello.ko
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ lsmod
Module Size Used by
g_multi 50407 2
libcomposite 15028 1 g_multi
omap_rng 4062 0
mt7601Usta 639170 0
You can get information about the module using the modinfo command, which will identify the description, author and any module parameters that are defined:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ modinfo hello.ko
filename: /home/molloyd/exploringBB/extras/kernel/hello/hello.ko
license: GPL
srcversion: 9E3F5ECAB0272E3314BEF96
depends:
vermagic: 3.8.13-bone70 SMP mod_unload modversions ARMv7 thumb2 p2v8
The module can be unloaded using the rmmod command:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ sudo rmmod hello.ko
You can repeat these steps and view the output in the kernel log that results from the use of the printk()
function. I recommend that you use a second terminal window and view the output as your LKM is loaded and unloaded, as follows:
molloyd@beaglebone:~$ sudo su -
[sudo] password for molloyd:
root@beaglebone:~# cd /var/log
root@beaglebone:/var/log# tail -f kern.log
...
Apr 4 23:34:32 beaglebone kernel: [21613.495523]
Apr 4 23:35:17 beaglebone kernel: [21658.306647]
^C
root@beaglebone:/var/log#
Testing the LKM Custom Parameter
The code in Listing 1 also contains a custom parameter, which allows an argument to be passed to the kernel module on initialization. This feature can be tested as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ sudo insmod hello.ko
If you view /var/log/kern.log at this point then you will see “Hello Derek” in place of “Hello world”. However, it is worth having a look at /proc and /sys first.
Rather than using the lsmod command, you can also find out information about the kernel module that is loaded, as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ cd /proc
molloyd@beaglebone:/proc$ cat modules|grep hello
hello 972 0 - Live 0xbf903000 (O)
This is the same information that is provided by the lsmod command but it also provides the current kernel memory offset for the loaded module, which is useful for debugging.
The LKM also has an entry under /sys/module, which provides you with direct access to the custom parameter state. For example:
molloyd@beaglebone:/proc$ cd /sys/module
molloyd@beaglebone:/sys/module$ ls -l|grep hello
drwxr-xr-x 6 root root 0 Apr 5 00:02 hello
molloyd@beaglebone:/sys/module$ cd hello
molloyd@beaglebone:/sys/module/hello$ ls -l
total 0
-r--r--r-- 1 root root 4096 Apr 5 00:03 coresize
drwxr-xr-x 2 root root 0 Apr 5 00:03 holders
-r--r--r-- 1 root root 4096 Apr 5 00:03 initsize
-r--r--r-- 1 root root 4096 Apr 5 00:03 initstate
drwxr-xr-x 2 root root 0 Apr 5 00:03 notes
-r--r--r-- 1 root root 4096 Apr 5 00:03 refcnt
drwxr-xr-x 2 root root 0 Apr 5 00:03 sections
-r--r--r-- 1 root root 4096 Apr 5 00:03 srcversion
-r--r--r-- 1 root root 4096 Apr 5 00:03 taint
--w------- 1 root root 4096 Apr 5 00:02 uevent
-r--r--r-- 1 root root 4096 Apr 5 00:02 version
molloyd@beaglebone:/sys/module/hello$ cat version
0.1
molloyd@beaglebone:/sys/module/hello$ cat taint
O
The version value is 0.1 as per the MODULE_VERSION("0.1")
entry and the taint value is 0 as per the license that has been chosen, which is MODULE_LICENSE("GPL")
.
The custom parameter can be viewed as follows:
molloyd@beaglebone:/sys/module/hello$ cd parameters/
molloyd@beaglebone:/sys/module/hello/parameters$ ls -l
total 0
-r--r--r-- 1 root root 4096 Apr 5 00:03 name
molloyd@beaglebone:/sys/module/hello/parameters$ cat name
Derek
You can see that the state of the name
variable is displayed, and that superuser permissions where not required to read the value. The latter is due to the S_IRUGO
argument that was used in defining the module parameter. It is possible to configure this value for write access but your module code will need to detect such a state change and act accordingly. Finally, you can remove the module and observe the output:
molloyd@beaglebone:/sys/module/hello/parameters$ sudo rmmod hello.ko
As expected, this will result in the output message in the kernel logs:
root@beaglebone:/var/log# tail -f kern.log
…
Apr 5 00:02:20 beaglebone kernel: [23281.070193] EBB: Hello
Apr 5 00:08:18 beaglebone kernel: [23639.160009] EBB: Goodbye
Conclusions
Hopefully you have built your first loadable kernel module (LKM). Despite the simplicity of the functionality of this module there was a lot of material to cover — by the end of this article: you should have a broad idea of how loadable kernel modules work; you should have your system configured to build, load and unload such modules; and, you should be able to define custom parameters for your LKMs.
The next step is to build on this work to develop a kernel space LKM that can communicate with a user space C/C++ program by developing a basic character driver. See “Writing a Linux Kernel Module — Part 2: A Character Device“. Then we can move on to the more interesting task of interacting with GPIOs.
When I checked for my kernel version of Beaglebone Black using uname -a,
it shows that “Linux beaglebone 3.8.13-bone71 #1 SMP Tue Mar 17 18:07:44 UTC 2015 armv7l GNU/Linux”.
So, I tried to find the proper Linux headers and found it from https://rcn-ee.net/deb/wheezy-armhf/v3.8.13-bone71/.
And downloaded it by command following ‘wget https://rcn-ee.net/deb/wheezy-armhf/v3.8.13-bone71/linux-headers-3.8.13-bone71_1wheezy_armhf.deb‘.
Is this right for my BBB?
Thanks in advance,
John
After installation with the Linux headers with bone71, I followed the sequence you stated, and I saw the same results with you.
Thanks,
John
Hi Derek,
I have installed the 3.8.13-bone47 headers but there is no “mach” file under include.
Under “include” there are four files “asm debug generated uapi” and under “asm” there is the mach file.
should I create the file “timex.h” there??????
Hi there, you may have to create sub directories (I can’t remember if I did), but it should be empty and have the full path “/usr/src/linux-headers-3.8.13-bone47/arch/arm/include/mach/timex.h”. Kind regards, Derek.
created the “timex.h” in /asm/mach as I was getting error of “…./include/asm/mach/timex.h” — no such file or directory.
This solved the problem and compiled & loaded the LKM successfully.
Thanks for the contributions.
Now I am having only three questions in mind.
1.Can I use interrupt in user space and do run time debug in eclipse ?(at present I am using interrupt in kernel space and compiling & running code through command terminal but not in eclipse IDE, i would like to dubug LKM code in eclipse IDE also.)
2. Can I make program which contains both user space and kernel space program?
3.Can I run kernel program in eclipse & do run time debug in eclipse ?
Hi Derek
I have read a lot of articles written by you on Embedded Systems programming and all of them are utterly useful. You tutorial videos are crisp and clear, they go through the basics of the topic in question very smoothly. I would request you to please create a course on EdX or Coursera regarding Object Oriented embedded systems programming in the ARM platform. It would be really a great resource for all of us.
Thanks
Regards
Rish
These are really useful information. Very good to have such sites giving so much information about embedded systems.
Great article, Derek. Thanks for writing it.
Hi,
These articles are AMAZING!!!! I’ve been trying so hard to find an easy to follow and read articles on the internet but failed miserably, just stumpled upon this artice on reddit. Thanks alot Dr.Derek!!!! 🙂
Derek: Well done! I’m going to use this in my class next week.
–Mark
p.s. Why not use “apt-get install linux-headers-3.8.13-bone77” to load the headers?
Thanks Mark! The apt-get call wouldn’t work at the time — Glad to see that it is fixed! Kind regards, Derek.
Hi Derek,
great articles!
Do i need a LKM to get the SGX-Module on Sitara runing on Ubuntu?
Or, do you have an advice for me how it works
Thanks!
Hey there Derek,
I’m using the BeagleBone black with:
Linux beaglebone 3.8.13-bone47
Should i use the “v3.8.13-bone71/ “-headers which are available currenly? will the be suitable for my BeagleBone?
THANK YOU, for some awesome articles!!!
Okay, it turns out that the proper version of the header files is quite important 🙂 I got the ones from http://rcn-ee.net/deb/trusty-armhf/v3.8.13-bone47/ and added the mach/timex.h file, and was the able to follow this guide.
Thank you..
Hi Derek,
great tutorial,and great book.
I would like to ask you if I want to cross-compile a device driver,i.e. on jessie host machine, which kind of “steps” I had to performs since the arch and config file are not the same.
What I would like to do is ( if possible ) develop my dd and build it on host and then run on BBB. Could you tell me please where I could find some info about.
Thank you
Giorgio
Hi Derek-
It seems there a no .deb files anywhere under Robert Nelson’s website anymore — I’m just seeing patch .diff.gz files.
Any idea where to get deb packages for the various Beaglebone black debian releases anymore?
Thanks.
Derek-
I figured it out — maybe this will help someone if you approve this comment.
I’m running an older 2014-04-23 debian image (from dogtag file) kernel 3.8.13-bone69
To get the kernel headers from Robert Nelsons repo I had to add this to /etc/apt/sources.list
deb [arch=armhf] http://rcn-ee.net/repos/debian wheezy main
Then apt-get update and apt-cache search kernel-headers reveals a whole bunch of headers available to install including my kernel 3.8.13-bone69
Now I’m going to try and compile the kenrel module Nathanial Lewis wrote that supports the TI eQEP encoder hardware.
Thanks for all you do — makes using the beaglebone platform a pleasure!
Hi Mr. Malloy,
I have looked for Linux headers for the BeagleBone on Robert Nelson’s website to no avail.
Do you have any idea how to get those headers
Thanls for the good work
You should try my comment above by adding the line shown to /etc/apt/sources.list and do apt-get update.
Robert Nelsons site is a debian repository and when the apt package system accesses it you will find the linux headers no problem. Good luck!
Thanks for the advice.
The problem was solved by using the latest kernel: bone79
Here is Robert Nelson explanation:
bone50 was released around May 12, 2014..
It wasn’t till later that summer/fall 2014 did i get the repo up and running for every kernel release.
Hi Mr. Malloy, Here is the result:
root@beaglebone:~# sudo apt-get install linux-headers-
uname -r
Reading package lists… Done
Building dependency tree
Reading state information… Done
E: Unable to locate package linux-headers-3.8.13-bone50
E: Couldn’t find any package by regex ‘linux-headers-3.8.13-bone50’
Problem solved by using the latest kernel: bone79
Here is Robert Nelson explanation:
bone50 was released around May 12, 2014..
It wasn’t till later that summer/fall 2014 did i get the repo up and running for every kernel release..
“wget http://rcn-ee.net/deb/precise-armhf/v3.8.13-bone70/linux-headers-3.8.13-bone70_1precise_armhf.deb,”
The file is gone from the web site. Would you please tell where I can get the file? I try to use 3.8.13-bone70 on Beaglebone Black now to develop mt test driver of I2C device.
Hi Derek,
Really nice example of a device driver with interrupts!
I am trying to build a LKM using a cross compiler on an Ubuntu Linux PC. My target is not exactly beaglebone black but a very similar board for our specific purposes – we use the TI am3358 processor and buildroot. I just took button.c and tried to compile it and I get the errors:
1. error: negative width in bit-field ”
#define BUILD_BUG_ON_ZERO(e) (sizeof((struct { int:-!!(e); }))
^
I checked this file and since the __CHECKER__ flag is undefined it is going to this code…
What might I be doing wrong?
Thanks!
This is how I downloaded the Linux headers:
1) add this to the top of the file /etc/apt/sources.list deb [arch=armhf] http://rcn-ee.net/repos/debian wheezy main
2) apt-get update
3) apt-get upgrade
4)reboot
5)uname -r gave me 4.1.15-bone18
6)apt-get install linux-headers-4.1.15-bone18
7) The new linux headers are now in /usr/src/
Hi,
I tried to write a LKM for epaper lcd display which uses SPI,PWM and GPIOs. After loading the linux devicetree for BBB, I get an error message in dmesg. the last few lines of dmesg
[ 269.742198] check pwm
[ 269.742273] /ocp/spi@48030000/epd@0: could not get #pwm-cells for /ocp/epwmss@48302000/ehrpwm@48302200
[ 269.752250] epd: Cannot get pwm -22
[ 269.777286] Call epd_therm_remove()
[ 269.781123] i2c temperature probe excluded
[ 269.799667] epd: Fail to create COG-G1
[ 269.812813] prvdsp,g1-epd: probe of spi1.0 failed with error -22
May I get some help in device tree coding for BBB.
regards
venkat
great tutorial sir…!
Hey Derek,
I’m using the BeagleBone black with:
Linux beaglebone 3.8.13-bone47
sudo apt-get update command give this error
W: There is no public key available for the following key IDs:
7638D0442B90D010
W: There is no public key available for the following key IDs:
7638D0442B90D010
W: GPG error: http://rcn-ee.net wheezy Release: The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY D284E608A4C46402
W: There is no public key available for the following key IDs:
9D6D8F6BC857C906
Also unable to install header files . Please help me with this
I have the same problem. I’m also usingLinux beaglebone 3.8.13-bone47 and I get the same kind of error and it was not possible to download the headers. Any help?
Hi derek,
when i make it then it shows the following error and my module doesn’t load
make -C /lib/modules/3.8.13-bone79/build/ M=/home/debian/Desktop/exploringBB-master/extras/kernel/hello modules
make: *** /lib/modules/3.8.13-bone79/build/: No such file or directory. Stop.
make: *** [all] Error 2
Hi Derek
In any of your writing, do you compare the merits of using LKMs and UIO (user-space I/O) for developing device drivers?
Just wondered whether your new Raspberry Pi book discusses this?
Best regards
i think we should avoid to develop the modules for kernel.i think we should try to connect the kernel with a simple and more popular programming language.my opinion is this programming language is complex of present,so i think the performance of programmers is going to high when they get the easy of help-information and isn’t wrecking on the code.i think i can know how to create an operating system and i know how it’s make a sense from transistors,we could make it more simpler of syntax,but why we didn’t?
Thank you, highly informative article. I have been running the example on 4.1.15-ti-r43 without any issue. The linux kernel headers were already available from the sd card image downloaded from beaglebone.org (dpkg -l | grep Linux-headers).
insmod:ERROR: could not insert module hello.ko:Required ker not available
can you tell me what should I do now?
Hi,
Derek, this is a great initiative and helps Linux Noobs like us migrate from bare metal to Linux OS.
In case you are having trouble installing the linux kernel headers, like file not available etc, then you can refer to the below link.
https://groups.google.com/forum/#!topic/beagleboard/3LlPLiIGByM
It is a different way to install the linux kernel headers of BBB.
Thank Derek once again for your knowledge sharing and this platform.
Regards
Thanks a lot for this tutorial Derek.
Hi Derek ,
I must say really nice tutorials and you have done really well in organizing the stuffs.
I have done some character driver programming on my Linux machine on my laptop.Now I want to interface some hardware and do driver programming on BeagleBone. The problem I am facing is I am not getting the Kernel Headers for the version of Linus installed on my BeagleBone.
I have 3.8.13-bone81 , but kernel headers I am not able to get.
I would really appreciate if you can guide me in this respect.
Hey Derek,
I Just want to ask about the linux headers for cross compiling Kernel module on the host machin.
Here you write to download the linux headers of the host machin kernel version and in other tutorial was writen to download the linux headers of the BBB kernel version to the host machin.
i also have other linux device that based on the AM335x and i succeed to cross compile kernel module and “insmod” it on the device with the explanation of the tutorial about the linux kernel headers of the target device.
I Am very confusing about the cross compiling kernel module process.
Also, if i want to compile on my BBB, i need to download the linux headers for my beagle kernel that is 3.8.13-bone50 but i cant find headers for that kernel.
Thanks,
orenz
https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Installing_kernel_headers
this website provides the commands for automatically downloading the proper headers for the kernel.
That’s great the tutorial. Thanks Mr Derek.
very nice and Informative, preparing for linux Certification, looking for some linux tutorial,found http://www.kerneltraining.com/linux-admin-training/ best institute, can anyone suggest me some books and videos.
Hi, I cross-compiled and run your code on 2.6.37 kernel, but it stucks for like 13 seconds after I do insmod. Do you have any idea?
Derek – Great writeup. Thanks for taking the time to spin this out. Much appreciated!
Hi Derek,
Thanks for the intro to developing a LKM. Just what I needed.
There is a typo in the description of line 21. You say the value of name is initialized to “hello”, but in the code it is initialized to “world”.
This article is really great, I am a student interested in exploit development (Windows and Linux). I really want to learn how to develop kernel modules (rootkits) like a professional. Can you give me some references to resourceful materials please.
“Lectures in object-oriented programming with embedded systems, digital and analog electronics, and 3D computer graphics. His research contributions are largely in the fields of computer and machine vision, 3D graphics, embedded systems, and e-Learning.” — YOU ARE THE PERSON I WANT TO BE!
Thanks for writing this 🙂
Wow. That is so elegant and logical and clearly explained. Keep it up! I follow up your blog for future post.
sir,
I need your help while making drivers for my touchscreen in my custom kernel adnroid device melfas mip4 mms449 module touchscreen.
would you help me for making these drivers.
Best Regards
i was able to compile and run my first kernel driver with this blog. thank you!
the website that you used to download the kernel header doesn’t seem to work anymore.
I used: https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Installing_kernel_headers
to download my headers.
Specifically used the following command to automatically download the correct linux header version that i needed:
sudo apt-get install linux-headers-
uname -r
Hi derek,
thanks for this awesome tutorial,but i need one help i want know how to do cross compilation using ubuntu..
Great tutorial. We are trying external interrupt for NVidia TX2 (ARM). When I try to build the Hello project, I got this:
***************************************************************
make -C /lib/modules/4.4.38-tegra/build/ M=/home/nvidia/Downloads/exploringBB/extras/kernel/hello modules
make[1]: Entering directory ‘/lib/modules/4.4.38-tegra/build’
make[1]: *** No rule to make target ‘modules’. Stop.
make[1]: Leaving directory ‘/lib/modules/4.4.38-tegra/build’
Makefile:4: recipe for target ‘all’ failed
make: *** [all] Error 2
***************************************************************
I recall that when I do “$apt-cache search linux-headers-$(uname -r)”, I got nothing, however:
*************************************************
nvidia@tegra-ubuntu:~$ cd /usr/src/linux-headers-4.4.38-tegra/
nvidia@tegra-ubuntu:/usr/src/linux-headers-4.4.38-tegra$ ls
arch drivers ipc Makefile net sound
block firmware Kbuild mm README System.map
certs fs Kconfig modules.builtin samples tools
crypto include kernel modules.order scripts usr
Documentation init lib Module.symvers security virt
nvidia@tegra-ubuntu:/usr/src/linux-headers-4.4.38-tegra$
**************************************************
It seems cannot find the header files. Any suggestions?
I think you are missing the linux-header package.
Try this command first: sudo apt-get install –reinstall linux-headers-$(uname -r) linux-headers-generic build-essential dkms git
Hi derek;
I tried to strip -s the LKM to minimize his size as I usually do in normal binary.
In inserting the module i get an error : Ivalid module format.
and a dmesg log : module has no symbols (stripped?).
Is it denied to strip a Kernel module ?
Best regards;
Hey, Thanks for this neat introduction.
I accidentally found the reason behind this weird syntax for modules and built-in codes, so I thought I’d share it with others. In the Makefile of every subdirectory, there is a line:
obj-$(CONFIG_MODULES) += module.o
or something very similar. Depending on whether you selected each part as built-in (i.e. said y in kernel config) or module (indicated by ‘m’), this variable gathers the appropriate object files.
Thanks again!
This was a very helpful article, thanks Derek! I’ve been looking for some good learning resources on Linux Kernel Modules and this was fantastic. Looking forward to going through the following articles. Cheers!
Good day to you mr Derek Molloy
I am currenty using Ip Fire version 2.21 with BASE OS linux kernel version 4.14.72
I have a Internal “ADSL PCI Modem” Identified as “Integrated Telecom Express” but no drivers modued loaded
I was following your blog from part 1 and part 2 http://derekmolloy.ie/writing-a-linux-kernel-module-part-2-a-character-device/
It is impossible for me to install “linux-headers” dedicated for IPFIRE using wget command …it is not working on ipdfire
Is is working maynbe for Unbuntu ” Debian only”
Can you help me and assist me building kernel drivers module for linux kernel version 4.14.72 and Ip Fire version 2.21
Receive my regards and thanks in advance
i just go through your article it’s very interesting time just pass away by reading your article looking for more updates. Thank you for sharing.Naresh IT
A really excellent tutorial. Many thanks Derek.
the best tutorial i’ve ever seen,thank you so much
I am using Phytech-wega board where i am try to download the kernel header but face problem.Can you suggest me ,where from i can download the kernel header .
root@phyBOARD-WEGA-AM335x:~ uname -r
3.2.0-PD13.0.0