Linux内核模块简介
一. 摘要
这篇文章主要介绍了Linux内核模块的相关概念,以及简单的模块开发过程。主要从模块开发中的常用指令、内核模块程序的结构、模块使用计数以及模块的编译等角度对内核模块进行介绍。在Linux系统开发过程中,以模块的形式开发其重要性不言自明,而在嵌入式设备驱动开发中将驱动程序以模块的形式发布,更是极大地提高了设备使用的灵活性——用户只需要拿到相关驱动模块,再插入到用户的内核中,即可灵活地使用你的设备。
二. 文章提纲
1. 摘要
2. 文章提纲
3. 概述
4. 模块开发常用的指令
5. 内核模块程序结构
6. 模块使用计数
7. 模块的编译
8. 使用模块绕开GPL
9. 总结
三.概述
Linux内核整体结构已经很庞大,包含了很多的组件,而对于我们工程师而言,有两种方法将需要的功能包含进内核当中。
一:将所有的功能都编译进Linux内核。
二:将需要的功能编译成模块,在需要的时候动态地添加。
上述两种方式优缺点分析:
第一种:
优点:不会有版本不兼容的问题,不需要进行严格的版本检查
缺点:生成的内核会很大;要在现有的内核中添加新的功能,则要编译整个内核
第二种:
优点:模块本身不编译进内核,从而控制了内核的大小;模块一旦被加载,将和其它的部分完全一样。
缺点:可能会有内核与模块版本不兼容的问题,导致内核崩溃;会造成内存的利用率比较低。
四.模块开发常用的指令
在内核模块开发的过程中常用的有以下指令。
1) insmod: 将模块插入内核中,使用方法:#insmod XXX.ko
2) rmmod: 将模块从内核中删除,使用方法:#rmmod XXX.ko
3) lsmod: 列表显示所有的内核模块,可以和grep指令结合使用。使用方法:#lsmod | grep XXX
4) modprobe: modprobe可载入指定的个别模块,或是载入一组相依赖的模块。modprobe会根据depmod所产生的依赖关系,决定要载入哪些模块。若在载入过程中发生错误,在modprobe会卸载整组的模块。依赖关系是通过读取 /lib/modules/2.6.xx/modules.dep得到的。而该文件是通过depmod 所建立。
5) modinfo: 查看模块信息。使用方法:#modinfo XXX.ko
6) tree –a: 查看当前目录的整个树结构。使用方法:#tree -a
五.内核模块程序结构
1) 模块加载函数(一般需要)
在用insmod或modprobe命令加载模块时,该函数被执行。完成模块的初始化工作。
Linux内核的模块加载函数一般用__init标识声明,模块加载函数必须以module_init(函数名)的形式被指定。该函数返回整型值,如果执行成功,则返回0,初始化失败时则返回错误编码,Linux内核当中的错误编码是负值,在<linux/errno.h>中定义。
在Linux中,标识__init的函数在连接时放在.init.text这个区段,而且在.initcall.init中保留一份函数指针,初始化的时候内核会根据这些指针调用初始化函数,初始化结束后释放这些init区段(包括前两者)。
代码清单:
static int __init XXX_init(void) { return ;
} moudle_init(XXX_init);
2) 模块卸载函数(一般需要)
在用rmmod或modprobe命令卸载模块时,该函数被执行。完成与加载相反的工作。
模块的卸载函数和模块加载函数实现相反的功能,主要包括
- 若模块加载函数注册了XXX,则模块卸载函数注销XXX
- 若模块加载函数动态分配了内存,则模块卸载函数释放这些内存
- 若模块加载函数申请了硬件资源,则模块卸载函数释放这些硬件资源
- 若模块加载函数开启了硬件资源,则模块卸载函数一定要关闭这些资源
代码清单:
static void __exit XXX_exit(void) { } moudle_exit(XXX_exit);
3) 模块许可证声明(必须)
如果不声明,则在模块加载时会收到内核被污染的警告,一般应遵循GPL协议。
代码清单:
MODULE_LICENSE("GPL");
4) 模块参数(可选)
模块在被加载时传递给模块的值,本身应该是模块内部的全局变量。
示例程序book.c
#include <linux/init.h> #include <linux/module.h> static char *bookName = "Good Book."; static int bookNumber = ; static int __init book_init(void) { printk(KERN_INFO "Book name is %s\n", bookName); printk(KERN_INFO "Book number is %d\n", bookNumber); return ; } static void __exit book_exit(void) { printk(KERN_INFO "Book module exit.\n"); } module_init(book_init); module_exit(book_exit); module_param(bookName, charp, S_IRUGO); module_param(bookNumber, int, S_IRUGO); MODULE_LICENSE("GPL");
在向内核插入模块的时候可以用以下方式,并且可以在内核日志中看到模块加载以后变量已经有了值。
5) 模块导出符号(可选)
使用模块导出符号,方便其它模块依赖于该模块,并使用模块中的变量和函数等。
在Linux2.6的内核中,/proc/kallsyms文件对应着符号表,它记录了符号和符号对应的内存地址。对于模块而言,使用下面的宏可以导出符号。
EXPORT_SYMBOL(符号名);
或
EXPORT_GPL_SYMBOL(符号名);
6) 模块信息(可选)
模块信息则是指模块的作者信息等。
六.模块使用计数
Linux内核提供了MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT宏来管理模块使用计数。但是对于内核模块而言,一般不会自己管理使用计数。
七.模块的编译
将下面的Makefile文件放在book.c同级的目录下,然后使用#make命令或者#make all命令编译即可生成book.ko模块文件。
对应的Makefile:
ifneq ($(KERNELRELEASE),) mymodule_objs := book.o obj-m := book.o else PWD := $(shell pwd) KVER ?= $(shell uname -r) KDIR := /usr/src/linux-headers-2.6.--generic all: $(MAKE) -C $(KDIR) M=$(PWD) clean: rm -rf *.mod.c *.mod.o *.ko *.o *.tmp_versions *.order *symvers endif
八.使用模块绕开
如果功能不编译成模块,则无法绕开GPL,编译成模块后公司发布产品则只需要发布模块,而不需要发布源码。为了Linux系统能够支持模块,需要做以下的工作:
- 内核编译时选择“可以加载模块”,嵌入式产品一般都不需要卸载模块,则可以不选择“可卸载模块”
- 将我们的ko文件放在文件系统中
- Linux系统实现了insmod、rmmod等工具
- 使用时可以用insmod手动加载模块,也可以修改/etc/init.d/rcS文件,从而在系统启动的时候就加载模块。
九.总结
本文主要介绍内核模块的概念和基本编程方法,内核模块主要由加载、卸载函数功能函数等一系列声明组成。它可以被传入参数,也可以导出符号,供其它的模块使用。
Linux内核模块简介的更多相关文章
- Linux内核分析(二)----内核模块简介|简单内核模块实现
原文:Linux内核分析(二)----内核模块简介|简单内核模块实现 Linux内核分析(二) 昨天我们开始了内核的分析,网上有很多人是用用源码直接分析,这样造成的问题是,大家觉得很枯燥很难理解,从某 ...
- 【Linux开发】内核模块简介
一. 摘要 这篇文章主要介绍了Linux内核模块的相关概念,以及简单的模块开发过程.主要从模块开发中的常用指令.内核模块程序的结构.模块使用计数以及模块的编译等角度对内核模块进行介绍.在Linux系统 ...
- Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装
原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...
- Linux防火墙简介 – iptables配置策略
Linux防火墙简介 – iptables配置策略 Netfilter/iptables简介 要想真正掌握Linux防火墙体系,首先要搞清楚Netfilter和iptables的关系,Netfilte ...
- Linux内核模块学习
注:本文是<Linux设备驱动开发详解:基于最新的Linux 4.0内核 by 宋宝华 >一书学习的笔记,大部分内容为书籍中的内容. 书籍可直接在微信读书中查看:Linux设备驱动开发详解 ...
- linux 文件系统简介
linux文件系统简介 文件系统是linux的一个十分基础的知识,同时也是学习linux的必备知识. 本文将站在一个较高的视图来了解linux的文件系统,主要包括了linux磁盘分区和目录.挂载基 ...
- 5.linux内核模块基础,内核模块学习
linux内核模块基础 一.定义 Linux 内核的整体结构非常庞大,其包含的组件也非常多,如何使用这些组件呢: 方法 1:把所有的组件都编译进内核文件,即:zImage 或 bzImage,但这样会 ...
- Smart210学习记录-------linux内核模块
Linux 驱动工程师需要牢固地掌握 Linux 内核的编译方法以为嵌入式系统构建可运行的Linux 操作系统映像.在编译 LDD6410 的内核时,需要配置内核,可以使用下面命令中的 一个: #ma ...
- linux内核模块相关命令:lsmod,depmod,modprobe,modinfo,insmod,rmmod 使用说明
加载内核驱动的通常流程: 1.先将.ko文件拷贝到/lib/module/`uname -r`(内核版本号)/kernel/driver/...目录下, 根据具体用途的区别分为net.ide.scsi ...
随机推荐
- C语言实现Web客户端(转-kungstriving)
和我的上一篇文章是一起写的,呵呵,大家给提点意见啊. :-) /*********filename : Client.cpp**************** 该程序通过标准socket实 ...
- 安装初始化mysql后,默认几个库介绍
背景介绍: 当我们安装初始化mysql后,默认建了几个数据库,那么这些数据库有什么作用呢?mysql> show databases;+--------------------+| Datab ...
- Appium for win7 环境搭建
一.安装node.js 1.到官网下载node.js:https://nodejs.org/download/ 2.获取到安装文件后,直接双击安装文件,根据程序的提示,完成nodejs的安装. 3.安 ...
- Node.js网络编程
Node.js为javascript语言提供了一个在服务端运行的平台,它以其事件驱动,非阻塞I/O机制使得它本身非常适合开发运行在在分布式设备上的I/O密集型应用,分布式应用要求Node.js必须对网 ...
- UIView的使用
UIView是iOS中所有视图的基类,表示屏幕上的一块矩形区域. UIView的基本属性包括: 1.frame,控制视图的显示位置和大小 2.backgroundColor,控制视图的背景颜色 3.a ...
- Xcode解决代码高亮、语法提示、错误警告等功能失效的解决方法
在编写xcode的项目的时候出现过代码不高亮的症状,而且所有的warning都不再提示,include的内容也显示symbol not found,非常奇怪,解决方案如下: 方法一: 1.把.pch里 ...
- JSONP理解和使用
一.代码使用: $.ajax({ async:false, url: http://跨域的dns, type: "GET", dataType: 'jsonp'}); 二.理解: ...
- bzoj1837: [CROATIAN2009]cavli 凸包1
Description 给你N个点,请循环完成下列任务 1:求出这N个点的凸包的面积 2:拿掉最左或最右或最上或最下的一个点,当点的个数不足三个时停止 Input 第一行,一个数字N 接下来N行,每行 ...
- 对char类型的理解以及对补码的理解分析
今天遇到这样一个小程序,觉得当中有些问题很容易让人忽略的! 这个程序代码如下: 程序的结果为: 我想很多像我一样的小白可能才开始是想不明白为什么最后的结果是255吧!首先,我们得知道 strlen() ...
- android studio This client is too old to work with the working copy at
http://www.cnblogs.com/maijin/archive/2013/01/09/2852330.html http://stackoverflow.com/questions/283 ...