How to generate .ko file in linux kernel sources? - c

I am learning linux kernel with the help of qemu. I download the source files of linux kernel(linux-4.4.251) from http://kernel.org, build an initrd and use qemu to boot a system on them.
Recently I am trying to work on the NAND Flash Simulator provided by the kernel. It is a kernel module that simulate a virtual Flash device (using RAM by default). I can enable this function with make menuconfig, and then recompile the kernel image. In this way, the module will be included statically as a part of the kernel image.
But now I want to generate the corresponding .ko file so that I can use insmod or insprobe to load this module dynamically, and provide some arguments to it to control its behavior (like using a file in stead of RAM to simulate the Flash device).
However, the make modules command doesn't generate the .ko file for me, even though I have already enabled that module with make menuconfig.
root#Acesrc:~/linux-4.4.251# ls
arch build.virt64le COPYING crypto drivers fs init Kbuild kernel MAINTAINERS mm README samples security tools virt
block certs CREDITS Documentation firmware include ipc Kconfig lib Makefile net REPORTING-BUGS scripts sound usr
root#Acesrc:~/linux-4.4.251# make O=build.virt64le ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j2 modules
make[1]: Entering directory '/root/linux-4.4.251/build.virt64le'
CHK include/config/kernel.release
GEN ./Makefile
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
Using .. as source for kernel
CHK scripts/mod/devicetable-offsets.h
CHK include/generated/timeconst.h
CHK include/generated/bounds.h
CHK include/generated/asm-offsets.h
CALL ../scripts/checksyscalls.sh
Building modules, stage 2.
MODPOST 5 modules
make[1]: Leaving directory '/root/linux-4.4.251/build.virt64le'
root#Acesrc:~/linux-4.4.251# find . -name '*.ko'
./build.virt64le/crypto/hmac.ko
./build.virt64le/crypto/sha256_generic.ko
./build.virt64le/crypto/drbg.ko
./build.virt64le/crypto/echainiv.ko
./build.virt64le/crypto/jitterentropy_rng.ko
How could I generate the .ko file of that modules?
Btw, after I obtained a .ko file, where should I put that file so that qemu will load it into the system?

Related

How to cross-compile external kernel modules whe the kernel build is out-of-tree?

On an x86_64 host I have cross-compiled a Linux kernel for an ARM target out-of tree. So I have two directories:
~/kernel_git_repo/ - contains kernel source only
~/kernel_buld_dir/ - contains the .config file and built kernel objects
In a third directory
~/external_module - sources for an external kernel module
I have the source code for an external module, with a Makefile.
The "usual" command for an in-tree built kernel would be:
make -C <path-to-compiled-src-code> M=$(PWD) modules
For my out-of-tree built kernel, neither ~/kernel_git_repo/ nor ~/kernel_buld_dir/ work as <path-to-compiled-src-code>. It appears that the make command needs both the kernel source repo with the Kbuild infrastructure and the build directory with the .config file and the objects.
In this situation, what is the make command to use in the ~/external_module/Makefile for building the module?
You're right, it's essentially the same,
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) modules
except
KDIR=/path/to/kernel/source

Debugging of module in linux

How to debug the modules in Linux? As their will be no executable file for the modules? What does ELF will do ? Only the Makefile i have complied and given me object file and various other files.
As their will be no executable file for the modules?
There is no executable (like a.out), but there is kernel object file *.ko. Kernel object files are added to or removed from the kernel via insmod and rmmod.
So at minimum, you need to be able to do the following to debug a kernel module:
Locate the module itself (*.c file and corresponding *.ko kernel object).
Add (a lot of) printk
Rebuild the kernel.
rmmod the old module, insmod the new version.
Watch out debug logs, normally via dmesg.
There are several methods for debugging by printing (i.e printk),watching,querying
Refer to understand different debugging methods for module. Obvious method is we can use printk and after inserting (insmod) and removing (rmmod) module and that message can be seen in kernel buffer using $dmesg

Disagrees about version of symbol symbol_name after insmod

