android 最新bootloader LK加载kernel的问题

本文深入探讨了UBoot在启动内核过程中如何关闭MMU及Cache,以支持多线程环境,并解释了在跳转到内核前关闭MMU的重要性。分析了UBoot代码片段,包括其使用的逻辑地址与物理地址映射方式,以及在跳转到内核前为何必须关闭MMU。同时,解释了关闭MMU的具体实现过程及其对内核启动的影响。

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

  1. MMU

 执行boot命令的时候,会执行以下跳入kernel的函数,这和其他bootloader的做法是一样的,唯一的不同是LK使用了MMU和Cache来支持多线程,所以在跳到内核之前要先disable mmu和cache,代码如下


uboot使用了MMU吗??



体系结构有关,可以打开也可以不打开。一般uboot代码很少,为了简化设计,都是不使用mmu,如果不能绕开mmu的,通过最简单的逻辑地址==物理地址映射方式就可以了。
链接 的时候会指定代码段,数据段的逻辑地址, 这个要和实际运行时候的逻辑地址一致,每个体系结构都会指定cpu上电后的第一个指令的地址,这个很关键。



所以在bootloader中 执行C语言时是否打开MMU都没有关系,关键是跳转时必须close MMU.


[cpp]  view plain copy
  1. void boot_linux(void *kernel, unsigned *tags,   
  2.                 const char *cmdline, unsigned machtype,  
  3.                 void *ramdisk, unsigned ramdisk_size)  
  4. {  
  5.         unsigned *ptr = tags;  
  6.         void (*entry)(unsigned,unsigned,unsigned*) = kernel;  
  7.   
  8. ................  
  9.   
  10. for (i = 0; i < 500; i++)  
  11.         dprintf("%x ", (char *)kernel[i]);  //打印出kernel地址处的数据,的确是zImage的数据00 00 a0 e1 .... , kernel 地址为0x00208000  
  12.   
  13.         enter_critical_section();  //关闭中断  
  14.         platform_uninit_timer();  //关闭watch dog  
  15.         arch_disable_cache(UCACHE); //关闭cache  
  16.         arch_disable_mmu(); //关闭mmu  
  17.   
  18.         entry(0, machtype, tags);  
  19. }  

但是,在arch_disable_mmu()之后并没有继续执行entry这个函数,而如果把arch_disable_mmu()去掉,则可以到entry(0, machtype, tags); 但是内核同样跑不起来,可能是进入内核前一定要关闭mmu导致?所以问题的关键还是在arch_disable_mmu();后为什么没有到entry(0, machtype, tags); ?
arch_disable_mmu();的是这样实现的:
[cpp]  view plain copy
  1. void arch_disable_mmu(void)  
  2. {  
  3.         arm_write_cr1(arm_read_cr1() & ~(1<<0)); //  disable mmu  
  4. }  

arm_write_cr1和arm_read_cr1的实现为:
[cpp]  view plain copy
  1. /* uint32_t arm_read_cr1(void) */  
  2. FUNCTION(arm_read_cr1)  
  3.         mrc                p15, 0, r0, c1, c0, 0  
  4.         bx                lr  
  5.   
  6. /* void arm_write_cr1(uint32_t val) */  
  7. FUNCTION(arm_write_cr1)  
  8.         mcr                p15, 0, r0, c1, c0, 0  
  9.         bx                lr  

