Advertisement

Linux内核-内核配置

阅读量:

Linux内核特性 :

1.可移植性 , 支持的硬件平台广泛

arch目录 就是体系结构的概念 , 针对我们现目前有的一些 平台,

注意ARM里面的源码跟X86里面的源码, 不能共同编译, 需要不同的编译器 ,,

支持这么多平台, 我们怎么让你只编译ARM而不编译其他平台的呢 ?

进入ARM文件里.我们可以看到所支持的所有的开发板型号,

内核就像一个仓库, 我们从中选择我们所需要的就可以了,

2.超强得网络功能 :

大型得路由器防火墙, 很多功能都是在Liunx基础上去研发和设置得, 它得网络功能非常非常强大,

TCP/IP 等都已经实现好了,对一个产品得开发周期是大大可以缩短得,

如果你不跑操作系统,那就需要你自己写, 如果你跑操作系统, 那就表示拥有了成熟得代码帮我们去处理, 用不用操作系统其实不是一个很大的问题, 就看你的产品适用点 .

3. 模块化的设计 :

通过模块来帮助辅助我们来进行我们驱动程序的开发 , 这是我们认为Linux 内核的一个特性

Linux内核提供的 五大子系统 :

进程管理子系统 内存管理子系统 文件管理子系统 网络协议子系统 设备管理子系统

内核是一个很多很多子系统来融合的一个中和系统 , 我们学习内核也一样, 先掌握一个最基本的系统, 然后通过这个系统,会跟其他系统都有些联系 ,那么我们可以把其他系统 一步一步的去理解,

我们会对设备管理子系统做一个更深入的理解, 作为驱动开发工程师就足够了, , 如果涉及到网络协议栈, 比如新的网络协议的话,那么专门的有些公司或做这个网络协议层 , 做专门的研究,.

如何获取内核 :

获取内核在工作中有两种方法 :

第一种 : 干脆直接从官方网站上去获取,

第二种 : 工作中 公司在定好一个方案之后, 选择一些硬件方案, 比如我们要做一些智能的设备, 芯片厂商会针对芯片厂提供demo 板,如果demo板上跑的是linux系统的话, 厂商已经制定好的linux的源码包, 然后直接在这个板上添加设备,添加设备过程中你就有可能会涉及一个重新编译一下源码 . 然后再进行一个修改 .很多可能都是通过芯片源码产生的

那么如何从官方下载的内核 编程成你demo板所需要的内核 ,

新手先从芯片厂商提供的linux上面去学, 如果有经验了再做官方发布的源码 再一步一步的修改成我们所需要的Liunx

下载地址 : https://mirrors.edge.kernel.org/pub/linux/kernel

然后找到 3.x点进去, 找linux_3.0.8.tar bz2 得包 , 下载bz2得就行

Linux 目录结构

把下载好的linux_3.0.8.tar.bz2 把它解压

tar -jxvf linux_3.0.8.tar.bz2 -C /work/maiziedu/进行解压到指定目录,

然后解压后, 我们进入到 linux_3.0.8目录下

arch 所有体系相关得所有代码都在这个仓库里,

block 块 算法得一些目录

crypto 算法加密目录

Documentation 内核得官方文档

drivers 下可加驱动 所有得驱动程序

firmware 部件

fs 存放得都是文件系统得一些信息

include 内核使用得头文件

init 系统初始化得目录

ipc 进程间通讯得一些机制 (信号量 ,消息队列,共享内存等等)

kbuild kconfig 带k得一般都可以认为是kernel得一些东西 , kbuild kernel得一些编译方法, kconfig kerner的config

kerner 内核中的一些核心算法 ,

mm 内存

net 网络的一些协议

我们进到arch 会看到很多平台文件, 我们进入到x86文件里, 可以看到 它里面又包含boot include kerner lib等文件, 有个问题 x86底下也有kerner也有lib 那我们的内核顶层目录下也有lib 也有kerner 所以我们就会发现这俩个是重名的, 我们思考一下这种分层 , 内核的kerner是于平台无关的, 所以内核都遵循的机制, 但是这套机制肯定要落实到于体系结构相关的代码上 . 最终你还是要在相应的硬件上运行, 我们可以理解到, 平台无关的这个kerner最终还是要依赖于平台相关的这个kerner , 最后系统启动的肯定是平台相关的kerner和平台相关的kerner互相之间的内部调度, 平台无关性的东西要依赖于平台相关性的东西,

我们可以认为平台无关的代码是一个主框架, 而框架中最终还是要要运行在平台相关性的代码 , 所以在以后的代码中,要确认它是在平台无关的代码还是平台相关的代码,

我们进入arm 目录

