小核引导RTOS---RISC-V C906

文章目录

    • 参考
    • 日志
    • 编译框架
      • 目标fip
    • 启动流程
      • fip文件组成
      • BL2程序
    • 总结
    • 思考
    • 备注


参考

  • 参考1. How does FSBL load the FreeRTOS on the small core and execute it?
  • 参考2. Duo now supports big and little cores?Come and play!Milk-V Duo, start!
  • 参考3. 使用uboot引导自己的操作系统
  • 参考4. 安全启动介绍

日志

FSBL Jb2829:g362832ac6-dirty:2024-04-02T13:31:11+00:00				# 版本信息
st_on_reason=40f0003
st_off_reason=800e0003
P2S/0x1000/0xc00a400.
SD/0x9400/0x1000/0x1000/0.P2E.
DPS/0xa400/0x2000.
SD/0xa400/0x2000/0x2000/0.DPE.
DDR init.							# DDR 初始化
ddr_param[0]=0x78075562.
pkg_type=1
D2_4_1
DDR3-4G-BGA
Data rate=1866.
DDR BIST PASS
PLLS/OD.
C2S/0xc400/0x9fe00000/0x3600.2RET.:00/0x3600/0x3600/0.RSC.[M1S./208x2f8a0000]/P0rxe8 0s0y0s0t0e0m0 /i0nxi1tb 0d0o0n.eRT: [1.289126]CVIRTOS Build Date:Apr  2 2024  (Time :13:31:11) 		# FreeRTOS 启动;
RT: [1.295040]Post system init done
RT: [1.298355]create cvi task
RT: [1.301172][cvi_spinlock_init] succeess
RT: [1.305076]prvCmdQuRunTask run
SD/0xfa00/0x1b000/0x1b000/0.ME.
L2/0x2aa00.
SD/0x2aa00/0x200/0x200/0.L2/0x414d3342/0xcafedbb7/0x80200000/0x37400/0x37400
COMP/1.
SD/0x2aa00/0x37400/0x37400/0.DCP/0x80200020/0x1000000/0x81900020/0x37400/1.
DCP/0x73c7a/0.
Loader_2nd loaded.					# 第二阶段:Opensbi;
Switch RTC mode to xtal32k
Jump to monitor at 0x80000000.
OPENSBI: next_addr=0x80200020 arg1=0x80080000
OpenSBI v0.9

可知:

  1. FSBL Jb2829...,FSBL启动,打印版本信息;
  2. DDR初始化完成后,紧跟RTOS任务初始化打印,中间无引导小核的工作打印

所以可以先对FSBL有个大致认知,再确认RTOS启动过程。

编译框架

# fsbl/Makefile.DEFAULT_GOAL := all	# 如果没有指定.DEFAULT_GOAL,make会执行第一个在Makefile中定义的目标。
MAKEOVERRIDES =			# 不传递任何父make的变量给子make,保持子make实例的独立性ARCH ?=					# make 传参可带ARCH=xxx 指定架构;ifneq ($(origin CROSS_COMPILE),command line)ifeq ($(ARCH),riscv)	# 如果不是命令行 make ARCH=xxx 形式,指明由RiscV核心来完成引导启动工作CROSS_COMPILE := ${CROSS_COMPILE_GLIBC_RISCV64}BOOT_CPU ?= riscv
...
ifeq (${CHIP_ARCH},)		# 必带参数:CHIP_ARCH$(error CHIP_ARCH is undefined)
...
ifeq (${CROSS_COMPILE},)	# 必带参数:CROSS_COMPILE$(error CROSS_COMPILE is undefined)
...
HOSTCC		:=	gcc
export HOSTCCCC			:=	${CROSS_COMPILE}gcc
...							# 工具链配置
include ${MAKE_HELPERS_DIRECTORY}build_macros.mk	# Makefile 宏定义,如:assert_boolean、add_define_val
include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk	# Make 辅助实现
...
include ${PLAT_MAKEFILE_FULL}	# 在plat_makefiles.mk中定义,指向:plat/${CHIP_ARCH}/platform.mk文件,
# fsbl/plat/sg200x/platform.mk,工作:
# - 定义哪些源码文件加入编辑链接;
# - 定义链接脚本文件;all: fip bl2 blmacros		# 第一目标all,依赖于fip、bl2、blmaacros
...
include ${MAKE_HELPERS_DIRECTORY}fip.mk	# 目标:fip
$(eval $(call MAKE_BL,2))				# 目标:bl2
$(eval $(call MAKE_BL,macros))			# 目标:blmacros

目标fip

目标fip有如下涉及RTOS的内容

# fsbl/make_helpers/fip.mk
...
fip: fip-all										# 目标fip 依赖于fip-all
...
fip-all: fip-dep$(print_target)${Q}echo "  [GEN] fip.bin"${Q}. ${BUILD_PLAT}/blmacros.env && \${FIPTOOL} -v genfip \'${BUILD_PLAT}/fip.bin' \'${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}'...	

由实际编译过程打印有(为简洁,将绝对路径中的SDK顶层目录替换为${SDK_TOP}):

. ${SDK_TOP}/fsbl/build/cv1813h_milkv_duos_sd/blmacros.env && \
./plat/cv181x/fiptool.py -v genfip \'${SDK_TOP}/fsbl/build/cv1813h_milkv_duos_sd/fip.bin' \--MONITOR_RUNADDR="${MONITOR_RUNADDR}" \--BLCP_2ND_RUNADDR="${BLCP_2ND_RUNADDR}" \--CHIP_CONF='${SDK_TOP}/fsbl/build/cv1813h_milkv_duos_sd/chip_conf.bin' \--NOR_INFO='FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' \--NAND_INFO='00000000'\--BL2='${SDK_TOP}/fsbl/build/cv1813h_milkv_duos_sd/bl2.bin' \--BLCP_IMG_RUNADDR=0x05200200 \--BLCP_PARAM_LOADADDR=0 \--BLCP=test/empty.bin \--DDR_PARAM='test/sophon/ddr_param.bin' \--BLCP_2ND='${SDK_TOP}/freertos/cvitek/install/bin/cvirtos.bin' \--MONITOR='../opensbi/build/platform/generic/firmware/fw_dynamic.bin' \--LOADER_2ND='${SDK_TOP}/u-boot-2021.10/build/cv1813h_milkv_duos_sd/u-boot-raw.bin' \--compress='lzma'	

截取其中的关键信息:

  • --BLCP_2ND='${SDK_TOP}/freertos/cvitek/install/bin/cvirtos.bin' \,RTOS定义为BLCP_2ND;

    其运行地址BLCP_2ND在源头在板型目录下的memmap.py文件中定义,如文件:build/boards/cv181x/cv1813h_milkv_duos_sd/memmap.py

    class MemoryMap:...DRAM_BASE = 0x80000000DRAM_SIZE = 512 * SIZE_1M# ==============# C906L FreeRTOS# ==============FREERTOS_SIZE = 2 * SIZE_1M# FreeRTOS is at the end of DRAMFREERTOS_ADDR = DRAM_BASE + DRAM_SIZE - FREERTOS_SIZEFSBL_C906L_START_ADDR = FREERTOS_ADDR
    

    可知:

    • Duos 内存起始地位:0x80000000;大小:512MB;
    • FreeRTOS镜像运行地址(非加载地址):0x9fe00000(内存倒数2MB位置);大小:2MB;

    转化路径:mempa.py – build/scripts/mmap.mk --> build/output/${PROJECT_FULLNAME}/cvi_board_memmap.h。

    关联方式:软链如上cvi_board_memmap.h文件链接到:fsbl/build/cvi_board_memmap.h;

  • --MONITOR='${SDK_TOP}/opensbi/build/platform/generic/firmware/fw_dynamic.bin' \,Opensbi定义为MONITOR;

    借鉴ATF,MilkV将Risc-V下的Opensbi等同于ATF中的BL31,也称为Monitor;

        # ==============================# OpenSBI | arm-trusted-firmware# ==============================# Monitor is at the begining of DRAMMONITOR_ADDR = DRAM_BASEATF_SIZE = 512 * SIZE_1KOPENSBI_SIZE = 512 * SIZE_1KOPENSBI_FDT_ADDR = MONITOR_ADDR + OPENSBI_SIZE
    

    可知:

    • Opensbi镜像运行地址:0x80000000;大小:512KB;
  • --LOADER_2ND='${SDK_TOP}/u-boot-2021.10/build/cv1813h_milkv_duos_sd/u-boot-raw.bin' \,U-boot定义为LOADER_2ND;

    借鉴ATF,MilkV将Risc-V下的U-boot等同于ATF中的BL32;

        # ===================# FSBL and u-boot-2021# ===================CVI_UPDATE_HEADER_SIZE = SIZE_1KUIMAG_SIZE = 16 * SIZE_1M# kernel image loading bufferUIMAG_ADDR = DRAM_BASE + 24 * SIZE_1M...# u-boot's run address and entry pointCONFIG_SYS_TEXT_BASE = DRAM_BASE + 2 * SIZE_1M
    

    可知:

    • U-boot运行地址:0x8020000(内存偏移2MB);大小:2MB;

实际也可在生成的链接脚本中验证如上内容,在链接脚本blmacros.ld中可查找到如下内容:

# fsbl/build/cv1813h_milkv_duos_sd/blmacros/blmacros.ldSECTIONS {...DEF_DRAM_BASE = 0x80000000;DEF_MONITOR_RUNADDR = 0x80000000;DEF_BLCP_2ND_RUNADDR = 0x9fe00000;

启动流程

​ 由上一章节可知追寻着BLCP_2ND的引用位置即可知晓RTOS如何加载启动,如头文件:

// fsbl/plat/sg200x/include/mmap.h#define BLCP_2ND_RUNADDR CVIMMAP_FSBL_C906L_START_ADDR// fsbl/build/cvi_board_memmap.h 软链指向如下实体文件
// build/output/cv1813h_milkv_duos_sd/cvi_board_memmap.h#define CVIMMAP_FSBL_C906L_START_ADDR 0x9fe00000  /* offset 510.0MiB */

​ 然而在FSBL源码中没有找到任何一处直接引用该宏定义的位置,所以可以有推论:FSBL并非直接编码该地址信息,而是间接传递地址信息。实际使用有可知,引导文件fip.bin是按对列的要求拼接的,这个其中就包含了关键信息BLCP_2ND_RUNADDR

所以先要对fip.bin文件的组成有一个了解。

fip文件组成

​ 参考SG200x厂商算能的手册信息,有fip.bin镜像结构与启动流程如下:

在这里插入图片描述

而只是大致的分部结构,参考Python打包脚本与结构定义头文件可以整理出具体的结构大小与分布,文件如下:

  • fsbl/plat/sg200x/fiptool.py,fip.bin文件的python生成脚本;

    class FIP下可以看到param1、body1、param2、body2的定义;

  • fsbl/plat/sg200x/include/bl2.h,param2 结构体定义;

  • fsbl/plat/${CHIP_ARCH}/include/platform.h,param1 结构体定义;

整理后的内容如下:

在这里插入图片描述

可知:

  1. Body1中第一个镜像是BLCP,由目标fip章节可获知BLCP的信息:

            --BLCP_IMG_RUNADDR=0x05200200 \--BLCP_PARAM_LOADADDR=0 \--BLCP=test/empty.bin \
    

    其中:

    • BLCP,即镜像文件,指向:${FSBL_DIR}/test/empty.bin,如其名内容为空,大小为0;
    • 因为BLCP为空,所以其加载地址(BLCP_PARAM_LOADADDR)与运行地址(BLCP_IMG_RUNADDR)信息就不太有参考价值;
  2. Body1中第二个镜像是BL2,同上可获知BL2的信息:

            --BL2='${SDK_TOP}/fsbl/build/cv1813h_milkv_duos_sd/bl2.bin' \
    

    其中:

    • BL2,即FSBL镜像文件,指向:${FSBL_DIR}/build/cv1813h_milkv_duos_sd/bl2.bin,大小33KB;
    • FSBL是一个阶段的统称,BL2是其中的一个小部分;
    • 在BL2阶段,完成工作:DDR 初始化;
  3. Body2中第一个镜像是DDR_PARAMM,可获知DDR_PARAM信息

            --DDR_PARAM='test/sophon/ddr_param.bin' \
    

    其中:

    • DDR_PARAM,即DDR初始化参数,指向:${FSBL_DIR}/test/sophon/ddr_param.bin,大小:8KB;
    • 十六进制方式查看,未能看到什么组织规范,可能是按特定的数据结构组织也可能是加密过,尝试在BL2中查看这个文件如何使用的才能知晓;
  4. Body2中等二个文件是:BLCP_2N,可获知信息:

            --BLCP_2ND_RUNADDR="${BLCP_2ND_RUNADDR}" \--BLCP_2ND='${SDK_TOP}/freertos/cvitek/install/bin/cvirtos.bin' \
    

    其中:

    • BLCP_2ND,即第二个BLCP镜像文件,指向:${SDK_TOP}/freertos/cvitek/install/bin/cvirtos.bin,大小:14KB;
    • 这即是我们查找的RTOS镜像文件,其运行地址为:0x9FE0_0000;
  5. Body2中的Monitor、LOADER_2ND再分析;

综上,如果按Body的组织顺序应有启动流程:BLCP => BL2 => BLCP_2ND => MONITOR => LOADER_2ND 。

而BLCP为空,结合实际内容启动流程为:bl2 => FreeRTOS => opensbi => U-boot;

所以可以有猜测:bl2 完成了FreeRTOS的引导启动工作。

BL2程序

​ 由章节编译框架章节可知:FSBL最终是为了生成fip.bin文件,其依赖于bl2.bin文件。Makefile中的目标依赖关系也是如此:

