一、什么是BootLoader

BootLoader代码是芯片复位后,进入操作系统之前执行的一段代码。主要用于完成由硬件启动到操作系统启动的过渡,从而为操作系统提供基本的运行环境。

BootLoder主要的启动流程可以概括为:PBL阶段、SBL阶段、LK阶段。之后会加载并启动kernel。

二、名词解释


5个处理器: 

  1. APPS :Cortex A53 core(MSM8953),运行android。
  2. RPM(Resource Power Manager):CortexM3 core,主要用于低功耗应用。
  3. Modem(MSS_QDSP6) :高通自有指令集处理器,处理3G、4G通信协议等。
  4. Pronto(WCNSS): 处理wifi相关代码。
  5. LPASS :音频相关。

启动相关: 

  1. PBL(Primary Boot Loader):位于芯片内ROM中,是芯片上电后执行的真正第一行代码,在正常启动流程中会加载SBL1。如果启动异常会虚拟出9008端口可用于 Emergency download(短接板子上的force_boot_from_usb引脚(MSM8953 为gpio37)到1.8v可以强制进入紧急下载模式)。(此段代码封装在芯片内部,并不开源)
  2. SBL1 (Second BootLoader stage 1) :位于eMMC中,由PBL加载,初始化buses、DDR、clocks等。
  3. QSEE/TrustZone  安全相关。
  4. Debug Policy 调试相关。
  5. APPSBL :即为BootLoader,目前使用LK(little kernel)。
  6. HLOS (High LevelOperating System) 即为Linux/Android。

三、启动流程

  1. AP侧CPU上电。
  2. 在芯片内部ROM的PBL首先运行,PBL会从boot device(eMMC)中加载并验证SBL1到TCM中。这里的TCM可以理解为CPU的二级缓存。既然PBL能够从boot device(eMMC)中加载SBL1,那PBL应该是初始化过boot device的。
  3. SBL1初始化DDR,并从boot device中加载并且校验如下镜像: QSEE或者TZ镜像、QHEE镜像、RPM_FW、镜像、APPSBL等。
  4. SBL1加载并验证完上述镜像后,即将执行权转移到QSEE中,QSEE将设置并初始化一个安全的执行环境。
  5. QSEE通知RPM去执行RPM_FW相关代码。
  6. QSEE将执行权转移到APPSBL中,APPSBL也就是LK。
  7. LK加载HLOS的kernel。

四、代码流程简要流程

SBL

PBL部分并不开源,所以从SBL开始。

sbl1入口: sbl1.s

此部分代码路径在:boot_images/core/boot/secboot3/hw/msm89xx/sbl1/sbl1.s,此文件引导处理器,主要有实现如下操作:

部分源码:

  • 设置硬件,继续boot进程。
  • 初始化ddr。
  • 加载Trust_Zone操作系统。
  • 加载RPM固件。
  • 加载APPSBL然后继续boot进程。
IMPORT |Image$$SBL1_SVC_STACK$$ZI$$Limit|
IMPORT |Image$$SBL1_UND_STACK$$ZI$$Limit|
IMPORT |Image$$SBL1_ABT_STACK$$ZI$$Limit|
IMPORT boot_undefined_instruction_c_handler
IMPORT boot_swi_c_handler
IMPORT boot_prefetch_abort_c_handler
IMPORT boot_data_abort_c_handler
IMPORT boot_reserved_c_handler
IMPORT boot_irq_c_handler
IMPORT boot_fiq_c_handler
IMPORT boot_nested_exception_c_handler
IMPORT sbl1_main_ctl #主要关注此函数
IMPORT boot_crash_dump_regs_ptr
...

sbl1_main_ctl函数

路径:...\sbl1\sbl1_mc.c