它的特点跟x86不太一样, x86是inter公司一家的 ,但是arm 并不是芯片, 它只是一个ip核, 最终来说是会被芯片厂商使用起来的, 所以说拥有arm芯片ip核的这个厂商特别多, 比如说三星 , 它就会研究出s3c2410 s3c2412 s5pv210 等其他高端产品, 的开发板

mach-xxx 称之为板子 区别大的东西

plat-xxx 称之为soc平台 把没有区别的东西放到一个平台里面,

arm下也有一个include 那么这个include目录,去区别于平台结构下的这个include

我们c语言的引用包 是#include <stdio.h> 我们知道它这个stdio.h是在include目录下实际去寻找的,但我们linux比较简单 是在user/include/stdio.h目录下就会有这个文件, 但是我们内核要怎么做呢 ? 我们内核有好几个include, 假如我们内核的一个文件中包含了一个 include<xxxx.h> 那么这个.h要到哪个目录下去寻找呢 ? , 那我们首先看一下内核是怎么来区分它的,

我们先看体系结构的, include目录下有个叫asm cd asm/

这里面有头文件 , 所以说如果我们要想 引用里面其中的一个头文件的话 , 比如ioctl.h, 我们应该这样用 #include <asm/ioctl.h>

内核的主目录也就是根目录, 称之为内核源码的目录, 我们再进到include目录下来看, 这个include里面其实没有.h ,所以实际上它也是通过文件夹把功能细分开了,, 其中linux文件目录 , 会是我们用的最多的目录 , ls linux 目录下的这些头文件 如果我要引用in6.h这个文件,那我们是不是应该在 #include<linux/in6.h> 也就是说include应该包含这个头文件, 这样就已经细分了,, 如果我们把/前缀部分加上我们自然而然就知道在哪里找了, 这是一种方法,

那我们到cd drivers 目录下进入到看门狗 cd watchdog/

vi ep93xx_wdt.c

我们可以看到内核源码的头文件跟我们平时看到的头文件其实不太一样, 应用程序头文件都是 #include<stdio.h> 但是linux头文件都是#include<linux/module.h> #include<mach/hardware.h>都是有个前缀 , , 所以当你看到别人写的代码的话就知道到那里去找这个.h了

现在有一个需要注意的地方, 我们linux内核源码中根目录中有一个include 而在arch/arm/include也有一个include , 在arch/arm/mach.xxx/中也有一个include 这个include下我们发现了mach文件, 也就是<mach/xxx.h>. 这已经是有三个include了

我们通过cd mach-spv210/include/mach 下确实看到了hardware.h

我们现在分析一下在watchdog.c中有一个头文件 是#include <mach/hardware.h>

arch/arm/mach-s5pv210/include/mach/hardware.h

arch/arm/mach-s3c2410/include/mach/hardware.h

...... 都有这个mach/hardware.h , 这里就有一个问题, 内核中有大量的重复文件的,那么我怎么样去区分它呢 ? 那么这个问题的解决办法是什么呢 ? 那么就要讲我们内核配置 . 内核你认为它是一个仓库,但是它编译过程的时候, 它能不能把所有的场景都拿来编译, 是不可以的,所以内核最主要的一步, 就是你要编译成你指定开发板的内核最重要的一步,就是你要根据每个仓库去选一个需要的仓库去编译就可以了,所以这里涉及到一个选板子 ,也就是说你选了这个板子,你就不能再选另一块板子, 那么像我们刷三星这个手机 能不能去刷那个苹果手机?或者去刷华为手机, 是不可以的, 因为他们可能用的结构不一样,除非华为和三星用的是同一款芯片,接口硬件是一样的只是外壳不同那就没有问题.

内核源码开发的头文件命名规范 :

#include<asm/xxx.h> cpu体系结构相关的

#include<linux/xxx.h> 平台无关的

#include<plat/xxx.h> 芯片公司相关的

#include<mach/xxx.h> 开发板

1.选择体系结构

2.选择文件

内核实际上是 一个很庞大的仓库,我们需要去揪出需要的一些仓库,最后编译组合

Linux内核配置初探 :

编译成内核镜像的时候,实际上并不需要编译所有的目录,我们就需要一个选配

1.配置哪些目录需要编译

2.配置哪些文件需要编译

编译时,到低文件是哪个目录.

<mach/hardware.h>

解决办法 :

1. Makefile make命令自动编译

然后通过 OBJS += xx.o 把需要的.o加进去 , 不需要的就不加进去

主目录下刚好有一个Makefile ,我们进入到drivers目录下 cd watchdog/ 这里面也有一个Makefile 所以你可以这样认为, 实际上每一个目录都有一个Makefile然后最终来说,你 可以认为 有一个主Makefile (根目录) 一层一层的映入到子目录层,

