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

本文详细解析了Android系统启动过程中Little Kernel的作用与工作流程,包括其在硬件、平台和系统初始化后的运行机制,以及如何将注册的应用程序逐个运行起来。重点分析了Little Kernel的入口函数、初始化步骤以及其在启动过程中的关键角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是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 过程) 后面会补上。

<think>好的,用户问的是LK和U-Boot,我需要先分别了解这两个概念,然后组织答案。 首先,LK是Little Kernel的缩写,我之前记得它是一个轻量级的开源引导程序,主要用于嵌入式系统和移动设备。需要确认它的主要功能和适用场景。可能涉及启动流程、支持平台等。另外,它和Android的关系,比如作为早期Android设备的Bootloader,这点可能需要提到。 然后是U-Boot,全称Das U-Boot,这是一个广泛使用的开源Bootloader,常见于嵌入式系统,尤其是基于ARM、PowerPC、MIPS等架构的设备。需要说明它的功能,比如初始化硬件、加载操作系统,支持网络启动、文件系统等高级功能。应用场景如路由器、物联网设备,以及开发板如Raspberry Pi的部分版本。 接下来,要比较两者的区别。LK更轻量,适合资源有限的环境,比如手机;而U-Boot功能更全面,支持的硬件更多,适合复杂的嵌入式设备。可能还要提到历史背景,比如LKAndroid中的使用,而U-Boot在更多领域应用。 用户可能需要了解两者的使用场景和选择依据,因此需要明确它们的优缺点。例如,LK启动速度快,占用资源少,但功能相对简单;U-Boot功能丰富但更庞大。 需要检查是否有错误信息,比如LK是否真的是Android早期使用的,以及U-Boot支持的具体架构。另外,确保术语准确,比如Bootloader的作用,启动流程的阶段划分。 最后,结构要清晰,分点介绍LK和U-Boot,再比较它们的区别,帮助用户逐步理解。注意使用中文,避免专业术语过于晦涩,必要时举例说明。</think>以下是关于LK和U-Boot的详细介绍及对比分析--- ### 一、LK(Little Kernel) #### 1. 基本定义 LK(Little Kernel)是一个轻量级开源**引导加载程序(Bootloader)**,专为嵌入式系统和移动设备设计。它最初由Android团队开发,用于早期Android设备的启动流程。 #### 2. 核心功能 - **硬件初始化**:初始化CPU、内存、时钟等关键硬件。 - **多阶段启动**:支持从低功耗模式唤醒设备,并加载后续引导阶段。 - **快速启动**:代码精简,占用资源少,适合对启动时间敏感的场景。 - **模块化设计**:可通过插件扩展功能(如文件系统、网络支持)。 #### 3. 应用场景 - 早期Android手机的Bootloader(如Nexus系列)。 - 嵌入式设备(如IoT设备)的快速启动解决方案。 --- ### 二、U-Boot(Das U-Boot) #### 1. 基本定义 U-Boot(全称Universal Boot Loader)是一个开源的**通用引导加载程序**,广泛应用于嵌入式系统,支持多种处理器架构(ARM、PowerPC、MIPS等)。 #### 2. 核心功能 - **硬件初始化**:配置CPU、内存、外设控制器等。 - **操作系统加载**:从存储介质(Flash、SD卡)或网络加载内核镜像。 - **交互式命令行**:提供丰富的调试和配置命令。 - **高级功能**:支持文件系统(FAT、EXT4)、网络协议(TFTP、NFS)、脚本执行等。 #### 3. 应用场景 - 嵌入式开发板(如树莓派、BeagleBone)。 - 工业控制设备、路由器、网络交换机等。 --- ### 三、LK与U-Boot的关键区别 | 特性 | LK | U-Boot | |---------------------|-----------------------------------------|---------------------------------------| | **设计目标** | 轻量级、快速启动 | 通用性、功能丰富 | | **代码体积** | 较小(约数万行代码) | 较大(数十万行代码) | | **硬件支持** | 专注ARM架构,适配移动设备 | 支持多架构(ARM、PowerPC、RISC-V等) | | **功能复杂度** | 基础功能为主,扩展性有限 | 功能全面,支持网络、文件系统等 | | **典型应用** | 早期Android设备、低资源嵌入式系统 | 开发板、复杂嵌入式系统 | --- ### 四、选择建议 1. **LK适用场景**: - 需要快速启动且硬件资源受限的设备(如穿戴设备)。 -Bootloader的实时性要求较高。 2. **U-Boot适用场景**: - 需要灵活配置、调试或网络功能的复杂系统- 多架构支持需求(如跨平台开发)。 --- ### 五、技术示例 - **LK启动流程**: $$ \text{硬件复位} \rightarrow \text{初始化时钟/内存} \rightarrow \text{加载第二阶段引导程序} \rightarrow \text{启动内核} $$ - **U-Boot命令行操作**: 通过串口输入`printenv`可查看环境变量: ```bash => printenv bootcmd=tftp 0x80008000 zImage; bootm 0x80008000 ``` --- 通过以上分析,可依据具体需求选择LK或U-Boot作为嵌入式系统的引导解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值