海思芯片(hi3516dv300)uboot镜像生成过程详解
Posted 正在起飞的蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了海思芯片(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里的代码有关,不过我们也不用关心;
以上是关于海思芯片(hi3516dv300)uboot镜像生成过程详解的主要内容,如果未能解决你的问题,请参考以下文章
Hi3516开发笔记:海思HI3516DV300芯片介绍,入手开发板以及Demo测试
海思Hi3516DV300---部署yolov5检测+Sort跟踪算法
海思Hi3516DV300之Ubuntu20.04环境搭建和编译