日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Bootloader LittleKernel的两篇文章 【转】

發(fā)布時(shí)間:2023/12/6 Android 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Bootloader LittleKernel的两篇文章 【转】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)自:http://blog.csdn.net/loongembedded/article/details/41747523

?分類: Android Bootloader(68)?

Android?開發(fā)之 ---- bootloader (LK)

?

LK是什么

???????????LK 是 Little Kernel 它是 appsbl (Applications ARM Boot Loader)流程代碼? ,little kernel 是小內(nèi)核小操作系統(tǒng)。

?????????? LK 代碼 在 bootable/bootloadler/lk 目錄下

?????????? LK 代碼結(jié)構(gòu)

?????????? +app??????????? // 應(yīng)用相關(guān)

?????????? +arch?????????? // arm 體系?

?????????? +dev??????????? // 設(shè)備相關(guān)

?????????? +include????? // 頭文件

?????????? +kernel??????? // lk系統(tǒng)相關(guān)???

?????????? +platform??? //?相關(guān)驅(qū)動(dòng)

?????????? +projiect???? // makefile文件

?????????? +scripts????? // Jtag 腳本

?????????? +target??????? // 具體板子相關(guān)


LK 流程分析

????????? 在?bootable/bootloadler/lk/arch/arm/ssystem-onesegment.ld 連接文件中 ENTRY(_start)指定 LK 從_start 函數(shù)開始,_start 在 lk/arch/crt0.S中 。crt0.S 主要做一些基本的 CPU 的初始化再通過 bl? kmain ;跳轉(zhuǎn)到 C 代碼中。

????????? kmain 在 lk/kernel/main.c 中


kmain()

??????????? kmain 主要做兩件事:1、本身 lk 這個(gè)系統(tǒng)模塊的初始化;2、boot 的啟動(dòng)初始化動(dòng)作。

??????????? kmain 源碼分析:

???????????? void kmain()

????????? {

???????????1.初始化進(jìn)程(lk 中的簡單進(jìn)程)相關(guān)結(jié)構(gòu)體。

?????? ? ? ? thread_init_early();

???????????2.做一些如 關(guān)閉 cache,使能 mmu 的 arm 相關(guān)工作。

??????????? arch_early_init();

?????????? 3.相關(guān)平臺(tái)的早期初始化

??????????? platform_early_init();

???????????4.現(xiàn)在就一個(gè)函數(shù)跳轉(zhuǎn),初始化UART(板子相關(guān))

??????????? target_early_init();

???????????5.構(gòu)造函數(shù)相關(guān)初始化

??????? ? ? call_constructors();

???????????6.lk系統(tǒng)相關(guān)的堆棧初始化

??????????? heap_init();

?????????? 7.簡短的初始化定時(shí)器對(duì)象

??????????? thread_init();

???????????8.lk系統(tǒng)控制器初始化(相關(guān)事件初始化)

??????????? dpc_init();

???????????9.初始化lk中的定時(shí)器

??????????? timer_init();
???????????
10.新建線程入口函數(shù)?bootstrap2 用于boot 工作(重點(diǎn))
?????????? thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));

?????????}

???以上與 boot 啟動(dòng)初始化相關(guān)函數(shù)是?arch_early_init、? platform_early_init 、bootstrap2,這些是啟動(dòng)的重點(diǎn),我們下面慢慢來看。


arch_early_init()

?????????體系架構(gòu)相關(guān)的初始化我們一般用的 ARM 體系

?????????1.關(guān)閉cache

???????? arch_disable_cache(UCACHE);

?????????2.設(shè)置向量基地址(中斷相關(guān))

???????? set_vector_base(MEMBASE);

?????????3.初始化MMU

???????? arm_mmu_init();

?????????4.初始化MMU映射__平臺(tái)相關(guān)

???????? 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.設(shè)置使能 fpexc 位?(中斷相關(guān))

??? ??? __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.使能循環(huán)計(jì)數(shù)寄存器

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

??????? en &= ~(1<<3);?/*循環(huán)計(jì)算每個(gè)周期*/

??????? en |= 1;?

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

???????9.使能循環(huán)計(jì)數(shù)器

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


platform_early_init()

???????平臺(tái)相關(guān)初始化不同平臺(tái)不同的初始化下面是msm7x30

? ? ? ??1.初始化中斷

?? ?? ??platform_init_interrupts();

????????2.初始化定時(shí)器

????????platform_init_timer();


bootstrap2?

?????????bootstrap2?在kmain的末尾以線程方式開啟。主要分三步:platform_init、target_init、apps_init。

????????1.platform_init

???????????????platform_init 中主要是函數(shù) acpu_clock_init。

?????????????? 在 acpu_clock_init?對(duì) arm11 進(jìn)行系統(tǒng)時(shí)鐘設(shè)置,超頻?

????????2.target_init

??????????? ? 針對(duì)硬件平臺(tái)進(jìn)行設(shè)置。主要對(duì) arm9 和 arm11 的分區(qū)表進(jìn)行整合,初始化flash和讀取FLASH信息

? ? ? ??3.apps_init??

???????????? apps_init 是關(guān)鍵,對(duì) LK 中所謂 app 初始化并運(yùn)行起來,而 aboot_init 就將在這里開始被運(yùn)行,android?Linux?內(nèi)核的加載工作就在 aboot_init 中完成的 。


aboot_init

????????1.設(shè)置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.讀取按鍵信息,判斷是正常開機(jī),還是進(jìn)入 fastboot ,還是進(jìn)入recovery 模式

?????? 。。。。。。。。。

??????通過一系列的 if (keys_get_state() == XXX) 判斷

?????? 。。。。。。。。。

????? 3.從 nand 中加載 內(nèi)核

??????boot_linux_from_flash();

?

????? partition_dump();

????? sz = target_get_max_flash_size();

????? fastboot_init(target_get_scratch_address(), sz);

????? udc_start(); // 開始 USB 協(xié)議

?


boot_linux_from_flash

???????????? 主要是內(nèi)核的加載過程,我們的 boot.img 包含:kernel 頭、kernel、ramdisk、second stage(可以沒有)。

???????????1.讀取boot 頭部

?????????? flash_read(p, offset, raw_header, 2048)?

?????????? offset += 2048;
? ? ? ? ???
2.讀取 內(nèi)核 ???
?????????? 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.啟動(dòng)內(nèi)核

????????????? ??boot_linux();//在boot_linux 中entry(0,machtype,tags);從kernel加載在內(nèi)核中的地址開始運(yùn)行了。

??????

????????到這里L(fēng)K的啟動(dòng)過程就結(jié)束了。

?

Android Kernel - Boot Loader

Android Boot loader 的 code 在 bootable/bootloader/lk 底下, LK 是 Little Kernel 的縮寫, 是 andriod bootloader 的核心精神.

?

入口函數(shù)在 kernel/main.c 中的 kmain(), 以下就來讀讀這一段 code.

?

?

