本文基于mips架构的Cavium的CPU。linux内核版本2.6.27.32
几乎每个module都有两个接口:
module_init()一般调用一个register的接口注册一个driver的驱动接口,例如:
static int __init cfi_probe_init(void)
{
register_mtd_chip_driver(&cfi_chipdrv); //注册驱动接口到链表:chip_drvs_list
//注意不同类型的设备挂载在不同类型的结构体链表上
return 0;
}
static struct mtd_chip_driver cfi_chipdrv = {
.probe = cfi_probe,
.name = "cfi_probe", //后续根据这个名字调用对应的驱动接口和驱动处理函数
.module = THIS_MODULE
};
module_exit()
下面说一下module_init接口的
实现以及调用流程:
在头文件init.h中/include/linux
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \ // 如上level = 6,id = 6
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
__define_initcall 宏将
module_init里面注册的函数名XXX,更改为:__initcall_XXX6 并将其注册到代码段.initcall6.init里面
而其调用在什么位置呢?
调用分两部分,中间从__early_initcall_end隔开。
start_kernel()---》rest_init()---》kernel_init()----》do_basic_setup()----》do_initcalls()
for (call = __early_initcall_end; call < __initcall_end; call++) //后半部分调用
do_one_initcall(*call);
start_kernel()--->rest_init()-->kernel_init(
(init/
main.c
)--->do_pre_smp_initcalls()
for (call = __initcall_start; call < __early_initcall_end; call++) //前半部分调用
do_one_initcall(*call);
那啥时候调用这个代码段呢? 在文件
vmlinux.lds.h中有如下定义:
#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.init) \
*(.initcallrootfs.init) \
*(
.initcall6.init) \
*(.initcall6s.init) \
*(.initcall7.init) \
*(.initcall7s.init)
#define
INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
INITCALLS \
VMLINUX_SYMBOL(__initcall_end) = .;
#define
INIT_DATA_SECTION(initsetup_align) \
.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { \
INIT_DATA \
INIT_SETUP(initsetup_align) \
INIT_CALLS \
CON_INITCALL \
SECURITY_INITCALL \
INIT_RAM_FS \
}
//在文件:./arch/mips/kernel/vmlinux.lds.S:114: INIT_DATA_SECTION(16) 中;
/* will be freed after init */
. = ALIGN(PAGE_SIZE); /* Init code and data */
__init_begin = .;
INIT_TEXT_SECTION(PAGE_SIZE)
INIT_DATA_SECTION(16)
表示INITCALLS宏内含有的相关代码放在__initcall_start和__initcall_end之间 ,并规划了其内存的存放位置对其字节数等信息
初始化数据区的流程和接口:
main(modpost.c)--->read_symbols--->check_sec_ref--->section_rela/section_rel--->check_section_mismatch-->secref_whitelist--->init_data_sections--->ALL_INIT_DATA_SECTIONS--->"
.init.data$等。。。
而其调用在什么位置呢?
调用分两部分,中间从__early_initcall_end隔开。
start_kernel()---》rest_init()---》kernel_init()----》do_basic_setup()----》do_initcalls()
for (call = __early_initcall_end; call < __initcall_end; call++) //后半部分调用
do_one_initcall(*call);
start_kernel()--->rest_init()-->kernel_init(
(init/
main.c
)--->do_pre_smp_initcalls()
for (call = __initcall_start; call < __early_initcall_end; call++) //前半部分调用
do_one_initcall(*call);
在./arch/mips/kernel/vmlinux.lds.S里面
Main()--->linux_main()
--->
start_uml()
--->
start_kernel_proc()
--->
start_kernel()
--->
rest_init()
--->
kernel_init()
--->
do_basic_setup()
--->
do_initcalls()
#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)