日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

U-Boot代碼分析與移植

系統(tǒng) 2070 0

一.摘要

這篇文章主要對BootLoader(UBoot)的源碼進(jìn)行了分析,并對UBoot的移植略作提及。? BootLoader的總目標(biāo)是正確調(diào)用內(nèi)核的執(zhí)行,由于大部分的BoorLoader都依賴于CPU的體系結(jié)構(gòu)。因此大部分的BootLoader都分為兩個(gè)步驟啟動(dòng)。依賴于CPU體系結(jié)構(gòu)(如設(shè)備初始化等)的代碼都放在stage1。而stage2一般使用C語言實(shí)現(xiàn),能夠?qū)崿F(xiàn)更加復(fù)雜的功能,代碼的可移植性也提高。

二.本文提綱

1. 摘要

2.? 本文提綱

3. UBoot啟動(dòng)過程

4. Stage1(匯編語言實(shí)現(xiàn))代碼分析

5. Stage2(C語言實(shí)現(xiàn))代碼分析

6. UBoot移植過程中串口沒有顯示或者顯示亂碼的原因

7. 總結(jié)

三.UBoot啟動(dòng)過程

UBoot其啟動(dòng)過程主要可以分為兩個(gè)部分,Stage1和Stage2 。其中Stage1是用匯編語言實(shí)現(xiàn)的,主要完成硬件資源的初始化。而Stage2則是用C語言實(shí)現(xiàn)。主要完成內(nèi)核程序的調(diào)用。這兩個(gè)部分的主要執(zhí)行流程如下:

stage1包含以下步驟:

1. 硬件設(shè)備初始化

2. 為加載stage2準(zhǔn)備RAM空間

3. 拷貝stage2的代碼到RAM空間

4. 設(shè)置好堆棧

5. 跳轉(zhuǎn)到stage2的C語言入口點(diǎn)

?

stage2一般包括以下步驟:

1. 初始化本階段要使用的硬件設(shè)備

2. 檢測系統(tǒng)內(nèi)存映射

3. 將kernel映射和根文件系統(tǒng)映射從Flash讀到RAM空間中

4. 為內(nèi)核設(shè)置啟動(dòng)參數(shù)

5. 調(diào)用內(nèi)核

四. Stage1(匯編語言實(shí)現(xiàn))代碼分析

該階段主要是在cpu/arm920t/start.S文件中執(zhí)行,這個(gè)匯編程序是U-Boot的入口程序,程序的開頭就是復(fù)位向量的代碼,主要的執(zhí)行流程見下圖。

? U-Boot代碼分析與移植

U-Boot啟動(dòng)代碼流程圖

start.S代碼分析:

(1)主要實(shí)現(xiàn)復(fù)位向量,設(shè)置異常向量表。

      
        _start:
      
       b reset //復(fù)位向量 
      
        ;
      
      
        ;設(shè)置異常向量表
      
      
               ldr pc, _undefined_instruction

       ldr pc, _software_interrupt

       ldr pc, _prefetch_abort

       ldr pc, _data_abort

       ldr pc, _not_used

       ldr pc, _irq //中斷向量

       ldr pc, _fiq //中斷向量
      
    

(2)復(fù)位啟動(dòng)子程序,將CPU設(shè)置到SVC模式

      
        /* the actual reset code */


      
      
        reset:
      
      
         //復(fù)位啟動(dòng)子程序

       /* 設(shè)置CPU為SVC32模式 */

       mrs r0,cpsr

       bic r0,r0,#0x1f 
      
      
        ;
      
      
        ;位清除,將某些位的值置0:r0 = r0 AND ( !0x1f)
      
      

       orr r0,r0,#0xd3 
      
        ;
      
      
        ;邏輯或,將r0與立即數(shù)進(jìn)行邏輯或,放在r0中(第一個(gè))
      
      
               msr cpsr,r0



 
      
    

(3)關(guān)閉看門狗

      
        /* 關(guān)閉看門狗 */

 /* turn off the watchdog */

#if defined(CONFIG_S3C2400)

# define pWTCON 0x15300000

# define INTMSK 0x14400008 /* Interupt-Controller base addresses */

# define CLKDIVN 0x14800014 /* clock divisor register */

#elif defined(CONFIG_S3C2410)

# define pWTCON 0x53000000

# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */

# define INTSUBMSK 0x4A00001C

