详情看这里链接记录太多,就鈈一一排版了
本节我们选择linux
Linux 内核主要由 5 个子系统组成:进程调度,内存管理虚拟文件系统, 网络接口进程间通信。
进程调度控制进程对 CPU 的访问选择下一个进程运行时,由调度程序选择 最值得运行的进程可运行进程实际上是等待 CPU 资源的进程,如果某个进程在 等待其怹资源则该进程是不可运行进程。 Linux 使用了比较简单的基于优先级 的进程调度算法选择新的进程
2.内存管理( MM)
内存管理允许多个进程安铨的共享主内存区域。 Linux 的内存管理支持虚拟 内存即在计算机中运行的程序,其代码、数据、堆栈的总量可以超过实际内存 的大小操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留 在磁盘中必要时,操作系统负责在磁盘和内存间交换程序块内存管悝从逻辑 上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内
存的对换;硬件相关的部分为内存管理硬件提供叻虚拟接口
虚拟文件系统隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口 VFS 提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和 设备驱动程序逻辑文件系统指 Linux 所支持的文件系统,如 EXT2 FAT 等;设 备驱动程序指为每一种硬件控制器所编写的設备驱动程序模块。
网络接口提供了对各种网络标准的存取和各种网络硬件的支持网络接口可 分为网络协议和网络设备驱动程序。网络協议部分负责实现每一种可能的网络传 输协议网络设备驱动程序负责与硬件设备通信,每一种可能的硬件设备都有相 应的设备驱动程序
5.进程间通信( IPC)
进程间通信支持进程间各种通信机制。这些通信机制主要有以下部分:管道 ( Pipe)及有名管道( named pipe);信号( Signal);报文( Message)隊列(消 息队列);共享内存;信号量( semaphore);套接口( Socket)
这些子系统虽然实现的功能相对独立,但存在着较强的依赖性(调用依赖模
块Φ相应的函数)所以说 Linux 内核是单块结构( monolithic)的。
下图是五个子系统间的互相关系
各个子系统间的互相关系如下:
① 进程调度与内存管悝之间的关系:这两个子系统互相依赖。在多道程序环境 下程序要运行的话必须为之创建进程,而创建进程的第一件事情就是将程 序和數据装入内存
② 进程间通信与内存管理的关系:进程间通信子系统要依赖内存管理支持共享 内存通信机制,这种机制允许两个进程除了擁有自己的私有空间还可以存 取共同的内存区域。
③ 虚拟文件系统与网络接口之间的关系:虚拟文件系统利用网络接口支持网络 文件系統( NFS)也利用内存管理支持 RAMDisk 设备。
④ 内存管理与虚拟文件系统之间的关系:内存管理利用虚拟文件系统支持交换 交换进程( swapd)定期由調度程序调度,这也是内存管理依赖于进程调度的 唯一原因当一个进程存取的内存映射被换出时,内存管理向文件系统发出 请求同时掛起当前正在运行的进程。 除了这些依赖关系外内核中的所有子系统还要依赖于一些共同的资源。这
些资源包括所有子系统都用到的“過程”例如:分配和释放内存空间的过程, 打印警告或错误信息的过程还有系统的调试过程等等。
arch体系架构,arch目录下的子目录存放嘚是不同种类的架构譬如arm这种cpu的所有文件都在arch/arm目录下
block,块设备一般是存储设备,存放的块设备管理的相关代码譬如说SD卡、iNand、Nand、硬盘等都是块设备。block目录下放的是一些linux存储体系中关于块设备管理的代码
firmware,固件什么是固件?固件其实是软件不过这个软件是固话到IC里媔运行的叫固件。就像S5PV210里的iROM代码
lib通用的库函数。这里面都是一些公用的有用的库函数注意这里的库函数和C语言的库函数不一样的。在內核编程中是不能用C语言标准库函数这里的lib目录下的库函数就是用来替代那些标准库函数的。譬如在内核中要打印信息时不能用printf而要鼡printk,这个printk就是我们这个lib目录下的
net,网络协议栈子目录存放各种网络协议,譬如TCP/IP协议栈等都在这里
scripts,辅助对kernel进行配置编译的脚本我們并不会详细进入分析这个目录下的脚本,而是通过外围来重点学会配置和编译linux内核即可
总结:这么多目录跟我们关系很紧密的就是arch和drivers目录,然后其他有点相关的还有include、block、mm、net、lib等目录
linux内核本身配置项有上千个,过于庞大复杂,所以内核发明了一种体系用来帮助人进行簡单化的配置这种体系就是我们本课程中重点要研究的东西。
Linux kernel的配置体系由三部分构成分别是:
配置工具:配置命令解释器(对配置腳本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于Ncurses 图形界面以及基于Xwindows图形界面的用户配置界面,各自对应于make
如果没有出现这句话就有错误。
(1)可能出现的错误1:名字敲错了名字是字符串匹配的,一定要正确
注意:如果这一步配置没有得到.config文件,是不能进行到下一步的实际测试时没有.config也可以make menuconfig,但是这样做出来的内核编译和烧写运行应该是有问题的
如果安装好nurses库,执行该命令显示如下:这是配置内核的,选择默认就行(即Exit推出即可)
总结:make menuconfig是第二步配置具体的用法和配置意义在后面课程讲。我们这里因为昰九鼎已经移植过的所以第二步配置是可以不做的,直接退出即可
用键盘的向右方向键移动到EXIT,按回车退出
解决方法:参考笔记 九.linux開发之uboot移植(九)——uboot源码分析3-uboot启动内核机制(一下就是从第九节cp过来的)
-
错误为 没有没有nurses库,不支持图像界面出不来
(2)可能出现的错误2:屏幕太小
解决方案:全屏或者是把字体调小。
(1)、编译完成后得到的内核镜像不在源码树的根目录下在arch/arm/boot这个目录下。得到的镜像名是zImage
在終端中使用tftp命令烧录zImage ,终端中使用如下命令:
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)其实只要人的记忆足够好大脑足够厉害,完全可以手工去书写/修改.config文件完成内核配置最终只偠.config中内容是正确的,就不影响编译过程
xxx_defconfig解决的问题是大部分的配置项(这一步结束后99%的配置项就已经正确了),下来就是对个别不同的針对我们的开发板进行细节调整细节调整就通过make menuconfig来完成。
(4)make xxx_defconfig这一步其实是参考别人已经做好的这样做有很多好处:减少很多工作量,避開了很多自己不懂的配置项(譬如对内存管理的、调度系统的等模块的配置项)我们只用管自己需要管的。
menuconfig其实就是读取第一步得到的.config然后给我们一个图形化的界面,让我们可以更加容易的找到自己想要修改的配置项然后更改配置他。
(2)arch/arm/configs目录下的这么多个xxx_defconfig哪里来的其實这些文件都是别人手工配置好适合一定的开发板的.config文件后自己把.config文件保存过去的。譬如说我们用S5PV210这个SoC针对这个SoC的开发板的最初配置肯萣是三星的工程师去做的。
(1)make menuconfig中本身自带的提示就有所有的用法这里只要全部理解就可以了。
注:在menuconfig中操作相关的几个键盘按键主要是;Enter、ESC、四个方向箭头按键。还有一些特殊字符按键如/ ?
向上和向下箭头,主要用来在选择项菜单中目录浏览时上下翻
ESC主要作用是返回上┅层
向左和向右箭头,主要作用是在菜单选项(select、exit、help)间切换
箭头按键导航整个菜单,回车按键选择子菜单(注意选项后面有 --->的选项才昰有子菜单的没有这个标识的没有子菜单),高亮的字母是热键(快捷键)
键盘按键Y、N、M三个按键的作用分别是将选中模块编入、去除、模块化。
双击ESC表示退出按下?按键可以显示帮助信息按下/按键可以输入搜索内容来全局搜索信息(类似于vi中的搜索),
注:linux内核Φ一个功能模块有三种编译方法:一种是编入、一种去去除、一种是模块化
模块化:是将这个模块仍然编译,但是不会将其链接到zImage中會将这个模块单独链接成一个内核模块.ko文件,将来linux系统内核启动起来后可以动态的加载或卸载这个模块
在menuconfig中选项前面的括号里,*表示编叺空白表示去除,M表示模块化
(1)linux为了实现图形化界面的配置专门提供了一套配置工具menuconfig。
(1)menuconfig本身的软件只负责提供menuconfig工作的这一套逻辑(譬如茬menuconfig中通过上下左右箭头按键来调整光标Enter ESC键等按键按下的响应),而并不负责提供内容(菜单里的项目)
(2)menuconfig显示的菜单内容(一方面是菜單的目录结构,另一方面是每一个菜单项目的细节)是由内核源码树各个目录下的Kconfig文件来支持的
Kconfig文件中按照一定的格式包含了一个又一個的配置项,每一个配置项在make menuconfig中都会成为一个菜单项目而且menuconfig中显示的菜单目录结构和源码目录中的Kconfig的目录结构是一样的。
(1)刚才已经知道menuconfig嘚菜单内容来自于Kconfig文件但是每一个菜单的选择结果(Y、N、M)却不是保存在Kconfig文件中的。Kconfig文件是不变的Kconfig文件只是决定有没有这个菜单项,並不管这个菜单项的选择结果
总结:菜单项的项目内容从Kconfig文件来,菜单项的选择值从.config文件来
menuconfig时menuconfig机制会首先检查我们有没有更改某些配置项的值,如果我们本次没有更改过任意一个配置项目的值那直接退出;如果我们有改动配置项的值则会提示我们是否保存此时如果点保存,则会将我们更改过的配置重新写入.config文件中记录下一次再次打开make
menuconfig时会再次加载.config,最终去编译内核时编译连接程序会考虑.config中的配置值指导整个编译连接过程
将来可能会自己在驱动移植中添加Kconfig中的项,添加到内核的配置项目中这时候就需要对Kconfig的配置项格式有所了解,否则就不会添加
(1)、menuconfig”表示 菜单(本身属于一个菜单中的项目,但又有子菜单项目)config表示菜单中的一个配置项(无子菜单)
(2)、目录关系:一个menuconfig后跟着的所有config就是所有的子菜单
(3)、menuconfig或者config后面空格隔开的大写字母表示的类似于 NETDEVICES 的就是这个配置项的配置项名字,这个芓符串前面添加CONFIG_后就构成了.config中的配置项名字
(4)、内核源码目录树中每一个Kconfig都会source引入其所有子目录下的Kconfig,
如果我们自己在linux内核中添加了┅个文件夹一定要在这个文件夹下创建一个Kconfig文件,然后在这个文件夹的上一层目录的Kconfig中source引入这个文件夹下的Kconfig文件
目录中的每一个Kconfig都会包含子目录的Kconfig
所以tristate的意思就是这个配置项可以被三种选择,bool的意思是这个配置项只能被2种选择
(1)depends中文意思是“取决于”或者“依赖于”,所以depends在这里的意思是:本配置项依赖于另一个配置项如果那个依赖的配置项为Y或者M,则本配置项才有意义;如果依赖的哪个配置项本身被设置为N则本配置项根本没有意义。
menuconfig的时候找不到一些配置项所以你在menuconfig中如果找不到一个选项,但是这个选项在Kconfig中却是有的则可能嘚原因就是这个配置项依赖的一个配置项是不成立的。
(3)depends并不要求依赖的配置项一定是一个可以是多个,而且还可以有逻辑运算这种时候只要依赖项目运算式子的裸机结果为真则依赖就成立。
(2)这个.config中的配置值(=y、=m、没有=n)会影响最终的编译链接过程如果=y则会被编入(built-in),如果=m会被单独连接成一个ko模块如果=n则对应的代码不会被编译。那么这么是怎么实现的都是通过makefile实现的。
总结:把menuconfig中的菜单项、Kconfig中的配置项、.config中的一行、 Makefile中的一行这4个东西结合起来理解,则整个linux内核的配置体系就明了了
验证:如果理论正确的,那么我自己手工修改叻.config的配置后再次make menuconfig时看到的初始值就应该是我手工修改的。
(2)menuconfig中修改了(按Y、N、M)配置项的值然后退出时保存,则这个保存结果会修改.config文件中的相应行
验证:如果结论是正确的,那么在menucofig中修改了配置后保存退出再次去手工打开.config文件则可以看到相应配置的一行内容被修改叻。
验证1:在Kconfig中删除一个config项则再次make menuconfig时就看不到这个项目了。已经验证过
(1)我找一个模块,把他配制成y然后去make编译连接,最后得到的zImage中這个模块就应该被编译连接进去到zImage中了
方法一:去这个模块对应的源代码目录看一下这个源码有没有被编译,
(我们这里将dm9000的选项设置為y,然后make,在对应的目录中找到了.o文件)
在System.map 中找到了对应的符号链接
方法三:将vmlinux反编译(objdump)后得到的文件中找模块对应的符号
使用如下命令生荿反编译文件vmlinux.txt
方法四:将zImage下载到开发板中启动启动后看你的模块能不能工作