标签 内核 下的文章

也许你并不需要编译 Linux 内核,但你能通过这篇教程快速上手。

在计算机世界里, 内核 kernel 是处理硬件与一般系统之间通信的 低阶软件 low-level software 。除过一些烧录进计算机主板的初始固件,当你启动计算机时,内核让系统意识到它有一个硬盘驱动器、屏幕、键盘以及网卡。分配给每个部件相等时间(或多或少)使得图像、音频、文件系统和网络可以流畅甚至并行地运行。

然而,对于硬件的需求是源源不断的,随着发布的硬件越多,内核就必须纳入更多代码来保证那些硬件正常工作。得到具体的数字很困难,但是 Linux 内核无疑是硬件兼容性方面的顶级内核之一。Linux 操作着无数的计算机和移动电话、工业用途和爱好者使用的板级嵌入式系统(SoC)、RAID 卡、缝纫机等等。

回到 20 世纪(甚至是 21 世纪初期),对于 Linux 用户来说,在刚买到新的硬件后就需要下载最新的内核代码并编译安装才能使用这是不可理喻的。而现在你也很难见到 Linux 用户为了好玩而编译内核或通过高度专业化定制的硬件的方式赚钱。现在,通常已经不需要再编译 Linux 内核了。

这里列出了一些原因以及快速编译内核的教程。

更新当前的内核

无论你买了配备新显卡或 Wifi 芯片集的新品牌电脑还是给家里配备一个新的打印机,你的操作系统(称为 GNU+Linux 或 Linux,它也是该内核的名字)需要一个驱动程序来打开新部件(显卡、芯片集、打印机和其他任何东西)的信道。有时候当你插入某些新的设备时而你的电脑表示发现了它,这具有一定的欺骗性。别被骗到了,有时候那就够了,但更多的情况是你的操作系统仅仅是使用了通用的协议检测到安装了新的设备。

例如,你的计算机也许能够鉴别出新的网络打印机,但有时候那仅仅是因为打印机的网卡被设计成为了获得 DHCP 地址而在网络上标识自己。它并不意味着你的计算机知道如何发送文档给打印机进行打印。事实上,你可以认为计算机甚至不“知道”那台设备是一个打印机。它也许仅仅是显示网络有个设备在一个特定的地址上,并且该设备以一系列字符 “p-r-i-n-t-e-r” 标识自己而已。人类语言的便利性对于计算机毫无意义。计算机需要的是一个驱动程序。

内核开发者、硬件制造商、技术支持和爱好者都知道新的硬件会不断地发布。它们大多数都会贡献驱动程序,直接提交给内核开发团队以包含在 Linux 中。例如,英伟达显卡驱动程序通常都会写入 Nouveau 内核模块中,并且因为英伟达显卡很常用,它的代码都包含在任一个日常使用的发行版内核中(例如当下载 FedoraUbuntu 得到的内核)。英伟达也有不常用的地方,例如嵌入式系统中 Nouveau 模块通常被移除。对其他设备来说也有类似的模块:打印机得益于 FoomaticCUPS,无线网卡有 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

内核更新后,你必须 reboot (除非你使用 kpatch 或 kgraft)。这时,如果你需要的设备驱动程序包含在最新的内核中,你的硬件就会正常工作。

安装内核模块

有时候一个发行版没有预计到用户会使用某个设备(或者该设备的驱动程序至少不足以包含在 Linux 内核中)。Linux 对于驱动程序采用模块化方式,因此尽管驱动程序没有编译进内核,但发行版可以推送单独的驱动程序包让内核去加载。尽管有些复杂但是非常有用,尤其是当驱动程序没有包含进内核中而是在引导过程中加载,或是内核中的驱动程序相比模块化的驱动程序过期时。第一个问题可以用 “initrd” 解决(初始化 RAM 磁盘),这一点超出了本文的讨论范围,第二点通过 “kmod” 系统解决。

