今天学习关于内核的中断
抛砖引玉:
提出问题:
1.请简述中断的处理过程
贴上一个百科知识中断
还找了一个关于异常和中断的关系的中断与异常的区别
CPU对中断处理的流程
我们首先必须了解CPU在接收到中断信号时会做什么。没办法,操作系统必须了解硬件的机制,不配合硬件就寸步难行。现在我们假定内核已被初始化,CPU在保护模式下运行。
CPU执行完一条指令后,下一条指令的逻辑地址存放在cs和eip这对寄存器中。在执行新指令前,控制单元会检查在执行前一条指令的过程中是否有中断或异常发生。如果有,控制单元就会抛下指令,进入下面的流程:
1.确定与中断或异常关联的向量i (0£i£255)。
2.籍由idtr寄存器从IDT表中读取第i项(在下面的描述中,我们假定该IDT表项中包含的是一个中断门或一个陷阱门)。
3.从gdtr寄存器获得GDT的基地址,并在GDT表中查找,以读取IDT表项中的选择符所标识的段描述符。这个描述符指定中断或异常处理程序所在段的基地址。
4.确信中断是由授权的(中断)发生源发出的。首先将当前特权级CPL(存放在cs寄存器的低两位)与段描述符(存放在GDT中)的描述符特权级DPL比较,如果CPL小于DPL,就产生一个“通用保护”异常,因为中断处理程序的特权不能低于引起中断的程序的特权。对于编程异常,则做进一步的安全检查:比较CPL与处于IDT中的门描述符的DPL,如果DPL小于CPL,就产生一个“通用保护”异常。这最后一个检查可以避免用户应用程序访问特殊的陷阱门或中断门。
5.检查是否发生了特权级的变化,也就是说, CPL是否不同于所选择的段描述符的DPL。如果是,控制单元必须开始使用与新的特权级相关的栈。通过执行以下步骤来做到这点:
a.读tr寄存器,以访问运行进程的TSS段。
b.用与新特权级相关的栈段和栈指针的正确值装载ss和esp寄存器。这些值可以在TSS中找到(参见第三章的“任务状态段”一节)。
c.在新的栈中保存ss和esp以前的值,这些值定义了与旧特权级相关的栈的逻辑地址。
6.如果故障已发生,用引起异常的指令地址装载cs和eip寄存器,从而使得这条指令能再次被执行。
7.在栈中保存eflag、cs及eip的内容。
8.如果异常产生了一个硬错误码,则将它保存在栈中。
9.装载cs和eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量域。这些值给出了中断或者异常处理程序的第一条指令的逻辑地址。
————————————————
版权声明:本文为CSDN博主「七七侠」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/kanghua/article/details/1843788
2.中断源有哪些
一般来说,外部硬件中断主要有以下几种:
一、I/O设备:如显示器、键盘、打印机等。
二、数据通道:软盘、硬盘、光盘等。
三、实时时钟:如外部的定时电路等。
四、用户故障源:如掉电、奇偶校验错误等。
产生于CPU内部的软件中断源有几种:
一、由CPU得运行结果产生:如除数为0、结果溢出、单步执行等。
二、执行中断指令INT:INT3
三、非法操作或指令引起异常处理。
3.中断发生时 暂停当前任务的时候采用的是哪一种处理方式(涉及哪些数据和结构)
4.中断的分类有哪些
软硬中断
5.恢复现场涉及的操作有哪些
从字面的意思也可以看成,这部分的代码就是将进入中断的时候保存的现场(寄存器值)恢复到实际的ARM的各个寄存器中,从而完全返 回到了中断发生的那一点
IRQ和FIQ
查询所用处理器的中断数据(查询用户手册)
以tiny4412为例
内核中断的操作过程
linux系统中有专门的中断子系统,原理很复杂,驱动开发者不需要知道具体细节,只需要知道如何应用该子系统提供的api来编写中断驱动代码即可
内核使用struct irqaction结构体描述一个中断,编写中断程序终极目标就是实现这个结构体
在内核中,文件大多以功能命名,内核中提供了一个interrupt.h的文件用来进行中断先关接口及数据结构的声明
interrupt.h include\linux 22053 2019/6/24 125
* struct irqaction - per interrupt action descriptor
* @handler: interrupt handler function
* @name: name of the device
* @dev_id: cookie to identify the device-----------是否是一个共享中断
* @percpu_dev_id: cookie to identify the device
* @next: pointer to the next irqaction for shared interrupts
* @irq: interrupt number
* @flags: flags (see IRQF_* above)
* @thread_fn: interrupt handler function for threaded interrupts
* @thread: thread pointer for threaded interrupts
* @thread_flags: flags related to @thread
* @thread_mask: bitmask for keeping track of @thread activity
* @dir: pointer to the proc/irq/NN/name entry
*/
struct irqaction {
irq_handler_t handler; //用户注册的中断处理函数
void *dev_id; //可以是用户传递的参数或者用来区分共享中断
void __percpu *percpu_dev_id;
struct irqaction *next; //irqaction结构链,一个共享中断可以有多个中断处理函数
irq_handler_t thread_fn;
struct task_struct *thread;
unsigned int irq; //中断号
unsigned int flags; //中断标识
unsigned long thread_flags;
unsigned long thread_mask;
const char *name; //用户注册的中断名字,cat/proc/interrupts时可以看到
struct proc_dir_entry *dir;
} ____cacheline_internodealigned_in_smp;
@flags: flags (see IRQF_* above)
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004 //指定中断触发类型:高电平有效
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
#define IRQF_TRIGGER_PROBE 0x00000010
/*
* These flags used only by the kernel as part of the
* irq handling routines.
*
* IRQF_DISABLED - keep irqs disabled when calling the action handler.
* DEPRECATED. This flag is a NOOP and scheduled to be removed
* IRQF_SAMPLE_RANDOM - irq is used to feed the random generator
* IRQF_SHARED - allow sharing the irq among several devices
* IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
* IRQF_TIMER - Flag to mark this interrupt as timer interrupt
* IRQF_PERCPU - Interrupt is per cpu
* IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
* IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
* registered first in an shared interrupt is considered for
* performance reasons)
* IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
* Used by threaded interrupts which need to keep the
* irq line disabled until the threaded handler has been run.
* IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
* IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
* IRQF_NO_THREAD - Interrupt cannot be threaded
* IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
* resume time.
*/
#define IRQF_DISABLED 0x00000020
#define IRQF_SAMPLE_RANDOM 0x00000040
#define IRQF_SHARED 0x00000080
#define IRQF_PROBE_SHARED 0x00000100
#define __IRQF_TIMER 0x00000200
#define IRQF_PERCPU 0x00000400
#define IRQF_NOBALANCING 0x00000800
#define IRQF_IRQPOLL 0x00001000
#define IRQF_ONESHOT 0x00002000
#define IRQF_NO_SUSPEND 0x00004000
#define IRQF_FORCE_RESUME 0x00008000
#define IRQF_NO_THREAD 0x00010000
#define IRQF_EARLY_RESUME 0x00020000
#define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
IRQF_DISABLED:私有中断,即一个中断请求对应一个中断服务函数
IRQF_SHARED:共享中断,多个中断请求对应一个中断服务函数
中断函数的函数指针:
typedef irqreturn_t (*irq_handler_t)(int, void *);
int:irq中断号
void *:dev设备标识
/**
* enum irqreturn
* @IRQ_NONE interrupt was not from this device
* @IRQ_HANDLED interrupt was handled by this device
* @IRQ_WAKE_THREAD handler requests to wake the handler thread
*/
enum irqreturn {
IRQ_NONE = (0 << 0),
IRQ_HANDLED = (1 << 0),
IRQ_WAKE_THREAD = (1 << 1),
};
typedef enum irqreturn irqreturn_t;
操作过程
1.向内核提出中断申请
函数:static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
参数:
unsigned int irq:中断号(线)
irq_handler_t handler:中断服务函数
unsigned long flags:中断标志
const char *name:设备名
void *dev:设备标识,只有在共享中断中此参数此参数才有效,因为私有中断不共享服务函数,无需判断是哪一个设备触发的中断
私有中断中可有直接赋值NULL
使能
extern void enable_irq(unsigned int irq);
失能
extern void disable_irq(unsigned int irq);
2.释放中断
函数:extern void free_irq(unsigned int, void *);
关于gpio的接口函数
1将gpio转换后成相对应的irq
gpio_to_irq:
2 setvalue
gpio_set_value
3 getvalue
gpio_get_value
编程
.