0 引言
本文是在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。
4 总结
本文针对cpu特权层级进行了初步讲解,通过本文可以初步明白cpu特权级别(内核态,用户态)相关概念。