我一直在开发带有嵌入式 ARM 处理器的主板。为了让它启动,我必须添加一个引导加载程序、一个 Linux 内核和一个包含根文件系统的磁盘映像。该磁盘映像可在 Internet 上找到用于目标板 (ZedBoard) 的磁盘映像。
编译内核并激活所有必需的驱动程序后,我发现 /lib/modules/kernel_number 中提供了许多驱动程序。
我对整个事情是如何运作的有点困惑。驱动程序是由内核加载的吗?如果是这样,为什么它们已经是 rootfs 的一部分?或者内核是否用其中编译的内容覆盖它们?
答案1
尽管我们应该区分“驱动程序”和“模块”,但它非常简单。 驱动程序可能是也可能不是模块。 如果不是,则它将内置到引导加载程序加载的内核中。
如果它是一个模块,那么它位于以 为根的文件系统层次结构中/lib/modules/[kernel-release]
。1 请注意,可以将内核与小型初步根文件系统(“initramfs”)一起引导,该文件系统也可能包含此类存储库。这对于通用内核来说是正常的,因此它们可以决定需要加载哪些模块化驱动程序才能访问真正的文件系统,因为如果它们不能这样做,它们就无法访问那里的任何模块。
驱动程序是由内核加载的吗?
是的。
如果是这样,为什么它们已经是 rootfs 的一部分?
装载前它们还应该存放在哪里?内核本身不包含 rootfs(除了 WRT 某些形式的 initramfs),它只是看门人。
内核是否会用其中编译的内容覆盖它们?
不会。如果您编译了驱动程序,内核将不会费心去检查/lib/modules
它。我不确定如果你明确要求它加载这样的驱动程序,会发生什么,大概它只会说不。
1. 正如 Celada 暗示的那样$(uname -r)
,这个版本字符串不一定只是版本号。您可以拥有具有相同版本和不同版本字符串的多个内核,因此可以使用单独的模块存储。同样,您可以拥有具有相同发布字符串的多个内核,因此具有相同的模块存储。
答案2
在 Linux 中,大多数驱动程序可以静态构建到内核中,也可以构建为模块。这是在配置内核进行编译时可以做出的选择。它们仅/lib/modules/$(uname -r)
在构建为可加载模块时才会出现。
通常,对于通用系统,尤其是作为 Linux 发行版的一部分提供的预编译内核,将静态构建严格的最小驱动程序集,并尽可能将其构建为模块。这允许每个用户的系统仅加载必要的模块,而无需提前知道它们是什么。
嵌入式系统的内核通常内置有更多的驱动程序,因为内核是为具有一组非常特定的不变硬件的系统而构建的,并且系统集成商事先知道它是什么。然而,许多驱动程序通常会作为模块加载,特别是对于可能存在或不存在的“额外”硬件(如 USB 设备)。