加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

U-boot在开发板上移植过程详解(2)---U-boot实现源码分析(第一阶

发布时间:2020-12-15 06:20:50 所属栏目:百科 来源:网络整理
导读:? 前边,我们说了,一般的bootloader都分为两个阶段。我在讲U-boot实现源码分析时,也是按照这连个阶段来分析,如果对这两个阶段不清楚,请看前边的博客。好了,开始今天的主题: U-boot在开发板上移植过程详解(2)---U-boot实现源码分析(start.S分析) 第一阶
?

前边,我们说了,一般的bootloader都分为两个阶段。我在讲U-boot实现源码分析时,也是按照这连个阶段来分析,如果对这两个阶段不清楚,请看前边的博客。好了,开始今天的主题:U-boot在开发板上移植过程详解(2)---U-boot实现源码分析(start.S分析)

第一阶段:

??? 1)一些基本的硬件初始化工作????????????????????????????????????????????????

??? u-boot对应的第一阶段代码放在cpu/arm920t/start.S文件中,入口代码如下:

.globl _start???????????????? ;global声明一个符号可被其它文件引用,相当于声明了一个全局变量,.globl与.global相同
_start:??? b?????? reset??? ;b是不带返回的跳转(bl是带返回的跳转),意思是无条件直接跳转到reset标号出执行程序
??? ldr??? pc,_undefined_instruction? ;ldr相当于mov操作
??? ldr??? pc,_software_interrupt
??? ldr??? pc,_prefetch_abort
??? ldr??? pc,_data_abort
??? ldr??? pc,_not_used
??? ldr??? pc,_irq
??? ldr??? pc,_fiq

;.word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。

_undefined_instruction:? .word undefined_instruction??? ;就是在当前地址,即_undefined_instruction 处存放 undefined_instruction

_software_interrupt:????? .word software_interrupt
_prefetch_abort:?????????? .word prefetch_abort
_data_abort:??????????????? .word data_abort
_not_used:????????????????? .word not_used
_irq:?????????????????????????? .word irq
_fiq:?????????????????????????? .word fiq

?

?? 这部分就是异常向量表。当系统上电或复位后,将执行第一条指令,即跳转到标签为reset的代码处执行,具体如下:

reset:?????????????????????????????????? ;设置CPU为SVC32管理模式
??? mrs??? r0,cpsr???????????????????? ;mrs将状态寄存器cpsr(current program status register)的内容传送至通用寄存器
??? bic??? r0,r0,#0x1f???????????????
;r0和0x1f(00022222)的反码进行位与,是把 r0后面5位清零
??? orr??? r0,#0xd3??????????????? ;r0和0xd3(11010011)进行位或,最后得到r0=11010011,目的是设置r0的后5位为10011,让ARM进入SVC特权模式
??? msr??? cpsr,r0

#if defined(CONFIG_S3C2400)?? ;关闭看门狗
# define pWTCON??????? 0x15300000?? ;看门狗寄存器
# define INTMSK???????? 0x14400008??? ;中断屏蔽寄存器
# define CLKDIVN??????? 0x14800014??? ;时钟分频寄存器
#elif defined(CONFIG_S3C2410)
# define pWTCON??????? 0x53000000
# define INTMSK???????? 0x4A000008???
# define INTSUBMSK??? 0x4A00001C?? ;次级中断屏蔽寄存器
# define CLKDIVN??? 0x4C000014???????
;时钟分频寄存器
#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
??? ldr?????? r0,=pWTCON
??? mov???? r1,#0x0
??? str?????? r1,[r0]

??? mov???? r1,#0xffffffff??????????????????? ;屏蔽所有中断
??? ldr?????? r0,=INTMSK
??? str?????? r1,[r0]
# if defined(CONFIG_S3C2410)
??? ldr?????? r1,=0x3ff
??? ldr?????? r0,=INTSUBMSK
??? str?????? r1,[r0]
# endif

??? ldr??? r0,=CLKDIVN?????????????????????? ;设置时钟
??? mov??? r1,#3
??? str??? r1,[r0]
#endif??? /* CONFIG_S3C2400 || CONFIG_S3C2410 */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
??? bl??? cpu_init_crit???????????????????????? ;跳转并把转移后面紧接的一条指令地址保存到链接寄存器LR(R14)中,以此来完成子程序的调用
#endif

?? 上面的代码将CPU设为管理模式,关闭看门狗,屏蔽中断并设置中断,最后调用cpu_init_crit函数进行cpu的初始化,代码如下:

cpu_init_crit:???????????????????????????????? ;清除指令和数据缓存
??? mov??? r0,#0
??? mcr??? p15,c7,0??????????? ;mcr{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2?

??? mcr??? p15,c8,0??????????? ;mcr指令用于将ARM处理器寄存器的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则

??????????????????????????????????????????????????? ;产生未定义指令异常。其中协处理器操作码1和协处理器操作码2为协处理器将要执行的操作,目的寄存器

??????????????????????????????????????????????????? ;为ARM处理器的寄存器,源寄存器1和源寄存器2均为协处理器的寄存器。?

??? mrc??? p15,c1,c0,0??????????? ;mrc 协处理器寄存器到ARM处理器寄存器的数据传送指令
??? bic??? r0,#0x00002300????????????? @ clear bits 13,9:8 (--V- --RS)
??? bic??? r0,#0x00000087????????????? @ clear bits 7,2:0 (B--- -CAM)
??? orr??? r0,#0x00000002????????????? @ set bit 2 (A) Align
??? orr??? r0,#0x00001000????????????? @ set bit 12 (I) I-Cache
??? mcr??? p15,0

??? mov??? ip,lr???????????????????????????????? ;设置SDRAM控制器,与具体的目标板相关
??? bl??? lowlevel_init
??? mov??? lr,ip
??? mov??? pc,lr

?? 在这个函数中做了一下工作:清除指令与数据缓存,禁用MMU与数据指令缓存,最后调用lowlevel_init函数设置SDRAM控制器。该函数的实现与具体的目标板有关的。

?? 2)准备RAM空间?

