内核arch_initcall的实现及如何自定义initcall

来源:互联网 发布:指南针软件指标 编辑:程序博客网 时间:2024/06/08 00:15

内核版本号:3.4~4.2

内核arch_initcall的实现

内核有种函数的标示方法,比如:arch_initcall(VSBOARD_XXXX),可以在内核初始化后自动运行VSBOARD_XXXX函数,以此来达到内核模块可裁剪的目的。

他的具体实现原理:

1、使用arch_initcall宏,会在生成的目标ELF文件增加一个名为".initcall"level".init"的section,并将函数指针放置于该section中。

如果多次调用arch_initcall,将会有多个函数指针放置于该section(他的巧妙之处就利用编译器这点)。

2、vmlinux.lds.S(include"vmlinux.lds.h"),会通过INIT_CALLS宏,将.initcallxxx.init系列section重排,并且通过宏,将函数指针变量__initcall0_start指向这些section的位置。

3、在start_kernel的最后阶段,调用该函数指针__initcall0_start:

start_kernel->reset_init->kernel_init->do_basic_setup->

do_initcalls

如何自定义initcall

比如自定义vsboard_initcall宏,并且希望他在内核初始化之初就能自动运行:

1、定义宏:

#definevsboard_initcall(fn)\

    static initcall_t __initcall_##fn##vsboard __used\

   __attribute__((__section__(".initcallvsboard.init"))) = fn

通过该宏标示的函数,会在ELF文件中增加名为.initcallvsboard.init的section。

2、想要自动初始化的函数用宏标示:

vsboard_initcall(VSBOARD_Test);

3、在vmlinux.lds.h中添加该section的函数指针定义:

#define INIT_CALLS                                               \

         VMLINUX_SYMBOL(__vsboard_initcall_start)= .;                  \

          *(.initcallvsboard.init)               \

              VMLINUX_SYMBOL(__initcall_start) =.;               \

              INITCALLS                                     \

              VMLINUX_SYMBOL(__initcall_end) =.;

4、在内核想运行该section函数指针的地方添加代码

extern initcall_t __vsboard_initcall_start[];

       initcall_t *fntest;

    int ret;

    for (fntest = __vsboard_initcall_start;fntest < __initcall_start; fntest++)

        ret = (*fntest)();

注意:fntest的结束位置__initcall_start,和第三点宏中的变量定义相呼应(不同内核版本略有不同)。

0 0
原创粉丝点击