GNU/Linux >> Linux の 問題 >  >> Linux

Linux カーネルは __init 呼び出しの順序をどのように決定しますか?

すべての init マジックはファイルに実装されています:

<オール>
  • include/asm-generic/vmlinux.lds.h
  • include/linux/init.h
  • init/main.c
  • まず、include/asm-generic/vmlinux.lds.h を見てください。 以下を含む:

     13  *      . = START;
     14  *      __init_begin = .;
     15  *      HEAD_TEXT_SECTION
     16  *      INIT_TEXT_SECTION(PAGE_SIZE)
     17  *      INIT_DATA_SECTION(...)
     18  *      PERCPU_SECTION(CACHELINE_SIZE)
     19  *      __init_end = .;
    

    ここで、INIT_TEXT_SECTION と INIT_DATA_SECTION は次のように定義されます:

    790 #define INIT_TEXT_SECTION(inittext_align)                               \
    791         . = ALIGN(inittext_align);                                      \
    792         .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {               \
    793                 VMLINUX_SYMBOL(_sinittext) = .;                         \
    794                 INIT_TEXT                                               \
    795                 VMLINUX_SYMBOL(_einittext) = .;                         \
    796         }
    797 
    798 #define INIT_DATA_SECTION(initsetup_align)                              \
    799         .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {               \
    800                 INIT_DATA                                               \
    801                 INIT_SETUP(initsetup_align)                             \
    802                 INIT_CALLS                                              \
    803                 CON_INITCALL                                            \
    804                 SECURITY_INITCALL                                       \
    805                 INIT_RAM_FS                                             \
    806         }
    

    たとえば、INIT_CALLS の定義を見てみましょう:

    628 #define INIT_CALLS_LEVEL(level)                                         \
    629                 VMLINUX_SYMBOL(__initcall##level##_start) = .;          \
    630                 *(.initcall##level##.init)                              \
    631                 *(.initcall##level##s.init)  
    
    633 #define INIT_CALLS                                                      \
    634                 VMLINUX_SYMBOL(__initcall_start) = .;                   \
    635                 *(.initcallearly.init)                                  \
    636                 INIT_CALLS_LEVEL(0)                                     \
    637                 INIT_CALLS_LEVEL(1)                                     \
    638                 INIT_CALLS_LEVEL(2)                                     \
    639                 INIT_CALLS_LEVEL(3)                                     \
    640                 INIT_CALLS_LEVEL(4)                                     \
    641                 INIT_CALLS_LEVEL(5)                                     \
    642                 INIT_CALLS_LEVEL(rootfs)                                \
    643                 INIT_CALLS_LEVEL(6)                                     \
    644                 INIT_CALLS_LEVEL(7)                                     \
    645                 VMLINUX_SYMBOL(__initcall_end) = .;
    

    これは、.initcall... でマークされたセクション名を定義していることがわかります。 .マークされたデータはすべて __initcall_start .. __initcall_end に入ります

    [include/linux/init.h を見てみましょう 以下を含む:

    44 #define __init          __section(.init.text) __cold notrace
    45 #define __initdata      __section(.init.data)
    

    さらに:

    189 #define __define_initcall(level,fn,id) \
    190         static initcall_t __initcall_##fn##id __used \
    191         __attribute__((__section__(".initcall" level ".init"))) = fn
    ...
    220 #define device_initcall(fn) __define_initcall("6",fn,6)
    ...
    225 #define __initcall(fn) device_initcall(fn)
    ...
    271 /**
    272  * module_init() - driver initialization entry point
    273  * @x: function to be run at kernel boot time or module insertion
    274  * 
    275  * module_init() will either be called during do_initcalls() (if
    276  * builtin) or at module insertion time (if a module).  There can only
    277  * be one per module.
    278  */
    279 #define module_init(x)  __initcall(x);
    

    module_init がわかります __initcall として定義 device_initcall と定義されている __define_initcall("6",fn,6) と定義されている .ここでの 6 は、initcall レベルを意味します。以下を参照してください...

    init/main.c 以下が含まれます:

    711 extern initcall_t __initcall_start[];
    712 extern initcall_t __initcall0_start[];
    713 extern initcall_t __initcall1_start[];
    714 extern initcall_t __initcall2_start[];
    715 extern initcall_t __initcall3_start[];
    716 extern initcall_t __initcall4_start[];
    717 extern initcall_t __initcall5_start[];
    718 extern initcall_t __initcall6_start[];
    719 extern initcall_t __initcall7_start[];
    720 extern initcall_t __initcall_end[];
    721
    722 static initcall_t *initcall_levels[] __initdata = {
    723         __initcall0_start,
    724         __initcall1_start,
    725         __initcall2_start,
    726         __initcall3_start,
    727         __initcall4_start,
    728         __initcall5_start,
    729         __initcall6_start,
    730         __initcall7_start,
    731         __initcall_end,
    732 };
    733 
    734 /* Keep these in sync with initcalls in include/linux/init.h */
    735 static char *initcall_level_names[] __initdata = {
    736         "early",
    737         "core",
    738         "postcore",
    739         "arch",
    740         "subsys",
    741         "fs",
    742         "device",
    743         "late",
    744 };
    745 
    746 static void __init do_initcall_level(int level)
    747 {
    748         extern const struct kernel_param __start___param[], __stop___param[];
    749         initcall_t *fn;
    750 
    751         strcpy(static_command_line, saved_command_line);
    752         parse_args(initcall_level_names[level],
    753                    static_command_line, __start___param,
    754                    __stop___param - __start___param,
    755                    level, level,
    756                    &repair_env_string);
    757 
    758         for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
    759                 do_one_initcall(*fn);
    760 }
    761 
    762 static void __init do_initcalls(void)
    763 {
    764         int level;
    765 
    766         for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
    767                 do_initcall_level(level);
    768 }
    

    ご覧のとおり do_initcall すべての initcall レベルを単純に反復し、do_initcall_level を呼び出します 各レベルのエントリに対して do_one_initcall を呼び出すそれぞれに対して。

    カーネルがすべての __init を破棄することにも注意してください 実行後の機能。そのため、カーネルのロード後にメモリ内で発生しません。

    以上です。


    Linux
    1. Linux – Linuxカーネルシステムコールの実装を見つける方法は?

    2. Linux – Linuxカーネルはどのようにしてデバイスのメジャー番号とマイナー番号を認識しますか?

    3. Linux –どのモジュールがカーネルを汚染しているかを判断する方法は?

    1. Linux – Unix / linuxファイルのディレクトリ構造情報をどのように検査しますか?

    2. Linux – Linuxカーネルはマイクロカーネルアーキテクチャとどのように比較されますか?

    3. 「ls」コマンドは Linux/Unix でどのように機能しますか?

    1. Linux カーネルが使用するキャッシュを消去する方法

    2. Linuxカーネルコードで__initはどういう意味ですか?

    3. Linux カーネルはマイクロカーネル アーキテクチャと比べてどうですか?