Linux 中断上下文(一)

Linux上下文的理解

1 Linux空间划分

Linux将整个空间划分为用户空间与内核空间,该空间是可配置的,还有一种是用户空间及内核空间各位2G,如下图:
在这里插入图片描述

2 Linux内部结构

Linux内部结构分为三部分,从底层往上分别是:硬件——>内核空间——>用户空间,如下图所示。

在这里插入图片描述
需要注意的细节问题:
1) 内核空间存放的是内核代码和数据,而进程的用户空间存放的是用户程序的代码和数据。不管是内核空间还是用户空间,他们都处于虚拟空间中;
2) Linux使用两级保护机制:0级供内核使用,3级供用户程序使用。
内核态与用户态:
1) 当一个任务(进程)执行系统调用而陷入内核代码中执行时,称进程处于内核运行态(内核态)。此时处理器处于特权级最高(0级)内核代码中执行。当进程处于内核态时,执行的内核代码使用当前的进程的内核栈。每个进程都有自己的内核栈。
2) 当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。此时处理器特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性的称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。

3 Linux上下文的理解

上下文context:上下文简单说来就是一个环境。

3.1 进程上下文

用户空间的应用程序,通过系统调用,进入内核空间。此时用户空间的进程要传递很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存器值、变量等。这就是所谓的“进程上下文”,可看作是用户进程传递给内核的这些参数及内核要保存的那一整套的变量、寄存器值及当时的环境等。
相对进程而言,就是进程执行的环境。具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。一个进程的上下文可分为三个部分:用户及上下文、寄存器上下文及系统级上下文。
1) 用户及上下文:正文、数据、用户堆栈及共享存储区;
2) 寄存器上下文:通用寄存器(R0~R13)、程序寄存器(PC,R14),处理器状态寄存器(CSPR),栈指针(SP,R15);
3) 系统上下文:进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。

当发生进程调度时,进行进程切换就是上下文切换(context switch)。操作系统必须对上面提到的全部信息进行切换,新调度的进程才能运行。而系统调用进行的模式切换(mode switch)。模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。

3.2 中断上下文

硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。此过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“中断上下文”,其实也可以看做是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被打断执行的进程环境)。中断时,内核不代表任何进程运行,它一般只访问系统空间,而不会访问进程空间,内核在中断上下文执行时一般不会阻塞。

3.3 总结

内核空间和用户空间是操作系统理论的基础之一,即内核功能模块运行在内核空间,而应用程序运行在用户空间。现代的CPU都具有不同的操作模式,代表不同的级别,不同的级别具有不同的功能,在较低的级别中将禁止某些操作。Linux系统设计时利用了这种硬件特性,使用了两个级别,最高级别和最低级别,内核运行在最高级别(内核态),这个级别可以进行所有操作,而应用程序运行在较低级别(用户态),在这个级别,处理器控制着对硬件的直接访问以及对内存的非授权访问。内核态和用户态有自己的内存映射,即自己的地址空间。
正是有了不同运行状态的划分,才有了上下文的概念。用户空间的应用程序,如果想要请求系统服务,比如操作一个物理设备,或者映射一段设备空间的地址到用户空间,就必须通过系统调用来(操作系统提供给用户空间的接口函数)实现。
通过系统调用,用户空间的应用程序就会进入内核空间,由内核代表该进程运行于内核空间,这就涉及到上下文的切换,用户空间和内核空间具有不同的地址映射,通用或专用的寄存器组,而用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行,所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

同理,硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理,中断上下文就可以理解为硬件传递过来的这些参数和内核需要保存的一些环境,主要是被中断的进程的环境。
Linux内核工作在进程上下文或者中断上下文。提供系统调用服务的内核代码代表发起系统调用的应用程序运行在进程上下文;另一方面,中断处理程序,异步运行在中断上下文。中断上下文和特定进程无关。
运行在进程上下文的内核代码是可以被抢占的(Linux2.6支持抢占)。但是一个中断上下文,通常都会始终占有CPU(当然中断可以嵌套,但我们一般不这样做),不可以被打断。正因为如此,运行在中断上下文的代码就要受一些限制,不能做下面的事情:
1)睡眠或者放弃CPU。
这样做的后果是灾难性的,因为内核在进入中断之前会关闭进程调度,一旦睡眠或者放弃CPU,这时内核无法调度别的进程来执行,系统就会死掉;
2)尝试获得信号量
如果获得不到信号量,代码就会睡眠,会产生和上面相同的情况;
3)执行耗时的任务
中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能;
4)访问用户空间的虚拟地址
因为中断上下文是和特定进程无关的,它是内核代表硬件运行在内核空间,所以在中断上下文无法访问用户空间的虚拟地址。

猜你喜欢

转载自blog.csdn.net/u013836909/article/details/107235210