zoukankan      html  css  js  c++  java
  • 从零开始之uboot、移植uboot2017.01(二、从入口分析流程)

    本节的开始之前,先看一下uboot的链接脚本。

    一、链接脚本

    /*
     * Copyright (c) 2004-2008 Texas Instruments
     *
     * (C) Copyright 2002
     * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
     *
     * SPDX-License-Identifier:  GPL-2.0+
     */
     
    #include <config.h>
    #include <asm/psci.h>
     
    OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
    OUTPUT_ARCH(arm)
    ENTRY(_start)                /* 程序入口代码标号 */
    SECTIONS
    {
    #ifndef CONFIG_CMDLINE
      /DISCARD/ : { *(.u_boot_list_2_cmd_*) }
    #endif
    #if defined(CONFIG_ARMV7_SECURE_BASE) && defined(CONFIG_ARMV7_NONSEC)
      /*
       * If CONFIG_ARMV7_SECURE_BASE is true, secure code will not
       * bundle with u-boot, and code offsets are fixed. Secure zone
       * only needs to be copied from the loading address to
       * CONFIG_ARMV7_SECURE_BASE, which is the linking and running
       * address for secure code.
       *
       * If CONFIG_ARMV7_SECURE_BASE is undefined, the secure zone will
       * be included in u-boot address space, and some absolute address
       * were used in secure code. The absolute addresses of the secure
       * code also needs to be relocated along with the accompanying u-boot
       * code.
       *
       * So DISCARD is only for CONFIG_ARMV7_SECURE_BASE.
       */
      /DISCARD/ : { *(.rel._secure*) }
    #endif
      . = 0x00000000;
     
      . = ALIGN(4);
      .text :
      {
        *(.__image_copy_start)
        *(.vectors)                    /* 程序入口文件 */
        CPUDIR/start.o (.text*)
        *(.text*)
      }
     
    #ifdef CONFIG_ARMV7_NONSEC
     
      /* Align the secure section only if we're going to use it in situ */
      .__secure_start :
    #ifndef CONFIG_ARMV7_SECURE_BASE
        ALIGN(CONSTANT(COMMONPAGESIZE))
    #endif
      {
        KEEP(*(.__secure_start))
      }
    #ifndef CONFIG_ARMV7_SECURE_BASE
    #define CONFIG_ARMV7_SECURE_BASE
    #define __ARMV7_PSCI_STACK_IN_RAM
    #endif
      .secure_text CONFIG_ARMV7_SECURE_BASE :
        AT(ADDR(.__secure_start) + SIZEOF(.__secure_start))
      {
        *(._secure.text)
      }
      .secure_data : AT(LOADADDR(.secure_text) + SIZEOF(.secure_text))
      {
        *(._secure.data)
      }
    #ifdef CONFIG_ARMV7_PSCI
      .secure_stack ALIGN(ADDR(.secure_data) + SIZEOF(.secure_data),
              CONSTANT(COMMONPAGESIZE)) (NOLOAD) :
    #ifdef __ARMV7_PSCI_STACK_IN_RAM
        AT(ADDR(.secure_stack))
    #else
        AT(LOADADDR(.secure_data) + SIZEOF(.secure_data))
    #endif
      {
        KEEP(*(.__secure_stack_start))
        /* Skip addreses for stack */
        . = . + CONFIG_ARMV7_PSCI_NR_CPUS * ARM_PSCI_STACK_SIZE;
        /* Align end of stack section to page boundary */
        . = ALIGN(CONSTANT(COMMONPAGESIZE));
        KEEP(*(.__secure_stack_end))
    #ifdef CONFIG_ARMV7_SECURE_MAX_SIZE
        /*
         * We are not checking (__secure_end - __secure_start) here,
         * as these are the load addresses, and do not include the
         * stack section. Instead, use the end of the stack section
         * and the start of the text section.
         */
        ASSERT((. - ADDR(.secure_text)) <= CONFIG_ARMV7_SECURE_MAX_SIZE,
               "Error: secure section exceeds secure memory size");
    #endif
      }
    #ifndef __ARMV7_PSCI_STACK_IN_RAM
      /* Reset VMA but don't allocate space if we have secure SRAM */
      . = LOADADDR(.secure_stack);
    #endif
     
    #endif
     
      .__secure_end : AT(ADDR(.__secure_end)) {
        *(.__secure_end)
        LONG(0x1d1071c);  /* Must output something to reset LMA */
      }
    #endif
     
      . = ALIGN(4);
      .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
     
      . = ALIGN(4);
      .data : {
        *(.data*)
      }
     
      . = ALIGN(4);
     
      . = .;
     
      . = ALIGN(4);
      .u_boot_list : {
        KEEP(*(SORT(.u_boot_list*)));
      }
     
      . = ALIGN(4);
     
      .__efi_runtime_start : {
        *(.__efi_runtime_start)
      }
     
      .efi_runtime : {
        *(efi_runtime_text)
        *(efi_runtime_data)
      }
     
      .__efi_runtime_stop : {
        *(.__efi_runtime_stop)
      }
     
      .efi_runtime_rel_start :
      {
        *(.__efi_runtime_rel_start)
      }
     
      .efi_runtime_rel : {
        *(.relefi_runtime_text)
        *(.relefi_runtime_data)
      }
     
      .efi_runtime_rel_stop :
      {
        *(.__efi_runtime_rel_stop)
      }
     
      . = ALIGN(4);
     
      .image_copy_end :
      {
        *(.__image_copy_end)
      }
     
      .rel_dyn_start :
      {
        *(.__rel_dyn_start)
      }
     
      .rel.dyn : {
        *(.rel*)
      }
     
      .rel_dyn_end :
      {
        *(.__rel_dyn_end)
      }
     
      .end :
      {
        *(.__end)
      }
     
      _image_binary_end = .;
     
      /*
       * Deprecated: this MMU section is used by pxa at present but
       * should not be used by new boards/CPUs.
       */
      . = ALIGN(4096);
      .mmutable : {
        *(.mmutable)
      }
     
    /*
     * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
     * __bss_base and __bss_limit are for linker only (overlay ordering)
     */
     
      .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.*) }
    }

    二.中断向量表的存放

    可以看到真正的入口是_start,真正的.text段是从.vectors开始的。从字面上就能看出.vector段是中断向量表的存放处。下面u-boot源码所示是根据CPU的硬件特性所定义的中断向量表:

    arch/arm/lib/vectors.S

             .section ".vectors", "ax"
     
    /*
     *************************************************************************
     *
     * Exception vectors as described in ARM reference manuals
     *
     * Uses indirect branch to allow reaching handlers anywhere in memory.
     *
     *************************************************************************
     */
     
    _start:
     
    #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
            .word   CONFIG_SYS_DV_NOR_BOOT_CFG
    #endif
     
            b       reset
            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
     
    #ifdef CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK
    /*
     * Various SoCs need something special and SoC-specific up front in
     * order to boot, allow them to set that in their boot0.h file and then
     * use it here.
     */
    #include <asm/arch/boot0.h>
    ARM_SOC_BOOT0_HOOK
    #endif
     
    /*
     *************************************************************************
     *
     * Indirect vectors table
     *
     * Symbols referenced here must be defined somewhere else
     *
     *************************************************************************
     */
     
      .globl  _undefined_instruction
      .globl  _software_interrupt
      .globl  _prefetch_abort
      .globl  _data_abort
      .globl  _not_used
      .globl  _irq
      .globl  _fiq
     
    _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
     
      .balignl 16,0xdeadbeef
     
    /*
     *************************************************************************
     *
     * Interrupt handling
     *
     *************************************************************************
     */
     
    /* SPL interrupt handling: just hang */
     
    #ifdef CONFIG_SPL_BUILD       
     
      .align  5
    undefined_instruction:
    software_interrupt:
    prefetch_abort:
    data_abort:
    not_used:
    irq:
    fiq:
     
    1:
      bl  1b      /* hang and never return */
    /* 可以看到,在SPL阶段,发生异常,则直接进入上面死循环,死掉 */
     
     
    #else  /* !CONFIG_SPL_BUILD */
     
    /* IRQ stack memory (calculated at run-time) + 8 bytes */
    .globl IRQ_STACK_START_IN
    IRQ_STACK_START_IN:
      .word  0x0badc0de
     
    #ifdef CONFIG_USE_IRQ
    /* IRQ stack memory (calculated at run-time) */
    .globl IRQ_STACK_START
    IRQ_STACK_START:
      .word  0x0badc0de
     
    /* IRQ stack memory (calculated at run-time) */
    .globl FIQ_STACK_START
    FIQ_STACK_START:
      .word 0x0badc0de
     
    #endif /* CONFIG_USE_IRQ */
     
    ......
     
    #ifdef CONFIG_USE_IRQ
     
      .align  5
    irq:
      get_irq_stack
      irq_save_user_regs
      bl  do_irq
      irq_restore_user_regs
     
      .align  5
    fiq:
      get_fiq_stack
      /* someone ought to write a more effiction fiq_save_user_regs */
      irq_save_user_regs
      bl  do_fiq
      irq_restore_user_regs
     
    #else
     
      .align  5
    irq:
      get_bad_stack
      bad_save_user_regs
      bl  do_irq
     
      .align  5
    fiq:
      get_bad_stack
      bad_save_user_regs
      bl  do_fiq
     
    #endif /* CONFIG_USE_IRQ */
     
    #endif  /* CONFIG_SPL_BUILD */


    三、初始代码开始

    从异常向量表的reset跳转过来,

      .globl  reset
    .globl save_boot_params_ret
    #ifdef CONFIG_ARMV7_LPAE
    .global switch_to_hypervisor_ret
    #endif

    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
    /* 关中断,设置cpu处于svc32模式
    * 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
    teq r1, #0x1a @ test for HYP mode
    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

    /* 我们是不是OMAP44XX系列的,所以会指行这里,在cp15的c12寄存器设置异常向量表的基地址(这里我们设置在了_start)
    * Setup vector:
    * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
    * Continue to use ROM code vector only in OMAP4 spl)
    */
    #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

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

    /* the mask ROM code should have PLL and others stable */
    /* 下面的两个skip的通常是不会被定义的,如果被定义,就不会初始化底层(lowlevel),定义skip是uboot被别的bootloader加载,uboot才会不再初始化底层 */

    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl cpu_init_cp15 /* cp15相关的(页表,icache,dcache无效) */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
    bl cpu_init_crit /* lowlovel init */
    #endif
    #endif

    bl _main

    /*------------------------------------------------------------------------------*/

    ENTRY(c_runtime_cpu_setup)
    /*
    * If I-cache is enabled invalidate it
    */
    #ifndef CONFIG_SYS_ICACHE_OFF
    mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
    mcr p15, 0, r0, c7, c10, 4 @ DSB
    mcr p15, 0, r0, c7, c5, 4 @ ISB
    #endif

    bx lr

    ENDPROC(c_runtime_cpu_setup)

    /*************************************************************************
    *
    * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
    * __attribute__((weak));
    *
    * Stack pointer is not yet initialized at this moment
    * Don't save anything to stack even if compiled with -O0
    *
    *************************************************************************/
    ENTRY(save_boot_params)
    b save_boot_params_ret @ back to my caller
    ENDPROC(save_boot_params)
    .weak save_boot_params

    #ifdef CONFIG_ARMV7_LPAE
    ENTRY(switch_to_hypervisor)
    b switch_to_hypervisor_ret
    ENDPROC(switch_to_hypervisor)
    .weak switch_to_hypervisor
    #endif

    /*************************************************************************
    *
    * cpu_init_cp15
    *
    * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless
    * CONFIG_SYS_ICACHE_OFF is defined.
    *
    *************************************************************************/
    ENTRY(cpu_init_cp15)
    /*
    * Invalidate L1 I/D,无效页表、指令缓存、数据缓存
    */
    mov r0, #0 @ set up for MCR
    mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
    mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
    mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
    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
    bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
    bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
    orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
    orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
    #ifdef CONFIG_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

    #ifdef CONFIG_ARM_ERRATA_716044 /* 没定义,跳过 */
    mrc p15, 0, r0, c1, c0, 0 @ read system control register
    orr r0, r0, #1 << 11 @ set bit #11
    mcr p15, 0, r0, c1, c0, 0 @ write system control register
    #endif

    #if (defined(CONFIG_ARM_ERRATA_742230) || defined(CONFIG_ARM_ERRATA_794072)) /* 没定义,跳过 */
    mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
    orr r0, r0, #1 << 4 @ set bit #4
    mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
    #endif

    #ifdef CONFIG_ARM_ERRATA_743622 /* 没定义,跳过 */
    mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
    orr r0, r0, #1 << 6 @ set bit #6
    mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
    #endif

    #ifdef CONFIG_ARM_ERRATA_751472 /* 没定义,跳过 */
    mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
    orr r0, r0, #1 << 11 @ set bit #11
    mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
    #endif
    #ifdef CONFIG_ARM_ERRATA_761320 /* 没定义,跳过 */
    mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
    orr r0, r0, #1 << 21 @ set bit #21
    mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
    #endif

    mov r5, lr @ Store my Caller /* 返回地址保存在r5 */
    mrc p15, 0, r1, c0, c0, 0 @ r1 has Read Main ID Register (MIDR) /* 读芯片id,放在r1中 */
    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

    #ifdef CONFIG_ARM_ERRATA_798870 /* 没定义,跳过 */
    cmp r2, #0x30 @ Applies to lower than R3p0
    bge skip_errata_798870 @ skip if not affected rev
    cmp r2, #0x20 @ Applies to including and above R2p0
    blt skip_errata_798870 @ skip if not affected rev

    mrc p15, 1, r0, c15, c0, 0 @ read l2 aux ctrl reg
    orr r0, r0, #1 << 7 @ Enable hazard-detect timeout
    push {r1-r5} @ Save the cpu info registers
    bl v7_arch_cp15_set_l2aux_ctrl
    isb @ Recommended ISB after l2actlr update
    pop {r1-r5} @ Restore the cpu info - fall through
    skip_errata_798870:
    #endif

    #ifdef CONFIG_ARM_ERRATA_801819 /* 没定义,跳过 */
    cmp r2, #0x24 @ Applies to lt including R2p4
    bgt skip_errata_801819 @ skip if not affected rev
    cmp r2, #0x20 @ Applies to including and above R2p0
    blt skip_errata_801819 @ skip if not affected rev
    mrc p15, 0, r0, c0, c0, 6 @ pick up REVIDR reg
    and r0, r0, #1 << 3 @ check REVIDR[3]
    cmp r0, #1 << 3
    beq skip_errata_801819 @ skip erratum if REVIDR[3] is set

    mrc p15, 0, r0, c1, c0, 1 @ read auxilary control register
    orr r0, r0, #3 << 27 @ Disables streaming. All write-allocate
    @ lines allocate in the L1 or L2 cache.
    orr r0, r0, #3 << 25 @ Disables streaming. All write-allocate
    @ lines allocate in the L1 cache.
    push {r1-r5} @ Save the cpu info registers
    bl v7_arch_cp15_set_acr
    pop {r1-r5} @ Restore the cpu info - fall through
    skip_errata_801819:
    #endif

    #ifdef CONFIG_ARM_ERRATA_454179 /* 没定义,跳过 */
    cmp r2, #0x21 @ Only on < r2p1
    bge skip_errata_454179

    mrc p15, 0, r0, c1, c0, 1 @ Read ACR
    orr r0, r0, #(0x3 << 6) @ Set DBSM(BIT7) and IBE(BIT6) bits
    push {r1-r5} @ Save the cpu info registers
    bl v7_arch_cp15_set_acr
    pop {r1-r5} @ Restore the cpu info - fall through

    skip_errata_454179:
    #endif

    #ifdef CONFIG_ARM_ERRATA_430973 /* 没定义,跳过 */
    cmp r2, #0x21 @ Only on < r2p1
    bge skip_errata_430973

    mrc p15, 0, r0, c1, c0, 1 @ Read ACR
    orr r0, r0, #(0x1 << 6) @ Set IBE bit
    push {r1-r5} @ Save the cpu info registers
    bl v7_arch_cp15_set_acr
    pop {r1-r5} @ Restore the cpu info - fall through

    skip_errata_430973:
    #endif

    #ifdef CONFIG_ARM_ERRATA_621766 /* 没定义,跳过 */
    cmp r2, #0x21 @ Only on < r2p1
    bge skip_errata_621766

    mrc p15, 0, r0, c1, c0, 1 @ Read ACR
    orr r0, r0, #(0x1 << 5) @ Set L1NEON bit
    push {r1-r5} @ Save the cpu info registers
    bl v7_arch_cp15_set_acr
    pop {r1-r5} @ Restore the cpu info - fall through

    skip_errata_621766:
    #endif

    mov pc, r5 @ back to my caller 前面存储在r5的返回地址,返回
    ENDPROC(cpu_init_cp15)

    #if !defined(CONFIG_SKIP_LOWLEVEL_INIT) &&
    !defined(CONFIG_SKIP_LOWLEVEL_INIT_ONLY)
    /*************************************************************************
    *
    * CPU_init_critical registers
    *
    * setup important registers
    * setup memory timing
    *
    *************************************************************************/
    ENTRY(cpu_init_crit)
    /*
    * Jump to board specific initialization...
    * The Mask ROM will have already initialized
    * basic memory. Go here to bump up clock rate and handle
    * wake up conditions.
    */
    b lowlevel_init @ go setup pll,mux,memory
    ENDPROC(cpu_init_crit)
    #endif

    可以发现执行流程是这样的:

    reset  ---->>>   save_boot_params(什么都没干,跳回reset后面) ----->>> save_boot_params_ret----->>关中断  

    ----->设置异常向量表的基地址 ------->cpu_init_cp15(无效icache,dcache等)------->cpu_init_crit(继续调用lowlevel)

    因为后面的lowlevel是要跳转到别的文件进行初始化了,所以我们在它前面增加代码先进行调试。

    在start.S的最后面增加led1的调试代码

     
    gpio_out:
            ldr r11, =0xe0200240
            ldr r12, =0x01111000
            str r12, [r11]
     
            ldr r11, =0xe0200244
            ldr r12, =0xff
            str r12, [r11]
            mov pc, lr
     
    .globl led1_on
    led1_on:
            ldr r11, =0xe0200244
            ldr r12, [r11]
            bic r12, r12,#(1<<3)
            str r12, [r11]
            mov pc, lr
     
    .globl led1_off
    led1_off:
            ldr r11, =0xe0200244
            ldr r12, [r11]
            orr r12, r12,#(1<<3)
            str r12, [r11]
            mov pc, lr

    在执行跳转代码前面让led灯如果点亮,则可以确定执行到这里的代码都正确。

     
     
            bl      gpio_out
            bl      led1_on
     
            /* the mask ROM code should have PLL and others stable */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
            bl      cpu_init_cp15
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
            bl      cpu_init_crit
    #endif
    #endif

     

    之后make编译生成u-boot.bin文件

    烧写,测试

     

    因为s5pv210通过sd卡启动,需要内部的irom代码校验的。所以我们先编写校验代码。

    校验算法applacation note也给出了,BL1的大小常见的为8k或16k。

     

     我这边为了方便,做成16k的BL1,代码如下

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define BL1_SIZE          (16*1024)
    #define BL_HEADER_INFO      "                "
    #define BL_HEADER_SIZE      16
     
     
    int main(int argc,char *argv[])
    {
      FILE *fp = NULL;
      int file_len = 0;
      unsigned char *buff = NULL,data = 0;    /* 这里要定义成unsigned 否则,否则data加出来的会有负数,导致校验和错误,这里用三星官方给的有点小坑 */
      int buf_len = 0;
      unsigned int checksum = 0,count;
      int i = 0;  
      unsigned int nbytes = 0;
     
        /* 输入三个参数,分别是自己可执行文件,uboot.bin,输出的16k文件 */
      if(3 != argc)
      {
        printf("argc paramenter number is %d,not 3 ",argc);
        printf("%s <source file> <destination file> ",argv[0]);
        return -1;
      }  
     
      buff = (unsigned  char *)malloc(BL1_SIZE);
      if(NULL == buff)
      {
        printf("malloc error ");
        return -1;
      }
     
      /* clear the buff memary */
      memset(buff, 0, BL1_SIZE);
     
      fp = fopen(argv[1],"rb");
      if(NULL == fp)
      {
        printf("open source file error ");
        return -1;
      }
      /* 定位到文件尾 */
      fseek(fp,0,SEEK_END);
      /* 得到文件长度 */
      file_len = ftell(fp);  
      /* 定位到文件头 */
      fseek(fp,0,SEEK_SET);
      /* get write BL1 size */
      count = (file_len < (BL1_SIZE - BL_HEADER_SIZE)) ? file_len : (BL1_SIZE - BL_HEADER_SIZE);
      /* write BL1 header info */
      memcpy(buff, BL_HEADER_INFO, BL_HEADER_SIZE);
      /* read fp file count size of buff +... */
      nbytes = fread(buff + BL_HEADER_SIZE, 1, count , fp);
      if(count != nbytes)
      {
        printf("fread %s faile   ",argv[1]);
        free(buff);
        fclose(fp);
        return -1;
      }
      fclose(fp);
      fp = NULL;
     
      /* calculate checksum */
      for(i = 0; i < count; i++ )
      {
        data = *(volatile unsigned char *)(buff + BL_HEADER_SIZE + i);
        checksum += data;
      }
     
      *(volatile unsigned int *)buff = BL1_SIZE;
      *(volatile unsigned int *)(buff + 8) = checksum;
     
      fp = fopen(argv[2],"wb");
      if(NULL == fp)
      {
        printf("open aim file error ");
        return -1;
      }
     
      nbytes = fwrite(buff, 1, BL1_SIZE, fp);
      if(BL1_SIZE != nbytes)
      {
        printf("write aim file faile ");
        free(buff);
        fclose(fp);
        return -1;
      }
        
      fclose(fp);
      free(buff);
     
      return 0;
    }

     

    生成16k制作工具

    gcc s5pv210_image.c -o make-16k

    生成16k烧写文件

     ./make-16k u-boot.bin u-boot-16k.bin

    烧写sd卡

    sudo dd iflag=dsync oflag=dsync if=./u-boot-16k.bin of=/dev/sdb seek=1

    发现led1确实被点亮了,说明到目前为止的程序运行正确。

    四、lowlevel_init

    lowlevel_init一般是由板级代码自己实现的.但是对于某些平台来说,也可以使用通用的lowlevel_init,其定义在arch/arm/cpu/lowlevel_init.S中。以goni为例,在移植goni的过程中,就需要在board/samsung/goni下,也就是板级目录下面创建lowlevel_init.S,在内部实现lowlevel_init。(其实只要实现了lowlevel_init了就好,没必要说在哪里是实现,但是通常规范都是创建了lowlevel_init.S来专门实现lowlevel_init函数)

    在查看lowlevel_init函数之前,先找到代码在哪里,搜了一下发现除去和我们不相关的两个SOC外还是有两个定义的地方。没办法,只有查看Makefile

     

    先看armv7下面的,可以知道这些系列的CPU我们都没定义,所以 它们是等于 NULL的,即不会包含lowlevel_init.o

    ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_MX7)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_ARCH_SUNXI)$(CONFIG_ARCH_SOCFPGA)$(CONFIG_LS102XA),)
    ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y)
    obj-y   += lowlevel_init.o
    endif
    endif


    接下来看goni下面的,直接包含了,没有任何条件(即:只要是goni的板子,必然包含它下面的lowlevel.o)

    obj-y  := goni.o onenand.oobj-y  += lowlevel_init.o

    在lowlevel_init中,要实现如下:
    * 检查一些复位状态 
    * 关闭看门狗 
    * 系统时钟的初始化 
    * 内存、DDR的初始化 
    * 串口初始化(可选) 

    下面要用到读pro_id来区分产品类型,我们s5pv210的如下图

     可以看一下lowlevel_init的代码

     
    #include <config.h>
    #include <asm/arch/cpu.h>
    #include <asm/arch/clock.h>
    #include <asm/arch/power.h>

    /*
    * Register usages:
    *
    * r5 has zero always (总是0,下面会用到)
    * r7 has S5PC100 GPIO base, 0xE0300000(s5pc100的gpio基址是0xe0300000,s5pc110和s5pv210的是0xe0200000,下一句注释也说明了用r8来放gpio的base)
    * r8 has real GPIO base, 0xE0300000, 0xE0200000 at S5PC100, S5PC110 repectively
    * r9 has Mobile DDR size, 1 means 1GiB, 2 means 2GiB and so on
    */

    .globl lowlevel_init
    lowlevel_init:
    mov r11, lr /* 里面要调用函数,会覆盖lr,这里先保存 */

    /* r5 has always zero */
    mov r5, #0

    ldr r7, =S5PC100_GPIO_BASE /* 在mach下s5pc1xx的cpu.h中定义 */
    ldr r8, =S5PC100_GPIO_BASE
    /* Read CPU ID */
    ldr r2, =S5PC110_PRO_ID
    ldr r0, [r2]
    mov r1, #0x00010000
    and r0, r0, r1
    cmp r0, r5
    beq 100f
    ldr r8, =S5PC110_GPIO_BASE
    /* 可以看到上面几句的意思是如果pro_id的第16bit如果是1,则r8等于s5pc110的基址,即s5pv210的基址 */

    100:
    /* Turn on KEY_LED_ON [GPJ4(1)] XMSMWEN */
    cmp r7, r8
    beq skip_check_didle @ Support C110 only 很明显我们不相等

    /* 下面几行就是检查复位状态,钥匙从睡眠状态唤醒的,会跳过一些初始化 */
    ldr r0, =S5PC110_RST_STAT
    ldr r1, [r0]
    and r1, r1, #0x000D0000
    cmp r1, #(0x1 << 19) @ DEEPIDLE_WAKEUP
    beq didle_wakeup /* 我们这里不是睡眠唤醒 */
    cmp r7, r8

    skip_check_didle:
    addeq r0, r8, #0x280 @ S5PC100_GPIO_J4
    addne r0, r8, #0x2C0 @ S5PC110_GPIO_J4 r7 != r8 我们执行这里
    /* 配置gpj4(1) */
    ldr r1, [r0, #0x0] @ GPIO_CON_OFFSET
    bic r1, r1, #(0xf << 4) @ 1 * 4-bit
    orr r1, r1, #(0x1 << 4)
    str r1, [r0, #0x0] @ GPIO_CON_OFFSET
    /* 点亮
    ldr r1, [r0, #0x4] @ GPIO_DAT_OFFSET
    bic r1, r1, #(1 << 1)
    str r1, [r0, #0x4] @ GPIO_DAT_OFFSET
    /* Don't setup at s5pc100 */
    beq 100f /* 上一次cmp的结果,我们不相等 */

    /*
    * Initialize Async Register Setting for EVT1
    * Because we are setting EVT1 as the default value of EVT0,
    * setting EVT0 as well does not make things worse.
    * Thus, for the simplicity, we set for EVT0, too
    *
    * The "Async Registers" are:
    * 0xE0F0_0000
    * 0xE1F0_0000
    * 0xF180_0000
    * 0xF190_0000
    * 0xF1A0_0000
    * 0xF1B0_0000
    * 0xF1C0_0000
    * 0xF1D0_0000
    * 0xF1E0_0000
    * 0xF1F0_0000
    * 0xFAF0_0000
    */
    ldr r0, =0xe0f00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xe1f00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1800000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1900000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1a00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1b00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1c00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1d00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1e00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xf1f00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    ldr r0, =0xfaf00000
    ldr r1, [r0]
    bic r1, r1, #0x1
    str r1, [r0]

    /*
    * Diable ABB block to reduce sleep current at low temperature
    * Note that it's hidden register setup don't modify it 隐藏寄存器,不管
    */
    ldr r0, =0xE010C300
    ldr r1, =0x00800000
    str r1, [r0]

    100:
    /* IO retension release 没什么作用 */
    ldreq r0, =S5PC100_OTHERS @ 0xE0108200
    ldrne r0, =S5PC110_OTHERS @ 0xE010E000
    ldr r1, [r0]
    ldreq r2, =(1 << 31) @ IO_RET_REL
    ldrne r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))
    orr r1, r1, r2
    /* Do not release retention here for S5PC110 */
    streq r1, [r0]

    /* Disable Watchdog ,关看门狗 */
    ldreq r0, =S5PC100_WATCHDOG_BASE @ 0xEA200000
    ldrne r0, =S5PC110_WATCHDOG_BASE @ 0xE2700000
    str r5, [r0]

    /* setting SRAM,设置bank1的总线宽度 */
    ldreq r0, =S5PC100_SROMC_BASE
    ldrne r0, =S5PC110_SROMC_BASE
    ldr r1, =0x9
    str r1, [r0]

    /* S5PC100 has 3 groups of interrupt sources,我们s5pv210有四组interrupt的 */
    ldreq r0, =S5PC100_VIC0_BASE @ 0xE4000000
    ldrne r0, =S5PC110_VIC0_BASE @ 0xF2000000
    add r1, r0, #0x00100000
    add r2, r0, #0x00200000

    /* Disable all interrupts (VIC0, VIC1 and VIC2) */
    mvn r3, #0x0
    str r3, [r0, #0x14] @ INTENCLEAR
    str r3, [r1, #0x14] @ INTENCLEAR
    str r3, [r2, #0x14] @ INTENCLEAR

    /* Set all interrupts as IRQ */
    str r5, [r0, #0xc] @ INTSELECT
    str r5, [r1, #0xc] @ INTSELECT
    str r5, [r2, #0xc] @ INTSELECT

    /* Pending Interrupt Clear */
    str r5, [r0, #0xf00] @ INTADDRESS
    str r5, [r1, #0xf00] @ INTADDRESS
    str r5, [r2, #0xf00] @ INTADDRESS

    /* for UART ,初始化串口*/
    bl uart_asm_init

    /* */
    bl internal_ram_init

    cmp r7, r8
    /* Clear wakeup status register ,清除睡眠*/
    ldreq r0, =S5PC100_WAKEUP_STAT
    ldrne r0, =S5PC110_WAKEUP_STAT
    ldr r1, [r0]
    str r1, [r0]

    /* IO retension release */
    ldreq r0, =S5PC100_OTHERS @ 0xE0108200
    ldrne r0, =S5PC110_OTHERS @ 0xE010E000
    ldr r1, [r0]
    ldreq r2, =(1 << 31) @ IO_RET_REL
    ldrne r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))
    orr r1, r1, r2
    str r1, [r0]

    b 1f

    didle_wakeup:
    /* Wait when APLL is locked */
    ldr r0, =0xE0100100 @ S5PC110_APLL_CON
    lockloop:
    ldr r1, [r0]
    and r1, r1, #(1 << 29)
    cmp r1, #(1 << 29)
    bne lockloop

    ldr r0, =S5PC110_INFORM0
    ldr r1, [r0]
    mov pc, r1
    nop
    nop
    nop
    nop
    nop

    1:
    mov lr, r11 /* 恢复最前面保存的lr寄存器 */
    mov pc, lr

    /*
    * system_clock_init: Initialize core clock and bus clock.
    * void system_clock_init(void) 没有用到
    */
    system_clock_init:
    ldr r0, =S5PC110_CLOCK_BASE @ 0xE0100000

    /* Check S5PC100 */
    cmp r7, r8
    bne 110f
    100:
    /* Set Lock Time */
    ldr r1, =0xe10 @ Locktime : 0xe10 = 3600
    str r1, [r0, #0x000] @ S5PC100_APLL_LOCK
    str r1, [r0, #0x004] @ S5PC100_MPLL_LOCK
    str r1, [r0, #0x008] @ S5PC100_EPLL_LOCK
    str r1, [r0, #0x00C] @ S5PC100_HPLL_LOCK

    /* S5P_APLL_CON */
    ldr r1, =0x81bc0400 @ SDIV 0, PDIV 4, MDIV 444 (1333MHz)
    str r1, [r0, #0x100]
    /* S5P_MPLL_CON */
    ldr r1, =0x80590201 @ SDIV 1, PDIV 2, MDIV 89 (267MHz)
    str r1, [r0, #0x104]
    /* S5P_EPLL_CON */
    ldr r1, =0x80870303 @ SDIV 3, PDIV 3, MDIV 135 (67.5MHz)
    str r1, [r0, #0x108]
    /* S5P_HPLL_CON */
    ldr r1, =0x80600603 @ SDIV 3, PDIV 6, MDIV 96
    str r1, [r0, #0x10C]

    ldr r1, [r0, #0x300]
    ldr r2, =0x00003fff
    bic r1, r1, r2
    ldr r2, =0x00011301

    orr r1, r1, r2
    str r1, [r0, #0x300]
    ldr r1, [r0, #0x304]
    ldr r2, =0x00011110
    orr r1, r1, r2
    str r1, [r0, #0x304]
    ldr r1, =0x00000001
    str r1, [r0, #0x308]

    /* Set Source Clock */
    ldr r1, =0x00001111 @ A, M, E, HPLL Muxing
    str r1, [r0, #0x200] @ S5PC1XX_CLK_SRC0

    b 200f
    110:
    ldr r0, =0xE010C000 @ S5PC110_PWR_CFG

    /* Set OSC_FREQ value */
    ldr r1, =0xf
    str r1, [r0, #0x100] @ S5PC110_OSC_FREQ

    /* Set MTC_STABLE value */
    ldr r1, =0xffffffff
    str r1, [r0, #0x110] @ S5PC110_MTC_STABLE

    /* Set CLAMP_STABLE value */
    ldr r1, =0x3ff03ff
    str r1, [r0, #0x114] @ S5PC110_CLAMP_STABLE

    ldr r0, =S5PC110_CLOCK_BASE @ 0xE0100000

    /* Set Clock divider */
    ldr r1, =0x14131330 @ 1:1:4:4, 1:4:5
    str r1, [r0, #0x300]
    ldr r1, =0x11110111 @ UART[3210]: MMC[3210]
    str r1, [r0, #0x310]

    /* Set Lock Time */
    ldr r1, =0x2cf @ Locktime : 30us
    str r1, [r0, #0x000] @ S5PC110_APLL_LOCK
    ldr r1, =0xe10 @ Locktime : 0xe10 = 3600
    str r1, [r0, #0x008] @ S5PC110_MPLL_LOCK
    str r1, [r0, #0x010] @ S5PC110_EPLL_LOCK
    str r1, [r0, #0x020] @ S5PC110_VPLL_LOCK

    /* S5PC110_APLL_CON */
    ldr r1, =0x80C80601 @ 800MHz
    str r1, [r0, #0x100]
    /* S5PC110_MPLL_CON */
    ldr r1, =0x829B0C01 @ 667MHz
    str r1, [r0, #0x108]
    /* S5PC110_EPLL_CON */
    ldr r1, =0x80600602 @ 96MHz VSEL 0 P 6 M 96 S 2
    str r1, [r0, #0x110]
    /* S5PC110_VPLL_CON */
    ldr r1, =0x806C0603 @ 54MHz
    str r1, [r0, #0x120]

    /* Set Source Clock */
    ldr r1, =0x10001111 @ A, M, E, VPLL Muxing
    str r1, [r0, #0x200] @ S5PC1XX_CLK_SRC0

    /* OneDRAM(DMC0) clock setting */
    ldr r1, =0x01000000 @ ONEDRAM_SEL[25:24] 1 SCLKMPLL
    str r1, [r0, #0x218] @ S5PC110_CLK_SRC6
    ldr r1, =0x30000000 @ ONEDRAM_RATIO[31:28] 3 + 1
    str r1, [r0, #0x318] @ S5PC110_CLK_DIV6

    /* XCLKOUT = XUSBXTI 24MHz */
    add r2, r0, #0xE000 @ S5PC110_OTHERS
    ldr r1, [r2]
    orr r1, r1, #(0x3 << 8) @ CLKOUT[9:8] 3 XUSBXTI
    str r1, [r2]

    /* CLK_IP0 */
    ldr r1, =0x8fefeeb @ DMC[1:0] PDMA0[3] IMEM[5]
    str r1, [r0, #0x460] @ S5PC110_CLK_IP0

    /* CLK_IP1 */
    ldr r1, =0xe9fdf0f9 @ FIMD[0] USBOTG[16]
    @ NANDXL[24]
    str r1, [r0, #0x464] @ S5PC110_CLK_IP1

    /* CLK_IP2 */
    ldr r1, =0xf75f7fc @ CORESIGHT[8] MODEM[9]
    @ HOSTIF[10] HSMMC0[16]
    @ HSMMC2[18] VIC[27:24]
    str r1, [r0, #0x468] @ S5PC110_CLK_IP2

    /* CLK_IP3 */
    ldr r1, =0x8eff038c @ I2C[8:6]
    @ SYSTIMER[16] UART0[17]
    @ UART1[18] UART2[19]
    @ UART3[20] WDT[22]
    @ PWM[23] GPIO[26] SYSCON[27]
    str r1, [r0, #0x46c] @ S5PC110_CLK_IP3

    /* CLK_IP4 */
    ldr r1, =0xfffffff1 @ CHIP_ID[0] TZPC[8:5]
    str r1, [r0, #0x470] @ S5PC110_CLK_IP3

    200:
    /* wait at least 200us to stablize all clock */
    mov r2, #0x10000
    1: subs r2, r2, #1
    bne 1b

    mov pc, lr

    internal_ram_init:
    ldreq r0, =0xE3800000
    ldrne r0, =0xF1500000
    ldr r1, =0x0
    str r1, [r0]

    mov pc, lr

    /*
    * uart_asm_init: Initialize UART's pins
    */
    uart_asm_init:
    /* set GPIO to enable UART0-UART4,只初始化了uart的引脚,没初始化uart寄存器 */
    mov r0, r8
    ldr r1, =0x22222222
    str r1, [r0, #0x0] @ S5PC100_GPIO_A0_OFFSET
    ldr r1, =0x00002222
    str r1, [r0, #0x20] @ S5PC100_GPIO_A1_OFFSET

    /* Check S5PC100 */
    cmp r7, r8
    bne 110f

    /* UART_SEL GPK0[5] at S5PC100 */
    add r0, r8, #0x2A0 @ S5PC100_GPIO_K0_OFFSET
    ldr r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET
    bic r1, r1, #(0xf << 20) @ 20 = 5 * 4-bit
    orr r1, r1, #(0x1 << 20) @ Output
    str r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET

    ldr r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET
    bic r1, r1, #(0x3 << 10) @ 10 = 5 * 2-bit
    orr r1, r1, #(0x2 << 10) @ Pull-up enabled
    str r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET

    ldr r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET
    orr r1, r1, #(1 << 5) @ 5 = 5 * 1-bit
    str r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET

    b 200f
    110:
    /*
    * Note that the following address
    * 0xE020'0360 is reserved address at S5PC100
    */
    /* UART_SEL MP0_5[7] at S5PC110 */
    add r0, r8, #0x360 @ S5PC110_GPIO_MP0_5_OFFSET
    ldr r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET
    bic r1, r1, #(0xf << 28) @ 28 = 7 * 4-bit
    orr r1, r1, #(0x1 << 28) @ Output
    str r1, [r0, #0x0] @ S5PC1XX_GPIO_CON_OFFSET

    ldr r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET
    bic r1, r1, #(0x3 << 14) @ 14 = 7 * 2-bit
    orr r1, r1, #(0x2 << 14) @ Pull-up enabled
    str r1, [r0, #0x8] @ S5PC1XX_GPIO_PULL_OFFSET

    ldr r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET
    orr r1, r1, #(1 << 7) @ 7 = 7 * 1-bit
    str r1, [r0, #0x4] @ S5PC1XX_GPIO_DAT_OFFSET
    200:
    mov pc, lr

     

    在goni.h头文件定义了,text段的基地址0x34800000

    在最终生成的u-boot.map表中查看lowlevel的地址,发现在16k以内,所以不用改这里。

    在uart2的初始化的末尾添加代码,在串口发送一个字符'O'

            ldr     r1, =0xe2900820        ldr     r2, =0x4f        str     r2, [r1]

    发现串口2可以打印出'O'字符

     

    在start.S的  调用_main之前调用,下面代码,发现不能正确打印'K'

            ldr     r1, =0xe2900820        ldr     r2, =0x4b        str     r2, [r1]

    下一节开始查找问题原因

  • 相关阅读:
    c# 时间操作
    JAVA file文件操作
    HttpServletRequest 转换成MultipartHttpServletRequest
    【日常笔记】java spring 注解读取文件
    【日常笔记】mybatis 处理 in 语句的使用
    购物车小程序
    Python中的r+和a+
    markdown基本语法
    markdown箭头的处理
    markdown中如何插入公式
  • 原文地址:https://www.cnblogs.com/idyllcheung/p/11212909.html
Copyright © 2011-2022 走看看