When looking at Linux Code, many of the drive's init functions contain macros similar to core_initcall and subsys_initcall. At first, they may not understand what these macros are used, later, I may guess it was called during kernel initialization, and later I may be interested in calling these initialization Macros in the kernel. Here I will summarize the issue and forget it.
Preface
Macro definition _ define_initcall (Level, FN) is very important for Kernel initialization, it indicates
During compilation, the compiler sorts the starting address values of a series of initialization functions in a certain order.
In a section. During kernel initialization, do_initcballs () will start from
Section extracts the starting addresses of these functions in the form of function pointers to complete the corresponding
. The initialization of some parts of the kernel depends on the initialization of some other parts.
Therefore, this order is often very important.
The following describes how to analyze the Code defined by the _ define_initcall (Level, FN) Macro.
Analyze the structure of the Section named initcall. init, and analyze the kernel initialization function.
How does do_initcballs () Use macro definition _ define_initcall (Level, FN) and its phase
To initialize some parts of the kernel in sequence.
1. Analysis _ define_initcall (Level, FN) macro definition
1) The macro is defined in inlclude/Linux/init. h:
# DEFINE _ define_initcall (Level, FN )/
Static initcall_t _ initcall _ # FN/
_ Attribute _ (_ Section _ (". initcall" level ". init ")))/
= FN
Initcall_t is a function pointer type:
Typedef int (* initcall_t) (void );
Attribute _ attribute _ (_ Section _ () indicates that the object is placed in
Section referred to by the name in parentheses.
Therefore, the definition of this macro is as follows: 1) declare a function named _ initcall _ # FN
Pointer (# indicates replacing the connection); 2) initialize this function pointer to FN; 3) Compile
You need to put this function pointer variable to the name ". initcall" level ". init"
(For example, level = "1" indicates that the section name is ". initcall1.init ").
2) Example: __define_initcall (6, pci_init)
The preceding macro call means: 1) declare a function pointer _ initcall_pic_init = pci_init;
And 2) the pointer Variable _ initcall_pic_init needs to be placed in the name of. initcall6.init.
Section (the essence is to place the first address of this function pic_init to this
Section ).
3) This macro is not directly used, but is defined as the following other simpler 7 derivative macros.
These macro extensions are also defined in inlclude/Linux/init. h:
# Define core_initcall (FN) _ define_initcall ("1", FN)
# Define postcore_initcall (FN) _ define_initcall ("2", FN)
# Define arch_initcall (FN) _ define_initcall ("3", FN)
# Define subsys_initcall (FN) _ define_initcall ("4", FN)
# Define fs_initcall (FN) _ define_initcall ("5", FN)
# Define device_initcall (FN) _ define_initcall ("6", FN)
# Define late_initcall (FN) _ define_initcall ("7", FN)
Therefore, the function pointer declared by macro core_initcall () will be placed in
. Initcall1.init section, and the macro postcore_initcall ()
The declared function pointer will be placed in the section named. initcall2.init,
And so on.
4) Example: device_initcall (pci_init)
Interpretation is as follows: 1-2 ).
2. the section related to the initialization call -- initcall. init is divided into seven subsections.
1) They are. initcall1.init,. initcall2.init,..., and. initcall7.init in sequence.
2) sort by order
3) they are defined in the vmlinux. LDS. s file.
For example, for i386 +, there are:
_ Initcall_start = .;
. Initcall. init :{
* (. Initcall1.init)
* (. Initcall2.init)
* (. Initcall3.init)
* (. Initcall4.init)
* (. Initcall5.init)
* (. Initcall6.init)
* (. Initcall7.init)
}
_ Initcall_end = .;
In makefile
Ldflags_vmlinux + =-t arch/$ (ARCH)/kernel/vmlinux. LDS. s
4) The total start position of the seven sections is marked as _ initcall_start,
The end is marked as _ initcall_end.
3. the kernel initialization function do_basic_setup (): do_initcall() will start from. initcall. init
, That is, all function pointers are retrieved from the seven sections in sequence, and these
Function pointer to complete the initialization of the kernel.
The function is defined in init/Main. C:
Extern initcall_t _ initcall_start, _ initcall_end;
Static void _ init do_initcils (void)
{
Initcall_t * call;
....
For (call = & __ initcall_start; call <& __ initcall_end; call ++)
{
....
(* Call )();
....
}
....
}
These function pointers direct to the macro _ define_initcall (Level, FN)
The assignment function fn. the order in which they call is the order placed in these sections,
This order is very important. This is the role of this macro _ define_initcall (Level, FN.
Note that _ initcall_start and _ initcall_end are sections.
Initcall. init header and end.
4. Inductive
1) _ define_initcall (Level, FN) indicates the compiler to initialize some functions.
Pointer (that is, the start address of the function) in order to place a pointer named. initcall. init
In section, this section is divided into seven subsections, which are arranged in order.
During kernel initialization, the function pointers placed in this section will be used
Do_initcils () is called in sequence to complete initialization.
2) The subsection to which the function pointer is placed is determined by the macro-defined level.
The subsection is located at the beginning. Function pointers in the same subsection are in an indefinite sequence,
It will be randomly specified by the compiler in the compilation order.
3) Therefore, if you want an initialization function to be called during kernel initialization
You should use macro _ define_initcall (Level, FN) or its seven derivative macros
The pointer corresponding to the function FN is placed in the corresponding section in the initialization order.
Colleague, if an initialization function fn_ B needs to depend on another initialization function fn_a's
Then, put fn_ B in a subsection that is greater than the level value corresponding to fn_a,
In this way, do_initcballs () will call fn_ B after fn_a.
In addition, there is an important macro used in many BSP (taking s3c as an example ):
The linux2.6.18 kernel has the following macro definitions in the Mach-s3c2410.c file:
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch to SMDK2410 */ /* Maintainer: Jonas Dietsche */ .phys_io = S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = smdk2410_map_io, .init_irq = s3c24xx_init_irq, .init_machine = smdk_machine_init, .timer = &s3c24xx_timer, MACHINE_END
|
Machine_start is defined in include/ASM-arm/Mach/arch. h.
#define MACHINE_START(_type,_name) / static const struct machine_desc __mach_desc_##_type / __attribute_used__ / __attribute__((__section__(".arch.info.init"))) = { / .nr = MACH_TYPE_##_type, / .name = _name, #define MACHINE_END / };
|
Expand the previously defined machine_start and obtain the following information,
static const struct machine_desc __mach_desc_SMDK2410 __attribute_used__ __attribute__((__section__(".arch.info.init"))) = { .nr = MACH_TYPE_SMDK2410, /* architecture number */ .name = "SMDK2410", /* architecture name */ /* Maintainer: Jonas Dietsche */ .phys_io = S3C2410_PA_UART, /* start of physical io */ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, /* tagged list */ .map_io = smdk2410_map_io, /* IO mapping function */ .init_irq = s3c24xx_init_irq, .init_machine = smdk_machine_init, .timer = &s3c24xx_timer, }
|
Mach_type_smdk2410 is defined in arch/include/ASM-arm/mach-types.h and the value is 193.
/* ARCH/include/ASM-arm/mach-types.h */
# Define mach_type_smdk2410 193
This value is the machine type value, which is generated by the data defined in arch/ARM/tool/Mach-types during compilation.
/* ARCH/ARM/tool/Mach-types */
Smdk2410 arch_smdk2410 smdk2410 193 found that machine_start mainly defines the type of "struct machine_desc" and puts it in section (".arch.info. init ") is the initialization data, which will be discarded after the kernel is up. Each member function is called in different periods:
1. init_machine is called by mimize_machine in arch/ARM/kernel/setup. C and placed in the arch_initcall () segment. It is automatically called in order. 2. init_irq is called in start_kernel () --> init_irq () --> init_arch_irq ()
3. map_io is used in setup_arch () --> paging_init () --> devicemaps_init (). Other calls are mainly used in setup_arch.