U-BOOT小全(二)

简介: U-BOOT小全(二)

U-Boot配置和编译

前面在大概了解U-Boot及其目录结构后,就可以开始配置和编译U-Boot了。

在U-Boot源码中有一个README文件,它描述了如何配置并编译U-Boot。(其实很多都有,只不过是英文的,哈哈哈)

正确编译U-Boot

正确编译U-Boot代码的过程如下:

1)首先是编译器的问题,如果使用GNU交叉编译工具链,请确保环境变量的设置生效。

2)为特定的板子建立配置文件。输入make NAME_config就可以,其中“NAME_config”代表一个存在的配置名称,顶层目录下的boards.cfg文件中是已经支持的配置名称。

3)最后,输入“make all”就可以得到U-Boot映像文件了。其中“u-boot.bin”是二进制文件,“U-Boot”是ELF二进制格式的文件。

其中第二步举个例子

第二步:为特定的硬件板pcDuino3建立配置文件,打开boards.cfg文件,添加一行配置信息:

Active  arm  armv7  sunxi  -  sunxi
pcDuino3  sun7i:PCDUINO,SPL,SUNXI_EMAC

然后输入make pcDuino3_config命令,执行第二步的命令,接下来分析这个命令做了什么:

%_config:: outputmakefile
    @$(MKCONFIG) -A $(@:_config=)

由于%是个通配符,所以无论是何种配置,make xxx_config都是这个目标。命令中的MKCONFIG在Makefile之前有如下定义:

MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG

该定义表明MKCONFIG是顶层目录下的mkconfig脚本文件。

我们继续来看完整的命令:@( M K C O N F I G ) − A (MKCONFIG)-A(MKCONFIG)A(@:_config=),这里$(@:_config=)是变量的替换引用。

其具体使用方法为:格式为“( V A R : A = B ) ”或者“ (VAR:A=B)”或者“(VAR:A=B)或者{VAR:A=B}”,意思是:**替换变量“VAR”中所有以“A”字符结尾的字为“B”结尾的字。**这将相当于把pcDuino3_config末尾的_config去除了。因此实际执行的是“mkconfig-A pcDuino3”命令。

执行该脚本将生成两个文件,这两个文件将在后面的步骤中被引用。

下面就是执行mkconfig脚本了:

mkconfig -A pcDuino3

执行该脚本,生成两个文件,一个是include/config.h,如下:

/* Automatically generated - do not edit */
#define CONFIG_PCDUINO        1
#define CONFIG_SPL        1
#define CONFIG_SUNXI_EMAC        1
#define CONFIG_SYS_ARCH  "arm"
#define CONFIG_SYS_CPU   "armv7"
#define CONFIG_SYS_BOARD "sunxi"
#define CONFIG_SYS_TARGET "pcDuino3"
#define CONFIG_SYS_SOC    "sunxi"
#define CONFIG_BOARDDIR board/sunxi
#include <config_cmd_defaults.h>
#include <config_defaults.h>
#include <configs/sun7i.h>
#include <asm/config.h>
#include <config_fallbacks.h>
#include <config_uncmd_spl.h>

还有一个文件是include/config.mk,如下:

ARCH   = arm
CPU    = armv7
BOARD  = sunxi
SOC    = sunxi

下一步就是make。

因为在boards.cfg文件中有配置sun7i:PCDUINO、SPL、SUNXI_EMAC,所以这里我们将使用SPL框架。在spl目录下,有一个Makefile文件。我们简单分析一下这个Makefile文件。

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

首先

CONFIG_SPL_BUILD := y
export CONFIG_SPL_BUILD

定义并导出CONFIG_SPL_BUILD,这个定义是SPL框架最重要的定义,在最初的汇编代码中很多代码段都由该定义隔开。

include include/config.mk
include $(TOPDIR)/config.mk

引入刚刚生成的include/config.mk和顶层目录下的config.mk,其中顶层目录下的config.mk是设置了一些编译链接的选项。

接下来是SPL需要的代码和模块。再往下是指定链接脚本。

