RT-Thread 进阶笔记之自动初始化机制

RT-Thread 自动初始化机制

1、自动初始化机制简介

在这里插入图片描述
在系统启动流程图中,有两个函数:rt_components_board_init() 与 rt_components_init(),其后的带底色方框内部的函数表示被自动初始化的函数,其中:

  1. “board init functions” 为所有通过 INIT_BOARD_EXPORT(fn) 申明的初始化函数。
  2. “pre-initialization functions” 为所有通过 INIT_PREV_EXPORT(fn)申明的初始化函数。
  3. “device init functions” 为所有通过 INIT_DEVICE_EXPORT(fn) 申明的初始化函数。
  4. “components init functions” 为所有通过 INIT_COMPONENT_EXPORT(fn)申明的初始化函数。
  5. “enviroment init functions” 为所有通过 INIT_ENV_EXPORT(fn) 申明的初始化函数。
  6. “application init functions” 为所有通过 INIT_APP_EXPORT(fn)申明的初始化函数
    用来实现自动初始化功能的宏接口定义详细描述如下表所示:
    在这里插入图片描述

2、自动初始化机制原理

RT-Thread 的自动初始化机制使用了自定义 RTI 符号段,将需要在启动时进行初始化的函数指针放到了该段中,形成一张初始化函数表,在系统启动过程中会遍历该表,并调用表中的函数,达到自动初始化的目的。
进入任意一个宏定义,可以查看源码中的宏定义如下:

/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn)           INIT_EXPORT(fn, "1")

/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn)            INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn)          INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn)       INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn)             INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn)             INIT_EXPORT(fn, "6")

继续展开INIT_EXPORT(fn, level) 如下:

        #define INIT_EXPORT(fn, level)                                                       \
            RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn

其中##代表连接符,把__rt_init_与fn这个形参名字链接起来,即__rt_init_fn
查看init_fn_t的定义如下:

typedef int (*init_fn_t)(void);

表示用typedef 定义了一个函数指针类型,init_fn_t _rt_init##fn SECTION(".rti_fn." level) = fn表示定义了一个函数指针变量,并初始化,把fn这个函数的地址赋给__rt_init_fn这个函数指针。
其中SECTION(".rti_fn." level)展开如下:

#define SECTION(x)                  __attribute__((section(x)))

_attribute_((section(“name”))) :将作用的函数或数据放入指定名为"name"的输入段中。(在不同的编译器中实现的方式也有所不同。)
总结:作用就是将函数 fn 的地址赋给一个 __rt_init_fn 的指针,然后放入相应 level 的数据段中。所以函数使用自动初始化宏导出后,这些数据段中就会存储指向各个初始化函数的指针。

3、自动初始化机制过程

在程序启动后,会分别运行 rt_components_board_init() 与 rt_components_init() 函数,其中 rt_components_board_init()完成了第1段的初始化,rt_components_init()完成了2到6段的初始化。
1、第一个函数 rt_components_board_init() 的实现:

void rt_components_board_init(void)
{
    const init_fn_t *fn_ptr;

    for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
    {
        (*fn_ptr)();
    }
}

2、第二个函数 rt_components_board_init() 的实现:

void rt_components_init(void)
{
    const init_fn_t *fn_ptr;

    for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
    {
        (*fn_ptr)();
    }
}

其中__rt_init_rti_board_start,__rt_init_rti_board_end,__rt_init_rti_end表示不同的区间段。
在系统中,定义了这几个空函数:rti_start、rti_board_start、rti_board_end、rti_end。划分成不同的段:0、 0.end 、 1.end 、6.end。
自定义的初始化函数就夹裹在这些段内。

static int rti_start(void)
{
    return 0;
}
INIT_EXPORT(rti_start, "0");

static int rti_board_start(void)
{
    return 0;
}
INIT_EXPORT(rti_board_start, "0.end");

static int rti_board_end(void)
{
    return 0;
}
INIT_EXPORT(rti_board_end, "1.end");

static int rti_end(void)
{
    return 0;
}
INIT_EXPORT(rti_end, "6.end");

这几个函数的导出,加上上面 6 个初始化宏的导出,就有了这样一个表格:
在这里插入图片描述
查看map文件可知:
在这里插入图片描述
其中__rt_init_finsh_system_init 为内核shell的初始化:

int finsh_system_init(void)
{
    rt_err_t result = RT_EOK;
    rt_thread_t tid;

#ifdef FINSH_USING_SYMTAB
#if defined(__CC_ARM) || defined(__CLANG_ARM)          /* ARM C Compiler */
    extern const int FSymTab$$Base;
    extern const int FSymTab$$Limit;
    extern const int VSymTab$$Base;
    extern const int VSymTab$$Limit;
    finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit);
#ifndef FINSH_USING_MSH_ONLY
    finsh_system_var_init(&VSymTab$$Base, &VSymTab$$Limit);
#endif
#elif defined (__ICCARM__) || defined(__ICCRX__)      /* for IAR Compiler */
    finsh_system_function_init(__section_begin("FSymTab"),
                               __section_end("FSymTab"));
    finsh_system_var_init(__section_begin("VSymTab"),
                          __section_end("VSymTab"));
#elif defined (__GNUC__) || defined(__TI_COMPILER_VERSION__)
    /* GNU GCC Compiler and TI CCS */
    extern const int __fsymtab_start;
    extern const int __fsymtab_end;
    extern const int __vsymtab_start;
    extern const int __vsymtab_end;
    finsh_system_function_init(&__fsymtab_start, &__fsymtab_end);
    finsh_system_var_init(&__vsymtab_start, &__vsymtab_end);
#elif defined(__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */
    finsh_system_function_init(&__fsymtab_start, &__fsymtab_end);
    finsh_system_var_init(&__vsymtab_start, &__vsymtab_end);
#elif defined(_MSC_VER)
    unsigned int *ptr_begin, *ptr_end;
		
    if(shell)
    {
        rt_kprintf("finsh shell already init.\n");
        return RT_EOK;
    }

    ptr_begin = (unsigned int *)&__fsym_begin;
    ptr_begin += (sizeof(struct finsh_syscall) / sizeof(unsigned int));
    while (*ptr_begin == 0) ptr_begin ++;

    ptr_end = (unsigned int *) &__fsym_end;
    ptr_end --;
    while (*ptr_end == 0) ptr_end --;

    finsh_system_function_init(ptr_begin, ptr_end);
#endif
#endif

#ifdef RT_USING_HEAP
    /* create or set shell structure */
    shell = (struct finsh_shell *)rt_calloc(1, sizeof(struct finsh_shell));
    if (shell == RT_NULL)
    {
        rt_kprintf("no memory for shell\n");
        return -1;
    }
    tid = rt_thread_create(FINSH_THREAD_NAME,
                           finsh_thread_entry, RT_NULL,
                           FINSH_THREAD_STACK_SIZE, FINSH_THREAD_PRIORITY, 10);
#else
    shell = &_shell;
    tid = &finsh_thread;
    result = rt_thread_init(&finsh_thread,
                            FINSH_THREAD_NAME,
                            finsh_thread_entry, RT_NULL,
                            &finsh_thread_stack[0], sizeof(finsh_thread_stack),
                            FINSH_THREAD_PRIORITY, 10);
#endif /* RT_USING_HEAP */

    rt_sem_init(&(shell->rx_sem), "shrx", 0, 0);
    finsh_set_prompt_mode(1);

    if (tid != NULL && result == RT_EOK)
        rt_thread_startup(tid);
    return 0;
}
INIT_APP_EXPORT(finsh_system_init);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章