积分305 / 贡献0

提问7答案被采纳4文章45

[经验分享] LiteOS启动流程分析(基于V3LTS版本) 原创

润开鸿_闻飞 显示全部楼层 发表于 2024-9-11 15:16:00

一、启动流程图

image.png

二、LiteOS启动第一阶段(汇编阶段)

代码路径:kernel/liteos_a/arch/arm/arm/src/startup/reset_vector_mp.S

入口函数:reset_vector

1、清寄存器TPIDRPRW

http://www.voidcn.com/article/p-oscrtoxb-bgz.html

    /* 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、获取物理地址和虚拟地址的差值

https://www.cnblogs.com/w-smile/p/13855291.html

    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(热启动)

http://blog.sina.com.cn/s/blog_a189aca10101se98.html

    /* 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

三、LiteOS启动第二阶段(main)

代码路径:kernel/liteos_a/platform/main.c

参考wiki:https://device.harmonyos.com/cn/docs/develop/guide/kernel-small-start-kernel-0000001127506594

入口函数:

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堆内存初始化

https://www.xujun.org/note-122317.html

https://www.tqwba.com/x_d/jishu/286766.html

#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))

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部