Vector_table.S

以arm cortex-M系列的启动流程为例,arch/arm/core/cortex_m:

vector_table.S: 定义了中断向量表_vector_table。其中arm cortex-M规定0x0地址存放栈的起始地址(栈顶)。0x4开始存放reset handler,…

没看到定义外部中断的地址

上电后跳转至z_arm_reset函数,进入reset.S

Reset.S

目前大部分的宏定义都没打开。这里关注下通用的一些流程:

    movs.n r0, #_EXC_IRQ_DEFAULT_PRIO
    msr BASEPRI, r0

设置BASEPRI寄存器, 中断的base prioriity, 低于或等于该优先级的中断都会被屏蔽。
这里#_EXC_IRQ_DEFAULT_PRIO宏展开为3,说明中断优先级只能配置为0/1/2。


    ldr r0, =z_interrupt_stacks
    ldr r1, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE
    adds r0, r0, r1
    msr PSP, r0 // write r0 to PSP
    mrs r0, CONTROL // read CONTROL to r0
    movs r1, #2
    orrs r0, r1 /* CONTROL_SPSEL_Msk */
    msr CONTROL, r0 // write 0x2 to CONTROL
    isb
    bl z_arm_prep_c

1.设置进程堆栈指针PSP, process stack pointer。
2.写CONTROL寄存器bit1,使用PSP作为当前的stack。
3.跳转至z_arm_prep_c

Prep_c.c

void z_arm_prep_c(void)
{
	relocate_vector_table();
#if defined(CONFIG_CPU_HAS_FPU)
	z_arm_floating_point_init();
#endif
	z_bss_zero();
	z_data_copy();
	z_arm_interrupt_init();
	z_cstart();
	CODE_UNREACHABLE;
}

z_bss_zero(): 清bss段。
z_data_copy(): 把data段数据从ROM拷贝到RAM。
z_arm_interrupt_init(): 设置外部中断优先级先都为1。
z_cstart(): 跳转至init.c

Init.c

void z_cstart(void)
{
	/* initialize early init calls */
	z_sys_init_run_level(INIT_LEVEL_EARLY);
	/* perform any architecture-specific initialization */
	arch_kernel_init();
	LOG_CORE_INIT();
#if defined(CONFIG_MULTITHREADING)
	/* Note: The z_ready_thread() call in prepare_multithreading() requires
	 * a dummy thread even if CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN=y
	 */
	struct k_thread dummy_thread;
	z_dummy_thread_init(&dummy_thread);
#endif
	/* do any necessary initialization of static devices */
	z_device_state_init();
	/* perform basic hardware initialization */
	z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_1);
	z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_2);

#ifdef CONFIG_MULTITHREADING
	switch_to_main_thread(prepare_multithreading());
	while (true) {
	}
#endif /* CONFIG_MULTITHREADING */
}

删掉了一些没打开的宏相关代码。

z_sys_init_run_level(INIT_LEVEL_EARLY)
z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_1)
z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_2)
根据优先级,初始化系统中所有driver的init函数和通过SYS_INIT()定义的init函数。
参考DEVICE_DT_DEFINE->Z_DEVICE_INIT_ENTRY_DEFINE宏定义的driver,会在z_sys_init_run_level函数中调用.init_fn->.dev(dev)
SYS_INIT()会调用到.init_fn->sys()

初始化完成后进入死循环。


其中arch_kernel_init函数:

static ALWAYS_INLINE void arch_kernel_init(void)
{
	z_arm_interrupt_stack_setup();
	z_arm_exc_setup();
	z_arm_fault_init();
	z_arm_cpu_idle_init();
	z_arm_clear_faults();
#if defined(CONFIG_ARM_MPU)
	z_arm_mpu_init();
	z_arm_configure_static_mpu_regions();
#endif /* CONFIG_ARM_MPU */
}

z_arm_interrupt_stack_setup(): 设置msp, interrupt使用的stack。
z_arm_exc_setup(): 设置好系统异常的中断优先级。
z_arm_fault_init(): 设置CPU CCR寄存器,打开除0异常。非对齐访问异常由宏开关控制是否打开,默认不打开。
z_arm_cpu_idle_init(): 设置CPU SCR寄存器,设置中断可以唤醒CPU idle状态。
z_arm_clear_faults(): reset all faults,清除所有异常。


switch_to_main_thread(prepare_multithreading()): 创建一个kernel线程,接着会跑进bg_thread_main:

static void bg_thread_main(void *unused1, void *unused2, void *unused3)
{
	ARG_UNUSED(unused1);
	ARG_UNUSED(unused2);
	ARG_UNUSED(unused3);

#ifdef CONFIG_MMU
	z_mem_manage_init();
#endif /* CONFIG_MMU */
	z_sys_post_kernel = true;
	z_sys_init_run_level(INIT_LEVEL_POST_KERNEL);
	boot_banner();
	/* Final init level before app starts */
	z_sys_init_run_level(INIT_LEVEL_APPLICATION);
	z_init_static_threads();

#ifdef CONFIG_MMU
	z_mem_manage_boot_finish();
#endif /* CONFIG_MMU */

	extern int main(void);

	(void)main();
}

包括一些低优先级的driver, SYS_INIT()初始化,MMU初始化,boot_banner会打印LOGO。这时kernel已经初始化完毕,之后跳转进应用程序的main()函数。

linker.ld

include/zephyr/arch/arm/cortex_m/scripts/linker.ld链接脚本。