u-boot分析(二)----工作流程分析


u-boot分析(二)

由於這兩天家里有點事,所以耽誤了點時間,沒有按時更新,今天我首先要跟大家說說我對於u-boot分析的整體的思路,然后呢我以后的博客會按照這個內容更新,希望大家關注。

言歸正傳,我首先說一說我以后的思路,對於u-boot呢,我會結合24406410210這三款主流的學習芯片進行分析,首先會結合u-boot的源碼以及我以前的arm啟動流程一文http://www.cnblogs.com/wrjvszq/p/4204703.html 總結出u-boot的工作流程,然后以后的博文會結合u-boot源碼、芯片手冊等內容去分析,u-boot為什么去這么做。

Ok我們下面進入我們今天的內容,今天我會以210為例來分析其u-boot的工作流程,因為2440,6410的啟動流程大家跟着u-boot源碼中的注釋就能解決。

我們根據上篇博文(http://www.cnblogs.com/wrjvszq/p/4206975.html)中提到的方法,可以得到其的入口為arch\arm\cpu\armv7\start.S中的_start我們可以輕松的找到其對應代碼,下面我們對其工作流程進行分析:

1.     設置中斷向量表。

 1 .globl _start
 2 
 3 _start: b    reset
 4 
 5       ldr  pc, _undefined_instruction
 6 
 7       ldr  pc, _software_interrupt
 8 
 9       ldr  pc, _prefetch_abort
10 
11       ldr  pc, _data_abort
12 
13       ldr  pc, _not_used
14 
15       ldr  pc, _irq
16 
17       ldr  pc, _fiq

2.     設置處理器到svc的模式(因為我們的上電將會觸發reset

 

1 reset:
2     bl    save_boot_params//空函數
3     /*
4      * set the cpu to SVC32 mode
5      */
6     mrs    r0, cpsr
7     bic    r0, r0, #0x1f
8     orr    r0, r0, #0xd3
9     msr    cpsr,r0

 

 

繼續跟隨代碼往下走我們會找到

1 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
2 
3       bl   cpu_init_crit//跳轉至cpu_init_crit
4 
5 #endif
6 
7 cpu_init_crit:

3.     L1I/D caches失效

 

 1 cpu_init_crit:
 2     /*
 3      * Invalidate L1 I/D
 4      */
 5     mov    r0, #0            @ set up for MCR
 6     mcr    p15, 0, r0, c8, c7, 0    @ invalidate TLBs
 7     mcr    p15, 0, r0, c7, c5, 0    @ invalidate icache
 8     mcr    p15, 0, r0, c7, c5, 6    @ invalidate BP array
 9     mcr     p15, 0, r0, c7, c10, 4    @ DSB
10     mcr     p15, 0, r0, c7, c5, 4    @ ISB

 

 

4.     關閉MMUcaches      

 

 1     /*
 2      * disable MMU stuff and caches
 3      */
 4     mrc    p15, 0, r0, c1, c0, 0
 5     bic    r0, r0, #0x00002000    @ clear bits 13 (--V-)
 6     bic    r0, r0, #0x00000007    @ clear bits 2:0 (-CAM)
 7     orr    r0, r0, #0x00000002    @ set bit 1 (--A-) Align
 8     orr    r0, r0, #0x00000800    @ set bit 11 (Z---) BTB
 9 #ifdef CONFIG_SYS_ICACHE_OFF
10     bic    r0, r0, #0x00001000    @ clear bit 12 (I) I-cache
11 #else
12     orr    r0, r0, #0x00001000    @ set bit 12 (I) I-cache
13 #endif
14     mcr    p15, 0, r0, c1, c0, 0

下面代碼我們將跳轉至lowlevel_init(我們在此以三星的smart210為例)我們可以在\board\samsung\smart210\lowlevel_init.S中找到

 

 1     /*
 2      * Jump to board specific initialization...
 3      * The Mask ROM will have already initialized
 4      * basic memory. Go here to bump up clock rate and handle
 5      * wake up conditions.
 6      */
 7     mov    ip, lr            @ persevere link reg across call
 8     bl    lowlevel_init        @ go setup pll,mux,memory
 9     mov    lr, ip            @ restore link
10     mov    pc, lr            @ back to my caller
11 #endif
12 
13 #ifndef CONFIG_SPL_BUILD

5.     檢查reset狀態(reset分為兩種1、掉電的reset   2、從睡眠喚醒的reset)所以要對其進行區分,以便跳過部分代碼。

 

 1     push    {lr}//保存lr的值以便待會返回
 2 
 3     /* check reset status  */
 4 
 5     ldr    r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
 6     ldr    r1, [r0]
 7     bic    r1, r1, #0xfff6ffff
 8     cmp    r1, #0x10000
 9     beq    wakeup_reset_pre
10     cmp    r1, #0x80000
11     beq    wakeup_reset_from_didle

 

 

6.     恢復IO引腳為默認值

 

1     /* IO Retention release */
2     ldr    r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)
3     ldr    r1, [r0]
4     ldr    r2, =IO_RET_REL
5     orr    r1, r1, r2
6     str    r1, [r0]

 

7.     關閉看門狗

 

1     /* Disable Watchdog */
2     ldr    r0, =ELFIN_WATCHDOG_BASE    /* 0xE2700000 */
3     mov    r1, #0
4     str    r1, [r0]

 

8.     SRAMSROM初始化

 

 1 /* SRAM(2MB) init for SMDKC110 */
 2     /* GPJ1 SROM_ADDR_16to21 */
 3     ldr    r0, =ELFIN_GPIO_BASE
 4 
 5     ldr    r1, [r0, #GPJ1CON_OFFSET]
 6     bic    r1, r1, #0xFFFFFF
 7     ldr    r2, =0x444444
 8     orr    r1, r1, r2
 9     str    r1, [r0, #GPJ1CON_OFFSET]
10 
11     ldr    r1, [r0, #GPJ1PUD_OFFSET]
12     ldr    r2, =0x3ff
13     bic    r1, r1, r2
14     str    r1, [r0, #GPJ1PUD_OFFSET]
15 
16     /* GPJ4 SROM_ADDR_16to21 */
17     ldr    r1, [r0, #GPJ4CON_OFFSET]
18     bic    r1, r1, #(0xf<<16)
19     ldr    r2, =(0x4<<16)
20     orr    r1, r1, r2
21     str    r1, [r0, #GPJ4CON_OFFSET]
22 
23     ldr    r1, [r0, #GPJ4PUD_OFFSET]
24     ldr    r2, =(0x3<<8)
25     bic    r1, r1, r2
26     str    r1, [r0, #GPJ4PUD_OFFSET]
27 
28 
29     /* CS0 - 16bit sram, enable nBE, Byte base address */
30     ldr    r0, =ELFIN_SROM_BASE    /* 0xE8000000 */
31     mov    r1, #0x1
32     str    r1, [r0]
33 
34     /* PS_HOLD pin(GPH0_0) set to high */
35     ldr    r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
36     ldr    r1, [r0]
37     orr    r1, r1, #0x300
38     orr    r1, r1, #0x1
39     str    r1, [r0]

 

以下代碼是在判斷是不是在內存中運行,如果是在內存中運行則跳過部分代碼,我們這是第一次運行BL,並且從nand啟動的所以代碼不在內存中不用關心。

 

 1 /* when we already run in ram, we don't need to relocate U-Boot.
 2      * and actually, memory controller must be configured before U-Boot
 3      * is running in ram.
 4      */
 5     ldr    r0, =0x00ffffff
 6     bic    r1, pc, r0        /* r0 <- current base addr of code */
 7     ldr    r2, _TEXT_BASE        /* r1 <- original base addr in ram */
 8     bic    r2, r2, r0        /* r0 <- current base addr of code */
 9     cmp     r1, r2                  /* compare r0, r1                  */
10     beq     1f            /* r0 == r1 then skip sdram init   */

 

9.     初始化時鍾

1 /* init system clock */
2     bl system_clock_init

 

10.  初始化內存

1 /* Memory initialize */
2     bl mem_ctrl_asm_init

 

11.  串口簡單初始化

1 1:
2     /* for UART */
3     bl uart_asm_init

 

12.  取消存儲保護區

1     bl tzpc_init
2  //我們沒有用onenand所以跳過
3 
4 #if defined(CONFIG_ONENAND)
5     bl onenandcon_init
6 #endif

 

13.  簡單初始化nand

1 #if defined(CONFIG_NAND)
2     /* simple init for NAND */
3     bl nand_asm_init
4 #endif

 

14.  關閉ABB

 1     /* ABB disable */
 2     ldr    r0, =0xE010C300
 3     orr    r1, r1, #(0x1<<23)
 4     str    r1, [r0]
 5 
 6     /* Print 'K' */
 7     ldr    r0, =ELFIN_UART_CONSOLE_BASE
 8     ldr    r1, =0x4b4b4b4b
 9     str    r1, [r0, #UTXH_OFFSET]
10 
11     pop    {pc}//函數返回到調用者

 

代碼將會返回到這里

 1     /*
 2      * Jump to board specific initialization...
 3      * The Mask ROM will have already initialized
 4      * basic memory. Go here to bump up clock rate and handle
 5      * wake up conditions.
 6      */
 7     mov    ip, lr            @ persevere link reg across call
 8     bl    lowlevel_init        @ go setup pll,mux,memory
 9     mov    lr, ip            @ restore link
10     mov    pc, lr            @ back to my caller

 

代碼繼續返回到

 

1     /* the mask ROM code should have PLL and others stable */
2 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
3     bl    cpu_init_crit
4 #endif

 

15.  設置堆棧

1 /* Set stackpointer in internal RAM to call board_init_f */
2 call_board_init_f:
3     ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
4     bic    sp, sp, #7 /* 8-byte alignment for ABI compliance */
5     ldr    r0,=0x00000000

 

下面代碼在判斷我們現在是不是在內存中運行,如果在內存將跳轉至board_init_in_ram

 

1 #if defined(CONFIG_TINY210) || defined(CONFIG_SMART210)
2     adr    r4, _start
3     ldr    r5,_TEXT_BASE
4     cmp     r5,r4
5     beq    board_init_in_ram

      下面代碼在判斷從什么地方啟動的我們是從nand啟動的所以跳轉至nand_boot_210

 

 1 ldr    r0, =PRO_ID_BASE
 2         ldr    r1, [r0,#OMR_OFFSET]
 3         bic    r2, r1, #0xffffffc1
 4 
 5     /* NAND BOOT */
 6     cmp    r2, #0x0        @ 512B 4-cycle
 7     moveq    r3, #BOOT_NAND
 8 
 9     cmp    r2, #0x2        @ 2KB 5-cycle
10     moveq    r3, #BOOT_NAND
11 
12     cmp    r2, #0x4        @ 4KB 5-cycle    8-bit ECC
13     moveq    r3, #BOOT_NAND
14 
15     cmp    r2, #0x6        @ 4KB 5-cycle    16-bit ECC
16     moveq    r3, #BOOT_NAND
17 
18     cmp    r2, #0x8        @ OneNAND Mux
19     moveq    r3, #BOOT_ONENAND
20 
21     /* SD/MMC BOOT */
22     cmp     r2, #0xc
23     moveq   r3, #BOOT_MMCSD    
24 
25     /* NOR BOOT */
26     cmp     r2, #0x14
27     moveq   r3, #BOOT_NOR    
28 
29     /* Uart BOOTONG failed */
30     cmp     r2, #(0x1<<4)
31     moveq   r3, #BOOT_SEC_DEV
32     
33     ldr    r0, =INF_REG_BASE
34     str    r3, [r0, #INF_REG3_OFFSET]
35 
36     ldr    r1, [r0, #INF_REG3_OFFSET]
37     cmp    r1, #BOOT_NAND        /* 0x0 => boot device is nand */
38     beq    nand_boot_210
39     cmp     r1, #BOOT_MMCSD
40     beq     mmcsd_boot_210
41     

下面代碼將會跳轉至board_init_f_nand

1 nand_boot_210:
2     bl     board_init_f_nand
3 
4 mmcsd_boot_210:
5     bl     board_init_f
6 board_init_in_ram:
7 #endif
8     bl    board_init_f

 

 

       我們繼續可以看看board_init_f_nand

 1 void board_init_f_nand(unsigned long bootflag)
 2 {
 3         __attribute__((noreturn)) void (*uboot)(void);
 4         copy_uboot_to_ram_nand();//復制nand中的bl2到內存
 5 
 6         /* Jump to U-Boot image */
 7         uboot = (void *)CONFIG_SYS_TEXT_BASE;//跳轉至內存執行uboot
 8     (*uboot)();
 9         /* Never returns Here */
10 }

16.  復制nand中的bl2到內存

l  我們可以到copy_uboot_to_ram_nand函數中看到其將我們的BL2復制到CONFIG_SYS_TEXT_BASE地址處,用SI(Source Insight)我們可以看到這個地址為0x23E00000,我在arm啟動流程一文中說到過210的地址布局可以知道其內存是從0x20000000開始的,所以上面這個地址在內存中

 

 1 int copy_uboot_to_ram_nand (void)
 2 {
 3     int large_block = 0;
 4     int i;
 5     vu_char id;
 6 
 7     NAND_CONTROL_ENABLE();
 8         NAND_ENABLE_CE();
 9         NFCMD_REG = NAND_CMD_READID;
10         NFADDR_REG =  0x00;
11 
12     /* wait for a while */
13         for (i=0; i<200; i++);
14     id = NFDATA8_REG;
15     id = NFDATA8_REG;
16 
17     if (id > 0x80)
18         large_block = 1;
19 
20     /* read NAND Block.
21      * 128KB ->240KB because of U-Boot size increase. by scsuh
22      * So, read 0x3c000 bytes not 0x20000(128KB).
23      */
24     return nandll_read_blocks(CONFIG_SYS_TEXT_BASE, COPY_BL2_SIZE, large_block);
25 }

 

17.  跳轉至內存執行uboot

l  通運行代碼段的方式完成向BL2的跳轉 

1         /* Jump to U-Boot image */
2         uboot = (void *)CONFIG_SYS_TEXT_BASE;//跳轉至內存執行uboot
3     (*uboot)();

 

到此我們第一階段的代碼分析完成,接下來我們進行第二階段的分析,由於我們的210第二階段的代碼入口和第一階段相同,所以第一階段執行的代碼又會被執行一次,直到運行到下面代碼的時候才會發生變化

 

1 #if defined(CONFIG_TINY210) || defined(CONFIG_SMART210)
2     adr    r4, _start
3     ldr    r5,_TEXT_BASE
4     cmp     r5,r4
5     beq    board_init_in_ram

 

我們代碼將會跳到board_init_in_ram運行

1 board_init_in_ram:
2 #endif
3     bl    board_init_f

 

我們繼續跳進board_init_f這個函數在arch\arm\lib\board.c中在這個函數中比較重要的一段代碼,下面的代碼是在遍歷一個函數指針數組,並且一一執行

 

1     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
2         if ((*init_fnc_ptr)() != 0) {
3             hang ();
4         }
5     }

 

通過查找我們可以發現這個數組中的內容,是一大堆東西的初始化函數,也就是說上面的代碼進行了一系列的初始化

 

 1 init_fnc_t *init_sequence[] = {
 2 #if defined(CONFIG_ARCH_CPU_INIT)
 3     arch_cpu_init,        /* basic arch cpu dependent setup */
 4 #endif
 5 #if defined(CONFIG_BOARD_EARLY_INIT_F)
 6     board_early_init_f,
 7 #endif
 8     timer_init,        /* initialize timer */
 9 #ifdef CONFIG_FSL_ESDHC
10     get_clocks,
11 #endif
12     env_init,        /* initialize environment */
13     init_baudrate,        /* initialze baudrate settings */
14     serial_init,        /* serial communications setup */
15     console_init_f,        /* stage 1 init of console */
16     display_banner,        /* say that we are here */
17 #if defined(CONFIG_DISPLAY_CPUINFO)
18     print_cpuinfo,        /* display cpu info (and speed) */
19 #endif
20 #if defined(CONFIG_DISPLAY_BOARDINFO)
21     checkboard,        /* display board info */
22 #endif
23 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
24     init_func_i2c,
25 #endif
26     dram_init,        /* configure available RAM banks */
27     NULL,
28 };

 

經過上面的代碼后其會返回到start.s中繼續運行,中間又經過一系列東西,好多和第一階段重復,所以這里就不一一分析了,最終通過下面代碼進入board_init_r函數

 

 1     ldr    r0, _board_init_r_ofs
 2     adr    r1, _start
 3     add    lr, r0, r1
 4     add    lr, lr, r9
 5     /* setup parameters for board_init_r */
 6     mov    r0, r5        /* gd_t */
 7     mov    r1, r6        /* dest_addr */
 8     /* jump to it ... */
 9     mov    pc, lr
10 
11 _board_init_r_ofs:
12     .word board_init_r - _start

 

在這個函數中又進行了硬件和軟件的初始化最后會落腳在

 

1     /* main_loop() can return to retry autoboot, if so just run it again. */
2     for (;;) {
3         main_loop();
4     }

 

通過上面的代碼對用戶命令進行解析。至此210u-boot工作流程分析完畢,24406410比較簡單,基本按照注釋就可以總結出來。

下面我將自己總結的流程跟大家分享一下

l  2440

第一階段

1.        設置中斷向量表

2.        設置處理器工作模式為svc

3.        刷新I/Dcaches

4.        關閉MMUcaches

5.        關閉看門狗

6.        關所有中斷

7.        設置系統時鍾

8.        初始化串口

9.        初始化nand

10.    初始化內存

11.    復制BL到內存

12.    設置堆棧

13.    清楚BSS

第二階段

1.        初始化串口

2.        LCD初始化

3.        網卡初始化

4.        Led初始化

5.        執行用戶命令

l  6410

第一階段

1.        設置中斷向量表

2.        設置處理器工作模式為svc

3.        刷新I/Dcaches

4.        關閉MMUcaches

5.        外設基地址初始化

6.        點亮led

7.        關看門狗

8.        初始化時鍾

9.        初始化串口

10.    初始化nand

11.    初始化內存

12.    復制BL到內存

13.    設置堆棧

14.    清楚BSS

第二階段

1.        初始化串口

2.        LCD初始化

3.        網卡初始化

4.        Led初始化

5.        執行用戶命令

l  210

第一階段

1.        設置中斷向量表

2.        設置處理器工作模式為svc

3.        L1I/D caches失效

4.        關閉MMUcaches

5.        檢查reset狀態

6.        回復io引腳為默認值

7.        關看門狗

8.        Sramsrom初始化

9.        初始化時鍾

10.    初始化內存

11.    初始化串口

12.    取消存儲保護區

13.    初始化nand

14.    關閉ABB

15.    設置堆棧

16.    復制BL2到內存

17.    跳轉到內存執行

第二階段

1.        初始化串口

2.        LCD初始化

3.        網卡初始化

4.        Led初始化

5.        執行用戶命令

 


免責聲明!

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



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