1. 程式人生 > >Embedded System-LAB1-PART1-PART2(loadable module and passing argument)

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, &param_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

[2].https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-3-passing-arguments-to-device-driver/

[3].http://devarea.com/linux-kernel-development-kernel-module-parameters/#.XBR6YhNKjVo