亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現(xiàn)在的位置是:首頁 > 技術(shù)閱讀 >  u-boot2020.04移植(2、從鏈接腳本開始)

u-boot2020.04移植(2、從鏈接腳本開始)

時(shí)間:2024-05-31

點(diǎn)擊下方閱讀原文可訪問文中超鏈接

首先分析一下u-boot的鏈接腳本,這樣就能夠知道u-boot本身的大體組成及分布,如果想更詳細(xì)的了解,可以查看生成的u-boot.map文件,這個文件就能看出u-boot各個段的排布。在上一篇文章中,已經(jīng)完成了u-boot的編譯,在u-boot根目錄下可以看到生成了一個u-boot.lds文件,這個文件就是u-boot的鏈接腳本,它是由arch\arm\cpu\u-boot.lds文件經(jīng)過處理后得到的,其內(nèi)容如下:

OUTPUT_FORMAT("elf32-littlearm""elf32-littlearm""elf32-littlearm")
OUTPUT_ARCH(arm)
/*整個u-boot的入口*/
ENTRY(_start)
SECTIONS
{
 . = 0x00000000;
 . = ALIGN(4);
 .text :
 {
   /*這個和以前舊的u-boot版本不一樣,這個現(xiàn)在被定義在arch/arm/lib/sections.c文件中,
   對應(yīng)頭文件為include/asm-generic/sections.h,
   用的是零長數(shù)組來實(shí)現(xiàn),不占內(nèi)存空間,相當(dāng)于只是放了一個符號,u-boot重定位時(shí)就是從這個地址開始拷貝*/

  *(.__image_copy_start)
  /*存放向量表的段,位于arch/arm/lib/vectors.S文件*/
  *(.vectors)
  /*這個就相當(dāng)于是u-boot代碼執(zhí)行的開始了(但第一句執(zhí)行的代碼不在這兒)*/
  arch/arm/cpu/armv7/start.o (.text*)
 }
 /*表示efi_runtime段的開始*/
 .__efi_runtime_start : {
  *(.__efi_runtime_start)
 }
 .efi_runtime : {
  *(.text.efi_runtime*)
  *(.rodata.efi_runtime*)
  *(.data.efi_runtime*)
 }
 /*表示efi_runtime段的結(jié)束*/
 .__efi_runtime_stop : {
  *(.__efi_runtime_stop)
 }
 .text_rest :
 {
   /*u-boot代碼段*/
  *(.text*)
 }
 . = ALIGN(4);
   /*u-boot只讀數(shù)據(jù)段*/
 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 . = ALIGN(4);
 .data : {
   /*u-boot數(shù)據(jù)段*/
  *(.data*)
 }
 . = ALIGN(4);
 . = .;
 . = ALIGN(4);
 .u_boot_list : {
   /*u-boot自定義段,u-boot命令、硬件驅(qū)動、環(huán)境變量相關(guān)的一些東西等放在此段(*號是通配符),具體的段可以查看u-boot.map文件*/
  KEEP(*(SORT(.u_boot_list*)));
 }
 . = ALIGN(4);
 .efi_runtime_rel_start :
 {
  *(.__efi_runtime_rel_start)
 }
 .efi_runtime_rel : {
  *(.rel*.efi_runtime)
  *(.rel*.efi_runtime.*)
 }
 .efi_runtime_rel_stop :
 {
  *(.__efi_runtime_rel_stop)
 }
 . = ALIGN(4);
 .image_copy_end :
 {
   /*u-boot重定位拷貝結(jié)束的地址*/
  *(.__image_copy_end)
 }
 .rel_dyn_start :
 {
   /*動態(tài)符號表的開始*/
  *(.__rel_dyn_start)
 }
 .rel.dyn : {
   /*放置了動態(tài)符號表,也是重定位的時(shí)候需要的*/
  *(.rel*)
 }
 .rel_dyn_end :
 {
   /*動態(tài)符號表的結(jié)束*/
  *(.__rel_dyn_end)
 }
 .end :
 {
  *(.__end)
 }
 /*整個u-boot bin文件的結(jié)束*/
 _image_binary_end = .;
 . = ALIGN(4096);
 .mmutable : {
   /*MMU頁表相關(guān)*/
  *(.mmutable)
 }
 /*bss段,建立C語言運(yùn)行環(huán)境的時(shí)候需要*/
 .bss_start __rel_dyn_start (OVERLAY) : {
  KEEP(*(.__bss_start));
  __bss_base = .;
 }
 .bss __bss_base (OVERLAY) : {
  *(.bss*)
   . = ALIGN(4);
   __bss_limit = .;
 }
 .bss_end __bss_limit (OVERLAY) : {
  KEEP(*(.__bss_end));
 }
 /*后面是一些其它的段*/
 .dynsym _image_binary_end : { *(.dynsym) }
 .dynbss : { *(.dynbss) }
 .dynstr : { *(.dynstr*) }
 .dynamic : { *(.dynamic*) }
 .plt : { *(.plt*) }
 .interp : { *(.interp*) }
 .gnu.hash : { *(.gnu.hash) }
 .gnu : { *(.gnu*) }
 .ARM.exidx : { *(.ARM.exidx*) }
 .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
}

