当前位置:   article > 正文

openharmonyos1.1.0 liteos-a内核学习记录(一)_(void)memset_s(g_taskcbarray, size, 0, size);

(void)memset_s(g_taskcbarray, size, 0, size);

 如果有问题,请加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函数分析:

  1. LITE_OS_SEC_TEXT_INIT INT32 main(VOID)
  2. {
  3. UINT32 uwRet = LOS_OK;
  4. OsSetMainTask();//配置系统初始化的任务
  5. OsCurrTaskSet(OsGetMainTask());
  6. /* set smp system counter freq */
  7. #if (LOSCFG_KERNEL_SMP == YES)
  8. #ifndef LOSCFG_TEE_ENABLE
  9. HalClockFreqWrite(OS_SYS_CLOCK);
  10. #endif
  11. #endif
  12. /* system and chip info */
  13. OsSystemInfo();//打印系统的相关信息
  14. PRINT_RELEASE("\nmain core booting up...\n");
  15. uwRet = OsMain();
  16. if (uwRet != LOS_OK) {
  17. return LOS_NOK;
  18. }
  19. #if (LOSCFG_KERNEL_SMP == YES)
  20. PRINT_RELEASE("releasing %u secondary cores\n", LOSCFG_KERNEL_SMP_CORE_NUM - 1);
  21. release_secondary_cores();
  22. #endif
  23. CPU_MAP_SET(0, OsHwIDGet());
  24. OsSchedStart();//系统使能调度器
  25. while (1) {
  26. __asm volatile("wfi");
  27. }
  28. }

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

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

  1. 备注:
  2. g_mainTask:struct LosTaskCB结构体数组,每一个元素代表一个任务
  3. VOID OsSetMainTask()
  4. {
  5. UINT32 i;
  6. CHAR *name = "osMain";
  7. for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {//遍历cpu所有核心,配置相关参数
  8. //LOSCFG_KERNEL_CORE_NUM,CPU核心数目
  9. g_mainTask[i].taskStatus = OS_TASK_STATUS_UNUSED;//初始化当前任务的状态为unused
  10. g_mainTask[i].taskID = LOSCFG_BASE_CORE_TSK_LIMIT;//初始化当前任务ID都为128
  11. g_mainTask[i].priority = OS_TASK_PRIORITY_LOWEST;//初始化当前任务的优先级都为低
  12. #if (LOSCFG_KERNEL_SMP_LOCKDEP == YES)
  13. g_mainTask[i].lockDep.lockDepth = 0;
  14. g_mainTask[i].lockDep.waitLock = NULL;
  15. #endif
  16. (VOID)strncpy_s(g_mainTask[i].taskName, OS_TCB_NAME_LEN, name, OS_TCB_NAME_LEN - 1);
  17. LOS_ListInit(&g_mainTask[i].lockList);//
  18. }
  19. }

(2)、OsGetMainTask()

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

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

(3)、OsCurrTaskSet(OsGetMainTask())

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

  1. //第一级
  2. STATIC INLINE VOID OsCurrTaskSet(LosTaskCB *task)
  3. {
  4. ArchCurrTaskSet(task);
  5. }
  6. //第二级
  7. STATIC INLINE VOID ArchCurrTaskSet(VOID *val)
  8. {
  9. ARM_SYSREG_WRITE(TPIDRPRW, (UINT32)(UINTPTR)val);
  10. }
  11. //第三级
  12. #define ARM_SYSREG_WRITE(REG, val) \
  13. ({ \
  14. __asm__ volatile("mcr " REG :: "r" (val)); \
  15. ISB; \
  16. })
  17. 备注:
  18. TPIDRPRW = CP15_REG(c13, 0, c0, 4)
  19. #define CP15_REG(CRn, Op1, CRm, Op2) "p15, "#Op1", %0, "#CRn","#CRm","#Op2
  20. 这样一级一级追下去,最终通过汇编代码对寄存器赋值

(4)、HalClockFreqWrite(OS_SYS_CLOCK)

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

  1. 第一级:
  2. VOID HalClockFreqWrite(UINT32 freq)
  3. {
  4. WRITE_TIMER_REG32(TIMER_REG_CNTFRQ, freq);
  5. }
  6. 第二级:
  7. #define WRITE_TIMER_REG32(reg, val) ARM_SYSREG_WRITE(reg, val)
  8. 第三级:
  9. #define ARM_SYSREG_WRITE(REG, val) \
  10. ({ \
  11. __asm__ volatile("mcr " REG :: "r" (val)); \
  12. ISB; \
  13. })
  14. 备注:
  15. 从代码中可以很清楚的看出来,和上面同样的套路,最终调用arm的汇编语言对相关寄存器进行配置

