在计算机领域,内核是处理与硬件通信和通用系统协调的底层软件。除了内置于计算机主板中的一些初始固件之外,当您启动计算机时,内核会提供对硬盘、屏幕、键盘和网卡的感知。内核的工作还要确保(或多或少)为每个组件分配相等的时间,以便您的图形、音频、文件系统和网络都能流畅运行,即使它们是同时运行的。
然而,对硬件支持的追求是持续不断的,因为发布的硬件越多,内核就必须在其代码中采用更多的东西,以使硬件按预期工作。很难获得准确的数字,但 Linux 内核无疑是硬件兼容性最高的内核之一。Linux 运行着无数的计算机和移动电话、用于业余爱好者和工业用途的片上嵌入式系统 (SoC) 板、RAID 卡、缝纫机等等。
回到 20 世纪(甚至 21 世纪初),Linux 用户期望当他们购买非常新的硬件时,他们需要下载最新的内核源代码,编译并安装它,以便他们可以获得对该设备的支持,这并非不合理。然而,最近,您很难找到一个编译自己的内核的 Linux 用户,除非是为了好玩或通过高度专业化的定制硬件获利。如今,通常不需要自己编译 Linux 内核。
以下是原因,以及在您需要时如何编译内核的快速教程。
更新您现有的内核
无论您是拥有一台配备了花哨的新显卡或 WiFi 芯片组的全新笔记本电脑,还是刚刚买了一台新打印机回家,您的操作系统(称为 GNU+Linux 或 Linux,这也是内核的名称)都需要一个驱动程序来打开与新组件(显卡、WiFi 芯片、打印机或任何东西)的通信通道。有时,当您插入新设备并且您的计算机似乎承认它时,这可能会具有欺骗性。但不要被它愚弄了。有时,这就是您所需要的全部,但其他时候,您的操作系统只是使用通用协议来探测连接的设备。
例如,您的计算机可能能够识别您的新网络打印机,但有时这仅仅是因为打印机中的网卡被编程为向网络标识自己,以便它可以获得 DHCP 地址。这并不一定意味着您的计算机知道向打印机发送哪些指令来生成一页打印文本。事实上,您可能会争辩说,计算机甚至不真正“知道”该设备是打印机;它可能只显示网络上有一个特定地址的设备,并且该设备用字符 p-r-i-n-t-e-r 的序列标识自己。人类语言的约定对计算机来说毫无意义;它需要的是驱动程序。
内核开发人员、硬件制造商、支持技术人员和爱好者都知道,新的硬件正在不断发布。他们中的许多人贡献驱动程序,直接提交给内核开发团队以包含在 Linux 中。例如,Nvidia 显卡驱动程序通常被写入 Nouveau 内核模块,并且由于 Nvidia 显卡很常见,因此该代码通常包含在为通用用途分发的任何内核中(例如,当您下载 Fedora 或 Ubuntu 时获得的内核)。在 Nvidia 不太常见的情况下,例如在嵌入式系统中,通常会排除 Nouveau 模块。许多其他设备也存在类似的模块:打印机受益于 Foomatic 和 CUPS,无线网卡有 b43, ath9k, wl 模块等等。
发行版倾向于在其 Linux 内核构建中尽可能多地包含内容,因为他们希望您能够连接设备并立即开始使用它,而无需安装驱动程序。在大多数情况下,情况就是这样,尤其是现在许多设备供应商都在资助他们销售的硬件的 Linux 驱动程序开发,并将这些驱动程序直接提交给内核团队以进行通用分发。
然而,有时,您运行的是六个月前安装的内核,并且使用了一周前刚上市的令人兴奋的新设备。在这种情况下,您的内核可能没有该设备的驱动程序。好消息是,通常情况下,该设备的驱动程序可能存在于内核的最新版本中,这意味着您只需更新您正在运行的内核即可。
通常,这是通过包管理器完成的。例如,在 RHEL、CentOS 和 Fedora 上
$ sudo dnf update kernel
在 Debian 和 Ubuntu 上,首先获取您当前的内核版本
$ uname -r
4.4.186
搜索较新版本
$ sudo apt update
$ sudo apt search linux-image
安装您找到的最新版本。在本例中,最新的可用版本是 5.2.4
$ sudo apt install linux-image-5.2.4
内核升级后,您必须重新启动(除非您正在使用 kpatch 或 kgraft)。然后,如果您需要的设备驱动程序在最新的内核中,您的硬件将按预期工作。
安装内核模块
有时,发行版不希望其用户经常使用某个设备(或者至少不希望设备驱动程序需要位于 Linux 内核中)。Linux 对驱动程序采用模块化方法,因此发行版可以发布单独的驱动程序包,这些驱动程序包可以由内核加载,即使驱动程序本身没有编译到内核中。这很有用,尽管当驱动程序未包含在内核中但在启动期间需要时,或者当内核从模块化驱动程序下更新时,它可能会变得复杂。第一个问题通过 initrd(初始 RAM 磁盘)解决,并且超出本文的范围,第二个问题通过名为 kmod 的系统解决。
kmod 系统确保在内核更新时,与其一起安装的所有模块化驱动程序也会更新。如果您手动安装驱动程序,您将错过 kmod 提供的自动化,因此您应该尽可能选择 kmod 包。例如,虽然 Nvidia 驱动程序作为 Nouveau 驱动程序内置于内核中,但官方 Nvidia 驱动程序仅由 Nvidia 分发。您可以通过访问网站、下载 .run 文件并运行它提供的 shell 脚本来手动安装 Nvidia 品牌驱动程序,但是您必须在安装新内核后重复相同的过程,因为没有任何东西告诉您的包管理器您手动安装了内核驱动程序。由于 Nvidia 驱动您的图形,手动更新 Nvidia 驱动程序通常意味着您必须从终端执行更新,因为在没有功能正常的图形驱动程序的情况下,您没有图形。

