十六.linux开发之Kernel移植——内核的配置和编译原理

版权声明:本文为博主原创文章,允许转载请注明。谢谢! https://blog.csdn.net/wangweijundeqq/article/details/82391008

有道云笔记地址:

详情看这里链接,记录太多,就不一一排版了。

http://note.youdao.com/noteshare?id=d25dbce79566963e3699574a74048154&sub=D0E2BC043B5B415C840A3A2FB393376F

 

本节我们选择linux 2.6.35.7版本kernel进行实践。使用的是九鼎X210的移植版本

一.linux内核源码目录结构

     Kbuild,Kernel Build,管理内核编译的文件

     Makefile,kernel工程的Makefile。

     mk,是九鼎在移植时自己添加的,不是linux内核本身的东西

     arch,体系架构,arch目录下的子目录存放的是不同种类的架构。譬如arm这种cpu的所有文件都在arch/arm目录下

     block,块设备,一般是存储设备,存放的块设备管理的相关代码。譬如说SD卡、iNand、Nand、硬盘等都是块设备。block目录下放的是一些linux存储体系中关于块设备管理的代码。

     crypto,加密相关,存放加密算法实现代码

     Documentation,说明文档

     drivers,设备驱动模块,存放各种设备类型驱动模块源代码

     firmware,固件。什么是固件?固件其实是软件,不过这个软件是固话到IC里面运行的叫固件。就像S5PV210里的iROM代码

     fs,文件系统,里面列出了linux支持的各种文件系统的实现。

     include,头文件,子目录存放通用的各种模块的头文件

     init,kernel启动时初始化的代码

     ipc,进程间通信机制的代码

     kernel,kernel内核本身需要的代码

    lib,通用的库函数。这里面都是一些公用的有用的库函数,注意这里的库函数和C语言的库函数不一样的。在内核编程中是不能用C语言标准库函数,这里的lib目录下的库函数就是用来替代那些标准库函数的。譬如在内核中要打印信息时不能用printf,而要用printk,这个printk就是我们这个lib目录下的。

    mm,mm是memory management,内存管理。linux的内存管理代码都在这里

    net,网络协议栈,子目录存放各种网络协议,譬如TCP/IP协议栈等都在这里。

    scripts,辅助对kernel进行配置编译的脚本。我们并不会详细进入分析这个目录下的脚本,而是通过外围来重点学会配置和编译linux内核即可。

    security,kernel安全机制相关的代码

    sound,音频相关的代码

    tools,linux常用工具相关

    usr,kernel启动相关,暂时不用管

    virt,虚拟机相关

总结:这么多目录跟我们关系很紧密的就是arch和drivers目录,然后其他有点相关的还有include、block、mm、net、lib等目录。

二、kernel的配置体系

linux内核本身配置项有上千个,过于庞大复杂,,所以内核发明了一种体系用来帮助人进行简单化的配置。这种体系就是我们本课程中重点要研究的东西。

Linux kernel的配置体系由三部分构成,分别是:

    Makefile分布在 Linux 内核源代码根目录及各层目录中,定义Linux kernel的编译规则,依据.config中定义的CONFIG_xxxx=xxxxx确定xxx以何种方式编译进kernel。

    Kconfig配置选项的文件,各个子目录下的Kconfig定义了子目录的功能模块的配置选项。

    配置工具:配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于Ncurses 图形界面以及基于Xwindows图形界面的用户配置界面,各自对应于make config、make menuconfig和make xconfig)。通过对配置工具选项进行配置后生成配置文件.config,.config文件决定Kconfig中的配置项是否编译进入kernel。

三、内核配置和编译体验

1.将九鼎X210kernel安装包拷贝到ubuntu中,解压后先make distclean 清理一遍,防止出现莫名其妙的错误

2、先确认Makefile

(1)主要是检查交叉编译工具链有没有设置对。CROSS_COMPILE   ?= /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-

(2)确认ARCH = arm。主要目的是为了编译时能找到arch/arm目录。

3、执行make x210ii_qt_defconfig命令

(1)最后只要出现:configuration written to .config这句话,就证明我们的操作是正确的。

如果没有出现这句话,就有错误。

(1)可能出现的错误1:名字敲错了。名字是字符串匹配的,一定要正确。

注意:如果这一步配置没有得到.config文件,是不能进行到下一步的。实际测试时没有.config也可以make menuconfig,但是这样做出来的内核编译和烧写运行应该是有问题的。

4.、执行make menuconfig

