高通平台的bootloader过程【转】
====================基本知识=======================
LK是(L)ittle (K)ernel的缩写。
高通平台android普遍采用LK作为其bootloader,LK是一个开源项目。但是,LK只是整个系统的引导部分,所以它不是独立存在。LK是一个功能及其强大的bootloader,但现在只支持arm和x86平台。
LK的一个显著的特点就是它实现了一个简单的线程机制(thread),和对高通处理器的深度定制和使用。
启动流程
1. 芯片上电复位到地址0, RPM PBL开始运行;
2. RPM PBL执行基本的电量和功率检测,然后复位APP处理器(地址0xFC010000);
3. APPS PBL在A53上执行,他从启动设备中加载(并鉴定)SBL1镜像到OCMEM;
4. APPS PBL将RVBAR设置为SBL1的入口,设置RMR_EL3为64位模式,然后触发热启动,程序转到SBL1;
5. SBL1开始运行,他首先初始化DDR,然后加载(并鉴定)HYP和TZ镜像;
6. SBL1将执行权转交给TZ;
7. TZ安全监管器建立安全环境;
8. TZ QSEE内核运行;
9. TZ应用程序(32/64位)运行,他们初始化系统;
10. TZ将执行权转交给HYP(监管程序);
11. 监管程序运行,他建立调试管理器,然后将执行权交回SBL1;
12. SBL1加载(并鉴定)RPM 固件,设置RPM固件准备就绪魔数;
13. RPM 固件在RPM处理器上运行;
14. SBL1加载(并鉴定)SDI(系统调试镜像),SDI pass 0开始执行;
15. SBL1加载(并鉴定)HLOS APPSBL(High-Level Operationg System,高级操作系统的SBL,指lk(little kernel));
16. SBL1将执行权转给HLOS APPSBL;
17. HLOS APPSBL加载(并鉴定)HLOS kernel(实指linux kernel);
18. HLOS APPSBL通过TZ陷阱系统调用(TZ trap syscall)将执行权转交给HLOS kernel;
19. 根据需要,HLOS kernel从启动设备中加载MBA(Modem Boot Authenticator)到DDR;
20. HLOS kernel复位Modem处理器,Modem PBL开始运行;
21. (此条疑似错误,参考80-NM328-6第26页);
22. Modem PBL从DDR中将MBA拷贝到modem TCM中,然后在modem TCM中鉴定MBA;
23. 根据需要,HLOS kernel从启动设备中加载MPSS镜像到DDR中;
24. MBA鉴定DDR中的MPSS镜像;
25. 根据需要,HLOS使用PIL加载LPASS镜像;
26. 根据需要,HLOS使用PIL加载Venus镜像。
====================源码架构=======================
app //主函数启动app执行的目录,第一个app在app/aboot/aboot.c中
====================程序执行流程============================
主函数lk/kernel/main.c
/* called from crt0.S */
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void) //从kmain函数开始执行
{
thread_init_early(); //线程初始化
arch_early_init(); //平台体系x86或者arm初始化,类似uboot的第一阶段汇编,在arch/arm下面实现
实现功能:关闭cache,设置异常向量,mmu初始化,打开cache
// do any super early platform initialization
platform_early_init();----> //开始涉及到具体平台
void platform_early_init(void)
{
board_init(); //目标平台板的初始化
platform_clock_init(); //平台时钟初始化msm8994_clock
qgic_init(); //通用IO通道初始化
qtimer_init(); //时钟初始化
scm_init(); //单片机初始化
}
// do any super early target initialization
target_early_init(); //只初始化串口为了打印信息,与后面的target_init对应
以上采用层层递进的关系进行初始化
dprintf(INFO, "welcome to lk\n\n"); //开始进入LK,INFO级别在console打印
// initialize the threading system
dprintf(SPEW, "initializing threads\n"); //SPEW级别在console口不打印
thread_init();
// initialize the dpc system
dprintf(SPEW, "initializing dpc\n");
dpc_init();
// initialize kernel timers
dprintf(SPEW, "initializing timers\n");
timer_init();
// create a thread to complete system initialization -->创建线程完成系统初始化,跳转到第二阶段
dprintf(SPEW, "creating bootstrap completion thread\n");
/*jump to bootstrap2*/
thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
// become the idle thread //变成空闲线程
thread_become_idle();
}
static int bootstrap2(void *arg)
{
platform_init(); --->void platform_init(void) //msm8994
{
dprintf(INFO, "platform_init()\n");
#if ENABLE_XPU_VIOLATION
scm_xpu_err_fatal_init();
#endif
}
target_init(); //各种板子资源初始化,mmc,sdc,usb,volumn等---->
//里面最重要的是mmc的初始化 target_sdc_init();
//还有RPM rpm_smd_init();
dprintf(SPEW, "calling apps_init()\n");//app初始化以及启动app
apps_init();//开始执行app/aboot.c中的aboot_init函数
}
接下来开始执行app/aboot/aboot.c
在amboot.c的源码最底端:
APP_START(aboot) //可以看出上述的app启动的第一个就是aboot_init
.init = aboot_init,
APP_END
/* each app needs to define one of these to define its startup conditions */每个app需要的定义
struct app_descriptor {
const char *name;
app_init init;
app_entry entry;
unsigned int flags;
};
开始研究aboot_init函数:
void aboot_init(const struct app_descriptor *app)
{
/* Setup page size information for nv storage */首先判断从哪启动emmc还是flash
if (target_is_emmc_boot())
{
page_size = mmc_page_size();
page_mask = page_size - 1;
}
else
{
page_size = flash_page_size();
page_mask = page_size - 1;
}
read_device_info(&device); //读取设备信息
/* Display splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN //初始化显示屏
dprintf(SPEW, "Display Init: Start\n");
target_display_init(device.display_panel);
dprintf(SPEW, "Display Init: Done\n");
#endif
target_serialno((unsigned char *) sn_buf); //获取串口号
dprintf(SPEW,"serial number: %s\n",sn_buf);
memset(display_panel_buf, '\0', MAX_PANEL_BUF_SIZE);
/*如果用户强制重启是进入正常模式的,不会进入fastboot模式,然而在实现中该函数返回0,不执行
* Check power off reason if user force reset,
* if yes phone will do normal boot.
*/
if (is_user_force_reset())
goto normal_boot;
接下来就做一些除了boot up之外的一些事情,这里面主要判断组合按键,其中可以进入dload(livesuit)模式和recovery模式
其中recovery模式进入Linux内核,启动recovery映像,通过界面选择烧写的软件包update.zip
注:android镜像烧写总共有三种:fastboot(调试用),livesuit(下载整个镜像),recovery(启动recovery镜像)
然后判断是正常启动还是非正常启动,如果正常启动就recovery_init然后直接启动内核(包括传参)
两种情况:emmc和flash启动
if (target_is_emmc_boot())
{
if(emmc_recovery_init())
dprintf(ALWAYS,"error in emmc_recovery_init\n");
if(target_use_signed_kernel())
{
if((device.is_unlocked) || (device.is_tampered))
{
#ifdef TZ_TAMPER_FUSE
set_tamper_fuse_cmd();
#endif
#if USE_PCOM_SECBOOT
set_tamper_flag(device.is_tampered);
#endif
}
}
boot_linux_from_mmc(); ---->lk的启动画面也在里面,其实就是完成启动前的最后准备工作
}
else
{
recovery_init();
#if USE_PCOM_SECBOOT
if((device.is_unlocked) || (device.is_tampered))
set_tamper_flag(device.is_tampered);
#endif
boot_linux_from_flash();
}
如果是非正常启动就进入fastboot模式,之前进行fastboot命令的注册以及启动fastboot
/* register aboot specific fastboot commands */注册fastboot命令
aboot_fastboot_register_commands();
/* dump partition table for debug info */
partition_dump();
/* initialize and start fastboot */初始化fastboot以及启动
fastboot_init(target_get_scratch_address(), target_get_max_flash_size());
}
现在分析fastboot_init函数做些什么工作:
int fastboot_init(void *base, unsigned size)
{
/* target specific initialization before going into fastboot. */进入fastboot前的目标板初始化
target_fastboot_init();
/* setup serialno */创建串口号
target_serialno((unsigned char *) sn_buf);
dprintf(SPEW,"serial number: %s\n",sn_buf);
surf_udc_device.serialno = sn_buf;
/* initialize udc functions to use dwc controller */初始化usb控制器,因为fastboot和板子通过usb进行通信
/* register udc device */注册usb controller设备
/* register gadget */注册gadget
thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);//创建线程
---->static int fastboot_handler(void *arg)
{
for (;;) {
event_wait(&usb_online);//等待usb连接
fastboot_command_loop();//循环处理fastboot命令
}
return 0;
}
}
大多数fastboot命令cmd_xxx是在aboot.c中实现的,然后进行注册
现在分析 boot_linux_from_mmc函数做些什么工作:
常用结构体:
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE];
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned dt_size; /* device_tree in bytes */
unsigned unused; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
unsigned char cmdline[BOOT_ARGS_SIZE]; //串口的传参在这里
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
现在研究串口cmdline在哪打印的:
void boot_linux(void *kernel, unsigned *tags,
const char *cmdline, unsigned machtype,
void *ramdisk, unsigned ramdisk_size)
{
final_cmdline = update_cmdline((const char*)cmdline);
}
void aboot_init(const struct app_descriptor *app)
{
bool boot_into_fastboot = false; //判断是否进入fastboot模式
#if UART_INPUT_INTO_FASTBOOT
char getc_value;
#endif
#if UART_INPUT_INTO_FASTBOOT //经测验,按键f要一直按住,否则很难检测到,后续可以考虑延迟一段时间
if(dgetc(&getc_value, 0) >= 0) {
if(getc_value == 'f') {
boot_into_fastboot = true;
dprintf(INFO,"keyboard is pressed, goto fastboot mode!\n");
}
}
#endif
}
高通平台的bootloader过程【转】的更多相关文章
- 高通平台Bootloader启动流程【转】
本文转载自:http://blog.csdn.net/fang_first/article/details/49615631 ====================基本知识============= ...
- 【转】高通平台android 环境配置编译及开发经验总结
原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...
- 高通平台 lcd driver 调试小结
一.概述 1.1 简介 本文档主要包括LCD模块的驱动流程分析.Framebuffer相关知识.Gralloc等相关内容,以及LCD调试的一些经验和相关bug的分析和讲解. 1.2 开发环境 And ...
- 高通平台msm8909 LK 实现LCD 兼容
前段时间小米出现红米note2 换屏门,现在我们公司也要上演了:有两个供应商提供不同IC 的LCD panel. 软件区分的办法是读取LCD IC 的ID 寄存器,下面解析高通平台LK中LCD兼容的过 ...
- [修改高通平台WIFI MAC 地址] & [adb over wifi]
[修改高通平台WIFI MAC 地址]fccmd --helpfccmd startfccmd getwifimacfccmd setwifimac 74:AC:5F:F5:D7:40 [adb ov ...
- 高通平台MSM8916LCM模块移植(一)-bootloader部分
此次移植打算分成两个模块来说,bootloader部分和kernel部分.在实际的移植调试过程中也是这么分成了两个部分分别调试. 高通平台中的bootloader叫做LK(Little Kernel, ...
- 高通平台MSM8916LCM模块移植(一)-bootloader部分【转】
本文转载自:http://www.mobile-open.com/2016/970947.html 高通平台中的bootloader叫做LK(Little Kernel,对于LCM来说LK部分相当重要 ...
- 在高通平台Android环境下编译内核模块【转】
本文转载自:http://blog.xeonxu.info/blog/2012/12/04/zai-gao-tong-ping-tai-androidhuan-jing-xia-bian-yi-nei ...
- android 6.0 高通平台sensor 工作机制及流程(原创)
最近工作上有碰到sensor的相关问题,正好分析下其流程作个笔记. 这个笔记分三个部分: sensor硬件和驱动的工作机制 sensor 上层app如何使用 从驱动到上层app这中间的流程是如何 Se ...
随机推荐
- idea 安装热部署插件
jrebel(http://zeroturnaround.com/)的作用就是当你的代码改变时,你不需要重启服务,节省了时间.代码的改变有很多种,比如增加class.在class中增加方法等等.下面介 ...
- IDEA 初始配置教程
IDEA 初始配置教程 如果你是第一次使用 IDEA,或者对 IDEA 常用配置仍然不熟悉,那么本文就特别适合你. 本文只是根据我自己的使用经验来进行配置,不一定适合所有的情况,但是对你肯定会有帮助. ...
- springboot+CXF开发webservice对外提供接口(转)
文章来源:http://www.leftso.com/blog/144.html 1.项目要对外提供接口,用webservcie的方式实现 2.添加的jar包 maven: <dependenc ...
- 【功能代码】---3 JS判断字符串是否包含某个字符串
JS判断字符串是否包含某个字符串 var str ="abc"; if(str.indexOf("bc")>-1){ alert('str中包含bc字符串 ...
- 记录在vue中使用jsx时踩过的坑
使用方法及细节就不一一说了. 1.给input或者textarea绑定value时,出现失效的问题.解决方法:https://github.com/vuejs/babel-plugin-transfo ...
- ligerUI---ligerForm中下拉框使用
写在前面: 最近项目的前框框架用的是ligerUI,一开始我是拒绝的,因为貌似ligerUI很少有人用,我真的很想问我们team的斌哥哥为什么要用ligerUI来做前端框架?????(啊哈哈哈,用什么 ...
- C# 委托高级应用----线程——创建无阻塞的异步调用(一)
前言 本文大部分内容来自于mikeperetz的Asynchronous Method Invocation及本人的一些个人体会所得,希望对你有所帮助.原英文文献可以在codeproject中搜索到. ...
- AI 系列 总目录
AI 系列 答应了园区大牛 张善友 要写AI 的系列博客,所以开始了AI 系列之旅. 一.四大平台系列(百度AI.阿里ET.腾讯.讯飞) 1.百度篇 (1) 百度OCR文字识别-身份证识别 (2) 基 ...
- iOS 讯飞语音测试没问题,一上线就用不了了
看一下打包的版本是不是release, Debug : 调试版本,主要是让程序员使用,在调试的过程中调用 Debug 会启动更多的服务来监控错误,运行速度相对较慢,而且比较耗能. Release : ...
- 浅析c++和c语言的enum类型
1.先看c语言枚举类型 1.c语言定义枚举类型,每一个枚举元素都是一个整数2.注重数据类型,没有数据类型限定3.相邻枚举元素相差整数4.可以通过整数访问,不够安全 2.上代码: 1 #include& ...