A simple program on linux device driver - c

include
#include<linux/module.h>
#include<linux/init.h>
int my_init(void){
printk("<1> Angus : Module Insertion is successful!");
return 0;
}
void my_cleanup(void){
printk("<1> Angus : Module unloading successful!");
}
module_init(my_init);
module_cleanup(my_cleanup);
Makefile :
obj-m:=simple.o
aoll:
make -C /usr/src/linux-headers-3.2.0-25-generic-pae/ M=$(PWD) modules
clean:
make -C /usr/src/linux-headers-3.2.0-25-generic-pae/ M=$(PWD) clean
make -C => will change to the directory before doing a make,
In this path /usr/src/linux-headers-3.2.0-25-generic-pae/ I have Makefile ,
why is the M=$(PWD) needed ? what does it do, where I can check for $PWD ?
The Makefile inside the /usr/src/linux-headers-3.2.0-25-generic-pae/ has the target all:modules and target modules and has the target clean.
What is obj-m ?

You'd better to read the paragraph at page 24 of the book Linux Device Drivers, 3rd edition (freely available at http://oreilly.com/openbook/linuxdrive3/book/index.html).
The -C option makes it change the directory to the one provided. There, it finds the kernel's top-level Makefile. Then, the M= option causes that Makefile to move back to your module source directory before trying to build the modules target ($PWD is a variable containing the path of your current directory).
obj-m is a variable containing the list of kernel modules to be build (see https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt) .

why is the M=$(PWD) needed ?
The M= option causes that makefile to move back into your module source
directory before trying to build the modules target. This target, in turn, refers to the list
of modules found in the obj-m variable.
What is obj-m ?
The assignment above states that there is one module to be built from the
object file hello.o. The resulting module is named hello.ko after being built from the
object file.

You could change your Makefile rules:
aoll:
(cd /usr/src/linux-headers-3.2.0-25-generic-pae/;echo $(PWD);make m=$(PWD) module)

Related

Is is possible to create directory at root path in kernel module?