/* Calculate the SBL start time for use during boot logger initialization. */
sbl_start_time = CALCULATE_TIMESTAMP(HWIO_IN(TIMETICK_CLK));
boot_clock_debug_init();
/* Enter debug mode if debug cookie is set */
sbl1_debug_mode_enter();
/* Initialize the stack protection canary */
boot_init_stack_chk_canary();/* Initialize boot shared imem */
boot_shared_imem_init(&bl_shared_data);
/*初始化RAM*/
boot_ram_init(&sbl1_ram_init_data);
/*初始化log系统,即串口驱动*/
sbl1_boot_logger_init(&boot_log_data, pbl_shared);
/*检索PBL传递过来的数据*/
sbl1_retrieve_shared_info_from_pbl(pbl_shared);
/* Initialize the QSEE interface */
sbl1_init_sbl_qsee_interface(&bl_shared_data,&sbl_verified_info);
/* Initialize SBL memory map. Initializing early because drivers could be located in RPM Code RAM. */
sbl1_populate_initial_mem_map(&bl_shared_data);
/*初始化DAL*/
boot_DALSYS_InitMod(NULL);
/*配置PMIC芯片,以便我们能通过PS_HOLD复位*/
sbl1_hw_init();
/*执行sbl1的目标依赖进程*/
boot_config_process_bl(&bl_shared_data, SBL1_IMG, sbl1_config_table);

sbl1_config_table函数

路径:boot_images\core\boot\secboot3\hw\msmxxxx\sbl1\sbl1_config.c

sbl1_config_table为一个结构体数组,里面存储了加载QSEE、RPM、APPSBL等镜像所需要的配置参数及执行函数。

boot_configuration_table_entry sbl1_config_table[] =
{/* SBL1 -> QSEE */{SBL1_IMG,                   /* host_img_id */CONFIG_IMG_QC,              /* host_img_type */GEN_IMG,                    /* target_img_id */CONFIG_IMG_ELF,             /* target_img_type */...load_qsee_pre_procs,        /* pre_procs */ load_qsee_post_procs,       /* post_procs */
}
/* SBL1 -> QHEE */
...
/* SBL1 -> RPM */
...
/* SBL1 -> APPSBL (即lk部分) */
...

LK

LK大概流程:

bootloader/lk目录结构:

  • 进行各种早期的初始化工作,包括 cpu, emmc, ddr, clocks, thread 等。
  • 判断进入 recovery 或 fastboot 的条件是否被触发,不触发则为Normal Boot。
  • 从 emmc 中获取 boot.img 并加载到指定内存区域 (scratch region)。
  • 加载Kernel、Ramdisk、DeviceTree等到指定地址。
  • 引导Kernel
-app        #应用相关
-arch       #arm体系、CPU架构
-dev        #设备驱动
-images     #image图片资源
-include    #头文件
-kernel     #LK系统、主文件,main.c
-lib        #库文件
-platform   #平台文件,如:msm8916
-project    #mk文件
-scripts    #脚本文件
-target     #目标设备文件

代码流程: 

lk 是使用 arm 汇编 和 c 语言联合编译而成的,其中偏向硬件和底层的代码使用 arm 汇编 编写,而偏上层提供功能的代码则使用 c 编写。

入口:

lk 代码的入口点是在 arch/arm 目录下的以 .ld 为后缀的 link 脚本文件中指定。

指定的入口点均为位于 arch/arm/crt0.S 文件中的 _start 函数:

  • system-onesegment.ld
  • system-twosegment.ld

_start 最主要的作用是设置一些 cpu 的特性,然后初始化各种 c 程序运行需要的栈环境,完成后直接跳转到 kmian 函数进入 c 语言环境。

Kmain()函数:

void kmain(void)
{thread_init_early(); // 初始化化lk线程上下文arch_early_init(); // 架构初始化,如关闭cache,使能mmuplatform_early_init(); // 平台硬件早期初始化target_early_init(); //目标设备早期初始化bs_set_timestamp(BS_BL_START);call_constructors(); //静态构造函数初始化heap_init(); // 堆初始化thread_init(); // 初始化线程dpc_init();  //lk系统控制器初始化timer_init(); //kernel时钟初始化#if (!ENABLE_NANDWRITE)thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); // 创建一个线程初始化系统exit_critical_section(); //使能中断thread_become_idle(); //本线程切换为idle线程
#elsebootstrap_nandwrite();
#endif
}

bootstrap2 

此函数由kmain中创建的线程调用,路径为:bootable\bootloader\lk\kernel\main.c。

static int bootstrap2(void *arg)
{arch_init(); //架构初始化bio_init();fs_init();platform_init(); //平台初始化, 主要初始化系统时钟,超频等target_init(); //目标设备初始化,主要初始化Flash,整合分区表等apps_init(); // 应用功能初始化,调用aboot_init,加载kernel等
}

apps_init()函数:

app_init 函数位于 app/app.c 文件中

/* app entry point */
struct app_descriptor;
typedef void (*app_init)(const struct app_descriptor *);
typedef void (*app_entry)(const struct app_descriptor *, void *args);/* app startup flags */
#define APP_FLAG_DONT_START_ON_BOOT 0x1/* each app needs to define one of these to define its startup conditions */
struct app_descriptor {const char *name;app_init  init;app_entry entry;unsigned int flags;
};void apps_init(void)
{const struct app_descriptor *app;/* call all the init routines */for (app = &__apps_start; app != &__apps_end; app++) {if (app->init)app->init(app);}/* start any that want to start on boot */for (app = &__apps_start; app != &__apps_end; app++) {if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {start_app(app);}}
}static void start_app(const struct app_descriptor *app)
{thread_t *thr;printf("starting app %s\n", app->name);thr = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);if(!thr){return;}thread_resume(thr);
}