kmod 系统保证了当内核更新后,所有与之安装的模块化驱动程序也得到更新。如果你手动安装一个驱动程序,你就体验不到 kmod 提供的自动化,因此只要能用 kmod 安装包,就应该选择它。例如,尽管英伟达驱动程序以 Nouveau 模块构建在内核中,但官方的驱动程序仅由英伟达发布。你可以去网站上手动安装英伟达旗下的驱动程序,下载 “.run” 文件,并运行提供的 shell 脚本,但在安装了新的内核之后你必须重复相同的过程,因为没有任何东西告诉包管理软件你手动安装了一个内核驱动程序。英伟达驱动着你的显卡,手动更新英伟达驱动程序通常意味着你需要通过终端来执行更新,因为没有显卡驱动程序将无法显示。

 title=

然而,如果你通过 kmod 包安装英伟达驱动程序,更新你的内核也会更新你的英伟达驱动程序。在 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

这仅仅是一个例子,但是如果你真的要安装英伟达驱动程序,你也必须屏蔽掉 Nouveau 驱动程序。参考你使用发行版的文档获取最佳的步骤吧。

下载并安装驱动程序

不是所有的东西都包含在内核中,也不是所有的东西都可以作为内核模块使用。在某些情况下,你需要下载一个由供应商编写并绑定好的特殊驱动程序,还有一些情况,你有驱动程序,但是没有配置驱动程序的前端界面。

有两个常见的例子是 HP 打印机和 Wacom 数位板。如果你有一台 HP 打印机,你可能有能够和打印机通信的通用的驱动程序,甚至能够打印出东西。但是通用的驱动程序却不能为特定型号的打印机提供定制化的选项,例如双面打印、校对、纸盒选择等等。HPLIP(HP Linux 成像和打印系统)提供了选项来进行任务管理、调整打印设置、选择可用的纸盒等等。

HPLIP 通常包含在包管理软件中;只要搜索“hplip”就行了。

 title=

同样的,电子艺术家主要使用的数位板 Wacom 的驱动程序通常也包含在内核中,但是例如调整压感和按键功能等设置只能通过默认包含在 GNOME 的图形控制面板访问。但也可以作为 KDE 上额外的程序包“kde-config-tablet”来访问。

这里也有几个类似的个别例子,例如内核中没有驱动程序,但是以 RPM 或 DEB 文件提供了可供下载并且通过包管理软件安装的 kmod 版本的驱动程序。

打上补丁并编译你的内核

即使在 21 世纪的未来主义乌托邦里,仍有厂商不够了解开源,没有提供可安装的驱动程序。有时候,一些公司为驱动程序提供开源代码,而需要你下载代码、修补内核、编译并手动安装。

这种发布方式和在 kmod 系统之外安装打包的驱动程序拥有同样的缺点:对内核的更新会破坏驱动程序,因为每次更换新的内核时都必须手动将其重新集成到内核中。

令人高兴的是,这种事情变得少见了,因为 Linux 内核团队在呼吁公司们与他们交流方面做得很好,并且公司们最终接受了开源不会很快消失的事实。但仍有新奇的或高度专业的设备仅提供了内核补丁。

官方上,对于你如何编译内核以使包管理器参与到升级系统如此重要的部分中,发行版有特定的习惯。这里有太多的包管理器,所以无法一一涵盖。举一个例子,当你使用 Fedora 上的工具例如 rpmdevbuild-essential,Debian 上的 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 比以前简单多了——包括内核。


via: https://opensource.com/article/19/8/linux-kernel-21st-century

作者:Seth Kenlon 选题:lujun9972 译者:LuMing 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

自从第一个 Linux 内核发布已经过去 28 年了。自 1991 年以来发布了几十个 Linux 内核版本,你喜欢的是哪个?投个票吧!

让我们回到 1991 年 8 月,那个创造历史的时间。科技界经历过许多关键时刻,这些时刻仍在影响着我们。在那个 8 月,Tim Berners-Lee 宣布了一个名为 万维网 World Wide Web 的有趣项目,并推出了第一个网站;超级任天堂在美国发布,为所有年龄段的孩子们开启了新的游戏篇章;在赫尔辛基大学,一位名叫 Linus Torvalds 的学生向同好们询问(1991 年 8 月 25 日)了他作为业余爱好开发的新免费操作系统的反馈。那时 Linux 内核诞生了。

如今,我们可以浏览超过 15 亿个网站,在我们的电视机上玩另外五种任天堂游戏机,并维护着六个长期 Linux 内核。以下是我们的一些作者对他们最喜欢的 Linux 内核版本所说的话。