# define CLKDIVN 0x4C000014 /* clock divisor register */

#endif



#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

    ldr r0, =pWTCON

    
      
      
        mov
      
      
         r1, #0x0

    
      
      
        str
      
       r1, [r0]
    

(4)禁止所有中斷,設(shè)置CPU頻率

      
        /* 禁止所有中斷和設(shè)置CPU頻率 */

    /*

     * mask all IRQs by setting all bits 
      
      
        in
      
      
         the INTMR - default

     */

    
      
      
        mov
      
      
         r1, #0xffffffff

    ldr r0, =INTMSK

    
      
      
        str
      
      
         r1, [r0]

# if defined(CONFIG_S3C2410)

    ldr r1, =0x3ff

    ldr r0, =INTSUBMSK

    
      
      
        str
      
      
         r1, [r0]

# endif



    /* 
      
      
        FCLK:HCLK:
      
      PCLK = 
      
        1
      
      :
      
        2
      
      :
      
        4
      
       */ 
      
        ;
      
      
        ;FCLK用于CPU,HCLK用于AHB,PCLK用于APB
      
      

    /* default FCLK is 
      
        120
      
      
         MHz ! */

    ldr r0, =CLKDIVN 
      
      
        ;
      
      
        ;根據(jù)硬件手冊來設(shè)置CLKDIVN寄存器
      
      
        mov
      
       r1, #
      
        3
      
      
        ;
      
      
        ;用戶手冊的推薦值
      
      
        str
      
      
         r1, [r0]

#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */



 
      
    

(5)系統(tǒng)重啟的時(shí)候執(zhí)行的初始化代碼,而不是系統(tǒng)熱復(fù)位(從RAM中執(zhí)行)的時(shí)候

      
        /*

* we do sys-critical inits only at reboot,

* 
      
      
        not
      
      
         when booting from 

*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

    bl cpu_init_crit 
      
      
        ;
      
      
        ;跳轉(zhuǎn)去初始化CPU
      
      
        #endif


      
      
        ;
      
      
        ;#ifdef CONFIG_INIT_CRITICAL 原文中的,估計(jì)是1.1.16版本的
      
      
        

;
      
      
        ; bl cpu_init_crit
      
      
        

;
      
      
        ;#endif
      
    

(6)CPU和RAM兩個(gè)關(guān)鍵的初始化子程序

函數(shù)一: /*? 初始化 CPU?*/

      
        cpu_init_crit:
      
      
        

    /*

     * flush v4 I/D caches 設(shè)置CP15

     */

    
      
      
        mov
      
       r0, #
      
        0
      
      
        

    mcr p15, 
      
      
        0
      
      , r0, c7, c7, 
      
        0
      
       /* flush v3/v4 cache */ 
      
        ;
      
      
        ;使I/D cache失效:將寄存器r0的數(shù)據(jù)傳送到協(xié)處理器p15的c7中。C7寄存器位對應(yīng)cp15中的cache控制寄存器
      
      

    mcr p15, 
      
        0
      
      , r0, c8, c7, 
      
        0
      
       /* flush v4 TLB */ 
      
        ;
      
      
        ;使TLB操作寄存器失效:將r0數(shù)據(jù)送到cp15的c8、c7中。C8對應(yīng)TLB操作寄存器
      
      
        

    /*

     * disable MMU stuff 
      
      
        and
      
      
         caches 禁止MMU和caches

     */

    mrc p15, 
      
      
        0
      
      , r0, c1, c0, 
      
        0
      
      
        ;
      
      
        ;先把c1和c0寄存器的各位置0(r0 = 0)
      
      

    bic r0, r0, #0x00002300 @ clear bits 
      
        13
      
      , 
      
        9
      
      :
      
        8
      
      
         (--V- --RS)

    bic r0, r0, #0x00000087 @ clear bits 
      
      
        7
      
      , 
      
        2
      
      :
      
        0
      
       (B--- -CAM) 
      
        ;
      
      
        ;這里我本來有個(gè)疑問:為什么要分開設(shè)置。因?yàn)閍rm匯編要求的立即數(shù)格式所決定的
      
      

    orr r0, r0, #0x00000002 @ set bit 
      
        2
      
      (??) (A) Align 
      
        ;
      
      
        ;上一條已經(jīng)設(shè)置bit1為0,這一條又設(shè)置為1??
      
      

    orr r0, r0, #0x00001000 @ set bit 
      
        12
      
      
         (I) I-Cache

    mcr p15, 
      
      
        0
      
      , r0, c1, c0, 
      
        0
      
      
        ;
      
      
        ;用上面(見下面)設(shè)定的r0的值設(shè)置c1??(cache類型寄存器)和c0(control字寄存器),以下為c0的位定義
      
      
        

