ARM64 linux 中断处理--架构

中断的发展背景

在计算机的发展过程中,外设的速度长期是低于CPU速度的,CPU 不能长期处于等待外设的状态,因此提供了外设通知CPU的方式--中断。

中断描述架构

中断架构分为三部分:

1、中断源,一般由外设产生,称之为 peripheral,是中断发送方;

2、中断控制器, 一般称之为 GIC Controller,负责对中断进行优先级,屏蔽等管理,并根据一定规则路由到CPU;

3、CPU,这是中断的接收方 ,负责处理中断;

中断控制器

struct irq_chip {
        const char    *name;
        void             (*irq_enable)(struct irq_data *data);
        void             (*irq_disable)(struct irq_data *data);
        void             (*irq_mask)(struct irq_data *data);
        void             (*irq_unmask)(struct irq_data *data);

        void             (*ipi_send_single)(struct irq_data *data, unsigned int cpu);
        void             (*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);
        ...
};

linux 使用 struct irq_chip 来描述中断控制器,它提供了对于中断的 enable, disable, mask, unmask等操作。

中断描述

struct irq_desc {
        const char          *name;
        unsigned int            depth;
        struct irqaction    *action;
        struct irq_data            irq_data;
        struct cpumask            *percpu_enabled;        
        ...
};

对于每个中断,linux 使用 irq_desc 来描述,它提供了中断 name, 处理函数, action以及目标cpu.

中断数据

struct irq_data {
        struct irq_chip                *chip;
        struct irq_domain        *domain;
        unsigned int                irq;
        unsigned long                hwirq;
        ...
};

irq_chip"结构体中的每个函数指针,都会携带一个指向struct irq_data的指针作为参数,可见这个"irq_data"与中断控制必定关系密切。也就是说,在"irq_desc"的定义中,与中断控制器紧密联系的这部分被单独提取出来,构成了"irq_data"结构体.

三者关系

中断初始化 

在启动过程中:

  1. irq 解析 dts 中包含 interrupt-controller 的 node, 确定为 intc, 然后分配 irq_chip 来描述
  2. irq 会对每一个从 dtb 中解析的 irq 都分配 irq_desc 来描述
  3. 通过 irq_domain 来建立 hwirq 和 irq 的映射,并确定处理函数
  4. 在 gic_init_bases 通过 irq_domain_create_tree 构建.

中断映射

在 irq domain 创建好之后, irq 和 hwirq 映射关系是空的。因此需要提供映射的方式。

典型映射方式

  1. 线性映射:线性映射其实就是一个lookup_table, 进行线性映射的方式要求 hwirq 不能太多。使用接口irq_domain_add_linear。
  2. radix映射:radix是建立一个 radix-tree,然后以 hwirq 为 index,irq 为 value 添加。使用 irq_domain_add_tree 进行创建映射。
  3. no-map: 有些中断控制器很强,可以通过寄存器配置HW interrupt ID而不是由物理连接决定的,在这种情况下,不需要进行映射,我们直接把IRQ number写入HW interrupt ID配置寄存器就OK了,这时候,生成的HW interrupt ID就是IRQ number,也就不需要进行mapping了。对于这种类型的映射,其接口API是 irq_domain_add_nomap.

linux 目前大多采用 radix-tree 方式进行映射

映射流程 

 首先,每个 hwirq 的信息描述通过 dts 进行描述

其次,每个 irq 需要对应一个 struct irq_desc

最后,建立 hwirq 到 irq 的映射

中断处理

中断上下文

 hardirq context 更新

  1. 进入中断
/* arm64/kernel/entry-common.c */
void __el1_irq(void)
{
   enter_from_kernel_mode(regs);

    irq_enter_rcu();
    do_interrupt_handler(regs, handler);
    irq_exit_rcu(); 
}
    
/* kernel/softirq.c */
void irq_enter_rcu(void)                                                                                                   {
    __irq_enter_raw();
}

#define __irq_enter_raw()               \
    do {                        \
        preempt_count_add(HARDIRQ_OFFSET);  \
        lockdep_hardirq_enter();        \
    } while (0)

在进入 hardirq 时, hardirq count 加1.

2.退出中断

