linux 2.6源代码情景分析笔记之中断与异常6

来源:互联网 发布:服装设计网络班 编辑:程序博客网 时间:2024/05/16 14:43

每个中断向量都有自己的irq_desc_t描述符,所有的这些描述符组织在一起形成irq_desc数组。

typedef struct irq_desc {
        hw_irq_controller *handler;指向pic对象(hw_irq_controller描述符),服务于irq线
        void *handler_data;指向pic方法所使用的数据
        struct irqaction *action;       /* IRQ action list */标识当出现irq时要调用的中断服务例程。该字段指向irq的irqaction描述符链表的第一个元素。
        unsigned int status;            /* IRQ status */描述irq线状态的一组标志
        unsigned int depth;             /* nested irq disables */如果irq线被激活,则显示0;如果irq线被禁止了不止一次,则显示一个正数
        unsigned int irq_count;         /* For detecting broken interrupts */中断计数器,统计irq线上发生的中断计数
        unsigned int irqs_unhandled;中断计数器,统计irq线上发生的无法处理的中断进行计数
        spinlock_t lock;用于串行访问irq描述符和pic的自旋锁。
} ____cacheline_aligned irq_desc_t;

extern irq_desc_t irq_desc [NR_IRQS];

/*
 * IRQ line status.
 */
#define IRQ_INPROGRESS  1       /* IRQ handler active - do not enter! */IRQ的一个处理程序正在执行
#define IRQ_DISABLED    2       /* IRQ disabled - do not enter! */由一个设备驱动程序故意地禁用irq线
#define IRQ_PENDING     4       /* IRQ pending - replay on enable */一个irq已经出现在线上,它的出现也已对pic做出应答,但是内核还没有为它提供服务
#define IRQ_REPLAY      8       /* IRQ has been replayed but not acked yet */irq线已被禁用,但是前一个出现的irq还没有对pic做出应答
#define IRQ_AUTODETECT  16      /* IRQ is being autodetected */内核在执行硬件设备探测时使用irq线
#define IRQ_WAITING     32      /* IRQ not yet seen - for autodetection */内核在执行硬件设备探测时使用irq线;此外,相应的中断还没有产生
#define IRQ_LEVEL       64      /* IRQ level triggered */在80x86结构上没有使用
#define IRQ_MASKED      128     /* IRQ masked - shouldn't be seen again */未使用
#define IRQ_PER_CPU     256     /* IRQ is per CPU */在80x86结构上没有使用


在初始化期间,下面的函数把每个irq主描述符的status字段设置成IRQ_DISABLED。此外,init_IRQ()通过替换由setup_idt()所建立的中断门来更新idt,通过其中的for循环来完成。
void __init init_IRQ(void)
{
        int i;
        /* all the set up before the call gates are initialised */
        pre_intr_init_hook();
        /*Cover the whole vector space, no vector can escape us. (some of these will be overridden and become 'special' SMP interrupts)*/
        for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
                int vector = FIRST_EXTERNAL_VECTOR + i;
                if (i >= NR_IRQS)
                        break;
                if (vector != SYSCALL_VECTOR)
                        set_intr_gate(vector, interrupt[i]);
        }
        /* setup after call gates are initialised (usually add in the architecture specific gates)*/
        intr_init_hook();
        /* Set the clock to HZ Hz, we already have a valid vector now:*/
        setup_pit_timer();
        /*External FPU? Set up irq13 if so, for original braindamaged IBM FERR coupling.*/
        if (boot_cpu_data.hard_math && !cpu_has_fpu)
                setup_irq(FPU_IRQ, &fpu_irq);
        irq_ctx_init(smp_processor_id());
}

其中interrupt数组中,有用于建立中断门的中断处理程序地址。其中的第n项中存放irqn的中断处理程序的地址。这里不包括与128号中断向量相关的中断门,因为它用于系统调用的编程异常。
在linux中,驱动程序不必关注安装在系统中的pic种类。每个驱动程序可见的中断源透明第连接到适当的控制器。定义pic对象的数据结构叫做hw_interrupt_type(也叫hw_irq_controller)。

static struct hw_interrupt_type i8259A_irq_type = {
        "XT-PIC",pic的名字
        startup_8259A_irq,启动芯片的irq线
        shutdown_8259A_irq,关闭芯片的irq线
        enable_8259A_irq,启用irq线
        disable_8259A_irq,禁用irq线
        mask_and_ack_8259A,函数通过把适当的字节发往8259A i/o端口来应答所接收到的irq.
        end_8259A_irq,函数在irq的中断处理程序终止时被调用
        NULL设置为空,用在多处理器系统中以声明特定irq所在cpu的“亲和力”。也就是说,那些cpu被启用来处理特定的irq.
};

unsigned int startup_8259A_irq(unsigned int irq)
{
        enable_8259A_irq(irq);
        return 0; /* never anything pending */
}

static void end_8259A_irq (unsigned int irq)
{
        if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && irq_desc[irq].action)
                enable_8259A_irq(irq);
}

void enable_8259A_irq(unsigned int irq)
{
        unsigned int mask = ~(1 << irq);
        unsigned long flags;

        spin_lock_irqsave(&i8259A_lock, flags);
        cached_irq_mask &= mask;
        if (irq & 8)
                outb(cached_slave_mask, PIC_SLAVE_IMR);
        else
                outb(cached_master_mask, PIC_MASTER_IMR);
        spin_unlock_irqrestore(&i8259A_lock, flags);
}