# Linker Script
ifdef CONFIG_SPL_LDSCRIPT
# need to strip off double quotes
LDSCRIPT := $(addprefix $(SRCTREE)/,$(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)),)
    LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot-spl.lds
Endif
ifeq ($(wildcard $(LDSCRIPT)),)
$(error could not find linker script)
endif

再下面是描述最终的目标:

ALL-y   += $(obj)/$(SPL_BIN).bin
ifdef CONFIG_SUNXI
ifndef CONFIG_SPL_FEL
ALL-y   += $(obj)/sunxi-spl.bin
endif
endif

所以最后在该目录下会生成u-boot-spl.bin和sunxi-spl.bin,其中sunxi-spl.bin是使用mksunxiboot工具生成的:

ifdef CONFIG_SUNXI
quiet_cmd_mksunxiboot = MKSUNXI $@
cmd_mksunxiboot = $(OBJTREE)/tools/mksunxiboot $< $@
$(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin
    $(call if_changed,mksunxiboot)
Endif

签名分析的是makefile

接下来分析一下链接脚本。根据前面关于链接脚本的一系列判断和指定,此处的链接脚本采用的是arch/arm/cpu/armv7/sunxi/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
}

在脚本最开始处,使用MEMORY命令定义了两个存储区域:一个是sram,起始地址为CONFIG_SPL_TEXT_BASE,长度为CONFIG_SPL_MAX_SIZE;另一个是sdram,起始地址为CONFIG_SPL_BSS_START_ADDR,长度为CONFIG_SPL_BSS_MAX_SIZE。这几个定义都是在include/configs/sunxi-common.h中:

#define                CONFIG_SPL_TEXT_BASE           0x20
#define                CONFIG_SPL_TEXT_BASE           0x5fe0
#define                CONFIG_SPL_BSS_START_ADDR      0x50000000
#define                CONFIG_SPL_BSS_MAX_SIZE        0x80000

这里可以看到TEXT段的基址定为0x20,这是因为mksunxiboot的存在,它会加上大小为0x20的特定的头。

在SECTIONS命令中定义了.text、.rodata、.data和.bss这四个段。其中.text、.rodata和.data段放在sram内存区域中,而.bss段放在sdram内存区域中。

在.text段中,我们将arch/arm/cpu/armv7/start.o中的.text段放置在最前面,其他对象文件的.text段随后放置。在.rodata段和.data段中,使用SORT_BY_ALIGNMENT将各个对象文件的相应段对齐排序。

或许到这里你很困惑,这是因为你和我一样对SPL框架没有认识,下面我们来学一下SPL,在了解了SPL以后,再反过来看看这里对SPL的Makefile和ldscript的讲解。

目录
相关文章
|
11天前
|
存储 前端开发 芯片
U-BOOT小全(三):SPL框架
U-BOOT小全(三):SPL框架
99 0
|
11天前
|
存储 缓存 安全
U-BOOT小全(五):BootLoader源码(SPL-UBoot 2)
U-BOOT小全(五):BootLoader源码(SPL-UBoot 2)
51 0
|
11天前
|
Linux 编译器 C语言
U-BOOT小全(四):BootLoader源码(SPL-UBoot 1)
U-BOOT小全(四):BootLoader源码(SPL-UBoot 1)
58 0
|
6月前
|
Java Spring
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
本篇笔者带大家走近 AutoConfigurationImportSelector,从整体上了解 Spring Boot 自动装配功能
66 2
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
|
11天前
|
网络协议 Unix Linux
U-BOOT小全(一)
U-BOOT小全(一)
47 0
|
Prometheus Cloud Native Java
Spring Boot 3.0 要来了,真心强!
Spring Boot 3.0 要来了,真心强!
|
XML Java 程序员
😧 Spring_day03(一)
😧 Spring_day03
84 1
|
开发框架 Java 数据库连接
😧 Spring_day01 ✅(一)
😧 Spring_day01 ✅
89 0
|
Java 数据库连接 数据库
😧 Spring_day03(五)
😧 Spring_day03
50 0
|
Java 数据安全/隐私保护 容器
😧 Spring_day03(三)
😧 Spring_day03
56 0