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加載在內核中的地址開始運行了。

      

        到這里LK的啟動過程就結束了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM