问题背景
在学习【奔跑吧Linux内核——基于Linux 4.x内核源代码问题分析】中断管理机制章节中如下部分:
系统初始化时,customize_machine()函数会去枚举并初始化“arm,amba-bus”和
“simple-bus”总线上的设备,最终解析 DTS 中的相关信息,把相关信息添加到 struct device
数据结构中,向 Linux 内核注册一个新的外设。我们只关注中断相关信息的枚举过程:
[customize_machine()->of_platform_populate()->of_platform_bus_create()->of
_amba_device_create()]
查看customize_machine接口,看到arch_initcall,产生好奇,不知道其具体是做什么,及customize_machine在哪里被调到(在代码中直接找,没找到调用点)
machine_desc->init_machine和machine_desc是全局变量?待研究,TODO
[arch/arm/kernel/setup.c]
static int __init customize_machine(void)
{
/*
* customizes platform devices, or adds new ones
* On DT based machines, we fall back to populating the
* machine from the device tree, if no callback is provided,
* otherwise we would always need an init_machine callback.
*/
if (machine_desc->init_machine)
machine_desc->init_machine();
return 0;
}
arch_initcall(customize_machine);
arch_initcall宏定义
代码中找到两处定义,为啥两处都有定义,看代码后应该是init.h
module.h里内容待后边研究,TODO
[include/linux/init.h]
/*
* 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.
* Keep main.c:initcall_level_names[] in sync.
*/
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
[include/linux/module.h]
/*
* 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)
#define subsys_initcall(fn) module_init(fn)
#define subsys_initcall_sync(fn) module_init(fn)
#define fs_initcall(fn) module_init(fn)
#define fs_initcall_sync(fn) module_init(fn)
#define rootfs_initcall(fn) module_init(fn)
#define device_initcall(fn) module_init(fn)
#define device_initcall_sync(fn) module_init(fn)
#define late_initcall(fn) module_init(fn)
#define late_initcall_sync(fn) module_init(fn)
#define console_initcall(fn) module_init(fn)
/* Each module must use one module_init(). */
#define module_init(initfn) \
static inline initcall_t __maybe_unused __inittest(void) \
{ return initfn; } \
int init_module(void) __copy(initfn) \
__attribute__((alias(#initfn))); \
__CFI_ADDRESSABLE(init_module, __initdata);
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
static inline exitcall_t __maybe_unused __exittest(void) \
{ return exitfn; } \
void cleanup_module(void) __copy(exitfn) \
__attribute__((alias(#exitfn))); \
__CFI_ADDRESSABLE(cleanup_module, __exitdata);
module.h里内容按下不表
先看init.h中的定义:
#define arch_initcall(fn) __define_initcall(fn, 3)
#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
___define_initcall宏第三个参数.initcall##id:
查看该宏定义处,可知为__sec,即为代码段名称,最终展开为字符串.initcall3
#define ___define_initcall(fn, id, __sec) \
__unique_initcall(fn, id, __sec, __initcall_id(fn))
#define __unique_initcall(fn, id, __sec, __iid) \
____define_initcall(fn, \
__initcall_stub(fn, __iid, id), \
__initcall_name(initcall, __iid, id), \
__initcall_section(__sec, __iid))
__initcall_id(fn)宏
/*
* 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.
*
* Initcalls are run by placing pointers in initcall sections that the
* kernel iterates at runtime. The linker can do dead code / data elimination
* and remove that completely, so the initcall sections have to be marked
* as KEEP() in the linker script.
*/
/* Format: <modname>__<counter>_<line>_<fn> */
#define __initcall_id(fn) \
__PASTE(__KBUILD_MODNAME, \
__PASTE(__, \
__PASTE(__COUNTER__, \
__PASTE(_, \
__PASTE(__LINE__, \
__PASTE(_, fn) \
) \
) \
) \
) \
) \
__initcall_id(fn)宏按层剥开:
再结合__PASTE宏(字符拼接)
/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)
__initcall_id(fn)宏小结:
__initcall_id(fn)宏展开是下边个鬼玩意:
当然上述宏展开后字符串中的三个宏,
编译器最终都会替换成对应的字符串
自己理解,整这么一长串,是为了防止重名
__unique_initcall(fn, id, __sec, __iid)宏
#define __unique_initcall(fn, id, __sec, __iid) \
____define_initcall(fn, \
__initcall_stub(fn, __iid, id), \
__initcall_name(initcall, __iid, id), \
__initcall_section(__sec, __iid) \
) \
tip:宏参数__iid就是上一小节探究的__initcall_id(fn)宏
__initcall_name(prefix, __iid, id)宏
/* Format: __<prefix>__<iid><id> */
#define __initcall_name(prefix, __iid, id) \
__PASTE(__, \
__PASTE(prefix, \
__PASTE(__, \
__PASTE(__iid, id))))
结合该宏上层调用处,prefix(前缀)是:initcall字符
展开后:
prefix,,__iid,id
替换后
(真实字符串是需要去掉,的,此处为方便阅读保留)
initcall,,__KBUILD_MODNAME____COUNTER_____LINE___fn,id
替换id后:
这是完整的初始化函数名称
__initcall_section(__sec, __iid)宏
#ifdef CONFIG_LTO_CLANG
#define __initcall_section(__sec, __iid) \
#__sec ".init.." #__iid
#define __initcall_stub(fn, __iid, id) \
__initcall_name(initstub, __iid, id)
#else
#define __initcall_section(__sec, __iid) \
#__sec ".init"
#define __initcall_stub(fn, __iid, id) fn
#endif
由上文可知参数:
__sec是.initcall3,
__iid是__KBUILD_MODNAME____COUNTER_____LINE___fn,
展开后
.initcall3.init…__KBUILD_MODNAME____COUNTER_____LINE___fn,
或.initcall3.init
这是完整的代码段名称
__initcall_stub(fn, __iid, id)宏
#define __initcall_stub(fn, __iid, id) \
__initcall_name(initstub, __iid, id)
__initstub____KBUILD_MODNAME____COUNTER_____LINE___fn3
这是完整的初始化打桩函数名称
____define_initcall(fn, __unused, __name, __sec)宏
#define ____define_initcall(fn, __unused, __name, __sec) \
static initcall_t __name __used \
__attribute__((__section__(__sec))) = fn;
把上边宏展开后:
其中__name是:
__initcall____KBUILD_MODNAME____COUNTER_____LINE___fn3
static initcall_t __name __used \
__attribute__((__section__(.initcall3.init))) = fn;
arch_initcall(fn)宏总结
arch_initcall(fn)-->fn: customize_machine
__define_initcall(fn, id)-->id: 3
___define_initcall(fn, id, __sec)-->__sec: .initcall3
__unique_initcall(fn, id, __sec, __iid)-->__iid: __initcall_id(fn)
____define_initcall(fn, __unused, __name, __sec)
调用处:
#define __unique_initcall(fn, id, __sec, __iid) \
____define_initcall(fn, \
__initcall_stub(fn, __iid, id), \
__initcall_name(initcall, __iid, id), \
__initcall_section(__sec, __iid) \
)
定义处:
#define ____define_initcall(fn, __unused, __name, __sec) \
static initcall_t __name __used \
__attribute__((__section__(__sec))) = fn;
__iid: __initcall_id(fn)
(__KBUILD_MODNAME)__(__COUNTER__)_(__LINE__)_fn
__unused: __initcall_stub(fn, __iid, id)
空(与编译宏CONFIG_LTO_CLANG是否定义有关)
__name: __initcall_name(initcall, __iid, id)
__initcall__((__KBUILD_MODNAME)__(__COUNTER__)_(__LINE__)_fn)id
__sec:__initcall_section(__sec, __iid)
.initcall3.init
__KBUILD_MODNAME:当前模块名字
__COUNTER__:出现次数?
__LINE__:行号
static initcall_t __name __used \
__attribute__((__section__(.initcall3.init))) = fn;
下边需要查看链接文件,看该代码段在哪里被调用,TODO
待填坑。。。
用arch_initcall宏处理后的函数调用处
参考wiki:
各种initcall的执行先后顺序(module_init、postcore_initcall、arch_initcall、subsys_initcall、 fs_initcall)