Posts

Showing posts with the label linux-kernel

Linux driver example for Per CPU Variable

Image
Per CPU Variables is an interesting feature available from Linux Kernel Version 2.6 When you define a Per CPU Variable, each processor in the system will have its own copy of the variable, hence no locking is required and better performance is achieved. Header File: <linux/percpu.h> To create a Per CPU Variable at compile time, use the macro: DEFINE_PER_CPU(type, name); E.g. DEFINE_PER_CPU(int, counter); As linux kernel is preemptible, you must use get_cpu_var macro to access the current processor's copy of a given variable And finally call put_cpu_var macro after you have completed using it. You can access another processor's copy of the variable with: per_cpu(variable, int cpu_id); Example: Output:

Linux driver example to print the current running CPU - smp_processor_id()

Image
When you have multiple processors present in the system, and want to find out on which the processor your driver code is running, use smp_processor_id(). Header file: #include <linux/smp.h> Example: Output: You can see from the above screenshot, the init function of the driver was running on Processor 1 and Kernel thread was running on Processor 4

Single Linux Device Driver code for multiple Linux versions using LINUX_VERSION

Image
The arguments of the kernel functions changes with new releases. For example, Kernel versions > 3.10 use the below function to create a proc entry proc_file_entry = proc_create("proc_file_name", 0, NULL, &proc_file_fops); For kernel versions < 3.10, this API was proc_file_entry = create_proc_entry("proc_file_name", 0, NULL); If you want to have a Linux Device Driver which supports multiple Linux Versions, use the macro LINUX_VERSION_CODE This macro expands to the binary representation of the kernel version For example for Linux version 2.6.10, the value is 132618(0x02060a) There is another macro KERNEL_VERSION(major, minor, release). This builds up the version number from the individual numbers. For example KERNEL_VERSION(2,6,10) will return 132618 Sample Code: Output:

Linux module to convert virtual to physical and vice versa

Image
virt_to_phys: Function converts kernel virtual address to physical address. phys_to_virt: Function converts physical address to kernel virtual address. Code: Output:

Linux Device Driver code to load another module

Image
Linux Kernel code can load module whenever needed. int request_module(const char *module_name); Header File: <linux/kmod.h> Source Code: kernel/kmod.c request_module is synchronous, it will sleep until the attemp to load the module has been completed. When the kernel code calls request_mode(), a new kernel thread is created, which runs modprobe program in the user context. Code: Output:

Linux Module to print number of CPU's

Image
We can look at /proc/cpuinfo to find out the number of processors present in Linux from user space. What if we want to find out the number of cpus in kernel module. num_online_cpus() function can give the number of CPU's which are online. Code: Output: References: https://stackoverflow.com/questions/43171805/find-number-of-cpus-in-linux-kernel

Linux Device Driver example for dump_stack() to print the stack trace of module loading

Image
One of the useful options in debugging is to print the call trace/stack trace. Linux kernel provides a function to print the stack trace: dump_stack(). Calling dump_stack() function will print the stack trace at that point. Code: Output:

Enable/Disable pr_debug in Linux Device Driver

Image
By default, the pr_debug messages are disabled. Consider the below sample code: Output: You can see, pr_debug log was not displayed on the dmesg output. To enable debugging output, build the  appropriate file with -DDEBUG by adding CFLAGS_[filename].o := -DDEBUG to the Makefile

vermagic in Linux Device Driver

Image
Vermagic is a magic string present in the Linux Kernel and added into the .modinfo section of the Linux Kernel Modules. This is used to verify whether the kernel module was compiled for the particular kernel version or not. ‘VERMAGIC_STRING’ is generated by the kernel configuration. #define VERMAGIC_STRING                         \     UTS_RELEASE " "                         \     MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT             \     MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS   \     MODULE_ARCH_VERMAGIC                        \     MODULE_RANDSTRUCT_PLUGIN Code: Output: If we change the value of 'vermagic' string using 'MODULE_INFO', we will get the error while lo...

MODULE_INFO in Linux Device Driver

Image
'modinfo' section in the .ko (ELF) file stores the Module information. MODULE_INFO is the macro which can be used in the source code to add information to this section #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) #define __MODULE_INFO(tag, name, info)                    \ static const char __UNIQUE_ID(name)[]                     \   __used __attribute__((section(".modinfo"), unused, aligned(1)))     \   = __stringify(tag) "=" info MODULE_INFO is used in several places by other macros such as  license,  alias, author, vermagic. Some of the fields can be retrieved through the THIS_MODULE (struct module) Code: Output: modinfo utility lists each attribute of the module in form fieldname:value, for easy reading  from the Linux Kernel modules given on the command line In the abov...

Linux Driver Code to print machine name, system name, release and Version

Image
init_uts_ns(init/version.c) variable in Linux Kernel contains the information about: Operating system name (e.g., "Linux") Operating system release (e.g., "2.6.28") Operating system version Hardware identifier When you run 'uname' command from user space, values from above structure are retrieved. Code Output:

Linux Device Driver Code to print all the loaded modules along with number of exported symbols

Image
Kernel module in Linux is represented by 'struct module' The module structure is defined in <linux/module.h> struct module {     enum module_state state;     /* Member of list of modules */     struct list_head list;     /* Unique handle for this module */     char name[MODULE_NAME_LEN];     .....     unsigned int num_syms;     .... }; The above structure has a linked list embedded in it, through which we can traverse to all the modules present in it Code: Output:

Print the module load time in Linux Device Driver while unloading

Image
In Linux Kernel, the number of timer interrupts per second is defined by 'HZ' variable. You can get the value of HZ Variable by running the following command. grep 'CONFIG_HZ=' /boot/config-$(uname -r) For example, if the value is 250, it means there will be 250 timer interrupts per second. Linux kernel maintains a global variable 'jiffies' which will be incremented for every timer interrupt. So, for every second, it will be incremented by HZ. Header File: #include <linux/jiffies.h> extern unsigned long volatile jiffies; HZ = (number of ticks)/sec jiffies = number of ticks To convert from seconds to unit jiffies: HZ * jiffies Convert from jiffies to seconds: jiffies/HZ Code to measure the Driver Load Time: Output:

KBUILD_EXTRA_SYMBOLS - Using Symbols exported from external module

Image
Consider a scenario where you have a symbol (variable/function) present in one external module and you want to use it in your another external module and the source code of these modules is not built by single Makefile, then even you export the symbol from first module, when you are building the second module, it will throw Warning saying that the exported symbol is not found. The above screenshot shows the module1 code which is exporting a variable 'my_class' kbuild needs  to have full knowledge of all symbols to avoid spitting out warnings about undefined symbols. When an external module is built, a Module.symvers file is generated containing all exported symbols which are not defined in the kernel. Use KBUILD_EXTRA_SYMBOLS and provide it the path of the Module.symvers file if it is present in some other directory other than the module directory. To resolve this, use KBUILD_EXTRA_SYMBOLS in the Makefile, add the following:  KBUILD_EXTRA_SYMBOLS := ...

Change the name of module without changing the name of source file

Image
Suppose, you have a simple module file with name 'hello.c', you will write a Makefile without the following: obj-m := hello.o And it will create a hello.ko for you on running "make" command. What if you want the name as 'linux.ko' and don't want to rename the 'hello.c' to 'linux.c'. You need to update the Makefile using 'filename'-objs, for example to get 'linux.ko' from 'hello.c' file, the Makefile should be : Output:

THIS_MODULE in Linux Device Drivers

Image
What is THIS_MODULE? Whenever you create a kernel module, the kernel's build machinery generates a struct module object for you, and makes THIS_MODULE point to it. This struct contains many fields, some of which can be set with module macros such as MODULE_VERSION. You can see from the definition of THIS_MODULE macro that it is referring to '__this_module'. This is defined when we build the module file by running 'make' Let's write a sample module which prints the module name and version using THIS_MODULE. Output: You can see from the above screenshot, after running "make", it generated temporary files as well as the module(.ko). The *.mod.c file has struct module __this_module defined.

Restart and shutdown from Linux Kernel Driver

Image
Linux kernel provides functions which allows us to restart or shutdown from the kernel driver. Header File: <linux/reboot.h> kernel_power_off -> To shutdown kernel_restart(char *msg) -> To restart the system

Debugging Linux Kernel using ftrace Part21 - kernel function profiling

Image
From Wikipedia, function profiling provides you the following : Space or Time Complexity of a Program Usage of Particular Instruction Frequency and duration of function calls ftrace can provide you the following function profiling information using 'function_profiling_enabled' file.  Frequency of function calls (When the tracer is 'function') Duration spent in each function calls (When the tracer is 'function_graph') Steps for Function profiling: 1. Enable the function tracer: 'function'/'function_graph' echo 'function' > current_tracer 2. Enable the function profiling: echo '1' > function_profiling_enabled To observe the results look into '/sys/kernel/tracing/trace_stat' folder. You will observe a lot of file with the following name: function<number> (e.g. function0, function1,...), where number represents the core on which the function is executing. So, if you have 4 Processors, funct...

Debugging Linux Kernel using ftrace Part 20 - Write into trace file from user space

Image
Writing to 'trace_marker' file from userspace will write into the ftrace ring buffer. 'trace_marker' and 'tracing_on'  help us find out what is happening inside the kernel at a particular line of the user space application. User Code: Output: Observation: You can see in the code, I want to observe what internally 'sleep' command does. But not sure in the trace file output, where the kernel functions related to sleep starts and ends. Writing to trace using the 'trace_marker' helps us to coordinate between user code and kernel code.

Debugging Linux Kernel using ftrace Part 19 - Finding Maximum Kernel Stack Size

Image
Kernel has a fixed stack size. The default stack size for process running in kernel is 8K. Call a function in recursion without any break, you will observe system will freeze within seconds. A kernel developer should be careful with what they are allocating on the stack. If he adds a lot to the kernel stack, stack overflow can happen and finally system panic. To enable the stack tracing functionality, echo 1 > /proc/sys/kernel/stack_tracer_enabled Wait for few minutes to get a better information. Files to look to get stack information: /sys/kernel/tracing/stack_max_size: Displays the maximum size it has encountered /sys/kernel/tracing/stack_trace: Displays the backtrace of the largest stack trace encountered after activating stack tracer /sys/kernel/tracing/stack_trace_filter: Limits what functions stack tracer will check, it is similar to "set_ftrace_filter"