IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> openharmonyos1.1.0 liteos-a内核学习记录(一) -> 正文阅读

[嵌入式]openharmonyos1.1.0 liteos-a内核学习记录(一)

?如果有问题,请加QQ群 891339868 进行交流

一、汇编部分

具体路径为:

1、多核处理器:arch/arm/arm/src/startup/reset_vector_mp.S;

2、单核处理器:arm/arm/arm/src/startup/reset_vector_up.S

汇编看的不是特别明白,但是备注写的还是比较清楚的,根据备注的意思主要是做了以下工作:

(1)、reset相关的寄存器,做一些CPU早期的配置

(2)、计算cpu虚拟地址与物理地址的线性映射关系

(3)、配置MMU相关参数

(4)、物理地址与虚拟地址之间映射页表的创建

、、、

最后跳转到C语言main函数

汇编能力有限,有时间了再深入研究

二、C语言部分

具体的路径为:platform/main.c

1、main函数分析:

LITE_OS_SEC_TEXT_INIT INT32 main(VOID)
{
    UINT32 uwRet = LOS_OK;

    OsSetMainTask();//配置系统初始化的任务
    OsCurrTaskSet(OsGetMainTask());

    /* set smp system counter freq */
#if (LOSCFG_KERNEL_SMP == YES)
#ifndef LOSCFG_TEE_ENABLE
    HalClockFreqWrite(OS_SYS_CLOCK);
#endif
#endif

    /* system and chip info */
    OsSystemInfo();//打印系统的相关信息

    PRINT_RELEASE("\nmain core booting up...\n");

    uwRet = OsMain();
    if (uwRet != LOS_OK) {
        return LOS_NOK;
    }

#if (LOSCFG_KERNEL_SMP == YES)
    PRINT_RELEASE("releasing %u secondary cores\n", LOSCFG_KERNEL_SMP_CORE_NUM - 1);
    release_secondary_cores();
#endif

    CPU_MAP_SET(0, OsHwIDGet());

    OsSchedStart();//系统使能调度器

    while (1) {
        __asm volatile("wfi");
    }
}

这一段代码就是liteos-a的main函数代码,其中的每一个代码段,都非常重要,都有各自非常关键的任务,下面一条一条进行分析:
(1)、OsSetMainTask()

根据函数的名称,应该是设置主函数的任务。跟进去看一下去代码:

备注:
g_mainTask:struct LosTaskCB结构体数组,每一个元素代表一个任务

VOID OsSetMainTask()
{
    UINT32 i;
    CHAR *name = "osMain";

    for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {//遍历cpu所有核心,配置相关参数
        //LOSCFG_KERNEL_CORE_NUM,CPU核心数目    
        g_mainTask[i].taskStatus = OS_TASK_STATUS_UNUSED;//初始化当前任务的状态为unused
        g_mainTask[i].taskID = LOSCFG_BASE_CORE_TSK_LIMIT;//初始化当前任务ID都为128
        g_mainTask[i].priority = OS_TASK_PRIORITY_LOWEST;//初始化当前任务的优先级都为低
#if (LOSCFG_KERNEL_SMP_LOCKDEP == YES)
        g_mainTask[i].lockDep.lockDepth = 0;
        g_mainTask[i].lockDep.waitLock = NULL;
#endif
        (VOID)strncpy_s(g_mainTask[i].taskName, OS_TCB_NAME_LEN, name, OS_TCB_NAME_LEN - 1);
        LOS_ListInit(&g_mainTask[i].lockList);//
    }
}

(2)、OsGetMainTask()

应该是获取当前cpu绑定的task,代码跟进去看一下:

备注:代码很短,就是活动当前CPU所运行的任务,返回当前task指针
LosTaskCB *OsGetMainTask()
{
    return (LosTaskCB *)(g_mainTask + ArchCurrCpuid());
}

(3)、OsCurrTaskSet(OsGetMainTask())

名称看不出来,代码跟进去看一下:

//第一级
STATIC INLINE VOID OsCurrTaskSet(LosTaskCB *task)
{
    ArchCurrTaskSet(task);
}
//第二级
STATIC INLINE VOID ArchCurrTaskSet(VOID *val)
{
    ARM_SYSREG_WRITE(TPIDRPRW, (UINT32)(UINTPTR)val);
}
//第三级
#define ARM_SYSREG_WRITE(REG, val)              \
({                                              \
    __asm__ volatile("mcr " REG :: "r" (val));  \
    ISB;                                        \
})

备注:
TPIDRPRW = CP15_REG(c13, 0, c0, 4)
#define CP15_REG(CRn, Op1, CRm, Op2)    "p15, "#Op1", %0, "#CRn","#CRm","#Op2
    
