linux总结-第一讲-中断和异常

中断与异常

一、中断(广义):会改变处理器执行指令的顺序,通常与CPU芯片内部或外部硬件电路产生的电信号相对应
  1. 中断——异步的:由硬件随机产生,在程序执行的任何时候可能出现
  2. 异常——同步的:在(特殊的或出错的)指令执行时由CPU控制单元产生
  3. 我们用“中断信号”来通称这两种类型的中断
二、中断信号的作用
  1. 中断信号提供了一种特殊的方式,使得CPU转去运行正常程序之外的代码
  2. 当一个中断信号到达时,CPU必须停止它当前正在做的事,并且切换到一个新的活动
    1. 在进程的内核态堆栈保存程序计数器的当前值(即eip和cs寄存器)以便处理完中断的时候能正确返回到中断点
    2. 并把与中断信号相关的一个地址放入进程序计数器,从而进入中断的处理
三、中断信号的处理原则
  1. 内核的目标就是让中断尽可能快的处理完,尽其所能把更多的处理向后推迟
  2. 允许不同类型中断的嵌套发生,这样能使更多的I/O设备处于忙状态
  3. 尽管内核在处理一个中断时可以接受一个新的中断,但在内核代码中还在存在一些临界区,在临界区中,中断必须被禁止
四、中断上下文
  1. 中断上下文不同于进程上下文

    1. 中断或异常处理程序执行的代码不是一个进程。它是一个内核控制路径,代表了中断发生时正在运行的进程执行
    2. 作为一个进程的内核控制路径,中断处理程序比一个进程要“轻”(中断上下文只包含了很有限的几个寄存器,建立和终止这个上下文所需要的时间很少)
五、由于Linux不为中断处理程序设置process context,A只能使用 C的kernel stack作为自己的运行栈
  1. 无论如何,Linux的interrupt context A绝对不会被某个进程C或者D抢占!!!
  2. 这是由于所有已经启动的interrupt contexts,不管是interrupt contexts之间切换,还是在某个interrupt context中执行代码的过程,决不可能插入scheduler调度例程的调用。
  3. 除非interrupt context主动或者被动阻塞进入睡眠,唤起scheduler,但这是必须避免的,危险性见第3点说明
    1. 首先,interrupt context没有process context,A中断是“借”了C的进程上下文运行的,若允许A“阻塞”或“睡眠”,则C将被迫阻塞或睡眠,仅当A被“唤醒”C才被唤醒;而“唤醒”后,A将按照C在就绪队列中的顺序被调度。这既损害了A的利益也污染了C的kernel stack。
    2. 其次,如果interrupt context A由于阻塞或是其他原因睡眠,外界对系统的响应能力将变得不可忍受
六、那么interrupt context A和B的关系又如何呢?
  1. 由于可能在interrupt context的某个步骤打开了CPU的IF flag标志,这使得在A过程中,B的irq line已经触发了PIC,进而触发了CPU IRQ pin,使得CPU执行中断B的interrupt context,这是中断上下文的嵌套过程。
  2. 通常Linux不对不同的interrupt contexts设置优先级,这种任意的嵌套是允许的
  3. 当然可能某个实时Linux的patch会不允许低优先级的interrupt context抢占高优先级的interrupt context

I/O设备如何引起CPU中断

七、中断分为:
  1. 可屏蔽中断(Maskable interrupt)

    1. I/O设备发出的所有中断请求(IRQ)都可以产生可屏蔽中断。
    2. 可屏蔽中断可以处于两种状态:屏蔽的(masked)和非屏蔽的(unmasked)
  2. 非屏蔽中断(Nonmaskable interrupt)
    1. 只有几个特定的危急事件才引起非屏蔽中断。如硬件故障或是掉电
八、异常分为:
  1. 处理器探测异常

    1. 由CPU执行指令时探测到一个反常条件时产生,如溢出、除0错等
  2. 编程异常
    1. 由编程者发出的特定请求产生,通常由int类指令触发
    2. 通常叫做“软中断”:例如系统调用
九、对于处理器探测异常,根据异常时保存在内核堆栈中的eip的值可以进一步分为:
  1. 故障(fault):eip=引起故障的指令的地址

    1. 通常可以纠正,处理完异常时,该指令被重新执行:例如缺页异常
  2. 陷阱(trap):eip=随后要执行的指令的地址。
  3. 异常中止(abort):eip=???
    1. 发生严重的错误。eip值无效,只有强制终止受影响的进程
