U-Boot移植过程中两种代码重定位技术研究

2017-06-27 08:08郭国法董辉张开生
单片机与嵌入式系统应用 2017年6期
关键词:拷贝代码嵌入式

郭国法,董辉,张开生

(陕西科技大学 电气与信息工程学院,西安 710021)

U-Boot移植过程中两种代码重定位技术研究

郭国法,董辉,张开生

(陕西科技大学 电气与信息工程学院,西安 710021)

针对ARM架构的U-Boot移植过程中处理器种类繁多、启动方式多样化这一问题,提出了两种代码重定位技术。该代码重定位技术实现了在任何一种存储器上均能够启动U-Boot程序,并对两种技术进行了比较。实验表明,选择使链接地址固定的代码重定位技术可以实现U-Boot的高效移植。

嵌入式系统;U-Boot;代码重定位技术;移植

引 言

嵌入式Linux系统包括BootLoader、内核、文件系统和应用程序。上电或复位后,首先执行的是BootLoader程序,BootLoader初始化硬件设备,创建好C程序运行环境,然后引导内核,内核启动后挂接文件系统,最后启动init进程,执行应用程序。对于嵌入式系统,BootLoader依赖于实际的硬件和应用环境,因此要为嵌入式系统建立一个通用、标准的BootLoader是非常困难的。不过,大部分BootLoader仍然具有很多共性,某些BootLoader也能够支持多种体系结构的嵌入式系统。例如U-Boot同时支持PowerPC、ARM、MIPS和X86等体系结构,支持的开发板有上百种。通常,它们能够自动从存储介质上启动,引导操作系统启动,并且大部分可以支持串口和以太网接口。

1 U-Boot的概述

U-Boot是由开源项目PPCBoot发展起来的,ARMboot并入了PPCBoot,PPCBoot和其他一些架构的BootLoader合称U-Boot。U-Boot的功能强大,涵盖了绝大部分处理器构架,提供大量外设驱动,支持多个文件系统,附带调试、脚本、引导等工具,特别支持Linux,为板级移植做了大量的工作。

U-Boot启动分为两个阶段。第一阶段主要包含依赖于CPU体系结构的硬件初始化代码,通常都用汇编语言来实现。第二阶段通常用C语言完成,以便实现更复杂的功能,也使程序有更好的可读性和可移植性,最终调用内核。

第一阶段包括:① 硬件设备初始化;② 加载U-Boot第二阶段代码到RAM空间;③ 设置栈;④ 跳转到第二阶段代码入口。

第二阶段包括:① 初始化本阶段使用的硬件设备;② 检测系统内存映射;③ 将内核从Flash读取到RAM中;④ 为内核设置启动参数;⑤ 调用内核。

2 代码重定位技术

2.1 代码重定位技术由来

什么是代码重定位?在嵌入式系统中,系统上电后,将代码从一个存储区域拷贝到另一个存储区域,然后跳转到拷贝的那个存储区域执行代码,这就是代码重定位。ARM系列的处理器支持多种启动方式[2],包括NAND Flash,NOR Flash,eMMC,SD卡启动,如图1所示。

图1 ARM存储器结构示意图

系统上电或复位后,其过程如图2所示,U-Boot程序把自身的程序从存储介质拷贝到片外SDRAM,跳转到SDRAM执行U-Boot程序,然后引导操作系统,操作系统挂接根文件系统,最后执行应用程序。可见ARM架构处理器的U-Boot移植中都涉及到代码重定位问题。

图2 系统从上电或复位到执行应用程序的过程

2.2 ARM架构微处理器两种启动方式

CPU上电或复位后首先执行0地址处的代码,按照0地址所在RAM是否在CPU内部,将启动方式分为两类:片外0地址启动方式,NOR Flash启动;片内iRAM起始地址启动方式,NAND Flash、eMMC、SD卡启动。现结合ARM9 架构的S3C2440芯片对两种启动方式做介绍。

2.2.1 片内iRAM起始地址启动方式

ARM架构微处理器大多采用统一编址方式,部分处理器的片内iRAM起始地址不是0,之所以不是从0开始,是因为0地址开始是厂家固化好的一段引导程序,就是图2中处理器自动完成部分,为了统一,统称为片内iRAM起始地址启动方式,除了NOR Flash启动外,其他启动方式都是片内iRAM起始地址启动方式。以NAND Flash为例,NAND Flash可以存储程序,要执行程序唯一的方法就是把程序读到RAM中,然后在RAM执行程序。对于S3C2440处理器,当系统上电或复位后,芯片内部固化的程序判断是从NAND Flash启动,然后把NAND Flash的前4 KB内容拷贝到片内iRAM,从片内iRAM的0地址处开始执行U-Boot程序。U-Boot程序里面的代码重定位程序会将NOR Flash中的U-Boot程序整个拷贝到片外RAM(SDARM)中去,清除bss段,bss段在程序运行时存放未初始化的全局变量,然后将程序指针指向外部RAM(SDARM)中执行程序,即完成重定位功能。

