linux中断机制

更新时间:2023-05-16 09:48:10 阅读: 评论:0

ARM Linux中断机制分析
作者:张俊岭
EMAIL: sprite_;
QQ: 251450387
日期:2009-8-15
说明:本文档基于AT91SAM9260EK板
1 数据结构
中断机制的核心数据结构是irq_desc,它完整地描述了一条中断线(或称为“中断通道” )。irq_desc结构在include/linux/irq.h中定义:
typedef void fastcall (*irq_flow_handler_t)(unsigned int irq,
struct irq_desc *desc);
struct irq_desc {
irq_flow_handler_t handle_irq;/* 高层次的中断事件处理函数 */
struct irq_chip  *chip;    /* 低层次的硬件操作 */future是什么意思
struct msi_desc  *msi_desc; /* MSI 描述符?? */
void *handler_data; /* chip方法使用的数据*/
void *chip_data;    /* chip私有数据 */
struct irqaction *action;  /* 行为链表(action list) */
unsigned int status;    /* 状态 */
unsigned int depth; /* 关中断次数 */
unsigned int wake_depth; /* 唤醒次数 */
unsigned int irq_count; /* 发生的中断次数 */
unsigned int irqs_unhandled;
spinlock_t lock;  /* 自旋锁 */
#ifdef CONFIG_SMPkomanic>begin什么意思
cpumask_t affinity;
unsigned int cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) cpumask_t pending_mask;
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;  /* 在proc文件系统中的目录 */
#endif
const char *name;  /* 名称 */
} ____cacheline_aligned;
在kernel/irq/handle.c中有个全局irq_desc数组,描述了系统中所有的中断线:
我自己的英文struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
#ifdef CONFIG_SMP
.affinity = CPU_MASK_ALL
#endif
}
};
数组共有NR_IRQS个元素,每个元素对应一条中断线。其中NR_IRQS是系统中的中断线的数量,对于AT91SAM9260EK板,这个值为32。
下面来看irq_desc结构中的重要数据成员。
首先是handle_irq,这是个函数指针,指向的是一个高层次的中断事件处理函数,定义了处理中断事件的一种策略。
在kernel/irq/chip.c中实现了5个函数:handle_simple_irq(),handle_level_irq(), handle_edge_irq(),handle_fasteoi_irq()以及handle_percpu_irq()。handle_irq指针可以指向这5个函数中的一个,选择一种中断事件处理策略,这是通过函数t_irq_handler()完成的。
接下来是chip,这是个irq_chip结构指针。irq_chip结构定义了对中断线的底层硬件操作,在include/linux/irq.h中:
struct irq_chip {
const char *name;
unsigned int (*startup)(unsigned int irq);
datsvoid (*shutdown)(unsigned int irq);
void (*enable)(unsigned int irq);
void (*disable)(unsigned int irq);
void (*ack)(unsigned int irq);      /* 确认中断 */
void (*mask)(unsigned int irq);    /* 屏蔽中断 */
void (*mask_ack)(unsigned int irq); /* 确认并屏蔽中断 */
void (*unmask)(unsigned int irq);  /* 取消屏蔽中断 */
void (*eoi)(unsigned int irq);      /* 中断结束 */
void (*end)(unsigned int irq);
void (*t_affinity)(unsigned int irq, cpumask_t dest);
/* 重新触发中断 */
int  (*retrigger)(unsigned int irq);
/* 设置中断触发类型:高电平/低电平/上升沿/下降沿 */
int  (*t_type)(unsigned int irq, unsigned int flow_type);
/* 唤醒中断*/
int  (*t_wake)(unsigned int irq, unsigned int on);
… …
};
这个数据结构很简单,就是定义了一系列的函数指针,表示对底层硬件的具体操作行为。
最后的数据成员是action,这是个irq_action结构指针。irq_action结构定义了安装在中断线上的一个中断处理程序,在include/linux/interrupt.h中:
struct irqaction {
6级真题
irq_handler_t handler;  /* 具体的中断处理程序 */
unsigned long flags;
抛出窗外cpumask_t mask;
const char *name;  /* 名称,会显示在/proc/interreupts中 */
void *dev_id;      /* 设备ID,用于区分共享一条中断线的多个处理程序 */
struct irqaction *next; /* 指向下一个irq_action结构 */
int irq;  /* 中断通道号 */
struct proc_dir_entry *dir; /* procfs目录 */
};
多个中断处理程序可以共享同一条中断线,irqaction结构中的next成员用来把共享同一条中断线的所有中断处理程序组成一个单向链表,dev_id成员用于区分各个中断处理程序。
综合起来,可以得出中断机制各个数据结构之间的联系,如下图:
提高工作执行力
2 初始化
中断机制的初始化通过start_kernel()中的两个函数完成:trap_init()和init_IRQ()。 trap_init()在arch/arm/kernel/traps.c中:
void __init trap_init(void)
{
unsigned long vectors = CONFIG_VECTORS_BASE;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
__kur_helper_start[], __kur_helper_end[];
char
extern
int kur_sz = __kur_helper_end - __kur_helper_start;
拉丁语名字>abbreviation/* 异常向量表拷贝到0x0000_0000(或0xFFFF_0000),
异常处理程序的stub拷贝到 0x0000_0200(或0xFFFF_0200) */
__vectors_start, __vectors_end - __vectors_start);
memcpy((void
*)vectors,
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
memcpy((void *)vectors + 0x1000 - kur_sz, __kur_helper_start, kur_sz);
/* 拷贝信号处理函数 */
memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
sizeof(sigreturn_codes));
/* 刷新Cache,修改异常向量表占据的页面的访问权限*/
flush_icache_range(vectors, vectors + PAGE_SIZE);
DOMAIN_CLIENT);
modify_domain(DOMAIN_USER,
}
这个函数把定义在arch/arm/kernel/entry-armv.S中的异常向量表和异常处理程序的stub进行重定位:异常向量表拷贝到0xFFFF_0000,异常向量处理程序的stub拷贝到0xFFFF_0200。然后调用modify_domain()修改了异常向量表所占据的页面的访问权限,这使得用户态无法访问该页,只有核心态才可以访问。
arm处理器发生异常时总会跳转到0xFFFF_0000(设为“高端向量配置”时)处的异常向量表,因此进
行这个重定位工作。至于异常向量表所使用的物理空间和虚拟空间,则是在tup_arch()->paging_init()->devicemaps_init()中创建的(参见《ARM Linux的存储映射》)。init_IRQ()在arch/arm/kernel/irq.c中:
void __init init_IRQ(void)
{
irq;
int

本文发布于:2023-05-16 09:48:10,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/110469.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:中断   断线   向量   处理程序   函数   定义   机制   访问
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图