/* kernel/softirq.c */
void irq_exit_rcu(void)
{
    __irq_exit_rcu();
    /* must be last! */
    lockdep_hardirq_exit();
}

static inline void __irq_exit_rcu(void)
{
    ...
    preempt_count_sub(HARDIRQ_OFFSET);
}

在退出 hardirq 时,hardirq count 减1.

hardirq context 解决的是当前是否在中断中,但是中断的竞争的解决是通过 irq_enable,irq_disable 解决的。

softirq context 更新

  1. 进入 softirq
static inline void softirq_handle_begin(void)
{
    __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
}

      2. 退出 softirq

static inline void softirq_handle_end(void)
{
    __local_bh_enable(SOFTIRQ_OFFSET);
}

对于当前 cpu, 当触发softirq 时,只需要更新 SOFTIRQ_OFFSET, 也就是表示是否在中断上下文中。

参考

https://zhuanlan.zhihu.com/p/83709066

中断子系统 - 蜗窝科技

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "Linux ARM GIC 中断流程" 是指在 ARM 架构Linux 操作系统中,使用 Generic Interrupt Controller(GIC)处理器来管理系统中各种中断的流程。它负责将来自不同设备和外部事件的中断请求,分派给适当的处理程序来处理,并确保系统按顺序执行这些处理程序。中断处理是系统中一个重要的组成部分,它允许设备和软件互相通信,并提高了系统的稳定性和可靠性。 ### 回答2: Linux是一个非常流行的开源操作系统,可以在不同架构的计算机上运行。ARM架构是一种广泛使用的嵌入式系统架构,因此,许多嵌入式设备都使用Linux作为其操作系统。在ARM架构上,通常会使用GIC(通用中断控制器)来管理中断,这个过程可以分为中断触发、CPU响应和中断处理三个部分。 中断触发是指中断信号从设备到达GIC的过程。当一个设备需要发送一个中断时,它会向GIC发送一个中断请求信号,并指定中断号,这个中断号是唯一的,用于区分不同的中断。GIC会根据中断号去查找到这个中断对应的中断控制器,进而把这个请求传递给指定的CPU。 CPU响应是指CPU接收到中断请求信号后的响应过程。当GIC把中断请求传递给CPU时,CPU需要检查是否允许这个中断请求,也就是检查中断屏蔽寄存器(Interrupt Mask Register)。如果这个中断请求已被屏蔽,则CPU不会响应,否则,它会设置自己的中断挂起寄存器(Interrupt Pending Register),告诉GIC它已经准备好去处理这个中断中断处理是指CPU执行中断处理程序,处理具体的中断。当CPU设置了它的中断挂起寄存器后,GIC会向CPU发送一个中断信号。CPU会暂停当前的进程,并把当前的上下文信息(比如,寄存器值)保存到内存中。之后,CPU会跳转到中断处理程序(Interrupt Service Routine),开始执行具体的中断处理代码。中断处理程序完成后,CPU会从内存中恢复之前保存的上下文信息,并恢复之前进程的执行。 总的来说,ARM架构上的Linux操作系统通常使用GIC来管理中断,其中包括中断触发、CPU响应和中断处理三个方面。这个流程对于保证系统的稳定性和快速响应非常重要。 ### 回答3: 在ARM架构Linux系统中,GIC(Generic Interrupt Controller)被用来管理中断。当发生中断时,GIC会将中断信号发送到CPU,然后CPU会停止当前的进程并处理中断。 GIC的中断流程如下: 1. 报告中断:设备或其他外部事件引发中断信号,设备向GIC发送中断信号,GIC会产生一个中断源标识符,然后将其发给CPU。 2. 响应中断:CPU根据中断源标识符查询GIC,查看中断请求的优先级和处理器状态,如果中断请求的优先级高于当前中断处理器,那么CPU会中止当前进程,执行中断处理程序。 3. 中断处理中断处理程序会读取设备状态,进行相应的操作,处理完成后会发出一个中断信号,通知GIC中断已被处理。 4. 中断结束:GIC收到来自设备的中断完成信号后,将中断源标识符置为未激活状态。 在这个流程中,GIC起到了一种路由的作用,将中断信号从设备传输到CPU,同时根据中断请求的优先级来优先处理高优先级的中断。这样就可以保证系统的稳定性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值