整个遍历 app 并启动的过程并不复杂,有趣的是 __apps_start__apps_end 的定义,这两个变量符号在所有源文件中并不存在,而是在 arch/arm/*.ld 链接脚本中存在, __apps_start__apps_end 是自定义的两个符号,代表了自定义段 .apps 的开始位置和结束位置。也就是说所有的 app 都通过在特殊的段 .apps 中注册实现了一套插件系统,是一个十分精巧的设计。后续的任何新的 app 只需要使用以下两个宏声明即可注册到 .apps 段中:

#define __SECTION(x) __attribute((section(x)))
#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
#define APP_END };

bootloader/lk/app/aboot/aboot.c 结尾:

APP_START(aboot).init = aboot_init,
APP_END

说明apps_init函数调用了aboot_init函数

aboot_init函数:

是通过 APP_START注册的 aboot 入口函数, aboot 的所有功能都是由此开始。位于 bootloader/lk/app/aboot/aboot.c文件中。

简单流程:

  • 设置NAND/eMMC读取信息页面的大小。
  • 打印一些设备模块的Log信息以及初始化。
  • 检测按键,判断是否进入fastboot或者recovery模式。
  • 获取device info(设备是否lock,是否root,img是否已鉴权等信息)
  • 从eMMC或NAND flash中加载内核。

主要函数:boot_linux_from_mmc 

boot.img 解析:https://blog.csdn.net/ty3219/article/details/78879398

  • 首先加载boot image
  • 获取image header size,分配image header buffer,从指定分区加载image header。
  • 如果配置了Secure Boot
  • imagesizeActure += 签名size
  • imagesize = imagesizeActure + image header pagesize
  • 分配image buffer并从分区中加载image
  • 校验签名
  • 校验失败通知TZ,启动失败。
  • 校验成功则即系加载image。
  • 解压缩boot.img,分别加载kernel、ramdisk、device tree等到指定地址。
  • 通知TZ加载结束。启动kernel。
  • BootLoader结束。

boot.image加签:

  1. 将原始boot.img通过SHA256算法进行计算得到一个哈希值。
  2. 使用private key对哈希值进行加签。
  3. 将最终的哈希值和签名添加到原始boot.img末尾。

签名校验: 

  1. 将boot.img进行SHA256哈希计算,获得文件digest1。
  2. 将签名通过public key进行解密,获得文件digest2。
  3. 对比digest1和digest2两个文件。
  4. 相同则校验成功,不同则校验失败。

Boot流程的粗略理解。

[Android]高通平台BootLoader启动流程相关推荐

  1. 高通平台Bootloader启动流程【转】

    本文转载自:http://blog.csdn.net/fang_first/article/details/49615631 ====================基本知识============= ...

  2. 高通平台RF配置流程

    高通平台RF配置流程 **注:**本文参考项目路径和代码为SIM7600 LE20分支 1 准备工作 需要的资料: 各个器件的datasheet 原理图 逻辑表(内容包含支持哪些制式.band,各个b ...

  3. 高通简单的启动流程说明

    高通的启动流程较MTK稍微复杂一点,大体阶段如下: 一.系统上电后加载rom里面的一段代码,其实这个过程就是PBL,此处也是启动的开始,假如此处枚举不出来启动,也就是我们常说的救机其实也就是从此处进行 ...

  4. 高通平台ADSP USB流程

    在高通平台上,ADSP(Audio Digital Signal Processor,音频数字信号处理器)可以通过 USB 接口与主机进行数据传输,以下是大致的 ADSP USB 流程: 主机发起 U ...

  5. 高通平台android开发总结 MSM平台上的AMSS

    http://blog.csdn.net/mirkerson/article/details/7691029 MSM平台上的AMSS REX启动分析--基于Qualcomm平台 1.高通平台andro ...

  6. 高通平台android开发总结

    http://www.cnblogs.com/yuzaipiaofei/archive/2012/07/24/4124179.html 1.高通平台android开发总结 1.1 搭建高通平台环境开发 ...

  7. 高通平台android 环境配置编译及开发经验总结

    完全转自:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

  8. 高通平台android开发总结 .

    http://blog.csdn.net/mirkerson/article/details/7691029 http://blog.csdn.net/mirkerson/article/detail ...

  9. 高通平台android 环境配置编译及开发经验总结【转】

    1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流 ...

  10. 高通 MSM8K bootloader : SBL1 .

    一. MSM8K Boot Flow 图1: 高通MSM8K平台bootloader启动流程基本类似,但具体各平台,比如MSM8974.MSM8916.MSM8994等,会有微小区别. 从上图,可以看 ...

最新文章

  1. 浅谈百度新一代query-ad 推荐引擎如何提升广告收益率
  2. 数据库常忽略小问题汇总
  3. CPU怎么认识代码的?
  4. 信息安全工程师笔记-公钥密钥体制概念
  5. Oracle Data Guard (RAC+DG) 归档删除策略及脚本
  6. Gstreamer调试命令(五)
  7. UPX3.03+UpolyX.5 Shell v1.0 汉化绿色版
  8. Windows XP优化设置之网络篇
  9. linux7启动ib子网管理器,IB_Switch交换机SB7890配置及Band网卡
  10. Soui Button学习一
  11. KDD 2022论文合集(持续更新中)
  12. oracle函数按周,关于oracle按日周月分组统计以及next_day()函数详解
  13. LOJ.6073.[2017山东一轮集训Day5]距离(可持久化线段树 树链剖分)
  14. postgresql12的同步流复制搭建及主库hang问题处理和分析
  15. DELL服务器 R740的风扇设置
  16. [附源码]java毕业设计家政管理系统
  17. 太逗了 不得不藏 “郭德纲绝句,没有一句不让你笑的”
  18. 5G室内定位来了,化工厂人员定位,电厂室内定位都有用它!-新导智能
  19. 采用CCG和kkt条件编制两阶段鲁棒优化程序,以储能、发电、风电和光伏容量作为第一阶段变量
  20. Java基本知识——继承与组合

热门文章

  1. “立字据,你们这群混蛋!”
  2. php 防恶意注册,论坛防恶意注册 for PHPWindv5.0.1
  3. 一切从零开始------软件篇
  4. QPushButton 实现保持按下效果
  5. 零基础无实物一步一步学PLCS7-1200仿真(一)--电动机的点动控制
  6. 出差沈阳记之初来乍到
  7. PDF文件编辑指南4:PDF文档加密和移除PDF文档密码方法
  8. Linux教程shell篇——黑马课程笔记
  9. 微信小程序 - 扫描小程序码进入小程序并获取参数
  10. 2021江西省数学建模A题