zoukankan      html  css  js  c++  java
  • 高通平台Bootloader启动流程【转】

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

    ====================基本知识=======================
    LK是(L)ittle (K)ernel的缩写。
    高通平台android普遍采用LK作为其bootloader,LK是一个开源项目。但是,LK只是整个系统的引导部分,所以它不是独立存在。LK是一个功能及其强大的bootloader,但现在只支持arm和x86平台。
    LK的一个显著的特点就是它实现了一个简单的线程机制(thread),和对高通处理器的深度定制和使用。
     
    ====================源码架构=======================

    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
     1 /* called from crt0.S */
     2 void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
     3 void kmain(void)     //从kmain函数开始执行
     4 {
     5            thread_init_early();      //线程初始化
     6            arch_early_init();          //平台体系x86或者arm初始化,类似uboot的第一阶段汇编,在arch/arm下面实现
     7 实现功能:关闭cache,设置异常向量,mmu初始化,打开cache
     8            // do any super early platform initialization
     9            platform_early_init();---->                                    //开始涉及到具体平台
    10 void platform_early_init(void)
    11 {
    12     board_init();                  //目标平台板的初始化
    13     platform_clock_init();  //平台时钟初始化msm8994_clock
    14     qgic_init();                  //通用IO通道初始化
    15     qtimer_init();              //时钟初始化
    16     scm_init();                   //单片机初始化
    17 }
    18                     
    19           // do any super early target initialization
    20            target_early_init();    //只初始化串口为了打印信息,与后面的target_init对应
    21 以上采用层层递进的关系进行初始化
    22 
    23    dprintf(INFO, "welcome to lk
    
    ");  //开始进入LK,INFO级别在console打印
    24 
    25     // initialize the threading system
    26     dprintf(SPEW, "initializing threads
    ");    //SPEW级别在console口不打印
    27     thread_init();
    28 
    29     // initialize the dpc system
    30     dprintf(SPEW, "initializing dpc
    ");
    31     dpc_init();
    32 
    33     // initialize kernel timers
    34     dprintf(SPEW, "initializing timers
    ");
    35     timer_init();
    36 
    37  // create a thread to complete system initialization    -->创建线程完成系统初始化,跳转到第二阶段
    38     dprintf(SPEW, "creating bootstrap completion thread
    ");
    39            /*jump to bootstrap2*/
    40           thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
    41 
    42     // become the idle thread    //变成空闲线程
    43     thread_become_idle();
    44 }
    45 
    46 static int bootstrap2(void *arg)
    47 {
    48             platform_init();              --->void platform_init(void)      //msm8994
    49 {
    50     dprintf(INFO, "platform_init()
    ");
    51 #if ENABLE_XPU_VIOLATION
    52     scm_xpu_err_fatal_init();
    53 #endif
    54 }
    55            target_init();  //各种板子资源初始化,mmc,sdc,usb,volumn等---->
    56               //里面最重要的是mmc的初始化   target_sdc_init();
    57               //还有RPM                                  rpm_smd_init();
    58 
    59             dprintf(SPEW, "calling apps_init()
    ");//app初始化以及启动app
    60             apps_init();//开始执行app/aboot.c中的aboot_init函数
    61 }
    接下来开始执行app/aboot/aboot.c
     1 在amboot.c的源码最底端:
     2 APP_START(aboot)     //可以看出上述的app启动的第一个就是aboot_init
     3     .init = aboot_init,
     4 APP_END
     5 
     6 /* each app needs to define one of these to define its startup conditions */每个app需要的定义
     7 struct app_descriptor {
     8     const char *name;
     9     app_init  init;
    10     app_entry entry;
    11     unsigned int flags;
    12 };
    13 开始研究aboot_init函数:
    14 void aboot_init(const struct app_descriptor *app)
    15 {
    16           /* Setup page size information for nv storage */首先判断从哪启动emmc还是flash
    17     if (target_is_emmc_boot())
    18     {
    19         page_size = mmc_page_size();
    20         page_mask = page_size - 1;
    21     }
    22     else
    23     {
    24         page_size = flash_page_size();
    25         page_mask = page_size - 1;
    26     }
    27         read_device_info(&device);      //读取设备信息
    28 
    29     /* Display splash screen if enabled */
    30 #if DISPLAY_SPLASH_SCREEN                           //初始化显示屏
    31     dprintf(SPEW, "Display Init: Start
    ");
    32     target_display_init(device.display_panel);
    33     dprintf(SPEW, "Display Init: Done
    ");
    34 #endif
    35 
    36 
    37     target_serialno((unsigned char *) sn_buf);   //获取串口号
    38     dprintf(SPEW,"serial number: %s
    ",sn_buf);
    39 
    40       memset(display_panel_buf, '', MAX_PANEL_BUF_SIZE);
    41     /*如果用户强制重启是进入正常模式的,不会进入fastboot模式,然而在实现中该函数返回0,不执行
    42      * Check power off reason if user force reset,
    43      * if yes phone will do normal boot.
    44      */
    45     if (is_user_force_reset())
    46         goto normal_boot;
    47 
    48     接下来就做一些除了boot up之外的一些事情,这里面主要判断组合按键,其中可以进入dload(livesuit)模式和recovery模式
    49      其中recovery模式进入Linux内核,启动recovery映像,通过界面选择烧写的软件包update.zip
    50 注:android镜像烧写总共有三种:fastboot(调试用),livesuit(下载整个镜像),recovery(启动recovery镜像)
    51 
    52     然后判断是正常启动还是非正常启动,如果正常启动就recovery_init然后直接启动内核(包括传参)
    53 两种情况:emmc和flash启动
    54             if (target_is_emmc_boot())
    55         {
    56             if(emmc_recovery_init())
    57                 dprintf(ALWAYS,"error in emmc_recovery_init
    ");
    58             if(target_use_signed_kernel())
    59             {
    60                 if((device.is_unlocked) || (device.is_tampered))
    61                 {
    62                 #ifdef TZ_TAMPER_FUSE
    63                     set_tamper_fuse_cmd();
    64                 #endif
    65                 #if USE_PCOM_SECBOOT
    66                     set_tamper_flag(device.is_tampered);
    67                 #endif
    68                 }
    69             }
    70 
    71             boot_linux_from_mmc();    ---->lk的启动画面也在里面,其实就是完成启动前的最后准备工作
    72         }
    73         else
    74         {
    75             recovery_init();
    76     #if USE_PCOM_SECBOOT
    77         if((device.is_unlocked) || (device.is_tampered))
    78             set_tamper_flag(device.is_tampered);
    79     #endif
    80             boot_linux_from_flash();
    81         }
    82 
    83     如果是非正常启动就进入fastboot模式,之前进行fastboot命令的注册以及启动fastboot
    84     /* register aboot specific fastboot commands */注册fastboot命令
    85     aboot_fastboot_register_commands();
    86 
    87     /* dump partition table for debug info */
    88     partition_dump();
    89 
    90     /* initialize and start fastboot */初始化fastboot以及启动
    91     fastboot_init(target_get_scratch_address(), target_get_max_flash_size());
    92 }

    现在分析fastboot_init函数做些什么工作:

     1 int fastboot_init(void *base, unsigned size)
     2 {
     3     /* target specific initialization before going into fastboot. */进入fastboot前的目标板初始化
     4     target_fastboot_init();
     5 
     6          /* setup serialno */创建串口号
     7     target_serialno((unsigned char *) sn_buf);
     8     dprintf(SPEW,"serial number: %s
    ",sn_buf);
     9     surf_udc_device.serialno = sn_buf;
    10 
    11         /* initialize udc functions to use dwc controller */初始化usb控制器,因为fastboot和板子通过usb进行通信
    12          /* register udc device */注册usb controller设备
    13 
    14          /* register gadget */注册gadget
    15 
    16 thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);//创建线程
    17                           ---->static int fastboot_handler(void *arg)
    18 {
    19     for (;;) {
    20         event_wait(&usb_online);//等待usb连接
    21         fastboot_command_loop();//循环处理fastboot命令
    22     }
    23     return 0;
    24 }
    25 }
    26 大多数fastboot命令cmd_xxx是在aboot.c中实现的,然后进行注册
    现在分析 boot_linux_from_mmc函数做些什么工作:
     常用结构体:
     1 struct boot_img_hdr
     2 {
     3     unsigned char magic[BOOT_MAGIC_SIZE];
     4 
     5     unsigned kernel_size;  /* size in bytes */
     6     unsigned kernel_addr;  /* physical load addr */
     7 
     8     unsigned ramdisk_size; /* size in bytes */
     9     unsigned ramdisk_addr; /* physical load addr */
    10 
    11     unsigned second_size;  /* size in bytes */
    12     unsigned second_addr;  /* physical load addr */
    13 
    14     unsigned tags_addr;    /* physical addr for kernel tags */
    15     unsigned page_size;    /* flash page size we assume */
    16     unsigned dt_size;      /* device_tree in bytes */
    17     unsigned unused;    /* future expansion: should be 0 */
    18 
    19     unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
    20 
    21     unsigned char cmdline[BOOT_ARGS_SIZE];    //串口的传参在这里
    22 
    23     unsigned id[8]; /* timestamp / checksum / sha1 / etc */
    24 };

    现在研究串口cmdline在哪打印的:

     1 void boot_linux(void *kernel, unsigned *tags,
     2         const char *cmdline, unsigned machtype,
     3         void *ramdisk, unsigned ramdisk_size)
     4 {
     5         final_cmdline = update_cmdline((const char*)cmdline);
     6 
     7 }
     8 
     9 void aboot_init(const struct app_descriptor *app)
    10 {
    11         bool boot_into_fastboot = false;    //判断是否进入fastboot模式
    12 #if UART_INPUT_INTO_FASTBOOT
    13     char getc_value;
    14 #endif
    15 
    16 #if UART_INPUT_INTO_FASTBOOT    //经测验,按键f要一直按住,否则很难检测到,后续可以考虑延迟一段时间
    17             if(dgetc(&getc_value, 0) >= 0) {
    18                 if(getc_value == 'f') {
    19                     boot_into_fastboot = true;
    20                     dprintf(INFO,"keyboard is pressed, goto fastboot mode!
    ");
    21                 }
    22             }
    23 #endif
    24 
    25 }
     
  • 相关阅读:
    【JAVA零基础入门系列】Day3 Java基本数据类型
    【JAVA零基础入门系列】Day2 Java集成开发环境IDEA
    【JAVA零基础入门系列】Day1 开发环境搭建
    易语言 【寻找文本】命令的bug
    类的进化史
    C++指针类型识别正确姿势
    C++ 编写DLL文件给易语言调用
    C++中的显式类型转化
    CC++ 1A2B小游戏源码
    C语言dll文件的说明以及生成、使用方法
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6423492.html
Copyright © 2011-2022 走看看