一、Driver初始化
每个驱动程序都有自己的init函数,但是这些init函数是如何初始化的?
两种假设:
1、放到一个总的init函数,我们把init函数填入这个函数?
2、放到一个专用的init文件,我们把init函数填入这个头文件?
Linux处理方式:
—在编译的镜像文件中定义一个INIT_CALL段(section),存放init函数的指针
—用module_init等宏定义将init函数填入对应INIT_CALL段中;
—用不同的init level实现初始化先后顺序的分级;
1、INIT_CALL段的定义
源码位置:
Kernel/include/asm-generic/vmlinux.lds.h
1.1、添加INIT_CALLS到initdata段
#define INIT_DATA_SECTION(initsetup_align) \
.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
\
INIT_DATA \
INIT_SETUP(initsetup_align) \
INIT_CALLS \
CON_INITCALL \
INIT_RAM_FS \
}
1.2、定义INIT_CALLS
#define INIT_CALLS \
__initcall_start = .; \
KEEP(*(.initcallearly.init)) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
__initcall_end = .;
1.3、定义INIT_CALLS_LEVEL
#define INIT_CALLS_LEVEL(level) \
__initcall##level##_start = .; \
KEEP(*(.initcall##level##.init)) \
KEEP(*(.initcall##level##s.init)) \
举例展开后level=6
#define INIT_CALLS_LEVEL(6) \
__initcall6_start = .; \
KEEP(*(.initcall6.init)) \
KEEP(*(.initcall6s.init))
#define INIT_CALLS \
__initcall_start = .; \
KEEP(*(.initcallearly.init)) \
__initcall0_start \
KEEP(*(.initcall0.init)) \
KEEP(*(.initcall0s.init)) \
__initcall1_start \
KEEP(*(.initcall1.init)) \
KEEP(*(.initcall1s.init)) \
__initcall2_start \
KEEP(*(.initcall2.init)) \
KEEP(*(.initcall2s.init)) \
__initcall3_start \
KEEP(*(.initcall3.init)) \
KEEP(*(.initcall3s.init)) \
__initcall4_start \
KEEP(*(.initcall4.init)) \
KEEP(*(.initcall4s.init)) \
__initcall5_start \
KEEP(*(.initcall5.init)) \
KEEP(*(.initcall5s.init)) \
__initcall6_start \
KEEP(*(.initcall6.init)) \
KEEP(*(.initcall6s.init)) \
__initcall7_start \
KEEP(*(.initcall7.init)) \
KEEP(*(.initcall7s.init)) \
__initcall_end = .;
2、init宏的展开
2.1、源码解析
源码位置:
#include <linux/module.h>
#ifndef MODULE
/**
* 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);
/**
* module_exit() - driver exit entry point
* @x: function to be run when driver is removed
*
* module_exit() will wrap the driver clean-up code
* with cleanup_module() when used with rmmod when
* the driver is a module. If the driver is statically
* compiled into the kernel, module_exit() has no effect.
* There can only be one per module.
*/
#define module_exit(x) __exitcall(x);
#else /* MODULE */
/*
* In most cases loadable modules do not need custom
* initcall levels. There are still some valid cases where
* a driver may be needed early if built in, and does not
* matter when built as a loadable module. Like bus
* snooping debug drivers.
*/
#define early_initcall(fn) module_init(fn)
#define core_initcall(fn) module_init(fn)
#define core_initcall_sync(fn) module_init(fn)
#define postcore_initcall(fn) module_init(fn)
#define postcore_initcall_sync(fn) module_init(fn)
#define arch_initcall(fn) module_init(fn)
#defi