17.U-boot的工作流程分析-6410

发布者:电子设计艺术家最新更新时间:2024-10-30 关键字:U-boot  工作流程 手机看文章 扫描二维码
随时随地手机看文章

6410开发板:

1.uboot的入口:

要看uboot工程的入口,首先打开顶层目录的Makefile:

Uboot所支持的开发板,在顶层的Makefile中都会有一个配置选项。比如6410,在Makefile中的配置选项是make forlinx_nand_ram256_config:在vim的命令模式按下/,然后输入make forlinx_nand_ram256_config回车会定位到这里:

这是Makefile里的一个目标。这是来配置6410开发板的。看到上图第二行的smdk6410,这个参数决定了开发板的名称。这个名称是有作用的。接下来看看他的作用。

首先是找一下目录:

可以看到这里有很多smdk的子目录,也包括smdk6410,这两个是对应的。该目录存放的就是6410开发板相关的文件。里面有一个叫uboot.lds的文件,前面知道lds文件是连接器脚本。Uboot的整个过程的链接,是通过该脚本来链接控制的。打开该链接器脚本:

OUTPUT_FORMAT('elf32-littlearm', 'elf32-littlearm', 'elf32-littlearm')

/*OUTPUT_FORMAT('elf32-arm', 'elf32-arm', 'elf32-arm')*/

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

    . = 0x00000000;

 

    . = ALIGN(4);

    .text :

    {

     cpu/s3c64xx/start.o    (.text) //1可以看到位于代码段前端的文件是start.o,对应的是一个汇编文件。这个汇编文件会最先被运行。但是这个汇编代码里最先执行的代码是哪些呢?

 

     cpu/s3c64xx/s3c6410/cpu_init.o    (.text)

     cpu/s3c64xx/onenand_cp.o    (.text)

     cpu/s3c64xx/nand_cp.o    (.text)

     cpu/s3c64xx/movi.o (.text)

     *(.text)

     lib_arm/div0.o

    }

 

    . = ALIGN(4);

    .rodata : { *(.rodata) }

 

    . = ALIGN(4);

    .data : { *(.data) }

 

    . = ALIGN(4);

    .got : { *(.got) }

 

    __u_boot_cmd_start = .;

    .u_boot_cmd : { *(.u_boot_cmd) }

    __u_boot_cmd_end = .;

 

    . = ALIGN(4);

    .mmudata : { *(.mmudata) }

 

    . = ALIGN(4);

    __bss_start = .;

    .bss : { *(.bss) }

    _end = .;

}

 

首先是找到该文件:

上面u-boot-lds文件里,在sections的标识之上,有一行:ENTRY(_start)是整个程序的入口。所以就找找start.S文件里有没_start这个标识呢?一搜会马上看到该标号:

到这里,看到这个_start才是整个uboot工程的入口。

 

接下来是第一阶段的代码:

在Linux里,打开上一节创建好的,Source Insight里的uboot工程:

然后找到smdk6410的start.S:

接下来看uboot做了什么事,主要是通过注释来分析:

开发板一上电,它会跳转到start.S的中断向量表的开始处执行:

从它的注释:

 

所以1,:知道上电后是跳到中断向量表来执行。执行的第一条指令是b reset。

Start_code的实在start.S的下面定义的:

从注释知道,这是actual start code。进入之后,set the cpu to svc32 mode,设置cpu为SVC模式。

接着执行的代码是:

3.刷新I/D caches。

4.然后是关闭MMU和cache:

5.对外围的基地址进行初始化。

6.接着到了bl lowlevel_init

点击:,然后在Symbol里输入:lowlevel_init:

会看到出现很多,然后在下面可以看到它们各自的目录。其实每一个开发板都对应一个lowlevel_init.S:

进入该文件:

7看到系统进入该文件做的第一件事是:led初始化:

上面是点亮led,是用来帮助调试程序。

8.接着是关闭开门狗的操作:

我们想到在2440里没有关闭看门狗,是不是忘记了呢?看看2440代码:

可以看到2440里的lowlevel_init.S的lowlevel_init标识有一个初始化系统时钟的:bl system_clock_init函数。进入该函数:

可以看到2440是在初始化系统时钟里关闭看门狗。

9.接着还有屏蔽中断的操作:

10.到这才初始化系统时钟:

11.接着初始化串口:

12.对nand进行简单初始化:

13.初始化内存:

初始完内存之后就返回start.S里:

返回:

14.跳转回来之后,由于我们选择的是NandFlash启动,所以是跳转到:

在2440里,是复制NandFlash里的内容到内存当中去。6410也是一样的:

Bl copy_from_nand。

15.接着不管MMU的使能操作:

我们看stack栈的初始化:

16.清除bss段:

 

最后同样是跳转到start_armboot:

我们在2440里讲过,start_armboot的代码,两个板子是同一个文件来的。所以6410的第二阶段与2440的一样的。只有board.c里面有。

验证看看是不是一样的:

 