但是,如果您将 Nvidia 驱动程序作为 kmod 包安装,则更新您的内核也会更新您的 Nvidia 驱动程序。在 Fedora 和相关发行版上
$ sudo dnf install kmod-nvidia
在 Debian 和相关发行版上
$ sudo apt update
$ sudo apt install nvidia-kernel-common nvidia-kernel-dkms nvidia-glx nvidia-xconfig nvidia-settings nvidia-vdpau-driver vdpau-va-driver
这只是一个示例,但如果您在现实生活中安装 Nvidia 驱动程序,您还必须将 Nouveau 驱动程序列入黑名单。有关最佳步骤,请参阅您的发行版文档。
下载并安装驱动程序
并非所有内容都包含在内核中,也并非所有其他内容都作为内核模块提供。在某些情况下,您必须下载由硬件供应商编写和捆绑的特殊驱动程序,而在其他情况下,您有驱动程序但没有配置驱动程序选项的前端。
两个常见的例子是 HP 打印机和 Wacom 绘图板。如果您获得 HP 打印机,您可能拥有可以与您的打印机通信的通用驱动程序。您甚至可能能够打印。但是通用驱动程序可能无法提供特定于您型号的专用选项,例如双面打印、分页、纸盘选择等等。HPLIP(HP Linux 图像和打印系统)提供管理作业、调整打印选项、选择适用的纸盘等等的选项。
HPLIP 通常捆绑在包管理器中;只需搜索“hplip”即可。