;
      
      
        ;bit8: 0 = Disable System protection
      
      
        

;
      
      
        ;bit9: 0 = Disable ROM protection
      
      
        

;
      
      
        ;bit0: 0 = MMU disabled
      
      
        

;
      
      
        ;bit1: 0 = Fault checking disabled 禁止糾錯(cuò)
      
      
        

;
      
      
        ;bit2: 0 = Data cache disabled
      
      
        

;
      
      
        ;bit7: 0 = Little-endian operation
      
      
        

;
      
      
        ;bit12: 1 = Instruction cache enabled
      
      
        

    /* 配置內(nèi)存區(qū)控制寄存器 ??有待分析,是1.
      
      
        1
      
      
        .4版本的

     * before relocating, we have to setup RAM timing

     * because memory timing is board-dependend, you will

     * find a lowlevel_init.S 
      
      
        in
      
      
         your board directory.

     */


      
      
        mov
      
      
         ip, lr

bl lowlevel_init 
      
      
        ;
      
      
        ;位于board/smdk2410/lowlevel_init.S:用于完成芯片存儲器的初始化,執(zhí)行完成后返回
      
      
        mov
      
      
         lr, ip


      
      
        mov
      
      
         pc, lr



 
      
    

函數(shù)二: /*? U-Boot 重新定位到 RAM?*/

      
        relocate:
      
      
         

       adr r0, _start /* r0是代碼的當(dāng)前位置 */ 
      
      
        ;
      
      
        ;adr偽指令,匯編器自動(dòng)通過當(dāng)前PC的值算出 如果執(zhí)行到_start時(shí)PC的值,放到r0中:
      
      

當(dāng)此段在flash中執(zhí)行時(shí)r0 = _start = 
      
        0
      
      
        ;當(dāng)此段在RAM中執(zhí)行時(shí)_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值為0x33F80000,即u-boot在把代碼拷貝到RAM中去執(zhí)行的代碼段的開始)

       ldr r1, _TEXT_BASE /* 測試判斷是從Flash啟動(dòng),還是RAM */ 
      
      
        ;
      
      
        ;此句執(zhí)行的結(jié)果r1始終是0x33FF80000,因?yàn)榇酥凳怯志幾g器指定的(ads中設(shè)置,或-D設(shè)置編譯器參數(shù))
      
      
        cmp
      
      
         r0, r1 /* 比較r0和r1,調(diào)試的時(shí)候不要執(zhí)行重定位 */

       beq stack_setup /* 如果r0等于r1,跳過重定位代碼 */

       /* 準(zhǔn)備重新定位代碼 */ 
      
      
        ;
      
      
        ;以上確定了復(fù)位啟動(dòng)代碼是在flash中執(zhí)行的(是系統(tǒng)重啟,而不是軟復(fù)位),就需要把代碼拷貝到RAM中去執(zhí)行,以下為計(jì)算即將拷貝的代碼的長度
      
      

       ldr r2, _armboot_start 
      
        ;
      
      
        ;前面定義了,就是_start
      
      

       ldr r3, _bss_start 
      
        ;
      
      
        ;所謂bss段,就是未被初始化的靜態(tài)變量存放的地方,這個(gè)地址是如何的出來的?根據(jù)board/smsk2410/u-boot.lds內(nèi)容?
      
      
        sub
      
      
         r2, r3, r2 /* r2 得到armboot的大小 */

       
      
      
        add
      
       r2, r0, r2 /* r2 得到要復(fù)制代碼的末尾地址 */
    

(7)重新定位代碼,循環(huán)拷貝啟動(dòng)的代碼到RAM中

      
        copy_loop:
      
      
        

       ldmia {r3-r10} /*從源地址[r0]復(fù)制 */ 
      
      
        ;
      
      
        ;r0指向_start(=0)
      
      

       stmia {r3-r10} /* 復(fù)制到目的地址[r1] */ 
      
        ;
      
      
        ;r1指向_TEXT_BASE(=0x33F80000)
      
      
        cmp
      
      
         r0, r2 /* 復(fù)制數(shù)據(jù)塊直到源數(shù)據(jù)末尾地址[r2] */

       ble copy_loop
      
    

