Linux进程空间分布
Posted 笨鸟居士的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进程空间分布相关的知识,希望对你有一定的参考价值。
Linux使用两级保护机制:0级供内核使用,3级供用户程序使用。从图中可以看出,每个进程有各自的私有用户空间(0~3G),这个空间对系统中的其他进程是不可见的。最高的1GB字节虚拟内核空间则为所有进程以及内核所共享。
http://developer.51cto.com/art/201110/299468.htm
http://blog.csdn.net/hjl243632044/article/details/7218283
http://www.cnblogs.com/Anker/p/3269106.html
针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,
而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。
每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。
有了用户空间和内核空间,整个linux内部结构可以分为三部分,从最底层到最上层依次是:硬件-->内核空间-->用户空间。如下图所示:
需要注意的细节问题:
(1) 内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据。不管是内核空间还是用户空间,它们都处于虚拟空间中。
(2) Linux使用两级保护机制:0级供内核使用,3级供用户程序使用。
内核态与用户态:
(1)当一个任务(进程)执行系统调用而陷入内核代码中执行时,称进程处于内核运行态(内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。
(2)当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。
程序在执行过程中通常有用户态和内核态两种状态,CPU对处于内核态根据上下文环境进一步细分,因此有了下面三种状态:
(1)内核态,运行于进程上下文,内核代表进程运行于内核空间。
(2)内核态,运行于中断上下文,内核代表硬件运行于内核空间。
(3)用户态,运行于用户空间。
但是,切换到中断处理,比进程切换,代价要小。
所谓的“进程上下文”,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等。
相对于进程而言,就是进程执行时的环境。具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。一个进程的上下文可以分为三个部分:用户级上下文、寄存器上下文以及系统级上下文。
(1)用户级上下文: 正文、数据、用户堆栈以及共享存储区;
(2)寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
(3)系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。
当发生进程调度时,进行进程切换就是上下文切换(context switch).操作系统必须对上面提到的全部信息进行切换,新调度的进程才能运行。
而系统调用进行的模式切换(mode switch)。模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。
硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的 一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“ 中断上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被打断执行的进程环境)。中断时,内核不代表任何进程运行,它一般只访问系统空间,而不会访问进程空间,内核在中断上下文中执行时一般不会阻塞。
LINUX完全注释中的一段话:
当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结构中。在发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中继服务结束时能恢复被中断进程的执行。
内核空间,用户空间
http://blog.csdn.net/bingqingsuimeng/article/details/7924756
内核空间和用户空间之间如何进行通讯?
内核空间和用户空间一般通过系统调用进行通信。
如何判断一个驱动是用户模式驱动还是内核模式驱动? 判断的标准是什么?
一般的硬件体系机构都提供一种“门”机制。“门”的含义是指在发生了特定事件的时候低特权的应用程序可以通过这些“门”进入高特权的内核空间。对于IntelX86体系来说,Linux操作系统正是利用了“系统门”这个硬件界面(通过调用int $0x80机器指令),构造了形形色色的系统调用作为软件界面,为应用程序从用户态陷入到内核态提供了通道。(其实就是系统调用)
通过“系统调用”使用“系统门”并不需要特别的权限,但陷入到内核的具体位置却不是随意的,这个位置由“系统调用”来指定,有这样的限制才能保证内核安全无虞。
我们可以形象地描述这种机制:作为一个游客,你可以买票要求进入野生动物园,但你必须老老实实的坐在观光车上,按照规定的路线观光游览。当然,不准下车,因为那样太危险,不是让你丢掉小命,就是让你吓坏了野生动物。
由内核主动发起的信息交互
在内核发起的交互中,我们最关心和感兴趣的应该是内核如何向用户程序发消息,用户程序又是怎样接收这些消息的,具体问题通常集中在下面这几个方面:内核可否调用用户程序?是否可以通过向用户进程发信号来告知用户进程事件发生?
内核中启动用户程序还是要通过execve这个系统调用原形,只是此时的调用发生在内核空间,而一般的系统调用则在用户空间进行。如果系统调用带参数,那将会碰到一个问题:因为在系统调用的具体实现代码中要检查参数合法性,该检查要求所有的参数必须位于用户空间——地址处于0x0000000——0xC0000000之间,所以如果我们从内核传递参数(地址大于0xC0000000),那么检查就会拒绝我们的调用请求。为了解决这个问题,我们可以利用set_fs宏来修改检查策略,使得允许参数地址为内核地址。这样内核就可以直接使用该系统调用了。
(2) 利用brk系统调用来导出内核数据
内核和用户空间传递数据主要是用get_user(ptr)和put_user(datum,ptr)例程。所以在大部分需要传递数据的系统调用中都可以找到它们的身影。可是,如果我们不是通过用户程序发起的系统调用——也就是说,没有明确的提供用户空间内的缓冲区位置——的情况下,如何向用户空间传递内核数据呢?
以上是关于Linux进程空间分布的主要内容,如果未能解决你的问题,请参考以下文章