出门莫恨无人随,书中车马多如簇。这篇文章主要讲述Android 开发之 ---- bootloader (LK)相关的知识,希望能为你提供帮助。
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加载在内核中的地址开始运行了。
【Android 开发之 ---- bootloader (LK)】
到这里LK的启动过程就结束了。
推荐阅读
- Hadoop 运行jar包时 java.lang.ClassNotFoundException: Class com.zhen.mr.RunJob$HotMapper not found
- CentOS7/RHEL7如何修改swappiness值()
- android studio ndk-builld方式开发
- 如何修复Mac上的“你的系统已用完应用程序内存”错误()
- 如何将Windows 11恢复出厂设置(操作方法分步指南)
- 如何在Windows 11上打开蓝牙(4种简单方法指南)
- 如果我的Mac不断重启怎么办(解决问题的10个技巧)
- 如何在Windows 11中清除缓存(7种有效方法指南)
- 为什么我的Mac风扇声音这么大(修复Mac过热的14种方法!)