`
猫太的鱼
  • 浏览: 239246 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Linux设备驱动编程-动态加载内核模块

阅读更多
内核模块

Linux设备驱动属于内核的一部分,Linux内核的一个模块可以以两种方式被编译和加载:

(1)直接编译进Linux内核,随同Linux启动时加载;

(2)编译成一个可加载和删除的模块,使用insmod加载(modprobe和insmod命令类似,但依赖于相关的配置文件),rmmod删除。这种方式控制了内核的大小,而模块一旦被插入内核,它就和内核其他部分一样。

下面我们给出一个内核模块的例子:

#include <linux/module.h> //所有模块都需要的头文件

#include <linux/init.h> // init&exit相关宏

MODULE_LICENSE("GPL");

static int __init hello_init (void)

{

 printk("Hello module init\n");

 return 0;

}

static void __exit hello_exit (void)

{

 printk("Hello module exit\n");

}

module_init(hello_init);

module_exit(hello_exit);

分析上述程序,发现一个Linux内核模块需包含模块初始化和模块卸载函数,前者在 insmod的时候运行,后者在rmmod的时候运行。初始化与卸载函数必须在宏module_init和module_exit使用前定义,否则会出现编译错误。程序中的MODULE_LICENSE("GPL")用于声明模块的许可证。

如果要把上述程序编译为一个运行时加载和删除的模块,可以编写makefile文件如下:

CC =/usr/local/arm/2.95.3/bin/arm-linux-gcc
KERNELDIR=/home/work/linux-2.4
CFLAGS =-D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O -Wall
test.o:test.c

    $(CC)$(CFLAGS) -c $< 

clean:
    rm -rf *.o

由此可见,Linux内核模块的编译需要给arm-linux-gcc指示-D__KERNEL__ -DMODULE 参数。-I选项跟着Linux内核源代码中Include目录的路径。

下列命令将可加载hello模块:

insmod ./hello.o

下列命令完成相反过程:

rmmod hello

如果要将其直接编译入Linux内核,则需要将源代码文件拷贝入Linux内核源代码的相应路径里,并修改Makefile。

我们有必要补充一下Linux内核编程的一些基本知识:

内存

在Linux内核模式下,我们不能使用用户态的malloc()和free()函数申请和释放内存。进行内核编程时,最常用的内存申请和释放函数为在include/linux/kernel.h文件中声明的kmalloc()和kfree(),其原型为:

void *kmalloc(unsigned int len, int priority);

void kfree(void *__ptr);

kmalloc的priority参数通常设置为GFP_KERNEL,如果在中断服务程序里申请内存则要用GFP_ATOMIC参数,因为使用GFP_KERNEL参数可能会引起睡眠,不能用于非进程上下文中(在中断中是不允许睡眠的)。

由于内核态和用户态使用不同的内存定义,所以二者之间不能直接访问对方的内存。而应该使用Linux中的用户和内核态内存交互函数(这些函数在include/asm/uAccess.h中被声明):

unsigned long copy_from_user(void *to,const void *from, unsigned long n);

unsigned long copy_to_user (void * to, void * from, unsigned long len);

copy_from_user、copy_to_user函数返回不能被复制的字节数,因此,如果完全复制成功,返回值为0。

include/asm/uaccess.h中定义的put_user和get_user用于内核空间和用户空间的单值交互(如char、int、long)。

这里给出的仅仅是关于内核中内存管理的皮毛,关于Linux内存管理的更多细节知识,《内存与I/O操作》进行更加深入地介绍。

输出

在内核编程中,我们不能使用用户态C库函数中的printf()函数输出信息,而只能使用 printk()。但是,内核中printk()函数的设计目的并不是为了和用户交流,它实际上是内核的一种日志机制,用来记录下日志信息或者给出警告提示。每个printk都会有个优先级,内核一共有8个优先级,它们都有对应的宏定义。如果未指定优先级,内核会选择默认的优先级 DEFAULT_MESSAGE_LOGLEVEL。如果优先级数字比int console_loglevel变量小的话,消息就会打印到控制台上。如果syslogd和klogd守护进程在运行的话,则不管是否向控制台输出,消息都会被追加进/var/log/messages文件。klogd 只处理内核消息,syslogd 处理其他系统消息,比如应用程序。

模块参数

2.4内核下,include/linux/module.h中定义的宏 MODULE_PARM(var,type) 用于向模块传递命令行参数。var为接受参数值的变量名,type为采取如下格式的字符串[min[-max]]{b,h,i,l,s}。min及max 用于表示当参数为数组类型时,允许输入的数组元素的个数范围;b:byte;h:short;i:int;l:long;s:string。

在装载内核模块时,用户可以向模块传递一些参数:

insmod modname var=value

如果用户未指定参数,var将使用模块内定义的缺省值。
分享到:
评论

相关推荐

    Linux设备驱动开发详解-基于最新的Linux4.0内核》配套代码.zip

    7. **模块化**:Linux支持模块化驱动,使得驱动可以动态加载和卸载,方便调试和更新。 8. **udev规则**:udev是Linux系统下的设备管理器,它根据设备属性生成设备节点,并赋予相应的权限,驱动开发者需要了解如何...

    linux内核模块编程-----源码

    在Linux操作系统中,内核模块(Kernel...总之,"Linux内核模块编程"涉及到操作系统核心层面的知识,需要深入理解内核API、设备驱动原理以及文件系统的运作机制。通过实践,开发者可以更灵活地定制和增强Linux系统功能。

    linux 内核模块编程指导

    * 编译和加载内核模块:编译和加载内核模块,以便在 Linux 操作系统中使用。 * 测试和调试内核模块:测试和调试内核模块,以确保其正确工作。 Linux 内核模块编程的常见问题 Linux 内核模块编程中常见的一些问题...

    linux设备驱动编程-(参考理解)1

    在Linux设备驱动编程中,了解内核模块的创建和管理是至关重要的。内核模块是一种可插入和移除的代码段,允许系统根据需要动态扩展功能。这些模块可以通过`insmod`、`modprobe`或`rmmod`命令进行加载和卸载,以控制...

    linux设备驱动详解-源代码

    - **内核API**:理解Linux内核提供的设备驱动编程接口,如`request_module()`、`device_register()`等。 - **Makefile编写**:驱动程序的构建过程,包括编译、链接以及如何将驱动模块加载到内核。 - **系统调用**:...

    深入linux设备驱动程序内核机制

    内核模块是Linux系统中实现设备驱动程序的一种方式,它们是可动态加载和卸载的代码片段。在第一章中,作者详细介绍了内核模块的特性,包括: 1. **模块加载过程**:内核模块以ELF(Executable and Linkable Format...

    LINUX内核编程---相当经典

    8. **内核模块**:内核模块允许动态加载和卸载代码,这使得对内核的修改变得更加灵活。学习如何编写和使用`module_init()`和`module_exit()`宏,以及如何使用`insmod`和`rmmod`命令,是内核编程实践中的重要环节。 ...

    linux内核模块编程

    Linux内核模块编程是深入Linux操作系统核心的一种编程实践,它允许开发者动态地向内核添加代码(模块),而无需重新编译整个内核。这种机制极大地提高了系统的可扩展性和灵活性,使得增加、更新或删除特定功能成为...

    深入浅出Linux设备驱动编程

    【深入浅出Linux设备驱动编程】是一本针对Linux操作系统中设备驱动程序开发的教程,旨在帮助读者理解并掌握Linux驱动的编写技术。作者宋宝华强调了Linux软件工程师的两个层次,即应用软件工程师和固件工程师,其中...

    LINUX内核模块编程

    Linux内核模块(Kernel Module)是动态加载到内核空间的一段代码,它可以在需要时加载,不需要时卸载,以实现对硬件设备驱动、文件系统或其他特定功能的支持。这使得系统能够根据实际需求调整内核的功能集,降低了...

    Linux网络设备驱动编程.pdf

    Linux网络设备驱动编程是内核编程领域中的一个重要分支,它涉及到内核模块的编写,主要负责与硬件设备进行通信。在Linux操作系统中,网络设备的驱动通常需要遵循一系列标准的编程接口和规范来实现。网络设备驱动程序...

    深入浅出Linux 设备驱动编程

    Linux内核模块是动态加载到内核中的独立组件,可以是设备驱动程序或其他功能扩展。模块可以有两种加载方式: - **直接编译进内核**:模块成为内核的一部分,在系统启动时自动加载。 - **编译成可加载模块**:使用`...

    linux 内核精髓-精通linux内核必会的75个绝技

    8. **内核模块开发**:介绍如何编写、加载和卸载内核模块,以及模块编程中的关键函数和数据结构。 9. **性能分析与调优**:讨论性能监控工具,如perf、sysfs和procfs,以及如何通过调整内核参数优化系统性能。 10....

    LINUX内核和驱动编程

    内核模块是LINUX内核的一个重要组成部分,它提供了一种动态加载和卸载内核功能的方法。这种方式使得内核能够根据需要扩展其功能,而无需重新编译整个内核。这对于嵌入式系统来说尤为重要,因为这些系统的资源有限,...

    Linux设备驱动程序开发基础(PPT)

    Linux 内核的一部分,标准接口是指驱动程序必须为 Linux 内核或者其从属的子系统提供一个标准的接口,核心机制是指驱动程序可以使用标准的核心服务,动态可加载是指多数的 Linux 设备驱动程序可以在核心模块发出加载...

    linux内核编程.pdf

    - `insmod`:加载内核模块。 - `rmmod`:卸载内核模块。 ### 总结 Linux内核编程是一个复杂而强大的过程,它允许开发者对操作系统的核心功能进行扩展和优化。内核模块编程涉及到对内核数据结构的深入理解,以及对...

    深入浅出Linux设备驱动编程入门

    Linux内核模块是设备驱动程序的核心组成部分,它可以有两种编译和加载方式: 1. **直接编译进内核**:这种方式下的模块会随同Linux内核启动时一起加载。 2. **编译成可加载模块**:这种方式允许开发者根据需求动态...

Global site tag (gtag.js) - Google Analytics