“引入模块的那个版本(1.2 吧?)。这是 Linux 迈向成功的未来的重要一步。” - Milan Zamazal

“2.6.9,因为它是我 2006 年加入 Red Hat 时的版本(在 RHEL4 中)。但我也更钟爱 2.6.18(RHEL5)一点,因为它在大规模部署的、我们最大客户(Telco, FSI)的关键任务工作负载中使用。它还带来了我们最大的技术变革之一:虚拟化(Xen 然后是 KVM)。” - Herve Lemaitre

“4.10。(虽然我不知道如何衡量这一点)。” - Ivan Bazulic

“Fedora 30 附带的新内核修复了我的 Thinkpad Yoga 笔记本电脑的挂起问题;挂起功能现在可以完美运行。我是一个笨人,只是忍受这个问题而从未试着提交错误报告,所以我特别感谢这项工作,我知道一定会解决这个问题。” - MáirínDuffy

“2.6.16 版本将永远在我的心中占有特殊的位置。这是我负责将其转换为在 hertz neverlost gps 系统上运行的第一个内核。我负责这项为那个设备构建内核和根文件系统的工作,对我来说这真的是一个奇迹时刻。我们在初次发布后多次更新了内核,但我想我必须还是推选那个最初版本,不过,我对于它的热爱没有任何技术原因,这纯属感性选择 =)” - Michael McCune

“我最喜欢的 Linux 内核版本是 2.4.0 系列,它集成了对 USB、LVM 和 ext3 的支持。ext3 是第一个具有日志支持的主流 Linux 文件系统,其从 2.4.15 内核可用。我使用的第一个内核版本是 2.2.13。” - Sean Nelson

“也许是 2.2.14,因为它是在我安装的第一个 Linux 上运行的版本(Mandrake Linux 7.0,在 2000 IIRC)。它也是我第一个需要重新编译以让我的视频卡或我的调制解调器(记不清了)工作的版本。” - GermánPulido

“我认为最新的一个!但我有段时间使用实时内核扩展来进行音频制作。” - Mario Torre

在 Linux 内核超过 52 个的版本当中,你最喜欢哪一个?参加我们的调查并在评论中告诉我们原因。


via: https://opensource.com/article/19/8/linux-kernel-favorite-release

作者:Lauren Pritchett 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

最近发布的 Ubuntu 18.04.3 包括 Linux 5.0 内核中的几个新功能和改进,但默认情况下没有安装。本教程演示了如何在 Ubuntu 18.04 LTS 中获取 Linux 5 内核。

Ubuntu 18.04 的第三个“点发布版”已经发布,它带来了新的稳定版本的 GNOME 组件、livepatch 桌面集成和内核 5.0。

可是等等!什么是“ 小数点版本 point release ”?让我先解释一下。

Ubuntu LTS 小数点版本

Ubuntu 18.04 于 2018 年 4 月发布,由于它是一个长期支持 (LTS) 版本,它将一直支持到 2023 年。从那时起,已经有许多 bug 修复、安全更新和软件升级。如果你今天下载 Ubuntu 18.04,你需要在在安装 Ubuntu 后首先安装这些更新

当然,这不是一种理想情况。这就是 Ubuntu 提供这些“小数点版本”的原因。点发布版包含所有功能和安全更新以及自 LTS 版本首次发布以来添加的 bug 修复。如果你今天下载 Ubuntu,你会得到 Ubuntu 18.04.3 而不是 Ubuntu 18.04。这节省了在新安装的 Ubuntu 系统上下载和安装数百个更新的麻烦。

好了!现在你知道“小数点版本”的概念了。你如何升级到这些小数点版本?答案很简单。只需要像平时一样更新你的 Ubuntu 系统,这样你将在最新的小数点版本上了。

你可以查看 Ubuntu 版本来了解正在使用的版本。我检查了一下,因为我用的是 Ubuntu 18.04.3,我以为我的内核会是 5。当我查看 Linux 内核版本时,它仍然是基本内核 4.15。

Ubuntu Version And Linux Kernel Version Check

