谈到CPU的这两个工作状态,也就是处理器的这两个工作状态,那我们有必要说一下为什么搞出这两个鬼玩意出来。
       用过电脑的娃娃们肯定知道在一个系统中既有操作系统的程序,也由普通用户的程序。但那么多指令,可不是随便乱用的,有些指令只能由系统来使用,禁止用户程序去直接访问。为了保证操作系统和各个应用程序能够顺利运行,就必须对他们进行限制,否则的话就根本没有办法保证系统的安全性和稳定。
       所以呢,根据运行程序对资源和机器指令的使用权限,把处理器设置为不同的状态。多数系统把处理器的工作状态分为管态和目态两种。也就是我们今天要说的这两个东西。
       所谓管态,即操作系统的管理程序运行时的状态,它具有较高的特权级别,也称为特权态、系统态、内核态或者核心态。当处理器处于管态时,他可以执行所有的指令,包括各种特权指令,也可以使用所有的资源,并且具有改变处理器状态的能力,是感觉很牛逼。需要指出的是,管态和超级用户不同,前者是指CPU的状态,后者是指一种特殊的计算机用户;前者主要是从硬件的角度去执行任何指令,而后者是从软件的角度来管理系统的软硬件资源,如用户账户、权限管理、文件访问等。超级用户执行的程序不一定运行在管态,而管态程序也不一定由系统管理员启动,普通用户也可以启动。
       所谓目态,即用户程序运行时的状态,它具有较低的特权级别,又称为普通态或用户态。在这种状态下不能使用特权指令,不能直接使用系统资源,也不能改变CPU的工作状态,并且只能访问这个用户程序自己的存储空间。用户态不允许程序进行处理器中要求特权态的操作,以避免操作系统崩溃。每个进程都在各自的用户空间中运行,而不允许存取其他程序的用户空间。
         百度百科上的这个图片对于这两个状态划分就挺好的。

      当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核
代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行 态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。
       在内核态下CPU可执行任何指令,在用户态下CPU只能执行非特权指令。当CPU处于内核态,可以随意进入用户态;而当CPU处于用户态时,用
户从用户态切换到内核态只有在系统调用和中断两种情况下发生,一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过调用软中断进入内核 态。   
       Linux使用了Ring3级别运行用户态,Ring0作为内核态,没有使用Ring1和Ring2。Ring3状态不能访问Ring0的地址

空间,包括代码和数据。Linux进程的4GB地址空间,3G-4G部分大家是共享的,是内核态的地址空间,这里存放在整个内核的代码和所有的内核模块,
以及内核所维护的数据。用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件操作,网络数据发送等操作,必须通过
write,send等系统调用,这些系统调用会调用内核中的代码来完成操作,这时,必须切换到Ring0,然后进入3GB-4GB中的内核地址空间去执
行这些代码完成操作,完成后,切换回Ring3,回到用户态。这样,用户态的程序就不能随意操作内核地址空间,具有一定的安全保护作用。
       我在网易的一篇博客中看到一个解释挺好的一个文章,对方是从一段实例中开始的,所以我粘贴过来分享了一下:

1. 用户态和内核态的概念区别

究竟什么是用户态,什么是内核态,这两个基本概念以前一直理解得不是很清楚,根本原因个人觉得是在于因为大部分时候我们在写程序时关注的重点和着眼的角度放在了实现的功能和代码的逻辑性上,先看一个例子:

1)例子

C代码
  1. void testfork(){
  2. if(0 = = fork()){
  3. printf(“create new process success!\n”);
  4. }
  5. printf(“testfork ok\n”);
  6. }


段代码很简单,从功能的角度来看,就是实际执行了一个fork(),生成一个
新的进程,从逻辑的角度看,就是判断了如果fork()返回的是0则打印相关语句,然后函数最后再打印一句表示执行完整个testfork()函数。代码
的执行逻辑和功能上看就是如此简单,一共四行代码,从上到下一句一句执行而已,完全看不出来哪里有体现出用户态和进程态的概念。

如果说前面两种是静态观察的角度看的话,我们还可以从动态的角度来看这段代码,即它被转换成CPU执行的指令后加载执行的过程,这时这段程序就是一个动态执行的指令序列。而究竟加载了哪些代码,如何加载就是和操作系统密切相关了。

