SG2002(CVITEK) Linux+RTOS异构操作系统bootloader构建与启动分析
性能or实时:为什么要搞异构
前几年的时候,性能核配实时核的国内SOC市场突然迎来爆炸,各大开发板厂商也逐渐跟进,相较于经典款MCU或者x86的CPU,这些个芯片一边具备着“古法嵌入式”的实时能力,一边又有一个或多个配备MMU的核心运行高性能任务,享受Linux丰富的软件栈与敏捷开发。
在更早的时候,许多工业项目已经有此类需求,例如Klipper的大量轨迹计算与补偿+精确时刻微步,无人机的高级导航功能+高频位姿估计,ZYNQ的PS+PL软核(好吧这个贵),机器人领域几乎需要复杂图形界面+高频控制闭环的东西都在某种程度上需要这一配置。如果能减轻一边盯着实时核一遍重造网络,界面,以及各种意想不到的轮子的痛苦,爱好者和研究人员很愿意付一颗额外SOC的钱,只不过需要用一根片外导线把高性能核心和实时核心链接在一起,外加忍受一些时间基准和各种自定义协议的麻烦。
尝试将性能核和实时核塞在同一个SOC的产物,iMX8和ST的MP1,似乎要比这些国产SOC稍早一些,不过那个时候的物联网要求似乎还没那么广泛,很多还是哑终端,他们更多面向工业和专业场景。
而今天,物联网设备想要彩色大屏+低功耗待机,机器人想要智慧的AI大脑+上百Hz的控制闭环,而且都要便宜,如果一块SOC能解决就不要上[一块高性能SOC+DRAM+EMMC+一块嵌入式核心+片外Flash]。而今天的主角SG2002则是把大部分能塞在一起的塞在一起的其中之一(的廉价款芯片)。这些使得简单的物联网,基础的DL+控制任务无需传统的MPU+MCU构造,甚至一些型号具备了SIP的运行内存,可以狠狠的减小板子面积了。
P.S. 本文写于2024年,从公众号迁移到Blog,仅限对写作时所用最新构建脚本进行分析
芯片框图与初次编译
本文所使用的开发板是milk-v-duo 256M,其上搭载了一颗算能科技(sophgo)公司的sg2002 SOC。这个芯片一共有四个核心,一个A53性能核,一个C906性能核,一个C906实时核,一个8051低功耗核。离谱的是那两个性能核只能选一个启动(。后文将这个C906实时核心称为C906L。特色是它配有一个1Tops的NPU,明显是和全志和堪楠比划比划。其他的配置就中规中矩,两组SDIO,支持高速SPI,和一堆以通信为主的外设。不过国产SOC的通病,这个芯片的资料写的也不太全。

尽管爱好者最常见的开发方式是micropython和Arduino框架,但是要完全发挥它的性能,依然建议使用官方提供的linux+FreeRTOS SDK,本文章基于milk-v开源社区移植的SDK来写。https://github.com/milkv-duo/duo-buildroot-sdk
首先把SDK的仓库clone下来,并按照README完成配置和编译all目标,编译过程在8核CPU上大约需要半个小时。编译成功后,会在install目录下生成以下几个升级文件。

因为写太多大家也不会看完,所以本文只分析一些fip.bin的构建和运行过程(使用risc-v核心)(sd卡启动),也就是从上电开始,到linux内核启动前启动之前的程序。
构建脚本分析
首先简单分析一下构建过程。 仓库目录下的build脚本通过对不同板子的选择来调用预编写的config文件。 随后调用build/milkvsetup.sh 中的build_all函数,该函数准备(主要是环境变量)环境,并逐一启动所有构建与打包工作。
function build_all(){ # build bsp build_uboot || return $? build_kernel || return $? build_osdrv || return $? build_middleware || return $? pack_access_guard_turnkey_app || return $? pack_ipc_turnkey_app || return $? pack_boot || return $? pack_cfg || return $? pack_rootfs || return $? pack_data pack_system || return $? copy_tools pack_upgrade}fip.bin的构建工作由build_uboot函数完成
function build_uboot(){( print_notice "Run ${FUNCNAME[0]}() function" _build_uboot_env _build_opensbi_env _link_uboot_logo
cd "$BUILD_PATH" || return [[ "$CHIP_ARCH" == CV182X ]] || [[ "$CHIP_ARCH" == CV183X ]] && \ cp -f "$OUTPUT_DIR"/fip_pre/fip_pre_${ATF_KEY_SEL}.bin \ "$OUTPUT_DIR"/fip_pre/fip_pre.bin
make u-boot)}可以看到,完成环境准备后,主要构建实际上是由make完成
这个Makefile在build/ 目录下
找到u-boot目标
u-boot: u-boot-dep虽然说我们构建的是u-boot目标,实际上这个目标同时构建了fsbl+openSBI+FreeRTOS+u-boot并把他们打包嘞。
我们看到它只有一个u-boot-dep的依赖,这实际上是为了适应不同的fip构建流程,我们使用的是fip-v2,可以打开build/scripts/fip_v2.mk查看这个target
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.elfendif这一目标实际上构建了fsbl-build
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
FSBL_OUTPUT_PATH = ${FSBL_PATH}/build/${PROJECT_FULLNAME}ifeq ($(call qstrip,${CONFIG_ARCH}),riscv)fsbl-build: opensbiendififeq (${CONFIG_ENABLE_FREERTOS},y)fsbl-build: rtosfsbl%: export BLCP_2ND_PATH=${FREERTOS_PATH}/cvitek/install/bin/cvirtos.binfsbl%: 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}endiffsbl%: 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-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.binelse ${Q}cp ${FSBL_OUTPUT_PATH}/fip.bin ${OUTPUT_DIR}/fip_spl.binendiffsbl首先依赖opensbi,调用opensbi目录下的子Makefile完成构建,opensbi会先构建u-boot,并将u-boot与opensbi组合在一起,sd卡启动方式中似乎并未用到这一组合文件,所以不展开解释了。
随后fsbl依赖rtos,调用freertos下的cmake完成构建
实际在运行时,rtos与opensbi均被加载到DDR内,地址映射如下
#define CONFIG_SYS_TEXT_BASE 0x80200000 /* offset 2.0MiB */#define CVIMMAP_ATF_SIZE 0x80000 /* 512.0KiB */#define CVIMMAP_BOOTLOGO_ADDR 0x8b13e000 /* offset 177.2421875MiB */#define CVIMMAP_BOOTLOGO_SIZE 0x1c2000 /* 1.7578125MiB */#define CVIMMAP_CONFIG_SYS_INIT_SP_ADDR 0x82800000 /* offset 40.0MiB */#define CVIMMAP_CVI_UPDATE_HEADER_ADDR 0x817ffc00 /* offset 23.9990234375MiB */#define CVIMMAP_CVI_UPDATE_HEADER_SIZE 0x400 /* 1.0KiB */#define CVIMMAP_DRAM_BASE 0x80000000 /* offset 0.0KiB */#define CVIMMAP_DRAM_SIZE 0x10000000 /* 256.0MiB */#define CVIMMAP_FRAMEBUFFER_ADDR 0x8b13e000 /* offset 177.2421875MiB */#define CVIMMAP_FRAMEBUFFER_SIZE 0x1c2000 /* 1.7578125MiB */#define CVIMMAP_FREERTOS_ADDR 0x8fe00000 /* offset 254.0MiB */#define CVIMMAP_FREERTOS_RESERVED_ION_SIZE 0x1600000 /* 22.0MiB */#define CVIMMAP_FREERTOS_SIZE 0x200000 /* 2.0MiB */#define CVIMMAP_FSBL_C906L_START_ADDR 0x8fe00000 /* offset 254.0MiB */#define CVIMMAP_FSBL_UNZIP_ADDR 0x81800000 /* offset 24.0MiB */#define CVIMMAP_FSBL_UNZIP_SIZE 0x1000000 /* 16.0MiB */#define CVIMMAP_H26X_BITSTREAM_ADDR 0x8b300000 /* offset 179.0MiB */#define CVIMMAP_H26X_BITSTREAM_SIZE 0x200000 /* 2.0MiB */#define CVIMMAP_H26X_ENC_BUFF_ADDR 0x8b500000 /* offset 181.0MiB */#define CVIMMAP_H26X_ENC_BUFF_SIZE 0x0 /* 0.0KiB */#define CVIMMAP_ION_ADDR 0x8b300000 /* offset 179.0MiB */#define CVIMMAP_ION_SIZE 0x4b00000 /* 75.0MiB */#define CVIMMAP_ISP_MEM_BASE_ADDR 0x8b500000 /* offset 181.0MiB */#define CVIMMAP_ISP_MEM_BASE_SIZE 0x1400000 /* 20.0MiB */#define CVIMMAP_KERNEL_MEMORY_ADDR 0x80000000 /* offset 0.0KiB */#define CVIMMAP_KERNEL_MEMORY_SIZE 0xfe00000 /* 254.0MiB */#define CVIMMAP_MONITOR_ADDR 0x80000000 /* offset 0.0KiB */#define CVIMMAP_OPENSBI_FDT_ADDR 0x80080000 /* offset 512.0KiB */#define CVIMMAP_OPENSBI_SIZE 0x80000 /* 512.0KiB */#define CVIMMAP_UIMAG_ADDR 0x81800000 /* offset 24.0MiB */#define CVIMMAP_UIMAG_SIZE 0x1000000 /* 16.0MiB */但此时他们还是一个一个单独的bin文件,真正把他们组装到一起的代码在fsbl构建过程中
${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这里调用了fsbl目录下的make,并为其传递了BLCP_2ND(协处理器第二阶段镜像)与LOADER_2ND(加载器第二阶段镜像)地址
all: fip bl2 blmacros
include ${MAKE_HELPERS_DIRECTORY}fip.mk这是fsbl下主目标的依赖目标,fip目标在make_helpers/fip.mk下被定义
fip: fip-all
fip-dep: bl2 blmacros-env gen-chip-conf
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')fip目标首先完成bl2(第二阶段引导器)的构建,随后打包一些芯片配置。
最后终于到了震撼人心的时候,通过genfip工具把上面构建出来那一堆镜像打包成一个。
启动过程分析
这一套启动流程其实借鉴的是arm的ATF启动。

接下来我们借助ATF的启动流程理解一下整个异构操作系统是如何一步一步启动起来的
我们先来看看调试串口的日志信息
C. E:RES▒C. E:RES▒C. E:RES▒C. E:RE▒C. E:RESC.C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/0▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/▒C.SCS/0/0.WD.URPL.SDI/25000000/6000000.BS/SD.PS.SD/0x0/0x1000/0x1000/0.PE.BS.SD/0x1000/0x8400/0x8400/0.BE.J.FSBL Jb2829:g27ada50:2024-07-31T05:11:50+08:00st_on_reason=d0000st_off_reason=0P2S/0x1000/0xc00a400.SD/0x9400/0x1000/0x1000/0.P2E.DPS/0xa400/0x2000.SD/0xa400/0x2000/0x2000/0.DPE.cv181x DDR init.ddr_param[0]=0x78075562.pkg_type=5D1_3_2DDR3-2G-QFNData rate=1866.DDR BIST PASSPLLS.PLLE.C2S/0xc400/0x8fe00000/0x13200. R2TE:.00/0x13200/0x13200/0.RSC..[1M.S4/601x18f162]0P0r/e0x 8sy0s0t0e0m00 0in/i0tx 1dc2o0ne0
RT: [1.467648]CVIRTOS Build Date:Jul 31 2024 (Time :05:11:50)RT: [1.473222]Post system init doneRT: [1.476310]dump_print_enable & log will not printSD/0x1f600/0x1c200/0x1c200/0.ME.L2/0x3b800.SD/0x3b800/0x200/0x200/0.L2/0x414d3342/0xcafe8c84/0x80200000/0x37600/0x37600COMP/1.SD/0x3b800/0x37600/0x37600/0.DCP/0x80200020/0x1000000/0x81900020/0x37600/1.DCP/0x74182/0.Loader_2nd loaded.Use internal 32kJump to monitor at 0x80000000.OPENSBI: next_addr=0x80200020 arg1=0x80080000OpenSBI v0.9-56-gab9b8f8 ____ _____ ____ _____ / __ \ / ____| _ \_ _| | | | |_ __ ___ _ __ | (___ | |_) || | | | | | '_ \ / _ \ '_ \ \___ \| _ < | | | |__| | |_) | __/ | | |____) | |_) || |_ \____/| .__/ \___|_| |_|_____/|____/_____| | | |_|
Platform Name : Cvitek. CV181X ASIC. C906.Platform Features : mfdelegPlatform HART Count : 1Platform IPI Device : clintPlatform Timer Device : clintPlatform Console Device : uart8250Platform HSM Device : ---Platform SysReset Device : ---Platform Suspend Device : cvi-suspendFirmware Base : 0x80000000Firmware Size : 144 KBRuntime SBI Version : 0.3
Domain0 Name : rootDomain0 Boot HART : 0Domain0 HARTs : 0*Domain0 Region00 : 0x0000000074000000-0x000000007400ffff (I)Domain0 Region01 : 0x0000000080000000-0x000000008003ffff ()Domain0 Region02 : 0x0000000000000000-0xffffffffffffffff (R,W,X)Domain0 Next Address : 0x0000000080200020Domain0 Next Arg1 : 0x0000000080080000Domain0 Next Mode : S-modeDomain0 SysReset : yesDomain0 SysSuspend : yes
Boot HART ID : 0Boot HART Domain : rootBoot HART ISA : rv64imafdcvsuxBoot HART Features : scounteren,mcounteren,timeBoot HART PMP Count : 16Boot HART PMP Granularity : 4096Boot HART PMP Address Bits: 38Boot HART MHPM Count : 8Boot HART MHPM Count : 8Boot HART MIDELEG : 0x0000000000000222Boot HART MEDELEG : 0x000000000000b109
U-Boot 2021.10-gc8d23960 (Jul 31 2024 - 05:11:29 +0800) soph
DRAM: 254 MiBgd->relocaddr=0x8b0c8000. offset=0xaec8000MMC: cv-sd@4310000: 0Loading Environment from nowhere... OKIn: serialOut: serialErr: serialNet:Warning: ethernet@4070000 (eth0) using random MAC address - 22:e4:6e:4e:08:75eth0: ethernet@4070000Hit any key to stop autoboot: 0Boot from SD ...switch to partitions #0, OKmmc0 is current device最先运行的是BL1程序,这一程序由芯片厂商直接烧录进ROM里,上电或硬复位后从这里开始运行,它会最低限度的初始化时钟系统(低速),同时读取配置引脚以确定启动设备与启动A53计算核还是C906计算核心。这些任务准备完成后,如果启动设备为sd(emmc)设备,将会检查并装载FAT32文件系统,如果是裸烧,将从第一分区中载入fip.bin,如果已经烧录完成,将从boot分区中载入fip.bin
fip.bin是ATF启动中所需要的软件包,其中包含了各个阶段的镜像及其地址。
BL1程序随后从fip.bin中获得BL2程序的地址,并开始复制BL2程序。
注意,此时DDR还未被初始化,所以BL2不能被加载进DDR,让我们看看它的链接脚本。
MEMORY { RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_SIZE}哎,那么这个BL2_BASE在哪里呢?
在includes/mmap.h里面可以看到
#define BL_RAM_BASE TPU_SRAM_BASE#define BL_RAM_SIZE TPU_SRAM_SIZE
/* * IO buffer specific defines. * block IO buffer's start address and size must be block size aligned */#define BL2_BASE (BL_RAM_BASE)#define BL2_SIZE (0x37000)#define BL2_ENTRY_OFFSET 32其实BL2是被加载进神经网络加速器的SRAM下了
BL2的入口点在fsbl/lib/cpu/riscv下面,做的还是些搞一搞向量表,搞一搞标志位,搞一搞cache,搞一搞状态寄存器之类的任务,随后进入c环境bl2_main.
void bl2_main(void){ // Start of addition set_baudrate(); // End of addition
enum CHIP_CLK_MODE mode; uint32_t v = p_rom_api_get_boot_src();
if (v == BOOT_SRC_UART) { console_init(0, PLAT_UART_CLK_IN_HZ, UART_DL_BAUDRATE); }
ATF_STATE = ATF_STATE_BL2_MAIN; time_records->fsbl_start = read_time_ms();
NOTICE("\nFSBL %s:%s\n", version_string, build_message);
INFO("sw_info=0x%x\n", get_sw_info()->value); INFO("fip_param1: param_cksum=0x%x param2_loadaddr=0x%x\n", fip_param1->param_cksum, fip_param1->param2_loadaddr);
INFO("CP_STATE_REG=0x%x\n", mmio_read_32(0x0E000018));
// print_sram_log(); lock_efuse_chipsn();
setup_dl_flag();
switch_rtc_mode_1st_stage();
set_rtc_en_registers();
load_ddr();
#ifdef OD_CLK_SEL mode = CLK_OD;#else#ifdef VC_CLK_OVERDRIVE mode = CLK_VC_OD;#else mode = CLK_ND;#endif#endif load_rest(mode); NOTICE("BL2 end.\n");
while (1) ;}也就是说,调试信息的第二行开始FSBL:xxxxxx就是BL2已经启动的标志
后面的任务就很清晰了,初始化rtc域
随后load_ddr调用ddr初始化程序
也就是genfip中声明的DDR_PARAM镜像
随后我们看load_rest函数
int load_rest(enum CHIP_CLK_MODE mode){ int retry = 0; uint64_t monitor_entry = 0; uint64_t loader_2nd_entry = 0;
// Init sys PLL and switch clocks to PLL sys_pll_init(mode);
retry_from_flash: for (retry = 0; retry < p_rom_api_get_number_of_retries(); retry++) { if (load_blcp_2nd(retry) < 0) continue;
if (load_monitor(retry, &monitor_entry) < 0) continue;
if (load_loader_2nd(retry, &loader_2nd_entry) < 0) continue;
break; }
if (retry >= p_rom_api_get_number_of_retries()) { switch (p_rom_api_get_boot_src()) { case BOOT_SRC_UART: case BOOT_SRC_SD: case BOOT_SRC_USB: WARN("DL cancelled. Load flash. (%d).\n", retry); // Continue to boot from flash if boot from external source p_rom_api_flash_init(); goto retry_from_flash; default: ERROR("Failed to load rest (%d).\n", retry); panic_handler(); } }
sync_cache(); console_flush();
switch_rtc_mode_2nd_stage();
if (monitor_entry) { NOTICE("Jump to monitor at 0x%lx.\n", monitor_entry); jump_to_monitor(monitor_entry, loader_2nd_entry); } else { NOTICE("Jump to loader_2nd at 0x%lx.\n", loader_2nd_entry); jump_to_loader_2nd(loader_2nd_entry); }
return 0;}首先启动PLL,满频运行
load_blcp_2nd(协处理器第二阶段,在本项目中也就是FreeRTOS,函数会装载RTOS的镜像并校验,随后将实时核复位到FreeRTOS入口点
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("C2E.\n");
也就是这些调试信息
随后的load_monitor与load_loader_2nd只装载镜像,而不运行,随后在处理cache同步,更新rtc域后,正式跳转进入monitor,也就是openSBI,相当于ARM启动流程中的BL31,该程序初始化后将一直保留。
最后BL2将执行权限移交给loader_2nd也就是u-boot,随后u-boot初始化,准备引导内核镜像。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!