(5)、OsSystemInfo()

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

  1. LITE_OS_SEC_TEXT_INIT VOID OsSystemInfo(VOID)
  2. {
  3. #ifdef LOSCFG_DEBUG_VERSION
  4. const CHAR *buildType = "debug";
  5. #else
  6. const CHAR *buildType = "release";
  7. #endif /* LOSCFG_DEBUG_VERSION */
  8. PRINT_RELEASE("\n******************Welcome******************\n\n"
  9. "Processor : %s"
  10. #if (LOSCFG_KERNEL_SMP == YES)
  11. " * %d\n"
  12. "Run Mode : SMP\n"
  13. #else
  14. "\n"
  15. "Run Mode : UP\n"
  16. #endif
  17. "GIC Rev : %s\n"
  18. "build time : %s %s\n"
  19. "Kernel : %s %d.%d.%d.%d/%s\n"
  20. "\n*******************************************\n",
  21. LOS_CpuInfo(),
  22. #if (LOSCFG_KERNEL_SMP == YES)
  23. LOSCFG_KERNEL_SMP_CORE_NUM,
  24. #endif
  25. HalIrqVersion(), __DATE__, __TIME__,\
  26. KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, buildType);
  27. }
  28. 备注:
  29. 从代码上看,这个子程序就是一个PRINT_RELEASE宏,打印内核名称,主版本号,次版本号,内核补丁等内容,只是打印,没有操作

