Overview
After the parsing of the kernel options is complete, the initialization of each subsystem enters the second part-the invocation of the entry function. Usually, USB, PCI subsystem will have a portal named Subsys_initcall, if you choose them as a starting point for the study of the kernel, then please find it first.
Statement of section
The section of the attribute attribute in C is the location that can be used to actively customize the code when the target file is linked, as in the wiki, as seen in the Linux kernel.
The following code is from the Linux kernel source include/linux/init.h file. The following variable names, which use the same syntax rules, hold the addresses of each initialization function.
More importantly, the section attribute is also based on a certain rule.
About section See http://lihuize123123.blog.163.com/blog/static/878290522010420111428109/
/* initcalls are now grouped by functionality into separate * subsections. ordering inside the subsections is determined * by link order. * for backwards compatibility, initcall () puts the call in * the device init subsection. * * The ' id ' arg to __define_initcall () is needed so that multiple initcalls * can point at the same handler without causing duplicate-symbol build errors. */#define __define_initcall (level,fn,id) static initcall_t __initcall_# #fn # #id __used __attribute__ (__section__ (". Initcall" level ". Init")) = fn/* * early initcalls run before initializing smp. * * only for built-in code, not modules. */#define early_initcall (FN) __define_ Initcall ("early", fn,early)/* * a "pure" initcall has no dependencies On anything else, and purely * initializes variables that couldn ' t be statically initialized. * * this only exists for built-in code, not for modules. */#define pure_initcall (FN) __define_initcall ("0" , fn,0) #define core_initcall (FN) __define_initcall ("1", fn,1) #define  CORE_INITCALL_SYNC (FN) __define_ Initcall ("1s", fn,1s) #define postcore_initcall (FN) __define_initcall ("2", fn,2) #define postcore_ Initcall_sync (FN) __define_initcall ("2s", fn,2s) #define arch_initcall (FN) __define_initcall ("3", fn,3) #define arch_initcall_sync (FN) __define_initcall ("3s", fn,3s) #define subsys_initcall (FN) __define_initcall ("4" , fn,4) #define subsys_iNitcall_sync (FN) __define_initcall ("4s", fn,4s) #define fs_initcall (FN) __define_initcall ("5", fn,5) #define fs_initcall_sync (FN) __define_initcall ("5s", fn,5s) #define rootfs_initcall (FN) __define_initcall (" Rootfs ", Fn,rootfs) #define device_initcall (FN) __define_initcall (" 6 ", fn,6) #define device_initcall_sync (FN) __define_initcall ("6s", fn,6s) #define late_initcall (FN) __define_initcall ("7", fn,7) #define late_ Initcall_sync (FN) __define_initcall ("7s", fn,7s) #define __initcall (FN) device_initcall (FN) #define __exitcall (FN) static exitcall_t __exitcall_# #fn __exit_call = fn#define console_initcall (FN) static initcall_t __initcall_# #fn __used __section (. Con_ Initcall.init) = fn#define security_initcall (FN) static initcall_t __initcall_## Fn __used __section (. Security_initcall.init)  = FN
Register
These portals have a common feature, which is defined using the __define_initcall macro. Their invocation is not random, but in a certain order, this order depends on the __define_initcall macro. The __define_initcall macro is used to place the specified function pointer in the. Initcall.init section.
. Initcall.init Festival
The kernel executable consists of many object files that are linked together. Object files have many sections, such as text, data, init data, bass, and so on. These object files are linked and loaded by a file called a linker script. The function of this linker script is to map the sections of the input object file to the output file, in other words, it links all the input object files to a single executable file, loading the sections of the executable file at the specified address. Vmlinux.lds is a kernel linker script that exists in the arch/<target>/directory, which is responsible for linking sections of the kernel and loading them into memory at a specific offset. Find the Initcall.init in the Vmlinux.lds file to see the following content
#define INITCALLS* (. initcallearly.init) Vmlinux_symbol (__early_initcall_end) =.; * (. Initcall0.init) * (. initcall0s.init) * (. initcall1.init) * (. initcall1s.init) * (. initcall2.init) * (. Initcall2s.init ) * (. initcall3.init) * (. initcall3s.init) * (. initcall4.init) * (. initcall4s.init) * (. initcall5.init) * (. Initcall5s.ini T) * (. initcallrootfs.init) * (. initcall6.init) * (. initcall6s.init) * (. initcall7.init) * (. initcall7s.init)
That tells us. The Initcall.init section is divided into 7 sub-sections, and the Xxx_initcall entry function pointer is specifically placed in which sub-section is defined by the Xxx_initcall, __define_initcall macro parameters, For example, Core_initcall puts the function pointer in the. Initcall1.init subsection, Device_initcall places the function pointer in the. Initcall6.init subsection, and so on. The order of the individual sub-sections is determined, that is, the function pointer in the. Initcall1.init is called before calling. Function pointers in Initcall2.init, and so on. The different entry functions are placed in different sub-sections, and therefore the order in which they are called is determined.
Note: The common module_init (x) function in the device driver, view init.h file discovery
/** * module_init () - driver initialization entry point * @x: function to be run at kernel boot time or module Insertion * * module_init () will either be called during do _initcalls () (If * builtin) or at module insertion time (if A module). there can only * be one per module. */# Define module_init (x) __initcall (x), #define __initcall (FN) device_initcall (FN)/* don ' t use these in modules, but some people do... */#define early _initcall (FN) module_init (FN) #define core_initcall (FN) module_init (FN) #define postcore_initcall (FN) Module_init (FN) #define arch_initcall (FN) module_init (FN) #define subsys_initcall (FN) Module_init (FN) # Define fs_initcall (FN) module_init (FN) #define device_initcall (FN) module_init (FN) #define late_initcall (FN) module_init (FN)
#define __define_initcall (LEVEL,FN) static initcall_t __initcall_# #fn __used __attribute__ ((__section__ (". Initcall") ". Init")) = fn/* userspace initcalls shouldn ' t depend on anything at the kernel, so we'll * make them run first. */#define __initcall (FN) __define_initcall ("1", fn) #define __exitcall (FN) static exitcall_t __exitcall_# #fn __exit_ Call = Fn#define __init_call__used __section (. Initcall.init)
This infers that the Module_init call priority is 6 lower than the Subsys_initcall call Priority 4
called
Static void __init do_initcalls (void) {initcall_t *fn;for (fn = __early_ initcall_end; fn < __initcall_end; fn++) Do_one_initcall (*FN);/* Make sure there is no pending stuff from the initcall sequence */ Flush_scheduled_work ();} Int __init_or_module do_one_initcall (INITCALL_T&NBSP;FN) {int count = preempt_count (); int ret;if (initcall_debug) Ret = do_one_initcall_debug (FN); Elseret = fn (); msgbuf [0] = 0;if (Ret && ret != -enodev && initcall_ Debug) sprintf (msgbuf, "error code %d ", ret);if (Preempt_count () != Count) {strlcat (msgbuf, "preemption imbalance ", sizeof (MSGBUF));p Reempt_count () = count;} if (irqs_disabled ()) {strlcat (msgbuf, "disabled interrupts ", sizeof(MSGBUF)); Local_irq_enable ();} if (Msgbuf[0]) {printk ("initcall %pf returned with %s\n", fn, msgbuf);} Return ret;}
In BUILDING
Initialization of the Linux subsystem _subsys_initcall ()