CPU的工作状态
CPU的两个工作状态,也就是处理器的两种执行状态。
在一个系统中既有操作系统的程序,也由普通用户的程序。众多的指令中,有些指令只能由系统来使用,禁止用户程序去直接访问。为了保证操作系统和各个应用程序能够顺利运行,就必须对它们进行限制,否则的话就无法保证系统的安全性和稳定性。所以根据运行程序对资源和机器指令的使用权限,把处理器设置为不同的状态,多数系统把处理器的工作状态分为管态和目态两种。
1、系统态(又叫管态、内核态、核心态、特权态)
系统态是操作系统的管理程序运行时的状态,它具有较高的特权级别。当处理器处于管态时,它可以执行所有的指令,包括各种特权指令,也可以使用所有的资源,并且具有改变处理器状态的能力,是感觉很牛逼。需要指出的是,管态和超级用户不同,前者是指CPU的状态,后者是指一种特殊的计算机用户;前者主要是从硬件的角度去执行任何指令,而后者是从软件的角度来管理系统的软硬件资源,如用户账户、权限管理、文件访问等。超级用户执行的程序不一定运行在管态,而管态程序也不一定由系统管理员启动,普通用户也可以启动。
2、用户态(又叫目态、普通态)
用户态是用户程序运行时的状态,它具有较低的特权级别。在这种状态下不能使用特权指令,不能直接使用系统资源,也不能改变CPU的工作状态,并且只能访问这个用户程序自己的存储空间。用户态不允许程序进行处理器中要求特权态的操作,以避免操作系统崩溃。每个进程都在各自的用户空间中运行,而不允许存取其他程序的用户空间。
在内核态下CPU可执行任何指令,在用户态下CPU只能执行非特权指令。
当CPU处于内核态,可以随意进入用户态;而当CPU处于用户态时,用户从用户态切换到内核态只有在系统调用和中断两种情况下发生,一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过软中断机制进入内核态。
两种CPU状态之间的转换方式:
- 用户态—>内核态:系统调用(通过中断、异常、陷入机制)
- 内核态—>用户态:设置程序状态字PSW
CPU的特权级别
接下来的讲解是在linux系统编程中所沉淀,主要从代码层面出发,直觉感受CPU特权级别的作用,然后初步讲解CPU特权级别的概念。
1 反汇编代码
本部分从两个代码示例出发。
反汇编代码访问RAX寄存器的内容,其代码示例如下
#include <iostream>
#include <cstdlib>
#include <cstdint>
int64_t get_rcx() {
asm volatile(
"push %rcx\n\t"
"movq $10, %rcx\n\t"
"movq %rcx, %rax\n\t"
);
asm volatile("pop %rcx");
}
int main() {
std::cout << "Hello, inline assembly: [RCX] = " << get_rcx() << "\n";
return 0;
}
上述输出结果为
Hello, inline assembly: [RCX] = 10
反汇编访问CR0控制寄存器,其代码如下
int64_t get_cr0() {
asm volatile ("movq %cr0, %rax");
}
int main() {
std::cout << "Hello, inline assembly: [CR0] = " << get_cr0() << "\n";
return 0;
}
其输出结果如下
Segmentation fault (core dumped)
那么,为什么应用程序访问cr0控制寄存器会coredump呢?
2 CPU特权级
出于操作系统及其控制的硬件资源的安全性、稳健性和正确性等原因,所有现代 CPU 都包含特权级别的概念。
现代 CPU 将支持至少两个特权级别或模式,通常由如下两部分构成:
- 特权(Supervisor)
- 用户
代码(即机器指令)在 CPU 上以给定的特权级别或模式运行。 设计和实现操作系统的人可以自由地利用处理器特权级别。 这正是现代操作系统的设计方式。 下表总结了通用 CPU 特权级别
权限级别或模式名称 | 特权级别 | 目的 | 术语 |
特权 | 高 | 内核代码跑在此层 | 内核空间 |
用户 | 低 | 用户代码跑在此层 | 用户空间 |
下面以x86架构讲解CPU的特权级别(ring), 英特尔处理器支持四种特权层级,分别为
- ring0
- ring1
- ring2
- ring3
上图箭头方向 特权级别逐渐升高 ,ring0特权级别最高,内核代码运行在此;ring3特权级别最低,应用程序在此。
为了进一步理解CPU特权级别,需要明白当前特权级别的概念,也即CPL。
当前特权级别 (CPL) :处理器当前执行代码的特权级别。
譬如,在一个处理器上有如下两条指令
- 机器指令a有特权级别(Ring0)
- 机器指令b有用户特权级别(Ring3)
因此,对于执行这些机器指令的正在运行的应用程序,会出现下表所示现象
机器指令 | 允许特权 | CPL | 是否work |
a | 特权(0) | 0 | 是 |
3 | 否 | ||
b | 用户(3) | 0 | 是 |
3 | 是 |
故可知,高特权级可以使用低特权层级,而低特权层级无法运行高特权层级的指令。
故在第一部分会出现CR0寄存器时,出现coredump。
3 总结
本文针对cpu特权层级进行了初步讲解,通过本文可以初步明白cpu特权级别(内核态,用户态)相关概念。