您的位置:首页 > 运维架构 > Linux

zephyr_02_内核启动

2017-12-11 08:22 211 查看
zephyr是一款轻量级的linux, 中文翻译为”和风, 西风, 轻薄织物”, 推出不到两年的时间, 已从刚开始支持的4,5个到现在支持市面上主流的MCU, 发展速度及其迅速, 最主要是开源, 现在更新到1.9.2, 基于最新版本代码, 汲取网上大牛们的经验, 对系统的启动流程做个简单的记录 (以cortex-cm4为例, 因手头的nrf52840是基于M4核的).

CPU上电复位操作流程

1. 查找向量中断表, 跳转到复位异常函数处理执行

2. 锁中断(NMI和hard Fault除外)

3. 初始化看门狗(条件编译, 可选)

4. 初始化中断栈空间(条件编译, 可选) // 但为什么要初始化为0xaa by Huihh 2017.12.8

5. 将PSP指向栈顶地址

6. 跳转到_PrepC函数, 准备C代码运行环境

7. 根据启动方式, 重定位向量表

8. 将BBS段清0

9. 数据拷贝, 从ROM拷贝到RAM中 (完成之后, C代码环境已准备好)

10. 初始化内核 (调用前必须确保系统已准备好执行C代码的环境, 处理器必须运行在32-bit模式, BSS段已清0)

1. 向量表

Cortex-M4的异常向量表
. 1-15     //系统异常向量表
. 16-255   //中断向量表, 芯片厂家一般只会实现其中一部分中断




2. 启动源文件(/${ZEPHYR_BASE}/arch/arm/core/cortex_m/vector_table.S)

#include <board.h>
#include <toolchain.h>
#include <linker/sections.h>
#include <drivers/system_timer.h>
#include "vector_table.h"

_ASM_FILE_PROLOGUE

GDATA(_main_stack)    //_main_stack 全局符号, 存放在数据段

SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)

.word _main_stack + CONFIG_MAIN_STACK_SIZE     //0 N/A

.word __reset            //1  系统上电, 发生复位异常, 既会跳转到 __reset符号处执行
.word __nmi              //2  不可屏蔽中断NMI,
.word __hard_fault       //3  硬中断
.word __mpu_fault        //4  MPU  fault
.word __bus_fault        //5  总线 fault
.word __usage_fault      //6  用法 fault
.word __reserved         //7  保留
.word __reserved         //8  保留
.word __reserved         //9  保留
.word __reserved         //10 保留
.word __svc              //11 SVC 系统调用
.word __debug_monitor    //12 调试监视器
.word __reserved         //13 保留
.word __pendsv           //14 PendSV

#if defined(CONFIG_CORTEX_M_SYSTICK)    //条件编译, 如果存在systick 则定义, 否则保留
.word _timer_int_handler //15 SysTick
#else
.word __reserved
#endif


3. 上电复位, __reset处理, 为执行C代码准备环境 (/${ZEPHYR_BASE}/arch/arm/core/cortex_m/reset.S)

1. 系统从reset中运行, 处理器处于特权级别的线程模式, 主堆栈(MSP)指向SRAM的有效区域
2. 锁定中断(除NMI和hard Fault外), 默认的NMI异常处理已存在向量表中, boot代码不应该产生hard Fault
3. 使用进程堆栈(PSP)替代主堆栈(MSP), 一旦主堆栈(MSP)用于指向唯一的中断堆栈继续启动, 这在运行C代码时是不可能的
4. 这些步骤完成后, 跳转到_PrepC()函数, 它将完成设置C代码的运行环境

#include <board.h>
#include <toolchain.h>
#include <linker/sections.h>
#include <arch/cpu.h>
#include <offsets_short.h>
#include "vector_table.h"

_ASM_FILE_PROLOGUE

GTEXT(__reset)
GTEXT(memset)
GDATA(_interrupt_stack)

SECTION_SUBSEC_FUNC(TEXT,_reset_section,__reset)

SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start)   //XIP启动, __start 开始启动处的别名

movs.n r0, #_EXC_IRQ_DEFAULT_PRIO       //锁中断
msr BASEPRI, r0

#ifdef CONFIG_WDOG_INIT        //条件编译   初始化看门狗
bl _WdogInit
#endif

