天天看点

Linux内核模块DemoLinux内核模块Demo

Linux内核模块Demo

文章目录

  • Linux内核模块Demo
    • 1. 思路
    • 2. 源代码
    • 3. Makefile

1. 思路

要实现一个内核模块,要考虑以下几个方面:

  • 头文件
  • 模块入口
  • 模块出口
  • 模块加载时是否需要传参
  • 模块许可协议声明,需要遵循GPL协议
  • 模块作者声明,告诉别人发现bug时该联系谁
  • 模块描述,简要叙述这个模块是干什么的
  • 模块版本,版本号对于软件的迭代更新是非常重要的

2. 源代码

/*
**  hello_module.c
**  该文件是linux内核模块的简单示例代码,
**  目的是展示一个Linux内核模块的基本构成。
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

static unsigned int param_int = 0;   //模块参数,用于存放模块加载时传入的整型参数。
static unsigned int param_array[16] = {0};    //模块参数,用于存放模块加载时传入的数组参数。
static unsigned int input_array_len = 0;    //与param_array结合使用,用于保存实际传入的参数长度。

MODULE_LICENSE("GPL v2"); //声明许可协议
MODULE_AUTHOR("Wanglehe"); //声明模块作者
MODULE_DESCRIPTION("This is a simple module test."); //模块说明
MODULE_VERSION("v1.0"); //模块版本说明

// 声明一个整型参数,输入值保存在param_int中。0644表明该参数root用户可写,其他用户只读。
module_param(param_int, uint, 0644);

// 声明一个数组型参数,输入值保存在param_array中,实际输入的数据长度保存在input_array_len中。
// 0644表明该参数root用户可写,其他用户只读。
module_param_array(param_array, uint, &input_array_len, 0644);

/*
**  模块入口函数。
**  该函数当模块加载时被调用。
**  static关键字用于限定该函数的作用域。
**  需要提供int型返回值。
**  __init关键字表明该函数被编译链接到init段。
**  init段的在执行完成之后,其所占用的资源就会被释放。
 */
static int __init hello_init(void)
{
    int i = 0;

    //作为示例代码,此处指打印一些提示信息。
    printk(KERN_ERR "%s %d %s: Hello module init.\n", __FILE__, \
        __LINE__, __func__);

    //打印参数的值,验证在有输入时,参数是否改变。
    printk(KERN_ERR "Int Arg = %d\n", param_int);
    for(i=0; i<input_array_len; i++)
    {
        printk(KERN_ERR "Array[%d]=%d\n", i, param_array[i]);
    }
	return 0;
}

/*
**  模块出口函数
**  该函数在模块卸载是被调用。
**  static关键字限定了该函数的作用域。
**  __exit关键字表明该函数被编译链接到exit段。
**  如果代码不是以模块的形式动态加载到内核,而是直接被编译到内核中,那么使用__exit
**  进行修饰的代码不会被编译到内核,因为永远不会被调用。
 */
static void __exit hello_exit(void)
{
    //作为示例代码,此处指打印一些提示信息。
    printk(KERN_ERR "%s %d %s: Hello module exit.\n", __FILE__, \
        __LINE__, __func__);
	return;
}

module_init(hello_init);        //指定模块入口
module_exit(hello_exit);        //指定模块出口


/**
 ** 模块操作命令:
 ** (1)模块加载:
 **         insmod hello_module.ko
 ** (2)模块带参数加载:
 **         insmod hello_module.ko param_int=100 param_array=1,2,3,4,5
 **         传入参数时,参数名必须正确,否则会出错。
 **         不同参数之间用空格隔开,数组参数的多个值之间用逗号隔开
 ** (3)获取模块信息:
 **         modinfo hello_module.ko
 ** (4)列出已经加载的模块:
 **         lsmod
 ** (5)卸载模块:
 **         rmmod hello_module
 **/

           

3. Makefile

#!/bin/bash

# 告诉编译器要编译哪些源码
# 鉴于示例代码为hello_module.c,所以此处指定为hello_module.o
obj-m += hello_module.o


# 内核源码目录
KDIR := /work/itop/iTop4412_Kernel_3.0

# 获取当前目录
PWD ?= $(shell pwd)

# 编译模块
all:
	make -C $(KDIR) M=$(PWD) modules

# 删除编译生成的文件
clean:
	rm -rf *.o *.mod.c *.ko *.order *.symvers
           

继续阅读