# fsbl/Makefile
$(eval $(call MAKE_BL,2))# fsbl/make_helpers/build_macros.mk
# MAKE_BL macro defines the targets and options to build each BL image.
# Arguments:
#   $(1) = BL stage (2, 2u, 30, 31, 32, 33)
#   $(2) = FIP command line option (if empty, image will not be included in the FIP)
define MAKE_BL$(eval BUILD_DIR  := ${BUILD_PLAT}/bl$(1))$(eval BL_SOURCES := $(BL$(call uppercase,$(1))_SOURCES))$(eval SOURCES    := $(BL_SOURCES))$(eval OBJS       := $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES))))$(eval LINKERFILE := $(call IMG_LINKERFILE,$(1)))$(eval MAPFILE    := $(call IMG_MAPFILE,$(1)))$(eval ELF        := $(call IMG_ELF,$(1)))$(eval SYM        := $(call IMG_SYM,$(1)))$(eval DUMP       := $(call IMG_DUMP,$(1)))$(eval BIN        := $(call IMG_BIN,$(1)))$(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE))     
...
$(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs	# 生成$(OBJS) $(LINKERFILE)前需要先保证 bl$(1)_dirs 目标已经创建@echo "  LD      $$@"@echo 'const char build_message[] = $(BUILD_MESSAGE_TIMESTAMP); \const char version_string[] = "${VERSION_STRING}";' | \$$(CC) $$(TF_CFLAGS) $$(CFLAGS) -xc -c - -o $(BUILD_DIR)/build_message.o	# 定义两个变量保存编译信息并编译生成目标文件build_mesage.o,再后面链接过程中会被用到$$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) -Map=$(MAPFILE) \--script $(LINKERFILE) $(BUILD_DIR)/build_message.o ${BL2_RLS_OBJS} $(OBJS) $(LDLIBS)
...
$(BIN): $(ELF)@echo "  BIN     $$@"$$(Q)$$(OC) -O binary $$< $$@			# 使用${CROSS_COMPILE}objcopy,从elf转化为bin;@${ECHO_BLANK_LINE}@echo "Built $$@ successfully"@${ECHO_BLANK_LINE}.PHONY: bl$(1)
bl$(1): $(BIN) $(SYM) $(DUMP)$$(print_target)
...
endef

可知:

  • bl$(1),即bl2,依赖于目标:$(BIN)、$(SYM)、$(DUMP)分别对应${SDK_TOP}/fsbl/build/${CHIP_ARCH}目录下的:bl2.bin,bl2.sym、bl2.dis;

  • $(BIN),即bl2.bin,依赖于目标:$(ELF),即bl2.elf;

    其生成方法为:使用工具链的objcopy工具由ELF格式文件bl2.elf生成二进制文件bl2.bin。

  • ELF,即bl2.elf,依赖于目标:$(OBJS) $(LINKERFILE)

    其生成方法为:

    1. $(CC) 。。。 -xc -c - -o $(BUILD_DIR)/build_message.o,生成版本信息文件build_mesage.o:使用管道将标准输入编辑为目标文件;

      注:-参数通常是用来表示要编译的源文件的位置,如果没有指定具体的源文件名,可能是表示要从标准输入读取源代码。

    2. $(LD) -o $$@ 。。。 --script $(LINKERFILE) $(BUILD_DIR)/build_message.o ${BL2_RLS_OBJS} $(OBJS) $(LDLIBS),bl2.elf链接方法,其中:

      • --script $(LINKERFILE),指定链接脚本:$(LINKERFILE),即:BL_LINKERFILE -> BL2_LINKERFILE -> plat/${CHIP_ARCH}/bl2/bl2.ld.S;
      • $(BUILD_DIR)/build_message.o,保存编译信息的目标文件,bl2.elf依赖的目标文件之一;
      • $(OBJS),依赖的目标文件,bl2.bin依赖的主要目标文件,即:OBJS ->来源于所有源码文件(*.c *.s): SOURCES -> BL_SOURCES -> BL2_SOURCES ,具体有哪些源码文件由${CHIP_ARCH}下的platform.mk文件决定,如:fsbl/plat/sg200x/platform.mk;
      • ${BL2_RLS_OBJS} $(LDLIBS),为空,不用关注;

综上可知:bl2.bin 文件由bl2.elf文件而来,bl2.elf文件由bl2源码编译链接而来。bl2.elf文件的链接由链接脚本plat/${CHIP_ARCH}/bl2/bl2.ld.S决定:

#include <platform.h>#ifdef __riscvOUTPUT_FORMAT("elf64-littleriscv")OUTPUT_ARCH(riscv)
...
#endif
ENTRY(bl2_entrypoint)				# 入口MEMORY {RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_SIZE			# 0x0C000000, 0x37000(220KB)
...        
SECTIONS
{. = BL2_BASE;					# 代码段从SRAM起始位置

可知:

  • ENTRY(bl2_entrypoint),bl2.elf程序的主入口为符号:bl2_entrypoint;
  • BL2在SRAM上运行,起始地址 0x0C00_0000,大小 0x3_7000(220KiB);1

milkV-Duo主干源码SDK中的fsbl未完全开放源码,因此需要从另一个fsbl仓库拉源码替换到主干SDK的fsbl目录。

  • MilkV Duo 主干SDK源码仓库:https://github.com/milkv-duo/duo-buildroot-sdk;
  • FSBL开源的源码仓库:https://github.com/milkv-duo/fsbl;

取在fsbl源码中查找该程序入口符号,查找到:fsbl/lib/cpu/riscv/bl2_entrypoint.S

bl2_entrypoint:				# 入口j bl2_entrypoint_real	# 调用真正入口:bl2_entrypoint_real.word 0 // resvered
...
bl2_entrypoint_real:atf_state_set x28, x29, ATF_STATE_BL2_ENTRY_POINT		# 将值ATF_STATE_BL2_ENTRY_POINT写入寄存器REG_GP_REG1li x1, 0					# 通用寄存器清零...						# 为跳转到C语言环境做准备,涉及:#	mtvec 向量表;plic 中断控制器;I-Cache、D-cache 缓存;BSS段清零;;call bl2_main				# 调用C程序入口bl2_mainj die
...

可知:

  • bl2_entrypoint只是纸面入口,实际起作用是bl2_entrypoint_real;
  • atf_state_set,使用寄存器REG_GP_REG1保存当前启动状态,对应关系:bl2_entrypoint -> ATF_STATE_BL2_ENTRY_POINT(0xB2000000);
  • bl2_entrypoint_real使用risc-v汇编代码编写,主要完成C语言环境的初始化工作,最终由bl2_mian进入C程序;

查找bl2_main入口,查找到:fsbl/plat/${CHIP_ARCH}/bl2/bl2_main.c,如:fsbl/plat/sg200x/bl2/bl2_main.c

// fsbl/plat/sg200x/bl2/bl2_main.cvoid bl2_main(void)uint32_t v = p_rom_api_get_boot_src();		// 查看启动方式;...set_baudrate();								// 串口设置波特率:115200ATF_STATE = ATF_STATE_BL2_MAIN;				// 更新寄存器REG_GP_REG1,记录启动状态time_records->fsbl_start = read_time_ms();NOTICE("\nFSBL %s:%s\n", version_string, build_message);	// 打印“编译信息”,关键信息打印...load_ddr();					// DDR 初始化for (retry = 0; retry < p_rom_api_get_number_of_retries(); retry++) {if (load_param2(retry) < 0)			// 从Flash中载入fip_param2到SRAMcontinue;if (load_ddr_param(retry) < 0)		// 从Flash中载入DDR_PARAM到SRAMcontinue;。。。ddr_init(&sram_union_buf.ddr_param);// DDR初始化load_rest(mode);			// 加载拿下启动程序到DDR并跳转运行NOTICE("BL2 end.\n");		// 此后的内容不应执行,因为在load_rest中就跳转到LOADER_2ND与MONITOR;while (1);

可知:

  • p_rom_api_get_boot_src为rom中芯片中固化的BL1程序符号,此时还是实模式直接调用。该接口用于获取当前的启动模式,又大致分为两大类:

    1. Flash启动,包含:SPI_NAND、SPI_NOR、EMMC;
    2. 下载启动,包含:SD、USB、UART;
  • ATF_STATE = ATF_STATE_BL2_MAIN,更新寄存器REG_GP_REG1,标记已经进入bl2_main阶段;

  • NOTICE("\nFSBL %s:%s\n", version_string。。。,即设备上电时打印的版本信息,内容即来自BL2程序章节中提及的build_mesage.o文件;

  • load_ddr(),DDR初始化,暂不完全展开。可知:在DDR初始化前,完成了读取SD卡中fip_param2、ddr_param文件到SRAM中

    load_param2(retry)NOTICE("P2S/0x%lx/%p.\n", sizeof(fip_param2), &fip_param2);            p_rom_api_load_image(&fip_param2, fip_param1->param2_loadaddr, PARAM2_SIZE, retry);
    

    可知:

    • 调用p_rom_api_load_image接口完成:从SD卡拷贝fip_param2到SRAM中,其中fip_param2加载地址在fip_param1.param2_loadaddr中记录

    • ddr_param类似,但其加载地址记录在fip_param2中,具体为:fip_param2.ddr_param_loadaddr;

    • 实际打印信息如下:

      P2S/0x1000/0xc00a400.
      SD/0x9400/0x1000/0x1000/0.P2E.
      

      可知:fip_param2 大小为4KB,将从SD卡地址0x1000 拷贝到SRAM地址0x0C00_A400(非固定值,在bl2.elf链接时确定);

  • load_rest(mode),BL2程序的主要初始化工作,需要单独展开说明。另外,这部分的工作都转入DDR环境中运行;

  • NOTICE("BL2 end。。。,不应执行到这个位置,因为在此之前就已经跳转到MONITOR阶段,所以在上电启动日志打印中看不到这个内容;

综上可知:bl2_main直接展现的内容较少,需要再跟进loader_rest实现。

loader_rest的实现在路径:fsbl/plat/${CHIP_ARCH}/bl2/bl2_opt.c,如:fsbl/plat/sg200x/bl2/bl2_opt.c

struct fip_param1 *fip_param1 = (void *)PARAM1_BASE;			// fip_param1 地址,关键信息
static struct fip_param2 fip_param2 __aligned(BLOCK_SIZE);int load_rest(enum CHIP_CLK_MODE mode)。。。sys_pll_init(mode);    		// PLL锁相环,时间初始化load_blcp_2nd(retry);		// BLCP_2NC 加载。。。time_records->release_blcp_2nd = time_records->ddr_init_end;// 启动时间记录NOTICE("C2S/0x%x/0x%x/0x%x.\n", fip_param2.blcp_2nd_loadaddr, fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_size);if (!fip_param2.blcp_2nd_runaddr) {		// 检查运行地址是否为空,即是否存在bl2程序if (!IN_RANGE(fip_param2.blcp_2nd_runaddr, DRAM_BASE, DRAM_SIZE)) {	// 检查blcp_2nd 运行地址是否在DRAM范围内?if (!IN_RANGE(fip_param2.blcp_2nd_runaddr + fip_param2.blcp_2nd_size, DRAM_BASE, DRAM_SIZE)) {	// 检查blcp_2nd 大小是否超出DRAM范围?p_rom_api_load_image((void *)(uintptr_t)fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_loadaddr, fip_param2.blcp_2nd_size, retry);        crc = p_rom_api_image_crc((void *)(uintptr_t)fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_size);       ret = dec_verify_image((void *)(uintptr_t)fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_size, 0, fip_param1);        flush_dcache_range(fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_size);rtos_base = mmio_read_32(AXI_SRAM_RTOS_BASE);init_comm_info(0);。。。      if (rtos_base == CVI_RTOS_MAGIC_CODE) {mmio_write_32(AXI_SRAM_RTOS_BASE, fip_param2.blcp_2nd_runaddr);        } else {reset_c906l(fip_param2.blcp_2nd_runaddr);NOTICE("RSC.\n");				// 小核启动前,打印:RSC.mmio_clrbits_32(0x3003024, 1 << 6);            mmio_setbits_32(SEC_SYS_BASE + 0x04, 1 << 13);mmio_write_32(SEC_SYS_BASE + 0x20, reset_address);			// 将RTOS入口地址低32位写入寄存器:0x020B_0020mmio_write_32(SEC_SYS_BASE + 0x24, reset_address >> 32);	// 将RTOS入口地址高32位写入寄存器:0x020B_0024mmio_setbits_32(0x3003024, 1 << 6);

分析如下:

  • fip_param1 = (void *)PARAM1_BASE,fip_param1地址直接由宏硬编码定义,值为:0x0C03_9000。2

  • sys_pll_init(mode),load_rest过程中先对时钟系统进制初始化,暂不展开;

  • load_blcp_2nd(retry),即加载RTOS镜像到DDR中运行,其中有如下过程:

    • NOTICE("C2S/0x%x/0x%x。。。,启动打包信息,C2S解释:C2,BLCP_2ND;S,Start;

      实际打印如:C2S/0xc400/0x9fe00000/0x3600.,即加载地址0xc400拷贝rtos镜像到DDR地址0x9fe0_0000,镜像大小0x3600;

    • RTOS镜像有效性检查,包含:文件是否为空,运行地址是否有效,大小是否溢出?

    • 真正执行向运行地址的镜像搬移;

    • CRC验证搬移过程中无差错;

    • 解密与检验RTOS镜像(未使能安全启动时,动作为空);

    • 刷新RTOS镜像范围内的D-Cache;

    • 检查寄存器AXI_SRAM_RTOS_BASE(地址:0x0E00_007C)是否为默认值CVI_RTOS_MAGIC_CODE(值:0xABC0DEF);

      • 如果仍为默认值,寄存器0x0E00_007C中写入RTOS运行地址:fip_param2.blcp_2nd_runaddr,即:0x9FE0_0000;
      • 如不为默认值(实现测试),寄存器0x020B_0000中写入RTOS运行地址:0x9FE0_0000,重启C906小核开始运行RTOS;

      关于这个AXI_SRAM_RTOS_BASE标致检测,猜测可能是一种防重入机制,具体原因与开源开发同事确认中。

至此找到了小核引导RTOS的启动的关键实现。

总结

​ 本文主要记录MilkV DuoS 上是如何引导C906L小核运行RTOS的记录,介绍从编译框架、文件打包、源码跟读方式最终确认找到启动入口,过程中记录了一些特别的收获,这其中包含:

  • Makkefile,一些对列属性的使用,如:.DEFAULT_GOAL、MAKEOVERRIDES;一些特别的目标文件生成方法,如:$(CC) 。。。 -xc -c - -o $(BUILD_DIR)/build_message.o,由标准输入生成目标文件;BL1固定符号地址,由BL2来调用,如:p_rom_api_load_image
  • Python,结构体数据的表达,如:Entry.make("MAGIC1", 8, int, b"CVBL01\n\0"),;文件的拼接,如:generate_fip
  • 启动流程,RISC-V兼容ARM的启动流程,可以OpenSbi等效于ARM中的BL31;
  • C906核启动方式较C910手册中提及的方式相似------向寄存器BOOT_REG写入程序入口地址,重启即完成该核的启动;

回顾整个小核CPU引导RTOS启动流程的梳理,即使有一些前置工作,但好像还是有些简单粗暴,可能这是THead系列的特别设计。**庆幸的是MilkV DuoS有两个小核,所以可以切换到A53核引导RTOS的,再梳理一篇。

思考

  1. BootRom 属于不开放的BL1,而BL2中也会有多处调用BL1接口的地方,说明BL1已经集成很多基础的、使用概率较高的实现。

    从行业方案看来,这与树莓派等硬件不开源的方案相类似,形成了一种趋势:随着IC厂商BL1功能变得愈发完备,板级适配(DDR等)工作也由IC厂商完成,最终产品端的BSP开发的需求将会变得越来越弱。

备注

// fsbl/plat/sg200x/include/platform_def.h
#define TPU_SRAM_ORIGIN_BASE 0x0C000000
#define TPU_SRAM_SIZE 0x40000 // 256KiB#if ROM_LOCATION == ROM_LOCATION_HSPERI_ROM#ifdef __riscv#define ROM_BASE 0x04418000 				// no mirrored address for c906b#define TPU_SRAM_BASE TPU_SRAM_ORIGIN_BASE 	// no mirrored address for c906b#define SYSMAP_MIRROR_OFFSET 0x20000000
// -------------------------------------------------
// fsbl/plat/sg200x/include/mmap.h
#define BL_RAM_BASE TPU_SRAM_BASE
#define BL2_BASE (BL_RAM_BASE)
#define BL2_SIZE (0x37000)
#define BOOT_LOG_BUF_BASE (BL2_BASE + BL2_SIZE)
#define BOOT_LOG_BUF_SIZE 0x2000
#define PARAM1_BASE (BOOT_LOG_BUF_BASE + BOOT_LOG_BUF_SIZE)// 转化PARAM1_BASE(BOOT_LOG_BUF_BASE + BOOT_LOG_BUF_SIZE)((BL2_BASE + BL2_SIZE) + BOOT_LOG_BUF_SIZE)		0x0C000000 + 0x37000 + 0x2000 = 0x0C03_9000

  1. SRAM 起始地址:0x0C00_0000,大小:0x3_9000(256KiB),即bl2.bin之后还有剩余36KiB空间。 ↩︎

  2. PARAM1_BASE换算 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/800357.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Mybatis】Mybatis 二级缓存全详解教程

【Mybatis-Plus】Mybatis-Plus 二级缓存全详解 一&#xff0c;Mybatis-Plus介绍 MyBatis-Plus&#xff08;简称MP&#xff09;是一个基于 MyBatis 的增强工具&#xff0c;它简化了 MyBatis 的开发&#xff0c;并且提供了许多便利的功能&#xff0c;帮助开发者更高效地进行持久…

数字电路基础(Digital Circuit Basis )

目录 一、什么是数字电路&#xff1f; &#xff08;Digital Circuit &#xff09; 1.概念 2.分类 3.优点 4.数电与模电的区别 二、数制 (十进制&#xff1a;Decimal) 1.概述 2.进位制 3.基数 4.位权 5.二进制的算术运算 三、编码 (二进制&#xff1a;Binary ) 1.什…

JAVA8新特性

JAVA8新特性 1、函数式编程 主要关注对数据进行了什么操作 1.1 优点 代码简洁 容易理解 易于“并发编程” 2、lamada表达式 (参数列表)->{代码}未使用 new Thread(new Runnable() {Overridepublic void run() {System.out.println(123123123);}}).start(); 使用…

CSS常见样式

字体相关的样式 <style>div{/* 斜体 */font-style: italic;/* 加粗 100-900*/font-weight: 900;/* 字体大小 */font-size: 20px;/* 声明字体格式 */font-family: "微软雅黑";}</style> div内部文字垂直居中 只需要将行高设为其height的大小即可。 div{…

B2985A是德科技B2985A静电计

181/2461/8938产品概述&#xff1a; B2985A 静电计/高阻表具有 0.01 fA&#xff08;0.01 x 10-15 A&#xff09;的分辨率&#xff0c;可帮助您信心十足地测量小电流和最高可达 10 PΩ&#xff08;10 x 1015 Ω&#xff09;的大电阻。 它拥有 4.3 英寸 LCD 彩色液晶屏并配有图形…

WebGL异步绘制多点

异步绘制线段 1.先画一个点 2.一秒钟后&#xff0c;在左下角画一个点 3.两秒钟后&#xff0c;我再画一条线段 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"…

redis的简单操作

redis中string的操作 安装 下载可视化软件&#xff1a;https://gitee.com/qishibo/AnotherRedisDesktopManager/releases。 Mac安装redis&#xff1a; brew install redisWindows安装redis: 安装包下载地址&#xff1a;https://github.com/tporadowski/redis/releases 1.…

C++:类和对象(上)

1.类的引入 C语言结构体中只能定义变量&#xff0c;在C中&#xff0c;结构体内不仅可以定义变量&#xff0c;也可以定义函数&#xff0c;同时C引入class关键字来也能实现这一作用&#xff0c;C更喜欢用class class/struct Stack {int * _array;size_t _capacity;size_t _size…

3.5、文本显示(Text/Span)

创建文本 Text 可通过以下两种方式来创建: string 字符串 效果图 Text(我是一段文本)引用 Resource 资源 资源引用类型可以通过 $r 创建 Resource 类型对象,文件位置为 /resources/base/element/string.json。 引用的资源位于:src/main/resources/base/element/string…

海外仓订单管理存在哪些问题?利用位像素海外仓系统能提升订单管理效率吗?

随着跨境电商业务的蓬勃发展&#xff0c;海外仓的订单量日益攀升&#xff0c;在海外仓的运作中&#xff0c;订单管理是一项看似简单实则复杂繁琐的任务。 然而&#xff0c;大批量订单的涌入&#xff0c;让其管理背后隐藏的问题也随机出现。让我们一起来看看有哪些问题吧&#…

一二三应用开发平台使用手册——系统管理-组织机构-使用说明

概述 平台文档是平台的重要组成部分&#xff0c;这块容易被忽视或不被重视。即使一个平台或系统架构优秀、设计合理、代码优雅&#xff0c;但文档缺失&#xff0c;对于平台的使用方而言&#xff0c;熟悉成本高、难度大。不可避免存在疑问&#xff0c;需要动手尝试验证或翻看源…

(表征学习论文阅读)A Simple Framework for Contrastive Learning of Visual Representations

Chen T, Kornblith S, Norouzi M, et al. A simple framework for contrastive learning of visual representations[C]//International conference on machine learning. PMLR, 2020: 1597-1607. 1. 前言 本文作者为了了解对比学习是如何学习到有效的表征&#xff0c;对本文所…

LeetCode题练习与总结:螺旋矩阵Ⅱ--59

一、题目描述 给你一个正整数 n &#xff0c;生成一个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]示例 2&#xff1a; 输入&#xff1…

VMware启动显示“打开虚拟机时出错: 获取该虚拟机的所有权失败”

提示框&#xff08;忘截图了&#xff09;里提示目录C:\Users\mosep\Documents\Virtual Machines\VM-Win10 x64\中的某个文件&#xff08;在我这里好像是VM-Win10 x64.vmx&#xff0c;VM-Win10 x64是我给虚拟机取的名字&#xff09;在被使用中。 找到这个目录&#xff0c;删除.…

【面试题】如何在亿级别用户中检查用户名是否存在?

前言 不知道大家有没有留意过&#xff0c;在使用一些app或者网站注册的时候&#xff0c;提示你用户名已经被占用了&#xff0c;比如我们熟知的《英雄联盟》有些人不知道取啥名字&#xff0c;干脆就叫“不知道取啥名”。 但是有这样困惑的可不止他一个&#xff0c;于是就出现了“…

如何从应用商店Microsoft Store免费下载安装HEVC视频扩展插件

在电脑上打开一张HEIC类型的图片提示缺少HEVC解码器&#xff0c;无法打开查看&#xff0c;现象如下&#xff1a; 这种情况一般会提示我们需要下载安装HEVC解码器&#xff0c;点击“立即下载并安装”会跳转到应用商店&#xff0c;但是我们发现需要付费7元才能下载安装 免费安装…

6. Z 字形变换(Java)

目录 题目描述&#xff1a;输入&#xff1a;输出&#xff1a;代码实现&#xff1a; 题目描述&#xff1a; 将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING” 行数为 3 时&#xff0c;排列如…

mac | Windows 本地部署 Seata2.0.0,Nacos 作为配置中心、注册中心,MySQL 存储信息

1、本人环境介绍 系统 macOS sonama 14.1.1 MySQL 8.2.0 &#xff08;官方默认是5.7版本&#xff09; Seata 2.0.0 Nacos 2.2.3 2、下载&数据库初始化 默认你已经有 Nacos、MySQL&#xff0c;如果没有 Nacos 请参考我的文章 &#xff1a; Docker 部署 Nacos&#xff08;单机…

订阅edk2社区邮件列表

给社区发邮件步骤 UEFI订阅邮件列表 开发者订阅邮箱 develedk2.groups.io | Home 点击Join This Group&#xff0c;按照步骤填写自己邮箱地址&#xff08;该地址是edk2,发送邮件到该邮箱的地址&#xff09; 自己邮箱确认就可以自动收到邮件了 比如&#xff1a;

虚拟串口工具vspd.exe的使用

关于vspd虚拟串口工具的获取&#xff1a; 工具下载 &#xff08;1、 虚拟串口工具官方下载链接 2、通过本文资源下载&#xff09;工具按照步骤&#xff08;过于简单&#xff0c;此处省略&#xff09; 关于vspd虚拟串口工具的使用&#xff1a; 打开软件&#xff0c;如下&…