====================基本知识=======================
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中

arch              //体系代码包含x86和arm
dev               //设备目录,包含显示器,键盘,net,usb等设备的初始化代码
include        //头文件
kernel          //kernel/main.c主函数以及kernel/thread.c线程函数
lib                //库文件
make          //编译规则
platform     //不同平台代码mdmxxx,msmxxx,apqxxx,qsdxxx,还有共享的目录msm_shared

project        //整个工程的编译规则
target          //通用init.c,具体目标板的初始化(主要为板子设备资源init.c代码中),编译规则代码(一级s810.mk二级hdc8094.mk)
 
 

====================程序执行流程============================
主函数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过程【转】的更多相关文章

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

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

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

    原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

  3. 高通平台 lcd driver 调试小结

    一.概述 1.1 简介 本文档主要包括LCD模块的驱动流程分析.Framebuffer相关知识.Gralloc等相关内容,以及LCD调试的一些经验和相关bug的分析和讲解. 1.2  开发环境 And ...

  4. 高通平台msm8909 LK 实现LCD 兼容

    前段时间小米出现红米note2 换屏门,现在我们公司也要上演了:有两个供应商提供不同IC 的LCD panel. 软件区分的办法是读取LCD IC 的ID 寄存器,下面解析高通平台LK中LCD兼容的过 ...

  5. [修改高通平台WIFI MAC 地址] & [adb over wifi]

    [修改高通平台WIFI MAC 地址]fccmd --helpfccmd startfccmd getwifimacfccmd setwifimac 74:AC:5F:F5:D7:40 [adb ov ...

  6. 高通平台MSM8916LCM模块移植(一)-bootloader部分

    此次移植打算分成两个模块来说,bootloader部分和kernel部分.在实际的移植调试过程中也是这么分成了两个部分分别调试. 高通平台中的bootloader叫做LK(Little Kernel, ...

  7. 高通平台MSM8916LCM模块移植(一)-bootloader部分【转】

    本文转载自:http://www.mobile-open.com/2016/970947.html 高通平台中的bootloader叫做LK(Little Kernel,对于LCM来说LK部分相当重要 ...

  8. 在高通平台Android环境下编译内核模块【转】

    本文转载自:http://blog.xeonxu.info/blog/2012/12/04/zai-gao-tong-ping-tai-androidhuan-jing-xia-bian-yi-nei ...

  9. android 6.0 高通平台sensor 工作机制及流程(原创)

    最近工作上有碰到sensor的相关问题,正好分析下其流程作个笔记. 这个笔记分三个部分: sensor硬件和驱动的工作机制 sensor 上层app如何使用 从驱动到上层app这中间的流程是如何 Se ...

随机推荐

  1. java注解细节

    现在很多框架都使用注解了,典型的像Spring里面就可以看到大量的注解,比如@Service,@Controller这一类的都是注解.注解Annotation是java一项很重要的功能.下面就来整理一 ...

  2. spring -boot s-tarter 详解

    Starter POMs是可以包含到应用中的一个方便的依赖关系描述符集合.你可以获取所有Spring及相关技术的一站式服务,而不需要翻阅示例代码,拷贝粘贴大量的依赖描述符.例如,如果你想使用Sprin ...

  3. 《Spark大数据处理:技术、应用与性能优化》【PDF】 下载

    内容简介 <Spark大数据处理:技术.应用与性能优化>根据最新技术版本,系统.全面.详细讲解Spark的各项功能使用.原理机制.技术细节.应用方法.性能优化,以及BDAS生态系统的相关技 ...

  4. 苹果审核返回崩溃日志 iOS .crash文件处理 symbolicatecrash.  困扰我多年的牛皮癣根治了 看到这篇文章拿过来用下

    AppStore审核被拒,返回crashLog.txt文件,可是打开后都是十六进制的地址,我们可以使用Xcode自带的 symbolicatecrash 解析得到我们需要的详细崩溃信息crashLog ...

  5. DataBase MongoDB高级知识-易扩展

    MongoDB高级知识-易扩展 应用程序数据集的大小正在以不可思议的速度增长.随着可用宽带的增长和存储器价格的下跌,即使是一个小规模的应用程序,需要存储的数据也可能大的惊人,甚至超出了很多数据库的处理 ...

  6. Hibernate学习---Configuration,Session,SessionFactory

    上一节我们讲到了Hibernate的测试,并且给出了测试代码,刚开始看见这个测试代码的同学估计是一头雾水把,所以这一节我们来讲一下测试代码. 本节主要内容: Configuration Session ...

  7. iOS开发--SQLite重要框架FMDB的使用

    什么是FMDB: FMDB是一个和iOS的SQLite数据库操作相关的第三方框架.主要把C语言操作数据库的代码用OC进行了封装.使用者只需调用该框架的API就能用来创建并连接数据库,创建表,查询等. ...

  8. 开发中关于Git那些事(续:Git变基)

    其实上一篇写的内容仅仅是Git的冰山一角,如果你认为Git就是简简单单的几行命令,那只能说明你还没有真正了解Git这个强大的内容寻址文件系统.这篇文章,还是接着介绍一些实用但是很少有人知晓的一些命令, ...

  9. 4.1 State Snapshot Transfer

    摘要: 出处:黑洞中的奇点 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但请保留该 ...

  10. c# 调用python语言

    config   文件配置 <configuration>节中 第一个的位置插入如下节点,版本根据实际用到的来写 <configSections>    <section ...