将内核内置模块替换为可加载模块



我开发了一个内核模块,将nf4标记作为char设备进行管理。

我在内核之外开发了这个模块,并在开发阶段将其作为可加载内核模块(即.ko)进行了测试。

一旦驱动程序足够正常和稳定,我就使用补丁将其插入到linux内核源代码(v4.9.30)中,使其成为内核的一部分。

在这里,我所处的情况是,内核在引导时对模块进行了

加载探测,因为它是内置的,并且出现在设备树中。

现在,我想尝试对驱动程序进行一些改进,但我不想将这些更改直接实现到内核中。

因此,我希望将驱动程序的代码集成到linux内核中,但不要在启动时插入。为了做到这一点,我刚刚在设备树中更改了带有status = "disable";的驱动程序状态字段,实际上在启动时不再插入模块。

但是,我无法插入已修改的可加载模块。我在插入时有一个ENODEV,这是由于在探测函数中找不到平台设备。

我不明白的是,当设备树除了状态字段值之外没有更改时,为什么找不到平台设备。


编辑:添加有关情况的精确信息

经过更多的探索,我必须准确地说,我甚至没有进入回调nf4_probe

在检查了v4.9.30内核源中的platform_driver_probe实现(请参阅此处)后,错误似乎来自此处:

if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
retval = -ENODEV;

通过从命令行检查设备树,我可以看到设备被定义为目录/proc/device-tree/nf4tag存在,并且用与设备树中的值相对应的值填充。


编辑:在@sawd的答案后添加关于问题目标的精确性

我显然误解了status=disable意味着该设备根本不存在于硬件配置中。尽管它只是描述了是否应该探查驾驶员。

为了使我的目标更加清晰,我精确地说,我确实将驱动程序编码为适当的模块,并编译为我正在使用的内核的可加载模块。

然而,我不想重新编译内核来测试我所做的每一个更改。因此,我的目标是只重新编译.ko,直到我的修改完成,然后,一旦完成所有操作,使用补丁将这些修改添加到内置模块中。

通过这种工作方式,我可以重新构建.ko并将其插入到我的目标平台上,而不是为每次修改重新编译内核。

所以继续我的问题应该是:

如何在不重新编译内核以禁用内置模块的情况下用可加载模块替换内置模块

也许除了禁用编译到内核上的内置模块之外,没有其他解决方案。

我不明白的是,当设备树除了状态字段值之外没有更改时,为什么找不到平台设备。

您似乎误解了status = "disable"属性的实际含义
除了意味着内核应该"在启动时不插入">之外,禁用节点意味着设备根本不属于当前硬件配置的一部分
驱动程序,无论是内置模块还是可加载模块,都不会被探测,因为它已被当前配置禁用。

如果希望驱动程序(无论是内置模块还是可加载模块)处于当前配置中,则在其"设备树"节点中具有status = "okay"属性。

IOW设备树用于向内核描述当前硬件配置
不要尝试使用设备树来控制可加载模块(因为它不能)。

这里的情况是,内核在启动时加载模块,因为它是内置的,并且它出现在设备树中。

这句话毫无意义,因为您似乎同时将驱动程序描述为内置模块和可加载模块
内置驱动程序不必"加载">即可调用其探测例程
因为驱动程序可以是内置的,也可以是可加载的,所以"加载"one_answers"探测"是两个不同的阶段,不应混为一谈。

因此,我希望将驱动程序的代码集成到linux内核中,但不要在启动时插入。

您似乎将Linux内核的概念与源代码树混为一谈
"集成到linux内核中的驱动程序代码">通常被解释为内置驱动程序,即驱动程序链接在中,并且是在引导时加载的内核映像的一部分
存储在内核源代码树中的驱动程序代码不指定它是内置模块还是可加载模块。许多驱动程序(和其他类型的模块)都可以编译,而编译配置指定了哪一个。

如果你希望你的驱动程序是一个可加载的模块,那么(而不是更改设备树):

a。你需要将你的驱动程序编码为一个合适的模块
b。您需要修改Kconfig文件,以便在内置模块或可加载模块之间进行选择(即tristatebool选择规范)
c。配置内核以将驱动程序构建为可加载模块。


作为可加载模块并在设备树中定义的设备驱动程序仍然可以在引导期间自动加载和探测。您可能必须使用模块黑名单来防止这种情况发生。


**附录**

如何在不重新编译内核以禁用内置模块的情况下用可加载模块替换内置模块?

你不能。这就是为什么如果您希望构建驱动程序,Kconfig会强制您在可加载模块(m)或内置(y)之间进行选择。

。。。然后,完成所有操作后,使用补丁将这些修改添加到内置模块中。

这毫无意义,因为您只需要驱动程序源代码的一个副本即可构建可加载模块或内置版本的驱动程序。

使用这种工作方式,我可以重建.ko并将其插入到我的目标平台上,而不是为每次修改重新编译内核。

似乎您将驱动程序集成到内核源代码中的方式值得怀疑
为了将驱动程序集成到内核源代码树中,您实际做了什么
您为驱动程序修改了哪个KconfigMakefile
您为驱动程序创建了哪些新的CONFIG_*符号?

是的,您必须"每次修改都要重新编译">,但make足够聪明,可以只重建必要的内容。当您知道只有可加载的驱动程序被修改时,可以使用make modules来进一步缩短内核重建时间。


结束

  • 如果不重新编译内核以禁用内置模块,就不可能使用树外可加载模块

但是

  • M处仅用tristate重新编译内核一次,并在内核引导行上将模块列入黑名单,成功
  • n使用tristate仅重新编译内核一次成功

因此,内核必须至少重新编译一次,但之后可以使用作为可加载模块编译的树外驱动程序,而不必删除集成到linux源代码中的代码。

最新更新