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

  • 相关阅读:
    win10下jdk8和jdk11切换的批处理脚本
    Deeping中使用python连接Oralce报错:Cannot locate a 64-bit Oracle Client library: "./instantclient_21_1/libclntsh.so: file too short"
    Redis作者“不懂”分布式锁【转载】
    搭建nacos高可用集群
    使用spring.config.location与本地配置文件属性不能互补
    protocol buffer应用场景方案想法
    protocol buffer 入门和基本知识
    IDEA快捷键
    软考问题总结
    pandas 使用问题记录
  • 原文地址:https://www.cnblogs.com/welhzh/p/4786711.html
Copyright © 2020-2023  润新知