十、中断向量
  1. 每个中断和异常由0~255之间的一个数(8位)来标识,Intel称其为中断向量。
  2. 非屏蔽中断的向量和异常的向量是固定的
  3. 可屏蔽中断的向量可以通过对中断控制器的编程来改变
十一、中断的产生
  1. 每个能够发出中断请求的硬件设备控制器都有一条称为IRQ(Interrupt ReQuest)的输出线。
  2. 所有的IRQ线都与一个中断控制器的输入引脚相连
  3. 中断控制器与CPU的INTR引脚相连
十二、中断控制器执行下列动作:
  1. 监视IRQ线,对引发信号检查
  2. 如果一个引发信号出现在IRQ线上
    1. 把此信号转换成对应的中断向量
    2. 把这个向量存放在中断控制器的一个I/O端口,从而允许CPU通过数据总线读这个向量
    3. 把引发信号发送到处理器的INTR引脚,即产生一个中断
    4. 等待,直到CPU应答这个信号;收到应答后,清INTR引脚
  3. 返回到第一步(a)
十三、IRQ号和中断向量号
  1. 中断控制器对输入的IRQ线从0开始顺序编号
  2. Intel给中断控制器分配的中断向量号从32开始,上述IRQ线对应的中断向量依次是:32+0、32+1、…
  3. 可以对中断控制器编程:
    1. 修改起始中断向量的值,或
    2. 有选择的屏蔽/激活每条IRQ线
  4. 屏蔽的中断不会丢失
    1. 一旦被激活,中断控制器又会将它们发送到CPU
  5. 有选择的屏蔽/激活IRQ线≠全局屏蔽/激活
    1. 前者通过对中断控制器编程实现
    2. 后者通过特定的指令操作CPU中的状态字
十四、I386:开中断和关中断
  1. CPU可以将屏蔽所有的可屏蔽终端
  2. Eflags中的IF标志:

    0=关中断;

    1=开中断。

  3. 关中断时,CPU不响应中断控制器发布的任何中断请求
  4. 内核中使用cli和sti指令分别清除和设置该标志
十五、8259A:禁止/激活某个IRQ线

十六、中断描述符表(Interrupt Descriptor Table,IDT)
  1. 中断描述符表是一个系统表,它与每一个中断或者异常向量相联系

    1. 每个向量在表中有相应的中断或者异常处理程序的入口地址。
    2. 每个描述符8个字节,共256项,占用空间2KB。
    3. 内核在允许中断发生前,必须适当的初始化IDT
  2. CPU的idtr寄存器指向IDT表的物理基地址
    1. 在允许中断之前,必须用lidt汇编指令初始化idtr。
十七、IDT包含3种类型的描述符

a)

b)

c)

x86 CPU如何在硬件级处理中断信号