这样一级一级追下去,最终通过汇编代码对寄存器赋值

(4)、HalClockFreqWrite(OS_SYS_CLOCK)

从名称上猜测,应该是时钟的设置,代码追进去看一下:

第一级:
VOID HalClockFreqWrite(UINT32 freq)
{
    WRITE_TIMER_REG32(TIMER_REG_CNTFRQ, freq);
}
第二级:
#define WRITE_TIMER_REG32(reg, val) ARM_SYSREG_WRITE(reg, val)
第三级:
#define ARM_SYSREG_WRITE(REG, val)              \
({                                              \
    __asm__ volatile("mcr " REG :: "r" (val));  \
    ISB;                                        \
})

备注:
从代码中可以很清楚的看出来,和上面同样的套路,最终调用arm的汇编语言对相关寄存器进行配置

(5)、OsSystemInfo()

从名称上看应该是系统的相关信息,代码追进去看一下:

LITE_OS_SEC_TEXT_INIT VOID OsSystemInfo(VOID)
{
#ifdef LOSCFG_DEBUG_VERSION
    const CHAR *buildType = "debug";
#else
    const CHAR *buildType = "release";
#endif /* LOSCFG_DEBUG_VERSION */

    PRINT_RELEASE("\n******************Welcome******************\n\n"
            "Processor   : %s"
#if (LOSCFG_KERNEL_SMP == YES)
            " * %d\n"
            "Run Mode    : SMP\n"
#else
            "\n"
            "Run Mode    : UP\n"
#endif
            "GIC Rev     : %s\n"
            "build time  : %s %s\n"
            "Kernel      : %s %d.%d.%d.%d/%s\n"
            "\n*******************************************\n",
            LOS_CpuInfo(),
#if (LOSCFG_KERNEL_SMP == YES)
            LOSCFG_KERNEL_SMP_CORE_NUM,
#endif
            HalIrqVersion(), __DATE__, __TIME__,\
            KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, buildType);
}
备注:
从代码上看,这个子程序就是一个PRINT_RELEASE宏,打印内核名称,主版本号,次版本号,内核补丁等内容,只是打印,没有操作

(6)、OsMain()

从名字上看,貌似很重要,代码追进去看一看:

LITE_OS_SEC_TEXT_INIT INT32 OsMain(VOID)
{
    UINT32 ret;

    osRegister();//看名称是系统注册,其实内容是获取时钟等基本信息
//展开上面osRegister()这个函数看一下
/******************************************************/
    LITE_OS_SEC_TEXT_INIT VOID osRegister(VOID)
    {
        g_sysClock = OS_SYS_CLOCK;//获取系统时钟
        g_tickPerSecond =  LOSCFG_BASE_CORE_TICK_PER_SECOND;//获取系统每秒钟的tick数目(类似于人的心跳)

        return;
    }
/******************************************************/

#ifdef LOSCFG_SHELL_DMESG
    ret = OsDmesgInit();//Dmesg工具的初始化
    if (ret != LOS_OK) {
        return ret;
    }
//展开上面OsDmesgInit()这个函数看一下
/******************************************************/
UINT32 OsDmesgInit(VOID)
{
    CHAR* buffer = NULL;

    buffer = (CHAR *)malloc(KERNEL_LOG_BUF_SIZE + sizeof(DmesgInfo));
    if (buffer == NULL) {
        return LOS_NOK;
    }
    g_mallocAddr = buffer;
    g_dmesgInfo = (DmesgInfo *)buffer;
    g_dmesgInfo->logHead = 0;
    g_dmesgInfo->logTail = 0;
    g_dmesgInfo->logSize = 0;
    g_dmesgInfo->logBuf = buffer + sizeof(DmesgInfo);
    g_logBufSize = KERNEL_LOG_BUF_SIZE;

    return LOS_OK;
}
//从上面的代码中,很容易能看出来,就是为了给dmesg工具分配内存,并初始化
/******************************************************/
#endif

#ifdef LOSCFG_SHELL_LK
    OsLkLoggerInit(NULL);
//展开上面OsLkLoggerInit(NULL)这个函数看一下
/**************************************************************/
    VOID OsLkLoggerInit(const CHAR *str)
    {
        (VOID)str;
        (VOID)memset_s(&g_logger, sizeof(Logger), 0, sizeof(Logger));//相关内存清零
        OsLkTraceLvSet(TRACE_DEFAULT);//设置内核信息追踪级别
        LOS_LkRegHook(OsLkDefaultFunc);//设置绑定函数
    #ifdef LOSCFG_SHELL_DMESG
        (VOID)LOS_DmesgLvSet(TRACE_DEFAULT);//设置dmesg打印级别
    #endif
    }
   这里面的一个核心结构是Logger,它具体的内容为:
    typedef struct {
        INT32 module_level;
        INT32 trace_level;
        FILE *fp;
    } Logger;
    从这里面可以大概猜出来,就是任务log的级别
/**************************************************************/
#endif

#if (LOSCFG_KERNEL_TRACE == YES)
    LOS_TraceInit();
#endif

#ifdef LOSCFG_EXC_INTERACTION
#ifdef LOSCFG_ARCH_CORTEX_M7
    /* 4096: 4K space for Stack */
    ret = OsMemExcInteractionInit((UINT32)&__bss_end + 4096);
#else
    ret = OsMemExcInteractionInit((UINTPTR)&__bss_end);
#endif
    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);//滴答定时初始化
    if (ret != LOS_OK) {
        return ret;
    }

