Chinaunix首页 | 论坛 | 博客
  • 博客访问: 473743
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: LINUX

2014-11-20 23:10:36

开源力量学习笔记
下载内核

可以从网站git.kernel.org中找到自己感兴趣的分支

Linus的分支
  1. git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
下载完成后,可以用make localmodconfig来按照现有的kernel编译源代码

开始编译
  1. make -j6
编译完后安装
  1. make modules_install
  2. make install
然后修改grub2,默认fedora19第一个就是安装的内核。ubuntu可以用sudo update-grub
  1. cd /boot/grub2
  2. vim grub.cfg
重启一下就可以进编译好的内核了。可以写个内核模块测试一下
  1. echo > main.c
  2. echo > Makefile
linux中底层有一个Kbuild,然后在各层中有kconfig.然后又对应一个Makefile
下面是一个简单的Makefile:
  1. obj-m = main.o

  2. all:
  3.         make -C /lib/modules/`uname -r`/build M=`pwd`
  4. clean:
  5.         rm -f *.o *.ko *.mod.c modules.order Module.symvers
make -C 后面是内核的目录,用``+shell可以获取内容。M应该是内核的源地址。

要使用内核的函数,必须只使用内核的导出函数。不能使用用户空间的任何Lib
-EXPORT_SYMBOL和EXPORT_SYMBOL_GPL
-或者在.h中实现的函数
编译有多个源文件的module
此时main.c文件中还是空的,加点东西试试吧
  1. #include <linux/module.h>

  2. MODULE_LICENSE("GPL");    //代码的说明
  3. MODULE_AUTHOR("Chen");
  4. MODULE_DESCRIPTION("The module is only used for test.");

  5. static __init int minit(void)    //如果函数只调用一次的函数可以用__init来修饰,调用完后可以free它
  6. {
  7.     printk("call %s.\n",__FUNCTION__);
  8.     return 0;
  9. }

  10. static __exit int mexit(void)    //退出的话就可以用__exit修饰
  11. {
  12.     printk("call %s.\n",__FUNCTION__);
  13. }

  14. module_init(minit)    //内核宏入口
  15. module_exit(mexit)    //内核宏退出
make后可以用insmod家在编译好的内核模块main.ko,卸载就是rmmod
然后通过dmesg看情况。

更进一步的话,可以再创建一个other.c
  1. #include <linux/module.h>

  2. void other_function(void)
  3. {
  4.     printk("call %s.\n",__FUNCTION__);
  5. }
然后在main.c中引用,当然我们还需要再改Makefile
  1. obj-m = test.o
  2. test-y = main.o other.o

  3. all:
  4.     make -C /lib/modules/`uname -r`/build M=`pwd`
  5. clean:
  6.     rm -f *.o *.ko *.mod.c modules.order Module.symvers
-y表示把mian.o和other.o生成test.o
编译多个源文件位于不同目录的module
如果other.o在src的文件目录下呢,那么test-y = main.o src/other.o
指定include.h位置
如果是other.h在include文件夹下,那么同样加上目录
  1. #ifndef __OTHER_H
  2. #define __OTHER_H

  3. extern void other_function(void);
  4. #endif
当然如果我们需要使用外部的库文件,文件路径没有那么固定。这时候就可以在Makefile中添加
  1. all:
  2.     make -C /lib/modules/`uname -r`/build EXTRA_CFLAGS=-I$(shell pwd)/include M=`pwd`
同时main.c中的#include "include/other.h"可以改成
  1. #include <other.h>
模块参数
我们可以用modinfo来看模块信息,如:
  1. [chen@localhost linux]$ modinfo ./fs/fuse/fuse.ko
  2. filename: /home/chen/mygit/linux/./fs/fuse/fuse.ko     表示模块的绝对路径
  3. alias: devname:fuse                                    alias:别名
  4. alias: char-major-10-229
  5. alias: fs-fuseblk
  6. alias: fs-fuse
  7. license: GPL                                           支持GPL协议
  8. description: Filesystem in Userspace                   模块的描述
  9. author: Miklos Szeredi <miklos@szeredi.hu>             模块作者
  10. alias: fs-fusectl
  11. depends:                                               depends:表示fuse.ko模块所依赖的模块
  12. intree: Y
  13. vermagic: 3.18.0-rc5 SMP mod_unload                    vermagic:表示编译时对应的内核版本、硬件平台及GCC版本
  14. parm: max_user_bgreq:Global limit for the maximum number of backgrounded requests an unprivileged user can set (uint)    parm:相对应的调试参数,括号中表示参数的类型如uint
  15. parm: max_user_congthresh:Global limit for the maximum congestion threshold an unprivileged user can set (uint)
可以自己编写一个
  1. static unsigned int testpar = 0;
  2. module_param(testpar, uint, S_IRUGO | S_IWUSR)
  3. //然后在main函数中加
  4.     printk("testpar = %d.\n", testpar);
编译后就看到了
  1. [chen@localhost test]$ modinfo tmain.ko
  2. filename: /home/chen/mygit/test/tmain.ko
  3. description: The module is only used for test.
  4. author: Chen
  5. license: GPL
  6. depends:
  7. vermagic: 3.18.0-rc5 SMP mod_unload
  8. parm: testpar:uint
然后我们就可以给模块参数赋值了
  1. [chen@localhost test]$ insmod tmain.ko
  2. [chen@localhost test]$ rmmod tmain.ko
  3. [chen@localhost test]$ insmod tmain.ko testpar=100
  4. [chen@localhost test]$ dmesg
  5. [ 7389.378824] testpar = 0.                    //之前没赋值
  6. [ 7389.378830] call minit.
  7. [ 7389.378831] call other_function.
  8. [ 7509.541034] call mexit.
  9. [ 7529.539102] testpar = 100.                   //赋值之后
  10. [ 7529.539107] call minit.
  11. [ 7529.539108] call other_function.
编写和编译一个module之间有依赖的情况
首先把上面的模块变成m1,复制一个m2,删除其中的src,在m2中编译会有警告说函数未定义
这时就可以把m1编译出来的Module.symvers复制到m2中,编译就能通过。加载时需要先加载m1模块,再加载m2模块




阅读(1798) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~