首页
|
新闻
|
新品
|
文库
|
方案
|
视频
|
下载
|
商城
|
开发板
|
数据中心
|
座谈新版
|
培训
|
工具
|
博客
|
论坛
|
百科
|
GEC
|
活动
|
主题月
|
电子展
注册
登录
论坛
博客
搜索
帮助
导航
默认风格
uchome
discuz6
GreenM
»
MCU 单片机技术
»
X86
» Linux内核的相关基础概念
返回列表
回复
发帖
发新话题
发布投票
发布悬赏
发布辩论
发布活动
发布视频
发布商品
Linux内核的相关基础概念
发短消息
加为好友
苹果也疯狂
当前离线
UID
852722
帖子
10369
精华
0
积分
5185
阅读权限
90
在线时间
277 小时
注册时间
2011-8-30
最后登录
2016-7-18
论坛元老
UID
852722
1
#
打印
字体大小:
t
T
苹果也疯狂
发表于 2015-7-27 21:56
|
只看该作者
Linux内核的相关基础概念
运行环境
,
Linux
,
资源
一
.
linux
设备驱动的作用
内核:用于管理软硬件资源,并提供运行环境。如分配
4G
虚拟空间等。
linux
设备驱动:是连接硬件和内核之间的桥梁。
linux
系统按个人理解可按下划分:
应用层:
包括
POSIX
接口,
LIBC
,图形库等,用于给用户提供访问
内核的接口。属于用户态,
ARM
运行在用户模式
(usr)
或
者系统模式
(sys)
下。
内核层:
应用程序调用相关接口后,会通过系统调用,执行
SWI
指
令切换
ARM
的工作模式到超级用户
(svc)
模式下,根据用
户函数的要求执行相应的操作。
硬件层:
硬件设备,当用户需要操作硬件时,内核会根据驱动接口
操作硬件设备
图结构如下:
举一个相对比较邪恶的类比:
在深圳的酒店经常会在门缝看到一些卡片,上面说可以通过打电话送货上门提供某中服务。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
二
.
内核代码树介绍
linux-2.6.29
|-
arch :
包含和硬件体系结构相关的代码
|-
block :
硬盘调度算法,不是驱动
|-
firmware :
固件,如
BOIS
|-
Documentation:
标准官方文档
|-
dirver : linux
设备驱动
|-
fs :
内核所支持的文件体系
|-
include
:头文件。
linux/module.hlinux/init.h
常用库。
|-
init
:库文件代码,
C
库函数在内核中的实现。
init/main.c->start_kernel->
内核执行第一条代码
|-
ipc :
进程件通信
|-
mm
:内存管理
|-
kernel :
内核核心部分,包括进程调度等
|-
net
:网络协议
|-
sound :
所有音频相关
|
其中,跟设备驱动有关并且经常查阅的文件夹有:
init
include: linux, asm-arm
drivers:
arch:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
三
.
内核补丁:
补丁一般都是基于某个版本内核生成的,用于升级旧内核。
打补丁需要注意:
1.
对应版本的补丁只能用于对应版本的内核。
2.
如果在已打补丁的内核再打补丁,需要先卸载原来补丁。
打补丁的方法:
1.
制作补丁:
diff-Nur linux-2.6.30/ linux-2.6.30.1/ > linux-2.6.30.1.patch
//N
为新加的文件全部修改
//linux-2.6.30
旧版本
//linux-2.6.30.1
新版本
//
目标补丁
2.
打补丁:
cdlinux-2.6.30 //
!!注意在原文件夹的目录中打补丁
patch-p1 < ../linux-2.6.30.1.patch //-p1
是忽略一级目录
3.
恢复:
cdlinux-2.6.30 //
!!注意在原文件夹的目录中打补丁
patch-R < ../linux-2.6.30.1.patch //
撤销补丁
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
四
.
内核中的
Makefile
:
对于内核,
Makefile
分为
5
类:
Documentation/kbuild/makefiles.txt
描述如下:
50 The Makefiles have five parts:
51
52 Makefile
总
Makefile
,控制内核的编译
53 .config
内核配置文件,配置内核时生成,
如
make menuconfig
后
54 arch/$(ARCH)/Makefile
对应体系结构的
Makefile
55 scripts/Makefile.* Makefile
共用的规则
56 kbuild Makefiles
各子目录下的
Makefile
,被上层的
Makefile
调用。
简单来说,编译内核会执行以下两步骤,它们分别干了以下的事情。
1
一般的,我们会拷贝一个对应体系结构的配置文件到主目录下并改名为
.config
,这样就在
makemenuconfig
生成的图形配置中
已经有了一些默认的配置,减少用户的劳动量。不过这一步不做也没关系的。
2.makemenuconfig
2.1
、由总
Makefile
决定编译的体系结构
(ARCH).
编译工具
(CROSS_COMPILE)
,并知道需要进去哪些内核根下的哪些目录进行编译。
2.2
、由
arch/$(ARCH)/Makefile,
决定
arch/$(ARCH)
下还有
的哪些目录和文件需要编译。
2.3
、知道了需要编译的目录后,递归的进入哪些目录下,读取每一个
Kconfig
的信息,生成了图形配置的界面。
2.4
、通过我们在图形配置界面中选项为
、
[M]
或者
[]
。
2.5
、保存并退出配置,会根据配置生成一份新的配置文件
.config
,并在同时生成
include/config/auto.conf
(这是
.config
的去注释版)。文件里面保存着
CONFIG_XXXX
等变量应该取
y
还是取
m
。
3.make
3.1
、根据
Makefile
包含的目录和配置文件的要求,进去个子目录进行编译,最后会在各子目录下
生成
一个
.o
或者
.a
文件,然后总
Makefile
指定的连接脚本
arch/$(ARCH)/kernel/vmlinux.lds
生成
vmlinux
,并通过
压缩编程
bzImage
,或者按要求在对应的子目录下
编译成
模块
。。
但是,具体是怎么生成配置文件的呢?
注:我使用的内核是
2.6.29
。
1.
在总
Makefile
中,根据以下语句进入需要编译的目录
470 # Objects we will link intovmlinux / subdirs we need to visit
471 init-y := init/
472 drivers-y := drivers/sound/ firmware/
473 net-y := net/
474 libs-y := lib/
475 core-y := usr/
476 endif # KBUILD_EXTMOD
639 core-y += kernel/ mm/fs/ ipc/ security/ crypto/ block/
上面说明了,根目录下的
init
、
driver
、
sound
、
firmware
、
net
、
lib
、
usr
等目录,在编译时都会进去读取目录下的
Makefile
并进行编译。
2.
在总
Makefile
中包含的目录还是不够的,内核还需要根据对应的
CPU
体系架构,
决定还需要将哪些子目录将要编译进内核。在总
Makefile
中有一个语句:
529 include$(srctree)/arch/$(SRCARCH)/Makefile //
在这里,我定义
SRCARCH= arm
可以看出,在总
Makefile
中进去读取相应体系
结构的
Makefile->arch/$(SRCARCH)/Makefile
。
arch/$(SRCARCH)/Makefile
中指定
arch/$(SRCARCH)
路径下的哪些子目录需要被编译。
在
arch/arm/Makefile
下:
95 head-y :=arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
187 # If we have a machine-specificdirectory, then include it in the build.
188 core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
189 core-y += $(machdirs) $(platdirs)
190 core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
191 core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
192 core-$(CONFIG_VFP) += arch/arm/vfp/
193
194 drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
195
196 libs-y := arch/arm/lib/ $(libs-y)
上面看到,指定需要进入
arch/arm/kernel/
、
arch/arm/mm/
、
arch/arm/common/
等目录编译,至于
core-y
、
core-$(CONFIG_FPE_NWFPE)
这些是什么东西呢?
其中,
y
表示编译成模块,
m
表示编译进内核
(
上面没有,因为默认情况下
ARM
全部编译进
内核
)
,但
$(CONFIG_OPROFILE)
又是什么呢?
这些是根据用户在
makemenuconfig
中设置后,生成的值赋给了
CONFIG_OPROFILE
。
3.
那
makemenuconfig
后的配置信息是怎么来的?
这是由各子目录下的
Kconfig
提供选项功用户选择并配置。
如
arch/arm/Kconfig
。
所有的配置都是根据
arch/$(ARCH)/Kconfig
文件通过
Kconfig
的语法
source
读取
各个包含的子目录
Kconfig
来生成一个配置界面。每个
Makefile
目录下都有一个
对应的
Kconfig
文件,用于生成配置界面来给用户决定内核如何配置,配置后会确定一个。
CONFIG_XXX
的的值(如上面的
CONFIG_OPROFILE
),来决定编译进内核,还是编译成模块或者不编译。
如在
arch/arm/Kconfig
下:
595 source"arch/arm/mach-clps711x/Kconfig"
596
597 source"arch/arm/mach-ep93xx/Kconfig"
598
599 source"arch/arm/mach-footbridge/Kconfig"
600
601 source"arch/arm/mach-integrator/Kconfig"
602
603 source"arch/arm/mach-iop32x/Kconfig"
604
605 source"arch/arm/mach-iop33x/Kconfig"
这些就是用来指定,需要读取以下目录下的
Kconfig
文件来生成一个使用
makemenuconfig
时的配置界面。
至于子目录下的
Kconfig
是怎么样的,待会介绍。
总结
Kconfig
的作用:
3.1.
在
makemenuconfig
下可以配置选项
;
3.2.
在
.config
中确定
CONFIG_XXX
的的值。
4.
只是读取以上的两个
Makefile
还是不够了,内核还会把包含的子目录一层一层的
读取它里面的
Makefile
和
Kconfig
。
上面啰啰嗦嗦地讲了这么久,无非就是想说,内核的编译并不是一个
Makefile
搞定的,需要通过根目录下的总
Makefile
来包含一下子
Makefile
(不管是根目录下的子目录还是
/arch/arm
中的子目录)。而
Kconfig
,为用户提供一个交互界面来选择如何配置并生成配置选项。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
五、子目录下的
Makefile
和
Kconfig
上面我一直介绍的都是两个比较大的
Makefile——
总
Makefile
和
arch/$(ARCH)/Makefile
。接下来看一下实例。
一、
在
makefile
中,
y
表示编译进内核,
m
表示编译成模块,不写代表不编译。
所以,配置最简单的方法就是,直接修改子目录的
Makefile
。
先看看
arch/arm/Makefile
:
/*arch/arm/mach-s3c2440/Makefile*/
12 obj-$(CONFIG_CPU_S3C2440) +=s3c2440.o dsc.o
13obj-$(CONFIG_CPU_S3C2440) += irq.o
14obj-$(CONFIG_CPU_S3C2440) += clock.o //
配置
2440
的时钟进入模块
15obj-$(CONFIG_S3C2440_DMA) += dma.o
如果我要取消
s3c2440
的时钟
(
当然这是必须要开的,只是举例
)
。
可以直接修改
arch/arm/mach-s3c2440/Makefile
将
obj-$(CONFIG_CPU_S3C2440) += clock.o
改为
obj- += clock.o
如果你想编译成模块也可以修改成:
obj-m += clock.o
在这里
CONFIG_CPU_S3C2440
的值默认是
y
,所以内核是要将时钟编译进内核的。也许有人会问,那我直接修改
CONFIG_CPU_S3C2440
的值为
m
不就可以将时钟编译成模块了,何必修改
Makefile
这么麻烦呢?的确是这样,只要我们通过在”
makemenuconfig”
的界面中配置后就能够改变
CONFIG_CPU_S3C2440
的值。接下来看看如何实现。
二、
在一般的编译内核时,我们都是
通过”
makemenuconfig”
进入图形界面面配置的,
接下来我实现一下如何将一个选项加入到图形配置界面中。
看看具体实现的步骤:
以下的执行环境是在
PC
机上,我使用的内核是
linux-2.6.29
:
2.1.
进入内核目录
cd linux-2.6.29
2.2.
在
driver
目录下模拟一个名为
test1
驱动的文件夹
mkdir driver/test1
2.3.
在目录下随便些一个
C
文件,只要不报错。
vim test1.c
我的
test1.c
如下:
1 void foo()
2 {
3 ;
4}
2.4vim Makefile //
在目录下编写一个简单的
Makefile
Makefile
文件编写如下:
obj-$(CONFIG_TEST1) += test1.o
CONFIG_TEST1
是决定
test1
是否编译进内核或者编译成模块的。这就是通
过同一目录下的
Kconfig
来在配置界面中生成选项,由用户在
makemenuconfig
中选择。
2.5
所以还要同一目录下写一个
Kconfig
:
vim Kconfig
Kconfig
修改如下:
menu "test1 driver here" //
这是在图形配置显示的
config TEST1
bool "xiaobai test1 driver" //
这同样也是在图形配置显示的
help
This is test1 //
这个也是在图形配置显示的。
说白了,就是在
图形配置的
driver
下多了一个配置选项
,用户配置后将
CONFIG_TEST1
的值存放在
.config
中,
Makefile
通过读取
.config
的去注
释版
include/config/auto.conf
读取到
CONFIG_TEST
的值,再进行编译。
但是,以上几步还不能达到目的,
因为虽然在总
Makefile
中已经包含了
目录
driver,
但是
driver
目录的
Makefile
中并没有包含
test
目录
。因此
需要在
driver/Makefile
中添加:
103 obj-$(CONFIG_PPC_PS3) +=ps3/
104 obj-$(CONFIG_OF) += of/
105 obj-$(CONFIG_SSB) += ssb/
106 obj-$(CONFIG_VIRTIO) +=virtio/
107 obj-$(CONFIG_STAGING) +=staging/
108 obj-y +=platform/
109obj-$(CONFIG_TEST1) += test1/ //
这是我添加的
虽然
Makefile
中已经包含了,但这样
还是不行
。因为当需要配置
ARM
时,
ARM
结构下的
Kconfig
并没有包含
test
的
Kconfig
。
这样的话就不会出现在
图形配置界面中,因此在
arch/arm/Kconfig
中添加:
1230 menu"Device Drivers" //
要在
DeviceDrivers
这个选项里面添加
1231
1232 source "drivers/base/Kconfig"
1233
1234 source"drivers/connector/Kconfig"
。。。。。。。。
1330 source"drivers/test/Kconfig" //
这是我添加的
1331
1332 endmenu
大功告成!
这样,
makemenuconfig
界面写的
DriverDevices
下就多了一个
"test1friver here"
的目录,里面有一个配置选项
"xiaobaitest1 driver"
。
Kconfig
文件的语法在
documentation/kbuild/kconfig-language.txt
文件中
有详细的讲解,上面我只是简单实现了一下,都是皮毛。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
六
.
内核和模块的编译
编译内核很简单,只需要配置完毕后执行
make
命令,将指定的文件编译进内核
bzImage
或者编译成模块。
make =make bzImage + make modules
因此如果值编译内核,即只编译配置文件中
-y
选项,可以直接用命令
makebzImage
如果值编译模块,即只编译配置文件中的
-m
选项,可以之直接使用命令
makemodules
模块可以编译当然也可以清除,使用命令
makemodules clean
如果只想单独编译一个模块,可以使用命令
makeM=drivers/test/ modules //
只单独编译
drivers/test
中的
.ko
makeM=drivers/test/ modules clean //
清除
上面的是在内核目录下的操作,但当我写驱动时,我并不可能在内核目录下编
写,但我编译时却要依赖内核中的规则和
Makefile
,所以就有了以下的方法,
同时这也是一般的编写驱动时
Makefile
的格式。
指定内核
Makefile
并单独编译
make-C /root/linux-2.6.29 M=`pwd` module
make-C /root/linux-2.6.29 M=`pwd` module clean
//-C
指定内核
Makefile
的路径,可以使用相对路径。
//-M
指定要编译的文件的路径,同样课使用相对路径。
编译生成的模块可以指定存放的目录
make-C /root/linux-2.6.29 M=`pwd` modules_installINSTALL_MOD_PATH=/nfsroot
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
七、总结
说了这么久估计都说糊涂了,其实我只是想表达一下内核编译时大体上究竟是怎么样的一个过程。
我以编译
S3C2440
的内核为例再说一遍:
1
一般我们会想将一份
S3C2440
的默认配置拷贝到内核跟目录下并改名为
.config
。
2.makemenuconfig
2.1
、由总
Makefile
决定编译的体系结构
(ARCH).
编译工具
(CROSS_COMPILE)
,并知道需要进去哪些内核根下的哪些目录进行编译。
2.2
、由
arch/$(ARCH)/Makefile,
决定
arch/$(ARCH)
下还有
的哪些目录和文件需要编译。
2.3
、知道了需要编译的目录后,递归的进入哪些目录下,读取每一个
Kconfig
的信息,生成了图形配置的界面。
2.4
、通过我们在图形配置界面中选项为
、
[M]
或者
[]
。
2.5
、保存并退出配置,会根据配置生成一份新的配置文件
.config
,并在同时生成
include/config/auto.conf
(这是
.config
的去注释版)。文件里面保存着
CONFIG_XXXX
等变量应该取
y
还是取
m
。
3.make
3.1
、根据
Makefile
包含的目录和配置文件的要求,进去个子目录进行编译,最后会在各子目录下
生成
一个
.o
或者
.a
文件,然后总
Makefile
指定的连接脚本
arch/$(ARCH)/kernel/vmlinux.lds
生成
vmlinux
,并通过
压缩编程
bzImage
,或者按要求在对应的子目录下
编译成
模块
。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
收藏
分享
评分
回复
引用
订阅
TOP
返回列表
电商论坛
Pine A64
资料下载
方案分享
FAQ
行业应用
消费电子
便携式设备
医疗电子
汽车电子
工业控制
热门技术
智能可穿戴
3D打印
智能家居
综合设计
示波器技术
存储器
电子制造
计算机和外设
软件开发
分立器件
传感器技术
无源元件
资料共享
PCB综合技术
综合技术交流
EDA
MCU 单片机技术
ST MCU
Freescale MCU
NXP MCU
新唐 MCU
MIPS
X86
ARM
PowerPC
DSP技术
嵌入式技术
FPGA/CPLD可编程逻辑
模拟电路
数字电路
富士通半导体FRAM 铁电存储器“免费样片”使用心得
电源与功率管理
LED技术
测试测量
通信技术
3G
无线技术
微波在线
综合交流区
职场驿站
活动专区
在线座谈交流区
紧缺人才培训课程交流区
意见和建议