这是为什么?如果 Ubuntu 18.04.3 有 Linux 5.0 内核,为什么它仍然使用 Linux 4.15 内核?这是因为你必须通过选择 LTS 支持栈 Enablement Stack (通常称为 HWE)手动请求在 Ubuntu LTS 中安装新内核。

使用 HWE 在Ubuntu 18.04 中获取 Linux 5.0 内核

默认情况下,Ubuntu LTS 将保持在最初发布的 Linux 内核上。 硬件支持栈 hardware enablement stack (HWE)为现有的 Ubuntu LTS 版本提供了更新的内核和 xorg 支持。

最近发生了一些变化。如果你下载了 Ubuntu 18.04.2 或更新的桌面版本,那么就会为你启用 HWE,默认情况下你将获得新内核以及常规更新。

对于服务器版本以及下载了 18.04 和 18.04.1 的人员,你需要安装 HWE 内核。完成后,你将获得 Ubuntu 提供的更新的 LTS 版本内核。

要在 Ubuntu 桌面上安装 HWE 内核以及更新的 xorg,你可以在终端中使用此命令:

sudo apt install --install-recommends linux-generic-hwe-18.04 xserver-xorg-hwe-18.04

如果你使用的是 Ubuntu 服务器版,那么就不会有 xorg 选项。所以只需在 Ubutnu 服务器版中安装 HWE 内核:

sudo apt-get install --install-recommends linux-generic-hwe-18.04

完成 HWE 内核的安装后,重启系统。现在你应该拥有更新的 Linux 内核了。

你在 Ubuntu 18.04 中获取 5.0 内核了么?

请注意,下载并安装了 Ubuntu 18.04.2 的用户已经启用了 HWE。所以这些用户将能轻松获取 5.0 内核。

在 Ubuntu 中启用 HWE 内核遇到困难了么?这完全取决于你。Linux 5.0 内核有几项性能改进和更好的硬件支持。你将从新内核获益。

你怎么看?你会安装 5.0 内核还是宁愿留在 4.15 内核上?


via: https://itsfoss.com/ubuntu-hwe-kernel/

作者:Abhishek Prakash 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

深入理解 Linux 配置/构建系统是如何工作的。

自从 Linux 内核代码迁移到 Git 以来,Linux 内核配置/构建系统(也称为 Kconfig/kbuild)已存在很长时间了。然而,作为支持基础设施,它很少成为人们关注的焦点;甚至在日常工作中使用它的内核开发人员也从未真正思考过它。

为了探索如何编译 Linux 内核,本文将深入介绍 Kconfig/kbuild 内部的过程,解释如何生成 .config 文件和 vmlinux/bzImage 文件,并介绍一个巧妙的依赖性跟踪技巧。

Kconfig

构建内核的第一步始终是配置。Kconfig 有助于使 Linux 内核高度模块化和可定制。Kconfig 为用户提供了许多配置目标:

配置目标解释
config利用命令行程序更新当前配置
nconfig利用基于 ncurses 菜单的程序更新当前配置
menuconfig利用基于菜单的程序更新当前配置
xconfig利用基于 Qt 的前端程序更新当前配置
gconfig利用基于 GTK+ 的前端程序更新当前配置
oldconfig基于提供的 .config 更新当前配置
localmodconfig更新当前配置,禁用没有载入的模块
localyesconfig更新当前配置,转换本地模块到核心
defconfig带有来自架构提供的 defconcig 默认值的新配置
savedefconfig保存当前配置为 ./defconfig(最小配置)
allnoconfig所有选项回答为 no 的新配置
allyesconfig所有选项回答为 yes 的新配置
allmodconfig尽可能选择所有模块的新配置
alldefconfig所有符号(选项)设置为默认值的新配置
randconfig所有选项随机选择的新配置
listnewconfig列出新选项
olddefconfigoldconfig 一样,但设置新符号(选项)为其默认值而无须提问
kvmconfig启用支持 KVM 访客内核模块的附加选项
xenconfig启用支持 xen 的 dom0 和 访客内核模块的附加选项
tinyconfig配置尽可能小的内核

