内核的解压缩过程详解
1、各种内核镜像之间的区别
参考博客:《vmlinuz/vmlinux、Image、zImage与uImage的区别》;
2、为什么内核需要解压缩
(1)需要解压缩是因为在制作内核镜像时进行了压缩,而压缩的镜像是不能直接执行的,内核镜像 = 未压缩的头部 + 压缩的内核;
(2)未压缩的头部主要功能就是将压缩的内核镜像解压缩后放到内存的合适地址处,然后调用解压缩的内核;
(3)将内核压缩的原因是未压缩的内核体积太大,压缩后可以节省存储空间。
(4)节省空间的代价就是内核启动过程更复杂,解压缩也会导致启动内核的时间更长。在现在复杂一些的嵌入式设备中,flash动辄就有几十个G,压缩内核节省的几兆空间其实影响不大,
所以个人觉得压缩内核对flash小的设备性价比高,对flash大的设备性价比不高,但是为了统一,都是采用了压缩的方式。
3、uboot启动内核的前期工作
(1)将内核镜像重定位到内存中,解析镜像的头部,找到内核镜像的入口地址;
(2)准备好机器码,tag参数地址或者dtb数据的地址;
(3)调用内核入口,将上一步准备好的数据传递给内核;
4、解压缩涉及的文件
(1)以arm架构的芯片为例:"arch/arm/boot/comperssed/"目录;
(2)分析镜像的程序入口和镜像组成结构,查看vmlinux.lds;
(3)整个镜像程序入口是在head.S文件中;
5、确认解压缩内核的存放地址
5.1、汇编代码
#ifdef CONFIG_AUTO_ZRELADDRmov r4, pc //当前PC的值保存到r4寄存器and r4, r4, #0xf8000000 //只保留高5位/* Determine final kernel image address. */add r4, r4, #TEXT_OFFSET //加上偏移量#TEXT_OFFSET
#elseldr r4, =zreladdr //在配置文件中指定解压缩的内核地址
#endif
5.2、CONFIG_AUTO_ZRELADDR宏
(1)上面汇编代码的功能就是计算出解压缩内核的存放地址,然后保存到r4寄存器中;
(2)定义了CONFIG_AUTO_ZRELADDR宏表示根据当前PC的值计算出解压缩后内核存放的地址,然后存放到r4寄存器;
(3)如果没有定义CONFIG_AUTO_ZRELADDR宏,则把zreladdr变量的值赋值给r4寄存器;
5.3、TEXT_OFFSET宏
(1)相对于内存起址的内核代码存放的偏移,通常设为 32k (0x8000);
(2)TEXT_OFFSET宏分析"arch/arm/boot/comperssed/Makefile"和"arch/arm/Makefile";
5.4、zreladdr变量
//arch/arm/boot/comperssed/Makefile
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
endif//arch/arm/boot/Makefile
ZRELADDR := $(zreladdr-y)//arch/arm/Mach-xxx/ Makefile.boot
在这里指定zreladdr-y的值
解压后内核存放的地址,也是最后解压后内核的运行起址,可以在配置文件中指定;
6、内核解压缩函数
6.1、汇编代码部分
* The C runtime environment should now be setup sufficiently.* Set up some pointers, and start decompressing.* r4 = kernel execution address* r7 = architecture ID* r8 = atags pointer*/mov r0, r4 //内核解压后存放的地址mov r1, sp @ malloc space above stackadd r2, sp, #0x10000 @ 64k maxmov r3, r7 //architecture ID:机器码bl decompress_kernel //执行解压zImage为elf格式的可执行kernel镜像bl cache_clean_flushbl cache_offmov r1, r7 @ restore architecture numbermov r2, r8 @ restore atags pointer//函数原型
void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, \unsigned long free_mem_ptr_end_p,int arch_id)
decompress_kernel函数传参 | 含义 |
---|---|
output_start | 内核解压缩后数据存放的起始内存地址 |
free_mem_ptr_p | 可用的内存起始地址 |
free_mem_ptr_end_p | 可用内存结束地址 |
arch_id | 机器码 |
(1)r4在这之前已经被存放了内核解压缩后存放的内存地址,这里将r4寄存器的值赋值给r0;
(2)sp是栈寄存器,r1寄存器的值是当前栈地址,r2寄存器的值是当前栈地址+64KB,效果就是在栈上面分配了64KB的内存空间传给decompress_kernel()函数;
(3)r3寄存器被赋值r7寄存器的值,是机器码;
(4)decompress_kernel()函数的4个传参分别对应r0-r3四个寄存器;
6.2、decompress_kernel()函数源码分析
//arch/arm/boot/compressed/piggy.S.section .piggydata,#alloc.globl input_data
input_data:.incbin "arch/arm/boot/compressed/piggy_data".globl input_data_end
input_data_end:void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,unsigned long free_mem_ptr_end_p, int arch_id)
{int ret;__stack_chk_guard_setup();//对一些全局变量赋值output_data = (unsigned char *)output_start; //解压缩后内核存放的内存地址free_mem_ptr = free_mem_ptr_p; //可用内存的起始地址free_mem_end_ptr = free_mem_ptr_end_p; //可用内存的结束地址__machine_arch_type = arch_id; //机器码//解压缩模块初始化arch_decomp_setup();putstr("Uncompressing Linux...");//(压缩内核镜像所在内存地址, 压缩内核镜像大小, 解压缩镜像的存放地址, 出错处理函数指针)ret = do_decompress(input_data, input_data_end - input_data,output_data, error);if (ret)error("decompressor returned an error");elseputstr(" done, booting the kernel.\n");
}
(1)do_decompress()函数才是真正做解压缩的函数,只需要将压缩内核镜像的地址和长度、解压缩内核存放地址等信息传进去,函数内部会根据配置项调用对应解压缩方法的函数,原则就是用什么压缩方法就用对应的解压缩方法;
(2)压缩内核镜像所在的起始地址和结束地址保存在input_data、input_data_end变量中,这在piggy.S文件中指定,具体可以分析链接脚本;
(3)piggy_data就是压缩后的内核镜像,生成的大致过程:vmlinux->Image->piggy_data->zImage->zImage-dtb;
7、调用解压缩的内核
b __enter_kernel__enter_kernel:mov r0, #0 @ must be 0ARM( mov pc, r4 ) @ call kernel 调用解压缩后的内核镜像M_CLASS( add r4, r4, #1 ) @ enter in Thumb mode for M classTHUMB( bx r4 ) @ entry point is always ARM for A/R classes
在内核解压缩阶段,已经把解压缩的内核放到了r4寄存器执行的内存地址,这里将r4寄存器的值赋值给PC寄存器,下面就是执行r4寄存器指向的内存地址,也就是内核的第一句代码。
内核的解压缩过程详解相关推荐
- linux系统启动过程详解-开机加电后发生了什么 --linux内核剖析(零)
本文参考了如下文章 深入理解linux启动过程 mbr (主引导记录(Master Boot Record)) 电脑从开机加电到操作系统main函数之前执行的过程 详解linux系统的启动过程及系统初 ...
- Linux学习之zImage内核镜像解压过程详解
zImage内核镜像解压过程详解 收藏 zImage内核镜像解压过程详解 作者: 刘洪涛,华清远见嵌入式培训中心 讲师. 本文以linux-2.6.14内核在S3C2410平台上运行为例,讲解内核 ...
- Linux开启动过程详解
Linux开启动过程详解 Linux启动过程 前言: Linux是一种自由和开放源代码的类UNIX操作系统.该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布.在加上用户空间的应用程序之后 ...
- tar 解压缩命令详解
2019独角兽企业重金招聘Python工程师标准>>> 今天对目录及其文件进行压缩: /usr/local/test# tar -cvf /usr/local/auto_bak/te ...
- tar 解压缩命令详解
对一下目录及其文件进行压缩: /usr/local/test # tar -cvf /usr/local/auto_bak/test.tar /usr/local/test 仅打包,不压缩 # ta ...
- centos7 启动流程图_Linux启动过程详解
Linux启动过程详解 作者:江远航 一.启动流程图如下 图1 Linux启动流程图 BIOS ---> MBR ---> Kernel---> Init 二.Linux启动顺序 一 ...
- Linux下的tar归档及解压缩功能详解
Linux下的tar归档及解压缩功能详解 一.Linux下解压缩工具 二.gzip工具的使用方法 三.其他解压缩工具 一.Linux下解压缩工具 二.gzip工具的使用方法 三.其他解压缩工具 一.L ...
- #转载:杨辉三角形实现过程详解-c语言基础
杨辉三角形实现过程详解-C语言基础 十一一个人 2018-12-26 06:45:45 6465 收藏 28 最后发布:2018-12-26 06:45:45首发:2018-12-26 06:45:4 ...
- U-Boot 之三 U-Boot 源码文件解析及移植过程详解
在之前的博文 Linux 之八 完整嵌入式 Linux 环境介绍及搭建说明 中我们说了要一步步搭建整个嵌入式 Linux 运行环境.我所使用的硬件平台及整个要搭建的嵌入式 Linux 环境见博文 ...
- U-Boot 之一 零基础编译 U-Boot 过程详解 及 编译后的使用说明
在之前的博文 Linux 之八 完整嵌入式 Linux 环境介绍及搭建过程详解 中我们说了要一步步搭建整个嵌入式 Linux 运行环境,今天就开始编译 U-Boot.我所使用的硬件平台及整个要搭建 ...
最新文章
- 原生编辑器_免费开源的GIF制作神器,可录屏幕/摄像头/画板,自带编辑器
- SQL语言之执行计划(Oracle)
- cpu,内核和逻辑处理器的关系
- 第一个Swift程序Hello World
- java udp 缓冲区_为什么特定的UDP消息总是低于特定的缓冲区大小?
- gis差值分析_新视窗产品展播(七) | BIM+GIS征地拆迁信息化管理平台
- LeetCode 97: 交错字符串
- Python中如何读取xml的数据
- 【BZOJ1096】仓库建设,斜率优化DP练习
- 团队组成五个基本要素_如何进行团队建设和团队沟通
- Lightroom Classic mac版怎样创建全景图和HDR全景图?
- Lesson 01 for Plotting in R for Biologists
- Qt 动图 播放png阵列 避免使用gif导致失真
- css3实现奔跑的小人动画
- Qt控件之toggle()、triggered()、clicked()——triggered发射信号无响应
- IntelliJ IDEA现有项目连接SVN(2)
- 搜狐狐友社交软件可以组合各个产品的用户量
- 转:用AutoCAD 系统变量编程
- 关于 *.csproj: 找不到此项目类型所基于的应用程序 的解决方案
- 海康相机html网页源码,海康摄像头 Web3.2_控件