内核态和用户态
现代的计算机体系结构中存储管理通常都包含保护机制。提供保护的目的,是要避免系统中的一个任务访问属于另外的或属于操作系统的存储区域。如在 IntelX86体系中,就提供了特权级这种保护机制:
CPU 的指令分为特权级指令和非特权级指令, 特权级指令通常是一些比较危险的指令(for example?), Intel X86架构的 CPU 将特权等级分为4个级别:RING0
, RING1
, RING2
, RING3
.
Linux 仅仅使用了 RING0和 RING3,来分别运行内核态(0)和用户态(3),来保证特权级指令不被错误的使用。
- 内核态(Ring 0)的进程具有最高权限,可以直接访问所有资源(@doubt 调用内核代码、访问硬件寄存器… )
- 用户态(Ring 3)的进程只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用(System Call)陷入到内核中,才能访问这些特权资源。
- 通过系统调用,用户空间的应用程序就会进入内核空间,由内核代表该进程运行于内核空间,这就涉及到上下文的切换
- 在”32 位 Linux 进程内存布局”一章,有些资料会把内存地址高位的 1G 称为“内核空间”
- 关于 X 86 系统的细节,请查阅参考资料1 一般的硬件体系机构都提供一种“门”机制。“门”的含义是指在发生了特定事件的时候低特权的应用程序可以通过这些“门”进入高特权的内核空间。
![[../_images/2023-04-13.png]]
如何在 Linux 内核中增加自定义的系统调用? 参考 🔗《使用 Linux 系统调用的内核命令【转】-阿里云开发者社区》: https://developer.aliyun.com/article/383766
当加载了系统的 C 库调用索引和参数时,就会调用一个软件中断(0x80 中断),它将执行
system_call
函数(通过中断处理程序),这个函数会按照 eax 寄存器(eax 寄存器用来标识应当调用的某个系统调用)中的标识处理所有的系统调用。在经过几个简单测试之后,使用system_call_table
和 eax 中包含的索引来执行真正的系统调用了。从系统调用中返回后,最终执行syscall_exit
,并调用resume_userspace
返回用户空间。然后继续在C
库中执行,它将返回到用户应用程序中。
用户态到内核态的切换
用户空间和内核空间具有不同的地址映射,通用或专用的寄存器组,而用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行,所谓的进程上下文,就是一个进程在执行的时候,CPU 的所有寄存器中的值、进程的状态以及堆栈中的内容,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。
引起用户态到内核态切换的几种可能:
- 普通程序进行系统调用 时主动要求切换到内核态, 此时用户态进程要向内核态传递参数, 同时保存用户进程的寄存器、变量等, 以便切换回来时能正确继续执行, 这个过程就是进程 上下文切换 ;
- 异常事件:当 CPU 在执行运行在用户态下的程序时, 发生了某些事先不可知的异常, 这时会触发由当前运行进程切换到处理此异常的内核相关程序中, 也就转到了内核态, 比如缺页异常;
- 硬件中断:当外围设备完成用户请求的操作后, 会向 CPU 发出相应的中断信号, 这时 CPU 会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序, 如果先前执行的指令是用户态下的程序, 那么这个转换的过程自然也就发生了由用户态到内核态的切换;
上下文切换 vs 模式切换
➤ 何为”上下文切换”
「A context is the contents of a CPU’s registers and program counter at any point in time」:上下文 是 CPU 寄存器和程序计数器在任何时间点的内容。
「Context switching can be described in slightly more detail as the kernel (i.e., the core of the operating system) performing the following activities with regard to processes (including threads) on the CPU: (1) suspending the progression of one process and storing the CPU’s state (i.e., the context) for that process somewhere in memory, (2) retrieving the context of the next process from memory and restoring it in the CPU’s registers and (3) returning to the location indicated by the program counter (i.e., returning to the line of code at which the process was interrupted) in order to resume the process」:
上下文切换 可以更详细地描述为操作系统的内核对 CPU 上的进程(包括线程)执行以下活动:
(1) 暂停一个进程的进程并将该进程的 CPU 状态(即上下文)存储在内存中的某个位置,
(2) 从内存中检索下一个进程的上下文并将其恢复到 CPU 的寄存器中,
(3) 返回到程序计数器指示的位置(即返回到进程中断的代码行),以便恢复进程。
「Context Switches and Mode Switches:system call causes the CPU to shift to kernel mode. This is referred to as a mode switch rather than a context switch, because it does not change the current process.」
区分“上下文切换” 和 “模式切换”:
- 系统调用过程通常称为模式切换,而不是上下文切换,系统调用过程中一直是同一个进程在运行;
- 上下文切换一般指多任务切换(多进程和多线程)时,对于进程和线程的上下文切换代价;
🔗《Context Switch definition》: http://www.linfo.org/context_switch.html
回顾:CPU 寄存器知识
- 通用寄存器:寄存器是 CPU 内部的少量非常快的内存(与 CPU 外部较慢的 RAM 主内存相反),用于通过提供对常用值(通常是计算过程中的值)的快速访问来加速计算机程序的执行;
- 程序计数器(Program Counter):是一个专用寄存器,用于指示 CPU 在其指令序列中的位置,并保存正在执行的指令的地址或要执行的下一条指令的地址;
![[../_images/2023-04-13-1.png]]