??? 所谓准备RAM空间,就是初始化内存芯片,使它可用。 在board/smdk2410/lowlevel.init.S就是这个作用,要注意这时的代码,数据都保存在NOR Flash上,内存中还没有,所以读取数据时要变换地址,如下:

_TEXT_BASE:
.word??? TEXT_BASE

.globl lowlevel_init
lowlevel_init:

??? ;现在起三行进行地址变化,因为这时候内存中还没有数据,不能使用连接程序时确定的地址来读取数据????
??? ldr???? r0,=SMRDATA????????????????? ;SMBRDATA表示这13个寄存器的值存放在开始地址(连接地址),值为0x33F8XXXX,处于内存中????????
??? ldr???? r1,_TEXT_BASE??????????????? ;获得代码段的起始地址(_TEXT_BASE=0X33F80000)
??? sub??? r0,r1???????????????????????? ;将r0和r1相减,这就是13个寄存器值在Nor Flash上存放的开始地址?????????????????????????????
??? ldr???? r1,=BWSCON?????????????????? ;Bus Width Status Controller
??? add???? r2,#13*4
0:
??? ldr???? r3,[r0],#4
??? str???? r3,[r1],#4
??? cmp?? r2,r0
??? bne??? 0b

??? mov?? pc,lr

??? .ltorg

SMRDATA:?????????????????????????????????? ;13个寄存器的值
??? .word … …

??? .word … …

?? 这里做完以后,就要将整个U-boot的代码都复制到SDRAM中,这些又都在start.S中实现,如下:

relocate:???????????????????????????????????? ;将u-boot复制到RAM中
??? adr??? r0,_start???????????????????????? ;r0:当前代码的开始地址
??? ldr???? r1,_TEXT_BASE??????????????? ;r1:代码段的连接地址
??? cmp?? r0,r1????????????????????????????? ;测试现在是在Flash中还是在RAM中
??? beq??? stack_setup????????????????????
;如果已经在RAM中(这通常是调试时直接下载到RAM中),则不需要复制

??? ldr???? r2,_armboot_start???????????? ;_armboot_start在前边已经定义,是第一条指令的运行地址
??? ldr???? r3,_bss_start?????????????????? ;在连接脚本u-boot.lds中定义,是代码的结束地址
??? sub??? r2,r3,r2????????????????????????? ;r2=代码段的长度
??? add??? r2,r2???????????????????????? ;r2=NOR Flash上代码段的结束地址

copy_loop:
??? ldmia??? r0!,{r3-r10}????????????????? ;从地址[r0]处获得数据
??? stmia??? r1!,{r3-r10}????????????????? ;复制到地址[r1]处
??? cmp??? r0,r2???????????????????????????? ;复制是否复制完毕
??? ble??? copy_loop???????????????????????
;没复制完,则继续

?? 接下来,就要设置栈,栈的设置灵活性很大,只要让sp寄存器指向一段没有使用的内存即可。

stack_setup:
??? ldr???? r0,_TEXT_BASE???????????????????????????????? ;_TEXT_BASE为代码段的开始地址,值为0x33F80000
??? sub??? r0,#CFG_MALLOC_LEN?????????????????? ;代码段下面,留出一段内存以实现malloc
??? sub??? r0,#CFG_GBL_DATA_SIZE????????????? ;再留出一段内存,存一些全局参数
#ifdef CONFIG_USE_IRQ
??? sub??? r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)??? ;IRQ,FIQ模式的栈
#endif
??? sub??? sp,#12??????????????????????????????????????
;最后,留下12字节的内存给abort异常,往下的内存就都是栈了

?? 3)跳转到第二阶段代码的C入口点

?? 在跳转之前,还要清除BSS段(初始值为0,无初始值的全局变量,静态变量放在BSS段),代码如下:

clear_bss:
??? ldr?????? r0,_bss_start???????????????? ;BSS段的开始地址,它的值在连接脚本U-boot.lds中确定
??? ldr?????? r1,_bss_end?????????????????? ;BSS段的结束地址,它的值也在连接脚本u-boot.lds确定
??? mov???? r2,#0x00000000??????

clbss_l:str??? r2,[r0]????????????????????? ;往BSS段中写入0值
??? add??? r0,#4
??? cmp??? r0,r1
??? ble??? clbss_l

?? 现在,c函数的运行环境已经完全准备好了,通过如下命令直接跳转(这之后,程序才在内存中执行),它将调用lib_arm/board.c中的start_armboot函数(这是一个C语言函数),这是第二阶段的入口点:

??? ldr??? pc,_start_armboot

_start_armboot:??? .word start_armboot

?? 在第二阶段代码中,将进行更多的初始化工作,如对各种设备和接口的初始化,串口终端的初始化等。如果没有设置自动运行,则最终将进入一个循环,在循环内读取用户输入的命令并执行,这些会在下一节详细介绍。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读