总结(速查版)下面是分析
常见的非特权指令:
存取数,读时钟,加减乘除,寄存器清零,压栈弹栈,跳转,trap(访管)。
常见的特权指令:
开关中断,写时钟,输入输出,写PSW。
前置知识
本篇文章基于之前这篇文章的思考进行了延拓:
为什么取数和寄存器清零是用户态的指令?
思想简洁来说就是,对于共享资源的访问需要特权指令来执行,对于独占资源的访问,非特权指令进行执行就可以了。
延拓
之前我以为主存或者ALU这些东西,包括PC都是公有资源(因为每个进程都可以访问),然后想到了指令的流水线突然豁然开朗,因为流水线的宗旨就是避免冲突,那么为什么要避免冲突呢?因为在执行一条指令时,比如一个阶段进行了访存,那么别的指令就不能够进行访存,换言之,就是保证了一个进程在执行的时候对内存和ALU等设备的访问都是私有的,都是不共享的。
也就是说,主存等设备可以分时共享,那么在进程使用的时候,实际上是独占的。
简要的分析一下为什么主存是独占的:
当一个指令在执行的时候,如果要执行访存,必然要拿到内存总线的控制权,而任意时刻只能有一个CPU能获得总线的控制权,而CPU又是宏观并行微观并发,也就是实际上一个CPU在同一时刻只能执行一个进程,因此,不管是多核CPU还是单核CPU,一个进程在他的时间片内,对主存是独占的。
接下来基于前置知识和延拓知识,对常见的非特权和特权指令进行一个分析。
常见的非特权指令
寄存器(组合逻辑)类
取数指令:取数在RISC中只能是对寄存器,在CISC中是对主存,在主存中的情况看存数即可。取数那么实际上寄存器在指令执行过程是私有的,有自己的通用寄存器,因此,不干扰别的进程,不用升级到特权指令。
加减乘除等算数指令:在指令流水线中,一个ALU同时只能为一组进程所访问(当然在超标量流水线时可以有多个ALU被访问,但是同一个ALU也只能被一个进程访问,这是底层硬件和流水线所保证的),因此,ALU在执行的时候也是不被共享的,也就不会干扰别的进程,不用特权。
寄存器清零指令:同取数,自己的寄存器,想干啥干啥。
压栈/弹栈指令:同取数,这里的栈可能是,EBP和ESP,在同一时刻,也只能被一个进程所占有,因此不共享。
跳转指令:PC同样也是一个进程在同一时刻所独占的(PC在取指时候被一个进程独占),因此,修改PC同样也不需要担心别的进程,这是流水线所保证的。
主存类
存数指令:主存在指令周期的访存阶段被一个进程独占,因此也不会干扰到其他进程,属于非特权指令。
共享资源类
读时钟指令:虽然是一个共享的资源,但是对他进行读操作也不影响其他进程,因此不是特权。
特殊类
trap指令:访管指令用于进入内核态,当然在用户态(特权指令需要在内核态进行)进行,自然就是非特权指令。
常见的特权指令
中断类
开关中断指令/输入输出指令:和中断有关的指令都需要是特权指令,因为如果用户程序可以随意中断CPU的执行,理论上一个用户程序可以无限占有CPU,那这自然是十分危险的,直接死机,因此,对于这种中断指令,要交由操作系统进行判断中断优先级,或者进行屏蔽等操作。开关中断自然是不可以非特权了,IO的时候,在不同的操作模式下,发出中断的时间不一样(轮询,DMA,通道)然而都是需要通过中断告诉CPU自己已经传送完信息了的,因此,IO指令也是特权指令。
写PSW寄存器指令:PSW主要储存了两种信息:1. 和运算相关的信息(溢出位,进位位)2. 控制信息:比如IF位(允许中断)。因此,由之前的分析我们可以知道,这个如果写PSW可以自己随便写的话,那么我直接把我的IF升级,从本来不允许中断变成允许中断,这样有些不重要的进程也可以获取大量的系统资源,显然会使操作系统的效率大大降低(本来IO优先,现在可能你打着游戏呢,我直接给你把系统更新了)。因此,写PSW也只能是特权指令。
共享资源类
写时钟指令:时钟是所有进程共享的节拍,大家都需要读,你如果改了,全部进程的节奏都变了,这是不可以的。