色yeye在线视频观看_亚洲人亚洲精品成人网站_一级毛片免费播放_91精品一区二区中文字幕_一区二区三区日本视频_成人性生交大免费看

當前位置: > 華清遠見教育科技集團 > 嵌入式學習 > 講師博文 > U-BOOT 第一階段分析(續)
U-BOOT 第一階段分析(續)
時間:2016-12-12作者:華清遠見

一、概述

芯片手冊:S5PC100_UM_REV1.02.pdf,有如下描述:



S5PC100有32K ROM(iROM),96K SRAM(IRAM),復位后,程序在iROM運行。Bootloader分為2個階段BL0和BL1。

BL0程序在iROM中,三星保密。功能:從啟動設備(比如nand flash)加載BL1(u-boot的前16K)到iRAM。

BL1:IRAM中16K代碼執行,會完成內存控制器的初始化把uboot從nand flash拷貝到DRAM,即第一次搬運,經常設定為搬到內存的0x27e00000地址。

u-boot終運行在高端地址,所以,有時u-boot剩下的代碼,把u-boot代碼做了個第二次搬運,搬到高端地址去。還把OS鏡像,拷貝到了內存中。

二、u-boot第一階段分析(續)

由匯編轉到了C,分析board_init_f函數:
         void board_init_f(ulong bootflag)
         {
                 bd_t *bd;
                 init_fnc_t **init_fnc_ptr;
                 gd_t *id;
                 ulong addr, addr_sp;
         #ifdef CONFIG_PRAM
 &nbsnbsp;               ulong reg;
         #endif

涉及到兩個重要的數據結構:1)bd_t結構體,關于開發板信息(波特率,ip, 平臺號,啟動參數)。2)gd_t結構體成員主要是一些全局的系統初始化參數。需要用到時,用宏定義DECLARD_GLOBAL_DATA_PTT,指定占用寄存器r8,具體定義如下:

typedef struct bd_info {
                 int                  bi_baudrate; /* serial console baudrate串口波特率 */
                 unsigned long                  bi_ip_addr; /* IP Address IP 地址*/
                 ulong                  bi_arch_number; /* unique id for this board 板子的id */
                 ulong                  bi_boot_params; /* where this board expects params 啟動參數*/
                 struct                  /* RAM configuration RAM 配置*/
                 {
                 ulong start;
                 ulong size;
                 }                  bi_dram[CONFIG_NR_DRAM_BANKS];
         } bd_t;

Gd_t結構體定義,如下:
        typedef struct global_data {
                bd_t *bd;
                unsigned long flags; //指示標志,如設備已經初始化標志等
                unsigned long baudrate; //串行口通信速率
                unsigned long have_console; /* serial_init() was called */
          #ifdef CONFIG_PRE_CONSOLE_BUFFER
                unsigned long precon_buf_idx; /* Pre-Console buffer index */
          #endif
                unsigned long env_addr; /* Address of Environment struct 環境參數地址 */
                     unsigned long env_valid; /* Checksum of Environment valid? 環境參數CRC檢驗有效標志*/
                unsigned long fb_base; /* base address of frame buffer 幀緩沖區基地址*/
         ……
         } gd_t;
        gd=(gd_t *)(CONFIG_SYS_INIT_SP_ADDR) &~0x07) .

CONFIG_SYS_INIT_SP_ADDR的定義如下:
        #define CONFIG_SYS_INIT_SP_ADDR (0x22000)
        0x22000 & ~0x07,為了保證結果八字節對齊。
        查芯片手冊,可知0x0002_0000----0x0003_8000范圍,為96K,是IRAM的空間。
        即gd指向IRAM的一個地址。

在本文中前面有聲明DECLARE_GLOBAL_DATA_PTR
跟蹤定義可看到下面形式:
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8") 這個聲明告訴編譯器使用寄存器r8來存儲gd_t類型的指針gd,即這個定義聲明了一個指針,并且指明了它的存儲位置。(即gd值放在寄存器r8中)
register表示變量放在機器的寄存器
volatile用于指定變量的值可以由外部過程異步修改
并且這個指針現在被賦值為CONFIG_SYS_INIT_SP_ADDR) &~0x07, __asm__ __volatile__("": : :"memory"); memset((void *)gd, 0, sizeof(gd_t));

memory 強制gcc編譯器假設RAM所有內存單元均被匯編指令修改,這樣cpu中的registers和cache中已緩存的內存單元中的數據將作廢。cpu將不得不在需要的時候重新讀取內存中的數據。這就阻止了cpu又將registers,cache中的數據用于去優化指令,而避免去訪問內存。

__asm__用于指示編譯器在此插入匯編語句。

__volatile__用于告訴編譯器,嚴禁將此處的匯編語句與其它的語句重組合優化。即:原原本本按原來的樣子處理這這里的匯編。 memory強制gcc編譯器假設RAM所有內存單元均被匯編指令修改,這樣cpu中的registers和cache中已緩存的內存單元中的數據將作廢。cpu將不得不在需要的時候重新讀取內存中的數據。這就阻止了cpu又將registers,cache中的數據用于去優化指令,而避免去訪問內存。

"":::表示這是個空指令。

gd->mon_len = _bss_end_ofs; _bss_end_ofs的定義在start.S中: .globl _bss_end_ofs

_bss_end_ofs:
        .word __bss_end__ - _start
                .word就是在當前地址_bss_end_ofs放值 __bss-end__ - _start。
        看到是所以段的大小,此時,新開終端。打開u-boot.lds,找__bss_end__ Gd->mon_len存的值就是u-boot的實際大小。

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
                if ((*init_fnc_ptr)() != 0) {
            &nnbsp;   hang ();
                }
        }

init_fnc_t **init_fnc_ptr。跟蹤init_fnc_t, 如下:
        typedef int (init_fnc_t) (void);
        是個函數指針類型。

當前這個文件里有init_sequence數組:
        init_fnc_t *init_sequence[] = {
        …
              timer_init, /* initialize timer */
        …
              env_init,       /* initialize environment */
              init_baudrate,       /* initialze baudrate settings */
              serial_init,       /* serial communications setup */
              console_init_f,       /* stage 1 init of console */
              display_banner,       /* say that we are here */
        …
              dram_init,       /* configure available RAM banks */
              NULL,
        };

通過循環,調用了函數指針數組中的一系列初始化函數:arch_cpu_init,timer_init,env_int,init_baudrate, serial_init,console_init_f,         display_banner, dram_init。
        串口初始化函數調用后,就可以用串口了,可以用printf來調試,串口初始化之前,串口可以工作之前,可用點燈的方式。

繼續分析board_init_f:
        addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

這樣addr是內存的高地址,0x20000000+256M
        關于gd->ram_size,在初始化函數dram_init中,已經給過值了

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
                /* reserve TLB table */
                addr -= (4096 * 4);
        //留給TLB,16K
                /* round down to next 64 kB limit */
                addr &= ~(0x10000 - 1);
        //64K對齊
                gd->tlb_addr = addr;
                debug("TLB table at: %08lx\n", addr);
         #endif

         /* round down to next 4 kB limit */
                addr &= ~(4096 - 1);
          // K對齊,此處前面已經64K對齊了,就不需改動

addr -= gd->mon_len;
                addr &= ~(4096 - 1);
        預留u-boot實際大小空間,4K對齊。

#ifndef CONFIG_SPL_BUILD
                addr_sp = addr - TOTAL_MALLOC_LEN;
                /*
                     * (permanently) allocate a Board Info struct
                    * and a permanent copy of the "global" data
                */
               addr_sp -= sizeof (bd_t);
               bd = (bd_t *) addr_sp;
               gd->bd = bd;

宏CONFIG_SPL_BUILD,用ctags找,在spl/Makefile中能找到,如下:
        CONFIG_SPL_BUILD := y
        export CONFIG_SPL_BUILD
        但是從u-boot根目錄的Makefile中,可以看到,ALL-$(CONFIG_SPL),如下:
        ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
        CONFIG_SPL沒有定義(include/configs/fsc100.h中沒這個宏),因此,相當于spl/Makefile沒有執行。

分析TOTAL_MALLOC_LEN:
        #define TOTAL_MALLOC_LEN CONFIG_SYS_MALLOC_LEN
        #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (1 << 20))
        #define CONFIG_ENV_SIZE (128 << 10) /* 128KiB, 0x20000 */

addr_sp = addr – TOTAL_MALLOC_LEN;
        =addr-CONFIG_ENV_SIZE + (1 << 20)
        = 128 << 10+1M
        =128K+1M
        128K是預留環境變量空間,1M是預留對空間。

addr_sp -= sizeof (bd_t);
                bd = (bd_t *) addr_sp;
                gd->bd = bd;
        …
        addr_sp -= sizeof (gd_t);
                id = (gd_t *) addr_sp;
                debug("Reserving %zu Bytes for Global Data at: %08lx\n",
        sizeof (gd_t), addr_sp);

/* setup stackpointer for exeptions */
                gd->irq_sp = addr_sp;
                沒用
        …
                /* leave 3 words for abort-stack */
                addr_sp -= 12;

/* 8-byte alignment for ABI compliance */
                addr_sp &= ~0x07;
                //8字節對齊

gd->bd->bi_baudrate = gd->baudrate;
/* Ram ist board specific, so move it to board code ... */
dram_init_banksize();
display_dram_config(); /* and display it */

gd->relocaddr = addr;
        //u-boot重新搬運后的起始地址。

gd->start_addr_sp = addr_sp;
        //堆棧指針,堆向下長??

gd->reloc_off = addr - _TEXT_BASE;
        //偏移量=搬后起始地址-27e00000(u-boot下載地址)