所以arch_disable_mmu();的最后一条指令时bx lr , 即返回指令,这条指令也执行了,但奇怪的是为什么entry(0, machtype, tags);这个就不执行了呢? 
entry(0, machtype, tags);被反汇编为5条指令,3条push压栈指令,一条mov r0 , #0, 最后是blx r9 , 跳到内核,其中 r9是zImage 地址.
<think>我们正在讨论的是Android Verified Boot (AVB) 是否属于LK(Little Kernel)对Kernel(Linux内核)的校验过程。根据引用[1]的内容,我们得知: - vbmeta.img 由私钥(oem_prvk.pem)签名。 - 在启动阶段,LK使用avbkey.h中配置的公钥对vbmeta.img进行验证。 - 这个公钥必须与签名vbmeta.img的私钥配对。 - 这个密钥与Secure Boot校验其他分区的密钥可以不同,但也可以配置成同一组。 现在,我们需要判断AVB是否参与LKKernel的校验过程。 ### 分析过程 1. **LK的作用**:LK是启动加载程序(bootloader),负责加载内核(Kernel)和初始RAM磁盘(ramdisk)等,并执行内核。在LK阶段,它会进行一些验证工作,以确保启动链的完整性。 2. **AVB的作用**:Android Verified Boot (AVB) 是Android启动时验证系统镜像完整性的机制。它通过验证分区(如boot、system等)的哈希值或签名来确保这些分区没有被篡改。其中,vbmeta.img是一个关键分区,它包含验证其他分区所需的元数据(如哈希树、签名等)。 3. **vbmeta.img与Kernel的关系**:在标准的AVB流程中,boot分区(包含Kernel和ramdisk)的验证信息通常存储在vbmeta.img中。也就是说,vbmeta.img包含了对boot分区的验证数据(例如boot分区的哈希值或签名)。 4. **LK对vbmeta.img的验证**:根据引用[1],在启动阶段,LK使用avbkey.h中的公钥验证vbmeta.img的签名。如果验证通过,则说明vbmeta.img是可信的。 5. **LKKernel的验证**:一旦vbmeta.img被验证为可信,LK就可以使用vbmeta.img中提供的验证数据(如哈希值或签名)来验证boot分区(即包含Kernel的分区)的完整性。因此,LKKernel的验证实际上是通过AVB机制完成的,具体步骤包括: - 验证vbmeta.img的签名(使用avbkey.h中的公钥)。 - 然后,使用vbmeta.img中的信息验证boot分区(包含Kernel)的完整性。 ### 结论 是的,**AVB参与了LKKernel的校验过程**。具体来说: - LK在启动过程中使用AVB机制验证vbmeta.img(通过公钥验证其签名)。 - 验证vbmeta.img后,LK再根据vbmeta.img中提供的验证数据(如boot分区的哈希描述符或签名)来验证boot分区(包含Kernel)的完整性和真实性。 因此,AVB是LK校验Kernel过程中的关键组成部分。 ### 引用支持 引用[1]明确指出:“在启动阶段lk使用avbkey.h中的公钥对vbmeta.img进行验证”,而vbmeta.img又包含了对其他分区(包括boot分区,即Kernel所在分区)的验证信息。因此,AVB机制贯穿了LKKernel的校验过程[^1]。 §§相关问题§§ 1. AVB验证vbmeta.img的具体步骤是什么? 2. 如何配置AVB密钥(如oem_prvk.pem和avbkey.h)以确保启动安全? 3. 如果vbmeta.img验证失败,系统启动流程会怎样处理? 4. AVB除了验证Kernel,还验证哪些分区? 5. 在LK中,AVB验证的代码流程是怎样的?</think>### 判断AVB是否参与LKKernel的校验过程 根据引用[1]和系统启动流程分析,**AVB(Android Verified Boot)直接参与并主导了LKKernel的校验过程**。具体机制如下: #### 1. **AVB在校验流程中的核心作用** - **vbmeta.img的签名与验证** vbmeta.img包含所有受保护分区(包括boot分区中的Kernel)的验证元数据,该文件由OEM私钥(oem_prvk.pem)签名生成。LK启动时通过内置公钥(avbkey.h)验证vbmeta.img的签名完整性[^1]。 - **校验关系表达式** 验证逻辑可表示为: $$ \text{SignatureValid} = \text{Verify}(\text{vbmeta.img}, \text{avbkey.h}) $$ 若验证失败,启动流程终止;成功则提取vbmeta.img中的校验数据。 #### 2. **AVB如何实现Kernel校验** - **Kernel的间接验证** LK并不直接校验Kernel二进制文件,而是通过vbmeta.img中的元数据验证boot分区(包含Kernel)的完整性: - vbmeta.img存储boot分区的哈希值或哈希树描述符 - LK计算boot分区实际哈希值:$ \text{Hash}_{\text{actual}} = \text{SHA256}(\text{boot分区数据}) $ - 与vbmeta.img中的$ \text{Hash}_{\text{vbmeta}} $比对 - **密钥分离设计** 引用[1]明确指出:AVB使用的密钥(oem_prvk.pem/avbkey.h)与Secure Boot其他分区的校验密钥独立,但可配置为同一组密钥[^1]。 #### 3. **在启动流程中的定位** | 阶段 | 校验对象 | AVB参与 | 执行位置 | |-------------|-------------|--------|---------| | BootROM | Preloader | ❌ | SRAM | | Preloader | LK | ❌ | SRAM | | **LK** | **Kernel** | **✓** | **DRAM**| - **关键结论**: LKKernel的校验本质是由AVB机制在DRAM中完成,具体表现为: 1. LK加载vbmeta.img到DRAM 2. 使用avbkey.h公钥验证其签名 3. 通过vbmeta.img的元数据验证boot分区(含Kernel) #### 4. **安全隔离设计** AVB的密钥体系与Secure Boot解耦,但共同构成防御纵深: ```mermaid graph LR A[Secure Boot密钥] -->|校验Preloader/LK| B[Bootloader] C[AVB密钥] -->|校验vbmeta.img| D[Kernel/系统分区] B --> D ``` 这种设计确保即使Secure Boot密钥泄露,攻击者仍需突破AVB才能篡改Kernel[^1]。 ### 总结 **AVB是LK校验Kernel的核心机制**: - ✅ AVB提供vbmeta.img签名验证框架 - ✅ LK通过vbmeta.img间接校验Kernel完整性 - ✅ 校验过程发生在DRAM中的LK运行阶段 - ✅ 使用独立于Secure Boot的密钥体系(可配置相同) 因此,脱离AVB机制谈"LK校验Kernel"是不完整的——AVB是Android启动链中Kernel验证的实际执行者。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值