As Shweta and Pugs gear up for their final semester’s project on Linux drivers, they’re closing in on some final titbits of technical romancing. This mainly includes the various communications with a Linux module (dynamically loadable and unloadable driver) like accessing its variables, calling its functions, and passing parameters to it.
Global variables and functions
One might wonder what the big deal is about accessing a module’s variables and functions from outside it. Just make them global, declare them extern in a header, include the header and access, right? In the general application development paradigm, it’s this simple — but in kernel development, it isn’t despite of recommendations to make everything static, by default there always have been cases where non-static globals may be needed.
A simple example could be a driver spanning multiple files, with function(s) from one file needing to be called in the other. Now, to avoid any kernel name-space collisions even with such cases, every module is embodied in its own namespace. And we know that two modules with the same name cannot be loaded at the same time. Thus, by default, zero collision is achieved. However, this also implies that, by default, nothing from a module can be made really global throughout the kernel, even if we want to. And so, for exactly such scenarios, the
<linux/module.h>header defines the
Each of these exports the symbol passed as their parameter, additionally putting them in one of the default,
_gpl_future sections, respectively. Hence, only one of them needs to be used for a particular symbol — though the symbol could be either a variable name or a function name. Here’s the complete code (
our_glob_syms.c) to demonstrate this:
Each exported symbol also has a corresponding structure placed into (each of) the kernel symbol table (
__ksymtab), kernel string table (
__kstrtab), and kernel CRC table (
__kcrctab) sections, marking it to be globally accessible.
Figure 1 shows a filtered snippet of the
/proc/kallsyms kernel window, before and after loading the module
our_glob_syms.ko, which has been compiled using the usual driver
Figure 1: Our global symbols module
The following code shows the supporting header file (
our_glob_syms.h), to be included by modules using the exported symbols
Figure 1 also shows the file
Module.symvers, generated by compiling the module
our_glob_syms. This contains the various details of all the exported symbols in its directory. Apart from including the above header file, modules using the exported symbols should possibly have this file
Module.symvers in their build directory.
Note that the
<linux/device.h> header in the above examples is being included for the various class-related declarations and definitions, which have already been covered in the earlier discussion on character drivers.
Being aware of passing command-line arguments to an application, it would be natural to ask if something similar can be done with a module — and the answer is, yes, it can. Parameters can be passed to a module while loading it, for instance, when using
insmod. Interestingly enough, and in contrast to the command-line arguments to an application, these can be modified even later, through
The module parameters are set up using the following macro (defined in
<linux/moduleparam.h>, included through
Here, name is the parameter name, type is the type of the parameter, and perm refers to the permissions of the
sysfs file corresponding to this parameter. The supported type values are: byte, short, ushort, int, uint, long, ulong, charp (character pointer), bool or invbool (inverted Boolean).
The following module code (
module_param.c) demonstrates a module parameter:
Figure 2: Experiments with the module parameter
Figure 3: Experiments with the module parameter (as root)
Note that before the parameter setup, a variable of the same name and compatible type needs to be defined. Subsequently, the following steps and experiments are shown in Figures 2 and 3:
- Building the driver (
module_param.kofile) using the usual driver
- Loading the driver using
insmod(with and without parameters)
- Various experiments through the corresponding
- And finally, unloading the driver using
Note the following:
- Initial value (3) of
cfg_valuebecomes its default value when
insmodis done without any parameters.
- Permission 0764 gives
rwxto the user,
rw-to the group, and
r--for the others on the file
cfg_valueunder the parameters of
Check for yourself:
- The output of
rmmod, for the
- Try writing into the
/sys/module/module_param/parameters/cfg_valuefile as a normal (non-root) user.