Chinaunix首页 | 论坛 | 博客
  • 博客访问: 726403
  • 博文数量: 104
  • 博客积分: 4320
  • 博客等级: 上校
  • 技术积分: 1948
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-30 14:42
文章分类

全部博文(104)

文章存档

2012年(4)

2011年(65)

2010年(35)

分类: LINUX

2010-07-22 16:27:11

本文例子是基于2.6内核。
能运行本文示例的前提是系统中已经构建好内核树,具体构建方法参见我的上一篇文章:http://blog.chinaunix.net/u3/115276/showart.php?id=2278576
 
以LDD3(《linux设备驱动程序》)上的hello.c为例:
1. 编写源程序文件 hello.c
//hello.c
#include
#include
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_ALERT "Hello, world\n");
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
 
2. 编写Makefile
文件的内容为:
obj-m := hello.o
KERNELDIR := /lib/modules/2.6.18/build
PWD := $(shell pwd)
modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
  其中,hello.c和Makefile文件应该位于同一个目录下。
 
3.编译和装载模块
  在文件所处的目录下,执行:
  # make
  然后查看该目录下有哪些文件生成:
# ls

hello.c   hello.ko  hello.mod.c  hello.mod.o  hello.o  Makefile  Module.symvers
  
可见,已经生成模块文件hello.ko.
  然后,就可以加载该模块:
  # insmod hello.ko
  查看模块是否加载进内核:
  # lsmod
  Module Size Used by
  hello 1344 0
  nfs 219468 0
  nfsd 202224 17
  …… ……
  其中Module名为hello的即为我们所加载的模块.
  
   卸载模块:
  # rmmod hello
  同样可以通过lsmod来查看该模块是否被卸载.

  这里有两个问题,其一就是printk()输出的问题.LDD3上也说,在加载和卸载模块的时候都会有信息输出在屏幕上,如果在Windows下通过终端仿真器(我们常用的虚拟机算是一种),则在屏幕上看不到任何输出.我同时在虚拟机和和物理机都运行了该模块,均未看到有"Hello,
world"(加载模块时printk的输出)或"Goodby, cruel world"(卸载模块时printk的输出).
这个不知道是我操作系统发行版的原因还是系统配置的问题,请了解这个问题的朋友指点一下.
  其二,书上讲到如果屏幕上看不到信息,可能输出在某个日志文件里面了,并说可能在/var/log/messages文件中.并且看到网上很多
网友也说是输出到这个文件里面.我不知道有没有发现输出在其他日志文件里的,不过我的这个信息输出在/var/log/syslog里面.在加载和卸载完
该模块后, 执行命令:
  # cat /var/log/syslog | grep world
  可以看到有两行内容.当然,也可以不用grep world, 应该会出现在最后两行.
  Jul 20 14:15:29 localhost kernel: Hello, world
  Jul 20 14:15:34 localhost kernel: Goodbye, cruel world
  这就是printk应该输出的信息.
  这里有另外一个方法,可以实现printk的信息输出在屏幕上,即更改printk输出的优先级.例子中的优先级为:KERN_ALERT,优先级为,如果将优先级改为KERN_EMERG即,则可以看到屏幕的输出信息.
  修改的方法只是修改一下hello.c中两句printk()的内容,修改后的hello.c如下:
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
    printk(KERN_EMERG "Hello, world\n");  /*改动部分*/
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_EMERG"Goodbye, cruel world\n"); /*改动部分*/
}
module_init(hello_init);
module_exit(hello_exit);  
同样的方法编译生成模块,再次用insmod和rmmod,则在屏幕上看到的输出信息为:
# insmod hello.ko
#
Message from syslogd@localhost at Fri Jul 20 14:27:32 2007 ...
localhost kernel: Hello, world
# rmmod hello
#
Message from syslogd@localhost at Fri Jul 20 14:27:42 2007 ...
localhost kernel: Goodbye, cruel world

 但是,是否能够将printk()的优先级改为KERN_EMERG值得商榷.因为在Linux Kernel
Development中,对该优先级的描述为: An emergency condition; the system is probably
dead.
  以上就是整个2.6内核编译步骤以及模块动态加载的方法.理解和解释有误的地方,也请各位浏览本文的朋友指点,也希望能和对内核和驱动感兴趣的朋友交流。
阅读(1402) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~