(6)、OsMain()

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

  1. LITE_OS_SEC_TEXT_INIT INT32 OsMain(VOID)
  2. {
  3. UINT32 ret;
  4. osRegister();//看名称是系统注册,其实内容是获取时钟等基本信息
  5. //展开上面osRegister()这个函数看一下
  6. /******************************************************/
  7. LITE_OS_SEC_TEXT_INIT VOID osRegister(VOID)
  8. {
  9. g_sysClock = OS_SYS_CLOCK;//获取系统时钟
  10. g_tickPerSecond = LOSCFG_BASE_CORE_TICK_PER_SECOND;//获取系统每秒钟的tick数目(类似于人的心跳)
  11. return;
  12. }
  13. /******************************************************/
  14. #ifdef LOSCFG_SHELL_DMESG
  15. ret = OsDmesgInit();//Dmesg工具的初始化
  16. if (ret != LOS_OK) {
  17. return ret;
  18. }
  19. //展开上面OsDmesgInit()这个函数看一下
  20. /******************************************************/
  21. UINT32 OsDmesgInit(VOID)
  22. {
  23. CHAR* buffer = NULL;
  24. buffer = (CHAR *)malloc(KERNEL_LOG_BUF_SIZE + sizeof(DmesgInfo));
  25. if (buffer == NULL) {
  26. return LOS_NOK;
  27. }
  28. g_mallocAddr = buffer;
  29. g_dmesgInfo = (DmesgInfo *)buffer;
  30. g_dmesgInfo->logHead = 0;
  31. g_dmesgInfo->logTail = 0;
  32. g_dmesgInfo->logSize = 0;
  33. g_dmesgInfo->logBuf = buffer + sizeof(DmesgInfo);
  34. g_logBufSize = KERNEL_LOG_BUF_SIZE;
  35. return LOS_OK;
  36. }
  37. //从上面的代码中,很容易能看出来,就是为了给dmesg工具分配内存,并初始化
  38. /******************************************************/
  39. #endif
  40. #ifdef LOSCFG_SHELL_LK
  41. OsLkLoggerInit(NULL);
  42. //展开上面OsLkLoggerInit(NULL)这个函数看一下
  43. /**************************************************************/
  44. VOID OsLkLoggerInit(const CHAR *str)
  45. {
  46. (VOID)str;
  47. (VOID)memset_s(&g_logger, sizeof(Logger), 0, sizeof(Logger));//相关内存清零
  48. OsLkTraceLvSet(TRACE_DEFAULT);//设置内核信息追踪级别
  49. LOS_LkRegHook(OsLkDefaultFunc);//设置绑定函数
  50. #ifdef LOSCFG_SHELL_DMESG
  51. (VOID)LOS_DmesgLvSet(TRACE_DEFAULT);//设置dmesg打印级别
  52. #endif
  53. }
  54. 这里面的一个核心结构是Logger,它具体的内容为:
  55. typedef struct {
  56. INT32 module_level;
  57. INT32 trace_level;
  58. FILE *fp;
  59. } Logger;
  60. 从这里面可以大概猜出来,就是任务log的级别
  61. /**************************************************************/
  62. #endif
  63. #if (LOSCFG_KERNEL_TRACE == YES)
  64. LOS_TraceInit();
  65. #endif
  66. #ifdef LOSCFG_EXC_INTERACTION
  67. #ifdef LOSCFG_ARCH_CORTEX_M7
  68. /* 4096: 4K space for Stack */
  69. ret = OsMemExcInteractionInit((UINT32)&__bss_end + 4096);
  70. #else
  71. ret = OsMemExcInteractionInit((UINTPTR)&__bss_end);
  72. #endif
  73. if (ret != LOS_OK) {
  74. return ret;
  75. }
  76. #endif
  77. #if (LOSCFG_PLATFORM_HWI == YES)
  78. OsHwiInit();//硬件中断初始化
  79. #endif
  80. OsExcInit();//栈初始化
  81. ret = OsTickInit(g_sysClock, LOSCFG_BASE_CORE_TICK_PER_SECOND);//滴答定时初始化
  82. if (ret != LOS_OK) {
  83. return ret;
  84. }
  85. #ifdef LOSCFG_PLATFORM_UART_WITHOUT_VFS
  86. #ifdef LOSCFG_DRIVERS
  87. uart_init();
  88. #endif
  89. #ifdef LOSCFG_SHELL
  90. #endif //LOSCFG_SHELL
  91. #endif //LOSCFG_PLATFORM_UART_WITHOUT_VFS
  92. ret = OsTaskInit();//系统的任务初始化
  93. if (ret != LOS_OK) {
  94. PRINT_ERR("OsTaskInit error\n");
  95. return ret;
  96. }
  97. /*上面那个OsTaskInit()函数展开看一下*/
  98. /************************************************/
  99. LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID)
  100. {
  101. UINT32 index;
  102. UINT32 size;
  103. g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;//设置系统的同时运行任务最大数
  104. size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);
  105. /*
  106. * This memory is resident memory and is used to save the system resources
  107. * of task control block and will not be freed.
  108. */
  109. g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);//申请空间
  110. if (g_taskCBArray == NULL) {
  111. return LOS_ERRNO_TSK_NO_MEMORY;
  112. }
  113. (VOID)memset_s(g_taskCBArray, size, 0, size);//空间初始化
  114. LOS_ListInit(&g_losFreeTask);//空闲任务链表初始化
  115. LOS_ListInit(&g_taskRecyleList);//回收任务链表初始化
  116. for (index = 0; index < g_taskMaxNum; index++) {//遍历所有任务并初始化
  117. g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;//设置任务状态
  118. g_taskCBArray[index].taskID = index;//根据任务在数组的位置设置任务id
  119. LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);//将该任务绑定挂起的链表结点加入到空闲任务链表中
  120. }
  121. #if (LOSCFG_KERNEL_TRACE == YES)
  122. LOS_TraceReg(LOS_TRACE_TASK, OsTaskTrace, LOS_TRACE_TASK_NAME, LOS_TRACE_ENABLE);
  123. #endif
  124. return OsSchedInit();
  125. }
  126. /**************************************************************************/
  127. #if ((LOSCFG_BASE_IPC_QUEUE == YES) || (LOSCFG_BASE_IPC_MUX == YES) || \
  128. (LOSCFG_BASE_IPC_SEM == YES) || (LOSCFG_BASE_IPC_RWLOCK == YES))
  129. ret = OsIpcInit();
  130. if (ret != LOS_OK) {
  131. return ret;
  132. }
  133. //展开上面的OsIpcInit()这个函数
  134. LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsIpcInit(VOID)
  135. {
  136. UINT32 ret;
  137. #if (LOSCFG_BASE_IPC_SEM == YES)
  138. ret = OsSemInit();//信号量初始化,具体的可以跟进去看一下,其实还是一个套路,按照系统信号量最大的数目限制申请内存,并一一初始化,并将每一个信号量加入到空闲信号量的链表中
  139. if (ret != LOS_OK) {
  140. return ret;
  141. }
  142. #endif
  143. #if (LOSCFG_BASE_IPC_QUEUE == YES)
  144. ret = OsQueueInit();//信号量队列初始化,具体的可以跟进去看一下,和信号量的初始化差不多
  145. if (ret != LOS_OK) {
  146. return ret;
  147. }
  148. #endif
  149. return LOS_OK;
  150. }
  151. #endif
  152. ret = OsSysMemInit();//系统内存初始化,内容还是比较复杂的,包括内存空间的初始化,虚拟内存与物理内存的转换关系,页表的产生,内存映射等内容
  153. if (ret != LOS_OK) {
  154. PRINT_ERR("OsSysMemInit error\n");
  155. return ret;
  156. }
  157. SyscallHandleInit();
  158. /*
  159. * CPUP should be inited before first task creation which depends on the semaphore
  160. * when LOSCFG_KERNEL_SMP_TASK_SYNC is enabled. So don't change this init sequence
  161. * if not neccessary. The sequence should be like this:
  162. * 1. OsIpcInit
  163. * 2. OsCpupInit
  164. * 3. other inits have task creation
  165. */
  166. #ifdef LOSCFG_KERNEL_CPUP
  167. ret = OsCpupInit();
  168. if (ret != LOS_OK) {
  169. PRINT_ERR("OsCpupInit error\n");
  170. return ret;
  171. }
  172. #endif
  173. ret = OsSystemProcessCreate();//创建系统进程
  174. if (ret != LOS_OK) {
  175. return ret;
  176. }
  177. #if (LOSCFG_BASE_CORE_SWTMR == YES)
  178. ret = OsSwtmrInit();//软件定时器的初始化
  179. if (ret != LOS_OK) {
  180. return ret;
  181. }
  182. #endif
  183. #ifdef LOSCFG_KERNEL_CPUP
  184. OsCpupGuardCreator();//cpu占有率监控进程创建,其实就是定时去采样cpu的状态,里面用到了软件定时器,所以必须在软件定时器初始化以后再创建
  185. #endif
  186. #if (LOSCFG_KERNEL_SMP == YES)
  187. (VOID)OsMpInit();//多核模式下,循环去查询所有的有效任务(线程)的状态,里面也用到了软件定时器
  188. #endif
  189. #if defined(LOSCFG_HW_RANDOM_ENABLE) || defined (LOSCFG_DRIVERS_RANDOM)
  190. random_alg_context.ra_init_alg(NULL);
  191. run_harvester_iterate(NULL);
  192. #endif
  193. #ifdef LOSCFG_COMPAT_BSD
  194. ret = OsBsdInit();
  195. if (ret != LOS_OK) {
  196. PRINT_ERR("init bsd failed!\n");
  197. return ret;
  198. }
  199. #endif
  200. #ifdef LOSCFG_KERNEL_PIPE
  201. OsDriverPipeInit();
  202. #endif
  203. ret = OsSystemInit();//系统相关的内容初始化,包括虚拟文件系统,创建SystemInit任务等
  204. if (ret != LOS_OK) {
  205. return ret;
  206. }
  207. #if (LOSCFG_BASE_CORE_HILOG == YES)
  208. ret = HiLogDriverInit();//看名字是HiLog设备的驱动初始化,可是HiLog是什么设备呢?和海思处理器相关?
  209. if (ret != LOS_OK) {
  210. return ret;
  211. }
  212. #endif
  213. #if LOSCFG_DRIVERS_HIEVENT
  214. OsDriverHiEventInit();
  215. #endif
  216. #if (LOSCFG_KERNEL_LITEIPC == YES)
  217. ret = LiteIpcInit();
  218. if (ret != LOS_OK) {
  219. return ret;
  220. }
  221. #endif
  222. #ifdef LOSCFG_KERNEL_VDSO
  223. ret = OsInitVdso();
  224. if (ret != LOS_OK) {
  225. return ret;
  226. }
  227. #endif
  228. ret = OsFutexInit(); //看名字是fast mutex 初始化,具体功能不详
  229. if (ret != LOS_OK) {
  230. PRINT_ERR("Create futex failed : %d!\n", ret);
  231. return ret;
  232. }
  233. ret = OomTaskInit(); //看名字是out of memory 任务初始化,具体功能不详
  234. if (ret != LOS_OK) {
  235. return ret;
  236. }
  237. return LOS_OK;
  238. }