如果安装好nurses库,执行该命令,显示如下:这是配置内核的,选择默认就行(即Exit推出即可)

总结:make menuconfig是第二步配置,具体的用法和配置意义在后面课程讲。我们这里因为是九鼎已经移植过的,所以第二步配置是可以不做的,直接退出即可。

用键盘的向右方向键移动到EXIT,按回车退出。

(1)可能出现的错误1:ncurses库没装

解决方法:参考笔记  九.linux开发之uboot移植(九)——uboot源码分析3-uboot启动内核机制(一下就是从第九节cp过来的)

  1. 错误为 没有没有nurses库,不支持图像界面出不来

需要ubuntu安装nurses库

参考:https://blog.csdn.net/mingtianwendy/article/details/51328562

输入命令:sudo apt-get install libncurses5-dev,即可解决

(2)可能出现的错误2:屏幕太小

错误信息:

Your display is too small to run Menuconfig!

It must be at least 19 lines by 80 columns.

解决方案:全屏,或者是把字体调小。

5.、执行make

(1)编译完成后得到的内核镜像不在源码树的根目录下,在arch/arm/boot这个目录下。得到的镜像名是zImage

(2)、拷贝到/tftpboot/目录下,使用tftp下载zImage到开发板

在终端中使用tftp命令烧录zImage ,终端中使用如下命令:

tftp 30008000 zImage

bootm 30008000

四、内核的配置原理

1、配置的关键是得到.config文件

(1).config以.开头,是一个隐藏文件,因此平时是看不到的,需要ls -a来看

(2)当我们make distclean后(也就是说默认情况下)是没有.config文件的,我们配置的两步过程就是为了得到内容合适的.config文件

(3).config文件是linux内核在编译过程中很重要的一个文件,其作用类似与uboot中的include/configs/x210_sd.h,内核在编译过程中会读取.config中的配置项,并且用这些配置项去指导整个编译链接过程。

(4).config文件的格式类似于脚本文件,其中内容类似于:CONFIG_ARM=y的一个一个的配置项。这些配置项就类似于脚本文件中定义的一个一个变量,所以这一行可以被理解为定义了一个变量CONFIG_ARM,这个变量的值为y。

(5).config文件中每一行都是一个配置项,从.config文件的规模可以看出linux内核的可配置项有两三千个。所以linux内核是高度可配置的,而且linux内核的所有配置项很难全部搞明白。因为linux内核的配置项太多太繁杂超出了人的大脑能够记忆和处理的数量级,因此linux内核不像uboot那样直接手工配置,而是发明了一个图形化的配置工具menuconfig。

2、make xx_defconfig和make menuconfig相配合

      (1)我们为了对.config文件中的两三千个配置项做逐一合适的配置,专门发明了两步结合的配置方式。

(2)其实只要人的记忆足够好,大脑足够厉害,完全可以手工去书写/修改.config文件完成内核配置,最终只要.config中内容是正确的,就不影响编译过程。

       (3)第一步:make xxx_defconfig解决的问题是大部分的配置项(这一步结束后99%的配置项就已经正确了),下来就是对个别不同的针对我们的开发板进行细节调整,细节调整就通过make menuconfig来完成。

(4)make xxx_defconfig这一步其实是参考别人已经做好的,这样做有很多好处:减少很多工作量,避开了很多自己不懂的配置项(譬如对内存管理的、调度系统的等模块的配置项),我们只用管自己需要管的。

       (5)make menuconfig其实就是读取第一步得到的.config,然后给我们一个图形化的界面,让我们可以更加容易的找到自己想要修改的配置项,然后更改配置他。

3、make xx_defconfig到底做了什么?

      (1)make x210ii_qt_defconfig其实相当于:

cp arch/arm/configs/x210ii_qt_defconfig .config

(2)arch/arm/configs目录下的这么多个xxx_defconfig哪里来的?其实这些文件都是别人手工配置好适合一定的开发板的.config文件后自己把.config文件保存过去的。譬如说我们用S5PV210这个SoC,针对这个SoC的开发板的最初配置肯定是三星的工程师去做的。

五、menuconfig的使用和演示

make menuconfig (基于文本菜单的配置界面,需要安装ncurse)

1、使用说明解释

(1)make  menuconfig中本身自带的提示就有所有的用法,这里只要全部理解就可以了。

注:在menuconfig中操作相关的几个键盘按键,主要是;Enter、ESC、四个方向箭头按键。还有一些特殊字符按键,如/  ?

