zoukankan      html  css  js  c++  java
  • S5PV210的启动过程

    初步认识IROM和IRAM

    S5PV210含有一个内64K的IROM和96K的IRAM,系统启动时主要依靠它们,IROM和IRAM所处的存储空间见下图:

    image

    S5PV210有IROM,且只能从IROM启动,不再支持原来的直接从外部介质启动方式。
    IROM代码(BL0)运行完毕后,根据OM[5:0]确定外部启动介质(BL1和BL2)完成启动。S5PV210支持的外部启动介质包括:NAND Flash、OneNAND、SD/MMC、eMMC、eSSD、UART/USB。

    完整的启动序列
    系统刚启动时,会运行IROM中的固化代码,进行一些通用的初始化,具体步骤包括:
    第一步 关闭看门狗;
    第二步 初始化icache;
    第三步 初始化堆栈;
    第四步 设置时钟;
    第五步 判断启动设备(nand/sd/onenand等),检查校验和,然后从启动设备中拷贝前16K的代码到IRAM的0xD0020000处;
    第六步 若是安全模式启动,则进行完整性检查;
    第七步 跳转到IRAM的0xD0020010地址上继续运行;

    UART /USB启动模式
    OM[5:4] = 0b10即可选择UART/USB启动模式此时IROM代码运行完毕后,会先尝试从UART 启动,若失败则会尝试从USB启动。若失败则会根据OM[3:0]选择相应的启动介质再次尝试启动。
    UART启动时,必须在S5PV210上电前将串口连接好,上位机使用dnw工具来发送启动代码可执行文件。本教材中使用USB启动方式作为调试,因此不详细探讨UART启动方式。
    1、USB启动方式必须借助dnw工具,教材中使用dnw v0.60c。
    2、打开dnw软件,将dnw中USB下载地址设置为0xd0020010。
    3、复位开发板。
    4、若是初次使用则Windows会弹出发现新硬件图标,索引安装开发板dnw USB驱动即可。若已经安装驱动,则dnw会显示USB:OK,表示USB连接已经成功。
    5、dnw菜单中USB Port->Transmit,选择编译好的bin文件即可。USB download完成后S5PV210会即刻跳转到0xd0020010处执行。

    1、// 关闭看门狗
    ldr    r0, =0xE2700000
    mov    r1, #0
    str    r1, [r0]

    2、控制icache
    // 打开icache可提高运行速度
    #ifdef CONFIG_SYS_ICACHE_OFF
    // clear bit 12 (I) I-cache 
        bic     r0, r0, #0x00001000
    #else 
    // set bit 12 (I) I-cache  
        orr     r0, r0, #0x00001000
    #endif
        mcr     p15, 0, r0, c1, c0, 0

    3、//设置栈
    栈的整体作用
    1) 保存现场;
    2) 传递参数:汇编代码调用C函数时,需传递参数;
    3) 保存临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量;

    4、重定位代码到IRAM+0x4000
    重定位:对于程序而言,我们需要理解两个概念,一是程序当前所处的地址,即程序在运行时,所处的当前地址;二是程序的链接地址,即程序运行时应该位于的运行地址。编译程序时,可以指定程序的链接地址。
    对于S5PV210而言,启动时只会从NAND Flash/sd等启动设备中拷贝前16K的代码到IRAM中,那么当我们的程序超过16K怎么办?那就需要我们在前16K的代码中将整个程序完完整整地拷贝到DRAM等其他更大存储空间,然后再跳转到DRAM中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。本章中我们主要学习如何重定位,但是并不会涉如何使用到DRAM,而是简单地将代码从IRAM的0xD0020010处拷贝到IRAM的0xD0024000处,然后跳转到0xD0024000处继续运行我们的代码。
    链接脚本:链接脚本就是程序链接时的参考文件,其主要目的是描述如何把输入文件中的段(SECTION)映射到输出文件中,并控制输出文件的存储布局。链接脚本的基本命令式SECTIONS命令,一个SECTIONS命令内部包含一个或多个段,段(SECTION)是链接脚本的基本单元,它表示输入文件中的某个段是如何放置的。
    链接脚本的标准格式如下:
    SECTIONS
    {
         sections-command
         sections-command
    }
    /*link.lds*/
    SECTIONS
    {
        . = 0xD0024000;
        .text : {
            start.o
            * (.text)
        }   
        .data : {
            * (.data)
        }
        bss_start = .;
        .bss : {
            * (.bss)
        }
        bss_end  = .;   
    }
    1) 在链接脚本中,单独的点号(.)代表了当前位置,. = 0xD0024000; 表示程序的链接地址是0xD0024000;
    2) link.lds中的.text 、 .data 、 .bss分别是text段、data段、bss段的段名(这些段名并不是固定的,是可以随便起的)。.text段包含的内容是start.o和其余代码中所有的text段;.data段包含的内容是代码中所有的data段;.bss段包含的内容是代码中所有的bss段。
    3) bss_start和bss_end保存的是bss段的起始地址和结束地址,在start.S中会被用到。

    data、text、bss段:
    1) data段:数据段(datasegment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。
    2) text段:代码段通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
    3) bss段:指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStarted by Symbol的简称。当我们的程序有全局变量是,它是放在bss段的,由于全局变量默认初始值都是0,所有我们需要手动清bss段。
    /*start.S*/
    .global _start
    _start: 
        // 关闭看门狗  
        ldr    r0, =0xE2700000              
        mov    r1, #0  
        str    r1, [r0]  
        // 设置栈,以便调用c函数  
        ldr    sp, =0xD0037D80   
        // 重定位                           
        // _start当前所位于的地址:0xd0022000  
        adr r0, _start            
        // _start的链接地址:0xd0024000 
        ldr r1, =_start      
        // bss段的起始地址 
        ldr r2, =bss_start  
        cmp r0, r1
        beq clean_bss
    copy_loop:  
        ldr r3, [r0], #4    // 源  
        str r3, [r1], #4    // 目的  
        cmp r1, r2  
        bne copy_loop  
    // 清bss段
    clean_bss:   
        ldr r0, =bss_start                      
        ldr r1, =bss_end  
        cmp r0, r1  
        beq run_on_dram  
        mov r2, #0
        clear_loop:  
        str r2, [r0], #4  
        cmp r0, r1  
        bne clear_loop 
    // 跳转
    run_on_dram:               
        ldr pc, =main

    /*main.c*/
    #define     GPJ2CON     (*(volatile unsigned long *) 0xE0200280)
    #define     GPJ2DAT        (*(volatile unsigned long *) 0xE0200284)
    // 延时函数
    void delay(unsigned long count)
    {
        volatile unsigned long i = count;
        while (i--);       
    }
    void main()               
    //LED 闪烁
    {
        GPJ2CON = 0x00001111;
        // 配置引脚
        while(1)                   
        // 闪烁
        {
            GPJ2DAT = 0;
            // LED on
            delay(0x100000);
            GPJ2DAT = 0xf;
            // LED off
            delay(0x100000);
        }
    }

    5、重定位代码到DRAM
    DRAM0对应的地址是0x2000_0000~0x3FFF_FFF共512M,DRAM1对应的地址是0x4000_000~0x7FFF_FFFF共1G。

    代码下载链接:http://download.csdn.net/detail/klcf0220/5508253

    喜欢开源,乐意分享的大神们,欢迎加入QQ群:176507146,你值的拥有哦!

    作者:快乐出发0220 ;Android群:151319601 ; Linux群:96394158 ;转载请注明出处 http://klcf0220.cnblogs.com/ !!!
  • 相关阅读:
    Linux报错排解
    linux中wget 、apt-get、yum rpm区别
    Java NIO系列教程
    Java NIO系列教程(七) FileChannel
    使用一条sql查询多个表中的记录数
    ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
    java.security.NoSuchAlgorithmException: SHA1PRNG SecureRandom not available
    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
    Oracle查询锁表和解锁
    Data source rejected establishment of connection, message from server: "Too many connections"
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3113695.html
Copyright © 2011-2022 走看看