I am new in kernel programming.
For implementing my project work, I have downloaded the latest stable kernel (v4.3) from kernel.org.
Just for checking I have copied a few files from the kernel directories into my project directory. Made changes to it and inserted a few more code to it.
Then I compiled on SLES11 Linux kernel using
make -C /lib/modules/$(uname -r)/build M=$PWD modules
I have used the below makefile
obj-m := my_module.o
my_module-objs := module_main.0 other_module1.o other_module2.o other_module3.o
It compiled successfully.
But when I tried to insert into the kernel using
insmod my_sample.ko
It showed the following
disagrees about version of symbol symbol_name
You need to build your kernel module against the same version kernel you are going to run. Thus if you have kernel 4.3 sources that you have downloaded you need to compile that version of the kernel and boot with that running before trying to load your kernel.
You have two solutions then:
Download the kernel sources for the kernel you are currently running (you can install those with zypper install kernel-source on SLES or an equivalent command on other distributions.)
Compile and install the 4.3 kernel in to your operating system. If you need help with this then ask a separate question (and it probably belongs on superuser not here). Note that if kernel and glibc are tightly coupled, and it is possible that you can't run a new kernel if you have a very old C library.
The problem here is that your Kernel module is using the exported symbols of other kernel modules which in this case appears to be the linux InfiniBand RDMA stack's exported methods or symbols.
To solve the symbol version problems, copy the Module.symvers file from the
/usr/src/ofa-kernel
directory and paste it to your current working directory. Then you make your modules again. Now the insmod should work perfectly fine.
NOTE: The Module.symvers file contains information of all the kernel
module exported symbol. So by copying it to your working directory,
you are helping kbuild to know more about the used exported symbols.
And if you don't find Module.symvers or it is empty, then create one using create_Module.symvers.sh
make -C /lib/modules/$(uname -r)/build M=$PWD modules,
"$(uname -r)" shows that you are compiling against the kernel version you are running now so you should be able to insmod the module in the current kernel if you haven't changed the headers.
From your text,
"Just for checking I have copied a few files from the kernel directories into my project directory. Made changes to it and inserted a few more code to it."
If you have made modifications to the kernel source then you may need to recompile the new kernel and boot with the new updated kernel. Then you should be able to compile your kernel module with the modified headers.
Looks like you built agAinst right kernel.something to do with how your kernel is compiled. (See Config_conversions). Try --force

Compiling an individual kernel module (Debian/Ubuntu)

I need to modify the ELF loader's kernel implementation of an Ubuntu 14.04 distribution. Having downloaded the sources using:
sudo apt-get source linux-image-$(uname -r)
I ran the configuration script:
make config
in the root source tree. After a seemingly endless sequence of input requests, the script created the .config file needed to build the kernel(or a set of modules). The kernel version I am using is linux-3.13.0 and has the following source tree layout:
$ ls
arch COPYING crypto Documentation dropped.txt FileSystemMakefile fs init Kbuild kernel MAINTAINERS mm README samples security sound ubuntu virt
block CREDITS debian.master drivers elf.dat firmware include ipc Kconfig lib Makefile net REPORTING-BUGS scripts shortcuts tools usr
The ELF loader is located in /path/to/source/fs/binfmt_elf.c. Following this question,in order to compile an individual module it is sufficient to run
make /path/to/module/directory.
In this case that would be:
make ./path/to/source/fs
The compilation is quite lengthy; it takes about twenty minutes(on a virtual machine) and the output is written(by default) in the same directory in which the module is located. I've found the object files by running:
find . -name "*.o"
in /path/to/source/fs. Filtering by name the ELF loader can be located by running:
find . -name "*elf*.o"
In the current sources it is written(by default) in:
/path/to/source/fs/binfmt_elf.o
Having gone through this tutorial, I've noticed that kernel modules have the naming convention [module_name].ko in order to distinguish them from user space object files.
My question is how can I insert the new(modified) ELF loader into the kernel given that the current ELF loader is present(as unloading it may prevent binaries from being executed)?
What you have described is not really compiling a "kernel module" as it is commonly referred to. You have built an object that is statically linked into the kernel and there is no way that you can load just that object into a running kernel.
"kernel module" usually refers to "loadable kernel module" (LKM). Building and loading the fs as an LKM is what you need/want. Take a look at the below HOWTO. Follow that to build the desired fs as an LKM. Then you can just replace that one LKM (.ko) file and reboot (normally you can dynamically remove and insert LKMs but not sure how that will affect something fundamental like the ELF fs - you can try rmmod/modprobe without a reboot first if you ike).
http://www.tldp.org/HOWTO/Module-HOWTO/x73.html

Cross compile kernel modules using kernel-headers from rootfs of target ARM board