我认为 menuconfig 是这些目标中最受欢迎的。这些目标由不同的 主程序 host program 处理,这些程序由内核提供并在内核构建期间构建。一些目标有 GUI(为了方便用户),而大多数没有。与 Kconfig 相关的工具和源代码主要位于内核源代码中的 scripts/kconfig/ 下。从 scripts/kconfig/Makefile 中可以看到,这里有几个主程序,包括 confmconfnconf。除了 conf 之外,每个都负责一个基于 GUI 的配置目标,因此,conf 处理大多数目标。

从逻辑上讲,Kconfig 的基础结构有两部分:一部分实现一种新语言来定义配置项(参见内核源代码下的 Kconfig 文件),另一部分解析 Kconfig 语言并处理配置操作。

大多数配置目标具有大致相同的内部过程(如下所示):

请注意,所有配置项都具有默认值。

第一步读取源代码根目录下的 Kconfig 文件,构建初始配置数据库;然后它根据如下优先级读取现有配置文件来更新初始数据库:

  1. .config
  2. /lib/modules/$(shell,uname -r)/.config
  3. /etc/kernel-config
  4. /boot/config-$(shell,uname -r)
  5. ARCH_DEFCONFIG
  6. arch/$(ARCH)/defconfig

如果你通过 menuconfig 进行基于 GUI 的配置或通过 oldconfig 进行基于命令行的配置,则根据你的自定义更新数据库。最后,该配置数据库被转储到 .config 文件中。

.config 文件不是内核构建的最终素材;这就是 syncconfig 目标存在的原因。syncconfig曾经是一个名为 silentoldconfig 的配置目标,但它没有做到其旧名称所说的工作,所以它被重命名。此外,因为它是供内部使用的(不适用于用户),所以它已从上述列表中删除。

以下是 syncconfig 的作用:

syncconfig.config 作为输入并输出许多其他文件,这些文件分为三类:

  • auto.conftristate.conf 用于 makefile 文本处理。例如,你可以在组件的 makefile 中看到这样的语句:obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
  • autoconf.h 用于 C 语言的源文件。
  • include/config/ 下空的头文件用于 kbuild 期间的配置依赖性跟踪。下面会解释。

配置完成后,我们将知道哪些文件和代码片段未编译。

kbuild

组件式构建,称为递归 make,是 GNU make 管理大型项目的常用方法。kbuild 是递归 make 的一个很好的例子。通过将源文件划分为不同的模块/组件,每个组件都由其自己的 makefile 管理。当你开始构建时,顶级 makefile 以正确的顺序调用每个组件的 makefile、构建组件,并将它们收集到最终的执行程序中。

kbuild 指向到不同类型的 makefile:

  • Makefile 位于源代码根目录的顶级 makefile。
  • .config 是内核配置文件。
  • arch/$(ARCH)/Makefile 是架构的 makefile,它用于补充顶级 makefile。
  • scripts/Makefile.* 描述所有的 kbuild makefile 的通用规则。
  • 最后,大约有 500 个 kbuild makefile。

顶级 makefile 会将架构 makefile 包含进去,读取 .config 文件,下到子目录,在 scripts/ Makefile.* 中定义的例程的帮助下,在每个组件的 makefile 上调用 make,构建每个中间对象,并将所有的中间对象链接为 vmlinux。内核文档 Documentation/kbuild/makefiles.txt 描述了这些 makefile 的方方面面。

作为一个例子,让我们看看如何在 x86-64 上生成 vmlinux

 title=

(此插图基于 Richard Y. Steven 的博客。有过更新,并在作者允许的情况下使用。)

进入 vmlinux 的所有 .o 文件首先进入它们自己的 built-in.a,它通过变量KBUILD_VMLINUX_INITKBUILD_VMLINUX_MAINKBUILD_VMLINUX_LIBS 表示,然后被收集到 vmlinux 文件中。

在下面这个简化的 makefile 代码的帮助下,了解如何在 Linux 内核中实现递归 make:

# In top Makefile
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps)
                +$(call if_changed,link-vmlinux)

# Variable assignments
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN) $(KBUILD_VMLINUX_LIBS)

export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y2) $(drivers-y) $(net-y) $(virt-y)
export KBUILD_VMLINUX_LIBS := $(libs-y1)
export KBUILD_LDS          := arch/$(SRCARCH)/kernel/vmlinux.lds