十八、中断和异常的硬件处理进入中断/异常
  1. 假定:内核已经初始化,CPU在保护模式下运行
  2. CPU的正常运行:
    1. 当执行了一条指令后,cs和eip这对寄存器包含了下一条将要执行的指令的逻辑地址。
    2. 在执行这条指令之前,CPU控制单元会检查在运行前一条指令时是否发生了一个中断或者异常。
    3. 如果发生了一个中断或异常,那么CPU控制单元执行下列操作:
      1. 确定与中断或者异常关联的向量i(0~255)
      2. 读idtr寄存器指向的IDT表中的第i项
      3. 从gdtr寄存器获得GDT的基地址,并在GDT中查找,以读取IDT表项中的段选择符所标识的段描述符
      4. 确定中断是由授权的发生源发出的。
        1. 中断:中断处理程序的特权不能低于引起中断的程序的特权(对应GDT表项中的DPL vs CS寄存器中的CPL
        2. 编程异常:还需比较CPL与对应IDT表项中的DPL
      5. 检查是否发生了特权级的变化,一般指是否由用户态陷入了内核态。如果是由用户态陷入了内核态,控制单元必须开始使用与新的特权级相关的堆栈
        1. 读tr寄存器,访问运行进程的tss段
        2. 用与新特权级相关的栈段和栈指针装载ss和esp寄存器。这些值可以在进程的tss段中找到
        3. 在新的栈中保存ss和esp以前的值,这些值指明了与旧特权级相关的栈的逻辑地址
      6. 若发生的是故障,用引起异常的指令地址修改cs和eip寄存器的值,以使得这条指令在异常处理结束后能被再次执行
      7. 在栈中保存eflags、cs和eip的内容
      8. 如果异常产生一个硬件出错码,则将它保存在栈中
      9. 装载cs和eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段。这对寄存器值给出中断或者异常处理程序的第一条指定的逻辑地址
  3. 此时的进程内核态堆栈
十九、从中断/异常返回
  1. 中断/异常处理完后,相应的处理程序会执行一条iret汇编指令,这条汇编指令让CPU控制单元做如下事情:

    1. 用保存在栈中的值装载cs、eip和eflags寄存器。如果一个硬件出错码曾被压入栈中,那么弹出这个硬件出错码
    2. 检查处理程序的特权级是否等于cs中最低两位的值(这意味着进程在被中断的时候是运行在内核态还是用户态)。若是,iret终止执行;否则,转入3
    3. 从栈中装载ss和esp寄存器。这步意味着返回到与旧特权级相关的栈
    4. 检查ds、es、fs和gs段寄存器的内容,如果其中一个寄存器包含的选择符是一个段描述符,并且特权级比当前特权级高,则清除相应的寄存器。这么做是防止怀有恶意的用户程序利用这些寄存器访问内核空间

Linux内核中软件级中断处理及其数据结构

二十、中断和异常处理程序的嵌套执行
  1. 当内核处理一个中断或异常时,就开始了一个新的内核控制路径
  2. 当CPU正在执行一个与中断相关的内核控制路径时,linux不允许进程切换。不过,一个中断处理程序可以被另外一个中断处理程序中断,这就是中断的嵌套执行
二十一、抢占原则
  1. 普通进程可以被中断或异常处理程序打断
  2. 异常处理程序可以被中断程序打断
  3. 中断程序只可能被其他的中断程序打断
二十二、Linux允许中断嵌套的原因
  1. 提高可编程中断控制器和设备控制器的吞吐量
  2. 实现了一种没有优先级的中断模型
二十三、初始化中断描述符表
  1. 内核启动中断前,必须初始化IDT,然后把IDT的基地址装载到idtr寄存器中
  2. int指令允许用户进程发出一个中断信号,其值可以是0-255的任意一个向量。
    1. 用户态程序特权级:3。内核态是:0。
  3. Linux中的中断门、陷阱门和系统门定义
    1. 中断门

      1. 用户态的进程不能访问的一个Intel中断门(特权级为0),所有的中断都通过中断门激活,并全部在内核态
    2. 系统门
      1. 用户态的进程可以访问的一个Intel陷阱门(特权级为3),通过系统门来激活4个linux异常处理程序,它们的向量是3,4,5和128。因此,在用户态下可以发布int3,into,bound和int $0x80四条汇编指令
    3. 陷阱门
      1. 用户态的进程不能访问的一个Intel陷阱门(特权级为0),大部分linux异常处理程序通过陷阱门激活
  4. 进入保护模式前IDT表的初始化:setup_idt()
二十四、异常的处理
  1. CPU产生的大部分异常都由linux解释为出错条件。

    当一个异常发生时,内核就向引起异常的进程发送一个信号通知它发生了一个反常条件

  2. 异常处理有一个标准的结构,由三部分组成
    1. 在内核态堆栈中保存大多数寄存器的内容
    2. 调用C语言的函数
    3. 通过ret_from_exception()从异常处理程序退出
  3. entry_32.S中error_code()该函数的主要功能:
    1. 按照pt_regs结构定义的堆栈数据格式完成相应的入栈操作,进一步完成现场的保存
    2. 把堆栈地址中的do_handler_name()函数的地址装入edi寄存器中,并在这个位置写入fs值,使栈结构进一步与pt_regs结构完全一致。
    3. 最后执行call *%edi指令
二十五、中断处理
  1. 中断跟异常不同,它并不是表示程序出错,而是硬件设备有所动作,所以不是简单地往当前进程发送一个信号就OK的
  2. 主要有三种类型的中断
    1. I/O设备发出中断请求
    2. 时钟中断
    3. 处理器间中断
  3. 处理程序都执行四个相同的基本操作
    1. 在内核态堆栈保存IRQ的值和寄存器的内容
    2. 为正在给IRQ线服务的PIC发送一个应答,这将允许PIC进一步发出中断
    3. 执行共享这个IRQ的所有设备的中断服务例程
    4. 跳到ret_from_intr()的地址后中断跳出
  4. 系统初始化时,调用init_IRQ()函数用新的中断门替换临时中断门来更新IDT。(调用init_IRQ()函数,把中断描述附表的中断处理代码段地址设在在interrupt数组中,该数组指向同一个函数处理common_interrupt)
  5. common_interrupt的功能:
    1. SAVE_ALL movl %esp,%eax call do_IRQ jmp $ret_from_intr
  6. do_IRQ()函数功能
  7. irqaction数据结构
    1. 用来实现IRQ的共享,维护共享irq的特定设备和特定中断,所有共享一个irq的链接在一个action表中,由中断描述符中的action指针指向
  8. 中断服务例程
    1. 一个中断服务例程实现一种特定设备的操作, handle_IRQ_evnet()函数依次调用这些设备例程
    2. 这个函数本质上执行了如下核心代码:
  9. 中断程序的注册:注册外部中断
    1. 一个模块被希望来请求一个中断通道(或者 IRQ, 对于中断请求), 在使用它之前要注册它, 并且当结束时释放它. 函数声明在
二十六、软中断、tasklet以及下半部分
  1. 对内核来讲,可延迟中断不是很紧急,可以将它们从中断处理例程中抽取出来,保证较短的中断响应时间
  2. Linux2.6提供了三种方法
    1. 可延迟的函数

      1. 软中断、tasklet

        1. Tasklet在软中断之上实现
        2. 一般原则:在同一个CPU上软中断/tasklet不嵌套
        3. 软中断由内核静态分配(编译时确定)
        4. Tasklet可以在运行时分配和初始化(例如装入一个内核模块时)
    2. 工作队列( work queues )
二十七、一般而言,可延迟函数上可以执行4种操作
  1. 初始化:定义一个新的可延迟函数,通常在内核初始化时进行
  2. 激活:设置可延迟函数在下一轮处理中执行
  3. 屏蔽:有选择的屏蔽一个可延迟函数,这样即使被激活也不会被运行
  4. 执行:在特定的时间执行可延迟函数
二十八、软中断的处理机制:
  1. 分别在softirq_init和net_dev_init、blk_dev_init等中通过open_softirq()初始化
二十九、在某些特定的时机,会检查是否有软中断被挂起
  1. 调用local_bh_enable重新激活软中断时
  2. 当do_IRQ完成了I/O中断的处理时
  3. 当那个特定的进程ksoftirqd被唤醒时
三十、Tasklet
  1. Tasklet是I/O驱动程序中实现可延迟函数的首选方法
  2. 建立在HI_SOFTIRQ和TASKLET_SOFTIRQ等软中断之上
  3. Tasklet和高优先级的tasklet
    1. 分别存放在tasklet_vec和tasklet_hi_vec数组中

      1. 数组的每一项针对一个CPU,代表这个CPU上的tasklet列表
    2. 分别由tasklet_action和tasklet_hi_action处理
      1. 找到CPU对应的那个项,遍历执行
三十一、Tasklet的使用
  1. 分配一个tasklet的数据结构,并初始化====相当于声明(定义)一个tasklet
  2. 可以禁止/允许这个tasklet====相当于定义了一个是否允许使用tasklet的窗口
  3. 可以激活这个tasklet====这个tasklet被插入task_vec或者task_hi_vec的相应CPU的链表上,将在合适的时机得到处理
    1. 激活tasklet的方法

      1. Tasklet_schedule
      2. Tasklet_hi_schedule
三十二、工作队列workqueue
  1. 工作队列和tasklet这两种下半部机制的主要区别在于:

    1. Tasklet在软中断的上下文中运行,所有的代码必须是原子的,不能睡眠、不能使用信号量或其它产生阻塞的函数;
    2. 工作队列在一个内核线程上下文运行,并且可以在延迟一段确定的时间后才执行;有更多的灵活性,它可以使用信号量等能够睡眠的函数。


参考资料:

深入理解Linux内核

备注:

转载请注明出处:http://blog.csdn.net/wsyw126/article/details/51803727

作者:WSYW126

时间: 2024-10-08 20:50:32

linux总结-第一讲-中断和异常的相关文章

深入理解Linux内核-中断和异常

Linux内核代码查看 http://androidxref.com/ 中断:被定义位一个事件,它能改变处理器执行指令的顺序.它对应硬件(CPU.其他硬件设备)电路产生的电信号. 同步中断:指令执行时CPU控制单元产生:称为同步,是因为只有在一条指令终止执行后CPU才回发出中断.也被称为异常 异步中断:其他硬件设备按照CPU时钟信号随机产生的.也被简称中断 中断的约束:1.中断必须尽快处理完成:中断一般被分两部分执行:关键而且紧急的部分,内核立即执行:其余部分内核稍后执行: 2.中断的处理必须能

Linux 2.6 内核阅读笔记 中断和异常

2014年7月24日 中断门.陷阱门及中断门 中断是可以禁止的,可以通过告诉PIC停止对某个中断的发布.被禁止的中断是不会丢失的,在解除禁止后又会发送到CPU上. 禁止中断和屏蔽(mask)中断的不同之处是屏蔽是忽略掉某个中断,而禁止相当于延迟发送. Intel提供了三种类型的中断描述符:任务门.中断门及陷阱门描述.linux使用与inten稍有不同的细分分类和术语,把他们进行如下分类: 中断门:用户态进程不能访问的一个intel中断门(DPL为0),所有的linux中断处理程序都通过中断门在内

Scrapy爬虫框架第一讲(Linux环境)

1.What is Scrapy? 答:Scrapy是一个使用python语言(基于Twistec框架)编写的开源网络爬虫框架,其结构清晰.模块之间的耦合程度低,具有较强的扩张性,能满足各种需求.(前面我们介绍了使用requests.beautifulsoup.selenium等相当于你写作文题,主要针对的是个人爬虫:而Scrapy框架的出现给了我们一个方便灵活爬虫程序架构,我们只需针对其中的组件做更改,即可实现一个完美的网络爬虫,相当于你做填空题!) 基于Scrapy的使用方便性,下面所有的S

第二课:第一讲Linux操作系统及常用命令

第二课:第一讲Linux操作系统及常用命令1.liunx中"X"表示图像显示协议X-window有三种:Gnome,KDE,Xface2.windows->.dll(dynamic link library)liunx->.so (shared object)3.认证:authentication授权:authorization审计:audition(通过日志记录下来实现审计机制)4.登录成功后的"[[email protected] root]"是pr

Linux内核中断和异常分析(下)

这节,我们继续上,中(以前的日志有)篇目进行分析,结合一个真实的驱动案例来描述linux内核中驱动的中断机制,首先我们先了解一下linux内核中提供的中断接口. 这个接口我们需要包含一个头文件:#include <linux/interrupt.h> 在中断接口中,最重要的是以下的接口函数: 1.这个是请求中断函数 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const cha

一个操作系统的实现(9)-中断和异常

这节讲了中断与异常的一些基本概念.然后通过代码实现一个显示字符的中断和时钟中断. 实模式与保护模式下的中断有区别 保护模式下的中断与实模式下的中断有几点不同. 实模式下的中断向量表在保护模式下被IDT取代 实模式下可以使用BIOS中断,而保护模式下不能用 这里面出现了一个新的名词IDT,接下来就介绍什么是IDT. 中断描述符表(IDT,Interrupt Descriptor Table) 中断描述符表的作用 与GDT和LDT一样,IDT也是一个描述符表,IDT的描述符可以是下面三种之一: 中断

基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)

