[zz]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  __devexitdatadevinitdata 类似但与__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_initcal
__initcall_end   |-------------------|
                      |                           |
                      |         ... ... ...       |
                      |                           |
__init_end        -------------------

初始化代码的内存结构

 

初始化代码的特点是:

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

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

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

l  probe()remove()函数应该使用__devinit__devexit标记,且只能标记probe()remov  如果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 */

posted @ 2013-01-04 18:33  zaleilynn  阅读(650)  评论(0编辑  收藏  举报