init-y          := init/
drivers-y       := drivers/ sound/ firmware/
net-y           := net/
libs-y          := lib/
core-y          := usr/
virt-y          := virt/

# Transform to corresponding built-in.a
init-y          := $(patsubst %/, %/built-in.a, $(init-y))
core-y          := $(patsubst %/, %/built-in.a, $(core-y))
drivers-y       := $(patsubst %/, %/built-in.a, $(drivers-y))
net-y           := $(patsubst %/, %/built-in.a, $(net-y))
libs-y1         := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2         := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))
virt-y          := $(patsubst %/, %/built-in.a, $(virt-y))

# Setup the dependency. vmlinux-deps are all intermediate objects, vmlinux-dirs
# are phony targets, so every time comes to this rule, the recipe of vmlinux-dirs
# will be executed. Refer "4.6 Phony Targets" of `info make`
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;

# Variable vmlinux-dirs is the directory part of each built-in.a
vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
                     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
                     $(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))

# The entry of recursive make
$(vmlinux-dirs):
                $(Q)$(MAKE) $(build)=$@ need-builtin=1

递归 make 的 配方 recipe 被扩展开是这样的:

make -f scripts/Makefile.build obj=init need-builtin=1

这意味着 make 将进入 scripts/Makefile.build 以继续构建每个 built-in.a。在scripts/link-vmlinux.sh 的帮助下,vmlinux 文件最终位于源根目录下。

vmlinux 与 bzImage 对比

许多 Linux 内核开发人员可能不清楚 vmlinuxbzImage 之间的关系。例如,这是他们在 x86-64 中的关系:

源代码根目录下的 vmlinux 被剥离、压缩后,放入 piggy.S,然后与其他对等对象链接到 arch/x86/boot/compressed/vmlinux。同时,在 arch/x86/boot 下生成一个名为 setup.bin 的文件。可能有一个可选的第三个文件,它带有重定位信息,具体取决于 CONFIG_X86_NEED_RELOCS 的配置。

由内核提供的称为 build 的宿主程序将这两个(或三个)部分构建到最终的 bzImage 文件中。

依赖跟踪

