首页 > 代码库 > 用户态与内核态之间的切换
用户态与内核态之间的切换
时间:2014.06.08
地点:基地
说明:本文由网上资料整理而成
--------------------------------------------------------------------------------------
一、用户态与内核态
程序在运行时会消耗操作系统的物理资源,比如在创建新进程时涉及物理内存的分配,从父进程拷贝相关信息,拷贝设置页目录、页表等。这些都涉及很底层的操作,不可随便让程序去做,而是由更高级的程序完成,以达到对资源的集中管理,减少冲突。在Linux中,根据这中对核心操作支持与否将进程特权级分为内核态和用户态,以实现有限资源的有效管理,也就是说内核态和用户态只是操作系统的两种运行级别。说到操作系统的运行级别Intel CPU提供了 0到3四种级别的运行模式,其中0的级别最高,3的级别最低,Linux只有第0级和第3级,即分别对应着内核态和用户态。特权级0级是留给操作系统代码和设备驱动程序代码使用的,它们工作于系统核心状态,而特权级3则是留给普通用户程序的,工作在用户态。运行于处理器内核态的代码不受任何限制,可自由访问任何有效地址或直接访问端口而运行于用户态的代码则要求首到处理器的诸多检查,它只能访问映射其地址空间的页表项中规定在用户态下可访问页面的虚拟地址。当任务或者说进程执行系统调用陷入内核代码中执行时,进程切入内核态,此时处理器处于特权级最高(0级)的内核代码中执行,执行内核代码时使用当前进程的内核栈,每个进程都有自己的内核栈,而当任务或进程执行用户自己的代码时,则称其为用户态,此时处理器处在特权级最低级用户代码中执行。
--------------------------------------------------------------------------------------
二、用户态与内核态之间的切换
运行于用户态的进程可执行的操作和访问的资源相比内核态进程会受到很大限制,内核态进程可执行任何操作和使用任何资源。一般来说,很多程序一开始运行于用户态,但当随着程序的执行,某些操作可能需要在内核权限下才能执行,于是,这就要求进程能从用户态切换到内核态了,因为只有内核态的进程才可以执行任何操作或者访问任何资源。 我们知道,操作系统中每个进程都有一个4G大小的虚拟地址空间,前0到3G为用户空间,每个进程的用户空间之间是相互独立的,剩下的1G为内核空间,它对于所有进程来说是共享的,因为每个进程都可以从用户态切换到内核态,当然进程内核空间中的存储内核栈的空间是不共享。内核态下CPU可执行任何指令,而用户态下CPU只能执行非特权指令,CPU处于内核态时,可随意进入用户态,CPU处于用户态时,从用户态切换到内核态需要满足一定条件,下面将会逐一地介绍。1 发生系统调用
用户态的进程通过系统调用申请使用操作系统提供的系统调用服务例程来处理任务,操作系统的调用机制其核心就是使用操作系统为用户特别开发的的中断即软中断机制来实现。这种发生系统调用时的切换属于用户态主动请求切换到内核态。2.产生异常
执行在用户态的进程,由于发生了某些事先无法预知的异常,会触发当前运行的进程切换到批处理异常的内核相关的程序中,即转换到内核态,典型的例子如却页异常。
3 外设产生中断
当外围设备完成用户请求的操作后,会向CPU发出相应中断信号,这时CPU会暂停执行下下一条即将要执行的指令转而去执行与中断信号对应的处理程序,从而切换到内核态。 比如硬盘地读写操作完成后,系统会切换到硬盘读写的中断处理程序中执行后续操作。以上三种情形,只有系统调用是进程主动请求发生由用户态到内核态的切换,中断和异常都是被动切换。系统调用处理程序都是运行在内核态之下。在系统调用时由于用户态和内核态是运行于两个独立的栈上,内核栈和用户栈,于是不能仅仅是传递函数指针,因为内核态堆栈在用户态下不可见,所以对于系统调用函数的处理程序对于用户态也是不可见,参数攒地的过程中也不能使用普通的压栈和出栈方式来进行参数传递,因为内核栈和用户栈是相互独立的,在Linux内核中主要是用寄存器方式来完成。