Linux 内核的 2.6 和 4.0 版本之间的差异非常广泛,因为这两个版本之间有很多的迭代和改进。下面是一些比较明显的区别:
-
发布时间:
- 2.6:2003 年发布。
- 4.0:2015 年发布。
-
性能和可扩展性:
- 4.0 版本在性能和可扩展性上都进行了大量优化,更好地支持了多处理器、多核心、NUMA 等现代硬件特性。
-
Live Patching:
- 在 4.0 中,内核引入了一种叫做 Live Patching 的新功能,它允许用户在不重启系统的情况下应用安全补丁。
-
文件系统:
- 2.6 中,Ext3 是主要的文件系统,但随后 Ext4 在后续版本中成为了默认文件系统。4.0 中对 Ext4 进行了进一步的优化。
- Btrfs 文件系统在 2.6 中刚开始出现,但在 4.0 版本中得到了进一步的完善和优化。
-
内存管理:
- 4.0 对 Transparent Huge Pages (THP) 进行了改进,对 NUMA 系统进行了优化。
-
设备驱动:
- 4.0 包括了更多的设备驱动,特别是对于新硬件的支持。
-
网络:
- 4.0 对多种网络协议和功能进行了优化,如 TCP、IPv6 等。
-
容器技术:
- 虽然容器技术在 2.6 中已经有了,但是到了 4.0,这项技术得到了进一步的发展和完善,尤其是与 Docker 和其他容器工具的集成。
-
安全:
- 4.0 增加了更多的安全功能,如 seccomp、namespace 的改进等。
-
系统调用和APIs:
- 4.0 版本引入了新的系统调用和APIs,同时废弃了一些旧的。
以上只是这两个版本之间的部分差异。实际上,这两个版本之间还有很多细节上的变化和改进。总之,从 2.6 到 4.0,Linux 内核经历了巨大的发展,不仅在性能和稳定性上有所提高,还引入了许多新的功能和技术。
在驱动开发上的不同
ChatGPT
在驱动开发上,Linux 内核 2.6 与 4.0 之间的变化也非常显著。这其中涉及到的核心概念、框架、APIs 和策略都有所更新和优化。以下列出了一些主要的差异:
-
Device Tree (设备树):
- 尤其针对 ARM 架构,Device Tree 成为了描述硬件的标准方式,减少了针对特定硬件平台的硬编码。
-
更好的硬件支持:
- 随着时间的推移,新的硬件和技术不断涌现。4.0 内核增加了对许多新硬件的支持,这也意味着驱动开发人员需要适应这些新硬件。
-
Generic PHY Framework (通用PHY框架):
- 这是一个新的框架,用于处理各种物理层接口。
-
Pin Control (pinctrl) 子系统:
- 在 4.0 中,pinctrl 子系统提供了一个统一的方式来管理和配置 SoC 的引脚。
-
驱动模型的改进:
- 2.6 开始引入了一个新的驱动模型,但到了 4.0,这个模型已经更加稳定和完善。
-
Platform Drivers 和 Device Drivers 的区分:
- 在 2.6 和 4.0 之间,对于平台驱动和设备驱动的处理方式也有所改进和区分。
-
新的内核APIs:
- 随着内核的发展,一些老的APIs被废弃,而新的APIs被引入。这意味着驱动开发人员需要不断更新和维护他们的代码。
-
更好的电源管理:
- 4.0 版本对于电源管理提供了更多的功能和策略,如 Runtime PM、系统休眠/唤醒等。
-
Bus Types (总线类型):
- 新的总线类型如 Greybus 被引入,而老的总线可能不再受到强烈的支持或优化。
-
更强的错误处理和调试支持:
- 4.0 版本提供了更多的工具和机制来帮助驱动开发者诊断问题,如 Tracepoints、ftrace、perf 等。
总的来说,从 2.6 到 4.0,Linux 的驱动开发面临了许多新的挑战和机会。这些变化反映了硬件、软件和行业标准的不断进化,也使得驱动开发更为复杂。但同时,这也为驱动开发人员提供了更多的资源、工具和框架,使得开发过程更加高效和稳定。
查看内核版本
ChatGPT
要在Linux系统中查看内核版本,您可以使用命令行工具。以下是几种常用的方法:
-
使用
uname
命令:bashCopy code
uname -r
这将显示当前运行的内核版本。
-
查看
/proc/version
文件:bashCopy code
cat /proc/version
这将显示更详细的内核版本信息,包括编译日期、GCC版本等。
-
使用
dmesg
命令: 如果你想看到系统启动时的内核版本信息,你可以使用dmesg
命令,然后从输出的开始部分查找:bashCopy code
dmesg | grep "Linux version"
这些命令应该可以帮助你确定Linux系统上的内核版本。
ubantu 的module.h
ChatGPT
在 Ubuntu 和其他 Linux 发行版中,module.h
是内核头文件,主要用于模块编程。这个文件定义了一些用于内核模块操作的基本结构、宏和函数。
如果您在 Ubuntu 上进行内核模块开发,您可能需要这个头文件。通常,这个文件位于 /usr/src/linux-headers-$(uname -r)/include/linux/
目录中,但前提是您已经安装了相应的内核头文件包。
要在 Ubuntu 上安装内核头文件,您可以使用以下命令:
bashCopy code
sudo apt update sudo apt install linux-headers-$(uname -r)
安装完成后,您可以找到 module.h
和其他内核头文件。如果您对内核模块编程或这个文件的内容有更深入的问题,请随时提问。
linux-headers-3.13.0-32
ChatGPT
linux-headers-3.13.0-32
是 Ubuntu 14.04 LTS (Trusty Tahr) 中的一个特定版本的内核头文件包。这些头文件主要用于那些需要与特定内核版本相对应的编译模块的场景。
如果您想在 Ubuntu 14.04 上安装这个特定版本的内核头文件,您可以使用以下命令:
bashCopy code
sudo apt update sudo apt install linux-headers-3.13.0-32-generic
请注意,如果您使用的是一个不同的Ubuntu版本或其他Linux发行版,这个包可能不可用,或者包名可能有所不同。
另外,由于 Ubuntu 14.04 已经达到了其生命周期的结束,所以默认的存档源可能不再提供这个包。如果您在安装时遇到问题,您可能需要从 Ubuntu 的旧版本存档中获取它,或者考虑升级到一个新的Ubuntu版本。
在 Ubuntu 14.04编写一个模块
ChatGPT
编写一个基础的 Linux 内核模块并在 Ubuntu 14.04 上加载它涉及以下步骤:
- 准备开发环境: 首先,确保您安装了必要的内核头文件和工具:
bashCopy code
sudo apt update sudo apt install linux-headers-$(uname -r) build-essential
- 编写模块代码: 创建一个新的文件,例如
hello_module.c
,并添加以下内容:
cCopy code
#include <linux/module.h> // 必要的头文件 #include <linux/kernel.h> // KERN_INFO #include <linux/init.h> // init、exit 宏 MODULE_LICENSE("GPL"); // 模块许可证 MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple Hello World module"); static int __init hello_init(void) { printk(KERN_INFO "Hello, world!\n"); return 0; // 加载成功返回0 } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, world!\n"); } module_init(hello_init); // 指定加载函数 module_exit(hello_exit); // 指定卸载函数
- 编写 Makefile: 为了编译模块,您需要一个
Makefile
。创建一个新文件名为Makefile
,并添加以下内容:
makeCopy code
obj-m += hello_module.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
- 编译模块: 在终端中,导航到您的源代码目录并运行
make
:
bashCopy code
make
成功后,您应该在当前目录中看到一个名为 hello_module.ko
的文件。
- 加载和卸载模块: 使用以下命令将模块加载到内核中:
bashCopy code
sudo insmod hello_module.ko
检查 dmesg
输出,您应该看到 "Hello, world!" 消息。
使用以下命令从内核中卸载模块:
bashCopy code
sudo rmmod hello_module
再次检查 dmesg
,您应该看到 "Goodbye, world!" 消息。
以上就是在 Ubuntu 14.04 上编写、编译和加载一个简单的 Linux 内核模块的基本步骤。这只是一个起始点,内核模块编程有很多其他的概念和功能可以探索。
obj-m :=和obj-m += 不同
ChatGPT
在 Linux 内核模块编程的 Makefile 中,obj-m
是一个特殊的变量,用于定义要编译为模块的对象文件。obj-y
是定义要直接链接到内核的对象文件。同样地,还有 obj-n
和 obj-
,分别用于表示不编译和条件编译的对象。
现在,来看 :=
和 +=
的区别:
-
obj-m :=
当你使用
:=
时,你实际上是在为obj-m
赋一个新值。这意味着之前对obj-m
的任何赋值都将被覆盖。简而言之,它设置了一个新值。例如:
makefileCopy code
obj-m := module1.o obj-m := module2.o
在这个例子中,最终只有
module2.o
会被编译为一个模块,因为它覆盖了先前的赋值。 -
obj-m +=
当你使用
+=
时,你是在向obj-m
追加值。这意味着先前对obj-m
的赋值不会被覆盖,新值会被添加到列表的末尾。例如:
makefileCopy code
obj-m += module1.o obj-m += module2.o
在这个例子中,
module1.o
和module2.o
都将被编译为模块。
总结,:=
用于设置新值,而 +=
用于追加值。在大多数内核模块的 Makefile 中,你会看到使用 +=
,因为它允许你在多个地方逐步构建模块列表,而不是每次都重新设置它。
ifneq ($(KERNELRELEASE),) 何解
ChatGPT
在内核模块的 Makefile 中,经常可以看到如下结构:
makefileCopy code
ifneq ($(KERNELRELEASE),) # 内核构建系统的规则部分 else # 外部模块构建的规则部分 endif
这个结构是为了处理两种不同的编译场景。让我们详细解释一下:
-
ifneq ($(KERNELRELEASE),)
检查KERNELRELEASE
变量是否已经设置。KERNELRELEASE
是内核构建系统在构建过程中设置的一个变量,它包含正在构建的内核版本。 -
内核构建系统的规则部分:
如果
KERNELRELEASE
已经被设置,这意味着我们当前处于内核构建系统的上下文中。这部分的规则是针对整个内核或内核模块构建的。 -
外部模块构建的规则部分:
如果
KERNELRELEASE
没有被设置,我们不在内核构建系统的上下文中。这部分通常包含命令,例如调用内核构建系统来构建一个外部模块,例如:makefileCopy code
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
这种方法的好处是,它允许同一个 Makefile 在两个不同的上下文中工作:一次是作为一个外部模块的构建脚本,一次是作为内核构建系统的一部分。这简化了模块的构建流程,因为不需要为两种情况维护两个不同的 Makefile。
如何查看$(KERNELRELEASE)
ChatGPT
$(KERNELRELEASE)
是在 Linux 内核构建过程中设置的一个变量,它包含了正在构建的内核的版本。它并不是一个常规的环境变量,所以你不能在常规的 shell 会话中直接查看它,例如使用 echo $KERNELRELEASE
。这是一个为 Makefile 设定的变量。
但如果你想在构建内核模块时查看其值,你可以在 Makefile 中添加一个简单的规则来打印它。例如:
makefileCopy code
print-kernelrelease: @echo $(KERNELRELEASE)
然后,在你的 Makefile 所在的目录中运行:
bashCopy code
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) print-kernelrelease
这将使用当前运行的内核版本构建目标,并打印 $(KERNELRELEASE)
的值。
另外,如果你只是想知道你的系统上当前正在运行的内核版本,你可以简单地使用 uname -r
命令。
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
ChatGPT
这个命令是用来编译 Linux 内核模块的。让我们逐步解释这个命令的每一部分:
-
make
: 这是 GNU Make 工具,用于处理Makefile
并执行相关命令。 -
-C /lib/modules/$(shell uname -r)/build
:-C
选项告诉make
更改到指定的目录并在那里查找Makefile
。/lib/modules/$(shell uname -r)/build
是当前系统正在运行的内核版本的内核头文件和构建文件的位置。其中,
$(shell uname -r)
是一个 shell 命令,它返回当前运行的内核版本。 -
M=$(PWD)
: 这告诉内核构建系统你的外部模块的源代码位于哪里。$(PWD)
是一个环境变量,代表当前目录。 -
modules
: 这是你想要执行的目标。对于内核构建系统,modules
目标意味着它将尝试编译指定目录(由M
变量指定)中的所有内核模块。
综上所述,这个命令的作用是:在当前目录中查找源代码,然后在内核构建系统的上下文中编译这些源代码为内核模块。成功编译后,它会产生一个 .ko
文件(例如,mymodule.ko
),这是一个可加载的内核模块。你可以使用 insmod
和 rmmod
命令来加载和卸载这个模块。
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
ChatGPT
这个命令用于清理之前在 Linux 内核模块编译过程中产生的中间文件和输出。
让我们解析一下这个命令的各个部分:
-
make
: 这是 GNU Make 工具,用于处理Makefile
并执行相关命令。 -
-C /lib/modules/$(shell uname -r)/build
:-C
选项告诉make
更改到指定的目录并在那里查找Makefile
。/lib/modules/$(shell uname -r)/build
是当前系统正在运行的内核版本的内核头文件和构建文件的位置。$(shell uname -r)
是一个 shell 命令,它返回当前运行的内核版本。 -
M=$(PWD)
: 这告诉内核构建系统你的外部模块的源代码位于哪里。$(PWD)
是一个环境变量,代表当前目录。 -
clean
: 这是你想要执行的目标。对于内核构建系统,clean
目标表示它应该清理指定目录(由M
变量指定)中的所有构建产物,例如.o
(对象文件)、.ko
(内核模块)、以及其他的临时文件。
简而言之,该命令用于清理当前目录中的所有与内核模块编译相关的临时文件和输出,使得目录回到一个“干净”的状态。这通常在重新编译模块之前或者当你不再需要这些编译产物时执行。
/lib/modules/$(shell uname -r)/build
ChatGPT
/lib/modules/$(shell uname -r)/build
是一个指向 Linux 内核源代码树的符号链接,其中 $(shell uname -r)
返回当前系统正在运行的内核版本。
具体解释一下:
-
/lib/modules/
: 这是所有安装的 Linux 内核模块的基本存储位置。每个内核版本都有其自己的子目录。 -
$(shell uname -r)
: 这是一个命令,它在 shell 中运行uname -r
并返回结果。uname -r
返回当前运行的内核版本,例如 "5.4.0-26-generic"。 -
/build
: 对于每个内核版本的子目录,build
是一个符号链接,它指向用于构建该特定版本的内核的源代码树。
因此,/lib/modules/$(shell uname -r)/build
指向的是你当前运行的 Linux 内核版本的源代码目录。当你想要编译内核模块时,这个路径经常被用作参考路径,因为它包含了内核构建系统和内核配置文件,这些都是编译内核模块所必需的。
不过,要注意的是,如果你只是安装了内核,但没有安装相关的内核头文件包,那么这个 /build
链接可能不存在或不可用。在 Ubuntu 和其他基于 Debian 的系统上,可以使用以下命令来安装当前运行的内核的头文件:
bashCopy code
sudo apt update sudo apt install linux-headers-$(uname -r)
安装这些头文件后,/build
链接应该会指向正确的位置。
/lib/modules/$(shell uname -r)/build 可以找到 module.h
ChatGPT
/lib/modules/$(shell uname -r)/build
是当前运行的内核版本的源代码和头文件的路径。其中,module.h
是定义内核模块操作的关键头文件。
要在这个路径下找到 module.h
,你可能需要查看 include/linux/
子目录。具体地说,你可以在以下路径找到它:
bashCopy code
/lib/modules/$(shell uname -r)/build/include/linux/module.h
这个文件包含了内核模块开发所需的基本宏和函数定义,例如 module_init()
, module_exit()
, MODULE_LICENSE()
, 等等。
如果你在该路径下没有找到 module.h
或者 /build
链接似乎不存在或不正确,那么可能是因为你没有为当前运行的内核版本安装内核头文件。在基于 Debian 的系统(如 Ubuntu)上,你可以使用以下命令来安装它们:
bashCopy code
sudo apt update sudo apt install linux-headers-$(uname -r)
安装完成后,你应该能在上述路径中找到 module.h
文件。