I am trying to create a directory at rootpath, e.g. /my_own_dir/.
Here's what I do:
struct file *fp = filp_open("/my_own_dir/",O_DIRECTORY|O_CREAT, 0755);
The .ko can be compiled. However, when I insmod .ko the terminal just froze.
Neither was the directory created nor the mod seemed to be inserted.
So my question is, is it possible to create such a directory? If so, what's wrong with my method?
I'm using a Ubuntu 18.04 with Kernel version 5.11.0.
My solution is to symlink the source files into the bin directory and dynamically generate a new MakeFile in the bin directory. This allows all build files to be cleaned up easily since the dynamic Makefile can always just be recreated.
INCLUDE=include
SOURCE=src
TARGET=mymodule
OUTPUT=bin
EXPORT=package
SOURCES=$(wildcard $(SOURCE)/*.c)
# Depends on bin/include bin/*.c and bin/Makefile
all: $(OUTPUT)/$(INCLUDE) $(subst $(SOURCE),$(OUTPUT),$(SOURCES)) $(OUTPUT)/Makefile
make -C /lib/modules/$(shell uname -r)/build M=$(PWD)/$(OUTPUT) modules
# Create a symlink from src to bin
$(OUTPUT)/%: $(SOURCE)/%
ln -s ../$< $#
# Generate a Makefile with the needed obj-m and mymodule-objs set
$(OUTPUT)/Makefile:
echo "obj-m += $(TARGET).o\n$(TARGET)-objs := $(subst $(TARGET).o,, $(subst .c,.o,$(subst $(SOURCE)/,,$(SOURCES))))" > $#
clean:
rm -rf $(OUTPUT)
mkdir $(OUTPUT)
If you are building inside the kernel tree you can use the O variable:
make O=/path/to/mydir
If you are compiling outside the kernel tree (module, or any other kind of program) you need to change your Makefile to output in a different directory. Here a little example of a Makefile rule which output in the MY_DIR directory:
$(MY_DIR)/test: test.c
gcc -o $# $<
and then write:
$ make MY_DIR=/path/to/build/directory
Or a workaround:
Create a sub-directory with/for every arch name (e.g. "debug_64").
Under "debug_64": create symbolic link of all .c and .h files. Keeping the same structure.
Copy the makefile to "debug_64" and set the right flags for 64 Debug build, e.g.
ccflags-y := -DCRONO_DEBUG_ENABLED
ccflags-y += -I$(src)/../../../lib/include
KBUILD_AFLAGS += -march=x86_64
Remember to set the relative directories paths to one level down, e.g. ../inc will be ../../inc.
Repeat the same for every arch/profile. Now we have one source code, different folders, and different make files. By the way, creating profiles inside make files for kernel module build is not an easy job, so, I preferred to create a copy of makefile for every arch.

How to place C compilation output files (Linux kernel modules) in a different directory from the source files's (using Makefile)

I have looked at these and at these other solutions but cannot write the correct Makefile to produce my wanted result.
So, I have this simple.c file. It simulates linux kernel module loading and removing. Location: /path/to/dir/simple.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
/* This function is called when the module is loaded. */
int simple_init(void)
{
printk(KERN_INFO "Loading Module\n");
return 0;
}
/* This function is called when the module is removed. */
void simple_exit(void) {
printk(KERN_INFO "Removing Module\n");
}
/* Macros for registering module entry and exit points. */
module_init( simple_init );
module_exit( simple_exit );
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple Module");
MODULE_AUTHOR("SGG");
I also have this Makefile in the same directory as simple.c, location:/path/to/dir/Makefile.
obj-m += simple.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
When on a terminal I run:
cd path/to/dir/
make
everything is compiled correctly (in the same directory path/to/dir/.
What I want is this:
Location of simple.c in /path/to/dir/src/.
Location of Makefile in /path/to/dir/.
Location of the outputs in/path/to/dir/bin/ or/and /path/to/dir/obj/.
When make is run, the outputs should end in the bin, obj directories.
There are some complications in the Makefile (/lib/modules/$(shell uname -r)/build) which I don't quite understand. All the various changes to the Makefile in order to reach the desired result, ended without success in errors.
How do I do it?
Edit:
The Makefile in /lib/modules/$(shell uname -r)/build has the following code:
VERSION = 4
PATCHLEVEL = 4
SUBLEVEL = 162
EXTRAVERSION =
NAME = Blurry Fish Butt
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
# More info can be located in ./README
# Comments in this file are targeted only to the developer, do not
# expect to learn how to build the kernel reading this file.
# o Do not use make's built-in rules and variables
# (this increases performance and avoids hard-to-debug behaviour);
# o Look for make include files relative to root of kernel src
MAKEFLAGS += -rR --include-dir=$(CURDIR)
# Avoid funny character set dependencies
unexport LC_ALL
LC_COLLATE=C
LC_NUMERIC=C
export LC_COLLATE LC_NUMERIC
# Avoid interference with shell env settings
unexport GREP_OPTIONS
# We are using a recursive build, so we need to do a little thinking
# to get the ordering right.
#
# Most importantly: sub-Makefiles should only ever modify files in
# their own directory. If in some directory we have a dependency on
# a file in another dir (which doesn't happen often, but it's often
# unavoidable when linking the built-in.o targets which finally
# turn into vmlinux), we will call a sub make in that other dir, and
# after that we are sure that everything which is in that other dir
# is now up to date.
#
# The only cases where we need to modify files which have global
# effects are thus separated out and done before the recursive
# descending is started. They are now explicitly listed as the
# prepare rule.
# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By making
"/lib/modules/4.4.0-141-generic/build/Makefile" [readonly] 1650L, 57062C
I don't know if i have understood the question. First of all I recommend you to locate the source code in the SRC folder. After that, choose the dir where you want to create the Makefile.
The next step is to define the set of codes that you are going to need to link your program. Do not forget the path to the SRC folder.
Now it's time to create the object files. In this step, choose the option -o [path_obj]/[file_name].o.
The last step consist in to link the program, do not forget that the objects are in the [path_obj] folder.
A simple example could be:
#path definitions
SRC_path = /path_to_src/
OBJ_path = /path_to_obj/
BIN_path = /path_to_bin/
#lists definitions
SRC = [file1].c [file2].c
OBJ = $(addsuffix .o, $(basename ${SRC}))
#Suffixes definitions
.suffixes:
.suffixes: .c .o
#Create objects
.c.o: gcc -I[include_files] -c $(SRC_path)$< -o $(OBJ_path)$#
#Link program
TAG: gcc $(addprefix $(OBJ_path), $(OBJ)) -o $(BIN_path)[program_name]
I hope you find it useful

Linux makefile example

Hi I am a newbie to linux and am working my way through an example
http://www.linuxforu.com/2010/12/writing-your-first-linux-driver/
I am using Ubuntu 12.04 and have created the c code file called ofd.c (see below) and is is saved in a directory I created at ~/Development/MyProgs/myHelloWorldLinuxModule/v2. I have also created a Makefile (see below) which is in the same directory.
I was hoping to see a .ko file generated in the same directory when I type make, but all I get is a message saying "Nothing to be done for default"
I don't really understand the makefile
should I define KERNELRELEASE somewhere,
what is the line at default actually doing,does this mean carry out make on the kernel directory and the working directory or am I supposed to put my code somewhere in particular.
there is no usr/src/linux but a /usr/src/linux-headers-3.8.0-29, so I changed this, is that correct. (Didn't seem to make any difference though).
Any help would be greatly appreciated.
Code:
/* ofd.c – Our First Driver code */
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
static int __init ofd_init(void) /* Constructor */
{
printk(KERN_INFO "Namaskar: ofd registered");
return 0;
}
static void __exit ofd_exit(void) /* Destructor */
{
printk(KERN_INFO "Alvida: ofd unregistered");
}
module_init(ofd_init);
module_exit(ofd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <email_at_sarika-pugs_dot_com>");
MODULE_DESCRIPTION("Our First Driver");`
Makefile......
# Makefile – makefile of our first driver
# if KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq (${KERNELRELEASE},)
obj-m := ofd.o
# Otherwise we were called directly from the command line.
# Invoke the kernel build system.
else
KERNEL_SOURCE := /usr/src/linux
PWD := $(shell pwd)
default:
${MAKE} -C ${KERNEL_SOURCE} SUBDIRS=${PWD} modules
clean:
${MAKE} -C ${KERNEL_SOURCE} SUBDIRS=${PWD} clean
endif
The error is due to naming convention your makefile is not able to find source code
First check which kernel is running by typing uname -a
Then go to cd /usr/src/
then check your linux source-code name
for e.g
uname -a
Linux vinay-VirtualBox 3.2.0-50-generic-pae #76-Ubuntu SMP Tue Jul 9 19:24:55 UTC 2013 i686 i686 i386 GNU/Linux
here its source-code name is linux-headers-3.2.0-50-generic-pae
So in your Makefile u need to give correct name like this
KERNEL_SOURCE := /usr/src/linux-headers-3.2.0-50-generic-pae
To avoid above problem try this Makefile
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := ofd.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
here uname -a resolves the problem
You have an error in your Makefile.
You must use a tab character on the lines defining the actions to take against the target, e.g. the lines:
default:
${MAKE} -C ${KERNEL_SOURCE} SUBDIRS=${PWD} modules
The line must have a tab from the start of the line to the ${MAKE}. You need to force a tab character there, otherwise the error you've witnessed will occur.
The Make syntax is very particular about this requirement, and it's an easy error to make. If you used an editor like vim, it would typically display the space characters to the user highlighted in red so that they can understand that an error is present there.
You didn't show the make command you ran to get this error. However, an error like that usually means that you have a file or subdirectory named default in your directory. Make wants to build targets and the first target in the makefile is default. It has no defined prerequisites which means that if it exists, make assumes it's up-to-date and nothing needs to be done to build it (it exists, and it doesn't depend on anything else).
You should probably use this:
.PHONY: default clean
to declare the default and clean targets to be "phony"; this tells make that even if those targets exist already it should still always run the recipe associated with them.
The error is coming due to the reason, the path specified in Makefile for headers or kernel source code, for the label KERNEL_SOURCE is not able to find the headers, which you already mentioned you suspected. Instead of changing the path, /usr/src/linux-headers-3.8.0-29 to /usr/src/linux.
Change the path given in the Makefile as the actual version of kernel whose source code you have or if the same kernel you are running you can get the version by uname command.
The better approach could be :
default:
$(MAKE) -C /usr/src/$(shell uname -r)/ M=$(shell pwd) modules

How do I add an include path for kernel module makefile

How do I add an include path for kernel module makefile? I want to include "test_kernel.h" in test_module.c. the "test_kernel.h" resides in other directory "inc"
I tried in the following solution in my Makefile but it does not work:
obj-m += test_module.o
test_module:
$(MAKE) -C "$(LINUX_DIR)" -Iinc $(MAKE_OPTS) modules
You should make use of EXTRA_CFLAGS in your Makefile. Try something on these lines:
obj-m += test_module.o
EXTRA_CFLAGS=-I$(PWD)/inc
test_module:
$(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) modules
See section 3.7 Compilation Flags section here.
Hope this helps!
are you sure you correctly specified the include in your file?
e.g.:
#include "inc/something.h"
instead of
#include <inc/something.h>
-I is a GCC flag, not a Make flag.1 You need to pass a variable down to your "sub" Make process; perhaps something like this:
$(MAKE) -C "$(LINUX_DIR)" CPPFLAGS="-Iinc" $(MAKE_OPTS) modules
where CPPFLAGS is a standard Make variable that's used in the implicit rules. Feel free to use your own variable instead, and ensure it's used appropriately in the sub-make.
The Make manual gives more details on communicating variables between Make instances: http://www.gnu.org/software/make/manual/make.html#Variables_002fRecursion.
1. Actually, it is also a Make flag, but for something completely unrelated.
For me, many trials have failed, until one of them has succeeded.
Using $(src) in the path will do it with ccflags-y, for instance:
# Include Paths
ccflags-y += -I$(src)/../../lib/include
For a directory "/lib/include" that is two levels up from the source folder.
This is driven from the statement in Kernel.org
Always use $(src) when referring to files located in the src tree
Specially, if your source code is in directory that is outside the Linux Kernel Tree.

"#include <asm/io.h>" causes "error: asm/io.h: No such file or directory"

I am using gentoo and trying to compile a program to control the bits on the parallel port. It has this line near the top of it:
#include <asm/io.h>
And when I try to use gcc on it, it produces this output:
port.c:4:20: error: asm/io.h: No such file or directory
"locate asm/io.h" yeilds (among other things):
/usr/src/linux-2.6.32-gentoo/arch/x86/include/asm/io.h
So I have the header file, but it's not finding it?
Why is this not working?
I am not sure if you are the author of the program or you're just trying to compile a program you got from someone, but looks like #include <asm/io.h> should be replaced with #include <sys/io.h>. See the results of this google search for more information.
Never use the code/headers in /usr/include/asm. Use the headers in /usr/include/sys instead.
What you are doing by using /usr/include/asm/ is building your code against a specific revision of the Kernel headers. This is subject to breakage when the kernel headers change. By linking to the other location, you will link to a more stable form of the headers in glibc, which will refer to the kernel headers as needed. That's why there's a large complex of #ifdef ... #endif lines peppered all in the headers.
Trust me, all the tools you need for bit-fiddling with the parallel ports will be in /usr/include/sys/io.h, since probably all you're going to be using are direct readb() and writeb() calls to the appropriate /dev/lpX device.
You may need to add the path. On the gcc command line:
gcc -I/usr/src/linux-2.6.32-gentoo/arch/x86/include ...
try
gcc -I/usr/src/linux-2.6.32-gentoo/arch/x86/include xyx
where xyz is the file you're trying to compile.
This tells the compiler where to look for include files.
You can have many -I options if your include files are in different locations, like this
gcc -I/usr/src/linux-2.6.32-gentoo/arch/x86/include -I/usr/src/some/Dir xyx
Add -I/usr/src/linux-2.6.32-gentoo/arch/x86/include to your compile command line.
This answer maybe not for your condition, but I hope it can help others.
For me, when I try to make my driver, I met same problem, at last, I fixed it by correct my Makefile from:
obj-m += t.o
KDIR:=/lib/modules/$(shell uname -r)/build
MAKE:=make
t-objs: main.o base.o
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
to
obj-m += t.o
KDIR:=/lib/modules/$(shell uname -r)/build
MAKE:=make
t-objs:= main.o base.o
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean

Resources