当前位置: 首页 > news >正文

`startup_gcc.S` 详细介绍(D13x):从复位到内核的完整路径

startup_gcc.S详细介绍(D13x)

ArtInChip D13xGCC 工具链下的RISC-V 启动汇编(典型为平头哥E907内核),负责:中断向量表、复位入口、早期硬件与 C 运行时准备,最后跳入内核或main。它与链接脚本、vectors.Sboot_param_gcc.Ssystem.c共同构成“上电 → 跑 RT-Thread/裸机”的第一段路径。


1. 在工程中的位置

角色说明
链接入口gcc_aic.ldENTRY(Reset_Handler),复位后 CPU 从Reset_Handler开始执行
代码段KEEP(*startup_gcc.o(*.text*))放在.text最前,保证复位代码不被优化掉
向量表KEEP(*startup_gcc.o(*.vectors*))放在.data段,与__global_pointer$等同在 SRAM
配套文件boot_param_gcc.S(保存启动参数)、vectors.S(默认/陷阱处理)、system.cSystemInit

上电后的调用链可概括为:

RT-Thread/FreeRTOS

其它

硬件复位

Reset_Handler

save_boot_params

save_boot_params_ret

mtvec/mtvt/gp/sp/缓存/TCM等

BSS清零 + reloc_private_params

SystemInit

内核类型

entry → rtthread_startup等

main


2. 文件结构概览

文件分三块:

  1. .section .vectors__Vectors中断向量表(100 项)
  2. Reset_Handler— 真正的启动逻辑
  3. __exit— 死循环兜底(正常不应到达)

3. 中断向量表__Vectors(第 11–118 行)

.section .vectors, "aw", @progbits .align 6 .globl __Vectors .type __Vectors, @object __Vectors: .long Default_Handler /* 0 */ ... .long PendSV_Handler /* 3 */ ... .long Default_IRQHandler /* 7 */ ... /* External interrupts */ .long Default_IRQHandler /* 16 */ ...

3.1 表项含义

  • 0–15:系统类异常/内部事件入口(多数先落到Default_Handler,再由vectors.S区分 trap / NMI)。
  • 3PendSV_Handler— 在KERNEL_BAREMETAL下由vectors.S实现,最终进trap;RTOS 场景下由内核提供真实实现。
  • 7:固定为Default_IRQHandler(与其它外部 IRQ 共用向量中断入口风格)。
  • 16–99:外部中断,默认均为Default_IRQHandler

表长100 × 4 字节,与 D13x CLIC 向量中断模型配合使用(具体 IRQ 号与芯片手册、aic_drv_irq.cdrv_irq_vectors_init一致)。

3.2 与mtvt的关系

后面Reset_Handler会执行:

la a0, __Vectors csrw mtvt, a0

这是T-Head 扩展 CSRmtvt:向量表基址。发生向量中断时,硬件按 IRQ 号从__Vectors取处理函数地址。
实际业务 IRQ 还会在SystemInitdrv_irq_vectors_init()里写入g_irqvector[],与Default_IRQHandler里的分发逻辑配合。

3.3 链接放置

向量表在.data(可写 RAM),不是只读 Flash。Bootloader/SPL 把镜像拷到 SRAM 后,表在运行地址上有效;若需要运行时改向量,也可写(本工程主要靠g_irqvector做二次分发)。


4.Reset_Handler:逐步解析

4.1 保存 Boot 参数(第 129–133 行)

Reset_Handler: .option push .option norelax j save_boot_params save_boot_params_ret:
  • j save_boot_params(实现在boot_param_gcc.S)。
  • SPL/Bootloader 跳转 OS 时会把a0–a7、s0–s11、sp、ra等写入boot_params_stash
  • a1 ≠ 0,还会把256 字节boot_arg从 SPL 拷到 OS 的boot_arg(DDR/资源等启动信息)。
  • 完成后j save_boot_params_ret回到本文件继续。

这样 OS 能保留上一阶段的启动上下文,供aic_get_boot_resource()reloc_private_params等使用。

4.2 全局指针与中断控制器初配(第 134–140 行)

la gp, __global_pointer$ .option pop la a0, Default_Handler ori a0, a0, 3 csrw mtvec, a0 la a0, __Vectors csrw mtvt, a0
步骤作用
la gp, __global_pointer$初始化 RISC-Vgp,访问小数据/.sdata.option norelax避免早期la被错误松弛
mtvec = Default_Handler | 3向量模式(低 2 位为 mode);未走mtvt的路径先进Default_Handler
mtvt = __Vectors绑定向量表,外部 IRQ 按表跳转