我们只需要定义Makefile 形式然后我们就可以知道该如何完成我们这样的需求.什么编什么不编,

我要分解一下,学习它还是分两步走 ,Makefile是我们学习内核的第二张地图, 第一张地图是目录,

第一种 : Makefile分两种地图(类型)一种称之为主目录, 就是内核根目录下Makefile 理解为是一个核心., 因为首先执行的是主Makefile

主目录Makefile能不能编译x86 能不能编arm ?主目录是于平台无关的

arch/xxx 到底是编译哪个文件夹 要被编译 不能又编ARM 又编x86 , 那么我们就可以猜测一下, 这个主Makefile一定是一个通用的,但是又要依赖于体系结构相关的Makefile 帮助 , 主目录Makefile不能把所有的体系结构都包含, 体系结构内容由体系结果目录的地方包含, 主目录的Makefile 肯定要跟体系结构下Makefile是要有相关联的,, 我们该如何来保证这个主Makefile跟体系结构上的Makefile 相关呢 ?我们如何包含其他的Makefile 有一个叫include , 只要在主Makefile里通过include关键字就可以包含到其他的文件, 就可以被主Makefile去解释内核去编译,

那么主Makefile能不能执行其他目录的Makefile呢 ? 肯定是由这个主目录Makefile一层一层的去调其他的子目录,

第二种 : 各个子目录Makefile

这两种Makefile形式是完全不一样的,相对而言,各个子目录Makefile是非常非常简单, 但是主目录Makefile是非常非常复杂

我们先看 watchdog/这个目录下的Makefile 都是obj做前缀然后-后面加上$符号 然后+= xxx.o

有三个同

obj-y : 编译进内核

obj- : 不编译进去 (不要了)

obj-m : 以模块形式编译

主目录的Makefile 把子目录的Makefile全部遍历一遍

目标定义是Kbuild Makefile的主要部分,也是核心部分。主要是定义了要编译的文件,所有的选项,以及到哪些子目录去执行递归操作。 最简单的Kbuild makefile 只包含一行:
例子:
obj-y += foo.o 该例子告诉Kbuild在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c 或foo.S文件编译得到。
如果foo.o要编译成一模块,那就要用obj-m了。所采用的形式如下:
obj-y += /usr/kernel/ 表示该目录下的对应所有文件生成的 .o 目标文件。
例子:
obj-(CONFIG_FOO) += foo.o (CONFIG_FOO)可以为y(编译进内核) 或m(编译成模块)。如果CONFIG_FOO不是y 和m,那么该文件就不会被编译联接了

除了y、m以外的obj-x 形式的目标都不会被编译。
除了obj-形式的目标以外,还有lib-y library 库、hostprogs-y 主机程序等。

意思是吧disk1/kernel/目录下的文件编译进内核, -y是编译进内核,-m是编译成模块

怎么配置内核 ?

我们在主Makefile里去搜索include 去反推, 看包含了哪些文件,是怎么包含的

$(hdr-arch) 我们如果知道这个变量的意义就能知道是怎么包含进来的,

-I(srctree)/arch/(hdr-arch)/include

include (srctree)/arch/(SRCARCH)/Makefile 这一行恰巧跟我们想的一样

如果我让SRCARCH = arm 那么我们就包含了arm的Makefile , 比如我们要配置我们现在的开发板,我们首先来说是不是要Makefile告诉它的SRCARCH = arm

hdr-arch = arm 也要包含arm 其实后面你会发现其实这两个是一样的,

那我们搜SRCARCH

结论 : 因为SUBARCH 默认就说x86的 ,我们不做任何改变的话,我们内核默认配置按照x86

1.编译体系结构相关

我们把 ARCH 这个变量改为 arm 单词 这个要跟arch目录里的名称一样 ,这个配置完之后我们就可以满足第一个体系结构就配好了

1.1 交叉编译

CROSS_COMPILE (195 - 196行)

2.哪些文件编译, 那些文件不编译 ?

上图我们会发现有大量的obj-$(CONFIG_xxx) 这样一个变量形式, 都有一个CONFIG_ 作为一个文件的前缀, 我们可以这样理解,这些文件的编译实际上都归结为 是否定义了一个 叫 CONFIG_xxxx 这样的变量是否被定义, 如果被定义自然而然obj-后面就说它的值, 这个值如果满足 obj-y 那么它就编译进内核, 如果满足 obj-m 自然而然就进入模块形式编译,下面的一个问题就是我们的主Makefile是如何把这样的文件引入到我们的整个变量中 (如果我们有一个CONFIG_xxxx这样的一个配置单,那么这个配置单想办法让主目录Makefile去把它读出来,然后在读出来的结果中呢去作用于剩下的所有子目录,那么这样的话我们哪些文件编译,哪些文件不编译这样就清楚了)