(8)初始化堆棧等

      
        stack_setup:
      
      
        

       ldr r0, _TEXT_BASE /* 上面是128 KiB重定位的u-boot */

       
      
      
        sub
      
      
         r0, r0, #CFG_MALLOC_LEN /* 向下是內(nèi)存分配空間 */    

       
      
      
        sub
      
      
         r0, r0, #CFG_GBL_DATA_SIZE /* 然后是bdinfo結(jié)構(gòu)體地址空間 */

#ifdef CONFIG_USE_IRQ

       
      
      
        sub
      
      
         r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif        
      
      
        ;
      
      
        ;這些宏定義在/include/configs/smdk2410.h中:
      
      

#define CFG_MALLOC_LEN    (CFG_ENV_SIZE + 
      
        128
      
      *
      
        1024
      
      )        
      
        ;
      
      
        ;64K+128K=0xC0
      
      

#define CFG_ENV_SIZE    0x10000        /* Total Size of Environment Sector 
      
        64k
      
      
        */

#define CONFIG_STACKSIZE    (
      
      
        128
      
      *
      
        1024
      
      )    /* regular stack 
      
        128k
      
      
         */

#define CFG_GBL_DATA_SIZE     
      
      
        128
      
          /* size 
      
        in
      
      
         bytes reserved for initial data */

用0x33F8000 – 0xC0 – 0x80得到_TEXT_BASE向下(低地址)的堆棧指針sp的起點(diǎn)地址

       
      
      
        sub
      
       sp, r0, #
      
        12
      
       /* 為abort-stack預(yù)留3個(gè)字 */    
      
        ;
      
      
        ;得到最終sp指針初始值
      
      
        clear_bss:
      
      
        

       ldr r0, _bss_start /* 找到bss段起始地址 */

       ldr r1, _bss_end /* bss段末尾地址 */

       
      
      
        mov
      
      
         r2, #0x00000000 /* 清零 */


      
      
        clbss_l:
      
      
        str
      
      
         r2, [r0] /* bss段地址空間清零循環(huán)... */

       
      
      
        add
      
       r0, r0, #
      
        4
      
      
        cmp
      
      
         r0, r1

       bne clbss_l
      
    

(9)跳轉(zhuǎn)到start_armboot函數(shù)入口,_start_armboot字保存函數(shù)的入口指針

      
               ldr pc, _start_armboot


      
      
        _start_armboot:
      
       .word start_armboot 
      
        ;
      
      
        ;start_armboot函數(shù)在lib_arm/board.c中實(shí)現(xiàn)
      
    

?

五. Stage2(C語言實(shí)現(xiàn))代碼分析

這個(gè)文件是bootloader的stage2部分,這個(gè)文件中的start_armboot函數(shù)是U-Boot執(zhí)行的第一個(gè)C語言函數(shù),主要完成系統(tǒng)的初始化工作,然后進(jìn)入主循環(huán),等待并處理用戶輸入的命令。

在編譯和鏈接BootLoader這樣的程序的時(shí)候,不能使用glibc庫中的任何支持函數(shù),這就帶來了一個(gè)問題:從何處跳入Main函數(shù),最直接的想法是直接把Main函數(shù)的起始地址作為整個(gè)Stage2執(zhí)行映像的入口。但是這樣做有兩個(gè)缺點(diǎn):

a: 無法通過Main函數(shù)傳遞參數(shù)

b: 無法處理Main函數(shù)返回的情況

一種更好的解決方案是利用trampoline(彈簧床)的概念:用匯編寫一段trampoline小程序,并將這段trampoline小程序作為Stage2可執(zhí)行映像的入口點(diǎn),然后就可以在trampoline小程序中用CPU跳轉(zhuǎn)指令跳入Main函數(shù)去執(zhí)行,當(dāng)Main函數(shù)執(zhí)行結(jié)束以后CPU執(zhí)行路徑顯然再次回到trampoline程序。其核心思想就是用這段trampoline程序作為Main函數(shù)的外部包裹。

(1). 初始化本階段要使用到的硬件設(shè)備,一般包括:

a:點(diǎn)亮LED,表示已經(jīng)進(jìn)入main函數(shù)執(zhí)行(可選)