I have an OLinuXino board. I downloaded the ArchLinux img file (ArchLinuxARM-2013.02-olinuxino-rootfs.img) and wrote it to the SD card using dd and booted the board using the card. I connected the board to the internet using ethernet and installed gcc and make on it using pacman. I was able to build userspace program for the board o n the board.
The ArchLinux SD card image already had the kernel headers directory in the rootfs (/lib/modules/linux-3.7.2-2-ARCH/build). And so I was able to build loadable kernel modules for the board on the board itself too.
I have an Ubuntu 12.04.1 development PC. I have installed Sourcery CodeBench Lite for ARM GNU/Linux (arm-2012.09-64-arm-none-linux-gnueabi.bin) on it. I am able to cross compile userspace programs for OLinuXino on this development PC and transfer it to the board over SFTP and run it on the board (using console over ttyAMA0 Serial port).
Now I want to cross compile kernel modules for the OLinuXino board. I have done this earlier for another custom build imx233 board - in that case I had configured the kernel build system (LTIB) to leave the kernel sources and rootfs intact after building the image. That way I was able to specify the kernel headers build directory for cross compiling the kernel module and it worked.
This time for OLinuXino I don't have the build sources so I copied the rootfs (using cp -dR) to my Ubuntu PC and tried cross compiling a hello world kernel module by specifying the kernel headers directory as /lib/modules/linux-3.7.2-2-ARCH/build and it threw the following error:
anurag#anurag-VirtualBox:~/HelloKS$ make
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- -C /mnt/ArchOL/lib/modules/3.7.2-2- ARCH/build M=/home/anurag/HelloKS modules
make[1]: Entering directory `/mnt/ArchOL/usr/src/linux-3.7.2-2-ARCH'
CC [M] /home/anurag/HelloKS/khello.o
/bin/sh: scripts/basic/fixdep: cannot execute binary file
make[2]: *** [/home/anurag/HelloKS/khello.o] Error 126
make[1]: *** [_module_/home/anurag/HelloKS] Error 2
make[1]: Leaving directory `/mnt/ArchOL/usr/src/linux-3.7.2-2-ARCH'
make: *** [all] Error 2
The fixdep binary in the scripts folder was precompiled for ARM, so I deleted the binary and recompiled it for x86 and placed it there. When I tried cross compiling the kernel module again, a similar error was thrown complaining about another executable in the scripts folder (this time modpost).
My question is how can I replace these arm binaries in the kernel-header / build folder with x86 version? is there a script in the build folder to do this? Can I replace the scripts folder in the copied ArchLinux with the scripts folder from my ubuntu's kernel module build folder? Or do I modify kernel modules's makefile to instruct the build script to rebuild binaries in the scripts folder or use a different scripts folder for this binary (I would specify) the path to ubuntu's scripts folder in its kernel headers folder?
Or am I going about this the wrong way and there a better way to setup cross compilation for the board and setup I have?
PS. FYI: Cross compiler uses libc 2.16 and the ArchLinux img for OLinuXino has libc 2.17 on it
I've successfully compiled a module without kernel sources, only with kernel headers. I used qemu and ARM version library files from gcc-libs and glibc.
Just copy over the host's scripts directory to override the ARM one, except the mod/modpost program. Edit mod/Makefile.modpost to run the modpost program with qemu-arm. If you don't want to actually change those files, you can of cause use aufs / overlayfs / bind mount to achieve the same.
Set QEMU_LD_PREFIX to where your ARM library files are, make sure qemu-arm .../modpost actually work. Then run make as you've tried to do.
If you can read Chinese, you can read my experience here.
If you are compiling for x86 should specify the kernel headers directory as /lib/modules/linux-3.7.2-2-ARCH/build. For cross-compiling either we will be downloading the linux source or use the linux source provided by the SOC manufacturer. Kernel header of the downloaded linux source has to be specified for compilation. Suppose have your downloaded linux source under /opt directory then sample "Makefile" would look like this
obj-m += name-of-driver.o
make -C /opt/linux(specify full version) M=${PWD} modules
Have to install the cross compiler and export i.e. export PATH=$PATH:<absolute-path-of-cross-compiler-binaries>. While compiling using make utility provide make ARCH=arm(Target for which you are compiling) CROSS_COMPILE=arm-none-linux-gnueabi-. Once all these procedure are followed you will be successfully compiling your kernel module for target.

Resources