内嵌驱动入口简单解释

修改内核lcd驱动为at040tn94
修改文件可以参考以下链接:
http://maker.zlgmcu.com/forum.php?mod=viewthread&tid=183303

先来阅读一下drivers/video/mxs/lcd_43wvf1g.c 文件
发现最尾部一句为:
subsys_initcall(register_devices);

该句是一个宏,展开后为:
static initcall_t __initcall_register_devices4 __attribute__((__used__))  __attribute__((__section__(".initcall" "4" ".init"))) = register_devices;

分析一下: initcall_t 是一个类型说明符
typedef int (*initcall_t)(void);
__initcall_register_devices4 是一个initcall_t 类型变量,
它被编译器放到".initcall4.init" section 中,
__initcall_register_devices4 赋值为register_devices

我们通过观察lcd_43wvf1g.o证实了这一点。
通过观察它的编译过程。我们发现lcd_43wvf1g.o 被链接入driver/video/mxs/build-in.o
而该build-in.o 又被链接如driver/video/build-in.o
该build-in.o 又被链接如driver/build-in.o
该build-in.o 又被链接入vmlinux.o
同时,该build-in.o 也被链接为vmlinux.

观察vmlinux.o 我们看到了.initcall4.init 节,现在它已经从原来的一个DWORD(4byte), 扩大到现在的0xa0 字节。符号表中也看到了__initcall_register_devices4
同时也看到了.initcall5.init, .initcall6.init 等节
但最终的映像文件vmlinux 却没有这些节, 那么,vmlinux 又是怎样调用的这些指针入口呢?

比较二者生成的差异,发现后者多了一个
-T arch/arm/kernel/vmlinux.lds
-T 选项指示后面是一个链接脚本,链接脚本浮出水面!
link script 是一种简单的脚本语言,
是为了把输入obj文件链接成输出elf文件
语言构成必然有一些关键字,用来完成特定的功能。 不过好在很好理解了。
SECTIONS 说明
. 是LMA(location memory addr), 加载地址,  付初值0xC0008000
定义.init 段,
在该段中定义_stext 变量
定义 _sinitext 变量
以下由所有的.head.txt, 所有的.init.txt, 所有的.cpuinit.txt, 所有的.meminit.txt构成
定义_einitext 变量
下面继续定义变量, 链接内容
从__initcall_start 开始,链接了所有.initcallearly.init, 定义__early_initcall_end
下面链接所有.initcall0.init, ... 链接所有的.initcall4.init (我们关注的subsys_call) ... rootrs 在.initcall5s 和.initcall6之间,最后是所有的.initcall7s.init
继续链接data, 并设置ALIGN
这样我们知道, .initcall4.init 已被并入.init 段

/DISCARD/ 段, 表示忽略所列的段,它们不会进入输出端
定义 .text 段, ...
定义 .rodata 段
定义 .data 段
定义 .sbss 段
定义 .stab 0 段  // 后面地址是VMA, debug 信息
定义 .comment 0段 // 后面地址是VMA, debug 信息
其中用到 AT 指令是LMA (load memory address)
VMA: virtual memroy address,  虚拟内存地址, 程序运行地址。
VMA 通常就等于 LMA, 但也有例外,如果两者不等,运行时需要把LMA 内容copy 到VMA处运行
ASSERT是命令,如果第一个参数为0,则打印第二个参数的信息

link script中定义的变量, 在c语言中通过extern 声明后可以引用。

一些变量在link script 中定义, 都是地址
extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
static void __init do_initcalls(void)
{
    initcall_t *fn;

    for (fn = __early_initcall_end; fn < __initcall_end; fn++)
        do_one_initcall(*fn);                  // 该函数对每一个取值执行初始化调用操作。

    /* Make sure there is no pending stuff from the initcall sequence */
    flush_scheduled_work();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值