Android 开发之 ---- bootloader (LK)

本文解析了LittleKernel(LK)启动流程,包括系统初始化、平台初始化、应用程序初始化等关键步骤,并详细介绍了LK如何加载Android Linux内核。

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

LK是什么

           LK 是 Little Kernel 它是 appsbl (Applications ARM Boot Loader)流程代码  ,little kernel 是小内核小操作系统。

           LK 代码 在 bootable/bootloadler/lk 目录下

           LK 代码结构

           +app            // 应用相关

           +arch           // arm 体系

           +dev            // 设备相关

           +include      // 头文件

           +kernel        // lk系统相关  

           +platform    // 相关驱动

           +projiect     // makefile文件

           +scripts      // Jtag 脚本

           +target        // 具体板子相关


LK 流程分析

          在 bootable/bootloadler/lk/arch/arm/ssystem-onesegment.ld 连接文件中 ENTRY(_start)指定 LK 从_start 函数开始,_start 在 lk/arch/crt0.S中 。crt0.S 主要做一些基本的 CPU 的初始化再通过 bl  kmain ;跳转到 C 代码中。

          kmain 在 lk/kernel/main.c 中


kmain()

            kmain 主要做两件事:1、本身 lk 这个系统模块的初始化;2、boot 的启动初始化动作。

            kmain 源码分析:

             void kmain()

          {

           1.初始化进程(lk 中的简单进程)相关结构体

             thread_init_early();

           2.做一些如 关闭 cache,使能 mmu 的 arm 相关工作。

            arch_early_init();

           3.相关平台的早期初始化

            platform_early_init();

           4.现在就一个函数跳转,初始化UART(板子相关)

            target_early_init();

           5.构造函数相关初始化

            call_constructors();

           6.lk系统相关的堆栈初始化

            heap_init();

           7.简短的初始化定时器对象

            thread_init();

           8.lk系统控制器初始化(相关事件初始化)

            dpc_init();

           9.初始化lk中的定时器

            timer_init();
          
10.新建线程入口函数 bootstrap2 用于boot 工作(重点
           thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));

         }

   以上与 boot 启动初始化相关函数是 arch_early_init、  platform_early_init 、bootstrap2,这些是启动的重点,我们下面慢慢来看。


arch_early_init()

         体系架构相关的初始化我们一般用的 ARM 体系

         1.关闭cache

         arch_disable_cache(UCACHE);

         2.设置向量基地址(中断相关)

         set_vector_base(MEMBASE);

         3.初始化MMU

         arm_mmu_init();

         4.初始化MMU映射__平台相关

         platform_init_mmu_mappings();

         5.开启cache        

         arch_enable_cache(UCACHE)

         6.使能 cp10 和 cp11

         __asm__ volatile("mrc    p15, 0, %0, c1, c0, 2" : "=r" (val));

         val |= (3<<22)|(3<<20);

         __asm__ volatile("mcr    p15, 0, %0, c1, c0, 2" :: "r" (val));
 

        7.设置使能 fpexc 位 (中断相关)

        __asm__ volatile("mrc  p10, 7, %0, c8, c0, 0" : "=r" (val));

        val |= (1<<30);

        __asm__ volatile("mcr  p10, 7, %0, c8, c0, 0" :: "r" (val));

        8.使能循环计数寄存器

        __asm__ volatile("mrc    p15, 0, %0, c9, c12, 0" : "=r" (en));

        en &= ~(1<<3); /*循环计算每个周期*/

        en |= 1;

        __asm__ volatile("mcr    p15, 0, %0, c9, c12, 0" :: "r" (en));

       9.使能循环计数器

       en = (1<<31);
       __asm__ volatile("mcr    p15, 0, %0, c9, c12, 1" :: "r" (en));


platform_early_init()

       平台相关初始化不同平台不同的初始化下面是msm7x30

        1.初始化中断

        platform_init_interrupts();

        2.初始化定时器

        platform_init_timer();


bootstrap2

         bootstrap2 kmain的末尾以线程方式开启。主要分三步:platform_init、target_init、apps_init。

        1.platform_init

               platform_init 中主要是函数 acpu_clock_init。

               在 acpu_clock_init 对 arm11 进行系统时钟设置,超频

        2.target_init

              针对硬件平台进行设置。主要对 arm9 和 arm11 的分区表进行整合,初始化flash和读取FLASH信息

        3.apps_init 

             apps_init 是关键,对 LK 中所谓 app 初始化并运行起来,而 aboot_init 就将在这里开始被运行,android linux 内核的加载工作就在 aboot_init 中完成的 。