Default_Handlervectors.S里会检查mcause:若为NMI(24).NMI_Handler,否则j trap进统一异常/系统调用路径。

4.3 栈指针(第 142–148 行)

la sp, g_top_irqstack #ifdef CONFIG_THEAD_EXT_SPSWAPEN csrw mscratch, sp #endif #ifdef KERNEL_BAREMETAL la sp, g_top_normalstack #endif
  • 默认sp = g_top_irqstackvectors.Sg_base_irqstack+AIC_INTERRUPTSTACK_SIZE的栈顶)。
  • CONFIG_THEAD_EXT_SPSWAPEN:把该栈顶写入mscratch,配合 T-HeadSPSWAPEN在中断里换栈。
  • 裸机KERNEL_BAREMETAL:再切到g_top_normalstack,中断与主流程栈分离。

4.4 使能 I/D Cache(第 150–153 行)

la a5, icache_enable jalr a5 la a5, dcache_enable jalr a5

调用system.c中的icache_enable()/dcache_enable()(内部走aicos_*)。
SystemInit()里还会再次csi_icache_enable()/csi_dcache_enable(),属于“尽早开缓存 + 正式初始化再确认”的常见做法。

4.5 芯片相关早期硬件(第 155–198 行,#ifndef QEMU_RUN

仅在真实芯片编译,QEMU 仿真跳过。

行为
AIC_TCM_ENmitcmcr/mdtcmcr使能 ITCM/DTCM;开 SYSCFG 时钟;SYSCFG 寄存器使能 TCM
AIC_SRAM1_EN配置 SYSCFG 中 SRAM1 大小/使能位(AIC_SRAM_S1_REG_SIZE
PSRAM_UNCACHED_ENSYSMAP_ADDR6_ATTR,把 PSRAM 标为non-cacheable

地址注释在源码中(如 ITCM0x30040000、DTCM0x30060000、CMU/SYSCFG 基址),与aic_soc.h一致。

4.6 QEMU 下的.data拷贝(第 201–215 行)

#if defined(QEMU_RUN) la a0, __erodata la a1, __data_start__ la a2, __data_end__ ... la t0, dcache_clean jalr t0 #endif

QEMU 启动时可能没有 Bootloader 做LMA→VMA拷贝,因此在启动代码里把已初始化数据从 rodata 末尾(加载地址)拷到__data_start____data_end__,再dcache_clean。真机通常由 SPL 完成,故用QEMU_RUN隔开。

4.7 BSS 清零(第 217–225 行)

标准 C 运行时:对__bss_start____bss_end__按字写 0,保证未初始化全局/静态变量为 0。

4.8 私有参数重定位(第 227–229 行)

la a5, reloc_private_params jalr a5

实现在bsp/common/private_param/private_param.c:从 boot 资源里解析PDAT/私有配置(如 DDR 参数等),拷入private_params_stashaic_set_boot_resource(),供后续驱动/内存初始化读取。

4.9SystemInit(第 231–234 行)

#ifndef __NO_SYSTEM_INIT la a5, SystemInit jalr a5 #endif

system.c中主要做:

  • FPU、MXSTATUS(THEADISAEE、MM)、MEXSTATUS(SPUSHEN/SPSWAPEN)
  • CLIC配置、清 pending、设向量中断属性
  • 再次开 cache、使能Machine Software(用于上下文切换/软中断)
  • drv_irq_vectors_init()aic_gtc_enable()、时钟低功耗、CoreT/SysTick(非 baremetal)

4.10 进入内核或应用(第 236–242 行)

#if (defined(KERNEL_RTTHREAD) || defined(KERNEL_FREERTOS)) la a5, entry jalr a5 #else la a5, main jalr a5 #endif
  • RT-Threadentry()rtthread_startup()kernel/rt-thread/src/components.c),再建主线程跑main()
  • FreeRTOSentry()建任务并vTaskStartScheduler()
  • 裸机/其它:直接main()

entry/main返回后不会继续执行有用代码;文件末尾__exit: j __exit为死循环。


5. 与vectors.S的分工

符号所在文件职责
__Vectorsstartup_gcc.S硬件向量表(指针数组)
Default_IRQHandlervectors.S外部 IRQ:ipush、保存 FPU/上下文、查g_irqvector分发
Default_Handlervectors.Smtvec入口:NMI 或trap
PendSV_Handlervectors.S(baremetal)软件 PendSV →trap
g_top_irqstackvectors.S中断栈顶

startup_gcc.S只建表、不配具体外设 ISR;外设驱动通过drv_irq_register()等改g_irqvectoraic_drv_irq.c)。


