These articles are the notes for reading the "Cultivation of Linux kernel" and some additional knowledge and insights. If you are not clear about these articles, please refer to the "Cultivation of Linux kernel" and other materials. If there is anything wrong with this article, please point out, thank you.
Reprinted please indicate the source: http://blog.csdn.net/muge0913/article/details/7252107
After the kernel option is parsed, the initialization of each subsystem enters the second part-the call of the entry function. Generally, subsystems such as USB and PCI have an entry named subsys_initcall. If you choose them as the entry point to study the kernel, find them first.
Zhu deyong said in "about work" that it takes the first half of the life to find the entrance and the later half to find the exit. It can be seen that the search portal is very important for us to look at the kernel code in our life.
However, in many cases, the entry is not only subsys_initcall, such as PCI.
117 # define pure_initcall (FN) _ define_initcall ("0", FN, 1)
118
119 # define core_initcall (FN) _ define_initcall ("1", FN, 1)
120 # define core_initcall_sync (FN) _ define_initcall ("1 s", FN, 1 s)
121 # define postcore_initcall (FN) _ define_initcall ("2", FN, 2)
122 # define postcore_initcall_sync (FN) _ define_initcall ("2 s", FN, 2 S)
123 # define arch_initcall (FN) _ define_initcall ("3", FN, 3)
124 # define arch_initcall_sync (FN) _ define_initcall ("3 S", FN, 3 S)
125 # define subsys_initcall (FN) _ define_initcall ("4", FN, 4)
126 # define subsys_initcall_sync (FN) _ define_initcall ("4 s", FN, 4S)
127 # define fs_initcall (FN) _ define_initcall ("5", FN, 5)
128 # define fs_initcall_sync (FN) _ define_initcall ("5 s", FN, 5S)
129 # define rootfs_initcall (FN) _ define_initcall ("rootfs", FN, rootfs)
130 # define device_initcall (FN) _ define_initcall ("6", FN, 6)
131 # define device_initcall_sync (FN) _ define_initcall ("6 s", FN, 6 S)
132 # define late_initcall (FN) _ define_initcall ("7", FN, 7)
133 # define late_initcall_sync (FN) _ define_initcall ("7 s", FN, 7 S)
134
135 # DEFINE _ initcall (FN) device_initcall (FN)
These entries share a common feature that is defined by the _ define_initcall macro. Their calls are not random, but in a certain order. The order depends on the _ define_initcall macro. The _ define_initcall macro is used to put the specified function pointer in the. initcall. init section.
. Initcall. init Section
The kernel executable file consists of many object files linked together. Object files have many sections, such as text, Data, init data, and bass. These object files are all 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 input object files to a single executable file, load the sections of the executable file to the specified address. Vmlinux. LDS is the kernel linker script that exists in the arch/<target>/directory. It is responsible for linking each section of the kernel and loading them to a specific offset in the memory. Find initcall. init in the vmlinux. LDS file and you can see the following content:
_ Inicall_start = .;
. Initcall. init: At (ADDR (. initcall. init)-0xc0000000 ){
* (. Initcall1.init)
* (. Initcall2.init)
* (. Initcall3.init)
* (. Initcall4.init)
* (. Initcall5.init)
* (. Initcall6.init)
* (. Initcall7.init)
}
_ Initcall_end = .;
This tells us. initcall. the init section is divided into seven subsections, And the xxx_initcall entry function pointer is defined by xxx_initcall, And the __define_initcall macro parameter determines the specific subsection, for example, core_initcall places the function pointer in. in the initcall1.init subsection, device_initcall places the function pointer. initcall6.init subsection. The sequence of each subsection is determined, that is, the function pointer in. initcall1.init is called before the function pointer in. initcall2.init. Different entry functions are placed in different subsections, which determines their call sequence.
Do_initcballs () function
The call of those entry functions is completed by the do_initcils function.
The do_initcall function uses the for loop and starts from _ initcall_start until _ initcall_end ends. It calls the identified initialization function in turn. The region is located between _ initcall_start and _ initcall_end. initcall. in the init section, the address of the macro Mark Function in the form of xxx_initcall is saved. The do_initcall function can easily obtain the function address and execute the function to which it points.
The function address saved in the. initcall. init section has a certain priority. The higher the priority of the previous function, the higher the priority will be called first than the function located later.
A function called by the do_initcils function should not change its priority State or prohibit interruption. Therefore, after each function is executed, do_initcils checks whether the function has made any changes. If necessary, it corrects the priority and interrupt status.
In addition, these executed functions can complete some tasks that require asynchronous execution. The flush_scheduled_work function is used to ensure that the do_initcils function waits until these asynchronous tasks end before returning.
666 static void _ init do_initcils (void)
667 {
668 initcall_t * call;
669 int COUNT = preempt_count ();
670
671 for (call = _ initcall_start; call <_ initcall_end; call ++ ){
672 ktime_t T0, T1, Delta;
673 char * MSG = NULL;
674 char msgbuf [40];
675 int result;
676
677 if (initcall_debug ){
678 printk ("calling initcall 0x % P", * Call );
679 print_fn_descriptor_symbol (": % s ()",
680 (unsigned long) * Call );
681 printk ("/N ");
682 T0 = ktime_get ();
683}
684
685 result = (* Call )();
686
687 if (initcall_debug ){
688 T1 = ktime_get ();
689 Delta = ktime_sub (T1, T0 );
690
691 printk ("initcall 0x % P", * Call );
692 print_fn_descriptor_symbol (": % s ()",
693 (unsigned long) * Call );
694 printk ("Returned % d./N", result );
695
696 printk ("initcall 0x % P ran for % LD msecs :",
697 * Call, (unsigned long) Delta. tv64> 20 );
698 print_fn_descriptor_symbol ("% s ()/n ",
699 (unsigned long) * Call );
700}
701
702 if (Result & result! =-Enodev & initcall_debug ){
703 sprintf (msgbuf, "error code % d", result );
704 MSG = msgbuf;
705}
706 if (preempt_count ()! = Count ){
707 MSG = "preemption imbalance ";
708 preempt_count () = count;
709}
710 if (irqs_disabled ()){
711 MSG = "disabled interrupts ";
712 local_irq_enable ();
713}
714 if (MSG ){
715 printk (kern_warning "initcall at 0x % P", * Call );
716 print_fn_descriptor_symbol (": % s ()",
717 (unsigned long) * Call );
718 printk (": returned with % s/n", MSG );
719}
720}
721
722/* make sure there is no pending stuff from the initcall sequence */
723 flush_scheduled_work ();
724}