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

简介

本博客使用的开发板是友善之臂提供的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)并运行它。
tiny4412 uboot 2018移植(一)移植前准备_第1张图片
tiny4412 uboot 2018移植(一)移植前准备_第2张图片

知识点

下面列出可能会用到的知识点,供后面移植参考。
一、概念
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 )去反汇编文件,就可以看出链接地址
tiny4412 uboot 2018移植(一)移植前准备_第3张图片
tiny4412 uboot 2018移植(一)移植前准备_第4张图片
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} , ,
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的理解:https://blog.csdn.net/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
4: e59f1050 ldr r1, [pc, #80] ; 5c
8: e5810000 str r0, [r1]
指令地址 :号前面的数值
指令机器码 e59f0050这一列
指令机器码反汇编到的指令 ldr r0, [pc, #80] ; 58
2、例子说明

1、start.S文件对应的
/* 2. 设置时钟 */
    ldr r0, =0x4c000014
    mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
    str r1, [r0]
2、反汇编dis文件对应的
33f8000c:    e59f0098     ldr    r0, [pc, #152]    ; 33f800ac <sdram_config+0x34>
33f80010:    e3a01003     mov    r1, #3    ; 0x3
33f80014:    e5801000     str    r1, [r0]

.........

33f80078 <sdram_config>:
........
33f800a8:    00000030     andeq    r0, r0, r0, lsr r0
33f800ac:    4c000014     stcmi    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, #0
    mov r0, #0
    mov r0, #0
    ldr r1, _start
    ldr r1, halt
    ldr r1, =halt
    ldr r1, =_start
    ldr lr, =halt
    ldr pc,_start

反汇编dis文件

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

你可能感兴趣的:(Tiny4412,u-boot,2018,移植)