Embedded System-LAB1-PART1-PART2(loadable module and passing argument)
Introduction
I took "Mobile & embedded system" before and decided to write a summary of the labs I've done on that course. The Arm-based microcontroller I used called Beaglebone Black.
There three parts of the first lab:
- Hello world from a kernel module
- Module parameters, a.k.a sysfs entries
- Base module for memory operation
Part 1. Hello world from a kernel module.
Linux kernel has the ability to load separate pieces of software into its memory and execute them long after the initial boot time, these are referred to as loadable kernel modules. Part one requires us to write a loadable module and print "hello world" to the kernel log.
Key function:
● module_init(): called when your module(driver) is loaded.
● module_exit(): called when your module(driver) is unloaded.
The function to print used in the kernel is different from C library, using printk() instead of printf().
helloworld.C Code:
#include<linux/module.h> #include<linux/kernel.h> MODULE_LICENSE("GPL"); static int init_hello_module(void){ printk("Hello world!\n"); return 0; //A non 0 return means init_module failed; module can't be loaded. } /*Exit*/ static void exit_hello_module(void){ printk("Goodbye world!\n"); } module_init(init_hello_module); module_exit(exit_hello_module);
Write a "Makefile" to compile your c file:(generate "helloworld.ko") //helloworld is the module name, make sure to use tab instead of 4 spaces
obj-m += helloworld.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
Using the command "make" to run Makefile, make sure there is only one makefile under your working directory.
Ru command under terminal
sudo insmod helloworld.ko
dmesg //the "hello world" information will show in the kernel log
sudo rmmod helloworld
Part 2. Module parameters, a.k.a sysfs entries.
Kernel logs are great, but they’re not always the best way to interact with a kernel module. For example, you can only look at the kernel log, meaning that the module can tell you what it’s doing, but you cannot tell the module what to do. Module parameters, colloquially called sysfs entries, can solve that problem! (Using the parameters, you can access the module global variables while loading the module and on runtime while the module is already loaded.)
Lab requirement:
Create a copy of your hello world module (from Part 1) and add two sysfs entries to it:
● enable_logging: a boolean switch that enables or disables all printk() logs from
-
0 for disabled, 1 for enabled
-
HINT: the kernel doesn’t really offer booleans, so just use an integer for this
-
HINT: just put if(enable_logging) conditionals around each printk(), we’re not
looking for some super fancy solution
● double_me: returns the specified number multiplied by 2
Should return an error if the value passed in is not a number
To test your sysfs entries, you can interact with them on the command line as such: ●echo0>/sys/module/hello/parameters/enable_logging
This disables printk() logging for your module
● cat/sys/module/hello/parameters/enable_logging
This prints whether logging is enabled (1) or disabled (0)
● echo5>/sys/module/hello/parameters/double_me
-
This should return 10
-
This should also log a message about the result to the kernel log by using
printk(). The enable_logging option would disable/enable this log message
Solution:
1. To declare a simple parameter in a module, declare a global variable and use module_param macro:
<span class="cp"> module_param(yourname, type, perm)</span>
This will create the sysfs entry. (/sys/module/hello/parameters/yourname
)
You can change the value of valueETX
from command line by
echo 1 > /sys/module/hello/parameters/yourname
2. Since you also want to notify the system when you use "echo x(random number) >/sys/module/hello/parameters/double_me" to change the input value, you need to implement an interface for setting an getting parameter values, using the callback function. The callback function in Linux kernel called module_param_cb[2]:
module_param_cb(name, ops, arg, perm)
1、name you want to set
2、oprations to set and get the value of this parameter
3、argument is the default name
4、permition(0644 or S_IRUSR|S_IWUSR)
There are several types of permissions:
- S_IWUSR
- S_IRUSR
- S_IXUSR
- S_IRGRP
- S_IWGRP
- S_IXGRP
In this S_I is a common header.
R = read ,W =write ,X= Execute.
USR =user ,GRP =Group
Code:
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include <linux/stat.h>
#include <linux/moduleparam.h>
int enable_logging;
module_param(enable_logging, int, 0644);
int set_test(const char *val, const struct kernel_param *kp)
{
int *value = kp->arg;
param_set_int(val, kp);
*value *=2;
int a;
a=(*value);
if(enable_logging == 1)
{printk("set%d\n", a);}
}
int get_test(char *buffer, const struct kernel_param *kp)
{
//int* value = kp->arg;
param_get_int(buffer, kp);
if(enable_logging==1)
{printk("get%s\n", buffer);}
}
const struct kernel_param_ops param_ops_message={
.set=set_test,
.get=get_test,
}; // callback function operations
int double_me; // callback parameter
module_param_cb(double_me, ¶m_ops_message, &double_me,0644);
/*Entrance*/
int init_module(void)
{
if(enable_logging ==1)
printk(KERN_ALERT "Hello world!\n");
return 0;
}
/*Exit*/
void cleanup_module(void)
{
if(enable_logging ==1)
printk(KERN_ALERT "Goodbye world!\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("WeixuPan");
Makefile is the same as Makefile in part one, only the module name changed to "hello" in first line.
Reference:
[1]. https://blog.sourcerer.io/writing-a-simple-linux-kernel-module-d9dc3762c234
[3].http://devarea.com/linux-kernel-development-kernel-module-parameters/#.XBR6YhNKjVo