linux kernel2.6编译启用新内核以及模块符号的导出和调用

一、为什么要编译源码?

先看看以下文章,描述的很详尽:

http://tscsh.blog.163.com/blog/static/20032010320131641225800/

http://zhidao.baidu.com/linkurl=jP0BO6nl4ZCSdEs_NNEELbQOK7IPu741vRiuONZPl5U5a1mKC8qUfuNivSKSJkOuV2L_jnqUX_G8vhNNHbLXka

http://www.ibm.com/developerworks/cn/linux/l-lkm/#icomments


二、编译启动系统内核


(1)下载源码:

www.kernel.org下载linux系统源码,格式为xxx.tar.xz。复制到/usr/src/下。 

(2)查看当前的系统内核版本,解压缩文件:

uname -r  查看版本。/usr/src/下,用xz 及tar解压缩命令:解压tar.xz文件:先 xz -d xxx.tar.xz 将 xxx.tar.xz解压成 xxx.tar 然后,再用 tar xvf xxx.tar来解包。

(3)配置内核:

  • cd /usr/src/linux.2.6.xx.xx进入刚才解压缩的那个文件目录
  • cp /boot/config-    按Tab键自动补全,再接着输入 .config,回车,目的是将当前运行版本的内核配置拷贝到新内核中。
  • make menuconfig具体配置内核,这里我选择的默认,按ESC2次,退出保存。
<a> 出错,make menuconfig错误 :   HOSTCC scripts/kconfig/kxgettext.o *** Unable to find the ncurses libraries or the *** required header files. *** 'make menuconfig' requires the ncurses libraries. *** *** Install ncurses (ncurses-devel) and try again. *** make[1]: *** [scripts/kconfig/dochecklxdialog] Error 1 make: *** [menuconfig] Error 2
<b> 解决办法:  sudo apt-get install libncurses5-dev  或者: sudo apt-get install ncurses-dev 

(4)编译内核:

  • make -j4    j后面的数字为编译时候开启的进程数,一般所需要的时间在1到4个小时。

(5)编译安装新内核模块:

  • make module_install

(6)安装内核:

  • make install

(7)生成启动项:

  • sudo mkinitramfs -o /boot/initrd.img-2.6.36.61             //此处是我自己的新内核版本号
  • sudo update -initramfs -c -k 2.6.36.61
  • sudo -grub2 //自动修改系统引导配置,将新内核的启动项添加到grub.cfg启动文件中

此处小结:对步骤(7)中的命令还不是太了解,在我的独立的ubuntu系统中,会出现两个ubuntu启动项,而虚拟机中则直接启动了新内核。此外,这一节中,主要参考的这篇文章:引用申明

三、编写两个简单模块

在当前的/home/ 目录下创建文件夹mkdir liulu_drivers,在liulu_drivers下创建两个文件夹hello和hello-1。

(1) hello/下包含有导出模块符号的被调用模块源文件hello.c以及Makefile文件:

>>>>>>>>>>hello.c文件代码>>>>>>>>>>

#include 
     
     
      
      
#include 
      
      
       
       
MODULE_LICENSE("Dual BSD/GPL");

int hello_num=5;

EXPORT_SYMBOL(hello_num);

static int hello_init(void)
{
	printk(KERN_ALERT "Hello ,liulu.go ahead!\n");
	return 0;
}

static void hello_exit()
{
	printk(KERN_ALERT "Goodbye,cruel world!\n");
}

module_init(hello_init);
module_exit(hello_exit);

      
      
     
     

Makefie文件:
# 如果已经定义KERNELRELEASE,则说明是从内核构造系统调用的?嘛意思?
# 因此可以利用其内建语句
#ifneq ($(KERNELRELEASE),)
#  obj-m :=hello.o
# 否则,是直接从命令行调用的
# 这时候要调用内核构造系统
#else
#  KERNELDIR := /lib/modules/$(shell uname -r)/build
#  PWD :=$(shell pwd)
#
#default:
#
#  $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
#
#endif
#
#
	KERNELDIR := /lib/modules/$(shell uname -r)/build
	PWD :=$(shell pwd)

	obj-m :=hello.o

modules:

	make -C $(KERNELDIR) M=$(PWD) modules

clean :

	rm -rf *.o
	rm -rf *.mod.*

