单核系统启动流程

更新时间:
2024-03-14
下载文档

单核系统启动流程

本节使用 mini2440 的 SylixOS BSP 来介绍 SylixOS 单核启动流程。其主要流程如下图 单核启动流程图:

前面提到过 SylixOS 启动时,会先从 startup.S 文件中的 reset 汇编函数开始执行,reset 函数最后会调用 bspInit.c 文件中的 C 入口函数 bspInit 函数。

bspInit 函数包含了整个 BSP 单核启动的所有流程,其内容可以总结为以下部分:

  • 初始化硬件,包括调试串口。
  • 设置操作系统启动参数。
  • 启动内核。

目前,因为 mini2440 大多使用 u-boot 启动,u-boot 本身会对板子上基础硬件做初始化操作,其中包括调试串口,所以第一步可以不必做过多操作。

第二步启动参数设置,在上节已经做过介绍,需将启动参数传入 API_KernelStartParam 函数执行即可。

bspInit 函数最主要的是第三步启动内核。启动内核调用的是 API_KernelStartAPI_KernelStart 是一个宏,内容如下:

#Include <SylixOS.h>
#define API_KernelStart API_KernelPrimaryStart

它对应内核里的 API_KernelPrimaryStart 函数。此函数原型如下:

#Include <SylixOS.h>
VOID  API_KernelPrimaryStart (PKERNEL_START_ROUTINE          pfuncStartHook,
                              PVOID                         pvKernelHeapMem,
                              size_t                        stKernelHeapSize,
                              PVOID                         pvSystemHeapMem,
                              size_t                        stSystemHeapSize);

函数 API_KernelPrimaryStart 原型分析:

  • 此函数没有返回值。
  • 参数 pfuncStartHook 是系统启动中的用户回调。
  • 参数 pvKernelHeapMem 是内核堆内存首地址。
  • 参数 stKernelHeapSize 是内核堆大小。
  • 参数 pvSystemHeapMem 是系统堆内存首地址。
  • 参数 stSystemHeapSize 是系统堆大小。

API_KernelPrimaryStart 函数是系统内核的入口,只允许系统逻辑主核调用。因为 mini2440 是单核,其唯一的一个核就是逻辑主核,因此可以使用这个函数。

API_KernelPrimaryStart 函数会先对内核底层做初始化操作,这里的底层指的是系统堆和内核堆,以及一些消息队列,内存管理等内容。然后会初始化中断系统,接着会对内核高层和CPP运行库做对应的初始化操作。

完成上述这些步骤后,会执行用户的回调函数,即执行 pfuncStartHook 。mini2440 的 BSP 里实现的这个回调参数为 usrStartup。其调用如下:

API_KernelStart(usrStartup,
               (PVOID)&__heap_start,
               (size_t)&__heap_end - (size_t)&__heap_start,
               LW_NULL, 0);                                       

usrStartup 函数会初始化应用相关的组件,并且创建操作系统的第一个任务。在初始化相关组件的时候,用户需要注意代码编写的顺序,必须先初始化 vmm,才能正确初始化 cache。网络因为需要其他资源,所以需要最后初始化。如下:

static VOID  usrStartup (VOID)
{
    LW_CLASS_THREADATTR     threakattr;
    /*
     *  注意, 不要修改该初始化顺序 (必须先初始化 vmm 才能正确的初始化 cache, 网络需要其他资源必须最后初始化)
     */
    halIdleInit();
#if LW_CFG_CPU_FPU2_EN > 0
    halFpuInit();
#endif                                                /*  LW_CFG_CPU_FPU_EN > 0       */
#if LW_CFG_RTC_EN > 0
    halTimeInit();
#endif                                                /*  LW_CFG_RTC_EN > 0           */
#if LW_CFG_VMM_EN > 0
    halVmmInit();
#endif                                                /*  LW_CFG_VMM_EN > 0           */
#if LW_CFG_CACHE_EN > 0
    halCacheInit();
#endif                                                /*  LW_CFG_CACHE_EN > 0         */
    API_ThreadAttrBuild(&threakattr,
                         __LW_THREAD_BOOT_STK_SIZE,
                         LW_PRIO_CRITICAL,
                         LW_OPTION_THREAD_STK_CHK,
                         LW_NULL);
    API_ThreadCreate("t_boot",
                     (PTHREAD_START_ROUTINE)halBootThread,
                     &threakattr,
                     LW_NULL);                        /*  Create boot thread          */
}

从上述代码中可以发现,在 usrStartup 最后会创建的操作系统的第一个任务,“t_boot”任务。其会初始化系统启动时要用的各项设备、驱动及 log 等内容。初始化完之后,会执行启动脚本并会创建“t_main”线程。

当“t_main”线程创建完成之后, pfuncStartHook 执行完成,此时代码继续从 API_KernelPrimaryStart 函数中往后执行,API_KernelPrimaryStart 函数最后通过调用 _KernelPrimaryEntry 函数启动内核。_KernelPrimaryEntry 函数原型如下:

#include <SylixOS.h>
static  VOID  _KernelPrimaryEntry (PLW_CLASS_CPU   pcpuCur)

函数 _KernelPrimaryEntry 原型分析:

  • 此函数没有返回值。
  • 参数 pcpuCur 是当前CPU的信息。

这个函数是主核调用的启动函数。因为 mini2440 是单核,因此当前的CPU就是主核,从而可以调用此函数。_KernelPrimaryEntry 函数最终会调用 _KernelPrimaryCoreStartup 函数,其函数原型如下:

#include <SylixOS.h>
static  VOID  _KernelPrimaryCoreStartup (PLW_CLASS_CPU   pcpuCur)

函数 _KernelPrimaryCoreStartup 原型分析:

  • 此函数没有返回值。
  • 参数 pcpuCur 是当前CPU的信息。

_KernelPrimaryCoreStartup 函数使得系统的主核 (负责初始化的核) 进入多任务状态,方法是调用 archTaskCtxStart,即进行一次任务切换。此时,SylixOS 单核启动的流程基本完成。

文档内容是否对您有所帮助?
有帮助
没帮助