热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>内核研究>

Hello, world:linux 内核模块版

来源: 作者: 时间:2008-07-09 Tag: 点击:


编译:

[root@localhost helloworld]# make
make -C /usr/src/kernels/2.6.21-1.3194.fc7-i686 M=/home/work/device_dev/helloworld modules
make[1]: Entering directory `/usr/src/kernels/2.6.21-1.3194.fc7-i686
'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: Leaving directory `/usr/src/kernels/2.6.21-1.3194.fc7-i686'

You have new mail in /var/spool/mail/root
[root@localhost helloworld]# ls
hello.c hello.ko hello.mod.c hello.mod.o hello.o Makefile Module.symvers
[root@localhost helloworld]#


加载该驱动:

[root@localhost helloworld]# insmod ./hello.ko
Hello world, zieckey


打印一行信息,该字符串由程序中的 hello_init 函数实现的。

查看驱动:

[root@localhost helloworld]# lsmod
Module Size Used by
hello 5504 0
zaurus 9409 0
cdc_ether 10049 1 zaurus

....


卸载该驱动:

[root@localhost helloworld]# rmmod hello
Goodbye,


打印一行信息,该字符串由程序中的 hello_exit 函数实现的。

如果在 XWindow 下面,会看不到内核输出,可以切换到文本界面下查看。

以下是网上资料:
http://blog.csdn.net/xdxiaodao/archive/2008/05/22/2470963.aspx

学习心得:
(1)驱动模块运行在内核空间,运行时不能依赖于任何函数库和模块连接,所以在写驱动时所调用的函数只能是作为内核一部分的函数。
(2)驱动模块和应用程序的一个重要不同是:应用程序退出时可不管资源释放或者其他的清除工作,但模块的退出函数必须仔细撤销初始化函数所作的一切,否则,在系统重新引导之前某些东西就会残留在系统中。
(3)处理器的多种工作模式(级别)其实就是为了操作系统的用户空间和内核空间设计的。在Unix类的操作系统中只用到了两个级别:最高和最低级别。
(4)要十分注意驱动程序的并发处理。
(5)内核API中具有双下划线(_ _)的函数,通常是接口的底层组件,应慎用。
(6)内核代码不能实现浮点书运算。

(7)Makefile文件分析:
obj-m := hello.o  代表了我们要构造的模块名为hell.ko,make 会在该目录下自动找到hell.c文件进行编译。如果 hello.o是由其他的源文件生成(比如file1.c和file2.c)的,则在下面加上(注意红色字体的对应关系):
hello-objs := file1.o file2.o ......

    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
其中 -C $(KERNELDIR) 指定了内核源代码的位置,其中保存有内核的顶层makefile文件。
    M=$(PWD) 指定了模块源代码的位置
    modules目标指向obj-m变量中设定的模块。

(8)insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局内核项(即函数和变量的地址),这是实现模块化驱动程序所必须的。
(9)Linux使用模块层叠技术,我们可以将模块划分为多个层,通过简化每个层可缩短开发周期。如果一个模块需要向其他模块到处符号,则使用下面的宏:

EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);
符号必须在模块文件的全局变量部分导出,因为这两个宏将被扩展为一个特殊变量的声明,而该变量必须是全局的。

(10)所有模块代码中都包含一下两个头文件:

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

(11)所有模块代码都应该指定所使用的许可证:

MODULE_LICENSE("Dual BSD/GPL");

此外还有可选的其他描述性定义:

MODULE_AUTHOR("");
MODULE_DESCRIPTION("");
MODULE_VERSION("");
MODULE_ALIAS("");
MODULE_DEVICE_TABLE("");

上述MODULE_声明习惯上放在文件最后。

(12)初始化和关闭
初始化的实际定义通常如下:

static int _ _init initialization_function(void)
{
/*初始化代码*/
}

module_init(initialization_function)

清除函数的实际定义通常如下:

static int _ _exit cleanup_function(void)
{
/*清除代码*/
}

module_exit(cleanup_function)


相关文章:
精通initramfs构建step by step
Linux利用kexec迅速切换内核
进程上下文VS中断上下文
内核通知链 学习笔记
linux spi子系统驱动分析
menuconfig 配置选项
《Linux操作系统内核实习》之练习一
udev详解
什么叫微内核,宏内核?
Linux 信号signal处理机制
开发简单的 Linux2.6 内核模块
删除内核的perl脚本
Linux2.6内核usb gadget驱动移植
GCC hacks in the Linux kernel
iomem
kernel学习的想法
让自己的驱动支持udev
linux内核编译步骤
内核的等待队列
Linux内核wait_queue深入分析
升级和删除内核
SD卡驱动分析2
Linux Kernel VDSO本地权限提升漏洞
内核中的TCP的追踪分析-15-TCP(IPV4)的客户端与
linux 2.6内核可加载模块的编译
内核模块HelloWorld
在环回接口上发送一个数据报
ARP初始化
1分钟编译FreeBSD内核
linux设备模型之uart驱动架构分析