操作系统的用户态和内核态

内核态和用户态  

  CPU的指令分为特权级指令和非特权级指令,特权级指令通常是一些比较危险的指令,这类指令的滥用可能会造成系统崩溃等灾难,所以特权级指令只允许操作系统及其相关模块使用,普通应用程

序不能使用这类指令。Intel X86架构的CPU将特权等级分为4个级别:RING0,RING1,RING2,RING3。操作系统通过区分用户态和内核态来保证特权级指令不被错误的使用。

  内核态与用户态是操作系统的两种运行级别,Linux没有使用Ring1和Ring2,而仅仅使用了Ring3级别运行用户态,Ring0作为内核态,Ring3状态不能访问Ring0的地址空间,包括代码和数据。一个

Linux进程占有4G的逻辑地址空间,其中用户态占0-3G对应的空间而内核态占3G-4G部分,这里存放了整个内核的代码和所有内核模块以及内核所维护的数据,即相当于每个进程有一份内核的拷贝。当用

户运行一个程序,该程序所创建的进程开始是运行在用户态,使用用户自己的数据段和代码段。当进程需要进行文件操作、网络数据发送等内核态才能完成的操作时,必须通过系统调用切换到内核态执

行。系统调用会调用内核中的代码来完成操作,这时,必须切换到Ring0,然后进入3GB-4GB中的内核地址空间去执行相应的内核代码完成操作,完成之后切换回Ring3,继续运行在用户态。

用户态到内核态的切换

  (1) 系统调用:户态进程需要进行一些只有内核态能执行的操作时,主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,此时用户态进程要向

内核态传递参数,同时保存用户进程的寄存器、变量等,以便切换回来时能正确继续执行,这个过程就是进程上下文的保存。

  (2) 异常:当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

  (3) 硬件中断:当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户

态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

  这3种方式是系统在运行时由用户态转到内核态的最主要方式,其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。

具体的切换操作

  从触发方式上看,可以认为存在前述3种不同的类型,但是从最终实际完成由用户态到内核态的切换操作上来说,关键步骤是完全一致的,没有任何区别,都相当于执行了一个中断响应的过程,因

为系统调用实际上最终是中断机制实现的,而异常和中断的处理机制基本上也是一致的,关于它们的具体区别这里不再赘述。关于中断处理机制的细节和步骤这里也不 做过多分析,涉及到由用户态切

换到内核态的步骤主要包括:

  [1] 从当前进程的描述符中提取其内核栈的ss0及esp0信息。

  [2] 使用ss0和esp0指向的内核栈将当前进程的cs,eip,eflags,ss,esp信息保存起来,这个过程也完成了由用户栈到内核栈的切换过程,同时保存了被暂停执行的程序的下一条指令。

  [3] 将先前由中断向量检索得到的中断处理程序的cs,eip信息装入相应的寄存器,开始执行中断处理程序,这时就转到了内核态的程序执行了。

原文地址:https://www.cnblogs.com/litterrondo/p/2960271.html