linux内核镜像解压,解压内核镜像
uboot 将 zimage 复制到内存之后,跳转到 zimage 处开始执行,首先执行的代码是
arch/arm/boot/compressed/head.s 文件,首先是一些涉及不同体系结构调试相关的汇编宏定义
#ifdef debug
#if defined(config_debug_icedcc)
#if defined(config_cpu_v6) || defined(config_cpu_v6k) || defined(config_cpu_v7)
.macro loadsp, rb, tmp
.endm
.macro writeb, ch, rb
mcr p14, 0, \ch, c0, c5, 0
.endm
... 省略 ...
#endif
#endif
#endif
步骤 1
首先是保存 bootloader 传递过来的机器 id 和 atags 起始地址
@ 设置段名
.section ".start", #alloc, #execinstr
.align
.arm @ 设置指令为 arm 模式
start:
.type start,#function @ 声明为函数标签
.rept 7
mov r0, r0
.endr
arm( mov r0, r0 )
arm( b 1f ) @ 向下跳转
thumb( adr r12, bsym(1f) )
thumb( bx r12 )
.word 0x016f2818 @ magic numbers to help the loader
.word start @ 程序其实地址,即 zimage 的地址
.word _edata @ zimage 结束地址
thumb( .thumb )
1: mov r7, r1 @ 保存 bootloader 传递过来的机器 id
mov r8, r2 @ 保存 bootloader 传递过来的 atags 起始地址
步骤 2
关闭中断、进入 svc 模式
#ifndef __arm_arch_2__
mrs r2, cpsr @ get current mode
tst r2, #3 @ not user?
bne not_angel
mov r0, #0x17 @ 进入 svc 模式
arm( swi 0x123456 ) @ angel_swi_arm
thumb( svc 0xab ) @ angel_swi_thumb
not_angel:
mrs r2, cpsr
orr r2, r2, #0xc0 @ 关闭 fiq 和 irq
msr cpsr_c, r2
#else
teqp pc, #0x0c000003 @ turn off interrupts
步骤 3
为了加速解压过程,打开缓存
#ifdef config_auto_zreladdr
@ 如果配置了运行时自动计算重定位地址
@ 则根据当前 pc 位置和 text_offset 计算出解压位置
@ text_offset 在 arch/arm/makefile 中指定,表示的是相对于内存起始地址的偏移
@ 定义为 textofs-y := 0x00008000 text_offset := $(textofs-y)
mov r4, pc
and r4, r4, #0xf8000000 @ 这里假设 zimage 是被放在内存的前 128mb 内的
add r4, r4, #text_offset @ 得到 zimage 解压的物理地址
#else
@ 这里是直接在 arch/arm/mach-s5p4418/makefile.boot 中定义的
@ 定义为 zreladdr-y := 0x40008000
ldr r4, =zreladdr @ r4 存放解压后内核存放的起始地址
#endif
@ 打开缓存和 mmu
bl cache_on
步骤 4
检查解压后的内核镜像是否与当前镜像发生覆盖
restart: adr r0, lc0
ldmia r0, {r1, r2, r3, r6, r10, r11, r12} @ 将 lc0 数据放入寄存器中
ldr sp, [r0, #28] @ 更新栈指针位置
sub r0, r0, r1 @ 计算当前程序位置和链接地址间的偏移量
add r6, r6, r0 @ 得到 zimage 运行地址的结束位置
add r10, r10, r0 @ 存放未压缩内核大小的运行地址
/*
* 内核编译系统会将未压缩的内核大小追加到压缩后的内核数据之后
* 并以小端格式存储
*/
@ 取出未压缩内核大小放入 r9
ldrb r9, [r10, #0]
ldrb lr, [r10, #1]
orr r9, r9, lr, lsl #8
ldrb lr, [r10, #2]
ldrb r10, [r10, #3]
orr r9, r9, lr, lsl #16
orr r9, r9, r10, lsl #24
#ifndef config_zboot_rom
/* 在栈指针之上分配内存空间放到 r10 中 (64k max) */
add sp, sp, r0
add r10, sp, #0x10000
#else
mov r10, r6
#endif
mov r5, #0 @ init dtb size to 0
/*
* 检查解压后的内核是否会覆盖当前代码
* r4 = 最终解压后的内核起始地址
* r9 = 解压后的内核镜像大小
* r10 = 当前镜像结束地址,其中包括所分配的内存区域
* we basically want:
* r4 - 16k 页表 >= r10 -> ok
* r4 + image length <= address of wont_overwrite -> ok
*/
add r10, r10, #16384 @ 内核镜像前的 16kb 页表
cmp r4, r10
bhs wont_overwrite @ 解压后的内核起始地址大于等于 r10
add r10, r4, r9
adr r9, wont_overwrite
cmp r10, r9 @ 或者解压后的内核结束地址在 wont_overwrite 地址之前
bls wont_overwrite
/*
* r6 = _edata
* r10 = end of the decompressed kernel
*/
@ 当前代码段向后移动到的目的地址,不足 256 字节的补足 256 字节,向上取整
add r10, r10, #((reloc_code_end - restart + 256) & ~255)
bic r10, r10, #255
@ 当前代码段起始地址,以 32 字节为单位,向下取整
adr r5, restart
bic r5, r5, #31
sub r9, r6, r5 @ 需要移动镜像的大小
add r9, r9, #31 @ 以 32 字节为单位向上取整
bic r9, r9, #31
add r6, r9, r5 @ 循环结束地址
add r9, r9, r10 @ 目的地址结束位置
@ 循环移动当前镜像
1: ldmdb r6!, {r0 - r3, r10 - r12, lr}
cmp r6, r5
stmdb r9!, {r0 - r3, r10 - r12, lr}
bhi 1b
sub r6, r9, r6 @ 代码重定位的偏移地址
#ifndef config_zboot_rom
add sp, sp, r6 @ 对栈指针也进行重定位
#endif
bl cache_clean_flush
@ 跳转到重定位后的镜像 restart 处重新执行,检查是否存在覆盖
adr r0, bsym(restart)
add r0, r0, r6
mov pc, r0
步骤 5
清理 bss 段、解压内核、关闭缓存,最后启动内核
/* 至此,当前镜像和解压后的内核不会发生覆盖问题 */
wont_overwrite:
/*
* if delta is zero, we are running at the address we were linked at.
* r0 = delta
* r2 = bss start
* r3 = bss end
* r4 = kernel execution address
* r5 = appended dtb size (0 if not present)
* r7 = architecture id
* r8 = atags pointer
* r11 = got start
* r12 = got end
* sp = stack pointer
*/
orrs r1, r0, r5
beq not_relocated
add r11, r11, r0
add r12, r12, r0
not_relocated: mov r0, #0
1: str r0, [r2], #4 @ 清理 bss 段
str r0, [r2], #4
str r0, [r2], #4
str r0, [r2], #4
cmp r2, r3
blo 1b
/*
* 至此,c 语言运行环境已经初始化完成
* r4 = 解压后的内核起始地址
* r7 = 机器 id
* r8 = atags 指针
*/
mov r0, r4
mov r1, sp @ 在栈指针之上分配内存空间
add r2, sp, #0x10000 @ 64k max
mov r3, r7
bl decompress_kernel @ 解压内核
bl cache_clean_flush
bl cache_off @ 关闭缓存
mov r0, #0 @ must be zero
mov r1, r7 @ restore architecture number
mov r2, r8 @ restore atags pointer
arm( mov pc, r4 ) @ 启动内核
thumb( bx r4 ) @ entry point is always arm
.align 2
.type lc0, #object
lc0: .word lc0 @ r1:lc0 的链接地址
.word __bss_start @ r2:bss 段的起始地址
.word _end @ r3:bss 段的结束地址
.word _edata @ r6:zimage 的结束地址
.word input_data_end - 4 @ r10:存放未压缩的内核大小的链接地址
.word _got_start @ r11:全局偏移表起始位置
.word _got_end @ ip:全局偏移表结束位置
.word .l_user_stack_end @ sp:栈指针
.size lc0, . - lc0 @ 该 lc0 数据的大小
linux内核镜像解压,解压内核镜像相关推荐
- 【正点原子Linux连载】第三十五章 Linux内核顶层Makefile详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...
- LINUX操作系统的内核编译内幕详解一
内核简介 内核,是一个操作系统的核心.它负责管理系统的进程.内存.设备驱动程序.文件和网络系统,决定着系统的性能和稳定性. Linux的一个重要的特点就是其源代码的公开性,所有的内核源程序都可以在/u ...
- uboot linux内核传递参数,Uboot与Linux之间的参数传递详解
原标题:Uboot与Linux之间的参数传递详解 U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等.而Linux kernel也会读取和处理这些参数.两者之间通 ...
- Linux下安装nginx (tar解压版安装) nginx1.16.1
https://blog.csdn.net/qq_40431100/article/details/104729504 Linux下安装nginx (tar解压版安装) nginx1.16.1 Jkc ...
- Linux设备驱动开发详解 第3版 (即 Linux设备驱动开发详解 基于最新的Linux 4 0内核 )前言
Linux从未停歇脚步.Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核.做技术,从来没有终南捷径,拼的就是坐冷板凳的 ...
- Linux下各压缩工具的解压压缩命令
Linux下各压缩工具的解压压缩命令 FileName 代表文件,DirName 代表目录,DirName/* 代表目录及子目录 tar命令 解包:tar xvf FileName.tar 打包:ta ...
- linux上 用unzip命令解压带密码保护的 zip 文件报错 unsupported compression method 99
1.问题: Linux上用 unzip 命令解压带密码保护的 zip 文件报错 unsupported compression method 99 2.解决办法: mac自带的解压工具,无法解密加密的 ...
- 解压安装包linux,Linux 下载安装 rar 并解压rar压缩包(Linux下如何解压.zip和.ra
Linux 下载安装 rar 并解压rar压缩包(Linux下如何解压.zip和.ra Linux 下载安装 rar 并解压rar压缩包(Linux下如何解压.zip和.rar文件) Linux下如何 ...
- linux shell脚本自动批量解压文件
单个文件解压很简单,批量不确定目录的压缩包呢?解压到原路径?解压后删除原压缩包?本脚本可一键解决以上所有问题 linux shell脚本自动批量解压文件 脚本免费下载地址: 传送门https://do ...
最新文章
- Shiro中的Remember me设置
- 多年密谋「闹独立」,谷歌为何拴不住DeepMind的心?
- [组图]海报:计算机的爱
- nedc和epa续航里程什么意思_了解 NEDC 之后 我发现电动车的续航还是得实测
- RunLoop已入门?不来应用一下?
- 关于一些Excel宏病毒的清除方法整理合集
- 7系列高速收发器简介 GTP IP核
- jquery 时间选择插件-jedate
- zktime 协议_zktime5.0考勤管理系统使用说明书(1.2版).pdf
- 常用编码说明-GB2312
- 360数科知微实验室发布反诈报告:揭秘黑灰产数据流转真相
- 近几十年基础科学的停滞影响研究
- 山东养殖业稳中有升,饲料企业较乐观
- 读《学会提问》有感(一)
- StringBuffer的equals
- 如何表示Unicode的字符?
- 01_搭建百度apollo环境实操可用
- 涂鸦Wi-FiBLE SoC开发幻彩灯带(5)----烧录授权
- 空中群体机器人研究综述
- BT TWS方案开发感悟
热门文章
- python3 面向对象详解_Python3面向对象
- 实验7.2 二维数组 7-4 判断上三角矩阵
- php 获取返回值,求助 如何获取php socket 返回值
- 每日程序C语言43-链表原地逆置
- Linux五部分的含义,Linux 目录下部分重要目录的用途及含义及一些命令的作用
- Java黑皮书课后题第7章:7.9(找出最小元素)使用下面的方法头编写一个方法,求出一个整数数组中的最小元素。编写测试程序,提示用户输入10个数字,调用这个方法返回最小值,并显示这个最小值
- 设计桑基图_教你用pyecharts制作交互式桑基图,赶快学起来吧!
- DevExpress WPF v18.2新版亮点(四)
- SpringBoot入门:新一代Java模板引擎Thymeleaf(实践)
- 直接用img 的src属性显示base64转码后的字符串成图片【原】