linux内核中经常用到的设备初始化宏

内核使用了大量不同的宏来标记具有不同作用的函数和数据结构。如宏__init、__devinit等。这些宏在include/linux/init.h头文件中定义。编译器通过这些宏可以把代码优化放到合适的内存位置,以减少内存占用和提高内核效率。

下面是一些常用的宏:

l  __init

标记内核启动时使用的初始化代码,内核启动完成后不再需要。以此标记的代码位于.init.text内存区域。

它的宏定义是这样的:

#define __init __attribute__ ((__section__ (".text.init")))

l  __exit

标记退出代码,如果驱动不是以模块存在的,则该用法无效。

l  __initdata

标记内核启动时使用的初始化数据结构,内核启动完成后不再需要。以此标记的代码位于.init.data内存区

域。

l  __devinit

用于标记:用于初始化设备的函数,例如:用于初始化的函数probe就是用此宏标识的。

l  __devexit

用于标记:设备卸载时被调用的函数。

l  __devexit_p

用于初始化由__devexit标记的函数的指针。

如果内核既支持模块也支持热拔插,则__devexit_p(fn)返回fn,否则返回NULL。

l  __devinitdata

标记初始化设备数据结构的函数。

l  __devexitdata与devinitdata 类似但与__devexit关联匹配

l  xxx_initcall,一系列的初始化代码,按降序优先级排列。

初始化代码的内存结构

_init_begin             ------------------

|  .init.text        | ----   __init

|-------------------|

|  .init.data        | ---- __initdata

_setup_start           |-------------------|

|  .init.setup      | ---- __setup_param

__initcall_start      |-------------------|

|  .initcall1.init  | ---- core_initcall

|-------------------|

|  .initcall2.init  | ---- postcore_initcall

|-------------------|

|  .initcall3.init  | ---- arch_initcall

|-------------------|

|  .initcall4.init  | ---- subsys_initcall

|-------------------|

|  .initcall5.init  | ---- fs_initcall

|-------------------|

|  .initcall6.init  | ---- device_initcall

|-------------------|

|  .initcall7.init  | ---- late_initcall

__initcall_end        |-------------------|

|                     |

|    ... ... ...    |

|                    |

__init_end              -------------------

初始化代码的特点是:

在系统启动运行,且一旦运行后马上退出内存,不再占用内存。

对于驱动程序模块来说,这些优化标记使用的情况如下:

通过module_init()module_exit()函数调用的函数就需要使用__init__exit宏来标记。

probe()remove()函数应该使用__devinit__devexit标记,且只能标记probe()remove()

l  如果remove()使用__devexit标记,则在设备驱动的数据结构中要用__devexit_p(remove)来引用remove()函数。

l  如果你不确定需不需要添加优化宏则不要随便添加。

上面谈到的内核初始化宏位于文件include/linux/init.h中:

#ifndef _LINUX_INIT_H

#define _LINUX_INIT_H

#include <linux/compiler.h>

/* These macros are used to mark some functions or

* initialized data (doesn‘t apply to uninitialized data)

* as `initialization‘ functions. The kernel can take this

* as hint that the function is used only during the initialization

* phase and free up used memory resources after

*

* Usage:

* For functions:

*

* You should add __init immediately before the function name, like:

*

* static void __init initme(int x, int y)

* {

*    extern int z; z = x * y;

* }

*

* If the function has a prototype somewhere, you can also add

* __init between closing brace of the prototype and semicolon:

*

* extern int initialize_foobar_device(int, int, int) __init;

*

* For initialized data:

* You should insert __initdata between the variable name and equal

* sign followed by value, e.g.:

*

* static int init_variable __initdata = 0;

* static const char linux_logo[] __initconst = { 0x32, 0x36, ... };

*

* Don‘t forget to initialize data not at file scope, i.e. within a function,

* as gcc otherwise puts the data into the bss section and not into the init

* section.

*

* Also note, that this data cannot be "const".

*/

/* 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)

/*

* modpost check for section mismatches during the kernel build.

* A section mismatch happens when there are references from a

* code or data section to an init section (both code or data).

* The init sections are (for most archs) discarded by the kernel

* when early init has completed so all such references are potential bugs.

* For exit sections the same issue exists.

*

* The following markers are used for the cases where the reference to

* the *init / *exit section (code or data) is valid and will teach

* modpost not to issue a warning.  Intended semantics is that a code or

* data tagged __ref* can reference code or data from init section without

* producing a warning (of course, no warning does not mean code is

* correct, so optimally document why the __ref is needed and why it‘s OK).

*

* The markers follow same syntax rules as __init / __initdata.

*/

#define __ref            __section(.ref.text) noinline

#define __refdata        __section(.ref.data)

#define __refconst       __section(.ref.rodata)

/* compatibility defines */

#define __init_refok     __ref

#define __initdata_refok __refdata

#define __exit_refok     __ref

#ifdef MODULE

#define __exitused

#else

#define __exitused  __used

#endif

#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)

/* For assembly routines */