#ifdef CONFIG_INIT_STACKS   //条件编译  初始化堆栈 (初始值为0xaa)   //为什么不是0x00   by Huihh 2017.12.8
ldr r0, =_interrupt_stack
ldr r1, =0xaa
ldr r2, =CONFIG_ISR_STACK_SIZE
bl memset                           //memset参数: Para1: r0, Para2: r1, Para3: r2
#endif

ldr r0, =_interrupt_stack             //将PSP指向栈顶(栈顶=栈起始地址+栈大小)
ldr r1, =CONFIG_ISR_STACK_SIZE
adds r0, r0, r1
msr PSP, r0
movs.n r0, #2
msr CONTROL, r0       //配置CONTROL寄存器, 使能进程堆栈寄存器(PSP)

b _PrepC     //跳转_PrepC 函数, 准备C代码执行环境


4. _PrepC (/${ZEPHYR_BASE}/arch/arm/core/cortex_m/prep_c.c)

启动方式(具体启动方式由SoC设计决定)

1. XIP 模式 (eXecute In Place), 在该模式下,CPU直接从Nor Flash上读代码执行 执行速度慢

2. 非XIP模式 在该模式下, 硬件先将代码从Flash上搬移到RAM上后, CPU才能从RAM上访问数据 执行速度快

#include <kernel.h>
#include <zephyr/types.h>
#include <toolchain.h>
#include <linker/linker-defs.h>
#include <nano_internal.h>
#include <arch/arm/cortex_m/cmsis.h>
#include <string.h>

#ifdef CONFIG_XIP
#define VECTOR_ADDRESS ((uintptr_t)&_image_rom_start + \
CONFIG_TEXT_SECTION_OFFSET)              //XIP启动, 向量表地址, 默认为0x00地址
#else
#define VECTOR_ADDRESS CONFIG_SRAM_BASE_ADDRESS     //非XIP启动, (硬件已搬移代码)向量表地址, 指向SRAM的地址
#endif

static inline void relocate_vector_table(void)   //重定位向量表地址, 决定从SRAM/Nor Flash启动
{
SCB->VTOR = VECTOR_ADDRESS & SCB_VTOR_TBLOFF_Msk;
__DSB();
__ISB();
}

#ifdef CONFIG_FLOAT
static inline void enable_floating_point(void)   //浮点单元配置
{
/*
* Upon reset, the Co-Processor Access Control Register is 0x00000000.
* Enable CP10 and CP11 coprocessors to enable floating point.
*/
SCB->CPACR |= CPACR_CP10_FULL_ACCESS | CPACR_CP11_FULL_ACCESS;
/*
* Upon reset, the FPU Context Control Register is 0xC0000000
* (both Automatic and Lazy state preservation is enabled).
* Disable lazy state preservation so the volatile FP registers are
* always saved on exception.
*/
FPU->FPCCR = FPU_FPCCR_ASPEN_Msk; /* FPU_FPCCR_LSPEN = 0 */

/*
* Although automatic state preservation is enabled, the processor
* does not automatically save the volatile FP registers until they
* have first been touched. Perform a dummy move operation so that
* the stack frames are created as expected before any task or fiber
* context switching can occur.
*/
__asm__ volatile(
"vmov s0, s0;\n\t"
"dsb;\n\t"
"isb;\n\t"
);
}
#else
static inline void enable_floating_point(void)
{
}
#endif

extern FUNC_NORETURN void _Cstart(void);
/**
*
* @brief Prepare to and run C code
*
* This routine prepares for the execution of and runs C code.
*
* @return N/A
*/

#ifdef CONFIG_BOOT_TIME_MEASUREMENT
extern u64_t __start_time_stamp;
#endif
void _PrepC(void)
{
relocate_vector_table();     //重定位向量表
enable_floating_point();     //浮点单元(FPU)
_bss_zero();                 //bss段清0            (实现 /${ZEPHYR_BASE}/kernel/init.c)
_data_copy();                //数据拷贝            (实现 /${ZEPHYR_BASE}/kernel/init.c)
#ifdef CONFIG_BOOT_TIME_MEASUREMENT
__start_time_stamp = 0;
#endif
_Cstart();             //初始化内核
CODE_UNREACHABLE;
}


5. _Cstart() 初始化内核 (/${ZEPHYR_BASE}/kernel/init.c)


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  内核 经验 开源 linux cpu