移植支持NAND Flash启动的U-Boot,其难点在于片内iRAM的大小只有4 KB,而一般编译出来的uboot.bin文件的大小从150 KB到350 KB大小不等,肯定大于RAM自带的4 KB空间,所以就把CPU初始化代码和重定位代码链接到U-Boot程序的最前面4 KB,并且汇编部分都使用位置无关代码,所以重定位功能必须在U-Boot程序的前4 KB代码完成。

2.2.2 片外0地址启动方式

NOR Flash可以像内存一样读,但是不能像内存一样写,所以程序可以在NOR Flash上执行[3]。对于S3C2440处理器,当系统上电或复位后,芯片内部固化的程序判断是从NOR Flash启动,然后从0地址处开始执行程序。由于NOR Flash不能像内存一样写, 而且我们的目的是让U-Boot程序在片外RAM(SDARM)中运行,所以NOR Flash也需要代码重定位。代码重定位程序会将NOR Flash 中的U-Boot程序整个拷贝到片外RAM(SDARM)中去,清除bss段,然后将程序指针指向外部RAM(SDARM)中执行程序,完成代码重定位。

3 两种代码重定位技术介绍

这里介绍两种代码重定位技术:一种是在Makefile[4]编译前把链接地址固定;另一种是先把U-Boot代码拷贝到SDRAM中,然后程序自己修改链接地址,现分别对这两种方法做介绍。

3.1 固定链接地址的代码重定位技术

链接地址是程序实际运行的地址。将U-Boot程序拷贝到链接地址的起始地址处,然后执行“ldr pc,=_start_armboot”,程序会跳转到SDRAM执行U-Boot程序。主要解决以下问题:从什么地方拷贝?拷贝多大?拷贝到什么地方去?如何拷贝?下面针对这些问题对固定链接地址的U-Boot代码重定位方法做论述。

① 首先将链接地址设置为片外RAM中的某个地址值,由于U-Boot的版本差别,其修改方法也不一样,对于U-Boot201003,在board目录下开发板目录里面的config.mk文件,有一行内容“TEXT_BASE=0x33F0 0000”,意思是链接地址的起始地址是0x33F0 0000,也就是U-Boot在SDRAM里面的起始地址是0x33F0 0000。

② 完成拷贝函数,拷贝函数从存储器把U-Boot程序拷贝到SDRAM的0x33F0 0000地址处,由于拷贝过程太复杂,所以用C语言完成。C语言运行需要栈,先设置栈,栈的设置比较灵活,就是把sp指针指向一块没有使用的内存[5],因为iRAM大小只有4 KB,SDRAM要64 MB,显然要把栈设置到SDRAM,设置好栈后就可以由汇编跳转到C语言来执行拷贝函数了。

③ 修改链接脚本,对于NAND Flash启动,要考虑第一阶段代码小于4 KB。上面讲过方法,就是修改链接脚本,把第一阶段用到的.o目标文件放在前面4 KB,最后把生成的U-Boot二进制文件反汇编,链接起始地址0x33F0 0000加4 KB等于0x33F0 1000,观察U-Boot第一阶段用到的函数是不是都小于0x33F0 1000,要是小于,则链接脚本修改正确。

④ 前4 KB内容必须使用位置无关代码[6]完成,所谓位置无关代码就是不管这条指令是在0地址还是其他地址执行,都能跳转到指定的位置。那么这条指令就是位置无关代码。

通过上述步骤可以得知,拷贝函数从存储器的0地址开始拷贝uboot.bin文件,拷贝到SDRAM的0x33F0 0000处,拷贝大小为从uboot.bin文件的__bss_start段链接地址减去.text段链接地址。

固定链接地址的重定位代码分析:

#define CONFIG_SYS_INIT_SP_ADDR 0X30000f80

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

bl nand_init_ll

mov r0, #0 //源

ldr r1, _TEXT_BASE //目的

ldr r2, _bss_start_ofs //大小

bl copy_code_to_sdram

ldr pc, =_start_armboot

首先宏定义了栈的地址,然后把sp指针指向该地址,bic sp、sp、#7指令使得sp以8字节对齐;相对跳转指令跳转到C语言nand_init_ll程序,完成NAND Flash初始化;然后给r0、r1、r2寄存器赋值作为下一步copy_code_to_sdram函数的参数,相对跳转指令bl跳转执行copy_code_to_sdram函数,完成uboot.bin拷贝到SDRAM;最后一条指令ldr pc, =_start_armboot在下一个机器周期到来后跳转到SDRAM的_start_armboot执行U-Boot第二阶段[7]。

3.2 修改链接地址的代码重定位技术

U-Boot的链接地址是0,程序运行时访问全局变量、静态变量,调用函数所使用的地址是“基于0地址编译得到的地址”。现在把程序复制到SDRAM需要修改代码,把“基于0地址编译得到的地址”修改为基于新地址。

程序里面有些地址在链接时候不能确定,要到运行前才能确定。此处用到的方法就是修改代码,让函数使用新地址。比如,原来程序的链接地址是0,变量的地址是0x100,复制程序到SDRAM的地址0x3200 0000,那么变量的链接地址就要做相应的修改,把0x100改为0x3200 0100,这样程序在0x3200 0100地址处便能找到这个变量[1],过程可以表示为:

旧链接地址+拷贝目的地址=新链接地址

那么如何知道旧地址存在哪里?编译u-boot.bin的时候加-pie选项,就会生成地址信息[8],存在“.rel”、“dynsym”这些段里,U-Boot程序运行的时候就根据这些段里的信息修改代码。把生成的ELF格式的可执行文件U-Boot用arm-linux-objdump-Du-boot>u-boot.dis命令反汇编,生成u-boot.dis文件,找到.rel段,如图3所示。从图中可以看出,rel段的起始位置为_ _rel_dyn_start,中间每隔一行有一个标记位0x17,每行为32个二进制位,占4个字节,重定位函数里面修改代码算法就是根据这些特点修改U-Boot.bin程序的。

图3 反汇编代码里的部分.rel段

在U-Boot-2012.03中使用的代码重定位函数为Relocate_code(addr_sp,id,addr),该函数有3个参数,分别是addr_sp、id和addr,其中addr_sp为栈的地址,id为gd_t数据结构地址,addr为拷贝到SDARM的目的地址。

图4 修改uboot.bin 文件原理图

修改部分的代码由汇报指令完成,现将其原理做简单介绍。如图4所示,为了说明修改算法原理,列举两个变量*A和D,指针变量A等于_ _rel_dyn_start_ofs的链接地址,D为A所指向的地址处的数值,V为偏移值,其值等于把u_boot拷贝到SDRAM的目的地址,给A加上偏移得到新的链接地址,然后把旧的值B赋给新的地址,一直循环,直到A等于_ _dyn_end_ofs,完成u_boot代码修改。

3.3 两种技术比较

上面介绍的两种代码的重定位技术各有优劣。固定链接地址的代码重定位技术相比修改链接地址的代码重定位技术代码简单,便于移植。然而修改链接地址的代码重定位技术可以把uboot.bin文件复制到SDARM的任何地方,但是代码很复杂,加-pie选项使得程序庞大,不利于NAND Flash启动。综合以上分析,推荐使用第一种方法完成代码重定位。

3.4 S3C2440平台上U-Boot移植

结合以上分析,使用固定链接地址的代码重定位技术,并选择交叉编译工具链arm-Linux-gcc4.3.2在Ubuntu16上对mini2440进行了U-Boot移植。按照第3.1节的步骤完成代码重定位部分代码,并修改时钟和串口初始化函数,使其支持DM9000网卡,图 5为NOR Flash启动的U-Boot界面。

图5 NOR Flash启动的U-boot界面

结 语

[1] 韦东山.嵌入式Linux 应用开发完全手册[M].北京:人民邮电出版社,2008:242-243.

[2] 田泽.嵌入式系统开发与应用[M].北京:北京航空航天大学出版社,2010:19-21,83-190.

[3] 周书林,邱磊,唐桂军.同时支持Nand Flash和Nor Flash启动的启动加载程序设计实现[J].科学技术与工程,2010,10(2):17-21.

[4] 柯敏毅,刘文锁.BootLoader下Makefile文件的分析研究[J].计算机与信息技术,2009,22(1):84.

[5] Lukasz Czech.On dynamics of automata with a stack[J].International Journal of Computer Mathematics,2015,92(3):486-497.

[6] 黄振华,李外云,刘锦高.ARM的位置无关程序设计在BootLoader中的应用[J].单片机与嵌入式系统应用,2008,8(1):22-25.

[7] 卢伟,潘炼.U-Boot在S3C2440上的移植[J].微型机与应用,2010,29(24):4-11.

[8] angrad.u-boot2012.04.01移植到mini2440[EB/OL].[2017-02].http:∥blog.chinaunix.net/uid-22609852-id-3515982.html.

郭国法(教授),主要研究方向为电气控制方面的研究;董辉(在读硕士),主要研究方向为嵌入式Linux系统开发与应用;张开生(教授),主要研究方向为嵌入式系统开发与应用。

Research on Two Kinds of Code Relocation Technique in U-Boot

Guo Guofa,Dong Hui,Zhang Kaisheng

(College of Electrical and Information Engineering,Shanxi University of Science and Technology,Xi'an 710021,China)

Aiming at the problem that the ARM processor has a wide variety of processors and the diversity of the boot mode in the process of U-Boot porting,two kinds of code relocation technology are proposed.It is achieved that each memory can start the U-Boot program,which is compared with the other.The experiment results show that the code relocation technique to fix the link address can realize the efficient transplantation of U-Boot.

embedded system;U-Boot;code repositioning technology;transplantation

TP277

A

�士然

2017-02-20)

猜你喜欢
拷贝代码嵌入式
唐氏综合征是因为“拷贝”走样了
创世代码
创世代码
创世代码
创世代码
搭建基于Qt的嵌入式开发平台
文化拷贝应该如何“拷”
嵌入式软PLC在电镀生产流程控制系统中的应用
Altera加入嵌入式视觉联盟
倍福 CX8091嵌入式控制器