失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > tiny4412 uboot 移植(一)移植前准备

tiny4412 uboot 移植(一)移植前准备

时间:2024-01-31 17:03:03

相关推荐

tiny4412 uboot 移植(一)移植前准备

简介

本博客使用的开发板是友善之臂提供的tiny4412 SDK开发板。它的bootloader是由E4412_N.bl1.bin(三星提供的),uboot-spl.bin,uboot.bin和E4412_tzsw.bin组合而成,它可以通过sd卡启动也可以通过emmc启动,但是我这里只讲解emmc启动的方式,因为这样操作比较简洁,不用去拔插sd卡到电脑进行烧录。

先来看下芯片内部的memory map,0x0202_0000到0x0206_0000是4412的内部RAM,简称iRAM。由于iRAM是只读存储,所以4412把0x0202_1000到0x0202_1400的地址空间分配给iROM使用,iRAM的特性就是一上电就能使用,不需要初始化。0x0202_1400到0x0202_3400这段地址空间被划分为BL1,0x0202_3400到0x0202_7400则被分为BL2。如果我把程序E4412_N.bl1.bin(后面简称BL1)、uboot-spl.bin(等同于BL2)、uboot.bin、E4412_tzsw.bin烧录到emmc的指定位置,那么开发板上电之后,它的内部引导程序就会把E4412_N.bl1.bin加载到BL1的起始地方,在0x0202_1400执行bootloader的第一行代码,随后BL1会把emmc的uboot-spl.bin拷贝到0x0202_3400处,开始执行BL2的代码。由于BL2是由uboot-spl.bin产生的,所以BL2属于可控代码段,它会负责初始化时钟树,外部ram,串口等,然后将uboot.bin拷贝到对应的地址(我在uboot中定义为0x43e00000,这地址属于外部ram)并运行它。

知识点

下面列出可能会用到的知识点,供后面移植参考。

一、概念

1、uboot是一种通用性比较强的bootloader

SRAM: static randowm accecc memory,静态随机访问存储器。只要不掉电,存储的数据就不会丢失

上电后就可以直接读写SRAM中的数据,无需初始化操作

SDRAM:synchronous Dynamic Random Access Memory,同步动态随机存取器。需要不断的刷新,才能保存数据。

需要初始化ddr 控制器才能读写SDRAM里面的数据

2、根据“ARM-thumb 过程调用标准”:

r0-r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。

被调用函数在返回之前不必恢复 r0-r3。如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。

r4-r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。

r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。

在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。

R13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。

r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复

r15 是程序计数器 PC。它不能用于任何其它用途。

3、地址

1)运行地址<—>链接地址:他们两个是等价的,只是两种不同的说法。

我们在移植的时候会定义到uboot的链接地址,CONFIG_SYS_TEXT_BASE=0x43e00000。

uboot-spl在拷贝uboot到外部ram的时候,会把uboot拷贝到这个地址上面去,这样就能跳过去执行了。

这个地址不是随便定义的:

比如我 BL1运行后会负责把uboot-spl拷贝到0x0202_3400上面,那这样我们在编译uboot-spl的时候就需要指定链接地址为0x0202_3400,不然你拷贝之后的uboot-spl就运行有问题。

比如我uboot-spl运行后会负责把uboot拷贝到0x43e00000上面,那这样我们就需要在编译uboot 的时候指定链接地址为0x43e00000。

关于这个链接地址你使用工具链反汇编(类似arm-linux-objdump -S u-boot > u-boot.S )(类似arm-linux-objdump -S uboot-spl > uboot-spl.S )去反汇编文件,就可以看出链接地址

2)加载地址<—>存储地址:他们两个是等价的,也是两种不同的说法

加载地址其实就是你的存储的地址,这个没啥好说的。

二、指令

1、ldr

用来从存储器中将一个32位的字数据传送到目的寄存器中,LDR:通常都是作加载指令的,但是它也可以作伪指令,通常有两种不同的表示,一种是有等号,一种是没等号

格式: LSL:logic shift left 逻辑左移ldr 目的寄存器,<存储器地址>LDR R0,[R1,R2,LSL#2]!;//将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。

1)LDR pc, =MyHandleIRQ 表示将MyHandleIRQ地址放入pc寄存器中,相当于PC=MyHandleIRQ 。

例如:

1. LDR r0,=label //用于加载立即数或一个地址值到指定寄存器中

//如果label是立即数: LDR r0,=0X123 ;将0X123存入r0中

//如果name是个标识符: LDR r0,=label_1 ;将label_1所指向的地址值存入r0中

2)LDR PC,MyHandleIRQ 表示将 MyHandleIRQ地址中的值放入pc寄存器中,类似于C语言中的指针形式,相当于PC=*(MyHandleIRQ )。

例如:

LDR r0,[r1] //将R1中的值存到r0中

