构造和运行模块

作者:蔡伦辉
写在前面
作者一直支持GPL的精神。允许任何人自由使用、转载、复制和再分发,但必须保留作者署名,必须保证全文完整转载,包括完整的版权声明。
由于作者水平有限,因此不能保证文章内容准确无误,请批判阅读。如果你发现任何错误或对文章内容有任何建议,欢迎你与我联系:
Email: caiallen@tom.com  QQ群: 14765968
设置测试系统
在该小节中,有以下一段话:
“不管内核来自哪里,想要为2.6x内核构造模块,还必须在自己的系统中配置并构造好内核树。这一要求和先前版本的内核不同,先前的内核只要有一套内核头文件就够了。但因为2.6内核的模块要和内核源代码树中的文件连接,通过这种方式,可得到一个更加健壮的模块装载器,但也需要这些目标文件存在于内核目录树中。”
这段话说出了2.4和2.6两种版本的驱动模块的编写的一个不同之处。问题来自,我用的操作系统是Fedora Core 5。FC5在安装时是不安装源代码树在PC上的。所以我必须在我的FC5上建立内核源代码树。最好在构造内核模块时运行的恰好是目标内核。书上的例子是在版本2.6.10中构造的,用命令uname -r查看,FC5的版本信息为:2.6.15-1.2054_FC5。所以我要建立的内核源代码树的版本为2.6.15。下面详细介绍其建立过程。
1。  下载内核rpm包
rpm包名称:kernel-2.6.15-1.2054_FC5.src.rpm
下载地址:http://download.fedora.redhat.com/pub/fedora/linux/core/5/source/SRPMS/
kernel-2.6.15-1.2054_FC5.src.rpm
2。    安装rpm包
以root身份登陆,以下步骤都以root身份执行。进入保存rpm包的目录下,运行命令:
#rpm -Uvh kernel-2.6.15-1.2054_FC5.src.rpm
            该命令将rpm的内容写到路径/usr/src/redhat/SOURSE和/usr/src/redhat/SPECS下。
3。   build源码包
            #cd /usr/src/redhat/SPECS
