4. Linux内核:不同的视角
4.1 知识背景:1991.8 Linus发布了著名通告。
4.1.1 内核版本:
linux官方网站:
linux版本号:
命名方式:主版本号,次版本号,序列号
编号系统区分两种内核代码树:一种是针对开发和实验的非稳定版本,另一种是可供生产和使用的稳定版本。
linux 2.4.x - 稳定内核版本
linux 2.5.x - 实验(开发)版本
linux 2.6.x - 稳定内核版本
内核源码树顶层有个../Makefile,定义了内核版本号:
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 22
EXTRAVERSION = .6
NAME = Holy Dancing Manatees, Batman!
在Makefile的后面,用宏定义描述内核版本号:
KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
但是KERNELVERSION已经被宏定义KERNELRELEASE取代。
在一个运行的linux系统中,查询内核的发布信息:
$ cat /proc/version
Linux version 2.6.31-14-generic (buildd@rothera) (gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu8) ) #48-Ubuntu SMP Fri Oct 16 14:04:26 UTC 2009
4.1.2 内核源码库
4.1.3 使用git下载内核
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux-2.6
4.2 linux内核的构造
4.2.1 顶层源码目录
源码树顶层目录:
a. 电脑桌面Linux工作站:/usr/src/linux-x.y.z
$ ls /usr/src
linux-headers-2.6.31-14 linux-headers-2.6.31-14-generic
b. 纯净Linux源码树:
$ ls ./linux-2.6.22.6
arch CREDITS drivers init kernel Makefile README security
block crypto fs ipc lib mm REPORTING-BUGS sound
COPYING Documentation include Kbuild MAINTAINERS net scripts usr
顶层Makefile会构建两个重要的目标:System.map, vmlinux。
在内核构建成功后,会在顶层源码目录中生成这两个文件,其中vmlinux是内核主体(kernel proper)。
4.2.2 编译内核
内核构建系统在成功构建内核后,总是会生成公共文件。其中两个System.map, vmlinux。
System.map:有助于调试内核,包含了一个人类可读的内核符号的列表以及他们各自的地址;
vmlinux: 是一个与具体架构相关的可执行文件,而且符合ELF格式。
配置内核:
在内核源码树下,输入命令:
$ make ARCH=arm CROSS_COMPILE=arm-linux- s3c2410_defconfig
输出:
....
*
CRC-CCITT functions (CRC_CCITT) [N/m/y/?] n
CRC16 functions (CRC16) [N/m/y/?] n
CRC ITU-T V.41 functions (CRC_ITU_T) [N/m/y/?] (NEW) n
CRC32 functions (CRC32) [Y/?] y
CRC32c (Castagnoli, et al) Cyclic Redundancy-Check (LIBCRC32C) [N/m/y/?] n
#
# configuration written to .config // 这表示配置了.config文件
#
这个命令并没有构建内核;它只是将内核源码树的架构配置为arm,为后面的内核构建做准备。
这个命令基于文件s3c2410_defconfig中的默认值生成一个默认的配置文件(.config文件),用于构建内核。
构建内核:
$ make ARCH=arm CROSS_COMPILE=arm-linux- zImage
输出:
......
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
AS arch/arm/boot/compressed/head.o
GZIP arch/arm/boot/compressed/piggy.gz
AS arch/arm/boot/compressed/piggy.o
CC arch/arm/boot/compressed/misc.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
命令行中指定:目标架构(ARCH = arm)和工具链( CROSS_COMPILE = arm-linux- )。
这就强制make使用arm-linux-工具链来构建内核镜像,并使用内核源码树的arm分支来编译生成镜像中与架构相关的部分。
并同时指定一个目标文件:zImage。
构建内核时,输出详细信息:
$ make ARCH=arm CROSS_COMPILE=arm-linux- V=1 zImage
可以输入make help查看帮助文档。
4.2.3 内核主体:vmlinux
LD arch/arm/boot/compressed/vmlinux
表示链接生成vmlinux文件。
vmlinux文件就是实际的内核主体(kernel proper),它是一个完全独立的单一ELF镜像,vmlinux这个二进制文件不包含任何为解析的外部引用。
我们很少直接引导ELF目标文件vmlinux来启动内核,而是使用它的压缩形式。
4.2.4 内核镜像的组成部分
vmlinux镜像的成员:
arch/arm/kernel/head.o 内核中与具体架构相关的启动代码 head.S
arch/arm/kernel/init_task.o 内核所需的初始的线程和任务结构体
init/built-in.o 主要的初始化代码
usr/built-in.o 内置的initramfs镜像
arch/arm/kernel/built-in.o 与具体架构相关的内核代码
arch/arm/mm/built-in.o 与具体架构相关的内存管理代码
arch/arm/common/built-in.o 与具体架构相关的通用代码
arch/arm/mach-s3c2410/built-in.o 与具体机器相关的代码
arch/arm/mach-s3c2400/built-in.o 与具体机器相关的代码
arch/arm/mach-s3c2412/built-in.o 与具体机器相关的代码
arch/arm/mach-s3c2440/built-in.o 与具体机器相关的代码
arch/arm/mach-s3c2442/built-in.o 与具体机器相关的代码
arch/arm/mach-s3c2443/built-in.o 与具体机器相关的代码
arch/arm/nwfpe/built-in.o 浮点运算模拟(floating-point emulation)代码
arch/arm/plat-s3c24xx/built-in.o 与具体机器相关的代码
kernel/built-in.o 内核自身的通用代码
mm/built-in.o 内存管理代码的通用部分
fs/built-in.o 文件系统代码
ipc/built-in.o 进程间通信
security/built-in.o 安全组件
crypto/built-in.o 加密API
block/built-in.o 内核块设备层的核心代码
arch/arm/lib/lib.a 与具体架构相关的辅助函数
lib/lib.a 通用的程序库函数
arch/arm/lib/built-in.o
lib/built-in.o
drivers/built-in.o
sound/built-in.o
net/built-in.o
4.2.5 子目录布局
4.3 内核构建系统
4.3.1 .config文件
用于构建linux内核镜像的配置文件,是一个隐藏文件。
注意:如果没有备份.config文件,则执行make distclean或者make mrproper命令,将删除.config文件!!
看.config片段:
#
# USB support
#
CONFIG_USB=m
# CONFIG_USB_DEBUG is not set
#
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
CONFIG_USB_DEVICE_CLASS=y
Linux采用单体(monolithic)内核结构,
a. 整个内核是由代码编译并静态链接生成的,是一个单一的可执行文件。
b. 也可以编译一组源码文件,通过增量链接的方式生成一个对象模块,它可以动态加载到运行的内核中,多用于设备驱动文件。
CONFIG_USB=m,表明这个内核配置中包含了USB子系统,并且它会编译成一个可动态加载的模块(=m)。
CONFIG_USB=y,表明USB模块会被编译和静态链接到内核镜像中,成为它的一部分。
在这种情况下,USB子系统会被最终编译到../drivers/built-in.o中,这是个复合二进制对象。
4.3.2 配置编辑器
Configuration targets:
config - Update current config utilising a line-oriented program
menuconfig - Update current config utilising a menu based program
xconfig - Update current config utilising a QT based front-end
gconfig - Update current config utilising a GTK based front-end
oldconfig - Update current config utilising a provided .config as base
silentoldconfig - Same as oldconfig, but quietly
randconfig - New config with random answer to all options
defconfig - New config with default answer to all options
allmodconfig - New config selecting modules when possible
allyesconfig - New config where all options are accepted with yes
allnoconfig - New config where all options are answered with no
大多数内核软件模块通过.config文件间接地读取配置内容,原理如下:
在构建过程中,构建系统会处理这个.config文件,并生成一个名为autoconf.h的文件,放在目录../include/linux中,这个文件
是自动生成的。尽量不要去修改这个文件,因为当配置有变动并且新的构建开始后,你所做的修改就丢失了。
在顶层目录下输入命令,查看与USB相关的一部分内容:
$ cat include/linux/autoconf.h | grep CONFIG_USB
#define CONFIG_USB_ARCH_HAS_OHCI 1
#define CONFIG_USB_MON 1
#define CONFIG_USB_DEVICEFS 1
#define CONFIG_USB_OHCI_HCD 1
#define CONFIG_USB_OHCI_LITTLE_ENDIAN 1
#define CONFIG_USB_DEVICE_CLASS 1
#define CONFIG_USB_ARCH_HAS_HCD 1
#define CONFIG_USB 1
4.3.3 Makefile目标
在顶层Linux源码中输入命令make help
$ make help
Cleaning targets:
clean - Remove most generated files but keep the config and
enough build support to build external modules
mrproper - Remove all generated files + config + various backup files
distclean - mrproper + remove editor backup and patch files
Configuration targets:
config - Update current config utilising a line-oriented program
menuconfig - Update current config utilising a menu based program
xconfig - Update current config utilising a QT based front-end
gconfig - Update current config utilising a GTK based front-end
oldconfig - Update current config utilising a provided .config as base
silentoldconfig - Same as oldconfig, but quietly
randconfig - New config with random answer to all options
defconfig - New config with default answer to all options
allmodconfig - New config selecting modules when possible
allyesconfig - New config where all options are accepted with yes
allnoconfig - New config where all options are answered with no
Other generic targets:
all - Build all targets marked with [*]
* vmlinux - Build the bare kernel
* modules - Build all modules
modules_install - Install all modules to INSTALL_MOD_PATH (default: /)
dir/ - Build all files in dir and below
dir/file.[ois] - Build specified target only
dir/file.ko - Build module including final link
rpm - Build a kernel as an RPM package
tags/TAGS - Generate tags file for editors
cscope - Generate cscope index
kernelrelease - Output the release version string
kernelversion - Output the version stored in Makefile
headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH
(default: /work/system/linux-2.6.22.6/usr)
Static analysers
checkstack - Generate a list of stack hogs
namespacecheck - Name space analysis on compiled kernel
headers_check - Sanity check on exported headers
Kernel packaging:
rpm-pkg - Build the kernel as an RPM package
binrpm-pkg - Build an rpm package containing the compiled kernel
and modules
deb-pkg - Build the kernel as an deb package
tar-pkg - Build the kernel as an uncompressed tarball
targz-pkg - Build the kernel as a gzip compressed tarball
tarbz2-pkg - Build the kernel as a bzip2 compressed tarball
Documentation targets:
Linux kernel internal documentation in different formats:
htmldocs - HTML
installmandocs - install man pages generated by mandocs
mandocs - man pages
pdfdocs - PDF
psdocs - Postscript
xmldocs - XML DocBook
Architecture specific targets (i386):
* bzImage - Compressed kernel image (arch/i386/boot/bzImage)
install - Install kernel using
(your) ~/bin/installkernel or
(distribution) /sbin/installkernel or
install to $(INSTALL_PATH) and run lilo
bzdisk - Create a boot floppy in /dev/fd0
fdimage - Create a boot floppy image
isoimage - Create a boot CD-ROM image
make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
make V=2 [targets] 2 => give reason for rebuild of target
make O=dir [targets] Locate all output files in "dir", including .config
make C=1 [targets] Check all c source with $CHECK (sparse by default)
make C=2 [targets] Force check of all c source with $CHECK
最常见的使用make方式是不指定目标。在这种情况下,它会生成内核ELF文件vmlinux和针对所选架构的默认二进制镜像(例如: x86
架构的bzImage)。
使用make时,如果不指定目标,它也会编译所有由配置文件指定的设备驱动程序模块(内核可加载模块)。
比如命令: $ make ARCH=arm CROSS_COMPILE=arm-linux- (不指定目标)
这将同时编译驱动内核模块。
$ make ARCH=arm CROSS_COMPILE=arm-linux-
......
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy.gz
AS arch/arm/boot/compressed/piggy.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
Building modules, stage 2.
MODPOST 19 modules
CC drivers/block/aoe/aoe.mod.o
LD [M] drivers/block/aoe/aoe.ko
CC drivers/block/nbd.mod.o
LD [M] drivers/block/nbd.ko
CC drivers/hwmon/hwmon-vid.mod.o
LD [M] drivers/hwmon/hwmon-vid.ko
CC drivers/hwmon/lm75.mod.o
LD [M] drivers/hwmon/lm75.ko
CC drivers/hwmon/lm78.mod.o
LD [M] drivers/hwmon/lm78.ko
CC drivers/hwmon/lm85.mod.o
LD [M] drivers/hwmon/lm85.ko
CC drivers/i2c/algos/i2c-algo-bit.mod.o
LD [M] drivers/i2c/algos/i2c-algo-bit.ko
CC drivers/i2c/chips/eeprom.mod.o
LD [M] drivers/i2c/chips/eeprom.ko
CC drivers/i2c/i2c-dev.mod.o
LD [M] drivers/i2c/i2c-dev.ko
CC drivers/ide/ide-floppy.mod.o
LD [M] drivers/ide/ide-floppy.ko
CC drivers/ide/ide-tape.mod.o
LD [M] drivers/ide/ide-tape.ko
CC drivers/leds/led-class.mod.o
LD [M] drivers/leds/led-class.ko
CC drivers/leds/leds-h1940.mod.o
LD [M] drivers/leds/leds-h1940.ko
CC drivers/leds/leds-s3c24xx.mod.o
LD [M] drivers/leds/leds-s3c24xx.ko
CC drivers/leds/ledtrig-heartbeat.mod.o
LD [M] drivers/leds/ledtrig-heartbeat.ko
CC drivers/leds/ledtrig-timer.mod.o
LD [M] drivers/leds/ledtrig-timer.ko
CC drivers/spi/spi_bitbang.mod.o
LD [M] drivers/spi/spi_bitbang.ko
CC drivers/spi/spi_s3c24xx.mod.o
LD [M] drivers/spi/spi_s3c24xx.ko
CC drivers/spi/spi_s3c24xx_gpio.mod.o
LD [M] drivers/spi/spi_s3c24xx_gpio.ko
很多架构和机器类型都需要一个二进制镜像目标,而这个目标与具体使用的架构和引导加载程序相关。比较常见的
这类目标是zImage。对于很多架构来说,这就是默认的二进制镜像目标,可以被加载到目标嵌入式系统中并运行。
注意:bzImage目标是针对x86/PC架构的,而不是经过压缩工具bzip2压缩过的镜像。
对于命令make help,也可以指定架构,比如:
$ make ARCH=arm help
Cleaning targets:
clean - Remove most generated files but keep the config and
enough build support to build external modules
mrproper - Remove all generated files + config + various backup files
distclean - mrproper + remove editor backup and patch files
Configuration targets:
config - Update current config utilising a line-oriented program
menuconfig - Update current config utilising a menu based program
xconfig - Update current config utilising a QT based front-end
gconfig - Update current config utilising a GTK based front-end
oldconfig - Update current config utilising a provided .config as base
silentoldconfig - Same as oldconfig, but quietly
randconfig - New config with random answer to all options
defconfig - New config with default answer to all options
allmodconfig - New config selecting modules when possible
allyesconfig - New config where all options are accepted with yes
allnoconfig - New config where all options are answered with no
Other generic targets:
all - Build all targets marked with [*]
* vmlinux - Build the bare kernel
* modules - Build all modules
modules_install - Install all modules to INSTALL_MOD_PATH (default: /)
dir/ - Build all files in dir and below
dir/file.[ois] - Build specified target only
dir/file.ko - Build module including final link
rpm - Build a kernel as an RPM package
tags/TAGS - Generate tags file for editors
cscope - Generate cscope index
kernelrelease - Output the release version string
kernelversion - Output the version stored in Makefile
headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH
(default: /work/system/linux-2.6.22.6/usr)
Static analysers
checkstack - Generate a list of stack hogs
namespacecheck - Name space analysis on compiled kernel
headers_check - Sanity check on exported headers
Kernel packaging:
rpm-pkg - Build the kernel as an RPM package
binrpm-pkg - Build an rpm package containing the compiled kernel
and modules
deb-pkg - Build the kernel as an deb package
tar-pkg - Build the kernel as an uncompressed tarball
targz-pkg - Build the kernel as a gzip compressed tarball
tarbz2-pkg - Build the kernel as a bzip2 compressed tarball
Documentation targets:
Linux kernel internal documentation in different formats:
htmldocs - HTML
installmandocs - install man pages generated by mandocs
mandocs - man pages
pdfdocs - PDF
psdocs - Postscript
xmldocs - XML DocBook
Architecture specific targets (arm):
* zImage - Compressed kernel image (arch/arm/boot/zImage)
Image - Uncompressed kernel image (arch/arm/boot/Image)
* xipImage - XIP kernel image, if configured (arch/arm/boot/xipImage)
bootpImage - Combined zImage and initial RAM disk
(supply initrd image via make variable INITRD=
)
install - Install uncompressed kernel
zinstall - Install compressed kernel
Install using (your) ~/bin/installkernel or
(distribution) /sbin/installkernel or
install to $(INSTALL_PATH) and run lilo
assabet_defconfig - Build for assabet
at91rm9200dk_defconfig - Build for at91rm9200dk
at91rm9200ek_defconfig - Build for at91rm9200ek
at91sam9260ek_defconfig - Build for at91sam9260ek
at91sam9261ek_defconfig - Build for at91sam9261ek
at91sam9263ek_defconfig - Build for at91sam9263ek
at91sam9rlek_defconfig - Build for at91sam9rlek
ateb9200_defconfig - Build for ateb9200
badge4_defconfig - Build for badge4
carmeva_defconfig - Build for carmeva
cerfcube_defconfig - Build for cerfcube
clps7500_defconfig - Build for clps7500
collie_defconfig - Build for collie
corgi_defconfig - Build for corgi
csb337_defconfig - Build for csb337
csb637_defconfig - Build for csb637
ebsa110_defconfig - Build for ebsa110
edb7211_defconfig - Build for edb7211
ep93xx_defconfig - Build for ep93xx
footbridge_defconfig - Build for footbridge
fortunet_defconfig - Build for fortunet
h3600_defconfig - Build for h3600
h7201_defconfig - Build for h7201
h7202_defconfig - Build for h7202
hackkit_defconfig - Build for hackkit
integrator_defconfig - Build for integrator
iop13xx_defconfig - Build for iop13xx
iop32x_defconfig - Build for iop32x
iop33x_defconfig - Build for iop33x
ixp2000_defconfig - Build for ixp2000
ixp23xx_defconfig - Build for ixp23xx
ixp4xx_defconfig - Build for ixp4xx
jornada720_defconfig - Build for jornada720
kafa_defconfig - Build for kafa
kb9202_defconfig - Build for kb9202
ks8695_defconfig - Build for ks8695
lart_defconfig - Build for lart
lpd270_defconfig - Build for lpd270
lpd7a400_defconfig - Build for lpd7a400
lpd7a404_defconfig - Build for lpd7a404
lubbock_defconfig - Build for lubbock
lusl7200_defconfig - Build for lusl7200
mainstone_defconfig - Build for mainstone
mx1ads_defconfig - Build for mx1ads
neponset_defconfig - Build for neponset
netwinder_defconfig - Build for netwinder
netx_defconfig - Build for netx
ns9xxx_defconfig - Build for ns9xxx
omap_h2_1610_defconfig - Build for omap_h2_1610
onearm_defconfig - Build for onearm
picotux200_defconfig - Build for picotux200
pleb_defconfig - Build for pleb
pnx4008_defconfig - Build for pnx4008
pxa255-idp_defconfig - Build for pxa255-idp
realview_defconfig - Build for realview
realview-smp_defconfig - Build for realview-smp
rpc_defconfig - Build for rpc
s3c2410_defconfig - Build for s3c2410
shannon_defconfig - Build for shannon
shark_defconfig - Build for shark
simpad_defconfig - Build for simpad
spitz_defconfig - Build for spitz
trizeps4_defconfig - Build for trizeps4
versatile_defconfig - Build for versatile
make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
make V=2 [targets] 2 => give reason for rebuild of target
make O=dir [targets] Locate all output files in "dir", including .config
make C=1 [targets] Check all c source with $CHECK (sparse by default)
make C=2 [targets] Force check of all c source with $CHECK
Execute "make" or "make all" to build all targets marked with [*]
For further info see the ./README file
注意:目标前面有个星号"*",表示此目标会默认创建。
4.4 内核配置
在顶层源码树下输入命令:find -name "*Kconfig"
可以看到源码树下包含很多Kconfig文件,这个文件用于配置其所在目录的源码的特性。
Kconfig中的每个配置参数都有附带的帮助文本,配置子系统会解析Kconfig的内容,并提示用户做出配置选择。
配置工具(比如menuconfig)会读取各个子目录中的Kconfig文件,首先读取的是arch子目录中的Kconfig文件。
它是在Kconfig的Makefile中读取的(这个Makefile具体路径../scripts/kconfig/Makefile)
../scripts/kconfig/Makefile 内容:
# ===========================================================================
# Kernel configuration targets
# These targets are used from top-level makefile
PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
xconfig: $(obj)/qconf
$< arch/$(ARCH)/Kconfig
gconfig: $(obj)/gconf
$< arch/$(ARCH)/Kconfig
menuconfig: $(obj)/mconf
$< arch/$(ARCH)/Kconfig // 第一个Kconfig文件,具体对应ARCH - ../arch/arm/Kconfig
......
根据选择的具体架构,menuconfig会读取该架构对应的Kconfig文件,并将其内容作为顶层配置定义。
Kconfig文件中包含很多类似的指令行:
source "drivers/pci/Kconfig"
这条指令告诉配置编辑器,从内核源码树的其他位置读取另一个Kconfig文件。
每种架构都包含很多这样的Kconfig文件,这些Kconfig文件组合起来成为一个完整的配置集合,当用户配置内核
时,配置集合会以菜单的形式展现在用户面前。每个Kconfig文件都可以随意指定处在源码树其他位置的Kconfig
文件。配置工具-menuconfig-会递归读取所有这些链接在一起的Kconfig文件,并相应地构造出配置时所用的菜单
结构。
看一下顶层配置文件: /arch/arm/Kconfig
$ vi arch/arm/Kconfig
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
mainmenu "Linux Kernel Configuration"
config ARM
bool
default y
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
handhelds such as the Compaq IPAQ. ARM-based PCs are no longer
manufactured, but legacy ARM-based PC hardware remains popular in
Europe. There is an ARM Linux project with a web page at
<
...
source "drivers/input/Kconfig"
source "drivers/char/Kconfig"
source "drivers/i2c/Kconfig"
source "drivers/spi/Kconfig"
source "drivers/w1/Kconfig"
......
4.4.1 定制配置选项
在配置选项里,如何加入对自己开发板的支持。
4.4.2 内核Makefile
如何将支持的开发板功能编译进内核。
4.5 内核文档
Linux自带文档 + Linux官方网站 + Google
4.6 获得定制的Linux内核