Android 系统开发之-----bootloader (lk) 分析

时间:2022-01-10 17:35:08

什么是LK

                lk 就是 Little Kernel ,android lk 也是appsboot 是Qualcomm平台 arm11 端的 bootloader。它是类似OS一样的小操作系统。

                lk源码位置在android 系统下:

                 boottable/bootloader/lk 目录

                   +app                    // 应用相关

                   +arch                   // arm 体系

                   +scripts               // Jtag 脚本

                   +kernel                // 系统相关

                   +platform            //  驱动相关

                   +project              // 一些 makefile 文件

                   +target                // 板子相关

LK 分析

    lk入口 在 crt0.s 中_start 函数开始 (在连接文件 system_onesegment.ld 中 ENTRY(_start)指定

     crt0.s :lk/arch/crt0.s

           1.设置向量表 

           2.初始化BSS 载

           3.跳到 C 函数( bl       kmain )

    kmain 函数: lk/kernel/main.c

          1.thread_init_early()       初始化lk系统进程相关

          2.arch_early_init()           cpu相关的初始化 如:关闭 cache 使能mmu等

          3.platform_early_init()     具体的平台相关初始化

          4.target_early_init()         对平台的检测

          5.call_constructors()        构造函数相关

          6.heap_init();                    lk系统堆栈的初始化 

          7.thread_init()                   线程相关初始化

          8.dpc_init();                      LK相关控制系统初始化(涉及event 事件机制)

          9.timer_init()                     lk定时器初始化

          10.bootstrap2()                系统相关 重点 下面专门分析


bootstrap2函数

           它在kmain的最后被以新的简单线程的方式运行起来的。

            thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));

      

             bootstrap2 主要做了3件事:platform_init() , target_init() , apps_init() .

              platform_init:  它就一个函数调用 acpu_clock_init ,对arm 11 进行系统时钟设置http://www.itxiazai.info/,超频。

              target_init:        针对不同的硬件平台进行设置,有键盘设置,和系统 分区表(partition table)的设置。

              apps_init:       apps_init是关键,对LK中的所谓app初始化并运行起来,而aboot_init 就在开始被运行。(aboot_init  加载linux


 源码片段:

             void acpu_clock_init(void)
             {

                   /* 初始化 PLL  */
                   writel(0x0, SCPLL_CTL);
                   writel(0x00400002, SCPLL_CTL);
                   writel(0x00600004, SCPLL_CTL);
                   thread_sleep(1);
                   while(readl(SCPLL_STAT) & 0x2);
                   writel(0x0, SCPLL_CTL);

                   /* 使能 pll */
                   while(readl(SCPLL_STAT) & 0x1);
                   val = readl(SCPLL_CTL);
                   val &= ~(0x7);
                   val |= 0x2;
                   writel(val, SCPLL_CTL);
                   thread_sleep(1);
                   val = readl(SCPLL_CTL);
                   val |= 0x7;
                   writel(val, SCPLL_CTL);
                   thread_sleep(1);

                   /*先调频到 384MHz 再跳到 768MHz */

                  /*设置cpu频率到 384 MHz */
                   while(readl(SCPLL_STAT) & 0x3);
                   val = readl(SCPLL_CTLE);
                   val &= ~(0x3F << 3);
                   val |= (0xA << 3);
                   val &= ~(0x3 << 0);
                   val |= (4 << 0);  
                   writel(val, SCPLL_CTLE);
                   writel(0x00600007, SCPLL_CTL);
                   thread_sleep(1);


                   /* 跳到 768MHz */
                  while(readl(SCPLL_STAT) & 0x3);
                   val = readl(SCPLL_CTLE);
                   val &= ~(0x3F << 3);
                   val |= (0x14 << 3); 
                   val &= ~(0x3 << 0);
                   val |= (5 << 0); 
                   writel(val, SCPLL_CTLE);  //升频
                   writel(0x00600007, SCPLL_CTL);
                   thread_sleep(1);

                   val = readl(A11S_CLK_SEL);
                   val &= ~(0x3 << 1);
                   val |= (1 << 1);
                   writel(val, A11S_CLK_SEL);  //升频

               }

 

           void target_init(void)
              {
                 #if (!ENABLE_NANDWRITE)

                           keys_init(); 

                    keypad_init();       
                 #endif
                      ptable_init(&flash_ptable); //读取 arm11 端分区表
                      smem_ptable_init();  //读取 arm9 端分区表
 
                        ............

                           flash_init();  //初始化flash

                           flash_info = flash_get_info();    //读取flash信息
                      ............

                           offset = smem_get_apps_flash_start();
 
                        ............

                    total_num_of_blocks = flash_info->num_blocks;

                    ...........

                   smem_add_modem_partitions(&flash_ptable);

                    ptable_dump(&flash_ptable);
             

                          flash_set_ptable(&flash_ptable); //把arm9 和 arm 11两个分区表整合起来

               }


             

                 void apps_init(void)
             {
                   const struct app_descriptor *app;

                   for (app = &__apps_start; app != &__apps_end; app++) {
                            if (app->init)
                    app->init(app);
                      }             //调用的就是aboot_init函数

                  for (app = &__apps_start; app != &__apps_end; app++) {
                             if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
                                    start_app(app);
                                 }
                    }
             }

        

       前面分析我们可以看出来,LK在硬件,平台和系统初始化后,运行起第一个进程bootstrap2,而 bootstrap2 再把注册在系统中的app(即进程)逐个运行起来。软件下载Development前面提到的Aboot就是被运行起来的其中一个app。在aboot中最终完成了linux kernel的加载运行动作。

   

aboot_init分析

             void aboot_init(const struct app_descriptor *app)
              {
                  /*设置NAND/EMMC的读取页面大小*/

                  if (target_is_emmc_boot())
             {

               page_size = 2048;

               page_mask = page_size - 1;
               }
              else
              {

                    page_size = flash_page_size();

                          page_mask = page_size - 1;
              }
                     /*内核相关*/
              if(target_use_signed_kernel())
         {
              read_device_info(&device);
              }

              /* 通过按键状态,判断是否正常开机,还是进入fastboot,还是recovery */
                  if (keys_get_state(KEY_HOME) != 0)
                  boot_into_recovery = 1;
                  if (keys_get_state(KEY_VOLUMEUP) != 0)
                  boot_into_recovery = 1;
                  if(!boot_into_recovery)
                  {
                  if (keys_get_state(KEY_BACK) != 0)
                                   goto fastboot;
                           if (keys_get_state(KEY_VOLUMEDOWN) != 0)
                                   goto fastboot;
                }

                   if (fastboot_trigger())
                             goto fastboot;
                    reboot_mode = check_reboot_mode();//恢复出厂设置,重启则走这个。
                    if (reboot_mode == RECOVERY_MODE) {
                                boot_into_recovery = 1;       //进recovery 
                        } else if(reboot_mode == FASTBOOT_MODE) {
                   goto fastboot;
               }
             

                。。。。。
                 recovery_init();
                 boot_linux_from_flash(); //一般从nand中加载linux kernel

                 fastboot:   // 我们平时烧写进fastboot ,就走这个。

                 target_fastboot_init();

                 if(!usb_init)
                      udc_init(&surf_udc_device);

                 fastboot_register("boot", cmd_boot);
  
                udc_start(); //开启usb协议
      }


这是Qualcomm(高通)平台android 启动过程到这里 LK 的内容就大致结束了,至于Kernel的启动和初始化,这里就不讨论了。而LK前面的过程(ARM9 过程) 后面会补上。