#ifdef LOSCFG_PLATFORM_UART_WITHOUT_VFS
#ifdef LOSCFG_DRIVERS
    uart_init();
#endif
#ifdef LOSCFG_SHELL
#endif //LOSCFG_SHELL
#endif //LOSCFG_PLATFORM_UART_WITHOUT_VFS
    ret = OsTaskInit();//系统的任务初始化
    if (ret != LOS_OK) {
        PRINT_ERR("OsTaskInit error\n");
        return ret;
    }
/*上面那个OsTaskInit()函数展开看一下*/
/************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID)
{
    UINT32 index;
    UINT32 size;

    g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;//设置系统的同时运行任务最大数
    size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);
    /*
     * This memory is resident memory and is used to save the system resources
     * of task control block and will not be freed.
     */
    g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);//申请空间
    if (g_taskCBArray == NULL) {
        return LOS_ERRNO_TSK_NO_MEMORY;
    }
    (VOID)memset_s(g_taskCBArray, size, 0, size);//空间初始化

    LOS_ListInit(&g_losFreeTask);//空闲任务链表初始化
    LOS_ListInit(&g_taskRecyleList);//回收任务链表初始化
    for (index = 0; index < g_taskMaxNum; index++) {//遍历所有任务并初始化
        g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;//设置任务状态
        g_taskCBArray[index].taskID = index;//根据任务在数组的位置设置任务id
        LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);//将该任务绑定挂起的链表结点加入到空闲任务链表中
    }

#if (LOSCFG_KERNEL_TRACE == YES)
    LOS_TraceReg(LOS_TRACE_TASK, OsTaskTrace, LOS_TRACE_TASK_NAME, LOS_TRACE_ENABLE);
#endif

    return OsSchedInit();
}
/**************************************************************************/
#if ((LOSCFG_BASE_IPC_QUEUE == YES) || (LOSCFG_BASE_IPC_MUX == YES) || \
     (LOSCFG_BASE_IPC_SEM == YES) || (LOSCFG_BASE_IPC_RWLOCK == YES))
    ret = OsIpcInit();
    if (ret != LOS_OK) {
        return ret;
    }
//展开上面的OsIpcInit()这个函数
LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsIpcInit(VOID)
{
    UINT32 ret;
#if (LOSCFG_BASE_IPC_SEM == YES)
    ret = OsSemInit();//信号量初始化,具体的可以跟进去看一下,其实还是一个套路,按照系统信号量最大的数目限制申请内存,并一一初始化,并将每一个信号量加入到空闲信号量的链表中
    if (ret != LOS_OK) {
        return ret;
    }
#endif

#if (LOSCFG_BASE_IPC_QUEUE == YES)
    ret = OsQueueInit();//信号量队列初始化,具体的可以跟进去看一下,和信号量的初始化差不多
    if (ret != LOS_OK) {
        return ret;
    }
#endif
    return LOS_OK;
}

#endif

    ret = OsSysMemInit();//系统内存初始化,内容还是比较复杂的,包括内存空间的初始化,虚拟内存与物理内存的转换关系,页表的产生,内存映射等内容
    if (ret != LOS_OK) {
        PRINT_ERR("OsSysMemInit error\n");
        return ret;
    }

    SyscallHandleInit();

    /*
     * CPUP should be inited before first task creation which depends on the semaphore
     * when LOSCFG_KERNEL_SMP_TASK_SYNC is enabled. So don't change this init sequence
     * if not neccessary. The sequence should be like this:
     * 1. OsIpcInit
     * 2. OsCpupInit
     * 3. other inits have task creation
     */
