• U-boot(三):start.S


            本文主要探讨x210的uboot的start.S文件,也是uboot启动的第一阶段。

    头文件

            config.h
                    config.h == x210_sd.h,由mkconfig脚本生成,包含了开发板的配置宏 

    1. root@kaxi-virtual-machine:~/qt_x210v3s_160307/uboot/include# cat config.h
    2. /* Automatically generated - do not edit */
    3. #include <configs/x210_sd.h>


            version.h

    1. #ifndef __VERSION_H__
    2. #define __VERSION_H__
    3. #ifndef DO_DEPS_ONLY
    4. #include "version_autogenerated.h"
    5. #endif
    6. #endif  /* __VERSION_H__ */

    1. root@kaxi-virtual-machine:~/qt_x210v3s_160307/uboot/include# cat version_autogenerated.h 
    2. #define U_BOOT_VERSION "U-Boot 1.3.4"

            定义uboot版本号,uboot启动时打印的版本信息


            asm/proc/domain.h
                    asm/proc/domain.h == include/asm-arm/proc-armv/domain.h

            regs.h
                    regs.h == s5pc110.h

    16字节头

    1. #if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
    2.     .word 0x2000
    3.     .word 0x0
    4.     .word 0x0
    5.     .word 0x0
    6. #endif

            定义16字节头,用于存放校验信息

    异常向量表构建

    1. .globl _start
    2. _start: b    reset
    3.     ldr    pc, _undefined_instruction
    4.     ldr    pc, _software_interrupt
    5.     ldr    pc, _prefetch_abort
    6.     ldr    pc, _data_abort
    7.     ldr    pc, _not_used
    8.     ldr    pc, _irq
    9.     ldr    pc, _fiq
    10. _undefined_instruction:
    11.     .word undefined_instruction
    12. _software_interrupt:
    13.     .word software_interrupt
    14. _prefetch_abort:
    15.     .word prefetch_abort
    16. _data_abort:
    17.     .word data_abort
    18. _not_used:
    19.     .word not_used
    20. _irq:
    21.     .word irq
    22. _fiq:
    23.     .word fiq
    24. _pad:
    25.     .word 0x12345678 /* now 16*4=64 */
    1. /*
    2.  * the actual reset code
    3.  */
    4. reset:
    5.     /*
    6.      * set the cpu to SVC32 mode and IRQ & FIQ disable
    7.      */
    8.     @;mrs    r0,cpsr
    9.     @;bic    r0,r0,#0x1f
    10.     @;orr    r0,r0,#0xd3
    11.     @;msr    cpsr,r0
    12.     msr    cpsr_c, #0xd3        @ I & F disable, Mode: 0x13 - SVC

            将CPU设置为禁止FIQ和IRQ,置于ARM状态设置SVC模式
            CPU复位默认进入SVC模式,uboot工作于SVC模式

            .balignl 16,0xdeadbeef.    对齐访问效率快,是硬件要求

    TEXT_BASE

    1. _TEXT_BASE:
    2.     .word    TEXT_BASE
    1. root@kaxi-virtual-machine:~/qt_x210v3s_160307/uboot/board/samsung/x210# cat config.mk 
    2. TEXT_BASE = 0xc3e00000
    1. x210_nand_config :      unconfig
    2.         @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
    3.         @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk


            定义uboot链接地址(0xc3e00000)
            make x210_sd_config(调用mkconfig脚本)  ==>  uboot/board/samsung/x210/config.mk


    CFG_PHY_UBOOT_BASE

    1. _TEXT_PHY_BASE:
    2.     .word    CFG_PHY_UBOOT_BASE

            CFG_PHY_UBOOT_BASE为0x33e0000是uboot在DDR中的物理地址


    cpu_init_crit(设置L2、L1cache、MMU)
        bl    disable_l2cache                // 禁止L2 cache
        bl    set_l2cache_auxctrl_cycle    // l2 cache相关初始化
        bl    enable_l2cache                // 使能l2 cache
        刷新L1 cache、icache、dcache。
        关闭MMU

    1. cpu_init_crit:
    2.     
    3.     bl    disable_l2cache
    4.     bl    set_l2cache_auxctrl_cycle
    5.     bl    enable_l2cache
    6.     
    7.        /*
    8.         * Invalidate L1 I/D
    9.         */
    10.         mov    r0, #0                  @ set up for MCR
    11.         mcr    p15, 0, r0, c8, c7, 0   @ invalidate TLBs
    12.         mcr    p15, 0, r0, c7, c5, 0   @ invalidate icache
    13.        /*
    14.         * disable MMU stuff and caches
    15.         */
    16.         mrc    p15, 0, r0, c1, c0, 0
    17.         bic    r0, r0, #0x00002000     @ clear bits 13 (--V-)
    18.         bic    r0, r0, #0x00000007     @ clear bits 2:0 (-CAM)
    19.         orr    r0, r0, #0x00000002     @ set bit 1 (--A-) Align
    20.         orr    r0, r0, #0x00000800     @ set bit 12 (Z---) BTB
    21.         mcr     p15, 0, r0, c1, c0, 0

    启动介质选择

    1. /* Read booting information */
    2.         ldr    r0, =PRO_ID_BASE
    3.         ldr    r1, [r0,#OMR_OFFSET]
    4.         bic    r2, r1, #0xffffffc1
    5. /* NAND BOOT */
    6.     cmp    r2, #0x0        @ 512B 4-cycle
    7.     moveq    r3, #BOOT_NAND
    8.     cmp    r2, #0x2        @ 2KB 5-cycle
    9.     moveq    r3, #BOOT_NAND
    10.     cmp    r2, #0x4        @ 4KB 5-cycle    8-bit ECC
    11.     moveq    r3, #BOOT_NAND
    12.     cmp    r2, #0x6        @ 4KB 5-cycle    16-bit ECC
    13.     moveq    r3, #BOOT_NAND
    14.     cmp    r2, #0x8        @ OneNAND Mux
    15.     moveq    r3, #BOOT_ONENAND
    16.     /* SD/MMC BOOT */
    17.     cmp     r2, #0xc
    18.     moveq   r3, #BOOT_MMCSD    
    19.     /* NOR BOOT */
    20.     cmp     r2, #0x14
    21.     moveq   r3, #BOOT_NOR    
    22.     /* Uart BOOTONG failed */
    23.     cmp     r2, #(0x1<<4)
    24.     moveq   r3, #BOOT_SEC_DEV
    25.     ldr    r0, =INF_REG_BASE
    26.     str    r3, [r0, #INF_REG3_OFFSET]

            寄存器(0xE0000004)存储OM引脚接法,用于判断启动介质是Nand还是SD等


    设置栈(SRAM栈)并调用lowlevel_init

    1. /*
    2.      * Go setup Memory and board specific bits prior to relocation.
    3.      */
    4.     ldr    sp, =0xd0036000 /* end of sram dedicated to u-boot */
    5.     sub    sp, sp, #12    /* set stack */
    6.     mov    fp, #0
    7.     
    8.     bl    lowlevel_init    /* go setup pll,mux,memory */

            设置栈(0xd0036000,第一次),当前代码在SRAM运行,DDR未初始化


    lowlevel_init.S
            
    uboot/board/samsumg/x210/lowlevel_init.S

    push    {lr}


                    由于lowlevel_init.S还调用了其他函数,防止之前的lr被覆盖(bl    lowlevel_init处的地址),需先入栈

            检查复位状态

    1. /* check reset status  */
    2.     
    3.     ldr    r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
    4.     ldr    r1, [r0]
    5.     bic    r1, r1, #0xfff6ffff
    6.     cmp    r1, #0x10000
    7.     beq    wakeup_reset_pre
    8.     cmp    r1, #0x80000
    9.     beq    wakeup_reset_from_didle

                    CPU允许复位情况:冷上电、热启动、睡眠唤醒等
                    依据复位状态初始化DDR:冷上电DDR需初始化,热启动或低功耗不需要

            IO状态恢复

    1. /* IO Retention release */
    2.     ldr    r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)
    3.     ldr    r1, [r0]
    4.     ldr    r2, =IO_RET_REL
    5.     orr    r1, r1, r2
    6.     str    r1, [r0]

            关看门狗

    1. /* Disable Watchdog */
    2.     ldr    r0, =ELFIN_WATCHDOG_BASE    /* 0xE2700000 */
    3.     mov    r1, #0
    4.     str    r1, [r0]

            SRAM,SROM的GPIO设置

    1. /* SRAM(2MB) init for SMDKC110 */
    2.     /* GPJ1 SROM_ADDR_16to21 */
    3.     ldr    r0, =ELFIN_GPIO_BASE
    4.     
    5.     ldr    r1, [r0, #GPJ1CON_OFFSET]
    6.     bic    r1, r1, #0xFFFFFF
    7.     ldr    r2, =0x444444
    8.     orr    r1, r1, r2
    9.     str    r1, [r0, #GPJ1CON_OFFSET]
    10.     ldr    r1, [r0, #GPJ1PUD_OFFSET]
    11.     ldr    r2, =0x3ff
    12.     bic    r1, r1, r2
    13.     str    r1, [r0, #GPJ1PUD_OFFSET]
    14.     /* GPJ4 SROM_ADDR_16to21 */
    15.     ldr    r1, [r0, #GPJ4CON_OFFSET]
    16.     bic    r1, r1, #(0xf<<16)
    17.     ldr    r2, =(0x4<<16)
    18.     orr    r1, r1, r2
    19.     str    r1, [r0, #GPJ4CON_OFFSET]
    20.     ldr    r1, [r0, #GPJ4PUD_OFFSET]
    21.     ldr    r2, =(0x3<<8)
    22.     bic    r1, r1, r2
    23.     str    r1, [r0, #GPJ4PUD_OFFSET]
    24.     /* CS0 - 16bit sram, enable nBE, Byte base address */
    25.     ldr    r0, =ELFIN_SROM_BASE    /* 0xE8000000 */
    26.     mov    r1, #0x1
    27.     str    r1, [r0]

            供电锁存

    1. /* PS_HOLD pin(GPH0_0) set to high */
    2.     ldr    r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
    3.     ldr    r1, [r0]
    4.     orr    r1, r1, #0x300    
    5.     orr    r1, r1, #0x1    
    6.     str    r1, [r0]

            判断执行代码位置

    1. /* when we already run in ram, we don't need to relocate U-Boot.
    2.      * and actually, memory controller must be configured before U-Boot
    3.      * is running in ram.
    4.      */
    5.     ldr    r0, =0xff000fff
    6.     bic    r1, pc, r0        /* r0 <- current base addr of code */
    7.     ldr    r2, _TEXT_BASE        /* r1 <- original base addr in ram */
    8.     bic    r2, r2, r0        /* r0 <- current base addr of code */
    9.     cmp     r1, r2                  /* compare r0, r1                  */
    10.     beq     1f            /* r0 == r1 then skip sdram init   */

                    对比运行地址和链接地址来判断在SRAM中(不相等)还是DDR中(相等),从而决定是否要时钟和DDR初始化


            system_clock_init,x210_sd.h有时钟相关配置值
            mem_ctrl_asm_init(uboot/cpu/s5pc11x/s5pc110/cpu_init.S)初始化DDR
            uboot中DMC0的256MB内存地址范围为0x30000000-0x3FFFFFFF
            uboot物理地址范围为:0x30000000-0x4FFFFFFF共512MB,30000000-3FFFFFFF为DMC0,40000000-4FFFFFFF为DMC1
            uart_asm_init初始化串口,发送'O',
            tzpc_init,trust zone初始化
            通过串口打印'K'


    设置栈(33E00000,DDR栈,二次)和重定位

    1. /* get ready to call C functions */
    2.     ldr    sp, _TEXT_PHY_BASE    /* setup temp stack pointer */
    3.     sub    sp, sp, #12
    4.     mov    fp, #0            /* no previous frame, so fp=0 */
    5.     /* when we already run in ram, we don't need to relocate U-Boot.
    6.      * and actually, memory controller must be configured before U-Boot
    7.      * is running in ram.
    8.      */
    9.     ldr    r0, =0xff000fff
    10.     bic    r1, pc, r0        /* r0 <- current base addr of code */
    11.     ldr    r2, _TEXT_BASE        /* r1 <- original base addr in ram */
    12.     bic    r2, r2, r0        /* r0 <- current base addr of code */
    13.     cmp     r1, r2                  /* compare r0, r1                  */
    14.     beq     after_copy        /* r0 == r1 then skip flash copy   */
    15. #if defined(CONFIG_EVT1)
    16.     /* If BL1 was copied from SD/MMC CH2 */
    17.     ldr    r0, =0xD0037488
    18.     ldr    r1, [r0]
    19.     ldr    r2, =0xEB200000
    20.     cmp    r1, r2
    21.     beq     mmcsd_boot
    22. #endif
    23.     ldr    r0, =INF_REG_BASE
    24.     ldr    r1, [r0, #INF_REG3_OFFSET]
    25.     cmp    r1, #BOOT_NAND        /* 0x0 => boot device is nand */
    26.     beq    nand_boot
    27.     cmp    r1, #BOOT_ONENAND    /* 0x1 => boot device is onenand */
    28.     beq    onenand_boot
    29.     cmp     r1, #BOOT_MMCSD
    30.     beq     mmcsd_boot
    31.     cmp     r1, #BOOT_NOR
    32.     beq     nor_boot
    33.     cmp     r1, #BOOT_SEC_DEV
    34.     beq     mmcsd_boot
    35. nand_boot:
    36.     mov    r0, #0x1000
    37.     bl    copy_from_nand
    38.     b    after_copy
    39. onenand_boot:
    40.     bl    onenand_bl2_copy
    41.     b    after_copy
    42. mmcsd_boot:
    43. #if DELETE
    44.     ldr     sp, _TEXT_PHY_BASE      
    45.     sub     sp, sp, #12
    46.     mov     fp, #0
    47. #endif
    48.     bl      movi_bl2_copy
    49.     b       after_copy
    50. nor_boot:
    51.     bl      read_hword
    52.     b       after_copy

            冷启动uboot的16kb从SD卡加载到SRAM中运行,要加载第二部分(SD卡)到DDR中(33e00000)
            D0037488内存地址(SRAM)是硬件设置,根据SD启动的通道修改值,EB000000为SD1启动,EB200000为SD2启动
            start.S的260确定MMCSD启动,278将BOOT_MMCSD写入INF_REG3寄存器,322读去并和和BOOT_MMCSD对比确定从MMCSD启动,跳转到mmcsd_boot
            uboot/cpu/s5pc11x/movi.c中调用movi_bl2_copy函数完成重定位

    1. copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
    2.             CFG_PHY_UBOOT_BASE, 0);

                    2表示通道2
                    MOVI_BL2_POS第二部分在SD卡中的开始扇区,和烧录uboot烧录位置相同
                    MOVI_BL2_BLKCNT是uboot长度占用的扇区数
                    CFG_PHY_UBOOT_BASE是重定位将第二部分复制到DDR中的起始地址(33E00000)

    虚拟地址映射

    1. after_copy:
    2. #if defined(CONFIG_ENABLE_MMU)
    3. enable_mmu:
    4.     /* enable domain access */
    5.     ldr    r5, =0x0000ffff
    6.     mcr    p15, 0, r5, c3, c0, 0        @load domain access register
    7.     /* Set the TTB register */
    8.     ldr    r0, _mmu_table_base
    9.     ldr    r1, =CFG_PHY_UBOOT_BASE
    10.     ldr    r2, =0xfff00000
    11.     bic    r0, r0, r2
    12.     orr    r1, r0, r1
    13.     mcr    p15, 0, r1, c2, c0, 0
    14.     /* Enable the MMU */
    15. mmu_on:
    16.     mrc    p15, 0, r0, c1, c0, 0
    17.     orr    r0, r0, #1
    18.     mcr    p15, 0, r0, c1, c0, 0
    19.     nop
    20.     nop
    21.     nop
    22.     nop
    23. #endif

            MMU实现虚拟地址到物理地址映射,在CP15协处理器中进行控制
            cp15的c3寄存器是使能域访问,及控制访问权限
            cp15的c2寄存器是设置TTB(转换表基地址)
            转换表是虚拟地址映射的关键包含表索引和表项,表索引对应虚拟地址,表项对应物理地址,表索引和表项构成转换表单元,可对内存块进行虚拟地址转换(ARM中包含3种块大小:细表1KB、粗表4KB、段1MB),转换表由转换表单元构成,每个单元对应1个内存块,整体对应整个内存空间(0-4G)的映射
            转换表在内存中,将基地址TTB设置到cp15的c2寄存器中,MMU工作时自动调用
            cp15的c1寄存器使能MMU单元

    再次设置栈(三次,DDR)

    1. skip_hw_init:
    2.     /* Set up the stack                            */
    3. stack_setup:
    4. #if defined(CONFIG_MEMORY_UPPER_CODE)
    5.     ldr    sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
    6. #else
    7.     ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot   */
    8.     sub    r0, r0, #CFG_MALLOC_LEN    /* malloc area                      */
    9.     sub    r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
    10. #if defined(CONFIG_USE_IRQ)
    11.     sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
    12. #endif
    13.     sub    sp, r0, #12        /* leave 3 words for abort-stack    */
    14. #endif

            栈设置在uboot起始地址上方2MB处,安全栈空间是:2MB减去uboot大小

    清理bss

    1. clear_bss:
    2.     ldr    r0, _bss_start        /* find start of bss segment        */
    3.     ldr    r1, _bss_end        /* stop here                        */
    4.     mov     r2, #0x00000000        /* clear                            */
    5. clbss_l:
    6.     str    r2, [r0]        /* clear loop...                    */
    7.     add    r0, r0, #4
    8.     cmp    r0, r1
    9.     ble    clbss_l

    执行二阶段代码

    1. ldr    pc, _start_armboot
    2. _start_armboot:
    3.     .word start_armboot
    4. #if defined(CONFIG_ENABLE_MMU)
    5. _mmu_table_base:
    6.     .word mmu_table
    7. #endif

            start_armboot在uboot/lib_arm/board.c

    uboot一阶段
           
    构建异常向量表,启动介质选择,设置CPU为SVC模式,关看门狗,开发板供电置锁,时钟初始化,DDR初始化,串口初始化并打印"OK",重定位,建立映射表并开启MMU,清理bss,跳转到第二阶段

  • 相关阅读:
    Jenkins 10 问 10 答,你想知道都在这
    [附源码]计算机毕业设计springboot农村人居环境治理监管系统
    linux系统nginx常用命令
    【Linux】 grep命令使用
    高并发场景下更新数据库报错,记录一次 MySQL 死锁问题的解决
    基于JSP+MySQL+HTML5的旅游网站系统
    cmmi3认证需要企业具备什么条件?
    基于javaweb的电影院管理系统
    DiFi: A Go-as-You-Pay Wi-Fi Access System 精读笔记(三)
    Java拆装箱
  • 原文地址:https://blog.csdn.net/tyro_wzp/article/details/134519789