三:

执行完上面,程序跳转到_start_armboot处执行:

上面的代码,通过伪指令ldr把_start_armboot的值装入pc指针,程序就会跳转到_start_armboot处执行。而此处的地址是start_armboot的地址。就是,程序会跳转到start_armboot函数处执行。就是把我们的pc指针跳转到内存去执行了。

下面看看start_armboot的地址是不是在内存中。

配置uboot:make forlinx_nand_ram256_config,然后执行make。

然后看到生成的文件:

 

其中,u-boot是elf文件,u-boot.bin是二进制文件。

接下来对u-boot的elf文件,进行反汇编,看看start_armboot函数的地址:

arm-linux-objdump -D -S u-boot >dump

查看:

看到函数的其实地址cfe02ad0的地址是在内存里的。所以start.S里的:

实现了从垫脚石跳转到内存。但是,此时会发现在这里的起始地址被变为了cfe02ad0:

在第一阶段里,不是说启动地址是在0吗?为什么这里是cfe02ad0呢?还有就是为什么是这个地址。

 

前面的学习知道,当去链接一个程序的时候,程序由多个文件构成,起始地址是由链接器脚本决定的。在/home/samba/uboot/Uboot/6410/uboot/board/samsung/smdk6410里的u-boot.lds:

起始地址是0:

这里是0,为什么那里会是cfe02ad0呢?我们回到uboot的顶层目录,打开config.mk:

搜索text_base:

找到:

在这里-T $(LDSCRIPT)就是定义使用链接器脚本。后面的-Ttext 是制定代码段的基地址的。$(TEXT_BASE)。这里有两个起始地址,然而程序运行的时候以后面的TEXT_BASE的地址为准。它会覆盖掉LDSCRIPT这个地址。

 

TEXT_BASE是在board/Samsung/smdk6410/config.mk里定义的:

 

接下来就是测试验证一下,把他修改为50008000。然后程序编译:

修改之后,执行make。

反汇编:

arm-linux-objdump -D -S u-boot >dump

上面的起始地址变了,刚才制定的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

那起始地址为什么不是0呢?下图:

从上图可以看到,ldr PC,=start_armboot的跳转,把地址从垫脚石跳转到内存里。在前面的代码里,有用到b reset等跳转指令,为什么这不会跳转到内存去执行,而是还在垫脚石里呢?

例如:

上面的跳转,bl lowlevel_init的跳转地址:

为什么PC指针还是在垫脚石中呢?

 

这就得讲两个词了。绝对跳转和相对跳转。

B和bl是相对跳转。

Ldr伪指令是绝对跳转:

 

第三阶段:

是从此函数Start_armboot进入的。主要完成的硬件和软件的初始化,只是一些基础的初始化。

该函数里有一个for循环:

在for里首先是让一个指针数组,把里面的函数指针依次调用一次,if里的判断语句就是函数指针。那么指针数组里有哪些函数指针呢。

 

指针数组:

可以看到里面都是函数指针。这里软件的初始化就不看了,我们只看硬件的初始化。在这些函数指针里,硬件初始化的有串口初始化。Serial_init。接着是lcd的初始化:

初始化网卡

初始化led:

接着进入一个主循环:

执行用户输入的命令。例如tftp命令。这里是一个死循环。老是等待执行用户继续输入命令。在第一个阶段,每个开发板可能有不同的地方,但是在这个地方都是一样的。就是,在第二阶段都是跳到start_armboot处执行代码。2440的第一阶段是在start.S的b reset开始。


关键字:U-boot  工作流程 引用地址:17.U-boot的工作流程分析-6410

上一篇:18.U-boot的工作流程分析-210
下一篇:16.U-boot的工作流程分析-2440

推荐阅读最新更新时间:2024-11-09 23:22

