当前位置:C++技术网 > 资讯 > Windows核心编程入门:7 用户态到内核态的穿越

Windows核心编程入门:7 用户态到内核态的穿越

更新时间:2016-05-15 22:06:48浏览次数:1+次

    在《Windows核心编程入门3:轻松理解用户态和内核态》中,我们理解了用户态和内核态的区别。然而我们还需要知道的一个知识,那就是状态的转换。
    如果你学习过核心编程,你应该知道用户态转换到内核态的一些知识。然而,用户态是如何转换到内核态的呢?怎么样才算是转入到内核态的呢?
    应用程序通常是用来处理业务逻辑的,而不会去关心系统内部的功能是如何实现的。工具类软件则偏向于系统管理软件,所以会接触到内核相关的东西。我们的应用程序都是工作在用户态的。
    内核态是用户维护和管理操作系统的,而操作系统又是隔离硬件的。对于系统本身的各种操作,如管理进程线程、管理内存之类的,都属于系统本身的东西。而对于硬件的管理和操作,则是操作系统的使命。这一类事情都是内核态来做的。
    我们应用程序处理的业务功能需求,如果只是处理业务本身的,就用不上内核态。但是如果想让软件本身变得厉害,性能好,那很可能就需要内核态的支持了。比如,火车票售票系统,如果单从业务来讲,也就是对数据库的操作,一个线程也可以售票。所以,业务上,只需要能够卖票即可。然而,售票需求太大,同时卖票的人太多,单线程是不可能应付的过来的。为了系统的性能,就需要支持多线程。那么也要对多线程进行管理。那么对于业务来说,多线程是不算业务要求的。多线程是系统性能需求。系统本身的需求,就需要对计算机资源等的管理和操作了,目的是提供更好的业务功能。
    如果我们开发一个维修硬盘的工具,我们应用程序是无法直接操作硬件的。所以我们也只有委托操作系统的内核态来完成这些功能。
    以上的描述,一个是业务功能需要系统本身的强大支持,需要系统底层提供高性能的支持,另一个是应用需要操作硬件,而应用无法直接操作硬件。两种情况下,都需要操作系统来提供支持。操作系统向应用提供的支持就是API函数。这里的API函数只是和系统内核交互的方式的统称。在编程中,我们什么都是调用系统的函数完成的。
    我们也就知道,运行在用户态的程序,是有执行内核态的功能的需求的。那么内核态有没有转为用户态的需求呢?答案是,没有必要。我们要知道,为什么会出现用户态到内核态的转变?因为内核态很多事情是用户态无法做的,所以才需要从用户态切换到内核态来完成。而内核态掌管了计算机的一切,什么事情都可以做,不需要切换。
    那么用户态切换到内核态是怎么回事呢?难道是用户态嫁给了内核态这个高富帅,一夜之间地位就提升了吗?事实上,我们一般在用户态到内核态的切换这个概念上模糊不清。是不是用户态程序拿到了权限后变成内核态的程序了,然后就和内核态程序一样,可以随意操作硬件了?答案是否定的。
    在操作系统安装后,系统内核态程序都是固定了的,不会再加其他程序进来的。所以,用户态程序升级为内核态程序的假设是不成立的。否则很容易被病毒利用,那破坏性就大了。因为病毒成为内核态之后,完全可以破坏硬件,可以直接操作硬件的。事实上,所有应用程序都不能直接操作硬件,都只是委托系统来完成硬件操作。
    所以,应用程序从用户态切换到内核态,并不是应用程序本身的状态的变化。这个切换的过程,实际上是从功能的角度来看的,从功能实现的流程的角度看的。也就是说,用户态到内核态的切换,只是一个功能流程逻辑的变化。假如一个功能需要三个步骤,第一步是用户态完成的,第二步需要内核态完成,第三步又是用户态完成的。那么在第一步和第二步之间就会将用户态切换到内核态。内核态执行完后,返回来用户态继续执行第三步。所以,用户态切换到内核态事实上就是一次委托人办事的意思。只是委托办事的这个过程,算是应用程序完成功能的其中一个步骤而已。从功能实现来讲,应用程序的状态切换了一次。在内核态执行前,用户态会将必要的参数传递到内核中,供内核态的程序执行所需的操作。

    这就好比是调用了系统的普通API一样。只不过这个API是内核态提供的API,而我们通常使用的win32API是用户态的,所以即使调用了win32的API,依然是用户态的。我们通常叫内核提供的API为系统服务接口,其实还是一种API,也是一些API函数。只是系统服务接口提供的函数可以帮应用程序操作硬件的。我们可以看看下面这个图,了解大意:

用户态和内核态的API调用情况

【用户态和内核态的API调用情况】

    说到这里,你应该不会再以为是应用程序跑到内核空间执行一些底层的操作甚至是直接操作硬件了吧。我想曾经用户态切换到内核态的概念模糊,在此时应该很明朗了。下面用一个简单的示意图描述状态切换的过程:

用户态切换到内核态的过程

【用户态切换到内核态的过程】
    用户态到内核态的切换,就是功能的其中一个环节让内核态程序来完成罢了。如果应用程序是调用系统API来请求完成某项功能的时候,此时是应用程序主动要执行内核态功能,这是主动切换状态的行为。而另外还有两种情况,虽然也是切换了状态,然而却是被动的。当程序执行时,一个异常出现了,会导致异常中断发生,此时程序无法继续正常执行下去,所以系统会中断用户态的应用的执行,转而进入了内核态来处理异常。而设备中断,是硬件产生的,通常也是很重要的。系统会打断正在执行的用户态的线程的执行,来先处理硬件的事情。
    那么总的来说,我是想阐述用户态和内核态应该做的不同的事情,功能需求要求将用户态切换到内核态完成一些特定的功能。重点是解释清楚用户态到内核态切换的概念,解开思维误区。最后简单提到了几种切换的方式。