U-boot原始碼全分析系列(基於PowerPC)-3

來源:互聯網
上載者:User

     這裡首先更正下上一篇中的一個錯誤,最後一步中的跳轉代碼當時一時倉促貼錯了,先改正如下:

7、跳轉到Stage2入口處

    這也是Stage1的最後一步,程式在執行到這一步後,基本的硬體初始化工作也就完成了,下面是跳轉的代碼:

clear_bss:/* 執行清空bss操作 */lwzr3,GOT(__bss_start)#if defined(CONFIG_HYMOD)/* * For HYMOD - the environment is the very last item in flash. * The real .bss stops just before environment starts, so only * clear up to that point. * taken from mods for FADS board     * 檢查當前代碼位置 */lwzr4,GOT(environment)#elselwzr4,GOT(_end)#endif/* 計算跳轉 */cmplw0, r3, r4beq6flir0, 05:stwr0, 0(r3)addir3, r3, 4cmplw0, r3, r4bne5b6:mrr3, r9/* Global Data pointer*/mrr4, r10/* Destination Address*/blboard_init_r

其中board_init_r就是Stage2的函數入口。

    由上可以看出start.S的流程為:異常向量——上電複位後進入複位異常向量——跳到啟動代碼處——設定處理器進入管理員模式——關閉看門狗——關閉中斷——設定時鐘分頻——關閉MMU和CACHE——進入low level初始化代碼——檢查當前代碼所處的位置,如果在FLASH中就將代碼搬移到RAM中。至此,Stage1分析到此結束。

    跳轉到board_init_r後,程式開始執行Stage2階段,代碼多為C。

望諒解。

    在上篇分析完Stage1的彙編代碼後,又細看了兩個C函數,也是屬於很重要的初始化函數,所以,在分析Stage2的代碼前,先還要看下Stage1的兩個C代碼程式,分別為cpu_init_f和board_init_f,二者在組譯工具in_flash中被調用,雖是C代碼,但實現的仍是基本的初始化功能,且運行在ROM中,屬於Stage1的範疇。

    先看cpu_init_f函數,它是用來初始化low-level CPU的,主要功能包括建立記憶體映射map、初始化一些寄存器和UPM(User-Programmable Machine)。

    首先初始化一個結構體:

gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET);/* Clear initial global data */memset ((void *) gd, 0, sizeof (gd_t));

    此處的結構體gd_t是一個放在啟動後很早就可用的記憶體中的,就像mpc8xx、mpc82xx的DPRAM,或者是資料cache的locked parts,主要用於存放一小部分系統初始化時要用的全域變數,直到初始化記憶體控制器可用RAM之前,這是我們唯一能用的全域變數。這個區間是很小的,在本區間中只有256個位元組。之後就開始配置各種裝置的時鐘模式,下面是對PCI和DMA的配置:

#ifdef CFG_SCCR_PCICM/* PCI & DMA clock mode */im->clk.sccr = (im->clk.sccr & ~SCCR_PCICM) |       (CFG_SCCR_PCICM << SCCR_PCICM_SHIFT);#endif

    這個配置的選項是要根據datasheet裡的SCCR寄存器來定的,下面是mpc83xx的一個系統時鐘控制寄存器的各位:

    根據說明來對應uboot中include/Mpc83xx.h中的相關配置,不過大多數的CPU型號都已經配置好了,一般無需改動。

    接下來初始化一些寄存器,如複位控制寄存器,DDR控制驅動寄存器等:

/* RSR - Reset Status Register - clear all status */gd->reset_status = im->reset.rsr;im->reset.rsr = ~(RSR_RES);/* RMR - Reset Mode Register  contains checkstop reset enable*/im->reset.rmr = (RMR_CSRE & (1<<RMR_CSRE_SHIFT));/* LCRR - Clock Ratio Register */im->lbus.lcrr = CFG_LCRR;/* Enable Time Base & Decrimenter ( so we will have udelay() )*/im->sysconf.spcr |= SPCR_TBEN;/* System General Purpose Register */im->sysconf.sicrh = CFG_SICRH;

    這些都需要對照著Datasheet裡的第四章:Reset,Clockig,and Initialization一一比對著看,這樣才能加深印象(儘管大多數實際應用中都不用修改)。

    最後是初始化記憶體映射,下面代碼作用為將bank0映射到Flash的bank0的初始地址,後面還有部分代碼,將根據需要映射bank1~7的:

im->lbus.bank[0].br = CFG_BR0_PRELIM;im->lbus.bank[0].or = CFG_OR0_PRELIM;im->sysconf.lblaw[0].bar = CFG_LBLAWBAR0_PRELIM;im->sysconf.lblaw[0].ar = CFG_LBLAWAR0_PRELIM;

    再來看下board_init_f函數,它主要用於在啟動時儘快的提供一個控制台介面(串口)用於輸出錯誤資訊,並且初始化記憶體以便於複製代碼。這段代碼的編寫需要注意:全域變數是唯讀,BSS還未初始化,堆棧空間也很小(盡量不要有複雜操作)。最開始先進行一系列的初始化操作,和ARM系列類似,將初始化函數列表放在結構體init_sequence中:

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

    主要包括板件前期初始化、擷取CPU及匯流排時鐘、初始化SDRAM時鐘、初始化串口等操作。此時記憶體已經映射好了,就可以在DRAM中運行程式了,接下來我們需要在RAM的末端儲存一些資料,包括uboot和Linux不能操作的地區、核心日誌緩衝、PRAM(被保護的RAM)、LCD幀緩衝、監聽代碼、板件資訊等。

 /*通過修改gd->ram_size可以使uboot無法訪問指定區間*/gd->ram_size -= CFG_MEM_TOP_HIDE;addr = CFG_SDRAM_BASE + get_effective_memsize();#ifdef CONFIG_LOGBUFFER#ifndef CONFIG_ALT_LB_ADDR/*儲存核心日誌*/addr -= (LOGBUFF_RESERVE);debug ("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr);#endif#endif#ifdef CONFIG_PRAM/* reserve protected RAM */i = getenv_r ("pram", (char *)tmp, sizeof (tmp));reg = (i > 0) ? simple_strtoul ((const char *)tmp, NULL, 10) : CONFIG_PRAM;addr -= (reg << 10);/* size is in kB */debug ("Reserving %ldk for protected RAM at %08lx\n", reg, addr);#endif /* CONFIG_PRAM */#ifdef CONFIG_LCD/* reserve memory for LCD display (always full pages) */addr = lcd_setmem (addr);gd->fb_base = addr;#endif /* CONFIG_LCD */#if defined(CONFIG_VIDEO) && defined(CONFIG_8xx)/* reserve memory for video display (always full pages) */addr = video_setmem (addr);gd->fb_base = addr;#endif /* CONFIG_VIDEO  */#ifdef CONFIG_AMIGAONEG3SEgd->relocaddr = addr;#endif/* reserve memory for malloc() arena */addr_sp = addr - TOTAL_MALLOC_LEN;debug ("Reserving %dk for malloc() at: %08lx\n",TOTAL_MALLOC_LEN >> 10, addr_sp);/* (permanently) allocate a Board Info struct and a permanent copy of the "global" dat*/addr_sp -= sizeof (bd_t);bd = (bd_t *) addr_sp;gd->bd = bd;debug ("Reserving %zu Bytes for Board Info at: %08lx\n",sizeof (bd_t), addr_sp);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);

    接下來的代碼比較容易理解,就是將板件資訊儲存到結構體board_info裡,包括串口資訊、PHY晶片資訊、啟動參數、RAM參數、flash資訊等。

    分析完這兩個C函數後,Stage1的分析就全部結束了。接下來跳入board_init_r函數中開始Stage2。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.