【深入Linux内核驱动】CLK_OF_DECLARE使用及其内在机制

【深入Linux内核驱动】CLK_OF_DECLARE使用及其内在机制

在clk驱动中有出现这样的一句宏定义调用

CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init)

通过查找kernel路径下,发现没有其他地方去调用这个s3c2410_clk,s3c2410_clk_init.很疑惑不知道这个接口是怎么被调用的.

CLK_OF_DECLARE通过百度查找,发现这个宏经常会在系统时钟初始化的时候进行使用:

Declare the compatible clocks and associate it with an initialization function using CLK_OF_DECLARE

使用CLK_OF_DECLARE声明兼容时钟并将其与初始化函数关联

CLK_OF_DECLARE 定义

#ifdef CONFIG_OF
#define _OF_DECLARE(table, name, compat, fn, fn_type)           \static const struct of_device_id __of_table_##name      \__used __section(__##table##_of_table)          \= { .compatible = compat,              \ .data = (fn == (fn_type)NULL) ? fn : fn  }
#else 
#define _OF_DECLARE(table, name, compat, fn, fn_type)           \static const struct of_device_id __of_table_##name      \__attribute__((unused))                 \= { .compatible = compat,              \.data = (fn == (fn_type)NULL) ? fn : fn }
#endif#define OF_DECLARE_1(table, name, compat, fn) \_OF_DECLARE(table, name, compat, fn, of_init_fn_1)
#define OF_DECLARE_2(table, name, compat, fn) \_OF_DECLARE(table, name, compat, fn, of_init_fn_2)#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)

通过_OF_DECLARE宏的实现发现其实CLK_OF_DECLARE是声明定义的时钟信息.转化之后:

static const struct of_device_id __of_table_s3c2410_clk __used __section(__clk_of_table) {...}

由上可知是声明了一个struct of_device_id类型的变量__of_table_s3c2410_clk.但是后面的__section(__clk_of_table)如何解释?

通过查询了解到:

section关键字可以将变量定义到指定的输入段中。例如

int a __attribute__((section(“list”))) = 0;

这句话的意思是将一个int型的变量a放到名为list的输入段中。

那么static const struct of_device_id __of_table_s3c2410_clk __used __section(__clk_of_table) {...}即可理解为将一个struct of_device_id类型的变量__of_table_s3c2410_clk放入到名为__clk_of_table的输入段中.

那为什么要这样操作,定义一个变量,最终再通过section放入到指定的段中呢?

传统的应用编写时,每添加一个模块,都需要在main中添加新模块的初始化

1

使用__attribute__((section()))构建初始化函数表后,由模块告知main:“我要初始化“,添加新模块再也不需要在main代码中显式调用模块初始化接口。

2

以此实现main与模块之间的隔离,main不再关心有什么模块,模块的删减也不需要修改main。

内核其实就是使用__attribute__((section()))从而实现的初始化函数表

1. module_init的定义

module_init定义在。代码如下:

图片

代码中使用的“_section_”,是一层层的宏,为了简化,把其等效理解为“section”

分析上述代码,我们发现module_init__attribute__((section(“name”)))实现,把初始化函数地址保存到名为".initcall6.init" 的数据段中。

2. 链接内核使用自定义的链接脚本

我们看到内核目录最上层的Makefile,存在如下代码:

# Rule to link vmlinux - also used during CONFIG_KALLSYMS
# May be overridden by arch/$(ARCH)/Makefile
quiet_cmd_vmlinux__ ?= LD      $@  
cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \-T $(vmlinux-lds) $(vmlinux-init)                          \--start-group $(vmlinux-main) --end-group                  \$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)

本文的关注点在于:-T $(vmlinux-lds),通过“ld -T

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部