作者:彭东林 邮箱:[email protected] QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面几篇博文列举了在有设备树的时候,gpio中断的用法示例.下面我们尝试分析一下Linux内核是如何做到的,如果哪写的有问题,欢迎大家批评指正,谢谢. 还是以GPIO中断为例分析,对于tiny4412,gpio中断可以分为两种,外部中断和普通的GPIO中断 外部中断:按键中断分别使用了外部中断XEINT26.XEINT27.XEINT28以及XEINT29,

中断、异常和系统调用

所谓中断是指CPU对系统发生的某个事件做出的一种反应,CPU暂停正在执行的程序,保留现场后自动地转去执行相应的处理程序,处理完该事件后再返回断点继续执行被"打断"的程序. 中断可分为三类,第一类是由CPU外部引起的,称作中断,如I/O中断.时钟中断.控制台中断等.第二类是来自CPU的内部事件或程序执行中的事件引起的过程,称作异常,如由于CPU本身故障(电源电压低于105V或频率在47-63Hz之外).程序故障(非法操作码.地址越界.浮点溢出等)等引起的过程. 第三类由于在程序中使用了请

操作系统的中断、异常和系统调用

温习一下,从学堂在线学习到关于<操作系统的中断.异常和系统调用>的知识.这门课是清华大学向勇老师讲授的.向勇老师讲得比较接地气,通俗易懂.喜欢操作系统的朋友可以到该网站去注册一个账号,就可以看到课程内容了.网址:www.xuetangx.com ------------------------------------------------------------------------------------------------------------------------------