当前位置:文档之家› IRQ0中断处理全过程

IRQ0中断处理全过程

i8259A_irq_type定义如下:
static struct hw_interrupt_type i8259A_irq_type = {
"XT-PIC",
startup_8259A_irq,
shutdown_8259A_irq,
do_8259A_IRQ,
enable_8259A_irq,
disable_8259A_irq
};
do_8259A_IRQ()是个重要的函数,是个IRQ响应处理程序。
同一个文件下,去掉那些不相关的部分,如下:
static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
{ struct irqaction * action;
{
bh_base[nr] = routine;
atomic_set(&bh_mask_count[nr], 0);
bh_mask |= 1 << nr;
}
就是简单的设置bh_base和bh_mask.
看看这些的定义:
atomic_t bh_mask_count[32];
unsigned long bh_active = 0;
s),
对于IRQ0来说,它会间接的调用timer_interrupt(),上面已经讲过。
④timer_interrupt(\arch\i386\kernel\Time.c)是内核接收到IRQ0之后使用的函数,从
CPU时间截记数器中读取一些属性值。如果有值,就调用do_timer_interrup
t(同一个文件中)。
irq_desc[i].depth = 0;
if (i < 16) {
irq_desc[i].handler = &i8259A_irq_type;
} else {
irq_desc[i].handler = &no_irq_type;
}
}
}
把IRQ小于16的handler都置为了i8259A_irq_type。
比较重要的调用就是init_ISA_irqs();
③init_ISA_irqs()在同一个文件里
void init_ISA_irqs (void)
{ int i;
for (i = 0; i < NR_IRQS; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[irq].handler->handle(irq, &regs);
if (1) {
if (bh_active & bh_mask)
do_bottom_half();/*处理下半部分*/
}
}
其实这里irq_desc[irq].handler->handle(irq, &regs);就是do_8259A_IRQ(irq,&reg
⑥时钟中断的另外一个下半底tqueue_bh(\kernel\Sched.c)
run_old_timers();
run_timer_list();
}
④void run_old_timers(void)
{/*
*简单的遍历处理timer_table数组的列表项,
*如果定时器已经触发,就调用相关的函数。*/
struct timer_struct *tp;
unsigned long mask;
⑤在do_timer_interrupt中又调用do_timer(\kernel\sched.c)。其他东西现在不感兴趣

⑥void do_timer(struct pt_regs * regs)
{
/*全局变量jiffies加1*/
(*(unsigned long *)&jiffies)++;
lost_ticks++;/*丢失的定时器滴答的数目*/
IRQ0中断处理全过程
1:系统注册IRQ0(时钟中断)的下半部分的处理过程。
在\kernel\sched.c的sched_init函数中
init_bh(TIMER_BH, timer_bh);/*TIMER_BH==0*/
init_bh(TQUEUE_BH, tqueue_bh);/*TQUEUE_BH==2*/
对于IRQ0,其实就是timer_interrupt函数。
不,其实现在还不是,等time_init()完就基本差不多了。
⑤time_init()在\arch\i386\kernel\Time.c中
感兴趣的就是setup_x86_irq(0, &irq0);作用就是给IRQ0增加一个操作。即timer_inte
}
mark_bh()函数把bh_active相应的位置1.
这里看到了没有,其实时钟中断有两个下半部分。
一个TIMER_BH,一个TQUEUE_BH。
4现在来看看系统执行下半底过程。do_bottom_half
①do_bottom_half(\kernel\softirq.c)做一些处理后,就调用run_bottom_halves();
continue;
timer_active &= ~mask;
tp->fn();
sti();
}
}
老的系统定时器如下组织:
timer_table[32] timer_struct
Timer_struct
Timer_active
31 0
⑤run_timer_list()也差不多是这样组织的。
Timer_head timer_list timer_list
unsigned long bh_mask = 0;
void (*bh_base[32])(void);
bh_base[]
31 bh_active 0
Bottom half handler(timer_bh)
31 bh_mask 0
不好意思,画的这么难看:P
如果bh_mask的第N位被置为1,则表明bh_base[]中的第N个指针指向了一个Bottom half
rrupt().
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer",
NULL, NULL};
现在关于IRQ0的初始化完成了。变成如下图示:
irq_desc_t irq_desc[]
struct hw_interrupt_type
{
int status;
int cpu = smp_processor_id();
irq_enter(cpu, irq);
status = 1; /* Force the "do bottom halves" bit */
do {
if (!(action->flags & SA_INTERRUPT))
②void run_bottom_halves(void)
{
unsigned long active;
void (**bh)(void);
active = get_active_bhs();/*取得激活的下半底*/
clear_active_bhs(active);/*清那些激活的下半底*/
bh = bh_base;
mark_bh(TIMER_BH);/*标记timer的下半部*/
if (!user_mode(regs))
lost_ticks_system++;/*如果在系统模式下
*在系统模式下丢失的滴答数加1
*/
if (tq_timer)/*判断定时器队列中有无任务*/
mark_bh(TQUEUE_BH);/*如果有,标记定时器队列的下半部分*/
do {
if (active & 1)
(*bh)();
bh++;
active >>= 1;
} while (active);
}
③对于IRQ0来说,(*bh)();就是timer_bh(\kernel\Sched.c);
void timer_bh(void)
{/*这是定时器真正的下半部分*/
update_times();/*更新统计数字*/
if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
__cli();
irq_exit(cpu, irq);
return status;
}
只注意这里一个函数:
action->handler(irq, action->dev_id, regs);
例程。
如果bh_active的第N位被置为1,则表明一旦调度进程许可,立即调用第N个Bottom hal
f例程。
bh_mask_count[]跟踪为每个下半部分提出的enable/disable请求嵌套对的数组。
2.系统初始化时钟中断(IRQ0)
①先看看start_kernel(\init\main.c)吧
}
handle_IRQ_event(irq, regs, action);
}
④handle_IRQ_event()也在同一个文件里。
int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqacti
相关主题