Linux内核初始化定义
转载:http://blog.csdn.net/beatbean/article/details/8448623
1. Compile宏控制
位于include/linux/init.h
- /* These are for everybody (although not all archs will actually
- discard it in modules) */
- #define __init __section(.init.text) __cold notrace
- #define __initdata __section(.init.data)
- #define __initconst __section(.init.rodata)
- #define __exitdata __section(.exit.data)
- #define __exit_call __used __section(.exitcall.exit)
·首先需要简要说明一下GCC的驱动程序:

#define __init __section(.init.text) __cold notrace
__init用于标记函数,放在.init.text section,标记为初始化的函数,表明该函数供在初始化期间使用。在模块装载之后,模块装载就会将初始化函数扔掉。这样可以将该函数占用的内存释放出来。__initdata用于标记数据
#define __cold __attribute__((__cold__))
__cold告诉编译器这个函数很可能不被执行到
#define notrace __attribute__((no_instrument_function))
notrace如同GCC的-finstrument-functions() 参数的作用是在程序中加入hook,让它在每次进入和退出函数的时候分别调用这个函数
#define __used __attribute__((__used__)) 意味着code必须发动附有该宏的函数
__exit修饰词标记函数,只在模块卸载时使用。如果模块被直接编进内核则该函数就不会被调用。如果内核编译时没有包含该模块,则此标记的函数将被简单地丢弃。
- #define __ref __section(.ref.text) noinline
- #define __refdata __section(.ref.data)
- #define __refconst __section(.ref.rodata)
#define noinline __attribute__((noinline)) 阻止该函数被内联
- #define __exit __section(.exit.text) __exitused __cold notrace
- /* Used for HOTPLUG */
- #define __devinit __section(.devinit.text) __cold notrace
- #define __devinitdata __section(.devinit.data)
- #define __devinitconst __section(.devinit.rodata)
- #define __devexit __section(.devexit.text) __exitused __cold notrace
- #define __devexitdata __section(.devexit.data)
- #define __devexitconst __section(.devexit.rodata)
- /* Used for HOTPLUG_CPU */
- #define __cpuinit __section(.cpuinit.text) __cold notrace
- #define __cpuinitdata __section(.cpuinit.data)
- #define __cpuinitconst __section(.cpuinit.rodata)
- #define __cpuexit __section(.cpuexit.text) __exitused __cold notrace
- #define __cpuexitdata __section(.cpuexit.data)
- #define __cpuexitconst __section(.cpuexit.rodata)
- /* Used for MEMORY_HOTPLUG */
- #define __meminit __section(.meminit.text) __cold notrace
- #define __meminitdata __section(.meminit.data)
- #define __meminitconst __section(.meminit.rodata)
- #define __memexit __section(.memexit.text) __exitused __cold notrace
- #define __memexitdata __section(.memexit.data)
- #define __memexitconst __section(.memexit.rodata)
2. 初始化宏
- /* 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.
- */
- #define __define_initcall(level,fn,id) \
- static initcall_t __initcall_##fn##id __used \
- __attribute__((__section__(".initcall" level ".init"))) = fn
- /*
- * Early initcalls run before initializing SMP.
- *
- * Only for built-in code, not modules.
- */
- #define early_initcall(fn) __define_initcall("early",fn,early)
- /*
- * 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.
- */
- #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)
- #define __initcall(fn) device_initcall(fn)
- #define __exitcall(fn) \
- static exitcall_t __exitcall_##fn __exit_call = fn
- #define console_initcall(fn) \
- static initcall_t __initcall_##fn \
- __used __section(.con_initcall.init) = fn
- #define security_initcall(fn) \
- static initcall_t __initcall_##fn \
- __used __section(.security_initcall.init) = fn
首先,
__define_initcall声明一个__initcall_##fn##id的initcall_t类型静态函数指针,并设置好属性,定义如下:
typedef int (*initcall_t)(void);
typedef void (*exitcall_t)(void);
然后,初始化为fn,编译的时候就会放在__section__(".initcall" level ".init")里面
3. .initcall.init section
在include/asm-generic/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 CON_INITCALL \
- VMLINUX_SYMBOL(__con_initcall_start) = .; \
- *(.con_initcall.init) \
- VMLINUX_SYMBOL(__con_initcall_end) = .;
- #define SECURITY_INITCALL \
- VMLINUX_SYMBOL(__security_initcall_start) = .; \
- *(.security_initcall.init) \
- VMLINUX_SYMBOL(__security_initcall_end) = .;
在arm中section定义如下(arch/arm/kernel/vmlinux.lds.s):
TCM是紧密耦合存储器,速度比 SDRAM 快很多,使得处理器能直接访问独立的指令和数据TCM(ITCM和DTCM)。TCM被用于存储实时性和性能要求极高的代码,它还提供一个DMA支持机制。不像AHP访问外部存储器,访问TCM是快速的,确定的,不造成总线负荷。
- .init : { /* Init code and data */
- _stext = .;
- _sinittext = .;
- HEAD_TEXT
- INIT_TEXT
- ARM_EXIT_KEEP(EXIT_TEXT)
- _einittext = .;
- ARM_CPU_DISCARD(PROC_INFO)
- __arch_info_begin = .;
- *(.arch.info.init)
- __arch_info_end = .;
- __tagtable_begin = .;
- *(.taglist.init)
- __tagtable_end = .;
- #ifdef CONFIG_SMP_ON_UP
- __smpalt_begin = .;
- *(.alt.smp.init)
- __smpalt_end = .;
- #endif
- __pv_table_begin = .;
- *(.pv_table)
- __pv_table_end = .;
- INIT_SETUP(16)
- <span style="color:#ff0000;">INIT_CALLS
- </span> CON_INITCALL
- SECURITY_INITCALL
- INIT_RAM_FS
- #ifndef CONFIG_XIP_KERNEL
- __init_begin = _stext;
- INIT_DATA
- ARM_EXIT_KEEP(EXIT_DATA)
- #endif
- }
#define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
INITCALLS \
VMLINUX_SYMBOL(__initcall_end) = .;
4. 初始化.initcallxx.init函数
位于init/main.c
- extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
- static void __init do_pre_smp_initcalls(void)
- {
- initcall_t *fn;
- for (fn = <span style="color:#ff0000;">__initcall_start</span>; fn < <span style="color:#ff0000;">__early_initcall_end</span>; fn++)
- do_one_initcall(*fn);
- }
- static void __init do_initcalls(void)
- {
- initcall_t *fn;
- for (fn = <span style="color:#ff0000;">__early_initcall_end</span>; fn < <span style="color:#ff0000;">__initcall_end</span>; fn++)
- do_one_initcall(*fn);
- }
- int __init_or_module do_one_initcall(initcall_t fn)
- {
- int count = preempt_count();
- int ret;
- if (initcall_debug)
- ret = do_one_initcall_debug(fn);
- else
- <span style="color:#ff0000;">ret = fn();
- </span>
- msgbuf[0] = 0;
- if (ret && ret != -ENODEV && initcall_debug)
- sprintf(msgbuf, "error code %d ", ret);
- if (preempt_count() != count) {
- strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
- preempt_count() = count;
- }
- if (irqs_disabled()) {
- strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
- local_irq_enable();
- }
- if (msgbuf[0]) {
- printk("initcall %pF returned with %s\n", fn, msgbuf);
- }
- return ret;
- }
Linux内核初始化定义的更多相关文章
- Linux内核中链表实现
关于双链表实现,一般教科书上定义一个双向链表节点的方法如下: struct list_node{ stuct list_node *pre; stuct list_node *next; ElemTy ...
- [翻译] Linux 内核中的位数组和位操作
目录 Linux 内核里的数据结构 原文链接与说明 Linux 内核中的位数组和位操作 位数组声明 体系结构特定的位操作 通用位操作 链接 Linux 内核里的数据结构 原文链接与说明 https:/ ...
- Linux 内核里的数据结构:位图(bitmap)
注: 本文由 LCTT 原创翻译,Linux中国 荣誉推出 Linux 内核中的位数组和位操作 除了不同的基于链式和树的数据结构以外,Linux 内核也为位数组(或称为位图(bitmap))提供了 A ...
- linux内核分析第三周
20135103王海宁 linux内核分析第三周 http://mooc.study.163.com/course/USTC-1000029000 按照课堂提供的方法,命令行一行行敲上去,我是手机缓 ...
- Linux内核的启动过程分析
秦鼎涛 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验目的及要求: 使用gdb跟踪调试内核从s ...
- linux内核分析(网课期末&地面课期中)
堆栈变化过程: Linux内核分析——计算机是如何工作的 计算机是如何工作的?(总结)——三个法宝 存储程序计算机工作模型,计算机系统最最基础性的逻辑结构: 函数调用堆栈,高级语言得以运行的基础,只有 ...
- Linux内核中断处理体系分析
前一篇博文中:linux内核初始化阶段通过early_trap_init()函数完毕了把异常向量复制到0xFFFF0000開始的地方,这些异常向量大部分指向通过vector_stub宏定义的那段代码. ...
- Linux内核设计第三周学习总结 跟踪分析Linux内核的启动过程
陈巧然 原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验步骤 登陆实验楼虚 ...
- Linux内核分析(三)内核启动过程分析——构造一个简单的Linux系统
一.系统的启动(各历史节点) 在最开始的时候,计算机的启动实际上依靠一段二进制码,可以这么理解,他并不是一个真正的计算机启动一道程序.计算机在开始加电的时候几乎是没有任何用处的,因为RAM芯片中包括的 ...
随机推荐
- 只有IE能上网,其他浏览器均不可以!
今天起来,高高兴兴的来到实验室,发现电脑打开上不了网.本人平时喜欢用Chrome,发现上不了网,就开始ping.发现可以ping通,但是网页打不开! 第一反应是DNS的问题,可以发现DNS没问题,能正 ...
- 给sublime text添加ubuntu launcher快捷方式
1.下载sublime text 2文件,解压并复制到/opt目录,文件夹名称不要含有空格 2.在/usr/share/applications目录下新建sublime_text.desktop文件 ...
- 【hadoop代码笔记】Mapreduce shuffle过程之Map输出过程
一.概要描述 shuffle是MapReduce的一个核心过程,因此没有在前面的MapReduce作业提交的过程中描述,而是单独拿出来比较详细的描述. 根据官方的流程图示如下: 本篇文章中只是想尝试从 ...
- HDU5806:NanoApe Loves Sequence Ⅱ(尺取法)
题目链接:HDU5806 题意:找出有多少个区间中第k大数不小于m. 分析:用尺取法可以搞定,CF以前有一道类似的题目. #include<cstdio> using namespace ...
- TopCoder SRM 605 DIV1
604的题解还没有写出来呢.先上605的. 代码去practice房间找. 说思路. A: 贪心,对于每个类型的正值求和,如果没有正值就取最大值,按着求出的值排序,枚举选多少个类型. B: 很明显是d ...
- 使用CocoaPods管理依赖库
本篇内容将介绍Mac和iOS开发中必备的一个依赖库管理工具CocoaPods. CocoaPods是什么 在iOS开发中势必会用到一些第三方依赖库,比如大家都熟悉的ASIHttpRequest.AFN ...
- HDU 5805 NanoApe Loves Sequence (模拟)
NanoApe Loves Sequence 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5805 Description NanoApe, the ...
- Spring Named Parameters examples in SimpleJdbcTemplate
In JdbcTemplate, SQL parameters are represented by a special placeholder "?" symbol and bi ...
- ucGUI例程收藏
ucGUI 几个重要例程Demo 按钮的定制 #include <stddef.h> #include <string.h> #include "WM.h&quo ...
- POJ 3169 Layout (spfa+差分约束)
题目链接:http://poj.org/problem?id=3169 差分约束的解释:http://www.cnblogs.com/void/archive/2011/08/26/2153928.h ...