转载: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;
- }