海思芯片(hi3516dv300)uboot镜像生成过程详解

1、前言

(1)本文介绍的uboot编译过程是基于海思提供SDK包里的uboot源码进行编译,具体的编译参数是根据hi3516dv300芯片来设置的,编译生成的uboot烧录镜像也是用于hi3516dv300芯片的uboot镜像;
(2)对于Makefile没有特别强调则表示是uboot源码顶层的Makefile;

2、uboot的编译过程

2.1、配置编译环境

编译命令:make ARCH=arm CROSS_COMPILE=arm-himix200v002-linux- hi3516dv300_emmc_defconfig V=1

指令含义
ARCH=arm指定CPU架构是arm
CROSS_COMPILE=arm-himix200v002-linux-指定交叉编译工具链是arm-himix200v002-linux-
hi3516dv300_emmc_defconfig这是编译的目标,在顶层Makefile中对应"%config"目标,作用就是将"./configs/hi3516dv300_emmc_defconfig"拷贝到顶层目录作为".config"配置文件
V=1表示将Makefile中执行的命令打印出来不隐藏,这是调试的功能,如果是学习阶段最好将此功能加上

2.2、编译u-boot.bin

(1)编译命令:make ARCH=arm CROSS_COMPILE=arm-himix200-linux- -j 20
(2)-j 20:指定采用20个线程同时编译,前提是你的电脑CPU有20个核心,如果不清楚你的电脑CPU是几核的可以不加;

2.3、编译gzip工具

(1)在海思提供的SDK中会有hi_gzip目录,里面是生成gzip工具的源码和编译脚本,gzip是个压缩工具,和分段式uboot镜像的生成有关,将生成好的gzip拷贝到uboot源码的对应目录下;
(2)编译指令:cd hi_gzip;make;cp ./bin/gzip uboot/arch/arm/cpu/armv7/hi3516dv300/hw_compressed/ -rf
补充:gzip是在PC机上运行的,Makefile中指定了编译工具是gcc,所以我们在编译gzip时不同指定交叉编译工具链;

2.4、编译寄存器配置表格文件

(1)海思提供的SDK中uboot_tools/目录下打开对应单板的Excel文件,在main标签中点击"Generate reg bin file"按钮,生成reg_info.bin即为对应平台的表格文件;
(2)拷贝生成的reg_info.bin到boot源代码顶层目录,重命名为.reg;

2.5、生成分段式镜像:u-boot-z.bin

(1)编译指令:make ARCH=arm CROSS_COMPILE=arm-himix200-linux- u-boot-z.bin
(2)最终生成可烧录的uboot镜像:u-boot-hi3516dv300.bin;

3、uboot寄存器配置表格文件

3.1、功能介绍

在这里插入图片描述

(1)在SDK包中有uboot_tools目录,里面存放了芯片寄存器配置的xlsm格式的表格文件,比如hi3516dv300芯片对应的表格文件名字是"Hi3516DV300-DMEB_4L_FLYBY-DDR3_1800M_512MB_16bitx2-A7_900M-SYSBUS_300M.xlsm";
(2)最下方是模块名,寄存器都是按模块存放的,比如当前是在ddrc模块,表格中的寄存器都是和配置ddrc功能相关的寄存器;
(3)Base Addrss:这是模块寄存器的基地址;芯片在分配寄存器地址时,相关寄存器的地址是连续的;
(4)Register:这一列是寄存器的名字,和数据手册相对应;
(5)Offset Address:寄存器地址相对于基地址的偏移量,对寄存器的访问是按照"基地址+偏移量"的方式;
(6)Value:将来uboot启动阶段会将这里的值写入对应寄存器;

3.2、使用方法

(1)在“main”界面点击"Generate reg bin file"按钮,在当前目录生成reg_info.bin即为对应平台的表格文件;
(2)将reg_info.bin文件拷贝到uboot源码的顶层目录,并重命名为".reg"文件;
(3)“.reg"文件会用于生成u-boot-hi3516dv300.bin镜像文件,uboot在启动阶段会去读取”.reg"文件来设置寄存器;

4、分段式uboot镜像的生成过程

4.1、整个uboot烧录镜像的组成

在这里插入图片描述

(1)海思内置代码在启动时,会读取uboot镜像的前一部分到片内RAM地址空间;
(2)先执行.o文件,这些代码会读取.reg去设置寄存器,最终要初始化DDR,将uboot镜像重定位到DDR中;
(3)解压DDR中的uboot镜像,然后执行解压后的uboot镜像的代码;