(7)、 release_secondary_cores()

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

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

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

(9)、OsSchedStart()

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

  1. VOID OsSchedStart(VOID)
  2. {
  3. UINT32 cpuid = ArchCurrCpuid();//获得当前任务的cpu核心id
  4. UINT32 intSave;
  5. SCHEDULER_LOCK(intSave);
  6. OsTickStart();//滴答定时器启动
  7. LosTaskCB *newTask = OsGetTopTask();//启动栈顶部的任务
  8. LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID);//根据当前任务绑定的进程ID创建一个进程
  9. newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//设置任务(线程)的状态
  10. newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;//设置进程的状态
  11. newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus);
  12. OsSchedSetStartTime(HalClockGetCycles());
  13. newTask->startTime = OsGerCurrSchedTimeCycle();
  14. #if (LOSCFG_KERNEL_SMP == YES)
  15. /*
  16. * attention: current cpu needs to be set, in case first task deletion
  17. * may fail because this flag mismatch with the real current cpu.
  18. */
  19. newTask->currCpu = cpuid;
  20. #endif
  21. OsCurrTaskSet((VOID *)newTask);
  22. /* System start schedule */
  23. OS_SCHEDULER_SET(cpuid);
  24. OsPercpuGet()->responseID = OS_INVALID;
  25. OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, newTask->startTime + newTask->timeSlice, OS_INVALID);
  26. PRINTK("cpu %d entering scheduler\n", cpuid);
  27. OsTaskContextLoad(newTask);
  28. }

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/228508
推荐阅读
相关标签
  

闽ICP备14008679号