在hello/下输入命令:make生成模块文件hello.ko,insmod hello.ko 加载该模块。

(2) hello-1/下包含有调用hello.c的模块源文件hello-1.c以及Makefile文件:

>>>>>>>>>>hello-1.c文件代码>>>>>>>>>>
#include 
    
    
     
     
#include 
     
     
      
      
MODULE_LICENSE("Dual BSD/GPL");

extern int hello_num;

int i=2;
module_param(i, int, S_IRUGO);

static int hello_init(void)
{
	for(;i
      
      
     
     
    
    

Makefile文件:
#自由发挥中...

KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)

obj-m :=hello-1.o

KBUILD_EXTRA_SYMBOLS += /home/liulu/liulu_drivers/hello/Module.symvers
export $(KBUILD_EXTRA_SYMBOLS)

Modules:

	make -C $(KERNELDIR) M=$(PWD) modules


Clean:

	rm -rf *.o
	rm -rf *.mod.*

(3)解释:两个文件的代码以及Makefile文件书本都有详细说明,在此不再赘述,只作大概的说明。

  • hello.c中的hello_num为导出符号,导出符号可以时变量或者函数接口名称,使用EXPORT_SYMBOL(xxx); 申明。
  • hello-1.ko中若要调用hello.ko导出的模块符号hello_num,需在hello-1.c中申明:extern int hello_num;
  • 此外hello-1.c中还使用了模块传入参数,使用module_param(变量名,类型,S_IRUGO);申明。

  • 关于Makefile的说明:$(uname -r)得到当前运行的内核版本,$(pwd)为当前的路径,其具体语法含义见书本。


四、模块导出符号及其调用方式:

<三>中已经准备好了两个模块的源文件代码,这时候就可以进行模块符号的导出及调用了,其具体的执行过程为:

  • hello.c代码中需申明导出符号hello_num
  • hello-1.c中需使用extern引用hello-1.c的导出符号

执行模块导出符号的调用方式一:

1.先编译hello.c生成模块文件hello.ko,然后su之后,insmod hello.ko加载这个模块。

2.将hello/下编译生成的Module.symvers复制到hello-1/下,该文件包含有hello.c的导出符号对应地址,hello-1.ko需要这个文件来查找导出符号。

3.编译hello-1.c生成模块文件hell-1.ko,然后insmod hello-1.ko i=xxx加载这个模块,其中i=xxx为可选,i初始化为2,不传入参数也可以。

4.我的机器下没有直接打印出信息,使用dmesg查看系统日志,可以看到模块加载的打印信息。

注意:2与3的顺序一定不能反,否则编译找不到hello_num地址。


执行模块导出符号的调用方式二:

1.先编译hello.c生成模块文件hello.ko,然后su之后,insmod hello.ko加载这个模块。

2.在hello-1的Makefile文件中添加如下两行语句:

KBUILD_EXTRA_SYMBOLS+= /home/liulu/liulu_drivers/hello/Module.symvers

export $(KBUILD_EXTRA_SYMBOLS)

这两行语句显示的再编译时指明了所需要用的导出符号的地址,然后使用export导出。

3.编译hello-1.c生成模块文件hell-1.ko,然后insmod hello-1.ko i=xxx加载这个模块,其中i=xxx为可选,i初始化为2,不传入参数也可以。

4.我的机器下没有直接打印出信息,使用dmesg查看系统日志,可以看到模块加载的打印信息。


程序运行如图所示:

(1)insmod 两个模块,无提示,成功加载。



(2)dmesg查看系统日志:



(3)先rmmod hello-1,再rmmod hello,这跟模块注册注销的顺序一样,前后相反,再查看系统打印信息:



分析:在打开Module.symvers中可以看到如下信息

0x987c032a hello_num /home/liulu/liulu_drivers/hello/hello EXPORT_SYMBOL

而模块在需找导出符号的时候查看的路径其实还有系统usr/src/$(uname -r)/下的Module.symvers,打开这个文件,可以看到里面对应的都是各个导出符号的地址。也有网友介绍过将hello_num的这行语句直接添加到系统的Module.symvers文件中,这样就相当于hello_num全局通用,不需要上述两个步骤那样繁琐,遗憾的是,在我添加之后,导致系统编译报错,目前还不知道原因是什么。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值