zoukankan      html  css  js  c++  java
  • uboot第一阶段详细分析

    原文:uboot第一阶段详细分析

    作者:程老师,华清远见嵌入式学院讲师。

    uboot的第一阶段设计的非常巧妙,几乎都是用汇编语言实现的,下面我们一起来看看它的精妙之处吧!

    首先我们来看一下它的链接脚本,通过它我们可以知道它整个程序的各个段是怎么存放的。

    OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
            OUTPUT_ARCH(arm)
            ENTRY(_start)
            SECTIONS
            {
                    . = 0x00000000;

            . = ALIGN(4);
                    .text :
                    {
                            cpu/arm920t/start.o        (.text)
                            *(.text)//所有的其他程序的代码段以四字节对齐放在它后面
                    }

            . = ALIGN(4);
                    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }//只读数据段

            . = ALIGN(4);
                    .data : { *(.data) }//指定读/写数据段

            . = ALIGN(4);
                    .got : { *(.got) }//指定got段,got段式是uboot自定义的一个段,非标准段

            . = .;
                    __u_boot_cmd_start = .;//把__u_boot_cmd_start赋值为当前位置,即起始位置
                    .u_boot_cmd : { *(.u_boot_cmd) }//指定u_boot_cmd段,uboot把所有的uboot命令放在该段
                    __u_boot_cmd_end = .;//把 __u_boot_cmd_end赋值为当前位置,即结束位置

            . = ALIGN(4);
                    __bss_start = .;//__bss_start赋值为当前位置,即bss段得开始位置
                    .bss (NOLOAD) : { *(.bss) . = ALIGN(4); }
                    _end = .;//把_end赋值为当前位置,即bss段得结束地址
            }

    从它我们可以看到,uboot运行的第一个程序是cpu/arm920t/start.S,其他的都有注释,就不多说了。

    下面我们来看看在fs2410上通过nor flash启动,u-boot的启动流程:

    电源一上电之后,pc指针从0x00000000 地址开始执行,也就是说这个时候程序跑在nor flash里面(别忘记,nor flash这个时候接在0x00000000地址,它是可以执行程序的只是速度没有在ram里面执行快)

    这个时候有人可能会问那s3c2410片内的4kRam映射到哪呢?通过查看芯片手册这个时候它在0x40000000,如下图:


    (使用NOR FLASH启动,设备地址映射图)

    现在我们知道是那个程序在哪里存储,从哪个地址运行,下面我们来看看这段程序的汇编代码:

    在这里我们知道运行的第一条指令是b start_code,呵呵!看到这段代码的时候许多人都认为_start的值是0x00000000,为什么是这个地址呢? 因为连接脚本上指定了。真的是这样吗?我们来看看我们编译好之后,在u-boot目录下有个System.map,这里面有各个变量的值,如下图:

    哈哈,_start的值怎么会是0x33f80000?这是因为在顶层的Makefile里面我们指定了它的连接地址。

    看到那个 -o u-boot了吗,就是通过它生成ELF格式的u-boot的,里面有个LDFLAGS变量,它是什么呢,我们继续往下面看:

    (顶层的config.mk里面有这个变量的说明)

    看到了没有,LDFLAGS里面除了指定链接脚本,如果TEXT_BASE不等于空,还加上了-Ttext$(TEXT_BASE),TEXT_BASE的值是多少呢?我们可以在board/samsung/smdk2410/config.mk里面有定义,它的值为0x33f80000。这样我就可以知道为什么System.map的地址都是0x33f80000。

    好我们来看第一条汇编指令b start_code,从System.map文件我们可以知道,这条指令相当于b 0x33f80050。"0x33f80050"?你是否有疑问,这个时候内存还没有初始化呢,怎么能跳到内存中去了(sdram的起始地址0x30000000)。呵呵,其实不是这样的。还记得b指令是相对跳转指令吗,它和代码的位置是无关的,这种精妙的设计才使得后面的指令能继续的执行。

    下面我们继续来看它的汇编指令:

    呵呵,这段汇编代码很好理解,就是设置CPU为 管理模式。

    这段汇编代码就不分析了,这是跟atmel相关的,我不管它,继续下面:

    这段汇编代码也很好理解,就是关掉看门狗,然后关掉所有中断。

    哦哦,设置时钟,还记得一上电FCLK是多少吗,只有12MHZ。

    呵呵!跳转指令,我们来看看它做了什么,这样我们先从名字上来猜猜它是什么意思?cpu初始化,初始化什么呢?继续向下看:

    呵呵,有英文注释,清cache,关闭MMU。都是用协处理指令实现的,如果看不懂,可以看看协处理器指令。多了解一点就多知道一点,不是吗?

    从上面可以看到,还有一次跳转bl lowlevel_init。这里面有干了一些什么呢,我们可以到board/samsung/smdk2410/ lowlevel_init.S去看。呵呵,这里我就不截图了,其实我们只有知道,它在这里面干了初始化内存操作。

    继续往下面看:

    呵呵,终于到重点部分了,代码重定向。下面我们来看看它到底是怎么重定向的:

    Adr r0,_start

    这条汇编指令的意思就是把_start当前代码存储的地址赋给r0,假如这段代码存储在SDRAM里面,那么r0的值就是0x30000000。现在这段代码存储在NOR Flash里面,所以r0的值就是

    0x0000000
            Ldr r1,_TEXT_BASE

    这条汇编指令的意思是把_TEXT_BASE的值作为地址,把这个地址的内容赋给r1,从下面可以知道:

    _TEXT_BASE里面存储的内容是TEXT_BASE,也就是0x33f80000,所以r1的值就是0x33f80000

    Cmp r0,r1

    将r0和r1做比较,此时r0 = 0x0000000,r1 = 0x33f80000,显然不相等,那么执行的就是下面的汇编指令:

    ldr r2, _armboot_start

    由此可以知道r2的值是_start,也就是0x33f80000,也是整个代码的起始地址。

    Ldr r3, _bss_start

    由u-boot.lds的链接脚本可以知道,r3的值是整个代码得结尾.

    Sub r2,r3,r2

    这条指令的意思是r2 = r3 -r2,即r2 = 代码结束 - 代码开始,这样得到的是r2 = 代码的大小。

    Add r2,r0,r2

    这条指令的意思是r2 = r0 + r3,即 r2 = 代码开始 + 代码大小,这样得到的是r2 = nor falsh 里面代码的结尾

    此时我们得到r0 = nor flash 代码的起始位置,r1 = 0x33f80000(sdram :0x300000000 ~ 0x34000000)

    呵呵,这个时候代码就被从nor flash里面拷贝到sdram里面了。

    这段代码的意思是设置一些堆栈

    这段代码的意思是清bss段,

    呵呵,终于看到pc指针的值被改变了。也就是这个时候,pc指针开始跳到sdram里面执行代码,这也就到了第二阶段(从语言阶段),后面的代码都是用C语言写得了。先分析到这里,下次我们看第二阶段。

  • 相关阅读:
    mybatis3.0-[topic10-14] -全局配置文件_plugins插件简介/ typeHandlers_类型处理器简介 /enviroments_运行环境 /多数据库支持/mappers_sql映射注册
    _MyBatis3-topic06.07.08.09_ 全局配置文件_引入dtd约束(xml提示)/ 引入properties引用/ 配置驼峰命名自动匹配 /typeAliases起别名.批量起别名
    MyBatis3-topic04,05 -接口式编程
    JDBC终章- 使用 DBUtils实现增删查改- C3P0Utils数据源/QueryRunner runner连接数据源并执行sql
    [课本10.1.4]JDBC数据库连接池- C3P0数据源--通过构造方法创建数据源对象--通过配置文件创建数据源对象[推荐]
    JDBC课程5--利用反射及JDBC元数据(ResultSetMetaData)编写通用的查询方法
    JDBC课程4--使用PreparedStatement进行增删查改--封装进JDBCTools的功能中;模拟SQL注入 ; sql的date()传入参数值格式!
    本周进度总结
    本周进度总结
    大道至简读后感
  • 原文地址:https://www.cnblogs.com/ganrui/p/3738082.html
Copyright © 2011-2022 走看看