kbuild 跟踪三种依赖关系:

  1. 所有必备文件(*.c*.h
  2. 所有必备文件中使用的 CONFIG_ 选项
  3. 用于编译该目标的命令行依赖项

第一个很容易理解,但第二个和第三个呢? 内核开发人员经常会看到如下代码:

#ifdef CONFIG_SMP
__boot_cpu_id = cpu;
#endif

CONFIG_SMP 改变时,这段代码应该重新编译。编译源文件的命令行也很重要,因为不同的命令行可能会导致不同的目标文件。

.c 文件通过 #include 指令使用头文件时,你需要编写如下规则:

main.o: defs.h
        recipe...

管理大型项目时,需要大量的这些规则;把它们全部写下来会很乏味无聊。幸运的是,大多数现代 C 编译器都可以通过查看源文件中的 #include 行来为你编写这些规则。对于 GNU 编译器集合(GCC),只需添加一个命令行参数:-MD depfile

# In scripts/Makefile.lib
c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
                 -include $(srctree)/include/linux/compiler_types.h       \
                 $(__c_flags) $(modkern_cflags)                           \
                 $(basename_flags) $(modname_flags)

这将生成一个 .d 文件,内容如下:

init_task.o: init/init_task.c include/linux/kconfig.h \
    include/generated/autoconf.h include/linux/init_task.h \
    include/linux/rcupdate.h include/linux/types.h \
    ...

然后主程序 fixdep 通过将 depfile 文件和命令行作为输入来处理其他两个依赖项,然后以 makefile 格式输出一个 .<target>.cmd 文件,它记录命令行和目标的所有先决条件(包括配置)。 它看起来像这样:

# The command line used to compile the target
cmd_init/init_task.o := gcc -Wp,-MD,init/.init_task.o.d  -nostdinc ...
...
# The dependency files
deps_init/init_task.o := \
    $(wildcard include/config/posix/timers.h) \
    $(wildcard include/config/arch/task/struct/on/stack.h) \
    $(wildcard include/config/thread/info/in/task.h) \
    ...
    include/uapi/linux/types.h \
    arch/x86/include/uapi/asm/types.h \
    include/uapi/asm-generic/types.h \
    ...

在递归 make 中,.<target>.cmd 文件将被包含,以提供所有依赖关系信息并帮助决定是否重建目标。

这背后的秘密是 fixdep 将解析 depfile(.d 文件),然后解析里面的所有依赖文件,搜索所有 CONFIG_ 字符串的文本,将它们转换为相应的空的头文件,并将它们添加到目标的先决条件。每次配置更改时,相应的空的头文件也将更新,因此 kbuild 可以检测到该更改并重建依赖于它的目标。因为还记录了命令行,所以很容易比较最后和当前的编译参数。

展望未来

Kconfig/kbuild 在很长一段时间内没有什么变化,直到新的维护者 Masahiro Yamada 于 2017 年初加入,现在 kbuild 正在再次积极开发中。如果你不久后看到与本文中的内容不同的内容,请不要感到惊讶。


via: https://opensource.com/article/18/10/kbuild-and-kconfig

作者:Cao Jin 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

CKI 团队是如何防止 bug 被合并到 Linux 内核中。

Linux 内核的每个发布版本包含了来自 1,700 个开发者产生的 14,000 个变更集,很显然,这使得 Linux 内核快速迭代的同时也产生了巨大的复杂性问题。内核上 Bug 有小麻烦也有大问题,有时是系统崩溃,有时是数据丢失。

随着越来越多的项目对于持续集成(CI)的呼声,内核持续集成(CKI)小组秉承着一个任务目标:防止 Bug 被合并到内核当中。

Linux 测试问题

许多 Linux 发行版只在需要的时候对 Linux 内核进行测试。而这种测试往往只在版本发布时或者用户发现错误时进行。

有时候,出现玄学问题时,维护人员需要在包含了数万个补丁的变更中匆忙地寻找哪个补丁导致这个新的玄学 Bug。诊断 Bug 需要专业的硬件设备、一系列的触发器以及内核相关的专业知识。

CI 和 Linux

许多现代软件代码库都采用某种自动化 CI 测试机制,能够在提交进入代码存储库之前对其进行测试。这种自动化测试使得维护人员可以通过查看 CI 测试报告来发现软件质量问题以及大多数的错误。一些简单的项目,比如某个 Python 库,附带的大量工具使得整个检查过程更简单。

在任何测试之前都需要配置和编译 Linux。而这么做将耗费大量的时间和计算资源。此外,Linux 内核必需在虚拟机或者裸机上启动才能进行测试。而访问某些硬件架构需要额外的开销或者非常慢的仿真。因此,人们必须确定一组能够触发错误或者验证修复的测试集。

CKI 团队如何运作?

Red Hat 公司的 CKI 团队当前正追踪来自数个内部内核分支和上游的稳定内核分支树等内核分支的更改。我们关注每个代码库的两类关键事件:

  1. 当维护人员合并 PR 或者补丁时,代码库变化后的最终结果。
  2. 当开发人员通过拼凑或者稳定补丁队列发起变更合并时。

当这些事件发生时,自动化工具开始执行,GitLab CI 管道开始进行测试。一旦管道开始执行 linting) 脚本、合并每一个补丁,并为多种硬件架构编译内核,真正的测试便开始了。我们会在六分钟内完成四种硬件架构的内核编译工作,并且通常会在两个小时或更短的时间内将反馈提交到稳定邮件列表中。(自 2019 年 1 月起)每月执行超过 100,000 次内核测试,并完成了超过 11,000 个 GitLab 管道。

每个内核都会在本地硬件架构上启动,其中包含:

这些内核上运行了包括 Linux 测试项目(LTP)在内的多个测试,其中包括使用常用测试工具的大量测试。我们 CKI 团队开源了超过 44 个测试并将继续开源更多测试。

参与其中

上游的内核测试工作日渐增多。包括 Google、Intel、LinaroSony 在内的许多公司为各种内核提供了测试输出。每一项工作都专注于为上游内核以及每个公司的客户群带来价值。

如果你或者你的公司想要参与这一工作,请参加在 9 月份在葡萄牙里斯本举办的 Linux Plumbers Conference 2019。在会议结束后的两天加入我们的 Kernel CI hackfest 活动,并推动快速内核测试的发展。

