[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 |
|
这行命令可以展示ls
命令执行期间所有的系统调用细节,有助于深入了解程序的运行机制和排查问题。
4 Kernel Installation
可以在系统上安装多个内核,并且在启动过程中通过GRUB菜单选择要启动的内核。
查看当前系统内核版本
要查看系统上已安装的内核版本,使用以下命令:
1 |
|
该命令将输出类似3.19.0-43-generic
的信息。uname
命令用于打印系统信息,参数-r
用于显示内核发布版本。
安装Linux内核
安装Linux内核有多种方式,包括从源代码下载并编译,或使用包管理工具进行安装。
例如,可以使用以下命令通过包管理工具安装特定版本的内核:
1 |
|
安装完成后,重启系统即可进入新安装的内核。需要注意的是,通常还需要安装其他相关软件包,如linux-headers
、linux-image-generic
等。此外,还可以指定确切的版本号,如:
1 |
|
如果仅需更新到最新内核版本,可以使用dist-upgrade
命令来升级系统上的所有软件包:
1 |
|
选择合适的内核版本
存在众多不同的内核版本,有些提供长期支持(LTS,long term support),而另一些则是最新的稳定版。不同内核版本之间的兼容性可能存在显著差异。
5 内核位置
当安装一个新的内核时,实际上会在系统中添加几个文件,这些文件通常被放置在/boot
目录下。
内核相关文件
在/boot
目录下,针对不同的内核版本,会看到以下几种类型的文件:
vmlinuz:这是实际的Linux内核映像。每个版本的内核都有一个对应的
vmlinuz
文件。initrd:
initrd
是一个临时文件系统,在加载内核之前使用,为内核提供必要的驱动程序和资源以访问存储设备等关键服务。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 |
|
如果您有一个名为peanut_butter
的模块,并希望通过设置参数type=almond
来调整其行为,则可通过上述配置文件使其在启动时加载。
阻止模块在启动时加载
同样地,也可以通过在/etc/modprobe.d
目录下创建配置文件来阻止特定模块在系统启动时加载,例如:
1 |
|
这样可以确保指定的模块不会在系统启动时自动加载。。