#define __HEAD       .section   ".head.text","ax"

#define __INIT       .section   ".init.text","ax"

#define __FINIT      .previous

#define __INITDATA   .section   ".init.data","aw",%progbits

#define __INITRODATA .section   ".init.rodata","a",%progbits

#define __FINITDATA  .previous

#define __DEVINIT        .section   ".devinit.text", "ax"

#define __DEVINITDATA    .section   ".devinit.data", "aw"

#define __DEVINITRODATA  .section  ".devinit.rodata", "a"

#define __CPUINIT        .section   ".cpuinit.text", "ax"

#define __CPUINITDATA    .section   ".cpuinit.data", "aw"

#define __CPUINITRODATA  .section  ".cpuinit.rodata", "a"

#define __MEMINIT        .section   ".meminit.text", "ax"

#define __MEMINITDATA    .section   ".meminit.data", "aw"

#define __MEMINITRODATA  .section  ".meminit.rodata", "a"

/* silence warnings when references are OK */

#define __REF            .section       ".ref.text", "ax"

#define __REFDATA        .section       ".ref.data", "aw"

#define __REFCONST       .section       ".ref.rodata", "a"

#ifndef __ASSEMBLY__

/*

* Used for initialization calls..

*/

typedef int (*initcall_t)(void);

typedef void (*exitcall_t)(void);

extern initcall_t __con_initcall_start[], __con_initcall_end[];

extern initcall_t __security_initcall_start[], __security_initcall_end[];

/* Used for contructor calls. */

typedef void (*ctor_fn_t)(void);

/* Defined in init/main.c */

extern int do_one_initcall(initcall_t fn);

extern char __initdata boot_command_line[];

extern char *saved_command_line;

extern unsigned int reset_devices;

/* used by init/main.c */

void setup_arch(char **);

void prepare_namespace(void);

extern void (*late_time_init)(void);

extern int initcall_debug;

#endif

#ifndef MODULE

#ifndef __ASSEMBLY__

/* 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

struct obs_kernel_param {

const char *str;

int (*setup_func)(char *);

int early;

};

/*

* Only for really core code.  See moduleparam.h for the normal way.

*

* Force the alignment so the compiler doesn‘t space elements of the

* obs_kernel_param "array" too far apart in .init.setup.

*/

#define __setup_param(str, unique_id, fn, early)        \

static const char __setup_str_##unique_id[] __initconst \

__aligned(1) = str; \

static struct obs_kernel_param __setup_##unique_id   \

__used __section(.init.setup)          \

__attribute__((aligned((sizeof(long)))))  \