向上和向下箭头,主要用来在选择项菜单中目录浏览时上下翻

回车,主要作用是选中并且执行select/exit/help。

ESC,主要作用是返回上一层

向左和向右箭头,主要作用是在菜单选项(select、exit、help)间切换。

(2)用法翻译:

箭头按键导航整个菜单,回车按键选择子菜单(注意选项后面有 --->的选项才是有子菜单的,没有这个标识的没有子菜单),高亮的字母是热键(快捷键),

键盘按键Y、N、M三个按键的作用分别是将选中模块编入、去除、模块化

双击ESC表示退出,按下?按键可以显示帮助信息,按下/按键可以输入搜索内容来全局搜索信息(类似于vi中的搜索),

[  ]不可以模块化,<>的才可以模块化。

注:linux内核中一个功能模块有三种编译方法:一种是编入、一种去去除、一种是模块化。

    编入:  就是将这个模块的代码直接编译连接到zImage中去

   去除:   就是将这个模块不编译链接到zImage中,

   模块化:是将这个模块仍然编译,但是不会将其链接到zImage中,会将这个模块单独链接成一个内核模块.ko文件,将来linux系统内核启动起来后可以动态的加载或卸载这个模块。

在menuconfig中选项前面的括号里,*表示编入,空白表示去除,M表示模块化

六.menuconfig的工作原理

1、menuconfig本身由一套软件支持

(1)linux为了实现图形化界面的配置,专门提供了一套配置工具menuconfig。

(2)ncurses库是linux中用来实现文字式的图形界面,linux内核中使用了ncurses库来提供menuconfig

(3)scripts\kconfig\lxdialog目录下的一些c文件就是用来提供menuconfig的那些程序源代码。

2、menuconfig读取Kconfig文件

(1)menuconfig本身的软件只负责提供menuconfig工作的这一套逻辑(譬如在menuconfig中通过上下左右箭头按键来调整光标,Enter ESC键等按键按下的响应),而并不负责提供内容(菜单里的项目)。

(2)menuconfig显示的菜单内容(一方面是菜单的目录结构,另一方面是每一个菜单项目的细节)是由内核源码树各个目录下的Kconfig文件来支持的

Kconfig文件中按照一定的格式包含了一个又一个的配置项,每一个配置项在make menuconfig中都会成为一个菜单项目。而且menuconfig中显示的菜单目录结构和源码目录中的Kconfig的目录结构是一样的。

(3)在相应的Kconfig文件中删除一个config项,则再次make menuconfig时这个项目已经看不到了。

3、menuconfig读取/写入.config文件

(1)刚才已经知道menuconfig的菜单内容来自于Kconfig文件,但是每一个菜单的选择结果(Y、N、M)却不是保存在Kconfig文件中的。Kconfig文件是不变的,Kconfig文件只是决定有没有这个菜单项,并不管这个菜单项的选择结果。

(2)menuconfig工作时在我们make menuconfig打开时,他会读取.config文件,并且用.config文件中的配置选择结果来初始化menuconfig中各个菜单项的选择值。

总结:菜单项的项目内容从Kconfig文件来,菜单项的选择值从.config文件来

(3)当我们每次退出make menuconfig时,menuconfig机制会首先检查我们有没有更改某些配置项的值,如果我们本次没有更改过任意一个配置项目的值那直接退出;如果我们有改动配置项的值则会提示我们是否保存。此时如果点保存,则会将我们更改过的配置重新写入.config文件中记录,下一次再次打开make menuconfig时会再次加载.config,最终去编译内核时编译连接程序会考虑.config中的配置值指导整个编译连接过程。

总结:本节课主要内容就是讲:menuconfig和Kconfig和.config的关系。

七.Kconfig文件详解

将来可能会自己在驱动移植中添加Kconfig中的项,添加到内核的配置项目中。这时候就需要对Kconfig的配置项格式有所了解,否则就不会添加。

1、Kconfig的格式

(1)、menuconfig”表示 菜单(本身属于一个菜单中的项目,但又有子菜单项目),config表示菜单中的一个配置项(无子菜单) 

(2)、目录关系:一个menuconfig后跟着的所有config就是所有的子菜单

(3)、menuconfig或者config后面空格隔开的大写字母表示的类似于 NETDEVICES 的就是这个配置项的配置项名字,这个字符串前面添加CONFIG_后就构成了.config中的配置项名字。

menuconfig NETDEVICES

default y if UML

depends on NET

