bbblack的linux的中断学习(第一篇)

本次以bbblack板子的内核为研究,中断向量表IDT,有CPU的本身的中断,还有外设的中断,其中CPU的中断里面的INT 0X80是软中断,很多系统调用就是用的这个中断。

其中外设的中断,可能多个外设共用一个中断号,所以猜测每一个中断号都有一个单独的中断请求队列,比如串口和定时器共用一个中断号,那么这两个中断都发送到同一个中断请求队列给CPU去处理,仅为猜测。

不过看书,在IDT的初始化阶段只是为每个中断向量,也即每一个表项准备一个中断请求队列,从而形成一个中断请求队列的数组irq_desc[NR_IRQS];。然后我去看下代码。

在\bb-black-kernel-3.8\kernel\kernel\include\linux找到这个数组。 Linux内核将所有的中断统一编号,使用一个irq_desc结构数组来描述这些中断;每个数组项对应一个中断,也可能是一组中断,它们共用相同的中断号,里面记录了中断的名称、中断状态、中断标记(比如中断类型、是否共享中断等),并提供了中断的低层硬件访问函数(清除、屏蔽、使能中断),提供了这个中断的处理函数入口,通过它可以调用用户注册的中断处理函数。

struct irq_desc {
    struct irq_data     irq_data;
    unsigned int __percpu   *kstat_irqs;
    irq_flow_handler_t  handle_irq;
    struct irqaction    *action;    /* IRQ action list */
    unsigned int        status_use_accessors;
    unsigned int        core_internal_state__do_not_mess_with_it;
    unsigned int        depth;      /* nested irq disables */
    unsigned int        wake_depth; /* nested wake enables */
    unsigned int        irq_count;  /* For detecting broken IRQs */
    unsigned long       last_unhandled; /* Aging timer for unhandled count */
    unsigned int        irqs_unhandled;
    raw_spinlock_t      lock;
    struct cpumask      *percpu_enabled;
    unsigned long       threads_oneshot;
    atomic_t        threads_active;
    wait_queue_head_t       wait_for_threads;
    int         parent_irq;
    struct module       *owner;
    const char      *name;
} ____cacheline_internodealigned_in_smp;
extern struct irq_desc irq_desc[NR_IRQS];

研究下具体中断是怎么实现的。看下struct irqaction *action;这个结构体,其中最重要的是函数指针handler,指向具体的中断服务程序。其中thread_fn是线程的中断,对这个东西不是很清楚,不作为此次研究的重点。

struct irqaction {
    irq_handler_t       handler;//用户注册的中断处理函数
    void            *dev_id;
    void __percpu       *percpu_dev_id;
    struct irqaction    *next;
    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;
    struct proc_dir_entry   *dir;
} ____cacheline_internodealigned_in_smp;

依然要回到原来的问题,串口和定时器共用一个中断号的时候,在代码级是怎么实现的?真正的中断服务要到具体设备的初始化程序将其中断服务程序通过request_threaded_irq()向系统登记,挂入某个中断请求队列以后才会发生。找到这个函数\bb-black-kernel-3.8\kernel\kernel\kernel\irq\manage.c,这个就是先申请了一个内存,存放中断处理函数的指针

int request_threaded_irq(unsigned int irq, irq_handler_t handler,
             irq_handler_t thread_fn, unsigned long irqflags,
             const char *devname, void *dev_id)
{
    struct irqaction *action;
    struct irq_desc *desc;
    int retval;
    if ((irqflags & IRQF_SHARED) && !dev_id)
        return -EINVAL;

    desc = irq_to_desc(irq);
    if (!desc)
        return -EINVAL;

    if (!irq_settings_can_request(desc) ||
        WARN_ON(irq_settings_is_per_cpu_devid(desc)))
        return -EINVAL;

    if (!handler) {
        if (!thread_fn)
            return -EINVAL;
        handler = irq_default_primary_handler;
    }

    action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
    if (!action)
        return -ENOMEM;

    action->handler = handler;
    action->thread_fn = thread_fn;
    action->flags = irqflags;
    action->name = devname;
    action->dev_id = dev_id;

    chip_bus_lock(desc);
    retval = __setup_irq(irq, desc, action);
    chip_bus_sync_unlock(desc);
    if (retval)
        kfree(action);
    return retval;
}

看下__setup_irq这个函数,找到这个函数
\bb-black-kernel-3.8\kernel\kernel\kernel\irq\manage.c,用户驱动程序通过request_irq函数向内核注册中断处理函数,request_irq函数根据中断号找到irq_desc数组项,然后在它的action链表添加一个表项。

用一个图片去看下整体的结构图,会更加的直观,可以看到action这个链表,可以添加串口中断服务函数,添加定时器中断服务函数。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值