Linux设备驱动开发详解-Note(7)---Linux 内核模块(1)

Linux 内核模块(1)

成于坚持,败于止步

Linux 内核模块简介 

Linux 内核的整体结构非常庞大,其包含的组件也非常多。我们怎样把需要的部分都包含在内核中呢? 

一种方法是把所有需要的功能都编译到 Linux 内核。这会导致两个问题,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核。 

有没有一种机制使得编译出的内核本身并不需要包含所有功能,而在这些功能需要被使用的时候,其对应的代码可被动态地加载到内核中呢? 

Linux 提供了这样的一种机制,这种机制被称为模块(Module),可以实现以上效果。模块具有以下特点。 

模块本身不被编译入内核映像,从而控制了内核的大小。 

模块一旦被加载,它就和内核中的其他部分完全一样。 

为了使读者对模块建立初步的感性认识,我们先来看一个最简单的内核模块“Hello World”,如代码所示:

1  #include <linux/init.h> 
2  #include <linux/module.h> 
3  MODULE_LICENSE("Dual BSD/GPL"); 
4  static int hello_init(void) 
5  { 
6  printk(KERN_ALERT " Hello World enter\n"); 
7  return 0; 
8  } 
9  static void hello_exit(void) 
10 { 
11 printk(KERN_ALERT " Hello World exit\n "); 
12 } 
13 module_init(hello_init); 
14 module_exit(hello_exit); 
15  
16 MODULE_AUTHOR("Song Baohua"); 
17 MODULE_DESCRIPTION("A simple Hello World Module"); 
18 MODULE_ALIAS("a simplest module"); 
这个最简单的内核模块只包含内核模块加载函数、卸载函数和对 Dual BSD/GPL许可权限的声明以及一些描述信息。编译它会产生 hello.ko 目标文件,通过“insmod ./hello.ko”命令可以加载它,通过“rmmod hello”命令可以卸载它,加载时输出“Hello World enter”,卸载时输出“Hello World exit”。 内核模块中用于输出的函数是内核空间的 printk()而非用户空间的 printf(),printk()的用法和 printf()相似,但前者可定义输出级别。printk()可作为一种最基本的内核调试手段。 

在 Linux 系统中,使用 lsmod 命令可以获得系统中加载了的所有模块以及模块间的依赖关系,例如:

[root@localhost driver_study]# lsmod 
Module                      Size   Used by 
hello                        1568    0  
ohci1394                    32716   0  
ide_scsi                  16708   0  
ide_cd                      39392   0  
cdrom                      36960   1 ide_cd 
lsmod 命令实际上读取并分析/proc/modules 文件,与上述 lsmod 命令结果对应的/proc/modules 文件如下:
[root@localhost driver_study]# cat /proc/modules  
hello 1568 0 - Live 0xc8859000 
ohci1394 32716 0 - Live 0xc88c8000 
ieee1394 94420 1 ohci1394, Live 0xc8840000 
ide_scsi 16708 0 - Live 0xc883a000 
ide_cd 39392 0 - Live 0xc882f000 
cdrom 36960 1 ide_cd, Live 0xc8876000 
内核中已加载模块的信息也存在于/sys/module 目录下,加载 hello.ko 后,内核中将包含/sys/module/hello 目录,该目录下又包含一个 refcnt 文件和一个 sections 目录,在/sys/module/hello 目录下运行“tree –a”得到如下目录树:
[root@localhost hello]# tree -a 
. 
|-- refcnt 
'-- sections 
      |-- .bss 
      |-- .data 
      |-- .gnu.linkonce.this_module 
      |-- .rodata 
      |-- .rodata.str1.1 
      |-- .strtab 
      |-- .symtab 
      |-- .text 
      '-- _ _versions 
modprobe 命令比 insmod 命令要强大,它在加载某模块时会同时加载该模块所依赖的其他模块。使用 modprobe 命令加载的模块若以“modprobe -r filename”的方式卸载将同时卸载其依赖的模块。 

使用 modinfo <模块名>命令可以获得模块的信息,包括模块的作者、模块的说明、模块所支持的参数以及 vermagic,如下所示:

[root@localhost driver_study]# modinfo hello.ko 
filename:       hello.ko 
license:        Dual BSD/GPL 
author:         Song Baohua 
description:    A simple Hello World Module 
alias:           a simplest module 
vermagic:       2.6.15.5 686 gcc-3.2 
depends: 

Linux 内核模块的程序结构 

一个 Linux 内核模块主要由以下几个部分组成。 

模块加载函数(必须)。 

当通过 insmod 或 modprobe 命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块的相关初始化工作。 

模块卸载函数(必须)。 

当通过 rmmod 命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能。 

模块许可证声明(必须)。 

模块许可证(LICENSE)声明描述内核模块的许可权限,如果不声明 LICENSE,模块被加载时,将收到内核被污染 (kernel tainted)的警告。 在 Linux 2.6 内核中,可接受的 LICENSE 包括“GPL”、“GPL v2”、“GPL and additional rights”、“Dual BSD/GPL”、“Dual MPL/GPL”和“Proprietary”。 大多数情况下,内核模块应遵循 GPL 兼容许可权。Linux 2.6 内核模块最常见的是以 MODULE_LICENSE( "Dual BSD/GPL" ) 语句 声 明模 块采用 BSD/GPL 双LICENSE。 

模块参数(可选)。 

模块参数是模块被加载的时候可以被传递给它的值,它本身对应模块内部的全局变量。 

模块导出符号(可选)。 

内核模块可以导出符号(symbol,对应于函数或变量),这样其他模块可以使用本模块中的变量或函数。 

模块作者等信息声明(可选)。

就到这里了,O(∩_∩)O~

我的专栏地址:http://blog.csdn.net/column/details/linux-driver-note.html

待续。。。。

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值