LDR r1,[r2,#16] //将(r2+16)地址中的内容存到r1中

LDR r1,[r2],#4 //将r2地址中的内容存到r1中,同时r2=r2+4

2、bl

b指令是单纯的跳转指令,即CPU直接跳转到某地址继续执行

bl 条件 目标地址

bl nand_init 跳转到函数nand_init

3、mov

完成从另一个寄存器,被移位的寄存器或将一个立即数加载到目的寄存器

MOV{条件}{S} 目的寄存器,源操作数

MOV R1,R0 ; //将寄存器R0的值传送到寄存器R1

MOV PC,R14 ;//将寄存器R14的值传送到PC,常用于子程序返回

mov r0, #0x1000

4、str

从源寄存器中将一个32位的字数据传送到存储器中,跟ldr相反

STR{条件} 源寄存器,<存储器地址>

STR R0,[R1],#8 ;//将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。

STR R0,[R1,#8] ;//将R0中的字数据写入以R1+8为地址的存储器中。

str r1, [r0]

5、sub

减法

SUB{条件}{S} , <op 1>, <op 2>

SUB R0, R1, R2 ; // R0 = R1 - R2

SUB R0, R1, #256 ; //R0 = R1 - 256

SUB R0, R2, R3,LSL#1 ; //R0 = R2 - (R3 << 1).减法可以在有符号和无符号数上进行

三、反汇编

反汇编文件dis的理解:/baidu_37973494/article/details/82796800

1、理解什么是:标号地址、标号名字、指令地址、指令机器码、指令机器码反汇编到的指令

下面以一段dis文件中代码来简单理解一下反汇编的读法(为了方便,部分说明已经卸载代码块双斜杠后面)

led.elf: file format elf32-littlearm //表明这是由led.elf文件反汇编得到的dis文件

//文件格式是elf32位的,且是小端模式存放

Disassembly of section .text: //说明反汇编文件是.text

00000000 <_start>: //标号地址、标号名字

0: e59f0050 ldr r0, [pc, #80] ; 58 <delay_loop+0x10>

4: e59f1050 ldr r1, [pc, #80] ; 5c <delay_loop+0x14>

8: e5810000 str r0, [r1]

指令地址 :号前面的数值

指令机器码 e59f0050这一列

指令机器码反汇编到的指令 ldr r0, [pc, #80] ; 58 <delay_loop+0x10>

2、例子说明

1、start.S文件对应的/* 2. 设置时钟 */ldr r0, =0x4c000014mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1str r1, [r0]2、反汇编dis文件对应的33f8000c: e59f0098ldr r0, [pc, #152] ; 33f800ac <sdram_config+0x34>33f80010: e3a01003mov r1, #3 ; 0x333f80014: e5801000str r1, [r0].........33f80078 <sdram_config>:........33f800a8: 00000030andeq r0, r0, r0, lsr r033f800ac: 4c000014stcmi 0, cr0, [r0], {20}

如果伪指令比较复杂,编译器会把这条ldr指令翻译得比较复杂,不是直接

33f80000: e3a00453 mov r0, #1392508928 ; 0x53000000

而是通过间接的方式取得这个值。

33f800ac = 33f8000c + 8 + 0x98(152转化成16禁止)

即到33f800ac这个地址去取值。整条stcmi指令不知道是什么意思,找不到资料 就不管了。

3、反汇编dis文件

//start.S文件.text.global _start_start:mov r0, #0mov r0, #0mov r0, #0ldr r1, _startldr r1, haltldr r1, =haltldr r1, =_startldr lr, =haltldr pc,_start

反汇编dis文件

boot.elf: file format elf32-littlearmDisassembly of section .text:33f80000 <_start>:33f80000: e3a00000mov r0, #033f80004: e3a00000mov r0, #033f80008: e3a00000mov r0, #033f8000c: e51f1014ldr r1, [pc, #-20] ; 33f80000 <_start>//ldr r1, _start33f80010: e59f1080ldr r1, [pc, #128] ; 33f80098 <halt> //ldr r1, halt33f80014: e59f10b4ldr r1, [pc, #180] ; 33f800d0 <sdram_config+0x34> //ldr r1, =halt33f80018: e59f10b4ldr r1, [pc, #180] ; 33f800d4 <sdram_config+0x38>//ldr r1, =_start ;33f8001c: e59fe0acldr lr, [pc, #172] ; 33f800d0 <sdram_config+0x34>//ldr lr, =halt33f80020: e51ff028ldr pc, [pc, #-40] ; 33f80000 <_start>//ldr pc,_start33f80024: eb00000d bl 33f80060<tzpc_init> //机器码翻译:pc=pc+0xd<<2+8= 33f80024+0x34+8=33f80060......33f80060<tzpc_init>:.......33f80098 <halt>:33f80098: eafffffeb 33f80098 <halt>.......33f8009c <sdram_config>:......c3e0046c: 110002e0.word 0x110002e0c3e00470: 110002e4.word 0x110002e433f800d0: 33f80098.word 33f80098 33f800d4: 33f80000.word 33f80000 //如果start的标号地址33f80000在链接脚本中制定成33f80004,那会有这样的变化:1、halt的地址也会编程33f80098+42、 在韦东山视频里面是这样的 mvnscc r0, #0编程 mvnscc r0, #4我也不知道为什么会反汇编成mvnscc指令,其实应该是一个word地址3、bl指令会翻译成 pc=pc+0xxx<<2+8,都是基于当前pc的,所以如果代码是在iRam中,跳转的就是iRam中代码,不会跳到高地址Sdram中可以看出函数偏移标志sdram_config下的指令机器码的值就是等于要跳转过去的地址从这里也可以看出你写的代码是不是对的。

如果觉得《tiny4412 uboot 移植(一)移植前准备》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。