從其內(nèi)容可以得知整個u-boot程序的入口為_start這個標(biāo)號,在以前的u-boot中,入口都是在start.S文件中,后面新增了一個vectors.S文件,現(xiàn)在_start標(biāo)號就位于此文件中,所以先從此文件開始分析。

arch/arm/lib/vectors.S

/*向量表的定義*/
.macro ARM_VECTORS
/*未定義*/
#ifdef CONFIG_ARCH_K3
    ldr     pc, _reset
#else
/*從這兒可以看到,芯片上電后立馬就會執(zhí)行復(fù)位*/
    b   reset
#endif
/*這里只是相當(dāng)于只是一個函數(shù)指針,真正的實(shí)現(xiàn)在本文件的后面*/
    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
    .endm


/*從這兒可以看出,向量表被放到了專門的.vectors段中*/
    .section ".vectors""ax"

/*未定義,這是給有些芯片用來在u-boot頭部定義一些數(shù)據(jù)使用的*/
#if defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
/*
 省略注釋
 */

#include <asm/arch/boot0.h>
#else

/*
 省略注釋
 */


/*這就是整個u-boot的入口*/
_start:
/*未定義*/
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
    .word   CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
/*放置的向量表,定義在此文件的上面,和C語言的宏定義一樣*/
    ARM_VECTORS
#endif /* !defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) */

下面的內(nèi)容相當(dāng)于給異常處理的函數(shù)指針綁定一個函數(shù)實(shí)現(xiàn)的實(shí)體:

/*未定義*/
#ifdef CONFIG_ARCH_K3
_reset:            .word reset
#endif
/*這里定義了異常產(chǎn)生后,該去哪兒執(zhí)行異常處理的過程*/
_undefined_instruction:    .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:        .word not_used
_irq:            .word irq
_fiq:            .word fiq

以undefined_instruction為例,產(chǎn)生異常后,先執(zhí)行l(wèi)dr    pc, _undefined_instruction,它會將undefined_instruction這個過程(函數(shù))地址加載到pc指針中,這樣就相當(dāng)于調(diào)用undefined_instruction這個函數(shù)了:

/*32字節(jié)對齊,2的5次方*/
    .align  5
undefined_instruction:
/*下面這些過程都是在本文件實(shí)現(xiàn)的,就不詳細(xì)介紹了*/
    get_bad_stack
    bad_save_user_regs
    bl  do_undefined_instruction

向量表分析了,接著執(zhí)行了b reset后,下面就進(jìn)入arch/arm/cpu/armv7/start.S文件了:

reset:
    /* Allow the board to save important registers */
    /*什么也沒做*/
    b   save_boot_params
save_boot_params_ret:
/*未定義*/
#ifdef CONFIG_ARMV7_LPAE
/*
 * check for Hypervisor support
 */

    mrc p15, 0, r0, c0, c1, 1       @ read ID_PFR1
    and r0, r0, #CPUID_ARM_VIRT_MASK    @ mask virtualization bits
    cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
    beq switch_to_hypervisor
switch_to_hypervisor_ret:
#endif

要看懂后面的內(nèi)容,先得了解armv7架構(gòu)的一些內(nèi)容,需要參考arm的相關(guān)手冊(ARMv7-A -R Architecture Reference Manual.pdf),先看一下cpsr寄存器各個位的定義:

在這里插入圖片描述
圖1
其中與模式相關(guān)的位是bit[4:0],詳細(xì)的定義參見下圖,可以看到armv7總共有九種模式:


在這里插入圖片描述
圖2
再來看一下關(guān)于中斷和異常相關(guān)的位描述:


在這里插入圖片描述
圖3
現(xiàn)在繼續(xù)看后面的程序就輕松很多了,下面這段內(nèi)容就是關(guān)閉中斷,并且設(shè)置CPU進(jìn)入SVC32模式,關(guān)于其過程這里就不推導(dǎo)了,對照上面的圖,很簡單就能夠推導(dǎo)出來:


/*
     * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
     * except if in HYP mode already
     */

    mrs r0, cpsr
    and r1, r0, #0x1f       @ mask mode bits
    /*看是否處于HYP模式*/
    teq r1, #0x1a       @ test for HYP mode
    /*如果未在HYP模式就設(shè)置為SVC模式*/
    bicne   r0, r0, #0x1f       @ clear all mode bits
    orrne   r0, r0, #0x13       @ set SVC mode
    orr r0, r0, #0xc0       @ disable FIQ and IRQ
    msr cpsr,r0

繼續(xù)往后看,是協(xié)處理器相關(guān)的內(nèi)容,還是一樣,先從手冊找到其相關(guān)的描述,建議先了解一下關(guān)于協(xié)處理器指令的使用方法,再理解這段代碼就會輕松很多:

在這里插入圖片描述
圖4 關(guān)于SCTLR寄存器的位定義


在這里插入圖片描述
圖5 關(guān)于V位的描述
下面看代碼:


#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
    /* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
    mrc p15, 0, r0, c1, c0, 0   @ Read CP15 SCTLR Register
    bic r0, #CR_V       @ V = 0
    mcr p15, 0, r0, c1, c0, 0   @ Write CP15 SCTLR Register

#ifdef CONFIG_HAS_VBAR
    /* Set vector address in CP15 VBAR register */
    ldr r0, =_start
    mcr p15, 0, r0, c12, c0, 0  @Set VBAR
#endif
#endif

從cp15協(xié)處理器SCTLR寄存器V位的描述來看,設(shè)置為0的話,向量表基地址就是0x00000000,并且向量表基地址是可以被重映射的,而設(shè)置為1的話,向量表基地址就是0xffff0000,不能被重映射,因?yàn)楹竺鎢-boot會被拷貝到DRAM中運(yùn)行,如果向量表還在內(nèi)部IRAM的話,如果我們想使用中斷,那就訪問不到了,所以得將向量表基地址重映射,這樣產(chǎn)生中斷后才能正確的被響應(yīng),因此這里將V位設(shè)置為0允許重映射,然后將向量表基地址設(shè)置為_start這個標(biāo)號所在的地址,從前面的內(nèi)容我們知道,_start標(biāo)號開始的地方就是放置的中斷向量表。

接下來cpu_init_cp15函數(shù)又是對協(xié)處理器的一堆操作,就不詳細(xì)講了,想繼續(xù)深入分析的可以參考ARMv7-A -R Architecture Reference Manual.pdf文檔,直接點(diǎn)擊鏈接就可下載,下面簡要的注釋一下相關(guān)的內(nèi)容:

ENTRY(cpu_init_cp15)
    /*
     * Invalidate L1 I/D
     */

    mov r0, #0          @ set up for MCR
    /*TLB無效*/
    mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs
    /*指令緩存無效*/
    mcr p15, 0, r0, c7, c5, 0   @ invalidate icache
    /*分支預(yù)測無效*/
    mcr p15, 0, r0, c7, c5, 6   @ invalidate BP array
    /*數(shù)據(jù)和指令同步屏障*/
    mcr     p15, 0, r0, c7, c10, 4  @ DSB
    mcr     p15, 0, r0, c7, c5, 4   @ ISB

    /*
     * disable MMU stuff and caches
     */

    mrc p15, 0, r0, c1, c0, 0
    /*設(shè)置向量表基地址,前面已經(jīng)設(shè)置過*/
    bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
    /*數(shù)據(jù)和緩存一致性失能,對齊錯誤檢查失能,MMU失能*/
    bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
    /*對齊錯誤檢查使能*/
    orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
    /*程序流預(yù)測使能*/
    orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
    /*未定義*/
#if CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
    bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
#else
    /*指令緩存使能*/
    orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
#endif
    mcr p15, 0, r0, c1, c0, 0

/*勘誤相關(guān)的都沒有定義*/
/*
省略勘誤相關(guān)的內(nèi)容
*/


    mov r5, lr          @ Store my Caller
    /*讀取芯片的一些信息,如版本號、架構(gòu)等,但實(shí)際上沒用到*/
    mrc p15, 0, r1, c0, c0, 0   @ r1 has Read Main ID Register (MIDR)
    mov r3, r1, lsr #20     @ get variant field
    and r3, r3, #0xf        @ r3 has CPU variant
    and r4, r1, #0xf        @ r4 has CPU revision
    mov r2, r3, lsl #4      @ shift variant field for combined value
    orr r2, r4, r2      @ r2 has combined CPU variant + revision
/* Early stack for ERRATA that needs into call C code */
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
    ldr r0, 
=(CONFIG_SPL_STACK)
#else
    /*設(shè)置一個臨時(shí)的棧用于下面的勘誤相關(guān)內(nèi)容的執(zhí)行,這個地址三星設(shè)置在了DRAM里面,
    要是現(xiàn)在我們還沒有初始化DRAM,那執(zhí)行C函數(shù)的時(shí)候,程序肯定就跑飛了,好在這部分內(nèi)容都沒有執(zhí)行*/

    ldr r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
    bic r0, r0, #7  /* 8-byte alignment for ABI compliance */
    mov sp, r0

/*
省略勘誤相關(guān)的內(nèi)容
*/


    /*這里就返回了*/
    mov pc, r5          @ back to my caller
ENDPROC(cpu_init_cp15)

到了這里,關(guān)于arm內(nèi)核相關(guān)的東西就結(jié)束了,后面就是SOC相關(guān)的內(nèi)容了。

歡迎掃碼關(guān)注我的微信公眾號

漫長當(dāng)下


主站蜘蛛池模板: 桂东县| 兰州市| 长乐市| 巴东县| 申扎县| 兴宁市| 滁州市| 鸡西市| 临朐县| 临澧县| 调兵山市| 新郑市| 运城市| 日照市| 武威市| 东城区| 左贡县| 平昌县| 客服| 贵港市| 安远县| 保德县| 竹溪县| 乌海市| 淄博市| 古交市| 玛沁县| 扶沟县| 庄河市| 五大连池市| 二连浩特市| 泰和县| 闽清县| 仁化县| 建宁县| 旬邑县| 伊金霍洛旗| 巴青县| 津市市| 永安市| 班戈县|