更多详细信息,请见我在 Texas Linux Fest 2019 上的演讲。


via: https://opensource.com/article/19/6/continuous-kernel-integration-linux

作者:Major Hayden 选题:lujun9972 译者:LazyWolfLin 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Canonical 在 Ubuntu 14.04 LTS 系统中引入了 内核实时补丁服务 Kernel Livepatch Service 。实时补丁服务允许你安装和应用关键的 Linux 内核安全更新,而无需重新启动系统。这意味着,在应用内核补丁程序后,你无需重新启动系统。而通常情况下,我们需要在安装内核补丁后重启 Linux 服务器才能供系统使用。

实时修补非常快。大多数内核修复程序只需要几秒钟。Canonical 的实时补丁服务对于不超过 3 个系统的用户无需任何费用。你可以通过命令行在桌面和服务器中启用 Canonical 实时补丁服务。

这个实时补丁系统旨在解决高级和关键的 Linux 内核安全漏洞。

有关支持的系统和其他详细信息,请参阅下表。

Ubuntu 版本架构内核版本内核变体
Ubuntu 18.04 LTS64-bit x864.15仅 GA 通用和低电压内核
Ubuntu 16.04 LTS64-bit x864.4仅 GA 通用和低电压内核
Ubuntu 14.04 LTS64-bit x864.4仅 Hardware Enablement 内核

注意:Ubuntu 14.04 中的 Canonical 实时补丁服务 LTS 要求用户在 Trusty 中运行 Ubuntu v4.4 内核。如果你当前没有运行使用该服务,请重新启动到此内核。

为此,请按照以下步骤操作。

如何获取实时补丁令牌?

导航到 Canonical 实时补丁服务页面,如果要使用免费服务,请选择“Ubuntu 用户”。它适用于不超过 3 个系统的用户。如果你是 “UA 客户” 或多于 3 个系统,请选择 “Ubuntu customer”。最后,单击 “Get your Livepatch token” 按钮。

确保你已经在 “Ubuntu One” 中拥有帐号。否则,可以创建一个新的。

登录后,你将获得你的帐户密钥。

在系统中安装 Snap 守护程序

实时补丁系统通过快照包安装。因此,请确保在 Ubuntu 系统上安装了 snapd 守护程序。

$ sudo apt update
$ sudo apt install snapd

如何系统中安装和配置实时补丁服务?

通过运行以下命令安装 canonical-livepatch 守护程序。

$ sudo snap install canonical-livepatch
canonical-livepatch 9.4.1 from Canonical* installed

运行以下命令以在 Ubuntu 计算机上启用实时内核补丁程序。

$ sudo canonical-livepatch enable xxxxc4xxxx67xxxxbxxxxbxxxxfbxx4e

Successfully enabled device. Using machine-token: xxxxc4xxxx67xxxxbxxxxbxxxxfbxx4e

运行以下命令查看实时补丁机器的状态。

$ sudo canonical-livepatch status

client-version: 9.4.1
architecture: x86_64
cpu-model: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
last-check: 2019-07-24T12:30:04+05:30
boot-time: 2019-07-24T12:11:06+05:30
uptime: 19m11s
status:
- kernel: 4.15.0-55.60-generic
  running: true
  livepatch:
    checkState: checked
    patchState: nothing-to-apply
    version: ""
    fixes: ""

使用 --verbose 开关运行上述相同的命令,以获取有关实时修补机器的更多信息。

$ sudo canonical-livepatch status --verbose

如果要手动运行补丁程序,请执行以下命令。

$ sudo canonical-livepatch refresh

Before refresh:

kernel: 4.15.0-55.60-generic
fully-patched: true
version: ""

After refresh:

kernel: 4.15.0-55.60-generic
fully-patched: true
version: ""

patchState 会有以下状态之一:

  • applied:未发现任何漏洞
  • nothing-to-apply:成功找到并修补了漏洞
  • kernel-upgrade-required:实时补丁服务无法安装补丁来修复漏洞

请注意,安装内核补丁与在系统上升级/安装新内核不同。如果安装了新内核,则必须重新引导系统以激活新内核。


via: https://www.2daygeek.com/enable-canonical-kernel-livepatch-service-on-ubuntu-lts-system/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出