#ifdef LOSCFG_KERNEL_CPUP
    ret = OsCpupInit();
    if (ret != LOS_OK) {
        PRINT_ERR("OsCpupInit error\n");
        return ret;
    }
#endif

    ret = OsSystemProcessCreate();//创建系统进程
    if (ret != LOS_OK) {
        return ret;
    }

#if (LOSCFG_BASE_CORE_SWTMR == YES)
    ret = OsSwtmrInit();//软件定时器的初始化
    if (ret != LOS_OK) {
        return ret;
    }
#endif

#ifdef LOSCFG_KERNEL_CPUP
    OsCpupGuardCreator();//cpu占有率监控进程创建,其实就是定时去采样cpu的状态,里面用到了软件定时器,所以必须在软件定时器初始化以后再创建
#endif

#if (LOSCFG_KERNEL_SMP == YES)
    (VOID)OsMpInit();//多核模式下,循环去查询所有的有效任务(线程)的状态,里面也用到了软件定时器
#endif

#if defined(LOSCFG_HW_RANDOM_ENABLE) || defined (LOSCFG_DRIVERS_RANDOM)
    random_alg_context.ra_init_alg(NULL);
    run_harvester_iterate(NULL);
#endif

#ifdef LOSCFG_COMPAT_BSD
    ret = OsBsdInit();
    if (ret != LOS_OK) {
        PRINT_ERR("init bsd failed!\n");
        return ret;
    }
#endif

#ifdef LOSCFG_KERNEL_PIPE
    OsDriverPipeInit();
#endif

    ret = OsSystemInit();//系统相关的内容初始化,包括虚拟文件系统,创建SystemInit任务等
    if (ret != LOS_OK) {
        return ret;
    }
#if (LOSCFG_BASE_CORE_HILOG == YES)
    ret = HiLogDriverInit();//看名字是HiLog设备的驱动初始化,可是HiLog是什么设备呢?和海思处理器相关?
    if (ret != LOS_OK) {
        return ret;
    }
#endif

#if LOSCFG_DRIVERS_HIEVENT
    OsDriverHiEventInit();
#endif

#if (LOSCFG_KERNEL_LITEIPC == YES)
    ret = LiteIpcInit();
    if (ret != LOS_OK) {
        return ret;
    }
#endif

#ifdef LOSCFG_KERNEL_VDSO
    ret = OsInitVdso();
    if (ret != LOS_OK) {
        return ret;
    }
#endif

    ret = OsFutexInit(); //看名字是fast mutex 初始化,具体功能不详
    if (ret != LOS_OK) {
        PRINT_ERR("Create futex failed : %d!\n", ret);
        return ret;
    }

    ret = OomTaskInit(); //看名字是out of memory 任务初始化,具体功能不详
    if (ret != LOS_OK) {
        return ret;
    }

    return LOS_OK;
}

(7)、?release_secondary_cores()

从名称上看,应该是启动其他cpu核心,具体代码没有看明白,后期补充

(8)、CPU_MAP_SET(0,?OsHwIDGet())

从名称上看,应该是设置cpu核心的ID

(9)、OsSchedStart()

从名称上看,应该是开启系统的各项task,代码跟进去看一下:
?

VOID OsSchedStart(VOID)
{
    UINT32 cpuid = ArchCurrCpuid();//获得当前任务的cpu核心id
    UINT32 intSave;

    SCHEDULER_LOCK(intSave);

    OsTickStart();//滴答定时器启动

    LosTaskCB *newTask = OsGetTopTask();//启动栈顶部的任务
    LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID);//根据当前任务绑定的进程ID创建一个进程

    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//设置任务(线程)的状态
    newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;//设置进程的状态
    newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus);

    OsSchedSetStartTime(HalClockGetCycles());
    newTask->startTime = OsGerCurrSchedTimeCycle();

#if (LOSCFG_KERNEL_SMP == YES)
    /*
     * attention: current cpu needs to be set, in case first task deletion
     * may fail because this flag mismatch with the real current cpu.
     */
    newTask->currCpu = cpuid;
#endif

    OsCurrTaskSet((VOID *)newTask);

    /* System start schedule */
    OS_SCHEDULER_SET(cpuid);

    OsPercpuGet()->responseID = OS_INVALID;
    OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, newTask->startTime + newTask->timeSlice, OS_INVALID);

    PRINTK("cpu %d entering scheduler\n", cpuid);
    OsTaskContextLoad(newTask);
}

到这里,openharmony的liteos-a内核的初始化过程基本上分析完成。好了,今天就记录到这里

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 11:01:09  更:2021-09-10 11:01:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:04:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码