aboot_init

        1.设置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;

        }

      2.读取按键信息,判断是正常开机,还是进入 fastboot ,还是进入recovery 模式

       。。。。。。。。。

      通过一系列的 if (keys_get_state() == XXX) 判断

       。。。。。。。。。

      3.从 nand 中加载 内核

      boot_linux_from_flash();

 

      partition_dump();

      sz = target_get_max_flash_size();

      fastboot_init(target_get_scratch_address(), sz);

      udc_start(); // 开始 USB 协议


boot_linux_from_flash

             主要是内核的加载过程,我们的 boot.img 包含:kernel 头、kernel、ramdisk、second stage(可以没有)。

           1.读取boot 头部

           flash_read(p, offset, raw_header, 2048)

           offset += 2048;
          
2.读取 内核   
           memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)
           n = (hdr->kernel_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1));

           flash_read(p, offset, (void*) hdr->kernel_addr, n)

           offset += n;
          
3.读取 ramdisk
           n = (hdr->ramdisk_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1));

           flash_read(p, offset, (void*) hdr->ramdisk_addr, n)

           offset += n;

            4.启动内核

                boot_linux();//在boot_linux 中entry(0,machtype,tags);从kernel加载在内核中的地址开始运行了。

     

        到这里LK的启动过程就结束了。

 