4.2、主Makefile

······

.PHONY: u-boot-z.bin
u-boot-z.bin: $(CURDIR)/u-boot.bin
	make -C $(CURDIR)/arch/$(ARCH)/cpu/$(CPU)/$(SOC)/$(HW_DIR)/ \
		CROSS_COMPILE=$(CROSS_COMPILE) \
		BINIMAGE=$(CURDIR)/u-boot.bin TOPDIR=$(CURDIR)
	
	#上面的指令具体化各个变量
	#make -C uboot/arch/arm/cpu/armv7/hi3516dv300/hw_compressed/ CROSS_COMPILE=arm-himix200-linux-  BINIMAGE=uboot/u-boot.bin TOPDIR=uboot/
······

(1)在顶层Makefile的u-boot-z.bin目标中,没有做什么实际的功能,就是依赖顶层目录的u-boot.bin文件,然后跳转到arch/arm/cpu/armv7/hi3516dv300/hw_compressed/hw_compressed目录执行make指令;
(2)补充:CURDIR是Makefile的内置变量,表示当前目录的绝对路径;

4.3、u-boot-hi3516dv300.bin的生成过程

在这里插入图片描述

4.4、hw_compressed/Makefile文件源码

################################################################################
#    Create By Hisilicon
################################################################################

PWD           = $(shell pwd)
HW_CROSS_COMPILE = $(CROSS_COMPILE)
TOPDIR        =

################################################################################
CC       := $(HW_CROSS_COMPILE)gcc
AR       := $(HW_CROSS_COMPILE)ar
LD       := $(HW_CROSS_COMPILE)ld
OBJCOPY  := $(HW_CROSS_COMPILE)objcopy


################################################################################
BOOT     := u-boot-$(SOC)

#镜像的链接脚本
TEXTBASE := 0x80700000

CFLAGS   :=-g -Os -fno-builtin -ffreestanding \
	-D__KERNEL__ -DTEXT_BASE=$(TEXTBASE) \
	-I$(TOPDIR)/include \
	-I$(TOPDIR)/drivers/ddr/hisilicon/default \
	-I$(TOPDIR)/drivers/ddr/hisilicon/$(SOC) \
	-I$(TOPDIR)/arch/arm/include \
	-I$(TOPDIR)/lib/hw_dec \
	-fno-pic -ffunction-sections \
	-fdata-sections -fno-common -ffixed-r9    \
	-fno-common -pipe -march=armv7-a \
	-Wall -Wstrict-prototypes -fno-stack-protector \
	-D__LINUX_ARM_ARCH__=7 -D__ARM__ \
	-DCONFIG_MMC\
	$(MKFLAGS) -fno-strict-aliasing

################################################################################

#这些.o文件会按照链接脚本u-boot.lds用于生成u-boot-hi3516dv300.elf
START := start.o
COBJS := lowlevel_init_v300.o \
	init_registers.o \
	emmc_boot.o \
	uart.o \
	ddr_training_impl.o \
	ddr_training_ctl.o \
	ddr_training_boot.o \
	ddr_training_custom.o \
	ddr_training_console.o \
	startup.o \
	image_data.o \
	div0.o \
	reset.o

# 这些.S和.c文件会被编译成.o文件,对应于COBJS
SSRC  := arch/arm/cpu/armv7/$(SOC)/start.S \
	arch/arm/cpu/armv7/$(SOC)/reset.S \
	arch/arm/cpu/armv7/$(SOC)/emmc_boot.c \
	arch/arm/cpu/armv7/$(SOC)/uart.S \
	arch/arm/cpu/armv7/$(SOC)/init_registers.c \
	arch/arm/cpu/armv7/$(SOC)/lowlevel_init_v300.c \
	drivers/ddr/hisilicon/default/ddr_training_impl.c \
	drivers/ddr/hisilicon/default/ddr_training_ctl.c \
	drivers/ddr/hisilicon/default/ddr_training_boot.c \
	drivers/ddr/hisilicon/default/ddr_training_console.c \
	drivers/ddr/hisilicon/$(SOC)/ddr_training_custom.c \
	arch/arm/lib/div0.c \
	lib/hw_dec/hw_decompress.c \
	lib/hw_dec/hw_decompress_$(SOC).c \
	lib/hw_dec/hw_decompress_v1.c \
	lib/hw_dec/hw_decompress_v1.h

