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的啓動過程就結束了。