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内核镜像解压,解压内核镜像相关推荐

  1. 【正点原子Linux连载】第三十五章 Linux内核顶层Makefile详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  2. LINUX操作系统的内核编译内幕详解一

    内核简介 内核,是一个操作系统的核心.它负责管理系统的进程.内存.设备驱动程序.文件和网络系统,决定着系统的性能和稳定性. Linux的一个重要的特点就是其源代码的公开性,所有的内核源程序都可以在/u ...

  3. uboot linux内核传递参数,Uboot与Linux之间的参数传递详解

    原标题:Uboot与Linux之间的参数传递详解 U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等.而Linux kernel也会读取和处理这些参数.两者之间通 ...

  4. Linux下安装nginx (tar解压版安装) nginx1.16.1

    https://blog.csdn.net/qq_40431100/article/details/104729504 Linux下安装nginx (tar解压版安装) nginx1.16.1 Jkc ...

  5. Linux设备驱动开发详解 第3版 (即 Linux设备驱动开发详解 基于最新的Linux 4 0内核 )前言

    Linux从未停歇脚步.Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核.做技术,从来没有终南捷径,拼的就是坐冷板凳的 ...

  6. Linux下各压缩工具的解压压缩命令

    Linux下各压缩工具的解压压缩命令 FileName 代表文件,DirName 代表目录,DirName/* 代表目录及子目录 tar命令 解包:tar xvf FileName.tar 打包:ta ...

  7. linux上 用unzip命令解压带密码保护的 zip 文件报错 unsupported compression method 99

    1.问题: Linux上用 unzip 命令解压带密码保护的 zip 文件报错 unsupported compression method 99 2.解决办法: mac自带的解压工具,无法解密加密的 ...

  8. 解压安装包linux,Linux 下载安装 rar 并解压rar压缩包(Linux下如何解压.zip和.ra

    Linux 下载安装 rar 并解压rar压缩包(Linux下如何解压.zip和.ra Linux 下载安装 rar 并解压rar压缩包(Linux下如何解压.zip和.rar文件) Linux下如何 ...

  9. linux shell脚本自动批量解压文件

    单个文件解压很简单,批量不确定目录的压缩包呢?解压到原路径?解压后删除原压缩包?本脚本可一键解决以上所有问题 linux shell脚本自动批量解压文件 脚本免费下载地址: 传送门https://do ...

最新文章

  1. Shiro中的Remember me设置
  2. 多年密谋「闹独立」,谷歌为何拴不住DeepMind的心?
  3. [组图]海报:计算机的爱
  4. nedc和epa续航里程什么意思_了解 NEDC 之后 我发现电动车的续航还是得实测
  5. RunLoop已入门?不来应用一下?
  6. 关于一些Excel宏病毒的清除方法整理合集
  7. 7系列高速收发器简介 GTP IP核
  8. jquery 时间选择插件-jedate
  9. zktime 协议_zktime5.0考勤管理系统使用说明书(1.2版).pdf
  10. 常用编码说明-GB2312
  11. 360数科知微实验室发布反诈报告:揭秘黑灰产数据流转真相
  12. 近几十年基础科学的停滞影响研究
  13. 山东养殖业稳中有升,饲料企业较乐观
  14. 读《学会提问》有感(一)
  15. StringBuffer的equals
  16. 如何表示Unicode的字符?
  17. 01_搭建百度apollo环境实操可用
  18. 涂鸦Wi-FiBLE SoC开发幻彩灯带(5)----烧录授权
  19. 空中群体机器人研究综述
  20. BT TWS方案开发感悟

热门文章

  1. python3 面向对象详解_Python3面向对象
  2. 实验7.2 二维数组 7-4 判断上三角矩阵
  3. php 获取返回值,求助 如何获取php socket 返回值
  4. 每日程序C语言43-链表原地逆置
  5. Linux五部分的含义,Linux 目录下部分重要目录的用途及含义及一些命令的作用
  6. Java黑皮书课后题第7章:7.9(找出最小元素)使用下面的方法头编写一个方法,求出一个整数数组中的最小元素。编写测试程序,提示用户输入10个数字,调用这个方法返回最小值,并显示这个最小值
  7. 设计桑基图_教你用pyecharts制作交互式桑基图,赶快学起来吧!
  8. DevExpress WPF v18.2新版亮点(四)
  9. SpringBoot入门:新一代Java模板引擎Thymeleaf(实践)
  10. 直接用img 的src属性显示base64转码后的字符串成图片【原】