配置单 :芯片厂商给我们提供了一个配置单, 参考配置单,

配置单在哪 ?

/arch/arm/configs

xxx_defconfig 配置单文件 各个芯片系列 都对应一个defconfig文件

这个文件,如果我们想办法让Makefile用到, 是不是我们就可以说相对而言把内核配好了,

这个文件怎么用 ?

配置单找到之后, 把它导出 出去,不能放到默认目录下, 一定要导出到内核的主目录下、并且命名为 点 。config ,这个名字是可以改的,只是不建议, 因为这是约定俗成的规则

export ----> .config

这些并不满足我们实际工作需要,我们在工作时候 这个defconfig 是满足不了我们的需求的, defconfig可能是一个小的,芯片公司提供的一个最新的模板,默认配置文件,那么这个配置文件作用在公司的产品上肯定是有差异的,

3. 修改配置文件 修改defconfig 文件,变成适应于板子的

我们不建议直接在defconfig 文件里直接改,

怎么去修改 ?如何进行增删改查?

就是对 config 修改的过程,

一般操作得时候都是在linux_3.0.8主目录下得

首先第一步我们会先修改我们得Makefile ,,把我们的体系结构和交叉编译器修改, 我们用 / 进行去搜索,

去搜索CROSS , 这个名字比较特殊,如果搜ARCH 你会发现搜的特别特别多 ,

这几行,如果你觉得这个语法规则不太愿意看, 那么先复制一份,然后把原来的注释掉 , , ARCH 的变量值我们是可以写死的, 当然还有另外一种方法, 这不改, 你直接在make的时候改 ,

arm-none-linux-gnueabi-

第二步, 修改复制后的 .config 文件

把这里面该改成y的 该注释掉的, 这个工作量是非常庞大的,而且你也不知道哪个宏是你对应想要的, 不想要的.

增删查改中, 内核提供给我们的一个十分好用的 工具,叫 make menuconfig make菜单配置项,用一个图行界面来做 , 但是它不是基于windows 的界面, 也就是说我们实际上在 我们的远程登录的这样一种文本方式, 你也可以操作图行界面的方式, 要求系统安装一个库 , ubuntu 默认是没有这个库的, , 那么怎么去安装 menuconfig 所依赖的库,

第一次会稍微慢一些, 有一些警告不用管,

我们再看 .config 中 用/ 搜索一下 CONFIG_MODULES 这个时候我们会发现就会 有这么一个选项, CONFIG_MODULES=y

下面我们再做一个操作实验一下, 把这个 改成 # CONFIG_MODULES=y 换句话说这个宏相当于没有被编译

我们再make menuconfig

我们可以看到这个地方,是空了, 没有*了, 现在我们清楚, menuconfig 的原理实际上是帮我们把.config 里面对应的CONFIG_xxx这样的一个变量名转换成一个个字符串, 让人看的更清晰明了, 所以我们改menuconfig 比直接改.config要简单多了,

那我们再改回来, 第一种方法就是再复制一份 .config 出来, 尽量多备份,方便回溯,

不能把这些每一条字符串的含有可以去搜一下

比如像Device Drivers 很显示是设备驱动 , 你要跟设备驱动打交道,就要去跟Device Drivers打交道

menuconfig 这么把 .config 转成图行界面的呢 ? 他们的关系是什么呢 ?

有一个重要的文件是 .config 但是这个.config 它是怎么来得到的呢 ? 最终来说它是要作用于Makefile ,然后通过Makefile 把.config里的内容读出来, Makefile 就知道了,哪些编译,哪些不编, 但是这个.config 又怎么生成呢 ? 是通过menuconfig 去生成它的,生成的时候并没有那么简单,因为它有大量的字符串, string 那么它这个字符串是怎么最终跟 .config 连接到一起的呢 ?有一个Kconfig 文件 , menuconfig 会解析 Kconfig里面的信息, 然后形成我们 menuconfig 里看到的情况, 然后用户选择 编还是不编, 最终形成.config

make menuconfig ------> .config -----> Makefile

Kconfig

Linux 内核编译 :

怎么进行内核编译 :

make Image{obj-y}

make modules obj-m

在内核中提供了一个比较重要的东西 make 这个make不建议直接用,因为这个make实际上包含了两个命令, 一个是make Image{obj-y}细分很多种, 另一种叫make modules obj-m 意思是你在敲 make 的时候,它实际上是把 obj-y 和 obj-m 的内容进行编译,

这个make Image 有些大 , 你可以敲make zImage ,也可以敲make uImage ,我们建议敲uImage, 在敲的过程中你会发现有新的问题,

全部评论 (0)

还没有任何评论哟~