一、启动流程图
二、LiteOS 启动第一阶段(汇编阶段)
代码路径:kernel/liteos_a/arch/arm/arm/src/startup/reset_vector_mp.S
入口函数:reset_vector
1、清寄存器 TPIDRPRW
/* clear register TPIDRPRW */
mov r0, #0
mcr p15, 0, r0, c13, c0, 4
对于 ARMV6K 和 ARMv7 版本,offset 保存在 TPIDRPRW 寄存器中,这样是为了提升系统性能。
2、关 cache 和 mmu
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1<<12)
bic r0, #(1<<2 | 1<<0)
mcr p15, 0, r0, c1, c0, 0
**3、使能 fpu(浮点运算单元)和 neon(**Neon 是适用于 ARM Cortex-A 系列处理器的一种 128 位 SIMD(Single Instruction, Multiple Data,单指令、多数据)扩展结构。)
#ifndef LOSCFG_TEE_ENABLE
MRC p15, 0, r0, c1, c1, 2
ORR r0, r0, #0xC00
BIC r0, r0, #0xC000
MCR p15, 0, r0, c1, c1, 2
LDR r0, =(0xF << 20)
MCR p15, 0, r0, c1, c0, 2
ISB
#endif
MOV r3, #0x40000000
VMSR FPEXC, r3
4、获取物理地址和虚拟地址的差值
ldr r7, =__exception_handlers /* r7: base of linked address (or vm address) */
ldr r6, =__bss_start /* r6: end of linked address (or vm address) */
sub r6, r7 /* r6: delta of linked address (or vm address) */
add r6, r4 /* r6: end of load address */
5、代码重定位
判断是否需要重定位到合适位置
重定位 image 到物理地址底部
ldr r7, =__exception_handlers /* r7: base of linked address (or vm address) */
ldr r6, =__bss_start /* r6: end of linked address (or vm address) */
sub r6, r7 /* r6: delta of linked address (or vm address) */
add r6, r4 /* r6: end of load address */
reloc_img_to_bottom_loop:
ldr r7, [r4], #4
str r7, [r5], #4
cmp r4, r6
bne reloc_img_to_bottom_loop
sub pc, r12
nop
sub r11, r11, r12 /* r11: eventual address offset */
reloc_img_to_bottom_done:
#ifdef LOSCFG_KERNEL_MMU
ldr r4, =g_firstPageTable /* r4: physical address of translation table and clear it */
add r4, r4, r11
mov r0, r4kernel/liteos_a/tools/build/liteos.ld
mov r1, #0
mov r2, #MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS
bl memset_optimized /* optimized memset since r0 is 64-byte aligned */
ldr r5, =g_archMmuInitMapping
add r5, r5, r11
init_mmu_loop:
ldmia r5!, {r6-r10} /* r6 = phys, r7 = virt, r8 = size, r9 = mmu_flags, r10 = name */
cmp r8, 0 /* if size = 0, the mmu init done */
beq init_mmu_done
bl page_table_build
b init_mmu_loop
init_mmu_done:
orr r8, r4, #MMU_TTBRx_FLAGS /* r8 = r4 and set cacheable attributes on translation walk */
ldr r4, =g_mmuJumpPageTable /* r4: jump pagetable vaddr */
add r4, r4, r11
ldr r4, [r4]
add r4, r4, r11 /* r4: jump pagetable paddr */
6、设置 1M 的 section 映射,这里 va == pa,方便后面的 mmu 跳转(这些都是在定义了 los_mmu 的前提下)
/* build 1M section mapping, in order to jump va during turing on mmu:pa == pa, va == pa */
mov r6, pc
mov r7, r6 /* r7: pa (MB aligned)*/
lsr r6, r6, #20 /* r6: va l1 index */
ldr r10, =MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
add r12, r10, r6, lsl #20 /* r12: pa |flags */
str r12, [r4, r7, lsr #(20 - 2)] /* jumpTable[paIndex] = pt entry */
rsb r7, r11, r6, lsl #20 /* r7: va */
str r12, [r4, r7, lsr #(20 - 2)] /* jumpTable[vaIndex] = pt entry */
bl mmu_setup /* set up the mmu */
7、清除中断、异常栈并设置 magic num 用于检查溢出
ldr r0, =__svc_stack
ldr r1, =__exc_stack_top
bl stack_init
STACK_MAGIC_SET __svc_stack, #OS_EXC_SVC_STACK_SIZE, OS_STACK_MAGIC_WORD
STACK_MAGIC_SET __exc_stack, #OS_EXC_STACK_SIZE, OS_STACK_MAGIC_WORD
8、warm_reset(热启动)
/* initialize CPSR (machine state register) */
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SVC_MODE)
msr cpsr, r0
/* Note: some functions in LIBGCC1 will cause a "restore from SPSR"!! */
msr spsr, r0
/* get cpuid and keep it in r12 */
mrc p15, 0, r12, c0, c0, 5
and r12, r12, #MPIDR_CPUID_MASK
/* set svc stack, every cpu has OS_EXC_SVC_STACK_SIZE stack */
ldr r0, =__svc_stack_top
mov r2, #OS_EXC_SVC_STACK_SIZE
mul r2, r2, r12
sub r0, r0, r2
mov sp, r0
LDR r0, =__exception_handlers
MCR p15, 0, r0, c12, c0, 0
cmp r12, #0
bne cpu_start
9、清除 BSS
ldr r0, =__bss_start
ldr r2, =__bss_end
mov r1, #0
sub r2, r2, r0
bl memset
10、栈保护初始化(Stack-Protector Init)
#if defined(LOSCFG_CC_STACKPROTECTOR_ALL) || \
defined(LOSCFG_CC_STACKPROTECTOR_STRONG) || \
defined(LOSCFG_CC_STACKPROTECTOR)
bl __stack_chk_guard_setup
#endif
11、启动 GDB(可选)
kernel/liteos_a/tools/build/liteos.ld#ifdef LOSCFG_GDB_DEBUG
/* GDB_START - generate a compiled_breadk,This function will get GDB stubs started, with a proper environment */
bl GDB_START
.word 0xe7ffdeff
#endif
12、跳转 main
DD一下:欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。
`欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。`
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案)
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.【OpenHarmony】Uboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......
三、LiteOS 启动第二阶段(main)
代码路径:kernel/liteos_a/platform/main.c
入口函数:
main
重要函数
OsMainkernel/liteos_a/tools/build/liteos.ld
OsSchedStart
1、OsMain 函数
LITE_OS_SEC_BSS STATIC LosTaskCB g_mainTask[LOSCFG_KERNEL_CORE_NUM];
#define LITE_OS_SEC_BSS /* __attribute__((section(".bss.sram"))) */
#ifdef LOSCFG_KERNEL_SMP
#define LOSCFG_KERNEL_CORE_NUM 2
#else
#define LOSCFG_KERNEL_CORE_NUM 1
#endif
liteos_a 中一次性定义了
1.1 OsInitCall------>InitLevelCall 函数的定义
Liteos 在初始化的时候会分不同阶段调用不同的字段内的函数接口并执行,通过 OsInitCall 函数实现,参数是段的
OS_INIT_LEVEL_REG(kernel, 10, g_kernInitLevelList);
#define OS_INIT_LEVEL_REG(_type, _num, _list) \
INIT_LABEL_REG_##_num(EXTERN_LABEL, _type) \
STATIC struct ModuleInitInfo* _list [] = { \
┊ INIT_LABEL_REG_##_num(GET_LABEL, _type) \
}
#define INIT_LABEL_REG_10(_op, _type) \
INIT_LABEL_REG_9(_op, _type) \
_op(_type, 10)
#define EXTERN_LABEL(_type, _level) extern struct ModuleInitInfo __##_type##_init_level_##_level;
#define GET_LABEL(_type, _level) &__##_type##_init_level_##_level,
struct ModuleInitInfo {
OsInitHook hook;
#ifdef LOS_INIT_DEBUG
const CHAR *name;
#endif
};
extern struct ModuleInitInfo __kernel_init_level_0;
extern struct ModuleInitInfo __kernel_init_level_1;
...
extern struct ModuleInitInfo __kernel_init_level_10;
static struct ModuleInitInfo *g_kernInitLevelList[] = {
&__kernel_init_level_0,
&__kernel_init_level_1,
...
&__kernel_init_level_10,
};
InitLevelCall 函数功能:
InitLevelCall("Kernel", level, g_kernInitLevelList);
取出 g_kernInitLevelList[level]字段内的所有函数然后执行一遍
关于__kernel_init_level_0 等字段的链接脚本定义可参考目录:kernel/liteos_a/tools/build/liteos.ld
1.2 OsTaskInite 函数
系统一次性会创建 129 个 task 的内存池
task 和 Sched 初始化
g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;
#define LOSCFG_BASE_CORE_TSK_LIMIT 128
1.3 OsSysMemInit
OsKHeapInit 堆内存初始化
#define HDF_INIT(module) HDF_DRIVER_INIT(module)
#define HDF_DRIVER_INIT(module) \
const size_t USED_ATTR module##HdfEntry HDF_SECTION = (size_t)(&(module))
#define USED_ATTR __attribute__((used))
#define HDF_SECTION __attribute__((section(".hdf.driver")))
const size_t __attribute__((used)) moduleHdfEntry __attribute__((section(".hdf.driver"))) = (size_t)(&(module))