2)特权级


悉Unix/Linux系统的人都知道,fork的工作实际上是以系统调用的
方式完成相应功能的,具体的工作是由sys_fork负责实施。其实无论是不是Unix或者Linux,对于任何操作系统来说,创建一个新的进程都是属于

核心功能,因为它要做很多底层细致地工作,消耗系统的物理资源,比如分配物理内存,从父进程拷贝相关信息,拷贝设置页目录页表等等,这些显然不能随便让哪

个程序就能去做,于是就自然引出特权级别的概念,显然,最关键性的权力必须由高特权级的程序来执行,这样才可以做到集中管理,减少有限资源的访问和使用冲
突。

特权级显然是非常有效的管理和控制程序执行的手
段,因此在硬件上对特权级做了很 多支持,就Intel
x86架构的CPU来说一共有0~3四个特权级,0级最高,3级最低,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查,相关的概念有
CPL、DPL和RPL,这里不再过多阐述。硬件已经提供了一套特权级使用的相关机制,软件自然就是好好利用的问题,这属于操作系统要做的事情,对于

Unix/Linux来说,只使用了0级特权级和3级特权级。也就是说在Unix/Linux系统中,一条工作在0级特权级的指令具有了CPU能提供的最
高权力,而一条工作在3级特权级的指令具有CPU提供的最低或者说最基本权力。

3)用户态和内核态


在我们从特权级的调度来理解用户态和内核态就比较好理解了,当程序运行在3级
特权级上时,就可以称之为运行在用户态,因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;反之,当程序运
行在0级特权级上时,就可以称之为运行在内核态。


然用户态下和内核态下工作的程序有很多差别,但最重要的差别就在于特权级的不
同,即权力的不同。运行在用户态下的程序不能直接访问操作系统内核数据结构和程序,比如上面例子中的testfork()就不能直接调用
sys_fork(),因为前者是工作在用户态,属于用户态程序,而sys_fork()是工作在内核态,属于内核态程序。


我们在系统中执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系
统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态,比如testfork()最初运行在用户态进程下,当它调用fork()最终触发
sys_fork()的执行时,就切换到了内核态。

2. 用户态和内核态的转换

1)用户态切换到内核态的3种方式

a. 系统调用


是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使
用操作系统提供的服务程序完成工作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户
特别开放的一个中断来实现,例如Linux的int 80h中断。

b. 异常

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

c. 外围设备的中断


外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会
暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到
内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

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

2)具体的切换操作


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

异常和中断的处理机制基本上也是一致的,关于它们的具体区别这里不再赘述。关于中断处理机制的细节和步骤这里也不做过多分析,涉及到由用户态切换到内核态
的步骤主要包括:

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

[2] 使用ss0和esp0指向的内核栈将当前进程的cs,eip,eflags,ss,esp信息保存起来,这个

过程也完成了由用户栈到内核栈的切换过程,同时保存了被暂停执行的程序的下一

条指令。

[3] 将先前由中断向量检索得到的中断处理程序的cs,eip信息装入相应的寄存器,开始

执行中断处理程序,这时就转到了内核态的程序执行了。

