[002]【手撕】《操作系统》第二章第2节:上下文切换,中断、异常、系统调用

本文详细解析了操作系统中用户态到内核态的切换过程,涉及计时器中断、CPL概念、用户级与内核级代码行为、中断向量表与中断描述符表的区别、中断屏蔽、中断栈、系统调用与上行调用,以及x86状态切换实例。深入理解了中断处理程序的执行流程及其安全性特点。
摘要由CSDN通过智能技术生成

首发于2022-11-11
完善于2022-12-05
这是Sum_sugar 的第002篇原创文章

前言:本系列以BUPT人工智能学院徐梦炜老师的课件为蓝本,以《王道操作系统考研复习指导》为知识补充,旨在系统梳理操作系统课程的知识点,以学生的视角出发解释学习操作系统过程中遇到的种种问题。如有疏漏及错误之处,烦请不吝赐教。

前文回顾补充

计时器中断

计时器中断是操作系统重新夺回CPU控制权的一种方式,可以避免进程完全控制CPU。否则,进程可能会其中无限循环执行。硬件计时器可以在内核模式下被重置,达到中断的效果。
当前的计时器中断后,操作系统可以调度另一个进程运行,该进程可以是之前被中断的进程。

current privilege level(CPL,当前特权级)

x86体系结构中,在cs段寄存器中使用较低的两位作为当前特权级,也就是指示当前为用户态还是内核态。请添加图片描述

几个小问题

  1. 用户级代码总是运行在用户进程下吗?——是的
  2. 用户级代码总是运行在用户态下吗?——大多数是的,除了eBPF
  3. 内核级代码总是运行在系统进程下吗?——不是,中断处理程序运行在用户进程下。
  4. 内核级代码总是运行在内核态下吗?——不是,图形界面,UI界面运行在用户态下。
  5. 代码/CPU如何判断当前是处于用户态还是内核态?——通过2比特的cs段选择器

用户→内核模式切换

异常(exceptions)

异常,也称内中断,是指来自CPU执行指令内部的事件(同步的)。如程序的非法操作码、地址越界、运算溢出、虚存系统的缺页及专门的陷入指令等引起的事件。包括除数为0,执行特权指令等等。

中断(interrupts)

中断,也称外中断,是指来自CPU执行指令外部的事件(异步的),通常是信息输入输出,如设备发出的IO结束中断,表示设备输入输出处理已经完成;时间中断,表示一个固定的时间片已到,让处理机处理计时、启动定时运行的任务等等。

系统调用(system calls)

系统调用,指用户在程序中调用操作系统所提供的一些子功能,系统中的各种共享资源都由操作系统统一掌管,因此在用户程序中,凡是与资源有关的操作(如存储分配,IO传输与文件管理等),都必须通过系统调用的方式向操作系统提出服务请求,并由操作系统代为完成。请添加图片描述

中断向量表(IVT)

中断向量表存储了异常、中断、系统调用等不同处理程序的条目,其中每个条目指向内核中不同处理程序的第一条指令。(在实模式下使用,存在一个固定的位置)请添加图片描述
在x86架构中,总共有256个条目,每个条目占4字节。

中断描述符表(interrupt description table, IDT)

中断描述符表告诉CPU 中断服务程序(ISR)被加载到了哪里。(在保护模式下使用)
在中断描述符表中,每一个条目被称为“门”,一共有256个门。
在32位处理器上,每个门的长度为8字节,或在64位处理器上,每个门的长度为16字节。
其位置保存在IDTR,也就是IDT寄存器中(位置不固定),并用LIDT汇编指令加载。请添加图片描述

  • offset: 占32比特,被分为两部分,表示中断服务程序的地址。
  • selector: 段选择器,指向全局描述符表中的有效代码段。
  • gate type:4比特的值,定义中断描述符表表示的门类型:任务门,中断门,陷入门,系统调用门等等。
  • DPL: 2比特的值,定义允许通过INT访问此中断的CPU特权级。
  • P:当前位,必须设置为1才能使描述符有效。

如何从中断发生以后定位到中断处理程序?

寄存器IDTR指向中断描述符表的开头,根据中断号找到中断描述符表里面对应的项,从项内可以提取出offset。对于进程来说,每一段内存有一个基地址。把offset加到基地址上,就可以找到相应的中断处理程序。
中断号从硬件处得知。