#rpmbuild -bp --target i686 kernel-2.6.spec
该命令将会把内核源码树放到目录
/usr/src/redhat/BUILD/kernel-2.6.15/kernel-2.6.15.686
4。    配置内核
Fedora Core 5附带的内核配置文件在内核源码树的configs/目录下。
例如,i686 SMP 配置文件被命名为
configs/kernel-version-i686-smp.config。
但我的PC机为i686,单CPU,所以不是SMP,应该选的内核配置文件是:kernel-2.6.15-i686.config
注意:如果你的PC是单CPU的,而选 configs/kernel-version-i686-smp.config进行内核配置,则在建立代码树后运行后面的insmod hello.ko会失败,失败原因我在文件/var/log/messages中找到如下:Nov 23 04:55:02 localhost kernel: hello: version magic '2.6.15-1.2054_FC5 SMP 686 REGPARM 4KSTACKS gcc-4.1' should be '2.6.15-1.2054_FC5 686 REGPARM 4KSTACKS gcc-4.1'
一对比:
'2.6.15-1.2054_FC5 SMP 686 REGPARM 4KSTACKS gcc-4.1'
'2.6.15-1.2054_FC5 686 REGPARM 4KSTACKS gcc-4.1‘
看出区别了吧,原因是我选的配置文件不对。我一开始就犯了这个错误错误,结果不得不又从头开始进行漫长的编译。
使用下列命令来将需要的配置文件复制到合适的位置,用来编译:
#cd /usr/src/redhat/BUILD/kernel-2.6.15/linux-2.6.15.i686 
#cp configs/kernel-version-i686.config .config你也可以在 /lib/modules/version/build/.config 这个位置找到与您当前的内核匹配的 .config 文件。因为build是个连接,其连接目标就是/usr/src/redhat/BUILD/kernel-2.6.15/linux-2.6.15.i686
用以下命令调出内核配置菜单。
#make menuconfig
配置如下:
Loadable module support --->

  • Enable loadable module support
  • Module unloading
    [ ] Module versioning support (EXPERIMENTAL)
  • Automatic kernel module loading       
    5。    修改Makefile
    每个内核的名字都包含了它的版本号,这也是 uname -r 命令显示的值。内核Makefile 的前四行定义了内核的名字。为了保护官方的内核不被破坏,Makefile经过了修改,以生成一个与运行中的内核不同的名字。在一个模块插入运行中的内核前,这个模块必须针对运行中的内核进行编译。为此,你必须编辑内核的Makefile。
    例如,如果 uname -r 返回字符串 2.6.15-1.2054_FC5,就将 EXTRAVERSION 定义从:
    EXTRAVERSION = -prep
    修改为:
    EXTRAVERSION = -1.2054_FC5
    也就是最后一个连字符后面的所有内容。
    6。    编译内核
    在目录/usr/src/redhat/BUILD/kernel-2.6.15/linux-2.6.15.i686下即Makefile所在的目录使用下面命令编译内核:
    #make bzImage           编译内核 
    #make modules           编译模块 
    #make modules_install   安装模块这一步可是一个漫长的过程啊,花去我差不多一个小时


    7。    完成“内核树”的安装
    以上这一步如果没什么错误,到此就完成了内核代码树的建立。
    目录“/usr/src/redhat/BUILD/kernel-2.6.15/kernel-2.6.15.686/”中就是所谓的“内核代码树”,同时“/lib/modules/2.6.15-1.2054_FC5/build”是个符号链接,也指向这个目录,所以这里也可以叫做“内核代码树”。
    以上的建立步骤是在参考《在Linux 2.6内核下编译可以加载的内核模块》(原文地址http://blog.csdn.net/wooin/archive/2007/05/21/1619141.aspx)同时结合自己的实践而得出,增加一些说明并修正了其中的一些错误。
    完成以上的步骤,便为我们后面的实践打下了基础。
    Hello World模块
    要想验证我们的内核代码树是否成功建立,可以写个内核模块测试一下,就从Hello world程序开始。以下是名为hello.c的文件的代码:
                    
                    #include linux/init.h>
    #include linux/module.h>
    MODULE_LICENSE("Dual BSD/GPL");//(1)
    static int hello_init(void)//(2) 
    {
       printk(KERN_ALERT "Hello, World!\n");//(3)
       return 0;
    }
    static void hello_exit(void) 
    {
       printk(KERN_ALERT "Goodbye, cruel World!\n");
    }
    module_init(hello_init);//(4)
    module_exit(hello_exit);//(5)
    代码说明:
        (1):
    MODULE_LICENSE是一个特殊的宏,用来告诉内核,该模块采用自由许可证;可以不要这样的声明,但不要的话,运行ismod hello.ko时会出现"hello: module
    license 'unspecified' taints
    kernel.",词典上对taints的解释是"感染,污点",即内核在装载该模块时会产生抱怨

    ,内核有情绪?!还要注意的一点是,这句不要写到最后,放到(5)后面,还是会出现内核污染的提示。
        (2):对模块内的函数一般需要加上static关键字进行修饰,这样可防止模块外访问该函数,这是应该养成的一个好习惯。
        (3):printk函数相当于C标准库函数printf, KERN_ALERT是指的输出消息的优先级别。
        (4)(5):模块初始化和模块退出时有专门的函数,这个函数在2.4和2.6两种版本的内核有所区别。
    然后编写该程序的Makefile:
    # Makefile for hello.c
    obj-m:=hello.o
    KDIR:=/lib/modules/2.6.15-1.2054_FC5/build
    PWD:=$(shell pwd)
    default:
        $(MAKE) -C $(KDIR) M=$(PWD) modules
    .PHONY:clean
    clean:
        rm -f *.o *~ *.ko
    该Makefile为何这样写,可以参考相关资料,如我转载的《2.6驱动移植系列之Getting started(2)--模块编译》和在内核代码的/Documentation/kbuild目录下的makefile.txt这篇文档。简单解析下,$(MAKE) -C $(KDIR) M=$(PWD) modules命令首先改变目录到-C选项指定的位置(即内核源代码目录),其中保存有内核的顶层Makefile文件,因为build脚本会首先判断有无必要重新编译内核,所以如果需要先重新编译内核的话,编译过程会运行一段时间。M=选项让该Makefile在构造modules目标之前返回到模块源代码目录。然后,modules目标指向obj-m变量中设定的模块。
    有一点需要注意的,Makefile文件名一定要大写,不能写出makefile,否则在你make时会出现“没有规则可以创建目标。停止”类似的提示。
    执行make命令进行编译就行了, 执行完毕后,会生成几个文件:
    hello.ko
    hello.mod.c
    hello.mod.o
    hello.o
    注意:2.6内核的模块后缀名为.ko
    运行命令:
    #insmod hello.ko挂载成功,但看不到输出:Hello World!。
    然后再运行命令:
    #rmmod hello同样卸载成功但也看不到输出:Goodbye, cruel world!
    后来查看日志文件/var/log/messages,哈哈,原来输出到这里来了!后来查找原因,原来在GNOME环境(即图形界面)信息不会输出到终端,在在控制台下则可以看到输出信息。按换到控制台模式,以root身份登陆,再运行insmod hello.ko,果然看到输出。再按可以切换回GNOME环境。
    如果你在运行insmod hello.ko时出现以下提示:
    insmod: error inserting 'hello.ko': -1 Invalid module format
    可能的原因有:
        1。内核源代码树没有建立好。
        2。编译器的版本不对。可以查看内核文档中的Documentation/Changes文件列出的需要的工具版本。
        3。Makefile编写不对。
    核心模块与应用程序的对比
    内核模块与应用程序的不同之处有:
        1。大多数小规模及中规模应用程序是从头到尾执行单个任务,而模块只是预先注册自己以便服务于将来的某个请求,然后它的初始化函数就立即结束。
        2。应用程序在退出时,可以不管资源的释放或者其他的清除工作,但模块的退出却必须仔细撤销初始化函数所做的一切,否则,在系统重新引导之前某些东西就会残留在系统中。
        3。模块运行在所谓的内核空间里,而应用程序运行在所谓的用户空间中。
    用户空间和内核空间
    操作系统的作用是为应用程序提供一个对计算机硬件的一致视图,除此之外,还必须负责程序的独立操作并保护资源不受非法访问。
    这两种运行模式都有自己的内存映射,也即自己的地址空间。
    每当应用程序执行系统调用或者被硬件中断挂起时,linux将执行模式从用户空间切换到内核空间。而处理硬件中断的内核代码和进程是异步的,与任何一个特定的进程无关。
    模块化代码在内核空间中运行,用于扩展内核功能。通常来讲,一个驱动程序要执行两类任务:模块中的某些函数作为系统调用的一部分而执行,而其他函数则负责中断处理。
    当前进程
    内核代码可以通过访问全局项current来获得当前进程。current指针指向当前正在运行的进程。在open,read等系统调用的执行过程中,当前进程指的是调用这些系统调用的进程。
    与早期linux内核版本不同,2.6中current不再是全局变量。然而,设备驱动程序只要包含头文件即可以引用当前进程。
    编译模块
    实际上hello world的makefile的一个更容易的写法是:
    # 如果已定义KERNELRELEASE,则说明是从内核构造系统调用的。
    # 因此可以利用其内建语句
    ifneq ($(KERNELRELEASE),) 
        obj-m := hello.o
    # 否则是直接从命令行调用
    # 这时要调用内核构造系统
    else 
        KERNELDIR ?= /lib/modules/$(shell uname -r)/build 
        PWD := $(shell pwd) 
    default: 
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendif 
    KERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没
    有被定义,
    所以make将读取执行else之后的内容。如果make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C
    $(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD)
    表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去
    解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句,
    指明模块源码中各文件的依赖关系,以及要生成的目标模块名。
    (continue...)

转载于:https://www.cnblogs.com/dayuhope/p/3286481.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/460817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分析与构建根文件系统中的/lib目录

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。 由根文件系统的目录结构_天糊土的博客-CSDN博客可知,/lib目录在根文件系统中也是不能省略的。该目录存放着操作系统中的动态和静态链接库文件。我们构建/lib目录,主要工作是是…

优化小技巧——复杂属性对象的read模式

本帖最后由 Aone 于 2013-7-27 12:23 编辑想必Rectangle或者Point这样的数据类在我们的程序中特别是当前的游戏中是非常常用的类型。那么一些类中获取这些属性的时候为了封装,往往会写一个get函数return一个复制的Rectangle对象给外部。目的是为了防止被获取内部rec…

从零开始构建根文件系统

以下内容源于网络资源的学习与整理,如有侵权请告知删除。 参考博客 Uboot和系统移植(19)------- 根文件系统构建过程详解_big__C的博客-CSDN博客 一、总结 (1)本节在前面的理论分析的基础上,我们开始从零开…

Perl常用语法记录

Perl常用语法记录##包的切换和调用其它包的方式 #package A; #my $a10;#package B; #print $A::a; #print $a;##local局部标识符的使用 #$aa20; #{ # local $aa; # $aa10; # print "$aa \n"; # #}#print $aa;##别名的使用 comment $b10; $a1; $c200; {local *b;*b*a…

关于uboot的简介——uboot常用的命令

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。 linux终端设计有3种缓冲机制:无缓冲、行缓冲、全缓冲。 uboot提供类似linux终端的行缓冲命令行。当我们向终端命令行输入命令的时候,这些命令没有立即被系统识别&#xff0c…

网站分析

网网站分析(Web Analytics) 是种网站访客行为的研究。于商务应用背景来说,网站分析特别指的是来自某网站搜集来的资料之使用,以决定网站布局是否符合商业目标;例如,哪个登陆页面(landing page)比较容易刺激顾客购买欲。这些搜集来…

关于uboot的简介——uboot常见的环境变量

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。 如何理解环境变量呢?环境变量就好像程序的全局变量一样。程序中任何地方都可以根据需要去调用或者更改环境变量(一般都是调用),环境变量和全局变量不同…

奋战杭电ACM(DAY9)1013

Digital Roots #include <iostream> #include <string> using namespace std;int main() {string s;//溢出神烦哈&#xff01;int m,n,i;while(cin >> s){ m0;if(s[0]0) break;for(i0; s[i]!\0; i)ms[i]-0;//转换为int&#xff0c;巧妙&#xff01;n ((m%…

工作两个月的感受随笔

转眼之间&#xff0c;已经离毕业三个月了&#xff0c;在格力凌达工作了近两个月&#xff0c;在这边的主要感受有&#xff1a;两不会&#xff1a;这也不会&#xff0c;那也不会。经过两个月的工作&#xff0c;学习&#xff0c;努力的学习WMS&#xff0c;MES&#xff0c;GW等系统…

BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会 树形DP

[Usaco2010 Mar]gather 奶牛大集会 Bessie正在计划一年一度的奶牛大集会&#xff0c;来自全国各地的奶牛将来参加这一次集会。当然&#xff0c;她会选择最方便的地点来举办这次集会。每个奶牛居住在 N(1<N<100,000) 个农场中的一个&#xff0c;这些农场由N-1条道路连接&a…

关于uboot的简介——uboot对Flash与DDR的管理

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 1、uboot阶段对Flash的分区 所谓分区&#xff0c;即对存储设备进行分块管理。 PC机等产品中&#xff0c;整个硬盘由操作系统统一管理&#xff0c;其使用文件系统帮我们管理硬盘空间&#xff0c;从而…

EF部署

2019独角兽企业重金招聘Python工程师标准>>> 部署 当应用程序使用EF后&#xff0c;可以通过Visual Studio来进行部署&#xff0c;即将数据库部署到真实环境中&#xff0c;可以作为正式上线使用环境。在进行部署前&#xff0c;我们也需要先做一些先前准备工作&#x…

1837Balance

看了题解的&#xff0c;有个高手跟我说这道题目要用到dp统计&#xff0c;把原点偏移&#xff0c;即把不能表示的部分移到能够表示的区域。这个想法可能是用在-7500那里 我的一开始的想法是dp[i][j] 其中i表示i码&#xff0c;j表示j钩&#xff0c;dp表示是否平衡&#xff0c;但…

uboot源码——根目录下的Makefile文件分析

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 uboot来源于uboot官网&#xff0c;或者SoC官方&#xff08;研发s5pv210这款芯片的公司推出的开发板叫SMDKV210&#xff09;&#xff0c;或者具体开发板的官方&#xff08;深圳市九鼎科技公司推出的…

linux(虚拟机中)与windows共享文件两种方法

Windows 下用 SourceInsight 与 Linux 协作编码习惯了用SourceInsight 读写代码&#xff0c;在Linux下一时没找到类似的工具&#xff0c;vi的操作也不熟&#xff0c;偶尔看看或小改动代码还行&#xff0c;项目一大就感觉就力不从心了&#xff1b;所以还是准备采用Windows下进行…

资源共享型智能指针实现方式

【1】资源共享型智能指针实现方式简述 资源共享型的智能指针有两种实现方式&#xff1a;一种是侵入式&#xff1b;一种是非侵入式。 网上以及书籍比较常见的是非侵入式的&#xff0c;它的实现完全放在智能指针模板类内。 模板类有一个用于保存资源类对象的指针变量和一个用于记…

uboot源码——根目录下的mkconfig文件分析

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、/mkconfig脚本概览 在uboot的根目录下执行“make x210_sd_config”进行配置时&#xff0c;x210_sd_config是目标。在主Makefile中2589行有如下代码。 x210_sd_config : unconfig$(MKCONFIG) …

springside 参考地址

2019独角兽企业重金招聘Python工程师标准>>> http://blog.csdn.net/wind520/article/details/8917944 http://blog.chinaunix.net/uid-122937-id-3935052.html 转载于:https://my.oschina.net/china008/blog/330265

虚拟机下安装vmtool

Ubuntu 12.04下安装VMware Tools 安装前准备&#xff1a; 1、一定要先安装 build-essential 软件,否则不能够顺利安装 命令&#xff1a;sudo apt-get install build-essential 2、要安装linux-headers 包&#xff0c;这个包要在配置VMware-tools之前装&#xff0c;即可…

linux实例 批量修改图片文件名

1、如10.11一批这样的目录&#xff0c;10.11 10.12等等 然后里面的图片.jpg文件要修改成对应的日期.jpg&#xff0c;也就是说 编程1011.jpg这样的文件名 示例如下&#xff1a; #!/bin/bashfor filename in lsdoecho $filenamecd $filenamefile1${filename%%.*}file2${filename…