bool "Network device support"

---help---

You can say N here if you don't intend to connect your Linux box to

any other computer at all.

(4)、内核源码目录树中每一个Kconfig都会source引入其所有子目录下的Kconfig,

如果我们自己在linux内核中添加了一个文件夹,一定要在这个文件夹下创建一个Kconfig文件,然后在这个文件夹的上一层目录的Kconfig中source引入这个文件夹下的Kconfig文件。

source “xx/xxx/Kconfig” 引入其他的Kconfig             目录中的每一个Kconfig都会包含子目录的Kconfig

例如:

(5)、tristate “三态”,对应Y/N/M 

           bool “布尔”,对应Y/N

所以tristate的意思就是这个配置项可以被三种选择,bool的意思是这个配置项只能被2种选择。

2、depends的含义

(1)depends中文意思是“取决于”或者“依赖于”,所以depends在这里的意思是:本配置项依赖于另一个配置项。如果那个依赖的配置项为Y或者M,则本配置项才有意义;如果依赖的哪个配置项本身被设置为N,则本配置项根本没有意义。

(2)depends项目会导致make menuconfig的时候找不到一些配置项。所以你在menuconfig中如果找不到一个选项,但是这个选项在Kconfig中却是有的,则可能的原因就是这个配置项依赖的一个配置项是不成立的。

(3)depends并不要求依赖的配置项一定是一个,可以是多个,而且还可以有逻辑运算。这种时候只要依赖项目运算式子的裸机结果为真则依赖就成立。

3、Kconfig和.config文件和Makefile三者的关联

(1)配置项被配置成Y、N、M会影响.config文件中的CONFIG_XXX变量的配置值。

(2)这个.config中的配置值(=y、=m没有=n)会影响最终的编译链接过程。如果=y则会被编入(built-in),如果=m会被单独连接成一个ko模块,如果=n则对应的代码不会被编译。那么这么是怎么实现的?都是通过makefile实现的。

(3)obj-$(CONFIG_DM9000) += dm9000.o

如果CONFIG_DM9000变量值为y,则obj += dm9000.o,因此dm9000.c会被编译;如果CONFIG_DM9000变量未定义,则dm9000.c不会被编译。如果CONFIG_DM9000变量的值为m则会被连接成ko模块(这个是在linux内核的Makefile中定义的规则)

总结:把menuconfig中的菜单项、Kconfig中的配置项、.config中的一行、 Makefile中的一行,这4个东西结合起来理解,则整个linux内核的配置体系就明了了。

八.menuconfig的实验学习思路

1、验证menuconfig和.config的关系

(1)make menuconfig时,会读取.config中的配置值来初始化menuconfig中的配置项。

验证:如果理论正确的,那么我自己手工修改了.config的配置后,再次make menuconfig时看到的初始值就应该是我手工修改的。

(2)menuconfig中修改了(按Y、N、M)配置项的值,然后退出时保存,则这个保存结果会修改.config文件中的相应行。

验证:如果结论是正确的,那么在menucofig中修改了配置后保存退出,再次去手工打开.config文件则可以看到相应配置的一行内容被修改了。

2、验证menuconfig和Kconfig的关系

(1)menuconfig读取Kconfig的内容作为菜单项目内容。

验证1:在Kconfig中删除一个config项,则再次make menuconfig时就看不到这个项目了。已经验证过。

验证2:在Kconfig中自己添加创建一个config项,则再次make menuconfig时就能看到多了一个项目。(这里我们以DM9000为例添加,DM9000的Kconfig目录为:drivers/net/Kconfig

)

3、验证验证menuconfig和Makefile的关系

(1)我找一个模块,把他配制成y,然后去make编译连接,最后得到的zImage中这个模块就应该被编译连接进去到zImage中了。

验证:

方法一:去这个模块对应的源代码目录看一下这个源码有没有被编译,

(我们这里将dm9000的选项设置为y,然后make,在对应的目录中找到了.o文件)

方法二:去zImage对应的elf格式的vmlinux中查看符号

在System.map 中找到了对应的符号链接

方法三:将vmlinux反编译(objdump)后得到的文件中找模块对应的符号

使用如下命令生成反编译文件vmlinux.txt

 /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-objdump  -D vmlinux > vmlinux.txt

打开vmlinux.txt,搜素到了dm9000

方法四:将zImage下载到开发板中启动,启动后看你的模块能不能工作

猜你喜欢

转载自blog.csdn.net/wangweijundeqq/article/details/82391008