REG := $(wildcard $(TOPDIR)/*.reg $(TOPDIR)/.reg)
SRC := $(notdir $(SSRC))

################################################################################
.PHONY: $(BOOT).bin
$(BOOT).bin: $(BOOT).tmp regfile
	#把./$(BOOT).tmp前64字节保存到tmp1
	@dd if=./$(BOOT).tmp of=./tmp1 bs=1 count=64 2>/dev/null 
	
	#把顶层.reg文件保存到tmp2中,文件大小扩充到8192字节
	@dd if=$(REG) of=./tmp2 bs=8192 conv=sync 2>/dev/null
	
	#把./u-boot-hi3516dv300.tmp保存到tmp3文件中,tmp3文件要跳过前8256个字节
	@dd if=./$(BOOT).tmp of=./tmp3 bs=1 skip=8256 2>/dev/null
	
	#将tmp1、tmp2、tmp3依次构成u-boot-hi3516dv300.bin文件
	@cat tmp1 tmp2 tmp3 > $(BOOT).bin
	@rm -f tmp1 tmp2 tmp3
	@chmod 754 $(BOOT).bin
	@cp -fv $@ $(TOPDIR)
	@echo $(BOOT).bin is Ready.

#用objcopy工具将可执行程序制作成二进制格式文件
$(BOOT).tmp: $(BOOT).elf
	$(OBJCOPY) -O srec $< $(BOOT).srec
	$(OBJCOPY) -j .text -O binary $< $(BOOT).text
	$(OBJCOPY) --gap-fill=0xff -O binary $< $@

#将image_data.gzip和.o文件链接成可执行程序$(BOOT).elf
#生成map文件$(BOOT).map
$(BOOT).elf: image_data.gzip $(SRC) $(START) $(COBJS)
	$(LD) -Bstatic -T u-boot.lds -Ttext $(TEXTBASE) $(START) \
		$(COBJS) -Map $(BOOT).map -o $@
	
	#生成反汇编文件
	$(OBJDUMP) -d  $@ > $@.asm

#检查顶层目录下是否有.reg文件
.PHONY: regfile
regfile:
	@if [ "$(words $(REG))" = "0" ]; then ( \
		echo '***' Need '.reg' or '*.reg' file in directory $(TOPDIR); \
		exit 1; \
	) fi
	@if [ "$(words $(REG))" != "1" ]; then ( \
		echo '***' Found multi '.reg' or '*.reg' file in directory $(TOPDIR); \
		echo '***' Files: $(notdir $(REG)); \
		exit 1; \
	) fi

################################################################################
start.o: start.S
	$(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c

#将u-boot.bin压缩成image_data.gzip
# -1 : --fast      -9 : --best
image_data.gzip: $(BINIMAGE)
	./gzip -fNqc -7 $< > $@

%.o: %.c
	$(CC) $(CFLAGS) -Wall -Wstrict-prototypes \
		-fno-stack-protector -o $@ $< -c

%.o: %.S
	$(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c

image_data.o: image_data.S image_data.gzip
	$(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c

#############################################################################

$(SRC):
	ln -sf ../../../../../../$(filter %/$@,$(SSRC)) $@
################################################################################
TMPS := $(COBJS) start.o $(SRC) \
	$(BOOT).map $(BOOT).elf $(BOOT).srec $(BOOT).bin $(BOOT).text $(BOOT).tmp \
	image_data.gzip

distclean: clean

clean:
	-rm -f $(TMPS)

################################################################################
.PHONY: clean
################################################################################

(1)image_data.gzip:由u-boot.bin被gzip工具压缩形成;
(2)u-boot-hi3516dv300.elf:由image_data.gzip和.o文件,在当前目录的u-boot.lds链接脚本文件指导下被连接成可执行文件,链接地址是0x80700000;还会生成u-boot-hi3516dv300.map地址映射文件和u-boot-hi3516dv300.asm反汇编文件;
(3)u-boot-hi3516dv300.tmp:用objcopy工具将elf格式生成二进制格式;
(4)u-boot-hi3516dv300.bin:由u-boot-hi3516dv300.tmp和.reg文件生成,具体为什么分成tmp1、tmp2、tmp3再组合成最终的烧录镜像,对应我们使用芯片的工程师来说并不清楚,应该是和海思芯片内置的IROM里的代码有关,不过我们也不用关心;

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值