2012-05-10 13 views
6

Istnieje wiele instancji wywołań __init w jądrze, zarówno w module module_init, jak i innych funkcjach jądra. Mam wątpliwości, w jaki sposób kernel określa kolejność wywołania __init. Co ważniejsze, w jaki sposób określa on również kolejność wywoływania modułu module_init?W jaki sposób Kernel określa sekwencję __init połączeń

Odpowiedz

9

Cała magia startowych są realizowane w plikach:

  1. include/asm-generic/vmlinux.lds.h
  2. include/linux/init.h
  3. init/main.c

Po pierwsze, patrzeć na include/asm-generic/vmlinux.lds.h który zawiera following:

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 = .; 

Gdzie INIT_TEXT_SECTION i INIT_DATA_SECTION zdefiniowane następująco:

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   } 

Spójrzmy na INIT_CALLS określa na przykład:

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) = .; 

Możesz zobaczyć ten definiuje sekcje nazwy, które oznaczone .initcall.... Wszystkie oznaczone dane trafiają do zakresu __initcall_start .. __initcall_end.


Teraz spójrzmy na [include/linux/init.h że zawiera following:

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

I dalej:

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); 

Więc widać, że module_init zdefiniowany jako __initcall że zdefiniowany jako device_initcall że zdefiniowanej jako __define_initcall("6",fn,6). Sześć tutaj oznacza poziom wejściowy. Zobacz poniżej ...


init/main.c zawiera following:

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 } 

Jak widać do_initcall prosto iteracje nad wszystkimi initcall poziomach i wzywa do_initcall_level dla każdego z nich, który wywołuje do_one_initcall do wejścia na każdy poziom. uwaga


Miejmy również, że kernel odrzuca wszystkie funkcje __init po wykonaniu. Więc nie odbywają się w pamięci po załadowaniu jądra.

To wszystko.

Powiązane problemy