美文网首页
[openharmony]liteos-a系统初始化框架分析

[openharmony]liteos-a系统初始化框架分析

作者: itsenlin | 来源:发表于2021-10-26 16:33 被阅读0次

    系统启动流程

    对于Hi3516dv300来说,系统上电之后是先启动一个uboot.bin;uboot.bin做一些初始化再转到内核调用;内核的入口为reset_vector,在连接文件liteos_llvm.ld中有描述,后面的启动如下图


    image.png
    image.png

    注意:openharmony3.0lts的los_config.c放在了kernel/platform/目录,而不是kernel/common了,还有其他一些代码也有改动,需要注意

    OsInitCall

    通过看OsMain接口源码,很多初始化并不是直接调用内核各模块的初始化接口,而是调用一个统一的接口:OsInitCall如下图(如果分析过linux系统的初始化的话,这个跟linux的驱动初始化很像,参考连接

    image.png

    OsInitCall源码如下:

    VOID OsInitCall(const UINT32 level)
    {
        if (level >= LOS_INIT_LEVEL_FINISH) {
            return;
        }
    
        InitLevelCall("Kernel", level, g_kernInitLevelList);
    }
    

    看源码是根据传入的初始化level值调用InitLevelCall接口初始化具体的level下的模块,代码如下(这里把不相关的代码删除了):

    /**
     * It is recommended that each startup framework encapsulate a layer of its own calling interface.
     */
    STATIC VOID InitLevelCall(const CHAR *name, const UINT32 level, struct ModuleInitInfo *initLevelList[])
    {
        struct ModuleInitInfo *module = NULL;
    
        if (ArchCurrCpuid() == 0) {
            g_initCurrentLevel = level;
            g_initCurrentModule = initLevelList[level];
        } else {
            while (g_initCurrentLevel < level) {
            }
        }
        do {
            LOS_SpinLock(&g_initLock);
            if (g_initCurrentModule >= initLevelList[level + 1]) {
                LOS_SpinUnlock(&g_initLock);
                break;
            }
            module = (struct ModuleInitInfo *)g_initCurrentModule;
            g_initCurrentModule++;
            LOS_SpinUnlock(&g_initLock);
            if (module->hook != NULL) {
                module->hook();
            }
        } while (1);
        if (level >= LOS_INIT_LEVEL_KMOD_TASK) {
            LOS_AtomicInc(&g_initCount);
            while ((LOS_AtomicRead(&g_initCount) % LOSCFG_KERNEL_CORE_NUM) != 0) {
            }
        }
    }
    

    从代码实现分析,第三个参数是一个列表,代表的是所有需要初始化的内核模块信息,而初始化入口在module->hook中;对于同一level的模块可能有多个,所以这里使用了一个do/while循环。
    从传入的参数看第三个参数是一个全局变量g_kernInitLevelList,这个变量是通过一个宏初始化的,如下

    /**
     * Register kernel init level labels.
     */
    OS_INIT_LEVEL_REG(kernel, 10, g_kernInitLevelList);
    

    这个宏的具体展开在下一节再详细说明,这里再说一下初始化level这个属性,从代码中看OpenHarmony的liteos-a系统中对系统模块初始化的级别定义了10个(0~9),如下

    /**
     * Kernel Module Init Level
     */
    #define LOS_INIT_LEVEL_EARLIEST                     0
    #define LOS_INIT_LEVEL_ARCH_EARLY                   1
    #define LOS_INIT_LEVEL_PLATFORM_EARLY               2
    #define LOS_INIT_LEVEL_KMOD_PREVM                   3
    #define LOS_INIT_LEVEL_VM_COMPLETE                  4
    #define LOS_INIT_LEVEL_ARCH                         5
    #define LOS_INIT_LEVEL_PLATFORM                     6
    #define LOS_INIT_LEVEL_KMOD_BASIC                   7
    #define LOS_INIT_LEVEL_KMOD_EXTENDED                8
    #define LOS_INIT_LEVEL_KMOD_TASK                    9
    #define LOS_INIT_LEVEL_FINISH                       10
    

    从OsMain函数中调用情况看,就是按这个level顺序来调用OsInitCall初始化各模块的

    内核模块初始化接口列表

    g_kernInitLevelList的初始化是通过一个宏来处理的,如下

    OS_INIT_LEVEL_REG(kernel, 10, g_kernInitLevelList);
    

    经过展开之后,代码如下:

    extern struct ModuleInitInfo __kernel_init_level_0;
    extern struct ModuleInitInfo __kernel_init_level_1;
    extern struct ModuleInitInfo __kernel_init_level_2;
    extern struct ModuleInitInfo __kernel_init_level_3;
    extern struct ModuleInitInfo __kernel_init_level_4;
    extern struct ModuleInitInfo __kernel_init_level_5;
    extern struct ModuleInitInfo __kernel_init_level_6;
    extern struct ModuleInitInfo __kernel_init_level_7;
    extern struct ModuleInitInfo __kernel_init_level_8;
    extern struct ModuleInitInfo __kernel_init_level_9;
    extern struct ModuleInitInfo __kernel_init_level_10;
    STATIC struct ModuleInitInfo *g_kernInitLevelList[] = {
        &__kernel_init_level_0,
        &__kernel_init_level_1,
        &__kernel_init_level_2,
        &__kernel_init_level_3,
        &__kernel_init_level_4,
        &__kernel_init_level_5,
        &__kernel_init_level_6,
        &__kernel_init_level_7,
        &__kernel_init_level_8,
        &__kernel_init_level_9,
        &__kernel_init_level_10,
    }
    

    其中__kernel_init_level_x的定义在连接脚本liteos_llvm.ld中,是在连接的时候才确定的值。

        .rodata : ALIGN(0x1000) {
            __rodata_start = .;
            __kernel_init_level_0 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.0.*)));
            __kernel_init_level_1 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.1.*)));
            __kernel_init_level_2 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.2.*)));
            __kernel_init_level_3 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.3.*)));
            __kernel_init_level_4 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.4.*)));
            __kernel_init_level_5 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.5.*)));
            __kernel_init_level_6 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.6.*)));
            __kernel_init_level_7 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.7.*)));
            __kernel_init_level_8 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.8.*)));
            __kernel_init_level_9 = ABSOLUTE(.);
            KEEP(*( SORT (.rodata.init.kernel.9.*)));
            __kernel_init_level_10 = ABSOLUTE(.);
            *(.rodata .rodata.* .gnu.linkonce.r.*)
            __exc_table_start = .;
            KEEP(*(__exc_table))
            __exc_table_end = .;
        } > ram
    

    编译之后查看OHOS_Image.map文件,可以看到这些定义之间存放了对应level下的内核模块入口,level0下有三个内核模块、level1~3无模块、level4有一个模块等等,如下:

    4057a000 4057a000        0     1         __rodata_start = .
    4057a000 4057a000        0     1         __kernel_init_level_0 = ABSOLUTE ( . )
    4057a000 4057a000        4     4         lto.tmp:(.rodata.init.kernel.0.HisiSmpInit)
    4057a000 4057a000        4     1                 ModuleInitInfo_HisiSmpInit
    4057a004 4057a004        4     4         lto.tmp:(.rodata.init.kernel.0.OsDmesgInit)
    4057a004 4057a004        4     1                 ModuleInitInfo_OsDmesgInit
    4057a008 4057a008        4     4         lto.tmp:(.rodata.init.kernel.0.OsLkLoggerInit)
    4057a008 4057a008        4     1                 ModuleInitInfo_OsLkLoggerInit
    4057a00c 4057a00c        0     1         __kernel_init_level_1 = ABSOLUTE ( . )
    4057a00c 4057a00c        0     1         __kernel_init_level_2 = ABSOLUTE ( . )
    4057a00c 4057a00c        0     1         __kernel_init_level_3 = ABSOLUTE ( . )
    4057a00c 4057a00c        0     1         __kernel_init_level_4 = ABSOLUTE ( . )
    4057a00c 4057a00c        4     4         lto.tmp:(.rodata.init.kernel.4.ShmInit)
    4057a00c 4057a00c        4     1                 ModuleInitInfo_ShmInit
    4057a010 4057a010        0     1         __kernel_init_level_5 = ABSOLUTE ( . )
    4057a010 4057a010        0     1         __kernel_init_level_6 = ABSOLUTE ( . )
    4057a010 4057a010        4     4         lto.tmp:(.rodata.init.kernel.6.OsBsdInit)
    4057a010 4057a010        4     1                 ModuleInitInfo_OsBsdInit
    4057a014 4057a014        0     1         __kernel_init_level_7 = ABSOLUTE ( . )
    4057a014 4057a014        4     4         lto.tmp:(.rodata.init.kernel.7.los_vfs_init)
    4057a014 4057a014        4     1                 ModuleInitInfo_los_vfs_init
    4057a018 4057a018        0     1         __kernel_init_level_8 = ABSOLUTE ( . )
    4057a018 4057a018        4     4         lto.tmp:(.rodata.init.kernel.8.HieventInit)
    4057a018 4057a018        4     1                 ModuleInitInfo_HieventInit
    4057a01c 4057a01c        4     4         lto.tmp:(.rodata.init.kernel.8.OsCpupInit)
    4057a01c 4057a01c        4     1                 ModuleInitInfo_OsCpupInit
    4057a020 4057a020        4     4         lto.tmp:(.rodata.init.kernel.8.OsFutexInit)
    4057a020 4057a020        4     1                 ModuleInitInfo_OsFutexInit
    4057a024 4057a024        4     4         lto.tmp:(.rodata.init.kernel.8.OsHiDumperDriverInit)
    4057a024 4057a024        4     1                 ModuleInitInfo_OsHiDumperDriverInit
    4057a028 4057a028        4     4         lto.tmp:(.rodata.init.kernel.8.OsHiLogDriverInit)
    4057a028 4057a028        4     1                 ModuleInitInfo_OsHiLogDriverInit
    4057a02c 4057a02c        4     4         lto.tmp:(.rodata.init.kernel.8.OsLiteIpcInit)
    4057a02c 4057a02c        4     1                 ModuleInitInfo_OsLiteIpcInit
    4057a030 4057a030        4     4         lto.tmp:(.rodata.init.kernel.8.OsPmInit)
    4057a030 4057a030        4     1                 ModuleInitInfo_OsPmInit
    4057a034 4057a034        4     4         lto.tmp:(.rodata.init.kernel.8.OsSysWorkQueueInit)
    4057a034 4057a034        4     1                 ModuleInitInfo_OsSysWorkQueueInit
    4057a038 4057a038        4     4         lto.tmp:(.rodata.init.kernel.8.OsSyscallHandleInit)
    4057a038 4057a038        4     1                 ModuleInitInfo_OsSyscallHandleInit
    4057a03c 4057a03c        4     4         lto.tmp:(.rodata.init.kernel.8.OsVdsoInit)
    4057a03c 4057a03c        4     1                 ModuleInitInfo_OsVdsoInit
    4057a040 4057a040        4     4         lto.tmp:(.rodata.init.kernel.8.ProcFsInit)
    4057a040 4057a040        4     1                 ModuleInitInfo_ProcFsInit
    4057a044 4057a044        4     4         lto.tmp:(.rodata.init.kernel.8.pipe_init)
    4057a044 4057a044        4     1                 ModuleInitInfo_pipe_init
    4057a048 4057a048        0     1         __kernel_init_level_9 = ABSOLUTE ( . )
    4057a048 4057a048        4     4         lto.tmp:(.rodata.init.kernel.9.OomTaskInit)
    4057a048 4057a048        4     1                 ModuleInitInfo_OomTaskInit
    4057a04c 4057a04c        4     4         lto.tmp:(.rodata.init.kernel.9.OsCpupGuardCreator)
    4057a04c 4057a04c        4     1                 ModuleInitInfo_OsCpupGuardCreator
    4057a050 4057a050        4     4         lto.tmp:(.rodata.init.kernel.9.OsMpInit)
    4057a050 4057a050        4     1                 ModuleInitInfo_OsMpInit
    4057a054 4057a054        4     4         lto.tmp:(.rodata.init.kernel.9.OsResourceFreeTaskCreate)
    4057a054 4057a054        4     1                 ModuleInitInfo_OsResourceFreeTaskCreate
    4057a058 4057a058        4     4         lto.tmp:(.rodata.init.kernel.9.OsSystemInit)
    4057a058 4057a058        4     1                 ModuleInitInfo_OsSystemInit
    4057a05c 4057a05c        0     1         __kernel_init_level_10 = ABSOLUTE ( . )
    4057a05c 4057a05c    d3d9d     1         <internal>:(.rodata)
    

    这些内核模块是怎么连接到这些对应地址的呢?下一节内容再详细讨论

    内核模块注册到系统初始化框架

    类似linux内核模块的注册,在liteos-a系统中使用了一个宏LOS_MODULE_INIT来注册,系统中调用如下:


    image.png

    宏定义源码在los_init.h中,如下:

    /**
     * @ingroup  los_init
     * @brief Register a startup module to the startup process.
     *
     * @par Description:
     * This API is used to register a startup module to the startup process.
     *
     * @attention
     * <ul>
     * <li>Register a new module in the boot process of the kernel as part of the kernel capability component.</li>
     * <li>In the startup framework, within the same _level, the startup sequence is sorted by
     * the registered function name </li>
     * <li>If the registration is not accompanied by the startup process after calling this interface,
     * try to add -u_hook to liteos_tables_ldflags.mk </li>
     * </ul>
     *
     * @param  _hook    [IN] Type  #UINT32 (*)(VOID)    Register function.
     * @param  _level   [IN] Type  #UINT32              Init level in the kernel.
     *
     * @retval None
     * @par Dependency:
     * <ul><li>los_init.h: the header file that contains the API declaration.</li></ul>
     * @see
     */
    #define LOS_MODULE_INIT(_hook, _level)                  OS_INIT_HOOK_REG(kernel, _hook, _level)
    

    以OsSystemInit为例进行展开
    定义如下:

    LOS_MODULE_INIT(OsSystemInit, LOS_INIT_LEVEL_KMOD_TASK);
    

    展开后如下

    STATIC const struct ModuleInitInfo ModuleInitInfo_OsSystemInit __attribute__((section(".rodata.init.kernel.9.OsSystemInit))) __attribute__((aligned(alignof(struct ModuleInitInfo)))) = 
    {
        .hook = (UINT32 (*)(VOID))&OsSystemInit, 
    #ifdef LOS_INIT_DEBUG
        .name = "OsSystemInit",
    #else
        
    #endif
    }
    

    这里最主要的就是定义了结构体中的.hook变量,指向模块的初始化入口;然后就可以在启动的时候InitLevelCall中调用了。这样对应内核模块就初始化了

    题外话

    Liteos-m属于嵌入式RTOS,应用于soc的rom/ram比较小的场景,基本上不涉及内核态、用户态的分离;

    liteos-a其实就是基于liteos-m增加了MMU/MPU等特性,可以实现用户态、内核态分离;并且很多用法参考了linux系统(像这里的内核模块初始化框架)

    可以参考《深度探索嵌入式操作系统》这本书来学习

    还有一个鸿蒙研究站的网站对liteos-a内核代码做了注释,可以学习

    相关文章

      网友评论

          本文标题:[openharmony]liteos-a系统初始化框架分析

          本文链接:https://www.haomeiwen.com/subject/nohyaltx.html