十四、linux内核裁剪
一、下载解压linux内核源码
1、进kernel官网下载源码
我这里下载的是5.4.191版本(仅做实验),为了和我ubuntu虚拟机的交叉编译环境匹配。
2、解压内核源码压缩包
xz -cd linux-5.4.191.tar.xz | tar xvf -
二、清理临时文件
1.删除大多数的编译生成文件, 但是会保留内核的配置文件.config, 还有足够的编译支持来建立扩展模块
make clean
2、mrproper删除的文件, 加上编辑备份文件和一些补丁文件
make distclean
3、删除所有的编译生成文件, 还有内核配置文件, 再加上各种备份文件
make mrproper
三、配置内核
1、基于文本模式,挨个配置选择y/n
make config
2、基于菜单模式,复选框都会有默认选项。
make menuconfig
3、使用已有的配置文件
make oldconfig
4、需要安装图形化系统
make xconfig
得到系统源文件下的config 文件。
四、编译
1、配置分析
make menuconfig进入配置菜单,
我们可以看到处理器默认的x86-64,分析内核顶层目录下的Makefile
查看makefile的内容后,我们可以知道makefile配置的x86架构的处理去时根据虚拟机的处理器架构配置的。
2、编译
执行make命令进行编译,make -jn多任务编译更快,编译成功后,会在arch/x86_64/boot目录下会生成bzImage镜像文件
3、linux内核镜像文件介绍
内核镜像有许多种,但是基本都是基于vmlinux压缩加头得到,目的是为了让内核镜像尽可能的小,在嵌入式中存储介质的空间比较小,也比较紧张,这些压缩镜像是为了去适应嵌入式而产生的内核编译(make)之后会生成两个文件,一个Image,一个zImage,其中Image为内核映像文件,而zImage为内核的一种映像压缩文件,Image大约为4M,而zImage不到2M。
Linux内核有多种格式的镜像,包括vmlinux、Image(vmlinux.bin)、zImage(vmlinux.bin.gz)、bzImage、uImage、xipImage、bootpImage等.
(1)vmlinux
vmlinux是可引导的、未压缩、可压缩的内核镜像,vm代表Virtual Memory.Linux支持虚拟内存,因此得名vm.它是由用户对内核源码编译得到,实质是elf格式的文件.也就是说vmlinux是编译出来的最原始的内核文件,未压缩.这种格式的镜像文件多存放在PC机上.
- elf格式文件 (ELF,Executable and Linkable Format,可执行可链接格式)是UNIX实验室作为应用程序二进制接口而发布的,扩展名为elf.可以简单的认为,在elf格式的文件中,除二进制代 码外,还包括该可执行文件的某些信息,比如符号表等。
vmlinuz 是可执行 的Linux内核,它位于/boot/vmlinuz,它一般是一个软链接,比如是 vmlinuz-3.13.0-32-generic 的软链接。vmlinuz是vmlinux的压缩文件。vmlinuz的建立有两种方式。一是编译内核时通过“make zImage”创建, 二是内核编译时通过命令make bzImage创
(2)Image
Image是经过objcopy处理的只包含二进制数据的内核代码,它已经不是elf格式了,但这种格式的内核镜像还没有经过压缩.
objcopy
GNU使用工具程序objcopy作用是拷贝一个目标文件的内容到另一个目标文件中,也就是说,可以将一种格式的目标文件转换成另一种格式的目标文件. 通过使用binary作为输出目标(-o binary),可产生一个原始的二进制文件,实质上是将所有的符号和重定位信息都将被抛弃,只剩下二进制数据.
(3)zImage
zImage是ARM linux常用的一种压缩镜像文件,它是由vmlinux加上解压代码经gzip压缩而成,命令格式是make zImage.这种格式的Linux镜像文件多存放在NAND上.
适用于小内核的情况,它的存在是为了向后的兼容性。
(4)bzImage
bzImage不是用bzip2压缩的,bz表示big zImage,其格式与zImage类似,但采用了不同的压缩算法,注意,bzImage的压缩率更高 是压缩的内核映像。
zImage bzImage:它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有解压缩代码。两者的不同之处在于,老的zImage解压缩内核到低端内存(第一个 640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么可以采用zImage或bzImage之一,两种方式引导的系统运行 时是相同的。大的内核采用bzImage,不能采用zImage。
(5)uImage
uImage是uboot专用的镜像文件,它是在 zImage 之前加上一个长度为0x40的头信息(tag),在头信息内说明了该镜像文件的类型、加载位置、生成时间、大小等信息.换句话说,若直接从uImage的0x40位置开始执行,则zImage和uImage没有任何区别.命令格式是#make uImage.这种格式的Linux镜像文件多存放在NAND上.
- 如何生成uImage文件?
首先 在uboot的/tools目录下寻找mkimage文件,把其copy到系统/usr/local/bin目录下,这样就完成制作工具。然后在内核目录下运行make uImage,如果成功,便可以在arch/arm/boot/目录下发现uImage文件,其大小比zImage多64个字节。
由于bootloader一般要占用0x0地址,所以,uImage相比zImage的好处就是可以和bootloader共存。其实就是一个自动跟手动的区别,有了uImage头部的描述,u-boot就知道对应Image的信息,如果没有头部则需要自己手动去搞那些参数。
(6)xipImage
这种格式的Linux镜像文件多存放在NorFlash上,且运行时不需要拷贝到内存SDRAM中,可以直接在NorFlash中运行.
4.Linux内核镜像的产生过程
在嵌入式Linux中,内核的启动过程分为两个阶段:
-
第一阶段启动代码放在arch/arm/kernel/head.S文件中,该文件与体系结构相关,与开发板周边硬件无关,主要是初始化ARM内核等.
-
第二阶段启动代码是init目录下的main.c.现以执行命令#make zImage为例来说明,arm-linux内核镜像的产生过程.
(1)当用户对Linux内核源码进行编译时,kernel的第1/2阶段代码会生成可执行文件vmlinux,该文件是未被压缩的镜像文件,非常大,不能直接下载到NAND中,通常放在PC机上,这也是最原始的Linux镜像文件.试验时该文件约50M.
(2)镜像文件vmlinux由于很大,肯定不能直接烧入NAND中,因此需要进行二进制化,即经过objcopy处理,使之只包含二进制数据的内核代 码,去除不需要的文件信息等,这样就制作成了image镜像文件.该镜像文件也是未压缩,只是经过了二进制化而变小.试验时该文件约5M.
(3) 一般来说,内存SDRAM中的内核镜像是经过压缩的,只是在运行时再将其解压.所以,编译时会先使用gzip将镜像文件image进行压缩(压缩比约为 2:1),再将压缩后的镜像文件和源码中的两个文件 arch/arm/boot/compressed/head.S、arch/arm/boot /compressed/misc.c一起链接生成压缩后的镜像文件compress/vmlinux(?).试验时该文件约为2.5M.注意,这两个源码文件 是解压程序,用于将内存SDRAM中的压缩镜像zImage进行解压.
(4)压缩后的镜像文件compress/vmlinux经过二进制化,最终生成镜像文件zImage,试验时该文件约为2.5M.当然,在内存 SDRAM中运行压缩镜像文件zImage时,会首先调用两个解压程序arch/arm /boot/compressed/head.S、arch/arm/boot/compressed/misc.c将自身解压,然后再执行kernel 的第一阶段启动代码arch/arm/kernel/head.S.简而言之,在内存中运行内核时,kernel先自身解压,再执行第一阶段启动代码.试 验时运行在内存中的镜像文件约为5M,与image镜像文件大小相同.
五、安装新内核镜像
1、 在/boot目录下新建mynewkernel目录,并将 bzImage 拷贝到 /boot/mynewkernel 目录下:
sudo cp arch/i386/boot/bzImage /boot/mynewkernel
2、更改 /boot/mynewkernel 中 bzImage 的名字
sudo mv bzImage vmlinuz-2.6.17.13
3、备份、修改grub配置文件
sudo cp /boot/grub/grub.cfg grub.cfg.origin
修改grub.cfg,加入以下内容(从既有的grub.cfg中相关的内容拷贝):
title zp, make defconfig, 2.6.17.13
root (hd0,2)
kernel /boot/mynewkernel/vmlinuz-2.6.17.13 root=/dev/sda3 ro quiet splash
savedefault
boot
4、安装模块
sudo make modules_install
reboot, 在grub启动菜单中选择新内核启动。