6. 关键编译宏小结

影响
QEMU_RUN跳过 TCM/SRAM1/PSRAM 硬件初始化;增加.data拷贝
AIC_TCM_EN/AIC_SRAM1_EN/PSRAM_UNCACHED_EN内存子系统早期配置
KERNEL_BAREMETAL使用g_top_normalstackPendSV_Handlervectors.S
KERNEL_RTTHREAD/KERNEL_FREERTOS跳转entry
CONFIG_THEAD_EXT_SPSWAPEN设置mscratch
__NO_SYSTEM_INIT跳过SystemInit(特殊镜像/调试)

7. 与标准 RISC-V 启动的差异(便于对照学习)

  1. 双 CSRmtvec(带 mode 3)+mtvt向量表,属 T-Head/E907 常见组合。
  2. Boot 参数链:先save_boot_params再 C 环境,适配 SPL → OS 跳转。
  3. 向量表在 RAM.data,且项数固定 100。
  4. SoC 寄存器初始化写在汇编里(TCM/SYSMAP),而不是全部放在SystemInit
  5. 内核入口统一为entry,与 ARM 上-eentry习惯类似。

8. 调试时可关注的点

  • 若卡在复位:查 SPL 是否已拷.data、BSS 范围是否与gcc_aic.ld一致。
  • 若 IRQ 全进默认处理:查mtvt是否指向__VectorsSystemInit是否执行、drv_irq_vectors_init是否注册。
  • 若栈溢出:确认AIC_INTERRUPTSTACK_SIZEg_top_irqstack/mscratch配置。
  • QEMU 与真机构建选项不同,注意是否定义QEMU_RUN
http://www.jsqmd.com/news/864463/

相关文章:

  • 5分钟掌握全网盘直链下载:LinkSwift终极提速指南
  • Slack线程内直接触发Lindy流程审批?——2024最新Contextual Action集成方案(支持OpenID Connect身份透传)
  • CFD仿真散记
  • Java并发编程 并发可见性问题 volatile
  • 从文字对话到具象共情:具身 Agent 如何颠覆健康交互认知
  • Taotoken的模型广场如何帮助我快速选型与切换模型
  • 综合心理健康测试平台测评 专业全面心理评估公众号深度评测 - 时讯资讯
  • 简单谈谈ios开发中的UI
  • 终极指南:OBS Mac虚拟摄像头插件的完整使用教程
  • 使用Nodejs和Taotoken构建一个简单的AI对话服务端应用
  • 2026年4月惠州市专利申请机构推荐,这些做得好别错过,高新企业申报/惠州市商标申请,惠州市专利申请企业哪家好 - 品牌推荐师
  • 3分钟掌握R3nzSkin:英雄联盟国服免费全皮肤终极方案
  • OpenPLC Editor:开源工业自动化编程的完整解决方案
  • 企业级应用整合大模型时如何利用Taotoken实现成本与稳定性管控
  • rk3576 sai tdm调试
  • NotebookLM可信度评估:从论文级可信论证到生产环境SLA保障——一位首席AI架构师的11年踩坑笔记(含3份脱敏审计日志)
  • 2026 全网超详细网络安全学习路线,零基础一步步成长为实战专家,全套免费教程
  • 2026年全网最全降AI率保姆级教程:高效降低AI! - 降AI实验室
  • 咖啡一杯,Token 无限,Real-Time Cafe 深圳站来了!新增「硬件晒晒桌」与「AI 桌游试玩桌」
  • 使用嘉立创EDA画PCB板时,布线遇到“违反DRC规则,请注意白色边框”问题的解决办法
  • 如何高效破解Cursor Pro限制:5步激活AI编程助手的终极方案
  • 网盘直链解析神器:八大平台免登录高速下载终极解决方案
  • QMCDecode:3步解锁你的QQ音乐加密文件
  • 宣城有实力的网络公司推荐
  • RLVR 技术深挖:强化学习微调大模型的范式转变与代码实战
  • 2026 年 AI 工具聚合站:从模型入口到开发基础设施的进化之路
  • UART 通信学习笔记
  • SMUDebugTool:5步掌握AMD Ryzen处理器深度调试与性能优化
  • 答辩加分秘籍!长江学者特聘教授专属PPT定制
  • 抖音批量下载完整指南:3步实现无水印视频高效获取