Yocto: Add hello world kernel module
In this section, you are going to learn
How to create a simple kernel module in yocto ?
How to generate full yocto image for RPI-4B ?
How to flash full yocto image for RPI-4B ?
How to run minicom and work remotely with RPI-4B ?
Topics in this section,
Step 1 : Add custom kernel module
Step 2 : Add configurations in .conf files
Step 5.1: Check the location of the kernel_module binary file
Step 5.2: Check the “objdump” output of the kernel_module binary file
Step 5.3: Check the “readelf” output of the kernel_module binary file
Step 5.4: Check the “nm” output of the kernel_module binary file
Step 5.5: Check the “file” command output of kernel_module binary file
Step 5.6: Check the “size” command output of kernel_module binary file
Step 5.7: Check the “strings” command output of kernel_module binary file
Step 6: Build full yocto - Incremental
Step 1: Install all the required packages
$ sudo apt-get install gawk wget git diffstat unzip texinfo gcc-multilib build-essential chrpath cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping
Step 2: Clone the yocto source directory
To clone poky directory
$ mkdir sources $ cd sources $ git clone -b langdale git://git.yoctoproject.org/poky.git
To clone openembedded core layer
$ git clone -b langdale git://git.openembedded.org/meta-openembedded
To clone meta-raspberrypi layer
$ git clone -b langdale git://git.yoctoproject.org/meta-raspberrypi
Step 3: Initialize the build environment
$ cd .. $ . sources/poky/oe-init-build-env
Step 4: Edit the local.conf and bblayers.conf file
Add the following configurations in conf/local.conf
MACHINE ??= "raspberrypi4"
Add the following yocto layers in conf/bblayers.conf
BBLAYERS ?= " \ /home/test/yocto/sources/poky/meta \ /home/test/yocto/sources/poky/meta-poky \ /home/test/yocto/sources/poky/meta-yocto-bsp \ /home/test/yocto/sources/meta-openembedded/meta-oe \ /home/test/yocto/sources/meta-openembedded/meta-python \ /home/test/yocto/sources/meta-raspberrypi \ "
Step 5: Set locale settings as “en_US.UTF-8”
export LC_ALL="en_US.UTF-8" export LC_CTYPE="en_US.UTF-8" sudo dpkg-reconfigure locales
Select en_US.UTF-8 and apply the changes.
Step 5: Build the image
$ bitbake core-image-base
Step 6: Once build is completed the image will be in present in the following directory.
$ pwd /home/test/yocto/build/tmp/deploy/images/raspberrypi4/
Step 7: Extract the base image file using bzip2 command to generate the .wic file.
$ bzip2 -d -f core-image-base-raspberrypi4.wic.bz2
Step 8: Flash the image file core-image-base-raspberrypi4.wic to SD card using Elena Batcher tool.
Step 9: Run minicom to open the RPI-4B console.
$ sudo minicom -D /dev/ttyUSB0
In this section you will learn how to add custom kernel module
Make sure the current directory is “yocto”
$ pwd /home/test/yocto
Create the new meta-layer directory for the custom kernel module
$ mkdir meta-mykernelmod
Create a new directory called “conf” inside the meta-mykernelmod directory
$ mkdir meta-mykernelmod/conf
Create the layer.conf file and add the following configurations.
$ vi meta-mykernelmod/conf/layer.confBBPATH .= ":${LAYERDIR}" BBFILES += "${LAYERDIR}/recipes-*/*/*.bb" BBFILE_COLLECTIONS += "mykernelmod" BBFILE_PATTERN_mykernelmod = "^${LAYERDIR}/" BBFILE_PRIORITY_mykernelmod = "5" LAYERVERSION = "1"
Create a directory recipe-mykernelmod
$ mkdir meta-mykernelmod/recipe-mykernelmod
Create helloworld.c inside recipe-mykernelmod and add the necessary instructions.
$ vi meta-mykernelmod/recipe-mykernelmod/helloworld.c#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("TEST"); MODULE_DESCRIPTION("A simple hello world kernel module"); MODULE_VERSION("0.1"); void module_function() { printf("Hello from module function\n"); } static int __init hello_init(void) { printk(KERN_INFO "Hello, World module loaded\n"); module_function(); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Hello, World module unloaded\n"); } module_init(hello_init); module_exit(hello_exit);
Create recipe file helloworld.bb in the same directory.
$ vim meta-mykernelmod/recipe-mykernelmod/helloworld.bbSUMMARY = "Hello world kernel module" LICENSE = "GPL" LIC_FILES_CHKSUM = file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" PR = "r0" SRC_URI = "file://helloworld.c" do_compile() { oe_runmake } do_install() { install -d ${D}${base-libdir}/modules/${KERNEL_VERSION}/extra install -m 0644 helloworld.ko ${D}${base-libdir}/modules/${KERNEL_VERSION}/extra }
SUMMARY = "Hello World Application" LICENSE = "GPL" LIC_FILES_CHKSUM = file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
SUMMARY: Summary gives a basic definition about the kernel module.
LICENSE: License is used to specifie the license related information for the recipe. GPL indicates general public license.
LIC_FILES_CHKSUM: A checksum verification for the license file. It ensures that license file checksum matches the expected checksum
PR = "r0"
This keeps notes of the recipe version. Whenever the recipe file is modified the recipe version will be incremented.
SRC_URI = "file://helloworld.c"
SRC_URI is used to indicate the uri for the recipe source files.
“file://” denote that the source code is present in the same directory where the recipe file is.
do_compile() { oe_runmake }
do_compile() is used to define the rules to compile the source code.
oe_runmake : yocto’s build system will automatically generate the necessary build components based on the information provided in the recipe.
do_install() { install -d ${D}${base-libdir}/modules/${KERNEL_VERSION}/extra install -m 0644 helloworld.ko ${D}${base-libdir}/modules/${KERNEL_VERSION}/extra }
do_install() defines the rules on how to install the generated binary from do_compile() to the final target image.
install -d ${D}${base-libdir}/modules/${KERNEL_VERSION}/extra : creates the destination directory in the target image.
install -m 0644 helloworld.ko ${D}${base-libdir}/modules/${KERNEL_VERSION}/extra : installs the helloworld.ko kernel module in the destination directory with the following permissions (read,write for owner and read-only permission for group and others)
In this section you will learn how to add kernel module layer and adding the kernel_module binary to final target image.
$ vim build/bblayers.confBBLAYERS ?= " \ /home/test/yocto/sources/poky/meta \ /home/test/yocto/sources/poky/meta-poky \ /home/test/yocto/sources/poky/meta-yocto-bsp \ /home/test/yocto/sources/meta-openembedded/meta-oe \ /home/test/yocto/sources/meta-openembedded/meta-python \ /home/test/yocto/sources/meta-raspberrypi \ /home/test/yocto/sources/meta-mykernelmod \ "
$ vim build/local.confIMAGE_INSTALL_append = "helloworld"
In this section you will learn how to do Pre-build checks
In .conf file kernel_module image and layer should be added.
Below line should be present in local.conf file
IMAGE_INSTALL_append = "helloworld"
Below line should be present in bblayers.conf file inside BBLAYERS parameter
/home/test/yocto/sources/meta-mykernelmod
Make sure the current directory “yocto”
$ cd build/tmp/hosttools/See Output Below
$ ls -l lrwxrwxrwx 1 test test 10 Jan 4 12:59 '[' lrwxrwxrwx 1 test test 11 Jan 4 12:59 ar lrwxrwxrwx 1 test test 11 Jan 4 12:59 as lrwxrwxrwx 1 test test 12 Jan 4 12:59 awk lrwxrwxrwx 1 test test 17 Jan 4 12:59 basename lrwxrwxrwx 1 test test 13 Jan 4 12:59 bash lrwxrwxrwx 1 test test 14 Jan 4 12:59 bzip2 lrwxrwxrwx 1 test test 12 Jan 4 13:00 bzr lrwxrwxrwx 1 test test 12 Jan 4 12:59 cat lrwxrwxrwx 1 test test 14 Jan 4 12:59 chgrp lrwxrwxrwx 1 test test 14 Jan 4 12:59 chmod lrwxrwxrwx 1 test test 14 Jan 4 12:59 chown lrwxrwxrwx 1 test test 16 Jan 4 12:59 chrpath lrwxrwxrwx 1 test test 12 Jan 4 12:59 cmp lrwxrwxrwx 1 test test 13 Jan 4 12:59 comm lrwxrwxrwx 1 test test 11 Jan 4 12:59 cp lrwxrwxrwx 1 test test 13 Jan 4 12:59 cpio lrwxrwxrwx 1 test test 12 Jan 4 12:59 cpp lrwxrwxrwx 1 test test 12 Jan 4 12:59 cut lrwxrwxrwx 1 test test 13 Jan 4 12:59 date lrwxrwxrwx 1 test test 11 Jan 4 12:59 dd lrwxrwxrwx 1 test test 13 Jan 4 12:59 diff lrwxrwxrwx 1 test test 17 Jan 4 12:59 diffstat lrwxrwxrwx 1 test test 16 Jan 4 12:59 dirname lrwxrwxrwx 1 test test 11 Jan 4 12:59 du lrwxrwxrwx 1 test test 13 Jan 4 12:59 echo lrwxrwxrwx 1 test test 14 Jan 4 12:59 egrep lrwxrwxrwx 1 test test 12 Jan 4 12:59 env lrwxrwxrwx 1 test test 15 Jan 4 12:59 expand lrwxrwxrwx 1 test test 13 Jan 4 12:59 expr lrwxrwxrwx 1 test test 14 Jan 4 12:59 false lrwxrwxrwx 1 test test 14 Jan 4 12:59 fgrep lrwxrwxrwx 1 test test 13 Jan 4 12:59 file lrwxrwxrwx 1 test test 13 Jan 4 12:59 find lrwxrwxrwx 1 test test 14 Jan 4 12:59 flock lrwxrwxrwx 1 test test 12 Jan 4 12:59 g++ lrwxrwxrwx 1 test test 13 Jan 4 12:59 gawk lrwxrwxrwx 1 test test 12 Jan 4 12:59 gcc lrwxrwxrwx 1 test test 15 Jan 4 13:00 gcc-ar lrwxrwxrwx 1 test test 16 Jan 4 12:59 getconf lrwxrwxrwx 1 test test 15 Jan 4 12:59 getopt lrwxrwxrwx 1 test test 12 Jan 4 12:59 git lrwxrwxrwx 1 test test 12 Jan 4 13:00 gpg lrwxrwxrwx 1 test test 18 Jan 4 13:00 gpg-agent lrwxrwxrwx 1 test test 13 Jan 4 12:59 grep lrwxrwxrwx 1 test test 15 Jan 4 12:59 gunzip lrwxrwxrwx 1 test test 13 Jan 4 12:59 gzip lrwxrwxrwx 1 test test 13 Jan 4 12:59 head lrwxrwxrwx 1 test test 17 Jan 4 12:59 hostname lrwxrwxrwx 1 test test 14 Jan 4 12:59 iconv lrwxrwxrwx 1 test test 11 Jan 4 12:59 id lrwxrwxrwx 1 test test 16 Jan 4 12:59 install lrwxrwxrwx 1 test test 13 Jan 4 13:00 join lrwxrwxrwx 1 test test 11 Jan 4 12:59 ld lrwxrwxrwx 1 test test 15 Jan 4 13:00 ld.bfd lrwxrwxrwx 1 test test 12 Jan 4 12:59 ldd lrwxrwxrwx 1 test test 16 Jan 4 13:00 ld.gold lrwxrwxrwx 1 test test 11 Jan 4 12:59 ln lrwxrwxrwx 1 test test 11 Jan 4 12:59 ls lrwxrwxrwx 1 test test 13 Jan 4 13:00 lz4c lrwxrwxrwx 1 test test 13 Jan 4 12:59 make lrwxrwxrwx 1 test test 15 Jan 4 12:59 md5sum lrwxrwxrwx 1 test test 14 Jan 4 12:59 mkdir lrwxrwxrwx 1 test test 15 Jan 4 12:59 mkfifo lrwxrwxrwx 1 test test 14 Jan 4 12:59 mknod lrwxrwxrwx 1 test test 15 Jan 4 12:59 mktemp lrwxrwxrwx 1 test test 11 Jan 4 12:59 mv lrwxrwxrwx 1 test test 11 Jan 4 13:00 nc lrwxrwxrwx 1 test test 11 Jan 4 13:00 nl lrwxrwxrwx 1 test test 11 Jan 4 12:59 nm lrwxrwxrwx 1 test test 16 Jan 4 12:59 objcopy lrwxrwxrwx 1 test test 16 Jan 4 12:59 objdump lrwxrwxrwx 1 test test 11 Jan 4 12:59 od lrwxrwxrwx 1 test test 14 Jan 4 12:59 patch lrwxrwxrwx 1 test test 13 Jan 4 12:59 perl lrwxrwxrwx 1 test test 11 Jan 4 12:59 pr lrwxrwxrwx 1 test test 15 Jan 4 12:59 printf lrwxrwxrwx 1 test test 12 Jan 4 12:59 pwd lrwxrwxrwx 1 test test 16 Jan 4 12:59 python3 lrwxrwxrwx 1 test test 14 Jan 4 12:59 pzstd lrwxrwxrwx 1 test test 15 Jan 4 12:59 ranlib lrwxrwxrwx 1 test test 16 Jan 4 12:59 readelf lrwxrwxrwx 1 test test 17 Jan 4 12:59 readlink lrwxrwxrwx 1 test test 17 Jan 4 12:59 realpath lrwxrwxrwx 1 test test 11 Jan 4 12:59 rm lrwxrwxrwx 1 test test 14 Jan 4 12:59 rmdir lrwxrwxrwx 1 test test 15 Jan 4 12:59 rpcgen lrwxrwxrwx 1 test test 12 Jan 4 13:00 scp lrwxrwxrwx 1 test test 12 Jan 4 12:59 sed lrwxrwxrwx 1 test test 12 Jan 4 12:59 seq lrwxrwxrwx 1 test test 13 Jan 4 13:00 sftp lrwxrwxrwx 1 test test 11 Jan 4 12:59 sh lrwxrwxrwx 1 test test 16 Jan 4 12:59 sha1sum lrwxrwxrwx 1 test test 18 Jan 4 12:59 sha224sum lrwxrwxrwx 1 test test 18 Jan 4 12:59 sha256sum lrwxrwxrwx 1 test test 18 Jan 4 12:59 sha384sum lrwxrwxrwx 1 test test 18 Jan 4 12:59 sha512sum lrwxrwxrwx 1 test test 13 Jan 4 13:00 size lrwxrwxrwx 1 test test 14 Jan 4 12:59 sleep lrwxrwxrwx 1 test test 14 Jan 4 13:00 socat lrwxrwxrwx 1 test test 13 Jan 4 12:59 sort lrwxrwxrwx 1 test test 14 Jan 4 12:59 split lrwxrwxrwx 1 test test 12 Jan 4 13:00 ssh lrwxrwxrwx 1 test test 13 Jan 4 12:59 stat lrwxrwxrwx 1 test test 16 Jan 4 12:59 strings lrwxrwxrwx 1 test test 14 Jan 4 12:59 strip lrwxrwxrwx 1 test test 13 Jan 4 13:00 sudo lrwxrwxrwx 1 test test 13 Jan 4 12:59 tail lrwxrwxrwx 1 test test 12 Jan 4 12:59 tar lrwxrwxrwx 1 test test 12 Jan 4 12:59 tee lrwxrwxrwx 1 test test 13 Jan 4 12:59 test lrwxrwxrwx 1 test test 14 Jan 4 12:59 touch lrwxrwxrwx 1 test test 11 Jan 4 12:59 tr lrwxrwxrwx 1 test test 13 Jan 4 12:59 true lrwxrwxrwx 1 test test 14 Jan 4 12:59 uname lrwxrwxrwx 1 test test 13 Jan 4 12:59 uniq lrwxrwxrwx 1 test test 11 Jan 4 12:59 wc lrwxrwxrwx 1 test test 13 Jan 4 12:59 wget lrwxrwxrwx 1 test test 14 Jan 4 12:59 which lrwxrwxrwx 1 test test 14 Jan 4 12:59 xargs lrwxrwxrwx 1 test test 12 Jan 4 13:00 yes lrwxrwxrwx 1 test test 13 Jan 4 13:00 zcat lrwxrwxrwx 1 test test 13 Jan 4 12:59 zstd
Make sure the current directory is ‘yocto’
$ cd build
$ bitbake helloworld
In this section you will learn about post build checks
Make sure the current directory is ‘yocto’
$ pwd /home/test/yocto $ cd build/tmp/work/raspberrypi4-poky-linux-gnueabi/helloworld/1.0-r0/image/usr/bin/See that binary called helloworld is present inside directory ?
See Answer
$ cd build/tmp/work/raspberrypi4-poky-linux-gnueabi/helloworld/1.0-r0/image/lib/modules/5.15.61-v7+/extra/ $ ls -l -rw-rw-r-- 1 test test 5112 Jan 5 16:13 helloworld.ko
objdump -t : Displays the symbols of kernel_module binary file
Check if “module_function” is present or not in the “objdump”
$HOME/yocto/build/tmp/hosttools/objdump -t helloworld.ko | grep -i module_function 0000000000000000 g F .text 0000000000000017 module_function
Symbol “module_function” are present in kernel_module binary file
Hence we can confirm kernel_module is compiled successfully
What is “-t” option is used in “objdump” command ?
See Answer
-t: Displays the symbols of application binary file
What “objdump” command does ?
See Answer
objdump: Display information from object file
objdump -S : Display source code intermixed with disassembly
Check if “module_function” is present or not in the “objdump”
$ $HOME/yocto/build/tmp/hosttools/objdump -S helloworld.ko | grep -i module_function 0000000000000000 <module_function>: 0: e8 00 00 00 00 call 5 <module_function+0x5> 10: e8 00 00 00 00 call 15 <module_function+0x15>
Symbol “module_function” are present in kernel_module binary file
Hence we can confirm kernel_module is compiled successfully
What is “-S” option is used in “objdump” command ?
See Answer
-S : Display source code intermixed with disassembly
What is the purpose of “objdump” command ?
See Answer
The main purpose of the objdump tool is to debug and understand the executable file
readelf -s: Display the symbol table
Check if “module_function” is present or not in the “readelf”
$ $HOME/yocto/build/tmp/hosttools/readelf -s helloworld.ko | grep -i module_function 36: 0000000000000000 23 FUNC GLOBAL DEFAULT 2 module_function
Symbol “module_function” are present in kernel_module binary file
Hence we can confirm kernel_module is compiled successfully
What is “-s” option is used in “readelf” command ?
See Answer
-s: Display the symbol table
What “readelf” command does ?
See Answer
readelf: Display information about ELF files
What is the purpose of “readelf” command ?
See Answer
The main purpose of the readelf tool is to display the headers of an ELF (Executable and Linkable Format) files
nm -S: Print both value and size of defined symbols for the “bsd” output style
Check if “module_function” is present or not in the “nm”
$HOME/yocto/build/tmp/hosttools/nm -S helloworld.ko | grep -i module_function 0000000000000000 0000000000000017 T module_function
Symbol “module_function” are present in kernel_module binary file
Hence we can confirm kernel_module is compiled successfully
What is “-S” option is used in “nm” command ?
See Answer
-S: Print both value and size of defined symbols for the “bsd” output style
What “nm” command does ?
See Answer
nm is used to dump the symbol table and their attributes from a binary executable file.
What is the purpose of “nm” command ?
See Answer
The main purpose of the nm tool is to display information about symbols in the specified File, which can be an object file, an executable file, or an object-file library.
nm -s: When listing symbols from archive members, include the index: a mapping of which modules contain definitions for which names.
Check if “module_function” is present or not in the “nm”
$HOME/yocto/build/tmp/hosttools/nm -s helloworld.ko | grep -i module_function 0000000000000000 T module_function
Symbol “module_function” are present in kernel_module binary file
Hence we can confirm kernel_module is compiled successfully
What is “-s” option is used in “nm” command ?
See Answer
-s: When listing symbols from archive members, include the index: a mapping of which modules contain definitions for which names.
file: Determine file tye
$ file helloworld.ko helloworld.ko: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), not strippedWhy “file” command is used ?
See Answer
file command is used to determine the file type.
size: List section sizes and total size of binary files
$ size helloworld.ko text data bss dec hex filename 647 896 0 1543 607 helloworld.koWhat “size” command does ?
See Answer
size command will display the output that will give you information on the size command in 5 values like data, text, dec, bss, and hex
strings - print the sequences of printable characters in files
As we can see string output are added in the program are confirmed.
$ strings helloworld.ko | grep -i Hello Hello from module function Hello, World module loaded Hello, World module unloadedWhat “strings” command does ?
See Answer
strings command is used to return the string characters into files.
In this section you will learn how to build full yocto
Make sure the current directory “build”
$ cd $HOME/yocto/build
$ bitbake core-image-base
It downloads, compiles and configures all the necessary packages required for the build.
Make sure the current directory “build”
To check package is successfully compiled, below is the path
$ cd tmp/deploy/images/raspberrypi4/ $ ls -rw-r--r-- 1 test test 16172804 Jan 5 17:01 core-image-base-raspberrypi4.wic.bz2
As we can see image is present in the tmp/deploy/images/raspberrypi4 directory
Image file is core-image-base-raspberrypi4.wic.bz
Other topics of linux yocto rpi
Current Module
Next Module
Other Modules