`
love19820823
  • 浏览: 944157 次
文章分类
社区版块
存档分类
最新评论

《深入理解Linux内核》--第四章 中断和异常:读书笔记

 
阅读更多

同步中断:只有在一条指令终止执行后CPU才会发出中断;
异步中断:由其它硬件设备依照CPU时钟信号随机产生的中断。
一般中断是指 异步中断。异常: 同步中断。

中断处理与进程切换的区别:中断或异常处理程序执行的代码不是一个进程,它是一个内核控制内经,代表中断发生时正在运行的进程执行。作为一个内核控制路径,中断处理程序比一个进程要“轻”。(没有进程要求那么多资源)

一、中断
分为:1)可屏蔽中断(maskable Interrupt);2)非屏蔽中断(nonmaskable Interrupt)
1)IRQ
IRQ线(即 外部中断 线):每个能够发出中断请求的硬件设备都有一条IRQ输出线,所有IRQ Line都和PIC硬件电路的输入引脚相连。PIC主要是用来监控IRQ线的信号。如果有信号产生则把信号向量发送到处理器的INTR引脚,产生一个中断。
IRQ分配给I/O时,一个IRQ的序号对应一个INT序号,INT序号即为CPU的INTR引脚序号。
IRQ从0开始编号,IRQn一般对应于Intel的缺省向量n+32。(注意LInux的128号向量用于系统调用的可编程的异常,32~127,129~238都用于IRQ)
中断请求在多处理器系统中分发方式:静态分发,动态分发。
数据结构式:irq_desc_t[NR_CPU],每个CPU对应一个irp_desc_t描述符

在多处理器系统中,kirqd()内核线程周期性执行do_irq_balance()函数,追踪最近时间间隔内每个CPU接收的中断次数。如果负荷不均匀,要么把一个IRQ从一个CPU转移到另一个CPU,要么让所有的IRQ在所有CPU之间“轮转”。

thread_info进程描述符:
union thread_union{
struct thread_info thread_info;
unsigned long stack[2048]; /*对4k的栈数组下表是1024 ,long是4byte */
}
如果为thread_union为8kB,则进程的内核栈被用于所有的内核控制路径:异常、中断和可延迟函数。(总共<=8K)
如果thread_union为4KB,则内核有三种类型的内核:异常栈、硬件请求栈(中断)、软中断请求栈(可延迟),它们是4KB对齐的,但是如果8KB的又都可以容下。

do_IRQ()函数执行与一个中断相关的所有中断服务例程,_ _do_IRQ()函数用于禁止本地中断运行。

I/O中断处理,两种不同方式:IRQ共享,IRQ动态分配
2)IDT
中断描述符表是一个系统表,内核在允许中断前必须初始化IDT,用lidt汇编指令初始化idtr。idtr CPU寄存器使 IDT可以位于内存的任何地方,idtr指定IDT的线性基地址及其限制(最大长度)。
描述符类型:task gate(任务门)、Interrupt gate、Trap gate
在初始化中断描述符表时,需要防止用户(用户态) int 指令(软件中断)模拟非法的中断和异常,通过吧中断或陷阱门描述符的DPL字段设置成0来实现。控制单元通过检查CPL 与 DPL的字段,如果不都为0(内核态)则有冲突,产生异常。

二、异常 (Divide error,Overflow,Double fault之类)
分为:1)故障(fault); 2)陷阱(trap);3)abort(异常中止);4)programmed exception(编程异常)
fault 和 trap 的区别:fault只要处理程序能纠正引起异常的反常条件,重新执行同一指令时必要的;
trap只有当没有必要重新执行已终止的指令时,才触发trap。

三、中断和异常的硬件处理
注意的地方:
1)需要比较CPL和DPL,如果CPL(0,内核态)小于DPL(3,用户态),则发生异常
2)在处理完后,相应的处理程序需要产生一条iret指令(非ret指令,ret用于用户程序)
在返回后,需要检查ds、es、fs和gs段寄存器的内容,如果其中一个包含的选择符是一个段描述符,并且DPL(0)值小于CPL(3)(也就是说当前的为用户态),需要清除相应的段寄存器。为了禁止用户态程序利用以前所用的段寄存器(DPL=0),恶意利用它们来访问内核地址空间。
3)内核控制路径嵌套执行。中断处理程序运行期间不允许进程切换。
异常处理程序引发 相关的 至多两个内核控制路径(第一个由系统调用引起,第二个由(缺页)异常)。

四、软中断(softirq) 和 tasklet
软中断可以并发地运行在多个CPU上。是可重入函数,必须明确地使用自旋锁保护其数据结构。
tasklet:同类型的tasklet总是被串行地执行,不能再两个CPU上同时运行相同类型的tasklet(类型不同的tasklet可以,分为普通的TASTKLET_SOFTIQT和HI_SOFTIRQ两种,即普通的和高级的)。是可重入的函数。
1)软中断
软中断对应的处理函数是:do_softirq(),使用的数据结构:softirq_vec[n].
preempt_count的字段中各位意思:抢占计数器(0~7)、软中断计数器(8~15)、硬中断计数器(16~27)、PREEMPT_ACTIVE标志(28)
in_interrupt()检查current_thread_info()->preempt_count字段的硬中断计数器和软中断计数器,只要这两个计数器中的一个值为正数,该宏就产生一个非零值。
raise_softirq()激活软中断,wakeup_softiqrd()唤醒本地CPU的ksoftirqd内核线程,do_softirq()来处理检测到的被挂起的软中断,_ _do_softirq()读取本地CPU的 软中断掩码 并执行与每个设置位相关的可延迟函数。
ksoftirq内核线程 解决了软中断的连续高流量(如网络中断)可能产生的问题。其代码如下:
for(::){
set_current_state(TASK_INTERRUPTIBLE);
schedule();
while(local_softirq_pending()){
preempt_disable();
do_softirq();
preempt_enable();
cond_resched();
}
}

2)tasklet
TASKLET_SOFTIRQ软中断类型对应的处理函数是:tasklet_action(),数据结构:tasklet_vec[n]
HI_SOFTIRQ软中断对应的处理函数:tasklet_hi_action(),数据结构:tasklet_hi_vec[n]
I/O驱动程序实现可延迟函数的首选方法:tasklet。
在tasklet_vec[n]或tasklet_hi_vec[n]指向的链表起始处增加taskl描述符(n表示本地CPU的逻辑号)
调用raise_softirq_irqoff()激活TASKLET_SOFTIRQ或HI_SOFTIRQ类型的软中断。

五、工作队列
描述符:workqueue_struct,数组元素个数:NR_CPUS
工作队列和可延迟函数(软中断)的区别:可延迟函数运行在中断上下文中,工作队列中的函数运行在进程上下文中。
相同:他们都不能访问进程的用户态地址空间。
工作队列的函数是有内核线程来执行的。

六、从中断和异常返回
1) ret_from_intr() 和 ret_from_exception() 入口点相当于:
ret_from_exception:
cli; missing if kernel preemption is not supported
ret_from_intr:
movl $-8192, %ebp ; -4096 if multiple Kernel Mode Stacks are used;8192(8K)
andl %esp, %ebp
movl 0x30(%esp), %eax
movb 0x2c(%esp), %a1
test1 $0x00020003, %eax
jnz resume_userspace
jpm resume_kernel
如果被恢复的程序在内核态,就需要resum_kernel,检查thread_info描述符的preempt_count字段,若为0则内核跳到need_resched检查内核抢占,所有没有执行完的内核控制路径都不是中断处理程序,否则preempt_count字段的值就会大于0。若preempt_count为不为0,则被中断的程序重新开始执行(直接restore_all)
在need_resched中,如果current->thread_info的flags字段中的TIF_NEED_RESCHED标志为0,说明没有需要切换进程,直接跳到restore_all恢复用户态程序。如果TIF_NEED_RESCHED不为0,则调用preempt_schedule_irq(),设置preempt_count字段的PREEMPT_ACTIVE标志,把大内核锁计数器暂时设置为-1,打开本地中断调用schedule()选择另一个进程运行;当前面的进程要恢复是,preempt_schedule_irq()使大内核计数器的值恢复为以前的值,清除PREEMPT_ACTIVE标志并且禁用本地中断。
resume_userspace,检查cureent->thread_info的flags字段的值,如果只设置了TIF_SYSCALL_TRACE、TIF_SYSCALL_AUDIT或TIF_SINGLESTEP标志,就不做任何其他事情,直接跳到restore_all,恢复用户程序。

七、附录

常见缩写:
IRQ(Interrupt ReQuest)中断请求
PIC(Programmable Interrupt Controller)可编程中断控制器
cli(clear Interrupt)、sti(set Interrupt)汇编指令分别清除和设置eflags寄存器的IF(Interrupt Flag)标志。
APIC(I/O Advanced Programmable Interrupt Controller)I/O高级可编程控制器
IRT(Interrupt Redirection Table)中断重定向表
IDT (Interrupt Descriptor Table)中断描述符表
DPL (Descriptor Priviledge Level) 描述符特权等级

内核中比较重要的函数、宏及变量
local_irq_save()用来保存IF标志的状态并禁用本地中断
local_irq_restore()恢复IF标志的状态
do_IRQ()
_ _do_IRQ()
set_task_gate(8,31);表示存放IDT的第8想中的任务门描述符,指向存放在GDT表中第32项的TSS段描述符。
preempt_count抢占计数字段,preempt中文意思:抢占
do_softirq(),检测到挂起的软件中断,内核调用该函数来处理它们。
_ _do_softirq()
ksoftirq/n内核线程(n为CPU的逻辑号)

注:这书里面挺侧重分析 多处理器 架构,Linux内核对多处理器的支持做了很多工作。
PS:这一章后面一些看的比较快,比较草率~

分享到:
评论

相关推荐

    joyfire的linux内核笔记

    Linux内核启动过程是操作系统核心运行的起点,涉及到一系列复杂而...了解这些启动步骤和初始化过程对于深入理解Linux内核的工作原理至关重要,有助于开发者调试和优化内核,以及解决与系统启动和资源管理相关的问题。

    linux内核设计与实现第二版 学习笔记

    通过阅读《Linux内核设计与实现》第二版的学习笔记,可以深入了解这些核心概念,并掌握如何分析和调试内核,这对于系统管理员、软件开发者或者对操作系统感兴趣的任何人都极其有价值。这份笔记详尽地介绍了Linux内核...

    Linux内核分析(《joyfire linux笔记》)

    Linux内核分析是一项深入理解操作系统核心机制的关键任务,尤其是在《joyfire Linux笔记》这样的资源中,我们可以获取到丰富的信息。这篇笔记涵盖了Linux内核的多个关键领域,包括启动流程、中断处理、内存管理、...

    《Linux内核设计与实现》 第一章 读书笔记 Linux内核简介

    《Linux内核设计与实现》 第一章 读书笔记 Linux内核简介 面试被怼了Linux内核,于是决定好好看一下这本书。作为经典书籍,Linux内核设计与实现是一本很重要的书籍。在大学本科的课程中已经学习过有关操作系统的内容...

    Linux内核相关资料和设计与实现

    通过阅读注释,开发者可以更直观地看到代码是如何与硬件交互,如何实现调度策略,以及如何处理中断和异常等关键任务的。 "Linux内核学习资料"可能包含各种教程、笔记、实践项目和问题解答,旨在帮助初学者或有经验...

    linux驱动开发详解(1-23章)

    书中的23章内容详细地解析了Linux内核驱动程序开发的各个方面,旨在帮助读者深入理解Linux内核机制,并具备实际编写驱动的能力。 在Linux驱动开发中,首先要理解的是Linux内核的基本架构。Linux内核是操作系统的...

    嵌入式Linux入门笔记

    5. 模块编程实验:讲解了如何编写和加载Linux内核模块,理解内核与用户空间的交互,这是进行内核定制和驱动开发的基础。 6. 简单的字符设备驱动实验:介绍如何为简单的硬件设备编写驱动程序,这是理解驱动开发的第...

    linux驱动程序设计学习笔记

    本笔记基于《Linux设备驱动程序》第三版,该书是Linux驱动开发的经典之作,为我们提供了深入理解Linux内核驱动模型的宝贵资源。 一、Linux驱动程序基础 Linux驱动程序是内核中的软件模块,它们为硬件设备提供了一个...

    韦东山二期驱动笔记

    这份笔记深入浅出地讲解了Linux内核驱动开发的基础与实践,旨在帮助读者理解和掌握Linux系统下的设备驱动编写技巧。Linux驱动是操作系统与硬件设备之间的桥梁,它使得操作系统能够有效控制和利用硬件资源。 笔记...

    linux v 0.01版本的源码和注释

    在阅读和分析Linux 0.01内核源码的过程中,我们可以深入理解以下几个关键知识点: 1. **内核初始化**:在源码中,你会看到内核启动过程的第一步,包括设置内存管理、设备初始化和进程调度等基础功能。这些代码展示...

    《鸟哥的Linux私房菜》读书笔记1

    《鸟哥的Linux私房菜》读书笔记1主要涵盖了Linux操作系统的基础知识,包括文件系统、权限管理、shell命令以及特殊权限。以下是对这些知识点的详细解释: 1. **Linux 文件属性与链接**: - **软链接(符号链接)** ...

    嵌入式linux学习笔记

    Linux内核是Linux操作系统的核心,负责管理硬件资源、调度任务、处理中断等。在嵌入式系统中,内核通常需要裁剪和优化以适应有限的硬件资源,例如内存大小、处理器性能等。 三、交叉编译环境 由于嵌入式设备的硬件...

    linux设备驱动程序

    这份学习笔记包含了对第三版的详细解读,旨在帮助读者理解Linux内核与硬件设备之间的交互机制,以及如何有效地编写和管理设备驱动。 Linux设备驱动程序是操作系统和硬件设备之间的桥梁,它们负责处理硬件的特定功能...

    嵌入式linux入门笔记.rar

    5. **Linux内核编译与裁剪**:内核是Linux的核心,你需要学会如何根据目标硬件配置和应用需求来编译和裁剪内核源码。这包括选择必要的驱动程序、设置内存管理策略等。 6. **根文件系统构建**:根文件系统包含了运行...

    若干源程序资料12.rar

    2012-06-11 21:44 6,947,979 Linux内核完全注释V3.0书签版(带源码).rar 2012-06-11 21:31 11,599 MATLAB仿真程序OFDM程序.txt 2012-06-11 21:37 14,584,477 msdn for vb6.0简体中文版.zip 2012-06-11 21:02 12,288 ...

    linux设备驱动学习

    在这个学习笔记中,我们将深入探讨Linux内核如何与各种硬件设备进行通信,以及如何编写和调试设备驱动程序。 首先,理解Linux设备驱动的基本概念至关重要。设备驱动是操作系统的一部分,它提供了操作系统与硬件设备...

    嵌入式设备驱动学习笔记

    《内核配置参考.doc》文档将指导你如何根据具体硬件配置Linux内核,这涉及到选择合适的驱动模块,裁剪不必要的功能,以优化嵌入式系统的性能和资源利用率。内核配置是嵌入式系统开发的第一步,因为它直接影响到设备...

    Linux驱动程序开发资料汇集

    6. "Linux驱动开发庖丁解牛之二——模块编程.pdf":这个文件可能是关于Linux内核模块编程的教程,模块是驱动程序的一种动态加载形式,可以方便地插入或移除内核,该文档可能会深入探讨模块的生命周期、加载和卸载...

    驱动二期学习笔记

    总结,"驱动二期学习笔记"是关于JZ2440处理器驱动开发和U-Boot使用的实践经验分享,对于想要深入理解嵌入式系统底层操作,特别是驱动程序开发的IT从业者来说,是非常有价值的学习材料。通过系统阅读和实践这些笔记,...

Global site tag (gtag.js) - Google Analytics