高通8996启动流程-4. lk启动之boot_linux_from_mmc
1.前言
本文档主要对MSM8996的启动流程进行一个简要的分析,目的在于展现启动流程的概貌,不会对每个细节做很详细的表述,但会对启动流程的关键节点进行重点说明。在lk正常启动时会进入boot_linux_from_mmc。
2. boot_linux_from_mmc
boot_linux_from_mmc主要完成了bootimg读取到缓存,解压kernel,重定位kernel, ramdisk, dtb,并最终启动kernel,启动的同时会向kernel传递dtb地址,dtb的chosen保存了cmdline, 同时保存了ramdisk的起止地址。
check_format_bit
get_ffbm
uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
此处获取到了boot image头部的信息所在的内存地址,通过调用 memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE),来判断0x8F6FF000 (EMMC_BOOT_IMG_HEADER_ADDR)是否和 boot.img 头的 MAGIC 值"ANDROID!" 相同。如果相同,则直接按照这个内存地址来启动系统,不再从emmc 中读取,直接启动Linuxmmc_read(ptn + offset, (uint32_t *) buf, page_size):从boot/recovery分区读取boot_img_hdr到全局变量buf中
对读取的内容进行基本的合法判断:
(1)header->MAGIC是否是ANDROID, 如果不是则异常退出
(2)读取到的header->page_size是否与PAGE_SIZE相等,如果不相等,根据读取到的header->page_size对page_size全局变量重新赋值,重新赋值page_mask对读取到的image header的kernel大小,ramdisk大小 向上取到PAGE_SIZE的整数倍
kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
second_actual = ROUND_TO_PAGE(hdr->second_size, page_mask);mage_addr = (unsigned char *)target_get_scratch_address()初始化image缓存地址,用于存放从boot分区读取到的image。image_addr这个值是 boot.img 在内存的缓存地址,缓存的地址由 SCRATCH_ADDR 宏指定,这个宏定义在target/msm8916/rules.mk 文件中,我们看到这个地址实际为0x91E00000
memcpy(image_addr, (void *)buf, page_size); 前面说全局变量buf中存放boot_img_hdr,此处将其拷贝到image_addr中,大小为1个page
imagesize_actual = (page_size + kernel_actual + ramdisk_actual + second_actual + dt_actual);
初始化image大小,page_size为image header大小,kernel, ramdisk, dt大小均从boot image header中获取。dt大小在mkbootimg命令运行时写入,看mkbootimg中注释说是假设是一个pageboot_verifier_init
check_aboot_addr_range_overlap((uint32_t) image_addr, imagesize_actual)
检查打算存放boot image的内存地址与当前运行的aboot是否有地址空间重叠部分mmc_read(ptn + offset, (void *)(image_addr + offset), imagesize_actual - page_size)
从boot/recovery分区读取镜像到image_addr地址(不读取image_header和signature)mmc_read(ptn + offset, (void *)(image_addr + offset), page_size)
对于需要验证签名的bootimage,还需要将签名读取到起始地址为image_addr,此处offset为imagesize_actual的位置,也就是将签名读取到image_addr+imagesize_actual的位置verify_signed_bootimg((uint32_t)image_addr, imagesize_actual);
对上述签名进行验证is_gzip_package((unsigned char *)(image_addr + page_size), hdr->kernel_size)
判断内核是否是压缩的,其中page_size为boot image头部大小
decompress((unsigned char *)(image_addr + page_size),
hdr->kernel_size, out_addr, out_avai_len,
&dtb_offset, &out_len)
如果内核是压缩的,则需要对内核进行解压缩,对kernel进行解压缩操作,解压缩后的内核存放到kernel_start_addr=image_addr +imagesize_actual+4k=0x91E00000+imagesize_actual+4k, kernel的大小为hdr->kernel_size
注:imageaddr这个值是boot image 在内存的缓存地址,缓存的地址由 SCRATCH_ADDR 宏指定,这个宏定义在target/msm8916/rules.mk 文件中
到目前为止已经将boot.img读取到缓存地址0x91E00000处,并且将压缩的kernel解压到kernel_start_addr处
- update_ker_tags_rdisk_addr(hdr, IS_ARM64(kptr));
一般情况下kernel地址,dtb地址,ramdisk地址由mkbootimage工具来指定为默认值,如果没有指定默认值则采用platform/msm8996/include/platform/iomap.h中定义的kernel地址,dtb地址,ramdisk地址来更新hdr(boot image header),此处使用了iomap.h中定义的如下:
其中DDR_STRT的地址为0x80000000
hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));
hdr->ramdisk_addr = VA((addr_t)(hdr->ramdisk_addr));
hdr->tags_addr = VA((addr_t)(hdr->tags_addr));
获取虚拟地址,此处由于没有开MMU,虚拟地址与物理地址相同check_aboot_addr_range_overlap
检查要拷贝的目标kernel地址和ramdisk地址是否会与aboot重合将解压后的kernel镜像和ramdisk镜像拷贝到image header所指定的位置,也就是重定位
memmove((void*) hdr->kernel_addr, kernel_start_addr, kernel_size);
memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);dev_tree_validate(table, hdr->page_size, &dt_hdr_size) 验证DTS
dev_tree_get_entry_info(table, &dt_entry)
decompress 如果dtb压缩了,则需要解压缩
check_aboot_addr_range_overlap(hdr->tags_addr, dtb_size) 验证hdr->tags_addr是否会越界到aboot
memmove((void *)hdr->tags_addr, (char *)best_match_dt_addr, dtb_size) 将解压后的dts拷贝到hdr->tags_addr
到目前为止,我们可以看到形成如下的内存布局,当前kernel,dtb,ramdisk分别位于如下红色框内.
至此我们所关心的几个问题:
Q: 磁盘中boot分区的boot.img被读取到内存的哪个位置?
A: image_addr这个值是boot.img 在内存的缓存地址,缓存的地址由 SCRATCH_ADDR宏指定,这个宏定义在target/msm8916/rules.mk 文件中,我们看到这个地址实际为0x91E00000Q:bootimg中kernel, ramdisk,dtb的size如何确定?
A:主要是在编译时由mkbootimg工具通过读取输出目录中kernel和ramdisk文件的大小来获取,dtb大小默认为4k,一个pageQ: kernel解压后的应该放到内存的哪个位置? A: 通过boot.img存放地址为起始地址, 在偏移kernel_size +
ramdisk_size + dtb_size大小的位置 其中dtb默认为4KQ:kernel解压后被重定位到哪个位置?
A:由LK的platform/msm8996/include/platform/iomap.h指定了kernel, ramdisk,
dtb的重定位的位置注:看4.9的内核对于ARM64,编译的时候会将vmlinux拷贝成Image,然后将Image进行gzip压缩为Image.gz。之后通过cat将Image.gz和DTB写入Image.gz-dtb,Image.gz-dtb与ramdisk一起组成了boot.img,此处dtb应该是被与kernel打包l组合在一起
25.boot_linux((void *)hdr->kernel_addr, (void *)hdr->tags_addr, (const char *)hdr->cmdline, board_machtype(), (void *)hdr->ramdisk_addr, hdr->ramdisk_size)
从kernel_addr启动kernel,同时传递了如下几个参数:
kernel地址,dtb地址,cmdline地址,板子类型,ramdisk地址,ramdisk大小
注:此处的tags_addr就是dts地址
3.boot_linux
1.upadate_cmdline
解析当初通过mkbootimg命令传入的—cmdline参数,更新到final_cmdline中。命令mkbootimg通过—cmdline参数传递的值会被保存到boot.img的头部,此处就是通过解析boot.img的头部来更新final_cmdline
2.update_device_tree
主要更新了如下内容:
(1)更新了memory的起始地址和大小到DTS;
(2)将ramdisk起止地址更新到chosen
3.scm_elexec_call
调用执行Linux内核,此处可以看到,通过scm_arg传递了如下的信息:
(1)kernel地址
(2)dts地址, dtb中的chosen中保存了cmdline以及ramdisk的起止地址
4.通过SMC调用会进入到安全世界QSEE,并由安全世界引导kernel执行
注:trustzone可以理解为安全世界,它跑的代码为QSEE对标ARM的arm trust firmware
4.总结
- 从boot/recovery分区读取boot.img镜像到image_addr地址
- 解压kernel到kernel_start_addr地址处
- 重定位kernel ramdisk, dtb
- 解析并保存cmd_line
- 更新DTS,包括增加memory的起始地址和大小到DTS;将ramdisk起止地址更新到chosen
- 启动kernel,启动的同时会向kernel传递dtb地址,dtb的chosen保存了cmdline, 同时保存了ramdisk的起止地址,这样内核起来后会找到cmdline和ramdisk解析和挂载
高通8996启动流程-4. lk启动之boot_linux_from_mmc相关推荐
- 高通8996启动流程-4. lk启动之mkbootimg工具
1.前言 Android在编译过程中会调用mkbootimg命令,mkbootimg是生成boo.img的命令,boot.img中包含了kernel, dtb, ramdisk等. 2. mkboot ...
- 深入理解Activity启动流程(三)–Activity启动的详细流程2
本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--A ...
- 深入理解Activity启动流程(二)–Activity启动相关类的类图
本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先 ...
- App 启动流程与 Activity 启动流程梳理
目录 前言 流程图 启动流程 第一阶段(Launcher 向 AMS 发送启动请求) 第二阶段(AMS 启动 Activity, 并告知 Launcher pasue) 第三阶段 (App 进程的 A ...
- 高通CamX-CHI关键流程
深入理解高通 Camx CHI 架构 - SegmentFault 思否 高通CamX关键流程 - 云+社区 - 腾讯云 CamX关键流程 - 简书
- 高通8996启动流程-3. sbl1启动流程
目录 1. 前言 2. sbl1总体流程 3.sbl1_main_ctl(pbl_shared)流程 4. boot_config_process_bl 4.1 Execute pre_procs 4 ...
- 高通8996启动流程-1.概述
1.前言 本文档主要对MSM8996的启动流程进行一个简要的分析,目的在于展现启动流程的概貌,不会对每个细节做很详细的表述,但会对启动流程的关键节点进行重点说明. 2.关键术语 Hexagon Dig ...
- 高通8996启动流程-2.总体启动流程
1.前言 本文档主要对MSM8996的启动流程进行一个简要的分析,目的在于展现启动流程的概貌,不会对每个细节做很详细的表述,但会对启动流程的关键节点进行重点说明.本文主要通过框图的方式展现bootlo ...
- linux uboot启动流程分析,uboot启动流程分析
uboot版本为NXP维护的2016.03版本 下载地址为http://git.freescale.com/git/... 分析uboot的启动流程,需要编译一下uboot,然后打开链接脚本 u-bo ...
最新文章
- 如何才能识别市场趋势?[转]
- ArrayList遍历
- iOS中AVFoundation的简单使用—音乐的播放
- SAP CRM和C4C的产品主数据price维护
- Python并发编程:多进程-守护进程
- 【Python自动化运维之路Day6】
- Newtonsoft.Json 方法使用()
- java代码读取dbsequence的值_JDBC读取新插入Oracle数据库Sequence值的5种方法
- java通信方式_java 认知底层的五种通信方式
- python简单代码-用Python代码实现5种最好的、简单的数据可视化!
- C语言中将数字形式的字符串转换为数字的方法
- 企业微信--扫一扫功能(隐形坑)
- viterbi 中文分词-超简单版
- 三十六计之借刀杀人(第三计)
- [软件人生]抢钱的电影与现在的软件开发
- PNI12927磁场强度传感器--金属检测实现方案
- 电脑重启bootmgr_Windows系统启动不了如何修复?Bootmgr/NTLDR is missing解决方法
- 破解XCode 3.2.5 免证书运行程序到 真机ipod(已破解)
- 自学python能干些什么副业-工作多年,总结出几个比较野的副业路子!
- 股票日内交易策(源码)
热门文章
- uniapp小程序实现弹幕功能
- PPIO PRoute —— 为当下全球互联网量身定做的智能路由
- 个人感悟—来自Google的TCP BBR拥塞控制算法解析
- Xcode 8新功能介绍
- mysql btree索引原理_Postgres BTREE索引原理简单介绍
- Mac Maya2017 ViewCube(视图盒子)不显示问题解决
- linux运维可视化工具,试用Grafana:一个自动化运维常用的可视化开源工具
- Windows10,夜间模式失效?
- winserver搭建smtp_如何在服务器搭建本地smtp邮件服务
- PPT母版怎么应用到每张幻灯片?