从寄存器到用户态与内核态

3,450 阅读3分钟

关键字:寄存器、ring0、ring3、内核态、用户态

欢迎关注我的公众号:Hoeller

寄存器是CPU内部重要的组成部分,寄存器内部由N个触发器组成,每个触发器可以保存1位二进制数,所以16位寄存器可以保存16个bit。

CPU内部一般有不同类型的多个寄存器,我们需要使用CPU对应的机器指令来操作这些寄存器,当然像内存、磁盘这些也是通过机器指令来操作的。

而CPU为了安全性,比如x86的CPU将机器指令分为了一般指令和特权指令,比如操作磁盘的指令就是特权指令,只有CPU处于某种特殊状态下才能执行特权指令。

x86 CPU利用内部一个特殊寄存器,用来标记此时的CPU能不能执行特权指令,这个特殊寄存器中可以存四种状态,ring0、ring1、ring2、ring3。

Windows、Linux操作系统中只用了ring0和ring3两种状态,如果处于ring0,表示CPU可以执行所有指令,包括特权指令,如果处于ring3,表示CPU不能执行特权指令,ring0等级高,ring3等级低。

不管是操作系统还是运行在操作系统之上的软件,都是用高级语言开发出来的,最终都需要翻译为机器指令。

所以本质上来说,我们自己用c或java开发的软件,只要翻译成了机器指令,也是可以直接操作寄存器的,操作磁盘的。

但是我们不会这么来做,也肯定不需要每个软件自己去实现这么底层并通用的功能,所以我们通常会调用操作系统的函数来操作磁盘。

操作系统就相当于一个中间层。

同时操作系统为了保护系统,就设计了内核态和用户态。

当我们电脑启动时,CPU处于ring0状态,这时所有指令都可以执行,从而启动引导程序,从而启动操作系统,操作系统在启动时,会对内存就行划分,划出一部分内存只能被操作系统自己使用,其他内存可以给应用软件使用。

操作系统启动完了之后,CPU状态就改为ring3,开始运行应用软件。

由于此时cpu处于ring3,所以应用软件想要运行一些特殊指令肯定是不行的。

当我们调用操作系统的提供的函数时,操作系统会来执行特权指令,可是操作系统不也是c语言写的代码吗,要执行特权指令需要ring0,如何把ring3切换成ring0呢?

系统中断,其实就是一条指令,比如int 0x80。

系统中断,cpu会自动切回到ring0状态,然后执行操作系统在系统启动时所设置好的代码,而这段代码可以根据中断之前所执行的代码来继续执行后续逻辑,并且此时cpu已经处于在ring0状态了,可以正常执行了。

而CPU处于ring0状态就是我们说的内核态,处于ring3状态就是我们说的用户态。

总结,当我们自己写的程序要操作磁盘时,因为要执行特权指令,但是CPU处于ring3,无法直接执行特殊指令,需要调用操作系统函数,从而会修改CPU处于ring0,从而进去内核态。

用户态时,CPU只能执行一些普通指令,内核态时,CPU能执行所有指令。

今天就聊到这,抛砖引玉,如果有不对的地方,欢迎大佬们指出。