中断向量表(IVT) vs 中断描述符表(IDT)

  • 好处:都保证了从用户到内核空间的入口数量有限,门的有限。好处在于写内核的时候只需要保证这几个门的安全性就可以了。
  • IVT运行在实模式下,IDT运行在保护模式下
  • IVT每个条目占4字节,IDT在32位处理器下占8字节,在64位处理器下占16字节
  • IVT通常位于0000:0000H,IDT可以位于内存中的任何位置,并通过LIDT指令进行定位

中断屏蔽

中断分为可屏蔽中断与不可屏蔽中断两种特权指令。

可屏蔽中断是指通过INTR线发出的中断请求,通过改变屏蔽字可以实现多重中断,从而使中断处理更加灵活(CPU可以响应也可以不响应)。所有的软件中断、所有的系统调用、以及部分硬件异常是可屏蔽中断。

不可屏蔽中断是指通过NMI线发出的中断请求,通常是紧急的硬件故障、如电源掉电等,CPU必须响应。此外,异常也是不能被屏蔽的。部分的硬件异常是不可屏蔽中断。通常由eflag寄存器指定。

屏蔽指的是中断被延迟而不是被忽略,也就是进入缓冲区buffer。

中断栈

中断栈是内核内存中(内核态)保存着中断程序状态的一种特殊的栈。当没有中断的时候中断栈为空,且运行在用户空间。
为了可靠性和安全性,中断栈没有直接使用用户空间的栈。
内核看到的memory也是虚拟地址,但是内核知道虚拟地址可以map到什么物理地址。

操作系统有几个中断栈?

答案:1×进程(线程)数量的中断栈
triple fault第三次中断:reboot
double fault第二次中断:进入一个新的中断处理程序,重新执行中断处理程序。且可以共享一个中断栈。
每一个进程或者线程都有自己的中断栈。这可以让操作系统更好地处理不同进程的中断。

内核→用户态模式切换

新生成了一个进程

用户发起操作,但是是以系统调用的方式在内核态下完成的。

中断、异常、系统调用恢复到用户态的程序

时间上的中断切换进程

upcalls 上行调用☆

与系统调用相反,是特权指令进入用户模式。由内核态来调用用户态的代码。

  • 异步IO通知
  • 进程之间的通信
  • 用户级异常处理——确保在应用程序关闭前保存文件
  • 用户级资源分配——JAVA垃圾回收

x86状态切换实例

背景知识

在x86中内存是分段的,每一个进程都有自己的一个段。在分段的内存里寻址需要两个寄存器。
找一段代码的时候用cs和eip两个寄存器。(寄存器的值没法直接改,但是可以用其他指令来更改)
找栈地址的时候用ss和esp两个寄存器。(可以改)
EFLAGS寄存器保存了处理器运行的状态,比如中断是否被屏蔽等等。
上述寄存器属于特殊目的寄存器,另一类是通用寄存器。
请添加图片描述

x86切换讲解请添加图片描述

cs eip 寄存器指向当前运行的代码;
ss esp 寄存器指向当前用的栈的位置;

中断、异常、系统调用发生以后,硬件做的事:

  • 首先把中断屏蔽掉,如果不屏蔽掉可能发生多级中断。
  • 把特殊寄存器的值存放到临时寄存器内。
  • 把栈从用户态切换到内核态的中断栈。
  • 把上述三个特殊寄存器的值存放到内核中断栈中。
  • 选择性地存放一些error code。
  • 然后调用内核的中断处理程序。
    请添加图片描述
    是否可以去掉第二步?
    为什么要先存放到临时寄存器内?而不是直接push?
    答:寄存器的值可能会被改变,现场就没有保存下来。

切换栈其实就是改ss esp寄存器的值。

中断、异常、系统调用发生以后,操作系统做的事:

  • 保存当前通用寄存器的值。可能保存了当前函数和当前进程执行上下文的信息。
  • 执行中断处理程序。
  • 恢复原来的进程。把刚刚push进来的值都pop出去。把栈里面的值又放回寄存器。
  • 还有几个硬件放进去的值,用ireturn语句将其pop出去。

为什么没有指向堆的寄存器?

因为不需要,指向栈是需要压栈和出栈。
堆是由用户库来维护的。

总结

中断处理程序对于用户来说是不可见的,并且不会改变程序的状态。
中断是安全的。其中有很多软硬协同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值