从零开始学习 sg200x 多核开发之 sophpi 编译生成 fip.bin 流程梳理
本文主要介绍 sophpi 编译生成 fip.bin 流程。
1、编译前准备
sophpi 的基本编译流程如下:
$ source build/cvisetup.sh
$ defconfig sg2002_wevb_riscv64_sd
$ clean_all
$ build_all
$ pack_burn_image
注:
- 需要在 bash 下运行
- clean_all 非必要可以不执行。
生成的固件位置: install/soc_sg2002_wevb_riscv64_sd/milkv-duo.img
。build_milkv.sh 也是一步一步调用这些函数。
build/cvisetup.sh
通过软链接,链接到 build/envsetup_soc.sh
,相关的编译命令都在这个文件中。
在 build/envsetup_soc.sh
文件中,定义了一些后续编译会用到的变量,如:
- TOP_DIR=$(gettop)
- BUILD_PATH=“$TOP_DIR/build”
2、编译入口
总的编译命令,可以不调用 clean_all
函数,不然每次都要全编译。
function clean_all()
{clean_ubootclean_opensbiclean_rtos[[ "$ATF_SRC" == y ]] && clean_atfclean_kernelclean_ramdiskclean_3rd_partyif [ "$TPU_REL" = 1 ]; thenclean_ive_sdkclean_ivs_sdkclean_tpu_sdkclean_tdl_sdkclean_cnv_sdkficlean_middlewareclean_osdrv
}
重点看一下 build_all
函数,位于 build/envsetup_soc.sh
文件中
function build_all()
{(build_uboot || return $?build_kernel || return $?build_ramboot || return $?build_osdrv || return $?build_3rd_party || return $?build_middleware || return $?if [ "$TPU_REL" = 1 ]; thenbuild_tpu_sdk || return $?build_ive_sdk || return $?build_ivs_sdk || return $?build_tdl_sdk || return $?fipack_cfg || return $?pack_rootfs || return $?pack_data || return $?pack_system || return $?copy_tools || return $?pack_upgrade || return $?
)}
根据上面函数,先调用 build_uboot
函数。
3、uboot编译
build_uboot
函数在 build/milkvsetup.sh 文件中定义
function build_uboot()
{(print_notice "Run ${FUNCNAME[0]}() function"_build_uboot_env_build_opensbi_env_link_uboot_logocd "$BUILD_PATH" || returnmake u-boot || return "$?"
)}
- 查看 build/Makefile 文件中 203 行 u-boot 依赖 u-boot-dep
u-boot: u-boot-dep
继续找 u-boot-dep 。。。(文件真多啊。。。)
根据 build/.config 中定义了 CONFIG_FIP_V2=y
找到 build/Makefile
文件
ifeq (${CONFIG_FIP_V1},y)
include scripts/fip_v1.mk
else ifeq (${CONFIG_FIP_V2},y)
include scripts/fip_v2.mk
else
$(error no fip version)
endif
flp_v2.mk
u-boot-dep: fsbl-build ${OUTPUT_DIR}/elf$(call print_target)
ifeq ($(call qstrip,${CONFIG_ARCH}),riscv)${Q}cp ${OPENSBI_PATH}/build/platform/generic/firmware/fw_payload.bin ${OUTPUT_DIR}/fw_payload_uboot.bin${Q}cp ${OPENSBI_PATH}/build/platform/generic/firmware/fw_payload.elf ${OUTPUT_DIR}/elf/fw_payload_uboot.elf
endif
- u-boot-dep 又依赖 fsbl-build
fsbl-build 定义在 scripts/fip_v2.mk 文件
ifeq ($(call qstrip,${CONFIG_ARCH}),riscv)
fsbl-build: opensbi
endif
ifeq (${CONFIG_ENABLE_FREERTOS},y)
fsbl-build: rtos
fsbl%: export BLCP_2ND_PATH=${FREERTOS_PATH}/cvitek/install/bin/cvirtos.bin
fsbl%: export RTOS_DUMP_PRINT_ENABLE=$(CONFIG_ENABLE_RTOS_DUMP_PRINT)
fsbl%: export RTOS_DUMP_PRINT_SZ_IDX=$(CONFIG_DUMP_PRINT_SZ_IDX)
fsbl%: export RTOS_FAST_IMAGE_TYPE=${CONFIG_FAST_IMAGE_TYPE}
fsbl%: export RTOS_ENABLE_FREERTOS=${CONFIG_ENABLE_FREERTOS}
endif
fsbl%: export FSBL_SECURE_BOOT_SUPPORT=${CONFIG_FSBL_SECURE_BOOT_SUPPORT}
fsbl%: export ARCH=$(call qstrip,${CONFIG_ARCH})
fsbl%: export OD_CLK_SEL=${CONFIG_OD_CLK_SEL}
fsbl%: export VC_CLK_OVERDRIVE=${CONFIG_VC_CLK_OVERDRIVE}
fsbl%: export SUSPEND=${CONFIG_SUSPEND}
fsbl%: export TPU_PERF_MODE=$(shell if [ "${CONFIG_CHIP_cv1812cp}" = "y" ] || [ "${CONFIG_CHIP_sg2002}" = "y" ] || [ "${CONFIG_CHIP_cv1812cpa}" = "y" ]; then echo "y";else echo "n";fi)
fsbl%: export BUILD_BOOT0=${CONFIG_ENABLE_BOOT0}
fsbl%: export BUILD_FASTBOOT0=${CONFIG_ENABLE_FASTBOOT0}
fsbl%: export STORAGE=${STORAGE_TYPE}ifeq (${CONFIG_ENABLE_BOOT0},y)
fsbl-build: u-boot-build memory-map$(call print_target)${Q}mkdir -p ${FSBL_PATH}/build${Q}ln -snrf -t ${FSBL_PATH}/build ${CVI_BOARD_MEMMAP_H_PATH}${Q}$(MAKE) -j${NPROC} -C ${FSBL_PATH} O=${FSBL_OUTPUT_PATH}${Q}cp ${FSBL_OUTPUT_PATH}/boot0 ${OUTPUT_DIR}/
else
fsbl-build: u-boot-build memory-map$(call print_target)${Q}mkdir -p ${FSBL_PATH}/build${Q}ln -snrf -t ${FSBL_PATH}/build ${CVI_BOARD_MEMMAP_H_PATH}${Q}$(MAKE) -j${NPROC} -C ${FSBL_PATH} O=${FSBL_OUTPUT_PATH} BLCP_2ND_PATH=${BLCP_2ND_PATH} \LOADER_2ND_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot-raw.bin${Q}cp ${FSBL_OUTPUT_PATH}/fip.bin ${OUTPUT_DIR}/
ifeq (${CONFIG_UBOOT_SPL_CUSTOM},y)${Q}$(MAKE) -C ${FSBL_PATH} clean O=${FSBL_OUTPUT_PATH}${Q}$(MAKE) -j${NPROC} -C ${FSBL_PATH} O=${FSBL_OUTPUT_PATH} BLCP_2ND_PATH=${BLCP_2ND_PATH} \CONFIG_SKIP_UBOOT=$(CONFIG_SKIP_UBOOT) LOADER_2ND_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/spl/u-boot-spl-raw.bin${Q}cp ${FSBL_OUTPUT_PATH}/fip.bin ${OUTPUT_DIR}/fip_spl.bin
else${Q}cp ${FSBL_OUTPUT_PATH}/fip.bin ${OUTPUT_DIR}/fip_spl.bin
endif
endif
又依赖 opensbi
opensbi: export CROSS_COMPILE=$(CONFIG_CROSS_COMPILE_SDK)
opensbi: u-boot-build$(call print_target)${Q}$(MAKE) -j${NPROC} -C ${OPENSBI_PATH} PLATFORM=generic \FW_PAYLOAD_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot-raw.bin \FW_FDT_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/arch/riscv/dts/${CHIP}_${BOARD}.dtb
又依赖 u-boot-build, build/Makefile中定义了 u-boot-build,所以会先执行 u-boot-build
u-boot-build: memory-map
u-boot-build: u-boot-dts
u-boot-build: ${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER} ${UBOOT_CVIPART_DEP} ${UBOOT_OUTPUT_CONFIG_PATH}$(call print_target)${Q}ln -snrf ${CVI_BOARD_MEMMAP_H_PATH} ${UBOOT_PATH}/include/${Q}rm -f ${UBOOT_CVI_BOARD_INIT_PATH}${Q}ln -s ${BUILD_PATH}/boards/${CHIP_ARCH_L}/${PROJECT_FULLNAME}/u-boot/cvi_board_init.c ${UBOOT_CVI_BOARD_INIT_PATH}${Q}rm -f ${UBOOT_CVITEK_PATH}${Q}ln -s ${BUILD_PATH}/boards/${CHIP_ARCH_L}/${PROJECT_FULLNAME}/u-boot/cvitek.h ${UBOOT_CVITEK_PATH}${Q}$(MAKE) -j${NPROC} -C ${UBOOT_PATH} olddefconfig${Q}$(MAKE) -j${NPROC} -C ${UBOOT_PATH} all${Q}cat ${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot.bin > ${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot-raw.bin
ifeq (${CONFIG_UBOOT_SPL_CUSTOM},y)${Q}cat ${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/spl/u-boot-spl.bin > ${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/spl/u-boot-spl-raw.bin
endif
依赖 memory-map, build/scripts/mmap.mk 中定义了 memory-map
.PHONY: memory-mapCVI_BOARD_MEMMAP_H_PATH := ${BUILD_PATH}/output/${PROJECT_FULLNAME}/cvi_board_memmap.h
CVI_BOARD_MEMMAP_CONF_PATH := ${BUILD_PATH}/output/${PROJECT_FULLNAME}/cvi_board_memmap.conf
CVI_BOARD_MEMMAP_LD_PATH:= ${BUILD_PATH}/output/${PROJECT_FULLNAME}/cvi_board_memmap.ldBOARD_MMAP_PATH := ${BORAD_FOLDER_PATH}/memmap.py
MMAP_CONV_PY := ${BUILD_PATH}/scripts/mmap_conv.py${CVI_BOARD_MEMMAP_H_PATH}: ${BOARD_MMAP_PATH} ${MMAP_CONV_PY}$(call print_target)mkdir -p $(dir $@)@${MMAP_CONV_PY} --type h $< $@${CVI_BOARD_MEMMAP_CONF_PATH}: ${BOARD_MMAP_PATH} ${MMAP_CONV_PY}$(call print_target)@mkdir -p $(dir $@)@${MMAP_CONV_PY} --type conf $< $@${CVI_BOARD_MEMMAP_LD_PATH}: ${BOARD_MMAP_PATH} ${MMAP_CONV_PY}$(call print_target)@mkdir -p $(dir $@)@${MMAP_CONV_PY} --type ld $< $@ifeq ($(wildcard ${BOARD_MMAP_PATH}),)
memory-map:
else
memory-map: ${CVI_BOARD_MEMMAP_H_PATH} ${CVI_BOARD_MEMMAP_CONF_PATH} ${CVI_BOARD_MEMMAP_LD_PATH}
endif
该脚本会自动生成 cvi_board_memmap.h
, cvi_board_memmap.conf
, cvi_board_memmap.ld
三个文件。
然后依赖 u-boot-dts
u-boot-dts:$(call print_target)
ifeq ($(UBOOT_SRC), u-boot-2021.10)
# U-boot doesn't has arch/arm64
ifeq ($(ARCH), arm64)${Q}find ${BUILD_PATH}/boards/${CHIP_ARCH_L} \\( -path "*linux/*.dts*" -o -path "*dts_${ARCH}/*.dts*" \) \-exec cp {} ${UBOOT_PATH}/arch/arm/dts/ \;${Q}find ${DTS_DEFATUL_PATHS} -name *.dts* -exec cp {} ${UBOOT_PATH}/arch/arm/dts/ \;
else${Q}find ${BUILD_PATH}/boards/${CHIP_ARCH_L} \\( -path "*linux/*.dts*" -o -path "*dts_${ARCH}/*.dts*" \) \-exec cp {} ${UBOOT_PATH}/arch/${ARCH}/dts/ \;${Q}find ${DTS_DEFATUL_PATHS} -name *.dts* -exec cp {} ${UBOOT_PATH}/arch/${ARCH}/dts/ \;
endif
endif
最终执行的命令为:
find sophpi/build/boards/cv181x \\( -path "*linux/*.dts*" -o -path "*dts_riscv/*.dts*" \) \-exec cp {} sophpi/u-boot-2021.10/arch/riscv/dts/ \;
find sophpi/build/boards/default/dts/cv181x sophpi/build/boards/default/dts/cv181x_riscv -name *.dts* -exec cp {} sophpi/u-boot-2021.10/arch/riscv/dts/ \;
在 sophpi/u-boot-2021.10/arch/riscv/dts
目录下执行 tree
命令,查看相关设备树文件。我们理论上用的是 sg2002 相关的 sg2002_wevb_riscv64_sd.dts
这个文件。
$ tree
.
├── ae350_32.dts
├── ae350_64.dts
├── ae350-u-boot.dtsi
├── binman.dtsi
├── cv1810c_wdmb_0006a_spinor.dts
├── cv1810c_wevb_0006a_spinand.dts
├── cv1810c_wevb_0006a_spinor.dts
├── cv1810h_wevb_0007a_spinor.dts
├── cv1811c_wdmb_0006a_spinor.dts
├── cv1811c_wevb_0006a_emmc.dts
├── cv1811c_wevb_0006a_spinand.dts
├── cv1811c_wevb_0006a_spinor.dts
├── cv1811h_wevb_0007a_emmc.dts
├── cv1811h_wevb_0007a_spinand.dts
├── cv1811h_wevb_0007a_spinor.dts
├── cv1812cp_sophpi_duo_sd.dts
├── cv1812cp_wevb_0006a_emmc.dts
├── cv1812cp_wevb_0006a_spinand.dts
├── cv1812cp_wevb_0006a_spinor.dts
├── cv1812h_wevb_0007a_emmc.dts
├── cv1812h_wevb_0007a_emmc_huashan.dts
├── cv1812h_wevb_0007a_spinand.dts
├── cv1812h_wevb_0007a_spinand_huashan.dts
├── cv1812h_wevb_0007a_spinor.dts
├── cv1812h_wevb_0007a_spinor_huashan.dts
├── cv1813h_wevb_0007a_emmc.dts
├── cv1813h_wevb_0007a_spinand.dts
├── cv1813h_wevb_0007a_spinor.dts
├── cv181x_asic_bga.dtsi
├── cv181x_asic_emmc.dtsi
├── cv181x_asic_qfn.dtsi
├── cv181x_asic_sd.dtsi
├── cv181x_asic_spinand.dtsi
├── cv181x_asic_spinor.dtsi
├── cv181x_base.dtsi
├── cv181x_base_riscv.dtsi
├── cv181x_default_memmap.dtsi
├── fu540-c000.dtsi
├── fu540-c000-u-boot.dtsi
├── fu540-hifive-unleashed-a00-ddr.dtsi
├── fu740-c000.dtsi
├── fu740-c000-u-boot.dtsi
├── fu740-hifive-unmatched-a00-ddr.dtsi
├── hifive-unleashed-a00.dts
├── hifive-unleashed-a00-u-boot.dtsi
├── hifive-unmatched-a00.dts
├── hifive-unmatched-a00-u-boot.dtsi
├── k210.dtsi
├── k210-maix-bit.dts
├── Makefile
├── microchip-mpfs-icicle-kit.dts
├── microchip-mpfs-icicle-kit-u-boot.dtsi
├── openpiton-riscv64.dts
├── qemu-virt.dts
├── sg2000_wevb_riscv64_sd.dts
└── sg2002_wevb_riscv64_sd.dts
- 执行到这里,才真正开始编译 u-boot,主要是以下几行命令
${Q}$(MAKE) -j${NPROC} -C ${UBOOT_PATH} olddefconfig${Q}$(MAKE) -j${NPROC} -C ${UBOOT_PATH} all${Q}cat ${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot.bin > ${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot-raw.bin
最终产物在 sophpi/u-boot-2021.10/build/sg2002_wevb_riscv64_sd/u-boot-raw.bin
4、opensbi 编译
有了 u-boot 之后,开始编译 opensbi
为了兼容不同的运行需求,OpenSBI 支持三种类型的 Firmware,分别为:
- dynamic:从上一级 Boot Stage 获取下一级 Boot Stage 的入口信息,以 struct fw_dynamic_info 结构体通过 a2 寄存器传递。
- jump:假设下一级 Boot Stage Entry 为固定地址,直接跳转过去运行。
- payload:在 jump 的基础上,直接打包进来下一级 Boot Stage 的 Binary。下一级通常是 Bootloader 或 OS,比如 U-Boot,Linux。
相关编译脚本位置: build/scripts/fip_v2.mk
opensbi: export CROSS_COMPILE=$(CONFIG_CROSS_COMPILE_SDK)
opensbi: u-boot-build$(call print_target)${Q}$(MAKE) -j${NPROC} -C ${OPENSBI_PATH} PLATFORM=generic \FW_PAYLOAD_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/u-boot-raw.bin \FW_FDT_PATH=${UBOOT_PATH}/${UBOOT_OUTPUT_FOLDER}/arch/riscv/dts/${CHIP}_${BOARD}.dtb
根据以上脚本获知,sophpi 上采用的是 payload 模式,payload 文件为 u-boot-raw.bin,就是上面我们编译出来的文件。
FW_FDT_PATH 为设备树路径,为 sophpi/u-boot-2021.10/build/sg2002_wevb_riscv64_sd/arch/riscv/dts/sg2002_wevb_riscv64_sd.dtb
编译完成后, 产物在 sophpi/opensbi/build/platform/generic/firmware
目录下。
5、fsbl编译
编译完了u-boot 和 opensbi,继续往回推,来到了 fsbl-build。(中间还有一个 rtos 编译,暂时略过先)。
FSBL 是 First Stage Boot Loader 的缩写。
fsbl-build: u-boot-build memory-map$(call print_target)${Q}mkdir -p ${FSBL_PATH}/build${Q}ln -snrf -t ${FSBL_PATH}/build ${CVI_BOARD_MEMMAP_H_PATH}${Q}$(MAKE) -j${NPROC} -C ${FSBL_PATH} O=${FSBL_OUTPUT_PATH}${Q}cp ${FSBL_OUTPUT_PATH}/boot0 ${OUTPUT_DIR}/
最终执行的编译命令为 :
make -j8 -C sophpi/fsbl O=sophpi/fsbl/build/sg2002_wevb_riscv64_sd BLCP_2ND_PATH=sophpi/freertos/cvitek/install/bin/cvirtos.bin \LOADER_2ND_PATH=sophpi/u-boot-2021.10/build/sg2002_wevb_riscv64_sd/u-boot-raw.bin
主要来看看 fsbl 编译流程,从 fsbl/Makefile 文件开始
all: fip bl2 blmacrosinclude ${MAKE_HELPERS_DIRECTORY}fip.mk
依次找到 fip 在 fsbl/make_helpers/fip.mk 文件
gen-chip-conf:$(print_target)${Q}mkdir -p '${BUILD_PLAT}'${Q}./plat/${CHIP_ARCH}/chip_conf.py ${CHIP_CONF_PATH}macro_to_env = ${NM} '${BLMACROS_ELF}' | awk '/DEF_${1}/ { rc = 1; print "${1}=0x" $$1 } END { exit !rc }' >> ${BUILD_PLAT}/blmacros.envblmacros-env: blmacros$(print_target)${Q}> ${BUILD_PLAT}/blmacros.env # clear .env first${Q}$(call macro_to_env,MONITOR_RUNADDR)${Q}$(call macro_to_env,BLCP_2ND_RUNADDR)
ifeq (${BUILD_BOOT0},y)
$(eval $(call add_define,ENABLE_BOOT0))
fip: fip_boot0
else
fip: fip-all
endiffip-dep: bl2 blmacros-env gen-chip-conffip_boot0: fip-dep$(print_target)${Q}echo " [GEN] boot0"${Q}. ${BUILD_PLAT}/blmacros.env && \${FIPTOOL} -v genfip \'${BUILD_PLAT}/boot0' \--MONITOR_RUNADDR="$${MONITOR_RUNADDR}" \--BLCP_2ND_RUNADDR="$${BLCP_2ND_RUNADDR}" \--CHIP_CONF='${CHIP_CONF_PATH}' \--NOR_INFO='${NOR_INFO}' \--NAND_INFO='${NAND_INFO}'\--BL2='${BUILD_PLAT}/bl2.bin' \--BLCP_IMG_RUNADDR=${BLCP_IMG_RUNADDR} \--BLCP_PARAM_LOADADDR=${BLCP_PARAM_LOADADDR} \--BLCP=${BLCP_PATH} \--DDR_PARAM='${DDR_PARAM_TEST_PATH}'${Q}echo " [LS] " $$(ls -l '${BUILD_PLAT}/boot0')${Q}cp ${BUILD_PLAT}/boot0 ${OUTPUT_DIR}fip-simple: fip-dep$(print_target)${Q}echo " [GEN] fip.bin"${Q}${FIPTOOL} -v genfip \'${BUILD_PLAT}/fip.bin' \--CHIP_CONF='${CHIP_CONF_PATH}' \--NOR_INFO='${NOR_INFO}' \--NAND_INFO='${NAND_INFO}'\--BL2='${BUILD_PLAT}/bl2.bin'${Q}echo " [LS] " $$(ls -l '${BUILD_PLAT}/fip.bin')
通过一堆复杂的操作。。。生成了一个 bl2.bin 文件。(正常情况下我们开发者也不会去修改这个玩意。。。)
主要关心 fip-all 这个操作,用于生成 fip.bin 文件。
6、fip.bin文件合成
查阅官方有限的资料,获知 fip.bin 为内含 bootloader+uboot 的文件
为啥要这么干?官方的文档里面是这么说的:
由于原生 u-boot 编译出 u-boot.bin 无法直接刻录到 FLASH 中。我们采取 ARM Trusted Firmware Design 中的 Firmware Image Package (FIP) 方式,将 uboot.bin 封装在 FIP.bin 里面。
https://doc.sophgo.com/cvitek-develop-docs/master/docs_latest_release/CV180x_CV181x/zh/01.software/BSP/U-boot_Porting_Development_Guide/build/html/3_U-boot_Transplant.html
通过 chatgpt 查询 fip 后得知:
FIP(Flexible Image Processor)文件是指存储在ARM架构的处理器设备上的固件映像文件。它主要用于引导和配置设备。FIP文件通常包含以下内容:
- Trusted Firmware-A(TF-A):TF-A 是 ARM 架构设备上的一个开源的可信固件。它负责设备的引导、安全检查和启动加载程序的执行。
- U-Boot:U-Boot 是一个开源的引导加载程序(bootloader),用于启动设备。它提供了引导设备的功能,并提供了配置和管理设备硬件的选项。
- ARM Trusted Firmware(ATF):ATF 是一组用于安全引导的固件,用于验证和启动设备上的其他软件组件(如操作系统)。
- 其他组件:FIP 文件还可以包含其他固件组件,如设备树(Device Tree)文件、TEE 固件(如 OP-TEE)、加密密钥和配置参数等。
FIP 文件在 ARM 架构设备上很常见,它们提供了引导和初始化处理器的必要组件。这些文件由设备制造商提供,并根据特定设备、硬件配置和需求进行定制。
按照前面的分析,fip.bin 在 fsbl 最后阶段合成
fip-all: fip-dep$(print_target)${Q}echo " [GEN] fip.bin"${Q}. ${BUILD_PLAT}/blmacros.env && \${FIPTOOL} -v genfip \'${BUILD_PLAT}/fip.bin' \--MONITOR_RUNADDR="$${MONITOR_RUNADDR}" \--BLCP_2ND_RUNADDR="$${BLCP_2ND_RUNADDR}" \--CHIP_CONF='${CHIP_CONF_PATH}' \--NOR_INFO='${NOR_INFO}' \--NAND_INFO='${NAND_INFO}'\--BL2='${BUILD_PLAT}/bl2.bin' \--BLCP_IMG_RUNADDR=${BLCP_IMG_RUNADDR} \--BLCP_PARAM_LOADADDR=${BLCP_PARAM_LOADADDR} \--BLCP=${BLCP_PATH} \--DDR_PARAM='${DDR_PARAM_TEST_PATH}' \--BLCP_2ND='${BLCP_2ND_PATH}' \--MONITOR='${MONITOR_PATH}' \--LOADER_2ND='${LOADER_2ND_PATH}' \--compress='${FIP_COMPRESS}'${Q}echo " [LS] " $$(ls -l '${BUILD_PLAT}/fip.bin')
转换成实际执行命令为:
. sophpi/fsbl/build/sg2002_wevb_riscv64_sd/blmacros.env && \
./plat/cv180x/fiptool.py -v genfip \'sophpi/fsbl/build/sg2002_wevb_riscv64_sd/fip.bin' \--MONITOR_RUNADDR="${MONITOR_RUNADDR}" \--BLCP_2ND_RUNADDR="${BLCP_2ND_RUNADDR}" \--CHIP_CONF='sophpi/fsbl/build/sg2002_wevb_riscv64_sd/chip_conf.bin' \--NOR_INFO='FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' \--NAND_INFO='00000000'\--BL2='sophpi/fsbl/build/sg2002_wevb_riscv64_sd/bl2.bin' \--BLCP_IMG_RUNADDR=0x05200200 \--BLCP_PARAM_LOADADDR=0 \--BLCP=test/empty.bin \--DDR_PARAM='test/cv181x/ddr_param.bin' \--BLCP_2ND='sophpi/freertos/cvitek/install/bin/cvirtos.bin' \--MONITOR='../opensbi/build/platform/generic/firmware/fw_dynamic.bin' \--LOADER_2ND='sophpi/u-boot-2021.10/build/sg2002_wevb_riscv64_sd/u-boot-raw.bin' \--compress='lzma'
相关文章:

从零开始学习 sg200x 多核开发之 sophpi 编译生成 fip.bin 流程梳理
本文主要介绍 sophpi 编译生成 fip.bin 流程。 1、编译前准备 sophpi 的基本编译流程如下: $ source build/cvisetup.sh $ defconfig sg2002_wevb_riscv64_sd $ clean_all $ build_all $ pack_burn_image注: 需要在 bash 下运行clean_all 非必要可以不…...

python--在服务器上面创建conda环境
今天刚开始使用服务器的时候使用上面的公共环境发现老师缺少模块, [guoyupingcins195 ~]$ conda --version Traceback (most recent call last): File "/home/miniconda3/bin/conda", line 12, in <module> from conda.cli import main Fil…...

day15 python(3)——python基础(完结!!)
【没有所谓的运气🍬,只有绝对的努力✊】 目录 1、函数 1.1 函数传参中的拆包 1.2 匿名函数的定义 1.3 匿名函数练习 1.4 匿名函数应用——列表中的字典排序 2、面向对象 OOP 2.1 面向对象介绍 2.2 类和对象 2.3 类的构成和设计 2.4 面向对象代码…...

/:087启动游戏时提示丢失”d3dx···.dll””VCOMP···.dll”
/:087启动游戏时提示丢失”d3dx.dll””VCOMP.dll”或遇到应用程序无法正常启动(0xc000007b)和游戏有图像没有声音等情况。 主要是因为系统缺少大型游戏/软件运行的必备组件,这些组件有DirectX,Visual C2010,2012&…...

利用PHP和phpSpider进行图片爬取及下载
利用PHP和phpSpider进行图片爬取及下载,可以遵循以下步骤。phpSpider是一个开源的PHP爬虫框架,它可以帮助你轻松地抓取网页内容。以下是一个基本的步骤指南: 1. 安装phpSpider 首先,你需要确保你已经安装了Composer(…...

企业架构划分探讨:业务架构与IT架构的利与弊
在企业架构(EA)的江湖里,大家一直致力于如何把企业的复杂性简化成有条有理的架构蓝图。有人选择把企业架构分成业务架构和IT架构,而IT架构又进一步细分为应用架构、数据架构和技术架构。但一提到这种划分方式,总有人跳…...

Java设计模式 —— 【结构型模式】桥接模式详解
前言 现在有一个需求,需要创建不同的图形,并且每个图形都有可能会有不同的颜色。 首先我们看看用继承来实现: 我们可以发现有很多的类,假如我们再增加一个形状或再增加一种颜色,就需要创建更多的类。 试想…...

MySQL学习之DDL操作
目录 数据库的操作 创建 查看 选择 删除 修改 数据类型 表的创建 表的修改 表的约束 主键 PRIMARY KEY 唯一性约束 UNIQUE 非空约束 NOT NULL 外键约束 约束小结 索引 索引分类 常规索引 主键索引 唯一索引 外键索引 优点 缺点 视图 创建 删除 修改…...

游戏AI实现-寻路算法(A*)
A*(A-star)是一种图遍历和寻路算法,由于其完整性、最优性和最佳效率,它被用于计算机科学的许多领域。给定一个加权图、一个源节点和一个目标节点,该算法将找到从源到目标的最短路径(相对于给定的权重&#…...

spring学习(spring的IoC思想、spring容器、spring配置文件、依赖注入(DI)、BeanProxy机制(AOP))
目录 一、spring-IoC。 (1)spring框架。(诞生原因及核心思想) 1、为什么叫框架? 2、spring框架诞生的技术背景。 (2)控制反转(IoC)。 (3)spring的Bean工厂和IoC容器。 &a…...

谁说C比C++快?
看到这个问题,我我得说:这事儿没有那么简单。 1. 先把最大的误区打破 "C永远比C快" —— 某位1990年代的程序员 这种说法就像"自行车永远比汽车省油"一样荒谬。我们来看个例子: // C风格 char* str (char*)malloc(100…...

GEE+本地XGboot分类
GEE本地XGboot分类 我想做提取耕地提取,想到了一篇董金玮老师的一篇论文,这个论文是先提取的耕地,再做作物分类,耕地的提取代码是开源的。 但这个代码直接在云端上进行分类,GEE会爆内存,因此我准备把数据下…...

OpenCV相机标定与3D重建(24)计算两个二维点集之间的最佳仿射变换矩阵(2x3)函数estimateAffine2D()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 计算两个二维点集之间的最优仿射变换,它计算 [ x y ] [ a 11 a 12 a 21 a 22 ] [ X Y ] [ b 1 b 2 ] \begin{bmatrix} x\\ y\\ \en…...

UIP协议栈 TCP通信客户端 服务端,UDP单播 广播通信 example
文章目录 1. TCP通信 客户端(关键配置)2. TCP 服务端配置3. UDP 点播通信4. UDP 广播通信5. UIP_UDP_APPCALL 里边的处理example6. TCP数据处理 ,UIP_APPCALL调用的函数 UIP_APPCALL TCP的数据都在这个宏定义的函数里进行数据处理的 UDP 数据…...

【NoSQL系列】为什么要使用Redis?
第一次知道Redis是以前准备面试的时候,只知道是用来缓存数据的。随着这几年的工作,对软件的认识从盲人摸象到睁眼看世界。 在常用的软件架构评价模型中,性能、可用性、安全性和可维护性是常见的评价属性,客户总希望系统响应又快有…...

MySQL Explain 分析SQL语句性能
一、EXPLAIN简介 使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。 (1) 通过EXPLAIN,我们可以分析出以下结果: 表的读取顺序数据读取…...

IIS部署程序https是访问出现403或ERR_HTTP2_PROTOCOL_ERROR
一、说明 在windows server 2016中的IIS程序池里部署一套系统,通过https访问站点,同时考虑到安全问题以及防攻击等行为,就用上了WAF云盾功能,能有效的抵挡部分攻击,加强网站的安全性和健壮性。 应用系统一直能够正常…...

学技术学英文:代码中的锁:悲观锁和乐观锁
本文导读: 1. 举例说明加锁的场景: 多线程并发情况下有资源竞争的时候,如果不加锁,会出现数据错误,举例说明: 业务需求:账户余额>取款金额,才能取钱。 时间线 两人共有账户 …...

青少年编程与数学 02-004 Go语言Web编程 02课题、依赖管理
青少年编程与数学 02-004 Go语言Web编程 02课题、依赖管理 课题摘要:一、项目结构各目录说明: 二、依赖项三、依赖管理任务四、依赖管理步骤1. 初始化Go Modules项目2. 添加依赖3. 指定依赖版本4. 更新依赖5. 清理未使用的依赖6. 离线工作7. 模块隔离8. 可重现构建 …...

MyBatis写法汇总
Mybatis写法汇总 1. 批量操作 1.1 批量插入 <insert id"batchInsert" parameterType"java.util.List">INSERT INTO user (username, password, create_time) VALUES<foreach collection"list" item"item" separator"…...

【Linux学习】十五、Linux/CentOS 7 用户和组管理
文章目录 一、组的管理1.组的创建格式:参数: 2.组的删除格式:参数: 3.组的属性修改格式:参数: 4.查看组的信息①cat /etc/group 命令②getent group 命令③仅显示系统中所有组名 二、用户的管理①超级用户&…...
三维无人机航迹算法的目标函数如何确定
一、定义目标函数 在三维无人机航迹算法中,目标函数的确定通常基于具体的任务需求和飞行约束。以下是一个简单的例子,展示了如何为三维无人机航迹规划定义一个目标函数。 例子:最小化飞行时间和避障的三维无人机航迹规划 1.任务描述:无人机需要从起点飞到终点,同时避开一些…...

uniapp v-tabs修改了几项功能,根据自己需求自己改
根据自己的需求都可以改 这里写自定义目录标题 1.数组中的名字过长,导致滑动异常2.change 事件拿不到当前点击的数据,通过index在原数组中查找得到所需要的id 各种字段麻烦3.添加指定下标下新加红点显示样式 1.数组中的名字过长,导致滑动异常…...

用vscode,进行vue开发
使用Visual Studio Code(VSCode)进行Vue.js开发是一个很好的选择,因为VSCode提供了强大的编辑功能以及丰富的插件生态。以下是使用VSCode进行Vue开发的基本步骤: 1. 安装Node.js和npm 首先,确保你的计算机上安装了No…...

Kafka 磁道寻址过程详解
前言 Apache Kafka 是一款高吞吐、分布式的消息流平台,广泛应用于实时数据处理和事件驱动系统。在 Kafka 中,消息是存储在磁盘上的,这种高效的数据读写性能得益于 Kafka 独特的磁盘存储架构和寻址机制。本文将从 Kafka 的存储结构、磁道寻址…...

基于Spring Boot的社区药房系统
一、系统背景与目的 随着医疗改革的深入和社区医疗服务的不断完善,社区药房在居民健康保障中扮演着越来越重要的角色。然而,传统的药房管理方式存在着库存管理混乱、药品销售不透明、客户信息管理不规范等问题。为了解决这些问题,基于Spring…...

005 QT常用控件Qwidget_上
文章目录 前言控件概述QWidgetenable属性geometry属性windowTitle属性windowlcon属性 小结 前言 本文将会向你介绍常用的Qwidget属性 控件概述 Widget 是 Qt 中的核心概念. 英文原义是 “⼩部件”, 我们此处把它翻译为 “控件” . 控件是构成⼀个图形化界面的基本要素. QWi…...

机器学习之交叉熵
交叉熵(Cross-Entropy)是机器学习中用于衡量预测分布与真实分布之间差异的一种损失函数,特别是在分类任务中非常常见。它源于信息论,反映了两个概率分布之间的距离。 交叉熵的数学定义 对于分类任务,假设我们有&#…...

数据结构 ——前缀树查词典的实现
数据结构 ——前缀树查词典的实现 一、前缀树的概念 前缀树是一种多叉树结构,主要用于存储字符串。每个节点代表一个字符,路径从根节点到叶节点表示一个完整的字符串。前缀树的关键特征是 共享前缀,也就是说,如果两个字符串有相…...

MySQL 主从复制与高可用架构
一、MySQL 主从复制概述 (一)定义与作用 MySQL 主从复制是一种允许在多个 MySQL 数据库服务器之间进行数据同步的技术。简单来说,就是可以把数据从一个 MySQL 服务器(主服务器、主节点)复制到一个或多个从节点&#…...