uboot移植之源码流程分析篇3(超详细!)

uboot移植之前期准备篇1

uboot移植之Makefile分析概述篇2

uboot移植之init_sequence_f函数数组分析(番外篇)

uboot移植之修改支持SDRAM篇4

uboot移植之修改支持NorFlash篇5

uboot移植之修改支持NandFlash识别篇6(超详细)


一、添加对smdk2440的支持

1、ubuntu下,先在/board/samsung目录下构建一个新的单板:cp smdk2410 smdk2440 -rf

2、在include/configs目录下复制并创建头文件smdk2440.h:cp smdk2410.h smdk2440.h,并将涉及smdk2410的宏名字修改为smdk2440.

3、将/board/samsung/smdk2440 目录下的Kconfig,MAINTAINERS,Makefile中涉及smdk2410的内容修改为smdk2440.

4、这时候还不能make smdk2410_config,否则会报错。

u-boot-2016.07$ make smdk2440_config

省略一些无关打印信息

***

*** Can't find default configuration "arch/../configs/smdk2440_defconfig"!

***

scripts/kconfig/Makefile:114: recipe for target 'smdk2440_defconfig' failed

make[1]: *** [smdk2440_defconfig] Error 1

Makefile:479: recipe for target 'smdk2440_config' failed

make: *** [smdk2440_config] Error 2

5、很明显,根据错误信息提示,u-boot-2016.07/configs目录下还缺了相关的配置文件,所以解决方法:

cp smdk2410_defconfig smdk2440_defconfig 

并且,将当中涉及smdk2410的内容修改为smdk2440。

6、需要在顶层makefile中自定义,指定编译架构,和编译器类型

7、make smdk2440_config

8、make。发现并不能通过,报错:

cc1: warning: unknown register name: x18
lib/asm-offsets.c:1:0: error: bad value (armv8-a) for -march= switch
 /*
 ^
Kbuild:43: recipe for target 'lib/asm-offsets.s' failed
make[1]: *** [lib/asm-offsets.s] Error 1
Makefile:1263: recipe for target 'prepare0' failed
make: *** [prepare0] Error 2

寻寻觅觅,总于在README官方文档中找到建单板的例子.....

发现漏了一个步骤,编译arch/arm/目录下的Kconfig并添加

121   config TARGET_SMDK2440
122       bool "Support smdk2440"
123       select CPU_ARM920T

968   source "board/samsung/smdk2440/Kconfig"

好了,再次make,编译已经没问题了,接下来应该对source insight的对应目录也执行上述操作,并且重新添加/删除对应的工程文件,保证文件一致性。

二、uboot源码分析

在分析之前,先不讨论其中代码是否适合运行在smdk2440,仅探讨其整体的流程,在什么时段?干了些啥?关于其中的一些bug(相对于JZ2440v3而言),在后篇移植会加以分析修改。

根据 uboot移植之Makefile分析概述篇2 中对u-boot.lds的分析,最开始应该从arch\arm\cpu\arm920t\start.S文件开始分析源码。

①复位之后,设置系统为SVC32管理模式

uboot移植之源码流程分析篇3(超详细!)_第1张图片

msr和mrs是程序状态寄存器(cpsr)数据传送的专属指令,先清掉后5bit,再或上0xd3,修改cpsr的控制位域中的对应模式位。在新版uboot里,异常向量(vector)通过连接脚本添加进代码中了,并没有直接在start.s中写出,但是反汇编之后,仍然可以看到其出现在代码中。

uboot移植之源码流程分析篇3(超详细!)_第2张图片

另外,关于start.s的包含的头文件,其实它们并没有存放在当前目录下arch\arm\cpu\arm920t,它们是在配置过程中自动生成的文件。

#include

#include

#include

感兴趣可穿越到:https://blog.csdn.net/wangdapao12138/article/details/79704718

②关看门狗&&屏蔽中断

uboot移植之源码流程分析篇3(超详细!)_第3张图片

0x53000000地址对应的寄存器为看门狗控制寄存器,bit0设为0即可关闭。

而INTSUBMSK,INTMSK 可以简单地认为对应于一二级中断屏蔽,分别用于:

uboot移植之源码流程分析篇3(超详细!)_第4张图片

所以,INTMSK只能屏蔽设为IRQ的中断,并不能屏蔽FIQ中断。

③设置时钟分频系数

uboot移植之源码流程分析篇3(超详细!)_第5张图片

注意:此处仅仅设置了时钟分频系数,并没有设置MPLLCON寄存器,启动MPLL,所以,系统时钟还是默认时钟频率,即12Mhz。s3c2440的时钟框图概要:

uboot移植之源码流程分析篇3(超详细!)_第6张图片

③相对跳转到 cpu_init_crit ,刷新TLB和cache,关闭MMU。TLB就是快表。

uboot移植之源码流程分析篇3(超详细!)_第7张图片

④相对跳转到 board\samsung\smdk2440\lowlevel_init.S,进行内存各种寄存器的配置。

uboot移植之源码流程分析篇3(超详细!)_第8张图片

阅读源码,可以知道这是要处理Flash上存放的13个寄存器的值,而不是通过绝对跳转到sdram内存中处理。此时,内存还没有初始化完毕呢。而且,使用到的参数是基于60Mhz的HCLK时钟频率计算出来的,但是我们的时钟仅仅只是设置了分配系数,MPLL还没开始工作,所以FCLK=12Mhz,而默认情况下HDIVN分频系数为1,所以HCLK=12Mhz。

该处理子程序lowlevel_init.S涉及到开发板相关的设置代码,后期需要根据情况去修改。

⑤相对跳转到_main (arch\arm\lib\crt0.S)。

uboot移植之源码流程分析篇3(超详细!)_第9张图片

下面逐步分析(双水平线之间),篇幅有点长。


首先ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR),设置栈指针,为调用c函数做准备,其宏定义看起来还挺复杂的,反汇编直接查看比较快速。

 744:    e59fd078     ldr    sp, [pc, #120]    ; 7c4

....

 7c4:    30000f50     andcc    r0, r0, r0, asr pc

ARM内核采用流水线技术,所以对于ARM指令,PC值是当前程序执行位置加上8(thumb指令则不同)

解析过程:ldr sp, [pc,#120]   >>>  ldr sp, [pc+120]  >>> ldr sp, [744 + 8 +0x78] >>> ldr sp, [7c4] 

ldr sp, [7c4] 就是到 7c4:这个地址把其中的值存放到sp中,所以sp=30000f50 。

分析下一指令8字节对齐之后,sp=30000f50,通过r0将sp作参传给top。

uboot移植之源码流程分析篇3(超详细!)_第10张图片

struct global_data就是gd结构体(global data),里面保存了uboot很多有用信息,像环境变量地址、设备信息、某些栈的地址等等。该函数给gd结构体划分了一块空间用于存放,挪动sp指向其起始地址。通过反汇编可以知道

   top = rounddown(top-sizeof(struct global_data), 16);
    c2fc:    e24000a8     sub    r0, r0, #168    ; 0xa8

一共减去了168个字节,所以sp=0x30000ea8,中间的空间用来存放gd_t结构体了。

接着往下分析将r0的值放入r9,r0也就是上一个sp的地址。而r9就指向了gd结构体的起始地址,还可以在整个工程文件中搜索 r9 ,从结果中看出一些端疑,其实就是将gd指针放入r9寄存器中。

global_data.h (arch\arm\include\asm) line 87 : #define DECLARE_GLOBAL_DATA_PTR    register volatile gd_t *gd asm ("r9")

之后,r0就作为传入参数,调用board_init_f_init_reserve函数,为了减少篇幅,删掉了几行无关紧要的代码。

uboot移植之源码流程分析篇3(超详细!)_第11张图片

该函数先根据传入的gd结构体的地址清除该块空间(写‘\0’),然后再设置gd结构体,为调用board_init_f()做准备。最后一句并没有起什么作用,可能是为了以后方便代码维护。

接下来bl board_init_f开启uboot的第二阶段(common\board_f.c), 去掉无关代码,还剩寥寥几句。

uboot移植之源码流程分析篇3(超详细!)_第12张图片

其实,CONFIG_ARM宏在 smdk2440_defconfig 配置文件中是有定义,只是 source insight 并没有识别出来。init_sequence_f是一个函数数组,在 initcall_run_list 函数中通过for循环调用其中的里面的函数指针。

uboot移植之源码流程分析篇3(超详细!)_第13张图片

所以,很多操作设置已经通过调用其中的函数来完成了。关于这个过程的详细讨论我把它放在uboot移植之init_sequence_f函数数组分析(番外篇) 里了,现在仅给出其最终结果,也就是调用完数组内所有函数之后的内存分布:

uboot移植之源码流程分析篇3(超详细!)_第14张图片


好的,最后从initcall_run_list函数一路返回到arch\arm\lib\crt0.S的_main,继续往下执行.。

 

重定位代码到 gd->relocaddr,重定位的范围是__image_copy_start ~ __image_copy_end的内容,但是其重定位过程和旧版的uboot不太一样。关于其差异,在移植修改的时候再详细讨论。

uboot移植之源码流程分析篇3(超详细!)_第15张图片

接着,清除bss段 ,往__bss_start ~ __bss_end段的内容写入零。

最后,设置好传入参数之后,绝对跳转到sdram的 board_init_r 函数,从此就不回头了,之前都是移植在flash中通过相对跳转执行函数。

board_init_r 函数也是一个关键的函数,通过for循环调用各种函数完成uboot的第二阶段启动设置。宏CONFIG_ARM在configs\smdk2440_defconfig文件下是有定义的。关于调用函数的详细过程我把它们放在 uboot移植之init_sequence_r函数数组分析(番外篇) 中了。

uboot移植之源码流程分析篇3(超详细!)_第16张图片

整个流程 OVER!!!

参考资料:

《ARM9嵌入式系统设计与应用开发》 熊茂华 杨震伦 主编

《汇编语言程序设计——基于ARM体系结构》 文全刚 赫志刚 主编

《嵌入式Linux应用开发完全手册》 韦东山著

《S3C2440A_UserManual_Rev13》

 

你可能感兴趣的:(uboot,2440)