一、前言
最近做微型嵌入式系统zephyr移植开发工作,过程中遇到一些系统加载问题,于是研究了下zephyr从上电到执行到main函数的中间过程,这里做下梳理总结。
二、镜像启动入口
研究启动流程常规做的事是寻找系统上电后的第一指令,一般是__start函数,但是在工程中寻找一遍之后只有__start的声明,如下图,只能看出声明了__start这个全局函数,但并未找到定义。
接着找了下镜像入口点指定的几种方法,有以下5种:
1.在链接时候使用-e参数
2.在脚本里使用ENTRY
3.定义过start入口函数
4.SECTION中.text的第一个入口函数
5.地址为0的指令
Zephyr采用第四种方式,在toolchain/gcc.h有如下定义:
其中_ASM_FILE_PROLOGUE便是执行入口,全局搜这个入口可以在中断向量表vector_table.S找到,所以想清楚zephyr上电到main函数的中间流程动作就需要研究中断向量表vector_table.S,本文以cotex-m系列芯片为例展开,文件位置:zephyrproject\zephyr\arch\arm\core\aarch32\cortex_m\vector_table.S
三、启动具体流程
1.向量表上来执行的第一个函数z_arm_reset,这个就要到同级目录的reset.S去看,这里简单说一下他做的操作,具体更详细的内容可以翻看zephyr源码:
1)调用_PlatformInit()函数执行平台相关初始化操作
2)屏蔽所有可以配置优先级的中断
3)初始化看门狗
4)初始化中断栈内容为0xaa
5)复位后CortexM处理器默认处于线程模式+特权访问+使用MSP主栈指针,这里切换为PSP指针并将PSP设为_interrupt_stack中断栈
6)最后进入C语言准备–z_arm_prep_c
2.z_arm_prep_c做的内容:
1)重定向向量表
2)使能浮点计算(相关单板支持该特性的话)
3)清零BSS段
4)从ROM拷贝数据段到RAM(针对XIP模式,这里说明一下,一般嵌入式处理器启动方式分为两种:1. XIP 模式 (eXecute In Place), 在该模式下CPU直接从Nor Flash上读代码执行,执行速度慢 ;2. 非XIP模式, 在该模式下硬件先将代码从Flash上搬移到RAM上后,CPU才能从RAM上访问数据,执行速度快;对于非XIP模式,启动前需要先借助boot把代码段从FLASH拷贝到RAM;对于XIP模式,如果FLASH基地址映射到0地址,复位后可以直接启动)
5)针对ARMV7,初始化_svc_stack、_abort_stack、_undef_stack、_fiq_stack、_interrupt_stacks栈内容为0xaa
6)初始化所有中断优先级
7)正式进入c环境执行--z_cstart
3.z_cstart做的内容:
1)做gcov静态初始化、硬件平台特定框架初始化
2)多线程初始化(支持的话)
3)PRE_KERNEL_1、PRE_KERNEL_2级别设备初始化
4)定时器的初始化和开启
5)切换主线程开始运行bg_thread_main,而main函数就在这个函数执行,至此从zephyr上电到main函数中间流程梳理完毕,整理过程只点了重要流程,具体可以看下源码