cpu的用户态和内核态和内存的用户空间内核空间的更多相关文章

  1. cpu与寄存器,内核态与用户态及如何切换

    cpu:相当于计算机的大脑负责运算和发送命令: 寄存器:寄存器是cpu当中的一个有限存储部件,cpu从内存调用数据时,寄存器会将从内存调用的数据进行更新在寄存器中以一个字或变量进行存储. 寄存器总共分 ...

  2. cpu内核态与用户态

    1.操作系统需要两种CPU状态 内核态(Kernel Mode):运行操作系统程序,操作硬件 用户态(User Mode):运行用户程序 2.指令划分 特权指令:只能由操作系统使用.用户程序不能使用的 ...

  3. Linux用户态和内核态

    究竟什么是用户态,什么是内核态,这两个基本概念以前一直理解得不是很清楚,根本原因个人觉得是在于因为大部分时候我们在写程序时关注的重点和着眼的角度放在了实现的功能和代码的逻辑性上,先看一个例子: 1)例 ...

  4. linux 用户态 内核态

    http://blog.chinaunix.net/uid-1829236-id-3182279.html 究竟什么是用户态,什么是内核态,这两个基本概念以前一直理解得不是很清楚,根本原因个人觉得是在 ...

  5. Linux探秘之用户态与内核态

    一. Unix/Linux的体系架构 如上图所示,从宏观上来看,Linux操作系统的体系架构分为用户态和内核态(或者用户空间和内核).内核从本质上看是一种软件——控制计算机的硬件资源,并提供上层应用程 ...

  6. Linux 用户态和内核态

    1.特权级特权级用来管理和控制程序执行.如Intel x86架构的CPU,有0~3四个特权级,0级最高,3级最低.硬件在执行每条指令时都会检查指令具有的特权级.硬件提供了特权级使用机制,对操作系统来说 ...

  7. 【转载】 Linux用户态和内核态

    [说明]转载自 http://my.oschina.net/liubin/blog/27795 究竟什么是用户态,什么是内核态,这两个基本概念以前一直理解得不是很清楚,根本原因个人觉得是在于因为大部分 ...

  8. 操作系统基本概念(内核态与用户态、操作系统结构)-by sixleaves

    内核态与用户态(为什么存在这种机制.程序应处于哪个状态.如何判断当前所处状态.哪些功能需要内核态.如何实现这种机制) 1.首先我们应该思考清楚为什么会有内核态和用户态?(为什么存在这种机制) 因为计算 ...

  9. Linux操作系统学习_用户态与内核态之切换过程

    因为操作系统的很多操作会消耗系统的物理资源,例如创建一个新进程时,要做很多底层的细致工作,如分配物理内存,从父进程拷贝相关信息,拷贝设置页目录.页表等,这些操作显然不能随便让任何程序都可以做,于是就产 ...

随机推荐

  1. RabbitMQ的安装及集群搭建方法

    RabbitMQ安装 1 安装erlang 下载地址:http://www.erlang.org/downloads 博主这里采用的是otp_src_19.1.tar.gz (200MB+) [roo ...

  2. 20145322《Java程序设计》第4次实验报告

    实验内容 1.搭建Android环境 2.运行Android 3.修改代码并输出自己的学号 实验步骤 搭建Android环境 安装Android,核心是配置JDK.SDK 运行Android 最终结果 ...

  3. 20145331 实验一 "Java开发环境的熟悉"

    20145331 实验一 "Java开发环境的熟悉" 实验内容 使用JDK和IDE编译.运行简单的Java程序.题目: 实现四则运算,并进行测试. 编写代码 1.首先第一步就是要输 ...

  4. 混合开发的大趋势之一React Native之简单的登录界面

    转载请注明出处:王亟亟的大牛之路 这些天都在学习RN这部分吧,然后写了个简单的登陆业务,从"实战"中讲解吧 还是继续安利:https://github.com/ddwhan0123 ...

  5. 关于vuex与v-route的结合使用

    把vue实际用于项目的过程中遇到过一些问题 1.如何将vuex和vue-route结合使用(接口调用成功回调页面这类等等) 1.初始考虑的方法是在vuex引入vue-router,vuex写一些业务逻 ...

  6. Berkeley parser使用方法

    1. 简介  Berkeley Parser 是加州大学伯克利分校 NLP 实验室开发的一种基于概率上下文无关文法(PCFG)的成分句法分析器,支持英语,汉语,德语等多个语种,它具有较高的句法分析性能 ...

  7. init() 方法

    1 /** * servlet init()在web应用程序启动之后,第一个请求到达Servlet之前调用. * 问题1:如果init()中需要处理大量的工作,那么servlet在处理第一个请求需要花 ...

  8. springboot统一异常处理及返回数据的处理

    一.返回code数据的处理 代码: Result.java /** * http请求返回的最外层对象 * Created by 廖师兄 * 2017-01-21 13:34 */ public cla ...

  9. Javascript中的void

    原来void是将其后的字面量当元表达式执行,并永远返回undefined.同时undefined不是关键词.. 由于JS表达式偏啰嗦,于是最近便开始采用Coffeescript来减轻负担.举个栗子,当 ...

  10. wordcount程序出现map 100% reduce 0%问题的解决方法

    运行wordcount程序一直停在map 100% reduce 0%, input文件夹的内容: 其中: f1.txt中的内容为:hello hadoop f2.txt中的内容为:hello had ...