= { __setup_str_##unique_id, fn, early }

#define __setup(str, fn)               \

__setup_param(str, fn, fn, 0)

/* NOTE: fn is as per module_param, not __setup!  Emits warning if fn

* returns non-zero. */

#define early_param(str, fn)                  \

__setup_param(str, fn, fn, 1)

/* Relies on boot_command_line being set */

void __init parse_early_param(void);

void __init parse_early_options(char *cmdline);

#endif /* __ASSEMBLY__ */

/**

* module_init() - driver initialization entry point

* @x: function to be run at kernel boot time or module insertion

*

* module_init() will either be called during do_initcalls() (if

* builtin) or at module insertion time (if a module).  There can only

* be one per module.

*/

#define module_init(x)   __initcall(x);

/**

* module_exit() - driver exit entry point

* @x: function to be run when driver is removed

*

* module_exit() will wrap the driver clean-up code

* with cleanup_module() when used with rmmod when

* the driver is a module.  If the driver is statically

* compiled into the kernel, module_exit() has no effect.

* There can only be one per module.

*/

#define module_exit(x)   __exitcall(x);

#else /* MODULE */

/* Don‘t use these in modules, but some people do... */

#define early_initcall(fn)      module_init(fn)

#define core_initcall(fn)       module_init(fn)

#define postcore_initcall(fn)      module_init(fn)

#define arch_initcall(fn)       module_init(fn)

#define subsys_initcall(fn)     module_init(fn)

#define fs_initcall(fn)         module_init(fn)

#define device_initcall(fn)     module_init(fn)

#define late_initcall(fn)       module_init(fn)

#define security_initcall(fn)      module_init(fn)

/* Each module must use one module_init(). */

#define module_init(initfn)               \

static inline initcall_t __inittest(void)     \

{ return initfn; }                 \

int init_module(void) __attribute__((alias(#initfn)));

/* This is only required if you want to be unloadable. */

#define module_exit(exitfn)               \

static inline exitcall_t __exittest(void)     \

{ return exitfn; }                 \

void cleanup_module(void) __attribute__((alias(#exitfn)));

#define __setup_param(str, unique_id, fn) /* nothing */

#define __setup(str, func)         /* nothing */

#endif

/* Data marked not to be saved by software suspend */

#define __nosavedata __section(.data..nosave)

/* This means "can be init if no module support, otherwise module load

may call it." */

#ifdef CONFIG_MODULES

#define __init_or_module

#define __initdata_or_module

#define __initconst_or_module

#define __INIT_OR_MODULE .text

#define __INITDATA_OR_MODULE    .data

#define __INITRODATA_OR_MODULE  .section ".rodata","a",%progbits

#else

#define __init_or_module __init

#define __initdata_or_module __initdata

#define __initconst_or_module __initconst

#define __INIT_OR_MODULE __INIT

#define __INITDATA_OR_MODULE __INITDATA

#define __INITRODATA_OR_MODULE __INITRODATA

#endif /*CONFIG_MODULES*/

/* Functions marked as __devexit may be discarded at kernel link time, depending

on config options.  Newer versions of binutils detect references from

retained sections to discarded sections and flag an error.  Pointers to

__devexit functions must use __devexit_p(function_name), the wrapper will

insert either the function_name or NULL, depending on the config options.

*/

#if defined(MODULE) || defined(CONFIG_HOTPLUG)

#define __devexit_p(x) x

#else

#define __devexit_p(x) NULL

#endif

#ifdef MODULE

#define __exit_p(x) x

#else

#define __exit_p(x) NULL

#endif

#endif /* _LINUX_INIT_H */

时间: 2024-10-28 01:46:45

linux内核中经常用到的设备初始化宏的相关文章

Linux内核中双向链表的经典实现

Linux内核中双向链表的经典实现 概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核中非常常用的两个经典宏定义offsetof和container_of.内容包括:1. Linux中的两个经典宏定义2. Linux中双向链表的经典实现 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3562146.html 更多

Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构struct timeval{time_t tv_sec; /***second***/susecond_t tv_usec;/***microsecond***/}到底microsecond是毫秒还是微秒?? 1秒=1000毫秒(3个零),1秒=1000 000微秒(6个零),1秒=1000 000 000纳秒(9个零),1秒=1000 000 000

Linux内核中的中断栈与内核栈的补充说明【转】

转自:http://blog.chinaunix.net/uid-12461657-id-3487463.html 原文地址:Linux内核中的中断栈与内核栈的补充说明 作者:MagicBoy2010 中断栈与内核栈的话题更多地属于内核的范畴,所以在<深入Linux设备驱动程序内核机制>第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题. 本贴在这个基础上对内核栈与中断栈的话题做些补充,讨论基于x86 32位系统,因为64位系

向linux内核中添加外部中断驱动模块

本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内核中添加外部中断驱动模块.7.完整驱动程序代码.linux的内核版本为linux2.6.32.2. 一.linux模块的框架以及混杂设备相关知识 1.内核模块的框架如下图所示,其中module_init()(图中有误,不是modules_init)只有在使用insmod命令手动加载模块时才会被调用,

Linux内核中的软中断、tasklet和工作队列详解

[TOC] 本文基于Linux2.6.32内核版本. 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的"下半部"(bottom half)演变而来.下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任务队列的函数都消失了,只剩下了前三者. 介绍这三种下半部实现之前,有必要说一下上半部与下半部的区别. 上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务.举个例子:在网络传输中,网卡接收到数据包这

Linux内核中namespace之PID namespace

前面看了LInux PCI设备初始化,看得有点晕,就转手整理下之前写的笔记,同时休息一下!!~(@^_^@)~ 这片文章是之前写的,其中参考了某些大牛们的博客!! PID框架的设计 一个框架的设计会考虑很多因素,相信分析过Linux内核的读者来说会发现,内核的大量数据结构被哈希表和链表链接起来,最最主要的目的就是在于查找.可想而知一个好的框架,应该要考虑到检索速度,还有考虑功能的划分.那么在PID框架中,需要考虑以下几个因素. 如何通过task_struct快速找到对应的pid 如何通过pid快

(笔记)Linux内核中内存相关的操作函数

linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) 内核空间申请指定大小的内存区域,返回内核空间虚拟地址.在函数实现中,如果申请的内存空间较大的话,会从buddy系统申请若干内存页面,如果申请的内存空间大小较小的话,会从slab系统中申请内存空间.有关buddy和slab,请参见<linux内核之内存管理.doc> gfp_t flags 的选项

大话Linux内核中锁机制之原子操作、自旋锁

转至:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 很多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态.这其中包括了我们所熟知的SMP系统,多核间的相互竞争资源,单CPU之间的相互竞争,中断和进程间的相互抢占等诸多问题. 通常情况下,如图1所示,对于一段程序,我们的理想是总是美好的,希望它能够这样执行:进程1先对临界区完成操作,

Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质

原文:Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质 Linux内核分析(六) 昨天我们对字符设备进行了初步的了解,并且实现了简单的字符设备驱动,今天我们继续对字符设备的某些方法进行完善. 今天我们会分析到以下内容: 1.      字符设备控制方法实现 2.      揭秘系统调用本质 在昨天我们实现的字符设备中有open.read.write等方法,由于这些方法我们在以前编写应用程序的时候,相信大家已经有所涉及所以就没单独列出来分析,今天我们主要来分析一下我们以前接触