1. 程式人生 > >buildroot構建項目(七)--- u-boot 2017.11 適配開發板修改 4 ---- 系統啟動初始化之四

buildroot構建項目(七)--- u-boot 2017.11 適配開發板修改 4 ---- 系統啟動初始化之四

ack tar span mov tel 變量初始化 清零 ppi ntb

  設置完寄存器控制器後,則跳出cpu_init_crit,進入_main 函數。即進入crt0.S (arch\arm\lib)
  跟著代碼流程慢慢走

一、crt0.S

1.1 第一步執行代碼

 1     /* 預設堆棧指針為CONFIG_SYS_INIT_SP_ADDR */
 2     /* #define CONFIG_SYS_INIT_SP_ADDR    (CONFIG_SYS_SDRAM_BASE + 0x1000 - GENERATED_GBL_DATA_SIZE) */
 3     /* #define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1 */
 4
/* #define PHYS_SDRAM_1 0x30000000 SDRAM Bank #1 */ 5 /* #define GENERATED_GBL_DATA_SIZE 176 */ 6 /* CONFIG_SYS_INIT_SP_ADDR = 0x3000 0000 + 0x1000 - 176 */ 7 /* 這裏是預設的堆棧地址,而不是最終的堆棧地址 */ 8 ldr r0, =(CONFIG_SYS_INIT_SP_ADDR) /* 0x3000 0f52*/ 9 bic r0, r0, #7 /* 8字節對齊後為,0x3000 0f50 */ 10 mov sp, r0 /*
sp 指針指向 0x3000 0f50 */ 11 bl board_init_f_alloc_reserve /* 給 gd 分配內存大小, 通過 u-boot.dis 文件可知 gd 大小為168 */

  跳轉到 board_init_f_alloc_reserve 中執行:

 1 /* 這個函數用於給global_data分配空間,在relocation之前調用
 2  * 傳入的參數是頂部地址,但是不一定是要內存頂部的地址,可以自己進行規劃
 3  */
 4 ulong board_init_f_alloc_reserve(ulong top)
 5 {
 6     /* Reserve early malloc arena 
*/ 7 /* 先從頂部向下分配一塊CONFIG_SYS_MALLOC_F_LEN大小的空間給early malloc使用 */ 8 /* 關於CONFIG_SYS_MALLOC_F_LEN可以參考README */ 9 /* 這塊內存是用於在relocation前用於給malloc函數提供內存池。 */ 10 #if CONFIG_VAL(SYS_MALLOC_F_LEN) 11 top -= CONFIG_VAL(SYS_MALLOC_F_LEN); 12 #endif 13 /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */ 14 /* 繼續向下分配sizeof(struct global_data)大小的內存給global_data使用,向下16byte對齊 */ 15 /* 這時候得到的地址就是global_data的地址。 */ 16 top = rounddown(top-sizeof(struct global_data), 16); 17 18 return top; /* 將top,也就是global_data的地址返回 */ 19 }

   設置完後,返回繼續執行crt0.S中的代碼:

1     mov    sp, r0      /* 分配後的棧頂為 3000 0de0,16字節對其後為 3000 0de0 */
2     /* set up gd here, outside any C code */
3     mov    r9, r0
4     bl    board_init_f_init_reserve   /* 啟動前初始化完成 */

  進入 board_init_f_init_reserve 中執行:

 1 /* 這個函數用於對global_data區域進行初始化,也就是清空global_data區域 */
 2 /* 傳入的參數就是global_data的基地址 */
 3 void board_init_f_init_reserve(ulong base)
 4 {
 5     struct global_data *gd_ptr;
 6 
 7     /*
 8      * clear GD entirely and set it up.
 9      * Use gd_ptr, as gd may not be properly set yet.
10      */
11 
12     gd_ptr = (struct global_data *)base;
13     /* zero the area, 先通過memset函數對global_data數據結構進行清零 */
14     memset(gd_ptr, \0, sizeof(*gd));
15     /* set GD unless architecture did it already */
16 #if !defined(CONFIG_ARM)
17     arch_setup_gd(gd_ptr);
18 #endif
19     /* next alloc will be higher by one GD plus 16-byte alignment */
20     /* global_data區域是16Byte對齊的,對齊後,後面的地址就是early malloc的內存池的地址 */
21     /* 這裏就獲取了early malloc的內存池的地址,S3C2440中我們沒有分配此內存池。*/
22     /* roundup計算處來的大小為 176,基地址為 0x3000 0e90 */
23     base += roundup(sizeof(struct global_data), 16);    
24 
25     /*
26      * record early malloc arena start.
27      * Use gd as it is now properly set for all architectures.
28      */
29 
30 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
31     /* go down one ‘early malloc arena‘ */
32     gd->malloc_base = base;
33     /* next alloc will be higher by one ‘early malloc arena‘ size */
34     base += CONFIG_VAL(SYS_MALLOC_F_LEN);
35 #endif
36 }

  上面進行的初始化,只是臨時的初始化,執行完後,跳出,繼續在 crt0.S中執行

1     mov    r0, #0      /* r0 清零 */
2     bl    board_init_f    /* 啟動前初始化完成 */

1.2 執行 board_init_f

  進入 board_init_f 則正式進入了C語言部分的初始化:

 1 /* 啟動前,板初始化,傳入參數 boot_flags = 0 */
 2 void board_init_f(ulong boot_flags)
 3 {
 4     gd->flags = boot_flags;
 5     gd->have_console = 0;
 6 
 7     /* 初始化 函數 結構體數組鏈表 */
 8     if (initcall_run_list(init_sequence_f))
 9         hang();
10 
11 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && 12         !defined(CONFIG_EFI_APP) && !CONFIG_IS_ENABLED(X86_64)
13     /* NOTREACHED - jump_to_copy() does not return */
14     hang();
15 #endif
16 }

  整個代碼就是在執行 init_sequence_f 中的函數

 1 static const init_fnc_t init_sequence_f[] = {
 2     setup_mon_len,  /* 獲取 u-boot 的大小 */
 3     initf_malloc,       /* early malloc的大小,沒有設置,為0 */ 
 4     initf_bootstage,    /* uses its own timer, so does not need DM */
 5     initf_console_record,   /* 直接返回0,沒定義宏 */
 6 
 7 #if !defined(CONFIG_M68K)
 8     timer_init,        /* initialize timer,初始化PWM定時器 */
 9 #endif
10     env_init,            /* initialize environment,環境變量初始化 */
11     init_baud_rate,        /* initialze baudrate settings,串口波特率初始化115200 */
12     serial_init,        /* serial communications setup,串口初始化 */
13     console_init_f,        /* stage 1 init of console,階段1初始化終端 */
14     display_options,    /* say that we are here,打印緩存信息 */
15     display_text_info,    /* show debugging info if required,打印u-boot 的大小 */
16 
17 #if defined(CONFIG_DISPLAY_CPUINFO)
18     print_cpuinfo,        /* display cpu info (and speed),打印CPU信息 */
19 #endif
20 
21 #if defined(CONFIG_DISPLAY_BOARDINFO)
22     show_board_info,        /* 打印板信息*/
23 #endif
24     announce_dram_init,         /* DRAM打印初始化 */
25     /* 給gd->bd中內存信息表賦值而已。 */
26     /* gd->ram_size = PHYS_SDRAM_1_SIZE; */
27     dram_init,        /* configure available RAM banks,DRAM初始化,RAM SIZE大小獲取 64M */
28     /*
29      * Now that we have DRAM mapped and working, we can
30      * relocate the code and continue running from DRAM.
31      *
32      * Reserve memory at end of RAM for (top down in that order):
33      *  - area that won‘t get touched by U-Boot and Linux (optional)
34      *  - kernel log buffer
35      *  - protected RAM
36      *  - LCD framebuffer
37      *  - monitor code
38      *  - board info struct
39      */
40     setup_dest_addr,    /* 設置重定向的地址為 0x3400 0000 */
41     reserve_round_4k,   /* 4字節對齊後為 0x3400 0000 */
42 #ifdef CONFIG_ARM
43     reserve_mmu,        /* 直接返回0,其中的宏未定義 */
44 #endif
45     reserve_video,      /* 直接返回0,其中的宏未定義 */
46     reserve_trace,      /* 直接返回0,其中的宏未定義 */
47     reserve_uboot,      /* 保留 u-boot 區域,u-boot 的啟動地址為當前減去u-boot大小後的地址 */
48     reserve_malloc,     /* 分配堆區大小 為 4M */
49     reserve_board,      /* bd-t 結構體大小 */
50     setup_machine,      /* 直接返回0,其中的宏未定義 */
51     reserve_global_data,/* gd-t 結構體大小 */
52     reserve_fdt,        /* fdt 大小 棧在此處*/
53     reserve_bootstage,  /* 直接返回0,其中的宏未定義 */
54     reserve_arch,       /* 直接返回0,其中的宏未定義 */
55     reserve_stacks,     /* 直接返回0,其中的宏未定義 */
56     dram_init_banksize, /* banksize 大小設定 */ 
57     show_dram_config,   /* dram 配置 */
58     display_new_sp,     /* 打印當前棧位置 */
59     reloc_fdt,          /* 設置 gd->fdt_blob */
60     reloc_bootstage,    /* 直接返回0,其中的宏未定義 */
61     setup_reloc,        /* 設置 gd->reloc_off為 0x3400 0000 */
62     NULL,
63 };

1.2.1 setup_mon_len

 1 /* #define CONFIG_SYS_MONITOR_LEN    (448 * 1024) */
 2 /* #define CONFIG_SYS_MONITOR_BASE    CONFIG_SYS_FLASH_BASE */
 3 /* #define CONFIG_SYS_FLASH_BASE    PHYS_FLASH_1 */
 4 /* #define PHYS_FLASH_1        0x00000000 /* Flash Bank #0 */ */
 5 static int setup_mon_len(void)
 6 {
 7     /* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
 8     /* 設置gd->mon_len 為編譯出來的 u-boot.bin+bss 段的大小 */
 9     gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
10     return 0;
11 }

1.2.2 timer_init

 1 /* PWM定時器設置 */
 2 int timer_init(void)
 3 {
 4     /* 獲取定時器的基地址 */
 5     struct s3c24x0_timers *timers = s3c24x0_get_base_timers();
 6     ulong tmr;
 7 
 8     /* use PWM Timer 4 because it has no output */
 9     /* prescaler for Timer 4 is 16 */
10     writel(0x0f00, &timers->tcfg0); /* 啟動定時器4 */
11     if (gd->arch.tbu == 0) {
12         /*
13          * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
14          * (default) and prescaler = 16. Should be 10390
15          * @33.25MHz and 15625 @ 50 MHz
16          */
17         gd->arch.tbu = get_PCLK() / (2 * 16 * 100);
18         gd->arch.timer_rate_hz = get_PCLK() / (2 * 16);
19     }
20     /* load value for 10 ms timeout */
21     writel(gd->arch.tbu, &timers->tcntb4);
22     /* auto load, manual update of timer 4 */
23     tmr = (readl(&timers->tcon) & ~0x0700000) | 0x0600000;
24     writel(tmr, &timers->tcon);
25     /* auto load, start timer 4 */
26     tmr = (tmr & ~0x0700000) | 0x0500000;
27     writel(tmr, &timers->tcon);
28     gd->arch.lastinc = 0;
29     gd->arch.tbl = 0;
30 
31     return 0;
32 }

1.2.3 setup_dest_addr

  /* 設置重定向的地址為 0x3400 0000 */

 1 static int setup_dest_addr(void)
 2 {
 3 #ifdef CONFIG_SYS_SDRAM_BASE
 4     gd->ram_top = CONFIG_SYS_SDRAM_BASE;    /* SDRAM 基地址 0x3000 0000,棧頂此時在此處 */
 5 #endif
 6     gd->ram_top += get_effective_memsize(); /* SDRAM 棧頂為 0x3400 0000 = 0x3000 000 + 400 0000 */
 7     gd->ram_top = board_get_usable_ram_top(gd->mon_len);    /* SDRAM 棧頂為 0x3400 0000 */
 8     gd->relocaddr = gd->ram_top;            /* 重定向的地址為 0x3400 0000 */
 9     return 0;
10 }

1.2.4 reserve_uboot

  保留 u-boot 區域,u-boot 的啟動地址為當前減去u-boot大小後的地址

 1 static int reserve_uboot(void)
 2 {
 3     /*
 4      * reserve memory for U-Boot code, data & bss
 5      * round down to next 4 kB limit
 6      */
 7     gd->relocaddr -= gd->mon_len;   /* 減去 u-boot 大小 */
 8     gd->relocaddr &= ~(4096 - 1);    /* gd->relocaddr 地址在u-boot的起始地址 */
 9     gd->start_addr_sp = gd->relocaddr; /* 棧地址為當前減去u-boot大小後的地址 */
10 
11     return 0;
12 }

1.2.5 reserve_malloc

 1 /* reserve memory for malloc() area */
 2 /* malloc大小 */
 3 static int reserve_malloc(void)
 4 {
 5     /* #define CONFIG_SYS_MALLOC_LEN    (4 * 1024 * 1024) 40 0000*/
 6     gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;
 7     debug("Reserving %dk for malloc() at: %08lx\n",
 8             TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
 9     return 0;
10 }

1.2.6 reserve_board

  給 gd->bd 分配大小

 1 static int reserve_board(void)
 2 {
 3     if (!gd->bd) {
 4         gd->start_addr_sp -= sizeof(bd_t);
 5         gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
 6         memset(gd->bd, \0, sizeof(bd_t));
 7         debug("Reserving %zu Bytes for Board Info at: %08lx\n",
 8               sizeof(bd_t), gd->start_addr_sp);
 9     }
10     return 0;
11 }

1.2.7 reserve_global_data

  gd大小分配,gd在bd的下方

1 static int reserve_global_data(void)
2 {
3     gd->start_addr_sp -= sizeof(gd_t);
4     gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
5     debug("Reserving %zu Bytes for Global Data at: %08lx\n",
6             sizeof(gd_t), gd->start_addr_sp);
7     return 0;
8 }

1.2.8 reserve_fdt

  fdt大小分配

 1 static int reserve_fdt(void)
 2 {
 3 #ifndef CONFIG_OF_EMBED
 4     /*
 5      * If the device tree is sitting immediately above our image then we
 6      * must relocate it. If it is embedded in the data section, then it
 7      * will be relocated with other data.
 8      */
 9     if (gd->fdt_blob) {
10         gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
11 
12         gd->start_addr_sp -= gd->fdt_size;
13         /* gd->new_fdt 指向當前棧地址 */
14         gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
15         debug("Reserving %lu Bytes for FDT at: %08lx\n",
16               gd->fdt_size, gd->start_addr_sp);
17     }
18 #endif
19 
20     return 0;
21 }

1.2.9 dram_init_banksize

  設置DRAM

 1 /* 設置物理地址 bank,這裏只設置了SDRAM的bank */
 2 __weak int dram_init_banksize(void)
 3 {
 4 /* #define CONFIG_NR_DRAM_BANKS    1  */
 5 /* #define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1 0x3000 0000 */
 6 #if defined(CONFIG_NR_DRAM_BANKS) && defined(CONFIG_SYS_SDRAM_BASE)
 7     gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
 8     gd->bd->bi_dram[0].size = get_effective_memsize();
 9 #endif
10 
11     return 0;
12 }

1.2.10 setup_reloc

 1 static int setup_reloc(void)
 2 {
 3     if (gd->flags & GD_FLG_SKIP_RELOC) {
 4         debug("Skipping relocation due to flag\n");
 5         return 0;
 6     }
 7 
 8 /* #define CONFIG_SYS_TEXT_BASE    0x0 */
 9 #ifdef CONFIG_SYS_TEXT_BASE
10     /* gd->relocaddr 為 0x3400 0000 - u-boot 大小,即在u-boot的起始地址處 */
11     gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
12 #endif
13     memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
14 
15     return 0;
16 }

buildroot構建項目(七)--- u-boot 2017.11 適配開發板修改 4 ---- 系統啟動初始化之四