如果有问题,请加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内核的初始化过程基本上分析完成。好了,今天就记录到这里