[c-sharp]?view plaincopyprint?
  • void?kmain(void)??
  • {??
  • ????//?get?us?into?some?sort?of?thread?context???
  • ????thread_init_early();??
  • ????//?early?arch?stuff???
  • ????arch_early_init();??
  • ????//?do?any?super?early?platform?initialization???
  • ????platform_early_init();??
  • ????//?do?any?super?early?target?initialization???
  • ????target_early_init();??
  • ????dprintf(INFO,?"welcome?to?lk/n/n");??
  • ??????
  • ????//?deal?with?any?static?constructors???
  • ????dprintf(SPEW,?"calling?constructors/n");??
  • ????call_constructors();??
  • ????//?bring?up?the?kernel?heap???
  • ????dprintf(SPEW,?"initializing?heap/n");??
  • ????heap_init();??
  • ????//?initialize?the?threading?system???
  • ????dprintf(SPEW,?"initializing?threads/n");??
  • ????thread_init();??
  • ????//?initialize?the?dpc?system???
  • ????dprintf(SPEW,?"initializing?dpc/n");??
  • ????dpc_init();??
  • ????//?initialize?kernel?timers???
  • ????dprintf(SPEW,?"initializing?timers/n");??
  • ????timer_init(); ?
  • #if?(!ENABLE_NANDWRITE)???
  • ????//?create?a?thread?to?complete?system?initialization???
  • ????dprintf(SPEW,?"creating?bootstrap?completion?thread/n");??
  • ????thread_resume(thread_create("bootstrap2",?&bootstrap2,?NULL,?DEFAULT_PRIORITY,?DEFAULT_STACK_SIZE));??
  • ????//?enable?interrupts???
  • ????exit_critical_section();??
  • ????//?become?the?idle?thread???
  • ????thread_become_idle(); ?
  • #else???
  • ????????bootstrap_nandwrite(); ?
  • #endif???
  • }??
  • ?

    ?

    ?

    In include/debug.h: 我們可以看到 dprintf 的第一個(gè)參數(shù)是代表 debug level.

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • /*?debug?levels?*/?
  • #define?CRITICAL?0??
  • #define?ALWAYS?0??
  • #define?INFO?1??
  • #define?SPEW?2??
  • ?

    ?

    ?

    In include/debug.h:?

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • #define?dprintf(level,?x...)?do?{?if?((level)?<=?DEBUGLEVEL)?{?_dprintf(x);?}?}?while?(0)??
  • ?

    ?

    ?

    所以 dprintf 會(huì)依 DEBUGLEVEL 來判斷是否輸出信息.

    ?

    來看第一個(gè) call 的函數(shù): thread_init_early, define in thread.c

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?thread_init_early(void)??
  • {??
  • ????????int?i;??
  • ????????/*?initialize?the?run?queues?*/??
  • ????????for?(i=0;?i?<?NUM_PRIORITIES;?i++)??
  • ????????????????list_initialize(&run_queue[i]);??
  • ????????/*?initialize?the?thread?list?*/??
  • ????????list_initialize(&thread_list);??
  • ????????/*?create?a?thread?to?cover?the?current?running?state?*/??
  • ????????thread_t?*t?=?&bootstrap_thread;??
  • ????????init_thread_struct(t,?"bootstrap");??
  • ????????/*?half?construct?this?thread,?since?we're?already?running?*/??
  • ????????t->priority?=?HIGHEST_PRIORITY;??
  • ????????t->state?=?THREAD_RUNNING;??
  • ????????t->saved_critical_section_count?=?1;??
  • ????????list_add_head(&thread_list,?&t->thread_list_node);??
  • ????????current_thread?=?t;??
  • }??
  • ?

    ?

    ?

    #define NUM_PRIORITIES 32 in include/kernel/thread.h

    ?

    list_initialize() defined in include/list.h: initialized a list

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • static?inline?void?list_initialize(struct?list_node?*list)??
  • {??
  • ????????list->prev?=?list->next?=?list;??
  • }??
  • ?

    ?

    ?

    run_queue 是?static struct list_node run_queue[NUM_PRIORITIES]

    ?

    thread_list 是?static struct list_node thread_list

    ?

    再來要 call ?的函數(shù)是: arch_early_init() defined in?arch/arm/arch.c

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?arch_early_init(void)??
  • {??
  • ????/*?turn?off?the?cache?*/??
  • ????arch_disable_cache(UCACHE);??
  • ????/*?set?the?vector?base?to?our?exception?vectors?so?we?dont?need?to?double?map?at?0?*/?
  • #if?ARM_CPU_CORTEX_A8???
  • ????set_vector_base(MEMBASE); ?
  • #endif??
  • #if?ARM_WITH_MMU???
  • ????arm_mmu_init();??
  • ????platform_init_mmu_mappings(); ?
  • #endif???
  • ????/*?turn?the?cache?back?on?*/??
  • ????arch_enable_cache(UCACHE); ?
  • #if?ARM_WITH_NEON???
  • ????/*?enable?cp10?and?cp11?*/??
  • ????uint32_t?val;??
  • ????__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));??
  • ????/*?set?enable?bit?in?fpexc?*/??
  • ????val?=?(1<<30);??
  • ????__asm__?volatile("mcr??p10,?7,?%0,?c8,?c0,?0"?::?"r"?(val)); ?
  • #endif???
  • }??
  • ?

    ?

    ?

    現(xiàn)代操作系統(tǒng)普遍采用虛擬內(nèi)存管理(Virtual Memory Management)機(jī)制,這需要處理器中的MMU(Memory Management Unit,

    ?

    內(nèi)存管理單元)提供支持。

    ?

    CPU執(zhí)行單元發(fā)出的內(nèi)存地址將被MMU截獲,從CPU到MMU的地址稱為虛擬地址(Virtual Address,以下簡稱VA),而MMU將這個(gè)地

    ?

    址翻譯成另一個(gè)地址發(fā)到CPU芯片的外部地址引腳上,也就是將VA映射成PA

    ?

    MMU將VA映射到PA是以頁(Page)為單位的,32位處理器的頁尺寸通常是4KB。例如,MMU可以通過一個(gè)映射項(xiàng)將VA的一頁

    ?

    0xb7001000~0xb7001fff映射到PA的一頁0x2000~0x2fff,如果CPU執(zhí)行單元要訪問虛擬地址0xb7001008,則實(shí)際訪問到的物理地

    ?

    址是0x2008。物理內(nèi)存中的頁稱為物理頁面或者頁幀(Page Frame)。虛擬內(nèi)存的哪個(gè)頁面映射到物理內(nèi)存的哪個(gè)頁幀是通過頁

    ?

    表(Page Table)來描述的,頁表保存在物理內(nèi)存中,MMU會(huì)查找頁表來確定一個(gè)VA應(yīng)該映射到什么PA。

    ?

    ?

    ?

    操作系統(tǒng)和MMU是這樣配合的:

    ?

    1. 操作系統(tǒng)在初始化或分配、釋放內(nèi)存時(shí)會(huì)執(zhí)行一些指令在物理內(nèi)存中填寫頁表,然后用指令設(shè)置MMU,告訴MMU頁表在物理內(nèi)存中

    ?

    ?? 的什么位置。

    ?

    2. 設(shè)置好之后,CPU每次執(zhí)行訪問內(nèi)存的指令都會(huì)自動(dòng)引發(fā)MMU做查表和地址轉(zhuǎn)換操作,地址轉(zhuǎn)換操作由硬件自動(dòng)完成,不需要用指令

    ?

    ?? ?控制MMU去做。

    ?

    ?

    MMU除了做地址轉(zhuǎn)換之外,還提供內(nèi)存保護(hù)機(jī)制。各種體系結(jié)構(gòu)都有用戶模式(User Mode)和特權(quán)模式(Privileged Mode)之分,

    ?

    操作系統(tǒng)可以在頁表中設(shè)置每個(gè)內(nèi)存頁面的訪問權(quán)限,有些頁面不允許訪問,有些頁面只有在CPU處于特權(quán)模式時(shí)才允許訪問,有些頁面

    ?

    在用戶模式和特權(quán)模式都可以訪問,訪問權(quán)限又分為可讀、可寫和可執(zhí)行三種。這樣設(shè)定好之后,當(dāng)CPU要訪問一個(gè)VA時(shí),MMU會(huì)檢查

    ?

    CPU當(dāng)前處于用戶模式還是特權(quán)模式,訪問內(nèi)存的目的是讀數(shù)據(jù)、寫數(shù)據(jù)還是取指令,如果和操作系統(tǒng)設(shè)定的頁面權(quán)限相符,就允許訪

    ?

    問,把它轉(zhuǎn)換成PA,否則不允許訪問,產(chǎn)生一個(gè)異常(Exception)

    ?

    常見的 segmentation fault 產(chǎn)生的原因:

    ?

    用戶程序要訪問一段 VA, 經(jīng) MMU 檢查后無權(quán)訪問, MMU 會(huì)產(chǎn)生異常, CPU 從用戶模式切換到特權(quán)模式, 跳轉(zhuǎn)到內(nèi)核代碼中執(zhí)行異常服務(wù)程序.

    ?

    內(nèi)核就會(huì)把這個(gè)異常解釋為 segmentation fault, 將引發(fā)異常的程序終止.

    ?

    簡單的講一下 NEON:?NEON technology can accelerate multimedia and signal processing algorithms such as video encode/decode,

    ?

    2D/3D graphics, gaming, audio and speech processing,?image processing, telephony, and sound synthesis.

    ?

    platform_early_init() defined in platform/<your-platform>/platform.c

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?platform_early_init(void)??
  • {??
  • ????uart_init();??
  • ????platform_init_interrupts();??
  • ????platform_init_timer();??
  • }??
  • ?

    ?

    ?

    uart_init.c defined in platform/<your-platform>/uart.c 所有用到的變數(shù),也都定義在 uart.c

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?uart_init(void)??
  • {??
  • ????uwr(0x0A,?UART_CR);??/*?disable?TX?and?RX?*/??
  • ??????
  • ????uwr(0x30,?UART_CR);??/*?reset?error?status?*/??
  • ????uwr(0x10,?UART_CR);??/*?reset?receiver?*/??
  • ????uwr(0x20,?UART_CR);??/*?reset?transmitter?*/?
  • ?????
  • #if?PLATFORM_QSD8K???
  • ????/*?TCXO?*/??
  • ????uwr(0x06,?UART_MREG);??
  • ????uwr(0xF1,?UART_NREG);??
  • ????uwr(0x0F,?UART_DREG);??
  • ????uwr(0x1A,?UART_MNDREG); ?
  • #else???
  • ????/*?TCXO/4?*/??
  • ????uwr(0xC0,?UART_MREG);??
  • ????uwr(0xAF,?UART_NREG);??
  • ????uwr(0x80,?UART_DREG);??
  • ????uwr(0x19,?UART_MNDREG);???? ?
  • #endif???
  • ??????
  • ????uwr(0x10,?UART_CR);??/*?reset?RX?*/??
  • ????uwr(0x20,?UART_CR);??/*?reset?TX?*/??
  • ????uwr(0x30,?UART_CR);??/*?reset?error?status?*/??
  • ????uwr(0x40,?UART_CR);??/*?reset?RX?break?*/??
  • ????uwr(0x70,?UART_CR);??/*?rest??*/??
  • ????uwr(0xD0,?UART_CR);??/*?reset?*/??
  • ??????
  • ????uwr(0x7BF,?UART_IPR);?/*?stale?timeout?=?630?*?bitrate?*/??
  • ????uwr(0,?UART_IMR);??
  • ????uwr(115,?UART_RFWR);?/*?RX?watermark?=?58?*?2?-?1?*/??
  • ????uwr(10,?UART_TFWR);??/*?TX?watermark?*/??
  • ??????
  • ????uwr(0,?UART_RFWR);???
  • ??????
  • ????uwr(UART_CSR_115200,?UART_CSR);??
  • ????uwr(0,?UART_IRDA);??
  • ????uwr(0x1E,?UART_HCR);??
  • //??uwr(0x7F4,?UART_MR1);?/*?RFS/?CTS/?500chr?RFR?*/???
  • ????uwr(16,?UART_MR1);??
  • ????uwr(0x34,?UART_MR2);?/*?8N1?*/??
  • ??????
  • ????uwr(0x05,?UART_CR);?/*?enable?TX?&?RX?*/??
  • ????uart_ready?=?1;??
  • }??
  • ?

    ?

    ?

    platform_init_interrupts: defined in platform/msm8x60/interrupts.c

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?platform_init_interrupts(void)??
  • {??
  • ????platform_gic_dist_init();??
  • ????platform_gic_cpu_init();??
  • }??
  • ?

    ?

    ?

    GIC 指的是 Generic Interrupt Controller. The gic-cpu and gic-dist are two subcomponents of GIC.

    ?

    Devices are wired to the?Git-dist which is in charge of distributing interrupts to the gic-cpu (per cpu IRQ IF).

    ?

    platform_init_timer(): defined in platform/<your-platform>/timer.c

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?platform_init_timer(void)??
  • {??
  • ????writel(0,?DGT_ENABLE);??
  • }??
  • ?

    ?

    ?

    DGT: Digital Game Timer: presents the countdowns of two players, it is also called chess timer or chess clock.

    ?

    target_early_init(): defined in target/init.c

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • /*?
  • ?*?default?implementations?of?these?routines,?if?the?target?code?
  • ?*?chooses?not?to?implement.?
  • ?*/??
  • __WEAK?void?target_early_init(void)??
  • {??
  • }??
  • __WEAK?void?target_init(void)??
  • {??
  • }??
  • ?

    ?

    ?

    call_constructors() is defined in kernel/main.c:

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • static?void?call_constructors(void)??
  • {??
  • ????void?**ctor;??
  • ?????
  • ????ctor?=?&__ctor_list;??
  • ????while(ctor?!=?&__ctor_end)?{??
  • ????????void?(*func)(void);??
  • ????????func?=?(void?(*)())*ctor;??
  • ????????func();??
  • ????????ctor++;??
  • ????}??
  • }??
  • ?

    ?

    ?

    ?

    heap_init is defined in lib/heap/heap.c:

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?heap_init(void)??
  • {??
  • ????LTRACE_ENTRY;??
  • ????//?set?the?heap?range???
  • ????theheap.base?=?(void?*)HEAP_START;??
  • ????theheap.len?=?HEAP_LEN;??
  • ????LTRACEF("base?%p?size?%zd?bytes/n",?theheap.base,?theheap.len);??
  • ????//?initialize?the?free?list???
  • ????list_initialize(&theheap.free_list);??
  • ????//?create?an?initial?free?chunk???
  • ????heap_insert_free_chunk(heap_create_free_chunk(theheap.base,?theheap.len));??
  • ????//?dump?heap?info???
  • //??heap_dump();???
  • //??dprintf(INFO,?"running?heap?tests/n");???
  • //??heap_test();???
  • }??
  • ?

    ?

    ?

    ?

    thread_init is defined in kernel/thread.c but nothing coded, 先記下.

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?thread_init(void)??
  • {??
  • }??
  • ?

    ?

    ?

    dpc_init() is defined in kernel/dpc.c:

    ?

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?dpc_init(void)??
  • {??
  • ????event_init(&dpc_event,?false,?0);??
  • ????thread_resume(thread_create("dpc",?&dpc_thread_routine,?NULL,?DPC_PRIORITY,?DEFAULT_STACK_SIZE));??
  • }??
  • ?

    ?

    ?

    dpc 為 Delayed Procedure Call 延遲過程調(diào)用的縮寫.

    ?

    timer_init() is defined in kernel/timer.c:

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?timer_init(void)??
  • {??
  • ????list_initialize(&timer_queue);??
  • ????/*?register?for?a?periodic?timer?tick?*/??
  • ????platform_set_periodic_timer(timer_tick,?NULL,?10);?/*?10ms?*/??
  • }??
  • ?

    ?

    ?

    ?

    ?

    執(zhí)行 thread_resume 或是 bootstrap_nandwrite

    ?

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • #if?(!ENABLE_NANDWRITE)???
  • ????//?create?a?thread?to?complete?system?initialization???
  • ????dprintf(SPEW,?"creating?bootstrap?completion?thread/n");??
  • ????thread_resume(thread_create("bootstrap2",?&bootstrap2,?NULL,?DEFAULT_PRIORITY,?DEFAULT_STACK_SIZE));??
  • ????//?enable?interrupts???
  • ????exit_critical_section();??
  • ????//?become?the?idle?thread???
  • ????thread_become_idle(); ?
  • #else???
  • ????????bootstrap_nandwrite(); ?
  • #endif??
  • ?

    ?

    ?

    In kermel/main.c:

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • static?int?bootstrap2(void?*arg)??
  • {??
  • ????dprintf(SPEW,?"top?of?bootstrap2()/n");??
  • ????arch_init();??
  • ????//?initialize?the?rest?of?the?platform???
  • ????dprintf(SPEW,?"initializing?platform/n");??
  • ????platform_init();??
  • ??????
  • ????//?initialize?the?target???
  • ????dprintf(SPEW,?"initializing?target/n");??
  • ????target_init();??
  • ????dprintf(SPEW,?"calling?apps_init()/n");??
  • ????apps_init();??
  • ????return?0;??
  • } ?
  • #if?(ENABLE_NANDWRITE)???
  • void?bootstrap_nandwrite(void)??
  • {??
  • ????dprintf(SPEW,?"top?of?bootstrap2()/n");??
  • ????arch_init();??
  • ????//?initialize?the?rest?of?the?platform???
  • ????dprintf(SPEW,?"initializing?platform/n");??
  • ????platform_init();??
  • ????//?initialize?the?target???
  • ????dprintf(SPEW,?"initializing?target/n");??
  • ????target_init();??
  • ????dprintf(SPEW,?"calling?nandwrite_init()/n");??
  • ????nandwrite_init();??
  • ????return?0;??
  • } ?
  • #endif??
  • ?

    ?

    ?

    continue to see apps_init():?app/app.c:void apps_init(void)

    ?

    ?

    [c-sharp]?view plaincopyprint?
  • #include?<app.h>??
  • #include?<kernel/thread.h>???
  • extern?const?struct?app_descriptor?__apps_start;??
  • extern?const?struct?app_descriptor?__apps_end;??
  • static?void?start_app(const?struct?app_descriptor?*app);??
  • /*?one?time?setup?*/??
  • void?apps_init(void)??
  • {??
  • ????const?struct?app_descriptor?*app;??
  • ????/*?call?all?the?init?routines?*/??
  • ????for?(app?=?&__apps_start;?app?!=?&__apps_end;?app++)?{??
  • ????????if?(app->init)??
  • ????????????app->init(app);??
  • ????}??
  • ????/*?start?any?that?want?to?start?on?boot?*/??
  • ????for?(app?=?&__apps_start;?app?!=?&__apps_end;?app++)?{??
  • ????????if?(app->entry?&&?(app->flags?&?APP_FLAG_DONT_START_ON_BOOT)?==?0)?{??
  • ????????????start_app(app);??
  • ????????}??
  • ????}??
  • }??
  • static?int?app_thread_entry(void?*arg)??
  • {??
  • ????const?struct?app_descriptor?*app?=?(const?struct?app_descriptor?*)arg;??
  • ????app->entry(app,?NULL);??
  • ????return?0;??
  • }??
  • static?void?start_app(const?struct?app_descriptor?*app)??
  • {??
  • ????printf("starting?app?%s/n",?app->name);??
  • ????thread_resume(thread_create(app->name,?&app_thread_entry,?(void?*)app,?DEFAULT_PRIORITY,?DEFAULT_STACK_SIZE));?????
  • }??
  • ?

    ?

    ?

    至于會(huì)有那些 app 被放入 boot thread section, 則定義在 include/app.h 中的 APP_START(appname)

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • #define?APP_START(appname)?struct?app_descriptor?_app_##appname?__SECTION(".apps")?=?{?.name?=?#appname,?
  • #define?APP_END?};??
  • ?

    ?

    ?

    在 app 中只要像 app/aboot/aboot.c 指定就會(huì)在 bootloader bootup 時(shí)放入 thread section 中被執(zhí)行.

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • APP_START(aboot)??
  • ????????.init?=?aboot_init,??
  • APP_END??
  • ?

    ?

    ?

    在我的 bootloader 中有 app/aboot/aboot.c, app/tests/tests.c, app/shell/shell.c, 及 app/stringtests/string_tests.c 皆有此聲明.

    ?

    接下來關(guān)注: aboot.c 中的 aboot_init()

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?aboot_init(const?struct?app_descriptor?*app)??
  • {??
  • ????unsigned?reboot_mode?=?0;??
  • ????unsigned?disp_init?=?0;??
  • ????unsigned?usb_init?=?0;??
  • ????//test_ram();???
  • ????/*?Setup?page?size?information?for?nand/emmc?reads?*/??
  • ????if?(target_is_emmc_boot())??
  • ????{??
  • ????????page_size?=?2048;??
  • ????????page_mask?=?page_size?-?1;??
  • ????}??
  • ????else??
  • ????{??
  • ????????page_size?=?flash_page_size();??
  • ????????page_mask?=?page_size?-?1;??
  • ????}??
  • ????/*?Display?splash?screen?if?enabled?*/?
  • ????#if?DISPLAY_SPLASH_SCREEN???
  • ????display_init();??
  • ????dprintf(INFO,?"Diplay?initialized/n");??
  • ????disp_init?=?1;??
  • ????diplay_image_on_screen(); ?
  • ????#endif???
  • ????/*?Check?if?we?should?do?something?other?than?booting?up?*/??
  • ????if?(keys_get_state(KEY_HOME)?!=?0)??
  • ????????boot_into_recovery?=?1;??
  • ????if?(keys_get_state(KEY_BACK)?!=?0)??
  • ????????goto?fastboot;??
  • ????if?(keys_get_state(KEY_CLEAR)?!=?0)??
  • ????????goto?fastboot; ?
  • ????#if?NO_KEYPAD_DRIVER???
  • ????/*?With?no?keypad?implementation,?check?the?status?of?USB?connection.?*/??
  • ????/*?If?USB?is?connected?then?go?into?fastboot?mode.?*/??
  • ????usb_init?=?1;??
  • ????udc_init(&surf_udc_device);??
  • ????if?(usb_cable_status())??
  • ????????goto?fastboot; ?
  • ????#endif???
  • ????init_vol_key();??
  • ????if(voldown_press())??
  • ????????goto?fastboot;??
  • ????reboot_mode?=?check_reboot_mode();??
  • ????if?(reboot_mode?==?RECOVERY_MODE)?{??
  • ????????boot_into_recovery?=?1;??
  • ????}?else?if(reboot_mode?==?FASTBOOT_MODE)?{??
  • ????????goto?fastboot;??
  • ????}??
  • ????if?(target_is_emmc_boot())??
  • ????{??
  • ????????boot_linux_from_mmc();??
  • ????}??
  • ????else??
  • ????{??
  • ????????recovery_init();??
  • ????????boot_linux_from_flash();??
  • ????}??
  • ????dprintf(CRITICAL,?"ERROR:?Could?not?do?normal?boot.?Reverting?"??
  • ????????"to?fastboot?mode./n");??
  • fastboot:??
  • ????if(!usb_init)??
  • ????????udc_init(&surf_udc_device);??
  • ????fastboot_register("boot",?cmd_boot);??
  • ????if?(target_is_emmc_boot())??
  • ????{??
  • ????????fastboot_register("flash:",?cmd_flash_mmc);??
  • ????????fastboot_register("erase:",?cmd_erase_mmc);??
  • ????}??
  • ????else??
  • ????{??
  • ????????fastboot_register("flash:",?cmd_flash);??
  • ????????fastboot_register("erase:",?cmd_erase);??
  • ????}??
  • ????fastboot_register("continue",?cmd_continue);??
  • ????fastboot_register("reboot",?cmd_reboot);??
  • ????fastboot_register("reboot-bootloader",?cmd_reboot_bootloader);??
  • ????fastboot_publish("product",?TARGET(BOARD));??
  • ????fastboot_publish("kernel",?"lk");??
  • ??????
  • ????fastboot_init(target_get_scratch_address(),?120?*?1024?*?1024);??
  • ??????
  • ????udc_start();??
  • ????target_battery_charging_enable(1,?0);??
  • }??
  • ?

    ?

    ?


    ?

    target_is_emmc_boot() is defined in target/init.c: _EMMC_BOOT 是 compiler 時(shí)的 flags

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • __WEAK?int?target_is_emmc_boot(void)??
  • { ?
  • #if?_EMMC_BOOT???
  • ????return?1; ?
  • #else???
  • ????return?0; ?
  • #endif???
  • }??
  • ?

    ?

    ?

    check_reboot_mode is defined in target/<your-platform>/init.c:

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • unsigned?check_reboot_mode(void)??
  • {??
  • ????????unsigned?restart_reason?=?0;??
  • ????????void?*restart_reason_addr?=?0x401FFFFC;??
  • ????????/*?Read?reboot?reason?and?scrub?it?*/??
  • ????????restart_reason?=?readl(restart_reason_addr);??
  • ????????writel(0x00,?restart_reason_addr);??
  • ????????return?restart_reason;??
  • }??
  • ?

    ?

    ?

    reboot mode in bootloader:

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • #define?RECOVERY_MODE???0x77665502??
  • #define?FASTBOOT_MODE???0x77665500??
  • ?

    ?

    ?

    ?

    再來就會(huì)執(zhí)行?boot_linux_from_mmc():

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • int?boot_linux_from_mmc(void)??
  • {??
  • ????struct?boot_img_hdr?*hdr?=?(void*)?buf;??
  • ????struct?boot_img_hdr?*uhdr;??
  • ????unsigned?offset?=?0;??
  • ????unsigned?long?long?ptn?=?0;??
  • ????unsigned?n?=?0;??
  • ????const?char?*cmdline;??
  • ????uhdr?=?(struct?boot_img_hdr?*)EMMC_BOOT_IMG_HEADER_ADDR;??
  • ????if?(!memcmp(uhdr->magic,?BOOT_MAGIC,?BOOT_MAGIC_SIZE))?{??
  • ????????dprintf(INFO,?"Unified?boot?method!/n");??
  • ????????hdr?=?uhdr;??
  • ????????goto?unified_boot;??
  • ????}??
  • ????if(!boot_into_recovery)??
  • ????{??
  • ????????ptn?=?mmc_ptn_offset("boot");??
  • ????????if(ptn?==?0)?{??
  • ????????????dprintf(CRITICAL,?"ERROR:?No?boot?partition?found/n");??
  • ????????????????????return?-1;??
  • ????????}??
  • ????}??
  • ????else??
  • ????{??
  • ????????ptn?=?mmc_ptn_offset("recovery");??
  • ????????if(ptn?==?0)?{??
  • ????????????dprintf(CRITICAL,?"ERROR:?No?recovery?partition?found/n");??
  • ????????????????????return?-1;??
  • ????????}??
  • ????}??
  • ????if?(mmc_read(ptn?+?offset,?(unsigned?int?*)buf,?page_size))?{??
  • ????????dprintf(CRITICAL,?"ERROR:?Cannot?read?boot?image?header/n");??
  • ????????????????return?-1;??
  • ????}??
  • ????if?(memcmp(hdr->magic,?BOOT_MAGIC,?BOOT_MAGIC_SIZE))?{??
  • ????????dprintf(CRITICAL,?"ERROR:?Invaled?boot?image?header/n");??
  • ????????????????return?-1;??
  • ????}??
  • ????if?(hdr->page_size?&&?(hdr->page_size?!=?page_size))?{??
  • ????????page_size?=?hdr->page_size;??
  • ????????page_mask?=?page_size?-?1;??
  • ????}??
  • ????offset?+=?page_size;??
  • ????n?=?ROUND_TO_PAGE(hdr->kernel_size,?page_mask);??
  • ????if?(mmc_read(ptn?+?offset,?(void?*)hdr->kernel_addr,?n))?{??
  • ????????dprintf(CRITICAL,?"ERROR:?Cannot?read?kernel?image/n");??
  • ????????????????return?-1;??
  • ????}??
  • ????offset?+=?n;??
  • ????n?=?ROUND_TO_PAGE(hdr->ramdisk_size,?page_mask);??
  • ????if?(mmc_read(ptn?+?offset,?(void?*)hdr->ramdisk_addr,?n))?{??
  • ????????dprintf(CRITICAL,?"ERROR:?Cannot?read?ramdisk?image/n");??
  • ????????????????return?-1;??
  • ????}??
  • ????offset?+=?n;??
  • unified_boot:??
  • ????dprintf(INFO,?"/nkernel??@?%x?(%d?bytes)/n",?hdr->kernel_addr,??
  • ????????hdr->kernel_size);??
  • ????dprintf(INFO,?"ramdisk?@?%x?(%d?bytes)/n",?hdr->ramdisk_addr,??
  • ????????hdr->ramdisk_size);??
  • ????if(hdr->cmdline[0])?{??
  • ????????cmdline?=?(char*)?hdr->cmdline;??
  • ????}?else?{??
  • ????????cmdline?=?DEFAULT_CMDLINE;??
  • ????}??
  • ????dprintf(INFO,?"cmdline?=?'%s'/n",?cmdline);??
  • ????dprintf(INFO,?"/nBooting?Linux/n");??
  • ????boot_linux((void?*)hdr->kernel_addr,?(void?*)TAGS_ADDR,??
  • ???????????(const?char?*)cmdline,?board_machtype(),??
  • ???????????(void?*)hdr->ramdisk_addr,?hdr->ramdisk_size);??
  • ????return?0;??
  • }??
  • ?

    ?

    ?

    mmc_read() is defined in platform/<your-platform>/mmc.c:

    ?

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • unsigned?int?mmc_read?(unsigned?long?long?data_addr,?unsigned?int*?out,?unsigned?int?data_len)??
  • {??
  • ????int?val?=?0;??
  • ????val?=?mmc_boot_read_from_card(?&mmc_host,?&mmc_card,?data_addr,?data_len,?out);??
  • ????return?val;??
  • }??
  • ?

    ?

    ?

    boot_linux(): 啟動(dòng) Linux, 看看函數(shù)定義

    ?

    [c-sharp:nogutter]?view plaincopyprint?
  • void?boot_linux(void?*kernel,?unsigned?*tags,???
  • ????????const?char?*cmdline,?unsigned?machtype,??
  • ????????void?*ramdisk,?unsigned?ramdisk_size)??
  • {??
  • ????unsigned?*ptr?=?tags;??
  • ????unsigned?pcount?=?0;??
  • ????void?(*entry)(unsigned,unsigned,unsigned*)?=?kernel;??
  • ????struct?ptable?*ptable;??
  • ????int?cmdline_len?=?0;??
  • ????int?have_cmdline?=?0;??
  • ????int?pause_at_bootup?=?0;??
  • ????/*?CORE?*/??
  • ????*ptr++?=?2;??
  • ????*ptr++?=?0x54410001;??
  • ????if?(ramdisk_size)?{??
  • ????????*ptr++?=?4;??
  • ????????*ptr++?=?0x54420005;??
  • ????????*ptr++?=?(unsigned)ramdisk;??
  • ????????*ptr++?=?ramdisk_size;??
  • ????}??
  • ????ptr?=?target_atag_mem(ptr);??
  • ????if?(!target_is_emmc_boot())?{??
  • ????????/*?Skip?NAND?partition?ATAGS?for?eMMC?boot?*/??
  • ????????if?((ptable?=?flash_get_ptable())?&&?(ptable->count?!=?0))?{??
  • ????????????int?i;??
  • ????????????for(i=0;?i?<?ptable->count;?i++)?{??
  • ????????????????struct?ptentry?*ptn;??
  • ????????????????ptn?=??ptable_get(ptable,?i);??
  • ????????????????if?(ptn->type?==?TYPE_APPS_PARTITION)??
  • ????????????????????pcount++;??
  • ????????????}??
  • ????????????*ptr++?=?2?+?(pcount?*?(sizeof(struct?atag_ptbl_entry)?/??
  • ???????????????????????????????sizeof(unsigned)));??
  • ????????????*ptr++?=?0x4d534d70;??
  • ????????????for?(i?=?0;?i?<?ptable->count;?++i)??
  • ????????????????ptentry_to_tag(&ptr,?ptable_get(ptable,?i));??
  • ????????}??
  • ????}??
  • ????if?(cmdline?&&?cmdline[0])?{??
  • ????????cmdline_len?=?strlen(cmdline);??
  • ????????have_cmdline?=?1;??
  • ????}??
  • ????if?(target_is_emmc_boot())?{??
  • ????????cmdline_len?+=?strlen(emmc_cmdline);??
  • ????}??
  • ????if?(target_pause_for_battery_charge())?{??
  • ????????pause_at_bootup?=?1;??
  • ????????cmdline_len?+=?strlen(battchg_pause);??
  • ????}??
  • ????if?(cmdline_len?>?0)?{??
  • ????????const?char?*src;??
  • ????????char?*dst;??
  • ????????unsigned?n;??
  • ????????/*?include?terminating?0?and?round?up?to?a?word?multiple?*/??
  • ????????n?=?(cmdline_len?+?4)?&?(~3);??
  • ????????*ptr++?=?(n?/?4)?+?2;??
  • ????????*ptr++?=?0x54410009;??
  • ????????dst?=?(char?*)ptr;??
  • ????????if?(have_cmdline)?{??
  • ????????????src?=?cmdline;??
  • ????????????while?((*dst++?=?*src++));??
  • ????????}??
  • ????????if?(target_is_emmc_boot())?{??
  • ????????????src?=?emmc_cmdline;??
  • ????????????if?(have_cmdline)?--dst;??
  • ????????????have_cmdline?=?1;??
  • ????????????while?((*dst++?=?*src++));??
  • ????????}??
  • ????????if?(pause_at_bootup)?{??
  • ????????????src?=?battchg_pause;??
  • ????????????if?(have_cmdline)?--dst;??
  • ????????????while?((*dst++?=?*src++));??
  • ????????}??
  • ????????ptr?+=?(n?/?4);??
  • ????}??
  • ????/*?END?*/??
  • ????*ptr++?=?0;??
  • ????*ptr++?=?0;??
  • ????dprintf(INFO,?"booting?linux?@?%p,?ramdisk?@?%p?(%d)/n",??
  • ????????kernel,?ramdisk,?ramdisk_size);??
  • ????if?(cmdline)??
  • ????????dprintf(INFO,?"cmdline:?%s/n",?cmdline);??
  • ????enter_critical_section();??
  • ????platform_uninit_timer();??
  • ????arch_disable_cache(UCACHE);??
  • ????arch_disable_mmu(); ?
  • #if?DISPLAY_SPLASH_SCREEN???
  • ????display_shutdown(); ?
  • #endif???
  • ????entry(0,?machtype,?tags);??
  • }??
  • ?

    ?

    ?

    配合 boot.img 來看會(huì)比較好理解.

    ?

    ?

    ?

    由此可知?boot_img_hdr?中各成員值為:

    ?

    ?

    ?

    TAGS_ADDR 如上 target/<your-platform>/rules.mk 所定義的 : 0x40200100,?所以 boot_linux(), 就是傳入TAGS_ADDR,

    ?

    然后將資料寫入 tag, tag 的結(jié)構(gòu)如下所示.

    ?

    ?

    然后進(jìn)入到 kernel 的入口函數(shù): entry(0, machtype, tags)











    本文轉(zhuǎn)自張昺華-sky博客園博客,原文鏈接:http://www.cnblogs.com/sky-heaven/p/6077828.html,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者


    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的Android Bootloader LittleKernel的两篇文章 【转】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。