基于S3C6410的ARM11学习(六) 核心初始化之关闭所有中断
上一次,我们完成了核心初始化之关闭看门狗了。下面就要关闭所有中断了。因为这个时候还在初始化整个硬件环境,应用程序还没有开始跑,所以是不希望有中断产生来打断CPU工作的。 中断是嵌入式系统中很重要的东西了。因为有了这个东西,可以使CPU解放出来,做更多的事。 学单片机的时候,对于按键,我们可以采用轮询检测,隔一段时间就去检测看看按键有没有按下,有按下的话就进行处理。没有的话就跳过。而使用外部中断后,就不必检测了,外部中断会自动检测,就不用CPU检测了。当外部中断有效后,外部中断模块就会产生一个中断源给CPU,CPU检测到这个中断源,再去执行对应的中断处理函数。比轮询法效率要高很多了。 至于S3C6410的中断的具体的一些
[单片机]
基于S3C<font color='red'>6410</font>的ARM11学习(六) 核心初始化之关闭所有中断
OK6410裸机学习之C语言调用汇编函数
start.S源码: .globl _start .globl delay //用globl声明,外部函数就可以调用delay函数 _start: // 硬件相关的设置 // Peri port setup ldr r0, =0x70000000 orr r0, r0, #0x13 mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff) // 关看门狗 // 往WTCON(0x7E004000)写0 ldr r0, =0x7E004000 mov r1, #0 str r1, // 设置栈 ldr sp, =8*1
[单片机]
基于S3C6410的ARM11学习(十三) C语言环境初始化
如今,汇编的部分,就剩下最后一步了。C语言环境初始化。因为后面的代码要用C语言来写了。毕竟C语言编写比汇编要容易对了,而且c程序具有易读性。 C程序要运行,一个最重要的东西就是栈了。因为有栈,c程序才能在程序跳转的时候,保存上文。然后在程序返回的时候,将保存的上文恢复。这样,才保证了调用函数之前和之后的上下文是不变的。 使用汇编代码写的话,是不用设置栈的,因为保护上下文是要用汇编在代码中自行写出的,而C代码是靠编译器编译自动加上的。 栈,有4种。 从图中可以看出四种栈的区别。栈都是放在内存空间的,因为要随时读写。栈的起始地址放在内存的高地址出,那么增长方向就是向下增长,这种就是递减栈。如果栈的起始地址放
[单片机]
基于S3C<font color='red'>6410</font>的ARM11学习(十三) C语言环境初始化
OK6410A 开发板 (八) 115 linux-5.11 OK6410A 内存文件系统的挂载实例
mount -t tmpfs tmpfs /work/mount/ struct mount 结构体 $1 = (struct mount *) 0x816f5780 // struct mount 结构体 地址 $2 = { // struct mount 结构体 内容 mnt_hash = { next = 0x0, pprev = 0x0 }, mnt_parent = 0x816f5780, // 表示挂载到了 /work/mount/ 所在的 struct mount 上 , 0x816f5780 为 /work/mount/ 所在的 struct mount 的地址 mnt_mo
[单片机]
U-Boot补丁 S3C2440
# tar xvf u-boot-1.1.6.tar.bz2 //解压 # cd u-boot-1.1.6/ 制作补丁文件 # diff -urN u-boot-1.1.6 u-boot-1.1.6.new u-boot-1.1.6_jz2440.patch 打补丁 # patch -p1 u-boot-1.1.6_jz2440.patch p1:忽略补丁文件第一个”/”之前的内容(也就是如下:u-boot-1.1.6) # head u-boot-1.1.6_jz2440.patch diff -urN u-boot-1.1.6/board/100ask24x0/100ask24x0.c u-boo
[单片机]
移植u-boot 1.1.6到TQ2440开发板-第二阶段
经过了第一阶段的修改,目前能够编译出uboot.bin文件,但是这个文件还不能支持TQ2440,因为我们是在smdk2410上移植,代码还是支持smdk2410,因此要开始第二阶段的修改 移植u-boot 1.1.6到TQ2440开发板-第二阶段 增加uboot对TQ2440的代码支持 第一步:修改 SDRAM 配置,修改u-boot-1.1.6/board/TQ2440目录lowlevel_init.S文件 第54行 #define B1_BWSCON (DW16) #define B2_BWSCON (DW16) #define B3_BWSCON (DW16 + WAIT + UBLB) #
[单片机]
s3c6410 RomCode文档读后总结
最近无意中看到一篇关于s3c6410 RomCode的介绍,结合自己的经验,做个总结。 首先贴张图,具体描述下该芯片的启动方式及具体流程。 因为s3c6410的板子多数是从SD或者Nand方式启动,重点就先放在Nand启动上。 启动基本流程: 上图中的IROM为芯片固化程序,被称为BL0,开机后最先运行,它会去做一些硬件初始化动作,代码里通过检测GPN 管脚状态从相应设备指定区域BL1中拷贝4KB执行代码到Stepping stone中运行; Disable the Watch-Dog Timer Initialize the TCM. Initialize the Block Device Copy Functi
[单片机]
s3c<font color='red'>6410</font> RomCode文档读后总结
基于S3C6410的ARM11学习(十六) 外部中断
中断的过程如下: 中断源检测中断信号产生,然后将中断信号发送给中断控制器,中断控制器判断该中断是否被屏蔽,从而决定该中断信号是否要发送给CPU。中断信号发送给CPU后,CPU对中断进行处理,也就是调用中断函数。 上述过程,基本上是嵌入式的通过中断处理过程,只是不同的嵌入式在这三部分配置有区别而已。 S3C6410共有64个中断源。 上图是S3C6410的中断控制器,这里就关心红色框部分。这两个是中断控制器,分别管理各自的32个中断。 这里,就截取了一部分的图。总共有64个中断,每个中断有自己的标号,以及自己的所属组,也是属于哪个中断控制器控制。标号是指在对应的中断控制器寄存器的哪一位或者是哪一个寄存器对应自己
[单片机]
基于S3C<font color='red'>6410</font>的ARM11学习(十六) 外部中断
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved