Modalias

出自 ArchWiki

本文或章节需要改进语言、wiki 语法或风格。请参考 Help:Style

原因: 文章需要更正式,避免使用第一人称视角。参见 Help:Style。(在 Talk:Modalias 中讨论)

本文档是对 Linux 内核和模块如何查看和理解硬件的介绍,以及这如何转化为 sysfs 'modalias'

什么是 modalias

Modalias 是一个小小的 sysfs 技巧,它将硬件信息导出到一个名为 'modalias' 的文件。该文件只是简单地包含了硬件正常暴露的信息的格式化形式。

$ cat /sys/devices/pci0000:00/0000:00:1f.1/modalias
pci:v00008086d000024DBsv0000103Csd0000006Abc01sc01i8A

什么是 modalias 文件?

如上所述,modalias 文件只是简单地暴露了给定硬件已经告诉内核的信息。该文件只是指定了一种暴露此信息的结构。让我们回到上面的例子

$ cat /sys/devices/pci0000:00/0000:00:1f.1/modalias
pci:v00008086d000024DBsv0000103Csd0000006Abc01sc01i8A

让我们逐个分解它。首先是文件名,/sys/devices/pci0000:00/0000:00:1f.1/modalias

  • pci0000:00 是第一个 PCI 总线的 ID。对于大多数机器来说,这将是你拥有的唯一 PCI 总线,但它有可能扩展到 pci0000:01pci0000:02 - 具体细节并不重要,因为你可以很好地猜测你只有一个 PCI 总线(提示: 尝试 ls /sys/devices/pci* 来检查)
  • 0000:00:1f.1 是给定设备在 PCI 总线上的索引。具体来说,它位于总线 0000:00 上,索引为 1f.1
  • 除非你想知道所有这些数字来自哪里,否则所有这些都相当不重要。为了完整性,如果你检查 lspci 的输出,你将看到相同的信息
$ lspci
00:1f.1 IDE interface: Intel Corp.: Unknown device 24db (rev 02)

现在,让我们看一下设备 00:1f.1 的 modalias 文件的内容

pci:v00008086d000024DBsv0000103Csd0000006Abc01sc01i8A

嗯,嘿,我能看到 pci!我认得那个,但是结尾那些乱七八糟的是什么?这些乱七八糟的东西实际上是结构化数据。你会注意到一个重复的字母/数字方案。让我们把它分开,使其更容易阅读

v  00008086
d  000024DB
sv 0000103C
sd 0000006A
bc 01
sc 01
i  8A

这些标识符以及相应的十六进制数字表示给定设备暴露的一些信息。首先,v供应商 IDd设备 ID - 这些都是非常标准的数字。实际上,像 hwdetect 这样的工具会使用这些以及其他 sysfs 文件来提供设备信息。你甚至可以找到网站来根据供应商和设备 ID 查找特定的硬件标识,例如,https://devicehunt.com/

我们也可以在这里看到这些数字

$ lspci -n
00:1f.1 Class 0101: 8086:24db (rev 02)

看看 8086:24db 如何与上面列出的 vd 标记匹配?

记录一下,svsd 是供应商和设备的“子系统”版本。大多数情况下,这些都被忽略。它们主要由硬件开发人员用来区分内部工作原理的细微差异,这些差异不会改变设备的整体。

bc(基类)和 sc(子类)用于创建 lspci 列出的“Class”,顺序为“bcsc”。这是设备类,它相当通用。在这种情况下,“class”在正常的 lspci 输出中查找。我们可以看到“Class 0101”映射到“IDE Interface”(lspci 也查找供应商和设备 ID - 8086 映射到“Intel Corp.”,24DB 映射到“Unknown Device”,呵呵)

i 是“编程接口”,它仅对少数设备类有意义。

此信息如何使用?

好的,现在我们都知道这些信息是什么了。一堆每个设备都暴露的晦涩数字。没什么大不了的。当谈论模块时,这有什么关系呢?

人们倾向于忽略的一件事是 depmod 所做的所有工作。当你运行 depmod 时,它会在 /lib/modules/`uname -r` 中构建一系列“map”文件,这些文件告诉 modprobe 如何处理它需要做的某些事情。在这种情况下,我们可以忽略它们中的大多数。重要的是 modules.alias。此文件包含模块的别名或辅助名称。只是为了演示,让我们看看别名,例如,snd_intel8x0m

$ grep snd_intel8x0m /lib/modules/$(uname -r)/modules.alias
alias pci:v00008086d00002416sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d00002426sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d00002446sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d00002486sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d000024C6sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d000024D6sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d0000266Dsv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d000027DDsv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00008086d00007196sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00001022d00007446sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v00001039d00007013sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v000010DEd000001C1sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v000010DEd00000069sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v000010DEd00000089sv*sd*bc*sc*i* snd_intel8x0m
alias pci:v000010DEd000000D9sv*sd*bc*sc*i* snd_intel8x0m

嘿,等等!我认得那个!那是之前的供应商/设备 ID 信息!

是的,它是。它是一个相当简单的格式“alias <something> <actual module>”。实际上,你可以为你想要的任何东西设置别名。我可以添加“alias boogabooga snd_intel8x0m”,然后安全地“modprobe boogabooga”。

“*”表示它将匹配任何内容,很像文件系统 globbing (ls somedir/*)。如前所述,大多数别名通过 “*” 匹配忽略 sv、sd、bc、sc 和 i。

modules.alias 文件从何而来?

好的,现在你可能会想“好吧,硬件探测 曾经根据设备表查找东西,这有什么不同?”

不同之处在于此查找表不是静态的。它不是手动维护的。实际上,它是在你每次运行 depmod 时动态构建的。“这些信息从何而来?”,你问?为什么,来自 内核模块 本身。当你考虑一下,每个特定的模块都应该知道它支持哪些硬件,因为它专门为该硬件编码。我的意思是,nvidia 模块开发人员知道他们的模块只适用于 Nvidia(供应商)显卡(类)。实际上,模块实际上导出了此信息。它说“嘿,我可以支持这个:”。

$ modinfo nvidia
  filename:       /lib/modules/2.6.14-ARCH/kernel/drivers/video/nvidia.ko
  license:        NVIDIA
  alias:          char-major-195-*
  vermagic:       2.6.14-ARCH SMP preempt 686 gcc-4.1
  depends:        agpgart
  alias:          pci:v000010DEd*sv*sd*bc03sc00i00*

正如你在列出的别名中看到的,它专门查找供应商“10DE”(Nvidia)和 bc/sc 0300(很可能是“显卡”)。实际上,如果你查看 snd_intel8x0m 的 modinfo

$ modinfo snd_intel8x0m
  filename:       /lib/modules/2.6.14-ARCH/kernel/sound/pci/snd-intel8x0m.ko
  author:         Jaroslav Kysela <perex@suse.cz>
  description:    Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7013; NVidia MCP/2/2S/3 modems
  license:        GPL
  vermagic:       2.6.14-ARCH SMP preempt 686 gcc-4.1
  depends:        snd-ac97-codec,snd-pcm,snd-page-alloc,snd
  alias:          pci:v00008086d00002416sv*sd*bc*sc*i*
  alias:          pci:v00008086d00002426sv*sd*bc*sc*i*
  alias:          pci:v00008086d00002446sv*sd*bc*sc*i*
  alias:          pci:v00008086d00002486sv*sd*bc*sc*i*
  alias:          pci:v00008086d000024C6sv*sd*bc*sc*i*
  alias:          pci:v00008086d000024D6sv*sd*bc*sc*i*
  alias:          pci:v00008086d0000266Dsv*sd*bc*sc*i*
  alias:          pci:v00008086d000027DDsv*sd*bc*sc*i*
  alias:          pci:v00008086d00007196sv*sd*bc*sc*i*
  alias:          pci:v00001022d00007446sv*sd*bc*sc*i*
  alias:          pci:v00001039d00007013sv*sd*bc*sc*i*
  alias:          pci:v000010DEd000001C1sv*sd*bc*sc*i*
  alias:          pci:v000010DEd00000069sv*sd*bc*sc*i*
  alias:          pci:v000010DEd00000089sv*sd*bc*sc*i*
  alias:          pci:v000010DEd000000D9sv*sd*bc*sc*i*

它匹配了通过 'grep'ing 别名文件找到的别名。每个模块导出的这些别名由 depmod 收集并动态合并到 modules.alias 文件中。没有手动更改查找表,因为它是即时构建的。每个模块都确切地知道它支持什么,因此 depmod 可以使用该信息来帮助加载模块。

udev 如何工作?

udev 与 sysfs(首先暴露 modalias 的文件系统)紧密相连。实际上,要基于 modalias 在添加新设备时(或在启动时首次启动 udev 时)加载模块,这非常简单

DRIVER!="?*", ENV{MODALIAS}=="?*", RUN{builtin}="kmod load $env{MODALIAS}"

是的,就是这样。这是一行代码。这简单的行代码,是默认 udev 规则的一部分,取代了 hotplug。令人惊叹,不是吗?

参见

本文展示了其他 modalias 模板,例如 usb、dmi 和 acpi 子类型