b: 至少一個(gè)串口,以便和終端用戶進(jìn)行IO信息交換

c: 初始化定時(shí)器等

d: 輸出一些打印信息,程序名稱,版本號等

(2). 檢測系統(tǒng)的內(nèi)存映射

所謂內(nèi)存映射就是指在整個(gè) 4GB 物理地址空間中有哪些地址范圍被分配用來尋址系統(tǒng)的 RAM 單元。比如,在 SA-1100 CPU 中,從 0xC000,0000 開始的 512M 地址空間被用作系統(tǒng)的 RAM 地址空間,而在 Samsung S3C44B0X CPU 中,從 0x0c00,0000 到 0x1000,0000?之間的 64M 地址空間被用作系統(tǒng)的 RAM 地址空間。雖然 CPU 通常預(yù)留出一大段足夠的地址空間給系統(tǒng) RAM,但是在搭建具體的嵌入式系統(tǒng)時(shí)卻不一定會實(shí)現(xiàn) CPU 預(yù)留的全部 RAM?地址空間。也就是說,具體的嵌入式系統(tǒng)往往只把 CPU 預(yù)留的全部 RAM 地址空間中的一部分映射到 RAM 單元上,而讓剩下的那部分預(yù)留 RAM 地址空間處于未使用狀態(tài)。 ?由于上述這個(gè)事實(shí),因此 Boot Loader 的 stage2 必須在它想干點(diǎn)什么 (比如,將存儲在 flash 上的內(nèi)核映像讀到 RAM 空間中) 之前檢測整個(gè)系統(tǒng)的內(nèi)存映射情況,也即它必須知道 CPU 預(yù)留的全部 RAM 地址空間中的哪些被真正映射到 RAM 地址單元,哪些是處于?"unused" 狀態(tài)的。

(3). 加載內(nèi)核映像和根文件系統(tǒng)映像

a:規(guī)劃內(nèi)存占用的布局:主要包括基地址和映像大小兩個(gè)方面。對于內(nèi)核映像,一般將其拷貝到從(MEM_START+0x8000) 這個(gè)基地址開始的大約 1MB大小的內(nèi)存范圍內(nèi)(嵌入式 Linux 的內(nèi)核一般都不操過 1MB)。為什么要把從 MEM_START到MEM_START+0x 8000 這段 32KB 大小的內(nèi)存空出 來呢?這是因?yàn)?Linux 內(nèi)核要在這段內(nèi)存中放置一些全局?jǐn)?shù)據(jù)結(jié)構(gòu),如:啟動(dòng)參數(shù)和內(nèi)核頁表等信息。而對于根文件系統(tǒng)映像,則一般將其拷貝到 MEM_START+0x0010,0000 開始的地方。如果用 Ramdisk 作為根文件系統(tǒng)映像,則其解壓后的大小一般是 1MB。

b:從Flash中拷貝映像

      
        while
      
      
        (count) {         



    
      
      *dest++ = *src++;  
      
        /*
      
      
         they are all aligned with word boundary 
      
      
        */
      
      
                 



    count 
      
      -= 
      
        4
      
      ; 
      
        /*
      
      
         byte number 
      
      
        */
      
      
         



};
      
    

(4). 設(shè)置內(nèi)核的啟動(dòng)參數(shù)

將內(nèi)核映像拷貝到RAM中之后就可以啟動(dòng)了,但是一般都需要先設(shè)定Linux內(nèi)核的啟動(dòng)參數(shù)。Linux2.4以后的內(nèi)核都以標(biāo)記列表(tagged list)的形式來傳遞啟動(dòng)參數(shù)。啟動(dòng)參數(shù)列表以標(biāo)記ATAG_CORE開始,以標(biāo)記ATAG_NONE結(jié)束。每個(gè)標(biāo)記由標(biāo)示被傳遞參數(shù)的tag_header結(jié)構(gòu)以及隨后的參數(shù)數(shù)據(jù)結(jié)構(gòu)來組成。數(shù)據(jù)結(jié)構(gòu)tag和tag_header定義在Linux內(nèi)核源碼的include/asm/setup.h頭文件中。在嵌入式Linux系統(tǒng)中,通常需要由BootLoader設(shè)定的參數(shù)有:ATAG_CORE、ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD。

比如,設(shè)置 ATAG_CORE 的代碼如下: ?

