内核启动流程

Posted 四季帆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核启动流程相关的知识,希望对你有一定的参考价值。

1. 链接脚本

        liteos_a的链接脚本路径如下:

OpenHarmony/kernel/liteos_a/tools/build/liteos_llvm.ld

        链接脚本的内容如下:

ENTRY(reset_vector)
INCLUDE board.ld
INPUT(libuserinit.O)
SECTIONS
{
   #各种段定义,此处全部省略
}

        链接脚本中指定了kernel的入口为reset_vector。

2. 入口函数(reset_vector)实现

        函数reset_vector是一个汇编函数,其定义在arch/arm/arm/src/startup/reset_vector_up.S中,reset_vector函数主要做了以下几件事:

    .global reset_vector
    .type   reset_vector,function
reset_vector:
    /* do some early cpu setup: i/d cache disable, mmu disabled 关闭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
    
     /* if we need to relocate to proper location or not ,镜像重定位*/
    adr     r4, __exception_handlers            /* r4: base of load address */
    ldr     r5, =SYS_MEM_BASE                   /* r5: base of physical address */
    subs    r12, r4, r5                         /* r12: delta of load address and physical address */
    beq     reloc_img_to_bottom_done            /* if we load image at the bottom of physical address */
    
    clear_bss:                     /* 清bss段 */
    ldr    r1, =__bss_start
    ldr    r2, =__bss_end
    mov    r0, #0
    
    bl     main                   /* 跳转到main */

        和Linux kernel的汇编阶段极其相似,对SOC做一些必须且早的设置,其余功能在C文件中实现。

3. main函数

        分析的主干思路:main ---> OsMain ---> OsSystemInit ---> OsSystemInitTaskCreate ---> SystemInit。

//OpenHarmony/kernel/liteos_a/platform/main.c
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)
{
    PRINT_RELEASE("\\nmain core booting up...\\n");
    ······
    uwRet = OsMain();         //在OsMain中做了大量的初始化动作
    CPU_MAP_SET(0, OsHwIDGet());
    OsStart();
}

        OsMain()函数中做了大量的初始化动作,与Linux kernel中的start_kernel类似,不同的是,liteos_a中大多数初始化动作都定义了宏来控制,也就是说不需要的初始化动作可以通过配置宏定义来去掉,即liteos_a的控制粒度比Linux kernel更精细。

//OpenHarmony/kernel/liteos_a/kernelcommon/los_config.c
LITE_OS_SEC_TEXT_INIT INT32 OsMain(VOID)
{
#ifdef LOSCFG_SHELL_DMESG
    ret = OsDmesgInit();    //dmesg相关初始化
    if (ret != LOS_OK) {
        return ret;
    }
#endif

#if (LOSCFG_PLATFORM_HWI == YES)
    OsHwiInit();           //应该是硬件相关的初始化
#endif

    OsExcInit();
    ······
    ret = OsTickInit(g_sysClock, LOSCFG_BASE_CORE_TICK_PER_SECOND);   //OS心跳初始化(定时器相关初始化)
    if (ret != LOS_OK) {
        return ret;
    }

#ifdef LOSCFG_DRIVERS
    uart_init();          //串口初始化
#endif
    ret = OsTaskInit();
    if (ret != LOS_OK) {
        PRINT_ERR("OsTaskInit error\\n");
        return ret;
    }

    ret = OsSysMemInit();
    if (ret != LOS_OK) {
        PRINT_ERR("OsSysMemInit error\\n");
        return ret;
    }

    SyscallHandleInit();

#if (LOSCFG_KERNEL_SMP == YES)
    (VOID)OsMpInit();
#endif

#ifdef LOSCFG_KERNEL_PIPE
    OsDriverPipeInit();
#endif

    ret = OsSystemInit();       //注意这里是没有通过宏来控制的 --->
    if (ret != LOS_OK) {
        return ret;
    }

    ret = OomTaskInit();
    if (ret != LOS_OK) {
        return ret;
    }
    return LOS_OK;
}

        OpenHarmony/kernel/liteos_a/kernel/common/los_config.c

UINT32 OsSystemInit(VOID)
{
    UINT32 ret;
#ifdef LOSCFG_COMPAT_LINUXKPI
    g_pstSystemWq = create_workqueue("system_wq");
#endif
    ret = OsSystemInitTaskCreate();    //初始化任务 --->
    ······
    return 0;
}

STATIC UINT32 OsSystemInitTaskCreate(VOID)
{
    UINT32 taskID;
    TSK_INIT_PARAM_S sysTask;

    (VOID)memset_s(&sysTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
    sysTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SystemInit;   //任务的入口函数
    sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
    sysTask.pcName = "SystemInit";
    ······
    return LOS_TaskCreate(&taskID, &sysTask);
}

        SystemInit()函数是具体单板相关的代码,以hi3516dv300为例,SystemInit()函数的实现在OpenHarmony/vendor/hisi/hi35xx/hi3516dv300/module_init/src/system_init.c中

void SystemInit(void)
{
#ifdef LOSCFG_DRIVERS_MMC
    dprintf("MMC dev init ...");
    extern int SD_MMC_Host_init(void);
    SD_MMC_Host_init();     //MMC host初始化
#endif
#ifdef LOSCFG_DRIVERS_USB
    dprintf("usb init ...\\n");
    usb_init(HOST, 0);     //usb初始化
#endif
#ifdef LOSCFG_PLATFORM_ROOTFS
    dprintf("OsMountRootfs start ...\\n");
    OsMountRootfs();       //挂载根文件系统
    dprintf("OsMountRootfs end ...\\n");
#endif
    ······
    if (OsUserInitProcess()) {  //创建用户init进程
        PRINT_ERR("Create user init process faialed!\\n");
        return;
    }
    dprintf("cat log shell end\\n");
    return;
}

以上是关于内核启动流程的主要内容,如果未能解决你的问题,请参考以下文章

操作系统的启动流程内核

Linux嵌入式驱动学习之路⑦Linux内核启动流程

Centos启动流程及grub legacy

13linux系统启动流程

Linux 内核启动流程

OpenHarmonyLiteOS-M内核启动流程