uboot的SPL框架

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

  1. 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 framework
has been created. With this framework almost all source files for a board
can 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 and
u-boot-spl.map.

During the SPL build a variable named CONFIG_SPL_BUILD is exported
in 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.o
else
COBJS-y += board.o
endif

COBJS-$(CONFIG_SPL_BUILD) += foo.o

#ifdef CONFIG_SPL_BUILD
        foo();
#endif


The building of SPL images can be with:

#define CONFIG_SPL

Because SPL images normally have a different text base, one have to be
configured by defining CONFIG_SPL_TEXT_BASE. The linker script have to be
defined with CONFIG_SPL_LDSCRIPT.

To support generic U-Boot libraries and drivers in the SPL binary one can
optionally define CONFIG_SPL_XXX_SUPPORT. Currently following options
are 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 directory
obj := $(OBJTREE)/spl/

    HAVE_VENDOR_COMMON_LIB := $(shell [ -f $(SRCTREE)/board/$(VENDOR)/common/Makefile ] 
    			&& echo y || echo n)

START := $(CPUDIR)/start.o

LIBS-y += arch/$(ARCH)/lib/lib$(ARCH).o
LIBS-y += $(CPUDIR)/lib$(CPU).o
ifdef SOC
LIBS-y += $(CPUDIR)/$(SOC)/lib$(SOC).o
endif
LIBS-y += board/$(BOARDDIR)/lib$(BOARD).o
LIBS-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/lib$(VENDOR).o

LIBS-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/libcommon.o
LIBS-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/libdisk.o
LIBS-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/libi2c.o
LIBS-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/libgpio.o
LIBS-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/libmmc.o
LIBS-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/libserial.o
LIBS-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.o
LIBS-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.o
LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o
LIBS-$(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) (b lowlevel_init: arch/arm/cpu/armv7/lowlevel_init.S) (b _main) –> (bl board_init_f) –> (board_init_r) –> (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。保存板子参数。

展开阅读全文

页面更新:2024-03-21

标签:初始化   变量   指令   架构   函数   框架   分配   定义   大小   内存   区域   代码   文件   程序   数据   科技   空间

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top