Linux如何确定模块初始化调用的顺序?

Sha*_*off 25 embedded linux-kernel ubifs

我有一个带有SPI闪存的设备我想在该闪存设备上使用UBIFS文件系统作为我的rootfs.我面临的问题是UBI模块在SPI模块初始化之前初始化.因此,当UBI加载时,它无法连接到我告诉它的UBI设备(通过内核命令行),因此没有rootfs.下面的控制台输出说明了这一点

我一直潜入源代码,看到它init/main.c有一个do_initcalls()简单地调用函数指针列表的函数.这些函数指针指向module_init()内置于内核的模块的所有功能.这些函数指针放在内核二进制文件的特殊部分中,因此在编译时选择此顺序.但是,我还没弄清楚该命令是如何确定的.

    [    0.482500] UBI error: ubi_init: UBI error: cannot initialize UBI, error -19
    [    0.492500] atmel_spi atmel_spi.0: Using dma0chan0 (tx) and  dma0chan1 (rx) for DMA transfers
    [    0.500000] atmel_spi atmel_spi.0: Atmel SPI Controller at 0xf0000000 (irq 13)
    [    0.507500] m25p80 spi0.1: mx25l25635e (32768 Kbytes)
    [    0.512500] Creating 7 MTD partitions on "jedec_flash":
    [    0.520000] 0x000000000000-0x000000020000 : "loader"
    [    0.527500] 0x000000020000-0x000000060000 : "u-boot"
    [    0.537500] 0x000000060000-0x000000080000 : "u-boot-env"
    [    0.547500] 0x000000080000-0x000000280000 : "kernel0"
    [    0.557500] 0x000000280000-0x000000480000 : "kernel1"
    [    0.567500] 0x000000480000-0x000001240000 : "fs"
    [    0.575000] 0x000001240000-0x000002000000 : "play"
    [    0.590000] AT91SAM9 Watchdog enabled (heartbeat=15 sec, nowayout=0)
    [    0.607500] TCP cubic registered
    [    0.615000] VFS: Cannot open root device "ubi0:root0" or unknown-block(0,0)
    [    0.622500] Please append a correct "root=" boot option; here are the available partitions:
    [    0.630000] 1f00             128 mtdblock0  (driver?)
    [    0.635000] 1f01             256 mtdblock1  (driver?)
    [    0.640000] 1f02             128 mtdblock2  (driver?)
    [    0.645000] 1f03            2048 mtdblock3  (driver?)
    [    0.650000] 1f04            2048 mtdblock4  (driver?)
    [    0.655000] 1f05           14080 mtdblock5  (driver?)
    [    0.660000] 1f06           14080 mtdblock6  (driver?)
    [    0.665000] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
Run Code Online (Sandbox Code Playgroud)

Tim*_*ird 38

由内核初始化的模块的初始化例程(当它们静态链接到内核时)被包装在一个initcall()宏中,该宏指示它们应该在启动序列中运行.

有关宏及其排序的列表,请参阅include文件:include/linux/init.h.

那里指定的顺序是:

  • early_initcall
  • pure_initcall
  • core_initcall
  • postcore_initcall
  • arch_initcall
  • subsys_initcall
  • fs_initcall
  • rootfs_initcall
  • device_initcall
  • late_initcall

其中大多数都有一个"initcall_sync()阶段,用于等待该阶段内所有模块初始化例程的完成.宏用于构建每个阶段的函数指针表,按顺序调用 do_initcalls().

如果"module_init()"用于包装初始化函数,则默认情况下initcall()将调用置于初始化的"设备"阶段.在该阶段内,项目按链接顺序排序.这意味着表是由链接器遇到的函数顺序创建的.

您可以通过更改哪个initcall宏包装模块初始化函数来将初始化移动到早期阶段,但要小心,因为各个模块之间存在顺序依赖关系.更改初始化顺序(在一个阶段内)的另一种方法是调整内核中模块的链接顺序.


ser*_*ico 0

我可能是错的,所以请检查这是否正确。
尝试将您需要的所有驱动程序编译为模块(M),并将要加载的模块按正确的顺序放入/etc/modules中,这可以解决您的问题。准确地说,因为您是在挂载 rootfs之前执行此操作,所以上述步骤应该在 initram 磁盘中完成。(我有一个类似的场景,我需要以正确的顺序加载一些模块,以便能够解密文件系统)

希望这对
CiaoCiao
Sergio有帮助