linux内核设备文件初始化失败,linux内核中经常用到的设备初始化宏

from:http://zqwt.012.blog.163.com/blog/static/12044684201272731246907/

内核使用了大量不同的宏来标记具有不同作用的函数和数据结构。如宏__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关联匹配

lxxx_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-------------------

初始化代码的特点是:

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

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

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

lprobe()和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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内核的根文件系统初始化是系统启动过程的一个重要步骤,它负责加载根文件系统并挂载为系统的根目录。 在启动过程,BIOS或UEFI首先加载引导加载程序(bootloader),如GRUB或Syslinux等。引导加载程序会加载内核映像(vmlinuz)到内存,并将控制权转交给内核内核启动后,它会执行一系列初始化操作,其包括根文件系统的初始化。根文件系统通常存储在硬盘或闪存设备上,可以是ext4、XFS、Btrfs等文件系统格式。 根文件系统初始化的过程主要包括以下几个步骤: 1. 设备初始化内核初始化硬件设备,如磁盘控制器、网络接口等,以便后续能够访问根文件系统所在的设备。 2. 文件系统驱动加载:内核会加载相应的文件系统驱动模块,以支持对特定文件系统格式的读写操作。 3. 根设备挂载:内核会根据引导参数或配置文件指定的根设备信息(如硬盘分区、NFS共享等),找到根文件系统所在的设备,并将其挂载为系统的根目录(/)。 4. 初始化进程:一旦根文件系统成功挂载,内核会运行用户空间的第一个进程,通常是init或systemd。这个进程负责启动其他用户空间进程和服务。 总而言之,根文件系统初始化Linux系统启动过程的一个关键步骤,它负责加载和挂载根文件系统,并启动用户空间的初始化进程,从而完成系统的初始化工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值