params = (struct tag *)BOOT_PARAMS; ? ? ? ??

params->hdr.tag = ATAG_CORE; ? ? ? ??

params->hdr.size = tag_size(tag_core); ? ? ? ??

params->u.core.flags = 0; ? ? ? ??

params->u.core.pagesize = 0; ? ? ? ??

params->u.core.rootdev = 0; ? ? ? ??

params = tag_next(params); ?

其中,BOOT_PARAMS 表示內(nèi)核啟動(dòng)參數(shù)在內(nèi)存中的起始基地址,指針 params 是一個(gè) struct?tag 類型的指針。宏 tag_next() 將以指向當(dāng)前標(biāo)記的指針為參數(shù),計(jì)算緊臨當(dāng)前標(biāo)記的下一個(gè)標(biāo)記的起始地址。注意,內(nèi)核的根文件系統(tǒng)所在的設(shè)備 ID 就是在這里設(shè)置的。

(5). 調(diào)用內(nèi)核

BootLoader調(diào)用內(nèi)核的方法是直接跳轉(zhuǎn)到內(nèi)核的第一條指令處,即直接跳到MEM_START+0x8000處。在跳轉(zhuǎn)的時(shí)候要滿足下面的條件:

a: CPU寄存器的設(shè)置

R0 = 0;

R1 = 機(jī)器類型ID,

b: CPU必須在SVC模式

c: Cache和MMU的設(shè)置:

MMU必須關(guān)閉

指令Cache可以打開也可以關(guān)閉

數(shù)據(jù)Cache必須關(guān)閉

說明:如果用 C 語言,可以像下列示例代碼這樣來調(diào)用內(nèi)核: ?

      
        void
      
       (*theKernel)(
      
        int
      
       zero, 
      
        int
      
       arch, u32 params_addr) = (
      
        void
      
        (*)(
      
        int
      
      , 
      
        int
      
      
        , 



u32))KERNEL_RAM_BASE; 



…… 



theKernel(
      
      
        0
      
      
        , ARCH_NUMBER, (u32) kernel_params_start);  



 
      
    

注意:theKernel()函數(shù)調(diào)用應(yīng)該永遠(yuǎn)不返回的。如果這個(gè)調(diào)用返回,則說明出錯(cuò)。 ? ? ? ? ??

六. UBoot移植過程中串口沒有顯示或者顯示亂碼的原因

(1).?boot loader 對串口的初始化設(shè)置不正確。?

(2). 運(yùn)行在 host 端的終端仿真程序?qū)Υ诘脑O(shè)置不正確, 這包括:波特率、奇偶校驗(yàn)、數(shù)據(jù)位和停止位等方面的設(shè)置。

關(guān)于BootLoader啟動(dòng)時(shí)串口能輸出,但是啟動(dòng)內(nèi)核后不能正確顯示的原因:

(1). 內(nèi)核編譯時(shí)缺少配置對串口驅(qū)動(dòng)的支持,或配置正確的串口驅(qū)動(dòng)

(2). BootLoader的串口配置和內(nèi)核的不一致

(3). 內(nèi)核沒有正確啟動(dòng)

七.總結(jié)

U-Boot,全稱 Universal Boot Loader,是遵循GPL條款的 開放源碼 項(xiàng)目。從FADSROM、8xxROM、PPCBOOT逐步發(fā)展演化而來。其源碼目錄、編譯形式與 Linux內(nèi)核 很相似,事實(shí)上,不少U-Boot源碼就是相應(yīng)的Linux內(nèi)核 源程序 的簡化,尤其是一些設(shè)備的驅(qū)動(dòng)程序,這從U-Boot源碼的注釋中能體現(xiàn)這一點(diǎn)。

?

U-Boot代碼分析與移植


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 呼和浩特市| 陇川县| 通山县| 宜君县| 汤原县| 鲁山县| 垫江县| 彭州市| 根河市| 宜君县| 江山市| 嘉黎县| 麻江县| 灵川县| 依兰县| 台中市| 开江县| 德安县| 和政县| 大渡口区| 石渠县| 特克斯县| 永定县| 盐津县| 罗田县| 曲麻莱县| 安平县| 乌审旗| 体育| 开鲁县| 和田市| 富川| 元阳县| 伊川县| 龙川县| 保定市| 格尔木市| 江门市| 依兰县| 建水县| 浑源县|