龙空技术网

uboot的SPL框架

禾宇 229

前言:

眼前我们对“uboot spl 编译”大概比较重视,看官们都需要了解一些“uboot spl 编译”的相关知识。那么小编在网摘上收集了一些对于“uboot spl 编译””的相关资讯,希望咱们能喜欢,兄弟们一起来学习一下吧!

比较杂,因为每天只发5篇,所以这一个相当于工作学习日志,记事本。各位勿怪,

BIC

BIC―――――位清除指令

指令格式:

BIC{cond}{S} Rd,Rn,operand2

BIC指令将Rn 的值与操作数operand2 的反码按位逻辑”与”,结果存放到目的寄存器Rd 中。指令示例:BIC R0,R0,#0x0F ;将R0最低4位清零,其余位不变。

6.

lr就是连接寄存器(Link Register, LR),在ARM体系结构中LR的特殊用途有两种:一是用来保存子程序返回地址;二是当异常发生时,LR中保存的值等于异常发生时PC的值减4(或者减2),因此在各种异常模式下可以根据LR的值返回到异常发生前的相应位置继续执行。

7.Program Counter程序计数器,用于指示当前将要执行的下一条机器指令的内存地址。在IBM PC计算机中所用的INTEL CPU中,它被称为 IP (Instruction Pointer指令指针)

8.adr r0, _start 得到的是_start的当前执行位置,由 pc+offset 决定的 得到有效地址

ldr r0, =_start 得到的是绝对的地址,链接时决定;

9.

bss段:

  bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。

  bss是英文Block Started by Symbol的简称。

  bss段属于静态内存分配。

data段:

  数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。

  数据段属于静态内存分配。

text段:

  代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。

  这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。

  在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):

  堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。

  当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);

  当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。

栈(stack):

   栈又称堆栈,是用户存放程序临时创建的局部变量,

  也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。

  除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。

  由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场。

  从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

一个程序本质上都是由 bss段、data段、text段三个组成的。

  这样的概念,不知道最初来源于哪里的规定,但在当前的计算机程序设计中是很重要的一个基本概念。

  而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。

在采用段式内存管理的架构中(比如intel的80x86系统),bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域,

  一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。

比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。

  text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;

  而bss段不在可执行文件中,由系统初始化。

【例】

两个小程序如下:

程序1:

int ar[30000];void main(){    ......}

程序2:

int ar[300000] = {1, 2, 3, 4, 5, 6 };void main(){    ......}

发现程序2编译之后所得的.exe文件比程序1的要大得多。当下甚为不解,于是手工编译了一下,并使用了/FAs编译选项来查看了一下其各自的.asm,

发现在程序1.asm中ar的定义如下:

_BSS SEGMENT

?ar@@3PAHA DD 0493e0H DUP (?) ; ar

_BSS ENDS

而在程序2.asm中,ar被定义为:

_DATA SEGMENT

?ar@@3PAHA DD 01H ; ar

DD 02H

DD 03H

ORG $+1199988

_DATA ENDS

区别很明显,一个位于.bss段,而另一个位于.data段,两者的区别在于:

全局的未初始化变量存在于.bss段中,具体体现为一个占位符;

全局的已初始化变量存于.data段中;

而函数内的自动变量都在栈上分配空间;

.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);

.data却需要占用,其内容由程序初始化。因此造成了上述情况。

bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小;

bss段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。

data段(已手动初始化的数据)则为数据分配空间,数据保存在目标文件中;

data段包含经过初始化的全局变量以及它们的值。当这个内存区进入程序的地址空间后全部清零。

包含data段和bss段的整个区段此时通常称为数据区。

10、

1.uboot SPL架构简介

在uboot-2011之后的版本中多了一个叫SPL的架构,这个架构有什么用呢?在uboot-2011的/doc/README.spl文件有简单的介绍:

Generic SPL framework=====================Overview--------To unify all existing implementations for a secondary program loader (SPL)and to allow simply adding of new implementations this generic SPL frameworkhas been created. With this framework almost all source files for a boardcan be reused. No code duplication or symlinking is necessary anymore.为了统一所有现有实现第二段的程序加载程序(SPL)并允许简单地添加新的实现这个,一个通用SPL框架已创建。用这个框架板的几乎所有的源文件可以重用。没有代码重复或符号链接是必要的了。How it works------------There is a new directory TOPDIR/spl which contains only a Makefile.The object files are built separately for SPL and placed in this directory.The final binaries which are generated are u-boot-spl, u-boot-spl.bin andu-boot-spl.map.During the SPL build a variable named CONFIG_SPL_BUILD is exportedin the make environment and also appended to CPPFLAGS with -DCONFIG_SPL_BUILD.Source files can therefore be compiled for SPL with different settings.ARM-based boards have previously used the option CONFIG_PRELOADER for it.For example:ifeq ($(CONFIG_SPL_BUILD),y)COBJS-y += board_spl.oelseCOBJS-y += board.oendifCOBJS-$(CONFIG_SPL_BUILD) += foo.o#ifdef CONFIG_SPL_BUILD        foo();#endifThe building of SPL images can be with:#define CONFIG_SPLBecause SPL images normally have a different text base, one have to beconfigured by defining CONFIG_SPL_TEXT_BASE. The linker script have to bedefined with CONFIG_SPL_LDSCRIPT.To support generic U-Boot libraries and drivers in the SPL binary one canoptionally define CONFIG_SPL_XXX_SUPPORT. Currently following optionsare supported:CONFIG_SPL_LIBCOMMON_SUPPORT (common/libcommon.o)CONFIG_SPL_LIBDISK_SUPPORT (disk/libdisk.o)CONFIG_SPL_I2C_SUPPORT (drivers/i2c/libi2c.o)CONFIG_SPL_GPIO_SUPPORT (drivers/gpio/libgpio.o)CONFIG_SPL_MMC_SUPPORT (drivers/mmc/libmmc.o)CONFIG_SPL_SERIAL_SUPPORT (drivers/serial/libserial.o)CONFIG_SPL_SPI_FLASH_SUPPORT (drivers/mtd/spi/libspi_flash.o)CONFIG_SPL_SPI_SUPPORT (drivers/spi/libspi.o)CONFIG_SPL_FAT_SUPPORT (fs/fat/libfat.o)CONFIG_SPL_LIBGENERIC_SUPPORT (lib/libgeneric.o)

移植过uboot的都知道,uboot的启动其实是分为BL0,BL1,BL2三个阶段的,即:ROM->SPL->uboot.img.而这个SPL架构将可以编译产生一个uboot-spl.bin。即BL1的代码。也就是说SPL结构其实做的工作就是uboot的BL1阶段的工作。

2.SPL结构是如何工作的

cd 进入spl目录,从编译文件看这个架构都包括了什么文件: 我们先来看该目录Makefile: 当CONFIG_SPL_BUILD := y driver下设备驱动和arch/arm与cup相关的东东将被编译。 CONFIG_SPL_BUILD := y export CONFIG_SPL_BUILD

include $(TOPDIR)/config.mk# We want the final binaries in this directoryobj := $(OBJTREE)/spl/    HAVE_VENDOR_COMMON_LIB := $(shell [ -f $(SRCTREE)/board/$(VENDOR)/common/Makefile ] \    			&& echo y || echo n)START := $(CPUDIR)/start.oLIBS-y += arch/$(ARCH)/lib/lib$(ARCH).oLIBS-y += $(CPUDIR)/lib$(CPU).oifdef SOCLIBS-y += $(CPUDIR)/$(SOC)/lib$(SOC).oendifLIBS-y += board/$(BOARDDIR)/lib$(BOARD).oLIBS-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/lib$(VENDOR).oLIBS-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/libcommon.oLIBS-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/libdisk.oLIBS-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/libi2c.oLIBS-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/libgpio.oLIBS-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/libmmc.oLIBS-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/libserial.oLIBS-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.oLIBS-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.oLIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.oLIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o

接下来是连接到一个脚本,u-boot-spl.lds

    # Linker Script    ifdef CONFIG_SPL_LDSCRIPT    # need to strip off double quotes    LDSCRIPT := $(addprefix $(SRCTREE)/,$(subst ",,$(CONFIG_SPL_LDSCRIPT)))    endif        ifeq ($(wildcard $(LDSCRIPT)),)    	LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds    endif    ifeq ($(wildcard $(LDSCRIPT)),)    	LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-spl.lds    endif    ifeq ($(wildcard $(LDSCRIPT)),)    $(error could not find linker script)    endif

在arm/cpu/armv7目录下找到u-boot-spl.lds这个连接脚本

MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\		LENGTH = CONFIG_SPL_MAX_SIZE }MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \		LENGTH = CONFIG_SPL_BSS_MAX_SIZE }OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{	.text      :	{	__start = .;	  arch/arm/cpu/armv7/start.o	(.text)	  *(.text*)	} >.sram	. = ALIGN(4);	.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram	. = ALIGN(4);	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram	. = ALIGN(4);	__image_copy_end = .;	_end = .;	.bss :	{		. = ALIGN(4);		__bss_start = .;		*(.bss*)		. = ALIGN(4);		__bss_end__ = .;	} >.sdram}

其实这个连接脚本最后连接到还是arch/arm/cpu/armv7/start.S,作为他的入口。

(reset) <arch/arm/cpu/armv7/start.S> (b lowlevel_init: arch/arm/cpu/armv7/lowlevel_init.S) (b _main) –> <arch/arm/lib/crt0.S> (bl board_init_f) –> <arch/arm/lib/spl.c> (board_init_r) –> <common/spl/spl.c> (jump_to_image_no_args去启动u-boot) 到此SPL的生命周期结束。

12/

.gd_t: global data数据结构定义,位于文件 include/asm-arm/global_data.h。其成员主要是一些全局的系统初始化参数。需要用到时用宏定义:DECLARE_GLOBAL_DATA_PTR,指定占用寄存器R8

2.bd_t : board info数据结构定义,位于文件 include/asm-arm/u-boot.h。保存板子参数。

标签: #uboot spl 编译