同样,Wacom 平板电脑(数字艺术家领先的绘图板)的驱动程序通常包含在您的内核中,但微调设置的选项(例如压力灵敏度和按钮功能)只能通过 GNOME 默认包含的图形控制面板访问,但在 KDE 上可以作为额外的包 kde-config-tablet 安装。
可能有一些边缘情况,内核中没有驱动程序,但提供驱动程序模块的 kmod 版本作为 RPM 或 DEB 文件,您可以下载并通过包管理器安装。
补丁和编译您自己的内核
即使在 21 世纪这个未来的乌托邦中,也有一些供应商不理解开源,无法提供可安装的驱动程序。有时,此类公司提供驱动程序的源代码,但希望您下载代码、修补内核、编译并手动安装。
这种分发模型与在 kmod 系统之外安装打包驱动程序具有相同的缺点:内核更新会破坏驱动程序,因为它每次内核更换为新内核时都必须手动重新集成到您的内核中。
幸运的是,这种情况已经变得很少见,因为 Linux 内核团队在强烈呼吁公司与他们沟通方面做得非常出色,并且因为公司最终接受了开源不会很快消失。但仍然有一些新颖或高度专业化的设备只提供内核补丁。
官方来说,对于如何编译内核以使您的包管理器参与升级系统的这个重要部分,存在特定于发行版的首选项。包管理器太多,无法一一介绍;例如,以下是当您在 Fedora 上使用 rpmdev 或在 Debian 上使用 build-essential 和 devscripts 等工具时幕后发生的事情。
首先,像往常一样,找出您正在运行的内核版本
$ uname -r
在大多数情况下,如果您尚未升级内核,则升级内核是安全的。毕竟,您的问題很可能会在最新版本中得到解决。如果您尝试过但没有奏效,那么您应该下载您正在运行的内核的源代码。大多数发行版都为此提供了特殊命令,但要手动执行此操作,您可以在 kernel.org 上找到源代码。
您还必须下载内核所需的任何补丁。有时,这些补丁特定于内核版本,因此请仔细选择。
将源代码和补丁放在 /usr/src/linux 中是传统的做法,或者至少在人们经常编译自己的内核时是这样做的。
根据需要解压缩内核源代码和补丁文件
$ cd /usr/src/linux
$ bzip2 --decompress linux-5.2.4.tar.bz2
$ cd linux-5.2.4
$ bzip2 -d ../patch*bz2
补丁文件可能包含有关如何打补丁的说明,但通常它们被设计为从您的树的顶层执行
$ patch -p1 < patch*example.patch
一旦内核代码被修补,您可以使用旧的配置来准备修补后的内核配置
$ make oldconfig
make oldconfig 命令有两个用途:它继承您当前内核的配置,并允许您配置补丁引入的新选项。
您可能需要运行 make menuconfig 命令,该命令启动一个基于 ncurses 的、菜单驱动的列表,其中包含新内核的可能选项。该菜单可能让人感到不知所措,但由于它以您的旧配置为基础开始,您可以浏览菜单并禁用您知道您没有并且不希望需要的硬件模块。或者,如果您知道您拥有某些硬件并且看到它未包含在您当前的配置中,您可以选择构建它,无论是作为模块还是直接构建到内核中。从理论上讲,这没有必要,因为据推测,您当前的内核对您来说运行良好,只是缺少补丁,并且您应用的补丁可能已经激活了最初提示您修补内核的任何设备所需的所有必要选项。
接下来,编译内核及其模块
$ make bzImage
$ make modules
这会为您留下一个名为 vmlinuz 的文件,它是可引导内核的压缩版本。保存您的旧版本并将新版本放在您的 /boot 目录中
$ sudo mv /boot/vmlinuz /boot/vmlinuz.nopatch
$ sudo cat arch/x86_64/boot/bzImage > /boot/vmlinuz
$ sudo mv /boot/System.map /boot/System.map.stock
$ sudo cp System.map /boot/System.map
到目前为止,您已经修补并构建了一个内核及其模块,您已经安装了内核,但您尚未安装任何模块。那是最后的构建步骤
$ sudo make modules_install
新内核已就位,其模块已安装。
最后一步是更新您的引导加载程序,以便在内核之前加载的计算机部分知道在哪里找到 Linux。GRUB 引导加载程序使此过程相对简单
$ sudo grub2-mkconfig
真实世界的编译
当然,现在没有人运行这些手动命令了。相反,请参阅您的发行版,以获取有关使用您的发行版维护者使用的开发人员工具集修改内核的说明。此工具集可能会创建一个新的可安装包,其中包含所有已合并的补丁,提醒包管理器进行升级,并为您更新引导加载程序。
内核
操作系统和内核是神秘的东西,但不需要太多即可了解它们构建在哪些组件之上。下次您获得一块在 Linux 上似乎无法工作的技术时,请深吸一口气,调查驱动程序的可用性,并选择阻力最小的路径。Linux 比以往任何时候都更容易——包括内核。
7 条评论