debug("relocation Offset is: %08lx\n", gd->reloc_off);

memcpy(id, (void *)gd, sizeof(gd_t));
        // gd在0x22000,SRAM中,此函數給gd的結構體賦值了,拷貝到內存中留的gd結構體中。(或者說把寄存器r8拷貝到內存?)

relocate_code(addr_sp, id, addr);
relocate_code(addr_sp, id, addr);在start.S中定義,C又回到了匯編
(棧指針,全局數據的地方, 搬后起始地址)
經過該函數的處理,內存分配圖如下:


繼續分析
relocate_code(addr_sp, id, addr);在start.S中定義,C又回到了匯編
(棧指針,全局數據的地方, 搬后起始地址)
完成了第二次搬運過程,把u-boot從27e00000搬到了addr.
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
          .globl relocate_code
relocate_code:
         mov r4, r0 /* save addr_sp */
         mov r5, r1 /* save addr of gd */
         mov r6, r2          /* save addr of destination */
……
/* Set up the stack */
stack_setup:
         mov sp, r4
adr r0, _start
//得到u-boot的鏈接地址

cmp r0, r6
//判斷u-boot是否已經搬移到終地址

moveq r9, #0               /* no relocation. relocation offset(r9) = 0 */
         beq clear_bss               /* skip relocation */
//若不需要再次搬移,直接清bss段。

... mov r1, r6 /* r1 <- scratch for copy_loop */
              ldr r3, _image_copy_end_ofs
//需要搬移的u-boot的大小。

add r2, r0, r3 /* r2 <- source end address */
//r0和r2之間的內容全部搬走。

copy_loop:
              ldmia r0!, {r9-r10} /* copy from source address [r0] */
              stmia r1!, {r9-r10} /* copy to target address [r1] */
              cmp r0, r2 /* until source end address [r2] */
              blo copy_loop
//若u-boot需要自搬移,即不在終地址運行,把u-boot復制到了SDRAM的高端地址

#ifndef CONFIG_SPL_BUILD
               /*
               * fix .rel.dyn relocations
               */
               ldr r0, _TEXT_BASE        /* r0 <- Text base */
               sub r9, r6, r0        /* r9 <- relocation offset */
        //由于u-boot第一階段用的是絕對地址,所以搬運后繼續運行,需要加一個偏移量r9。

       ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
               add r10, r10, r0 /* r10 <- sym table in FLASH */
               ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
               add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
               ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
               add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
        ……
        ldr r0, _board_init_r_ofs
               adr r1, _start
               add lr, r0, r1
               add lr, lr, r9
               /* setup parameters for board_init_r */
               mov r0, r5 /* gd_t */
               mov r1, r6 /* dest_addr */
               /* jump to it ... */
               mov pc, lr
       _board_init_r_ofs:
               .word board_init_r - _start


至此,第一階段分析完成。
        ∗概括起來,第一階段主要功能為:
        ∗初始化基本的硬件;
        ∗把bootloader自搬運到內存中;
        ∗設置堆棧指針并將bss段清零。為后續執行C代碼做準備;
        ∗跳轉到第二階段代碼中.

發表評論
評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
主站蜘蛛池模板: AV永久天堂一区二区三区 | 欧美熟妇无码XXXXXX | 秒播无码国产在线观看 | 一色一伦一区二区三区的区别 | 日本大胆欧美人术艺术 | 国产成人拍精品视频午夜网站 | 免费人成黄页在线观看国产 | 最新国产毛2卡3卡4卡 | www.4hu影院 | 成年免费A级毛片免费看无码 | 日韩精品久久无码中文字幕 | 四房色播开心网 | 尤物TV国产精品看片在线 | 日本岛国片在线观看一区二区 | 日本高清一级片 | 99精品国产福久久久久久 | 啦啦啦www在线观看免费视频 | 日本饥渴人妻欲求不满 | 福利午夜| 中国vodafonewifi精品网站 | 精品久久久久中文字幕日本 | 被部长肉体侵犯中文字幕 | h无码精品动漫在线观看 | 国产欧美日韩精品丝袜高跟鞋 | 女人夜夜春高潮爽A∨片传媒 | 五十路熟女俱乐部 | 无码少妇a片一区二区三区 国内精品久久久久影院蜜芽 | 老师好湿好紧我要进去了在线观看 | 色屁屁WWW影院免费观看入口 | 免费网站在线观看人数在哪买 | 好湿好紧太硬了我太爽了视频 | AV狠狠色超碰丁香婷婷综合久久 | 两个人看的视频WWW在线高清 | 亚洲国产精品自在拍在线播放蜜臀 | 老年一级片 | 强奷漂亮少妇高潮a片 | 亚洲gay片在线gv网站 | 免费麻豆文化传媒www欢迎你 | 永久免费观看的毛片手机视频 | 精品国内自产拍在线观看 | 中文字幕 制服 亚洲 另类 |