[Linux]Kernel

Kernel

1 内核概述

Linux操作系统可以分为三个抽象层次。

硬件层

最基础的层次是硬件,包括CPU、内存、硬盘、网络端口等。这是实际执行计算任务的物理层。

内核层

下一个层次是内核,负责进程与内存管理、设备通信、系统调用、文件系统设置等工作。内核的任务是与硬件交互,确保硬件按照我们的需求运行各个进程。

用户空间

包含了Shell、运行的各种程序以及图形界面等。

2 特权级别

为何区分用户空间与内核?

为什么用户空间和内核要分为不同的抽象层?为何不能将两者合并为一个层次?这两个层次分开存在有其充分的理由:它们在不同的模式下运行。内核工作于内核模式,而用户空间则工作于用户模式。

在内核模式下,内核对硬件拥有完全访问权限,并控制所有操作。而在用户模式下,仅允许访问一小部分安全内存和CPU资源。简而言之,当需要执行涉及硬件的操作,如从磁盘读取数据、向磁盘写入数据或控制网络等,都需在内核模式下完成。这样做是必要的,以防止恶意软件直接访问系统硬件,避免可能的数据泄露或其他安全隐患。

特权级别与保护环

这些不同的模式被称为特权级别,通常被描述为保护环。最内层的环对应最高特权级别。在x86架构计算机中,主要有两种模式或级别:Ring #3为用户模式应用程序的特权级别,Ring #0为内核的特权级别。Ring #0能够执行任何系统指令,并获得完全信任。

系统调用的作用

系统调用使得我们能够在内核模式下执行特权指令,然后切换回用户模式。这种方式既保证了系统的安全性,又提供了必要的灵活性,使得用户程序能够在必要时通过内核与硬件进行交互。

3 系统调用

系统调用的作用

系统调用(syscall)为用户空间进程提供了一种请求内核为我们执行特定操作的方法。内核通过系统调用API提供某些服务,这些服务包括读写文件、调整内存使用量、修改网络配置等。系统调用的数量是固定的,因此不能随意添加新的系统调用;系统中已有一张包含所有可用系统调用的表格,每个系统调用都有一个唯一的ID。

当运行如ls这样的程序时,该程序内部包含了系统调用wrapper,并非直接进行系统调用。此wrapper会触发系统调用,进而执行一个陷阱(trap),这个陷阱会被系统调用处理器捕获,然后根据系统调用ID在系统调用表中查找相应的系统调用。例如,当我们尝试调用stat()系统调用时,它通过系统调用ID识别,目的是查询文件状态。当尝试进行系统调用时,系统会切换到内核模式,完成一系列操作,其中最重要的是根据系统调用ID查找对应的系统调用并执行所需功能。完成后,系统返回至用户模式,进程将收到成功或错误的状态信息。

使用strace命令查看系统调用

可以使用strace命令来查看进程所做的系统调用。strace命令对于调试程序执行非常有用。

1
$ strace ls

这行命令可以展示ls命令执行期间所有的系统调用细节,有助于深入了解程序的运行机制和排查问题。

4 Kernel Installation

可以在系统上安装多个内核,并且在启动过程中通过GRUB菜单选择要启动的内核。

查看当前系统内核版本

要查看系统上已安装的内核版本,使用以下命令:

1
$ uname -r

该命令将输出类似3.19.0-43-generic的信息。uname命令用于打印系统信息,参数-r用于显示内核发布版本。

安装Linux内核

安装Linux内核有多种方式,包括从源代码下载并编译,或使用包管理工具进行安装。

例如,可以使用以下命令通过包管理工具安装特定版本的内核:

1
$ sudo apt install linux-generic-lts-vivid

安装完成后,重启系统即可进入新安装的内核。需要注意的是,通常还需要安装其他相关软件包,如linux-headerslinux-image-generic等。此外,还可以指定确切的版本号,如:

1
$ sudo apt install 3.19.0-43-generic

如果仅需更新到最新内核版本,可以使用dist-upgrade命令来升级系统上的所有软件包:

1
$ sudo apt dist-upgrade

选择合适的内核版本

存在众多不同的内核版本,有些提供长期支持(LTS,long term support),而另一些则是最新的稳定版。不同内核版本之间的兼容性可能存在显著差异。

5 内核位置

当安装一个新的内核时,实际上会在系统中添加几个文件,这些文件通常被放置在/boot目录下。

内核相关文件

/boot目录下,针对不同的内核版本,会看到以下几种类型的文件:

  • vmlinuz:这是实际的Linux内核映像。每个版本的内核都有一个对应的vmlinuz文件。

  • initrdinitrd是一个临时文件系统,在加载内核之前使用,为内核提供必要的驱动程序和资源以访问存储设备等关键服务。

  • System.map:这是一个符号查找表,用于将内核符号(如函数名)映射到它们在内存中的地址。

  • config:内核配置设置文件。如果自己编译内核,可以通过该文件设定可以加载哪些模块。

管理/boot空间

如果/boot目录空间不足,可以删除旧版本的上述文件来释放空间。不过,在执行此类维护操作时需格外小心,确保不会误删当前正在使用的内核。此外,也可以使用包管理器进行清理工作,但同样需要注意避免误操作。

6 内核模块

内核模块概述

尽管内核本身是一个庞大的软件,但当需要为其添加新功能(例如支持一种新型键盘)时,并不会直接将代码写入内核核心中。内核模块是可以在需要时加载到内核中的代码片段,它们扩展了内核的功能而不增加核心代码量。多数情况下,添加模块无需重启系统。

查看和管理已加载的模块

  • 查看当前已加载的模块

    1
    $ lsmod
  • 加载一个模块

    1
    $ sudo modprobe bluetooth

    modprobe命令尝试从/lib/modules/(内核版本)/kernel/drivers加载模块。如果模块有依赖关系,modprobe会自动加载所需的依赖项。

  • 卸载一个模块

    1
    $ sudo modprobe -r bluetooth

系统启动时加载模块

若希望在系统启动时加载模块,而非临时使用modprobe加载(重启后卸载),可以通过在/etc/modprobe.d目录下添加新的配置文件实现。例如,创建一个名为peanutbutter.conf的配置文件:

1
options peanut_butter type=almond

如果您有一个名为peanut_butter的模块,并希望通过设置参数type=almond来调整其行为,则可通过上述配置文件使其在启动时加载。

阻止模块在启动时加载

同样地,也可以通过在/etc/modprobe.d目录下创建配置文件来阻止特定模块在系统启动时加载,例如:

1
blacklist peanut_butter

这样可以确保指定的模块不会在系统启动时自动加载。。


[Linux]Kernel
https://erlsrnby04.github.io/2025/03/22/Linux-Kernel/
作者
ErlsrnBy04
发布于
2025年3月22日
许可协议