<think>好的,用户现在需要将MTK的LK2移植到LK中,首先我需要理解这两个项目的关系。LK是MTK原有的引导加载程序,而LK2可能是其更新版本或分支版本。用户可能是在进行系统升级或定制开发,需要将新功能合并到旧代码中。 接下来,用户的问题涉及到代码移植,这通常包括代码整合、解决冲突、适配硬件和验证功能。首先,我需要确认用户是否有足够的背景知识,比如对LKLK2的了解,以及是否有MTK平台开发经验。如果用户是开发者,可能已经有一定的经验,但如果是新手,可能需要更详细的步骤说明。 然后,我需要考虑可能的风险,比如代码兼容性问题、硬件差异、编译错误等。移植过程中,最大的挑战可能是代码冲突和硬件适配,特别是如果LKLK2针对不同的芯片或硬件配置设计的话。此外,LK可能依赖特定的MTK私有库或驱动,这些在移植时需要注意。 用户的需求可能不仅仅是步骤,而是希望了解如何高效、安全地完成移植,避免常见错误。因此,在回答中需要分步骤详细说明,同时提供验证方法和注意事项。比如,强调备份的重要性,逐步合并代码,处理冲突的方法,以及如何测试引导流程。 另外,用户可能没有提到的深层需求包括如何维护代码的稳定性,确保移植后的系统能够正常启动,以及后续的维护和更新策略。因此,回答中需要涵盖这些方面,比如建议使用版本控制工具,分阶段测试等。 最后,考虑到用户可能遇到的具体问题,比如编译错误或启动失败,提供排查方法和常见解决方案会更有帮助。例如,检查Makefile配置、硬件抽象层差异,或者利用调试工具进行日志分析。</think>将 MTK 的 `lk2` 移植到 `lk` 目录(即从 `vendor/mediatek/proprietary/bootable/bootloader/lk2` 迁移到 `vendor/mediatek/proprietary/bootable/bootloader/lk`)需要分步骤处理代码整合、依赖适配和编译验证。以下是具体操作指南: --- ### **1. 核心目标分析** - **`lk` 与 `lk2` 的关系**: - `lk` 是 MTK 设备的 **Legacy Little Kernel**(引导加载程序),负责早期硬件初始化和启动流程。 - `lk2` 可能是 MTK 的新版本或分支版本,可能包含新功能(如安全启动、多阶段加载等)或适配新硬件。 - **移植目的**: 将 `lk2` 的功能合并到 `lk` 中,同时兼容原有硬件和启动流程。 --- ### **2. 移植步骤** #### **(1) 代码备份与基线确认** - **备份原始 `lk` 代码**: ```bash cd vendor/mediatek/proprietary/bootable/bootloader cp -r lk lk_backup # 保留原始代码 ``` - **确认 `lk2` 的基线**: 检查 `lk2` 的 Git 提交历史或版本号,明确其适配的芯片平台(如 MT6765/MT6893)和功能特性。 #### **(2) 代码合并策略** - **直接覆盖(适用于全新替换)**: ```bash rm -rf lk/* # 删除原 lk 内容(确保已备份!) cp -r lk2/* lk/ # 复制 lk2 到 lk 目录 ``` **适用场景**:`lk2` 是 `lk` 的完全替代版本,且硬件平台一致。 - **增量合并(适用于功能整合)**: ```bash # 使用 Git 或 diff 工具合并差异 cd lk git init # 若未使用版本控制 git add . git commit -m "Original lk baseline" cp -r ../lk2/* . # 覆盖 lk2 内容 git diff # 检查差异并手动解决冲突 ``` **关键冲突点**: - `project/` 目录下的硬件配置文件(如 `project/<chip>/rules.mk`) - 平台驱动(如 `platform/<chip>/` 中的 GPIO、时钟初始化代码- 启动流程(`app/` 中的 `main.c` 或 `aboot.c`) #### **(3) 硬件适配修改** - **平台配置同步**: 对比 `lk2` 和 `lk` 的 `project/<chip>/` 目录,确保以下文件兼容: - `rules.mk`:编译规则(如 `TARGET_ARCH`、`CFLAGS`) - `lk.ld`:链接脚本(内存布局需匹配目标硬件) - `platform_<chip>.mk`:芯片特定配置 - **驱动层适配**: - 检查 `platform/<chip>/` 下驱动代码(如 `gpio.c`、`clock.c`)是否与目标硬件匹配。 - 若 `lk2` 为新型号芯片设计,需将 `lk` 原有驱动替换为 `lk2` 的实现。 #### **(4) 编译配置调整** - **更新 Makefile**: 修改 `lk` 根目录的 `Makefile` 或 `build.mk`,确保包含 `lk2` 新增的模块或源码路径。 ```makefile # 示例:添加新模块 SUBDIRS += \ app/new_feature # lk2 新增的子模块 ``` - **依赖库处理**: 若 `lk2` 依赖新的库(如安全启动库 `libsecureboot.a`),需将其复制到 `lk/lib/` 并更新编译链。 #### **(5) 编译验证** - **全量编译**: ```bash cd lk make clean make <project> # 如 make mt6765 ``` - **常见错误处理**: - **符号未定义**:检查是否遗漏源码或库文件。 - **内存布局冲突**:调整 `lk.ld` 中的 `BASE_ADDR` 和 `MEMORY` 区域。 - **硬件初始化失败**:比对 `lk2` 和 `lk` 的 `platform_init()` 流程。 --- ### **3. 关键注意事项** 1. **版本兼容性**: - 确保 `lk2` 的代码基线支持目标设备的芯片型号(如 MT6765 与 MT6893 差异较大)。 - 若 `lk2` 基于 Android 新版本(如 Android 12),需同步更新编译工具链(如 Clang 版本)。 2. **安全启动(Secure Boot)**: - 若 `lk2` 包含安全启动功能,需同步移植 **证书链** 和 **验签逻辑**。 - 检查 `app/aboot/aboot.c` 中的 `boot_linux()` 函数是否包含安全校验。 3. **多阶段引导**: - 若 `lk2` 采用多阶段加载(如 `lk` → `hyp` → `kernel`),需更新 **引导参数传递** 逻辑。 --- ### **4. 测试与调试** - **刷机测试**: 通过 `fastboot` 刷入编译后的 `lk.bin`,观察设备启动日志(UART 或 `dmesg`)。 ```bash fastboot flash lk lk.bin fastboot reboot ``` - **调试手段**: - 启用 `LK_DEBUG` 宏输出调试信息。 - 使用 JTAG 工具捕获启动异常时的 PC 指针和寄存器状态。 --- ### **5. 典型问题与解决** | **问题现象** | **可能原因** | **解决方案** | |---------------------------|-----------------------------|---------------------------------| | 编译失败:未定义 `platform_init()` | 驱动层未正确移植 | 检查 `platform/<chip>/platform.c` | | 设备卡在 `LK` 阶段 | 内存布局冲突或时钟初始化失败 | 比对 `lk.ld` 和 `lk2` 的链接脚本 | | 安全启动失败 | 证书路径错误或验签逻辑缺失 | 同步 `libsecureboot` 和证书文件 | --- ### **6. 总结** - **直接覆盖移植**适用于同芯片平台的版本升级。 - **增量合并移植**需重点解决硬件配置和驱动兼容性问题。 - 验证时需结合硬件调试工具(如 UART/JTAG)和日志分析。 建议在 **测试设备** 上验证通过后再部署到正式设备。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值