跳转至

User Kernel Mode

内核态

内核态是计算机系统中的一种特权模式,用于执行操作系统内核的代码和功能。与用户态相比,内核态具有更高的权限和更广泛的访问能力,可以执行一些用户态无法执行的关键任务和操作。下面是从用户态的角度上介绍内核态的功能:

  1. 系统调用(System Calls):内核态允许用户程序通过系统调用接口请求操作系统提供的服务和功能。用户程序可以通过系统调用请求文件操作、网络通信、内存管理等操作。当用户程序执行系统调用时,会触发从用户态切换到内核态的转换,以便内核在高权限下执行相应的操作。
  2. 资源管理:内核态负责管理计算机系统的各种资源,包括处理器、内存、磁盘、网络等。在内核态下,操作系统可以对这些资源进行分配、调度和释放,确保资源的有效利用和合理分配。
  3. 中断处理:当发生硬件中断或异常时,内核态负责处理中断并提供相应的服务。例如,当用户程序需要与设备进行交互时,内核可以响应设备的中断信号,进行数据传输、状态检查等操作。
  4. 进程管理:内核态负责创建、销毁和管理进程。它可以调度进程,分配和回收进程所需的资源,并在必要时进行进程间的通信和同步。
  5. 内存管理:内核态控制着计算机系统的内存分配和管理。它负责将物理内存分配给进程,并维护虚拟内存和物理内存之间的映射关系。内核还处理内存保护、页面置换、内存回收等任务。
  6. 设备驱动程序:内核态包含设备驱动程序,用于与硬件设备进行交互。它允许操作系统通过设备驱动程序来控制和管理硬件设备,如磁盘驱动程序、网络驱动程序等。
  7. 安全和权限管理:内核态能够执行与系统安全和权限相关的任务。它可以控制对系统资源的访问权限,并确保用户程序不能越权访问或修改关键数据和系统配置。

总的来说,内核态提供了操作系统核心功能的执行环境,拥有更高的权限和更广泛的访问能力,使得操作系统能够管理和控制计算机系统的各个方面,同时为用户程序提供必要的服务和保护。

代码位置

在Linux系统中,每个进程的虚拟地址空间中的高位部分通常被映射为内核空间,其中包含了内核态的代码和数据。这个区域通常被称为内核空间或内核页表。内核空间中的内容包括以下两类:

  1. 内核代码:内核代码是操作系统内核的实现,包括各种系统调用、设备驱动程序和核心功能的代码。这些代码用于提供操作系统的各种服务和功能,如文件系统操作、进程管理、内存管理、网络通信等。内核代码是所有进程共享的,因为它们代表了操作系统的核心部分,为所有进程提供服务。
  2. 共享内核数据结构:内核空间中还包含一些共享的内核数据结构,用于维护系统状态和资源管理。例如,进程调度器、内存管理数据结构、文件描述符表等。这些数据结构被多个进程共享,以便内核能够管理和控制系统资源的分配和使用。

除了以上共享的内容,内核空间还包含一些每个进程独有的部分,例如:

  1. 进程描述符(Process Descriptor):每个进程都有一个唯一的进程描述符,其中包含了进程的状态信息、上下文和其他与进程相关的数据。进程描述符存储在内核空间,每个进程都有自己独立的进程描述符。
  2. 用户栈和内核栈:每个进程都有自己的用户栈和内核栈。用户栈用于保存进程在用户态执行时的局部变量和函数调用信息,而内核栈用于保存进程在内核态执行时的上下文信息和函数调用。(内核函数也要嵌套调用)

总结起来,Linux进程的高位部分映射了内核空间,其中包含了内核代码、共享的内核数据结构以及每个进程独有的部分,如进程描述符和栈空间。这种映射允许进程与内核进行交互和访问操作系统的功能和服务。

如何共享

在内核中,代码共享并不是通过动态链接库(.so)的模式来实现的。内核态的代码通常被编译成内核模块或者直接编译进内核映像中,而不是作为独立的可加载库。因此,内核中的代码共享机制与用户空间中的动态链接库不同。

在内核中,代码共享是通过代码复用和内核模块的概念来实现的。内核模块是一种可以动态加载和卸载的代码和数据集合,它可以扩展内核的功能。内核模块可以包含新的设备驱动程序、文件系统、网络协议等,以便在需要时被加载到内核中运行。

内核模块的加载过程可以在运行时根据需要进行,而不需要重新编译整个内核。这样,多个进程可以共享同一个内核模块,从而实现内核代码的共享。当多个进程需要使用某个内核模块时,模块只需要加载一次,然后被多个进程共享调用。

值得注意的是,内核中的代码共享是在内核空间内部进行的,与用户空间的动态链接库不同,它不涉及用户进程的地址空间和加载机制。内核模块的共享是在内核内部完成的,不同进程间可以通过系统调用接口访问共享的内核模块提供的功能和服务。

总结起来,内核中的代码共享是通过内核模块的加载和运行机制来实现的,而不是像用户空间中的动态链接库那样。内核模块可以被多个进程共享调用,从而提供共享的内核功能和服务。

内核态与用户态切换

切换时机

内核态与用户态的切换通常由以下几种情况触发:

  • 系统调用(System Call):当用户程序通过系统调用请求操作系统提供的服务时,会触发从用户态到内核态的切换。这是最常见的切换方式。
  • 异常(Exception)和中断(Interrupt):当发生硬件中断、软件中断(如除零错误)、内存访问错误等异常情况时,CPU会切换到内核态来处理异常。这些异常可以是由程序错误、设备请求或其他条件引起的。
  • 外部事件:例如时钟中断、I/O 完成中断等,这些事件可能需要内核处理,因此会导致从用户态切换到内核态。

切换的细节

当进程从用户态切换到内核态,或者从内核态切换回用户态时,涉及到特权级的切换和上下文的保存与恢复。下面是内核态与用户态切换的一般细节:

  1. 特权级切换:内核态拥有更高的特权级别,因此从用户态切换到内核态时,CPU会从当前运行的用户模式切换到内核模式。这种切换会改变CPU的状态,包括特权级、堆栈和指令指针。

  2. 上下文保存与恢复:在切换到内核态之前,CPU会保存当前用户态下的进程上下文信息,包括程序计数器(PC)、寄存器的值、堆栈指针等。这些上下文信息保存在进程的内核栈中。

  3. 内核态执行:当切换到内核态后,CPU开始执行相应的内核代码,处理请求或异常。在内核态下,操作系统可以访问和操作系统的所有资源和功能,执行必要的操作。

  4. 上下文恢复与切换回用户态:当内核态的任务完成后,CPU会从内核栈中恢复之前保存的进程上下文信息。然后,CPU会将特权级切换回用户态,并从保存的程序计数器继续执行用户程序。

需要注意的是,内核态与用户态的切换涉及到CPU和操作系统的底层机制,具体细节可能会因操作系统的设计和架构而有所不同。上述描述是一般情况下的概述,不同的操作系统和处理器架构可能会有特定的实现细节。

开销来源

  1. 特权级切换
  2. 上下文保存与恢复
  3. 由于PTI的存在,内核维护了两套页表。切换到内核态时,可能需要切换内存地址空间的映射关系,例如将用户态的虚拟地址空间映射为内核态的地址空间。这可能涉及页表的切换和TLB(Translation Lookaside Buffer)的刷新,会带来一定的延迟和开销。

量化

内核态与用户态的切换时间在数百到数千个CPU周期之间

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。