ARM GIC 与Linux kernel的中断子系统(4)GIC和中断处理
1.GIC
GIC,Generic Interrupt Controller。是ARM公司提供的一个通用的中断控制器。主要作用为:接受硬件中断信号,并经过一定处理后,分发给对应的CPU进行处理。
GIC v3中断类别:
GICv3定义了以下中断类型:
- SGI (Software Generated Interrupt):软件触发的中断。软件可以通过写 GICD_SGIR 寄存器来触发一个中断事件,一般用于核间通信,内核中的 IPI:inter-processor interrupts 就是基于 SGI。
- PPI (Private Peripheral Interrupt):私有外设中断。这是每个核心私有的中断。PPI会送达到指定的CPU上,应用场景有CPU本地时钟。
- SPI (Shared Peripheral Interrupt):公用的外部设备中断,也定义为共享中断。中断产生后,可以分发到某一个CPU上。比如按键触发一个中断,手机触摸屏触发的中断。
- LPI (Locality-specific Peripheral Interrupt):LPI 是 GICv3 中的新特性,它们在很多方面与其他类型的中断不同。LPI 始终是基于消息的中断,它们的配置保存在表中而不是寄存器。比如 PCIe 的 MSI/MSI-x 中断。
中断类型 | 硬件中断号 |
---|---|
SGI | 0-15 |
PPI | 16-31 |
SPI | 32-1019 |
reserved | … |
LPI | 8192-MAX |
GIC v3 组成:
GICv3 控制器由以下三部分组成:
- Distributor:SPI中断的管理,将中断发送给Redistributor
- 打开或关闭每个中断。Distributor对中断的控制分成两个级别。一个是全局中断的控制(GIC_DIST_CTRL)。一旦关闭了全局的中断,那么任何的中断源产生的中断事件都不会被传递到 CPU interface。另外一个级别是对针对各个中断源进行控制(GIC_DIST_ENABLE_CLEAR),关闭某一个中断源会导致该中断事件不会分发到 CPU interface,但不影响其他中断源产生中断事件的分发。
- 控制将当前优先级最高的中断事件分发到一个或者一组 CPU interface。当一个中断事件分发到多个 CPU interface 的时候,GIC的内部逻辑应该保证只 assert一个CPU。
- 优先级控制
- interrupt属性设定。设置每个外设中断的触发方式:电平触发、边缘触发;
- interrupt group的设定。设置每个中断的Group,其中 Group0用于安全中断,支持 FIQ 和 IRQ,Group1 用于非安全中断,只支持IRQ
- Redistributor:SGI,PPI,LPI中断的管理,将中断发送给CPU interface
- 启用和禁用 SGI 和 PPI。
- 设置 SGI 和 PPI 的优先级
- 将每个 PPI 设置为电平触发或边缘触发。
- 将每个 SGI 和 PPI 分配给中断组。
- 控制SGI 和 PPI 的状态。
- 内存中数据结构的基址控制,支持 LPI 的相关中断属性和挂起状态。
- 电源管理支持
- CPU interface:传输中断给 Core
- 打开或关闭 CPU interface 向连接的 CPU assert 中断事件。对于 ARM,CPU interface 和 CPU 之间的中断信号线是 nIRQCPU 和 nFIQCPU。如果关闭了中断,即便是 Distributor 分发了一个中断事件到 CPU interface,也不会 assert 指定的 nIRQ 或者 nFIQ 通知 Core
- 中断的确认。Core 会向 CPU interface 应答中断(应答当前优先级最高的那个中断),中断一旦被应答,Distributor 就会把该中断的状态从 pending 修改成 active 或者 pending and active(这是和该中断源的信号有关,例如如果是电平中断并且保持了该 asserted 电平,那么就是 pending and active)。ack 了中断之后,CPU interface 就会 deassert nIRQCPU 和 nFIQCPU 信号线。
- 中断处理完毕的通知。当 interrupt handler 处理完了一个中断的时候,会向写 CPU interface 的寄存器通知 GIC CPU 已经处理完该中断。做这个动作一方面是通知 Distributor 将中断状态修改为 deactive,另外一方面,CPU interface 会 priority drop,从而允许其他的 pending 的中断向 CPU 提交。
- 为 CPU 设置中断优先级掩码。通过 priority mask,可以 mask 掉一些优先级比较低的中断,这些中断不会通知到 CPU。
- 设置 CPU 的中断抢占(preemption)策略。
- 在多个中断事件同时到来的时候,选择一个优先级最高的通知 CPU。
GICv3 控制器内部模块和各中断类型的关系如下图所示:
中断路由
GICv3 使用 hierarchy 来标识一个具体的 core, 如下图是一个四层的结构(aarch64):
用 <affinity level 3>.<affinity level 2>.<affinity level 1>.<affinity level 0> 的形式组成一个 PE 的路由。每一个 core 的 affnity 值可以通过 MPIDR_EL1 寄存器获取, 每一个 affinity 占用8bit。配置对应 core 的 MPIDR 值,可以将中断路由到该 core 上。
中断状态机
中断处理的状态机如下图:
- Inactive:无中断状态,即没有 Pending 也没有 Active。
- Pending:硬件或软件触发了中断,该中断事件已经通过硬件信号通知到 GIC,等待 GIC 分配的那个 CPU 进行处理,在电平触发模式下,产生中断的同时保持 Pending 状态。
- Active:CPU 已经应答(acknowledge)了该中断请求,并且正在处理中。
- Active and pending:当一个中断源处于 Active 状态的时候,同一中断源又触发了中断,进入 pending 状态。
中断处理流程
- 外设发起中断,发送给 Distributor
- Distributor 将该中断,分发给合适的 Redistributor
- Redistributor 将中断信息,发送给 CPU interface
- CPU interface 产生合适的中断异常给处理器
- 处理器接收该异常,并且软件处理该中断
2. GIC驱动
设备树
gic: interrupt-controller@51a00000 {compatible = "arm,gic-v3";reg = <0x0 0x51a00000 0 0x10000>, /* GIC Dist */<0x0 0x51b00000 0 0xC0000>, /* GICR */<0x0 0x52000000 0 0x2000>, /* GICC */<0x0 0x52010000 0 0x1000>, /* GICH */<0x0 0x52020000 0 0x20000>; /* GICV */#interrupt-cells = <3>;interrupt-controller;interrupts = <GIC_PPI 9(GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;interrupt-parent = <&gic>;
};
- compatible:用于匹配GICv3驱动
- reg :GIC的物理基地址,分别对应GICD,GICR,GICC…
- #interrupt-cells:这是一个中断控制器节点的属性。它声明了该中断控制器的中断指示符(interrupts)中 cell 的个数
- interrupt-controller: 表示该节点是一个中断控制器
- interrupts:分别代表中断类型,中断号,中断类型, PPI中断亲和, 保留字段
关于设备数的各个字段含义,详细可以参考 Documentation/devicetree/bindings 下的对应信息。
初始化
1. irq chip driver 的声明:
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
定义 IRQCHIP_DECLARE 之后,相应的内容会保存到 __irqchip_of_table 里边:
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)#define OF_DECLARE_2(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_2)#define _OF_DECLARE(table, name, compat, fn, fn_type) \ static const struct of_device_id __of_table_##name \ __used __section(__##table##_of_table) \ = { .compatible = compat, \ .data = (fn == (fn_type)NULL) ? fn : fn }
__irqchip_of_table 在链接脚本 vmlinux.lds 里,被放到了 __irqchip_begin 和 __irqchip_of_end 之间,该段用于存放中断控制器信息:
#ifdef CONFIG_IRQCHIP#define IRQCHIP_OF_MATCH_TABLE() \. = ALIGN(8); \VMLINUX_SYMBOL(__irqchip_begin) = .; \*(__irqchip_of_table) \*(__irqchip_of_end)
#endif
在内核启动初始化中断的函数中,of_irq_init 函数会去查找设备节点信息,该函数的传入参数就是 __irqchip_of_table 段,由于 IRQCHIP_DECLARE 已经将信息填充好了,of_irq_init 函数会根据 “arm,gic-v3” 去查找对应的设备节点,并获取设备的信息。or_irq_init 函数中,最终会回调 IRQCHIP_DECLARE 声明的回调函数,也就是 gic_of_init,而这个函数就是 GIC 驱动的初始化入口
2. gic_of_init 流程:
static int __init gic_of_init(struct device_node *node, struct device_node *parent)
{void __iomem *dist_base;struct redist_region *rdist_regs;u64 redist_stride;u32 nr_redist_regions;int err, i;/* 映射 GICD 的寄存器地址空间。*/dist_base = of_iomap(node, 0);if (!dist_base) {pr_err("%pOF: unable to map gic dist registers\n", node);return -ENXIO;}
/* 验证 GICD 的版本是 GICv3 还是 GICv4
(主要通过读GICD_PIDR2寄存器bit[7:4].
0x1代表GICv1, 0x2代表GICv2…以此类推)。*/err = gic_validate_dist_version(dist_base);if (err) {pr_err("%pOF: no distributor detected, giving up\n", node);goto out_unmap_dist;}
/* 通过 DTS 读取 redistributor-regions 的值。*/if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))nr_redist_regions = 1;rdist_regs = kcalloc(nr_redist_regions, sizeof(*rdist_regs),GFP_KERNEL);if (!rdist_regs) {err = -ENOMEM;goto out_unmap_dist;}/* 为一个 GICR 域分配基地址*/for (i = 0; i < nr_redist_regions; i++) {struct resource res;int ret;ret = of_address_to_resource(node, 1 + i, &res);rdist_regs[i].redist_base = of_iomap(node, 1 + i);if (ret || !rdist_regs[i].redist_base) {pr_err("%pOF: couldn't map region %d\n", node, i);err = -ENODEV;goto out_unmap_rdist;}rdist_regs[i].phys_base = res.start;}
/* 通过 DTS 读取 redistributor-stride 的值*/if (of_property_read_u64(node, "redistributor-stride", &redist_stride))redist_stride = 0;gic_enable_of_quirks(node, gic_quirks, &gic_data);err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,redist_stride, &node->fwnode);if (err)goto out_unmap_rdist;
/* 设置一组 PPI 的亲和性。*/gic_populate_ppi_partitions(node);if (static_branch_likely(&supports_deactivate_key))gic_of_setup_kvm_info(node);return 0;out_unmap_rdist:for (i = 0; i < nr_redist_regions; i++)if (rdist_regs[i].redist_base)iounmap(rdist_regs[i].redist_base);kfree(rdist_regs);
out_unmap_dist:iounmap(dist_base);return err;
}
3. gic_init_bases 流程:
static int __init gic_init_bases(void __iomem *dist_base,struct redist_region *rdist_regs,u32 nr_redist_regions,u64 redist_stride,struct fwnode_handle *handle)
{u32 typer;int err;if (!is_hyp_mode_available())static_branch_disable(&supports_deactivate_key);if (static_branch_likely(&supports_deactivate_key))pr_info("GIC: Using split EOI/Deactivate mode\n");gic_data.fwnode = handle;gic_data.dist_base = dist_base;gic_data.redist_regions = rdist_regs;gic_data.nr_redist_regions = nr_redist_regions;gic_data.redist_stride = redist_stride;/* 确认支持 SPI 中断号最大的值为多少。*/typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);gic_data.rdists.gicd_typer = typer;gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),gic_quirks, &gic_data);pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);/** ThunderX1 explodes on reading GICD_TYPER2, in violation of the* architecture spec (which says that reserved registers are RES0).*/if (!(gic_data.flags & FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539))gic_data.rdists.gicd_typer2 = readl_relaxed(gic_data.dist_base + GICD_TYPER2);
/* 向系统中注册一个 irq domain 的数据结构,irq_domain 主要作用是将硬件中断号映射到 irq number */gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,&gic_data);gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));gic_data.rdists.has_rvpeid = true;gic_data.rdists.has_vlpis = true;gic_data.rdists.has_direct_lpi = true;gic_data.rdists.has_vpend_valid_dirty = true;if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {err = -ENOMEM;goto out_free;}irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);gic_data.has_rss = !!(typer & GICD_TYPER_RSS);pr_info("Distributor has %sRange Selector support\n",gic_data.has_rss ? "" : "no ");if (typer & GICD_TYPER_MBIS) {err = mbi_init(handle, gic_data.domain);if (err)pr_err("Failed to initialize MBIs\n");}
/* 设定 arch 相关的 irq handler */set_handle_irq(gic_handle_irq);gic_update_rdist_properties();/* 初始化 Distributor。 */gic_dist_init();
/* 初始化 CPU interface。 */gic_cpu_init();
/* 设置 SMP 核间交互的回调函数,用于 IPI,回到函数为 gic_raise_softir。 */gic_smp_init();
/* 初始化 GIC 电源管理。 */ gic_cpu_pm_init();gic_syscore_init();/* 初始化 ITS。 */if (gic_dist_supports_lpis()) {its_init(handle, &gic_data.rdists, gic_data.domain);its_cpu_init();} else {if (IS_ENABLED(CONFIG_ARM_GIC_V2M))gicv2m_init(handle, gic_data.domain);}gic_enable_nmi_support();return 0;out_free:if (gic_data.domain)irq_domain_remove(gic_data.domain);free_percpu(gic_data.rdists.rdist);return err;
}
3.中断的映射
irq_domain 的引入相当于一个中断控制器就是一个 irq_domain。这样一来所有的中断控制器就会出现级联的布局。利用树状的结构可以充分的利用 irq 数目,而且每一个 irq_domain 区域可以自己去管理自己 interrupt 的特性。
每一个中断控制器对应多个中断号, 而硬件中断号在不同的中断控制器上是会重复编码的, 这时仅仅用硬中断号已经不能唯一标识一个外设中断,因此 linux kernel 提供了一个虚拟中断号的概念
外设的驱动创建硬中断和虚拟中断号的映射关系:
设备的驱动在初始化的时候可以调用 irq_of_parse_and_map 这个接口函数进行该 device node 中和中断相关的内容的解析,并建立映射关系
最后,我们可以通过 /proc/interrupts 下的值来看下它们的关系:
4.中断的注册
设备驱动中,获取到了 irq 中断号后,通常就会采用 request_irq/request_threaded_irq 来注册中断,其中 request_irq 用于注册普通处理的中断。request_threaded_irq 用于注册线程化处理的中断,线程化中断的主要目的把中断上下文的任务迁移到线程中,减少系统关中断的时间,增强系统的实时性
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
{return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}#define IRQF_SHARED 0x00000080 //多个设备共享一个中断号,需要外设硬件支持
#define IRQF_PROBE_SHARED 0x00000100 //中断处理程序允许sharing mismatch发生
#define __IRQF_TIMER 0x00000200 //时钟中断
#define IRQF_PERCPU 0x00000400 //属于特定CPU的中断
#define IRQF_NOBALANCING 0x00000800 //禁止在CPU之间进行中断均衡处理
#define IRQF_IRQPOLL 0x00001000 //中断被用作轮训
#define IRQF_ONESHOT 0x00002000 //一次性触发的中断,不能嵌套,1)在硬件中断处理完成后才能打开中断;2)在中断线程化中保持关闭状态,直到该中断源上的所有thread_fn函数都执行完
#define IRQF_NO_SUSPEND 0x00004000 //系统休眠唤醒操作中,不关闭该中断
#define IRQF_FORCE_RESUME 0x00008000 //系统唤醒过程中必须强制打开该中断
#define IRQF_NO_THREAD 0x00010000 //禁止中断线程化
#define IRQF_EARLY_RESUME 0x00020000 //系统唤醒过程中在syscore阶段resume,而不用等到设备resume阶段
#define IRQF_COND_SUSPEND 0x00040000 //与NO_SUSPEND的用户共享中断时,执行本设备的中断处理函数
5.中断的处理
当完成中断的注册后,所有结构的组织关系都已经建立好,剩下的工作就是当信号来临时,进行中断的处理工作。
假设当前在 EL0 运行一个应用程序,触发了一个 EL0 的 irq中断,则处理器先会跳到 arm64 对应的异常向量表:
/** Exception vectors.*/.pushsection ".entry.text", "ax".align 11
SYM_CODE_START(vectors)......kernel_ventry 1, sync // el1 下的同步异常,例如指令执行异常、缺页中断等kernel_ventry 1, irq // el1 下的异步异常,硬件中断。1代表异常等级kernel_ventry 1, fiq_invalid // FIQ EL1hkernel_ventry 1, error // Error EL1hkernel_ventry 0, sync // el0 下的同步异常,例如指令执行异常、缺页中断(跳转地址或者取地址)、系统调用等kernel_ventry 0, irq // el0 下的异步异常,硬件中断。0代表异常等级kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0kernel_ventry 0, error // Error 64-bit EL0......
#endif
SYM_CODE_END(vectors)
arm64 的异常向量表 vectors 中设置了各种异常的入口。kernel_ventry 展开后,可以看到有效的异常入口有两个同步异常 el0_sync,el1_sync 和两个异步异常 el0_irq,el1_irq,其他异常入口暂时都 invalid。中断属于异步异常。
通过上图,我们可以看出中断的处理分为三个部分,保护现场,中断处理,恢复现场。其中 el0_irq 和 el1_irq 的具体实现略有不同,但处理流程大致是相同的。
保护现场:
kernel_entry 0,其中 kernel_entry 是一个宏,此宏会将 CPU 寄存器按照 pt_regs 结构体的定义将第一现场保存到栈上
.macro kernel_entry, el, regsize = 64
.if \regsize == 32
mov w0, w0 // zero upper 32 bits of x0
.endif
stp x0, x1, [sp, #16 * 0]
stp x2, x3, [sp, #16 * 1]
stp x4, x5, [sp, #16 * 2]
stp x6, x7, [sp, #16 * 3]
stp x8, x9, [sp, #16 * 4]
stp x10, x11, [sp, #16 * 5]
stp x12, x13, [sp, #16 * 6]
stp x14, x15, [sp, #16 * 7]
stp x16, x17, [sp, #16 * 8]
stp x18, x19, [sp, #16 * 9]
stp x20, x21, [sp, #16 * 10]
stp x22, x23, [sp, #16 * 11]
stp x24, x25, [sp, #16 * 12]
stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14].if \el == 0
clear_gp_regs
mrs x21, sp_el0
ldr_this_cpu tsk, __entry_task, x20
msr sp_el0, tsk
中断处理:跳入中断处理 irq_handler。
/** Interrupt handling.*/.macro irq_handlerldr_l x1, handle_arch_irqmov x0, spirq_stack_entry //进入中断栈blr x1 //执行 handle_arch_irqirq_stack_exit //退出中断栈.endm
中断栈用来保存中断的上下文,中断发生和退出的时候调用 irq_stack_entry 和 irq_stack_exit 来进入和退出中断栈。中断栈是在内核启动时就创建好的,内核在启动过程中会去为每个 CPU 创建一个 per cpu 的中断栈:start_kernel->init_IRQ->init_irq_stacks
handle_arch_irq 指针指向 gic_handle_irq 函数
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{u32 irqnr;do {/* 读取中断控制器的寄存器GICC_IAR,并获取 hwirq */irqnr = gic_read_iar(); /* 外设触发的中断。硬件中断号 0-15 表示 SGI 类型的中断,15-1020 表示外设中断(SPI或PPI类型),8192-MAX 表示 LPI 类型的中断 */if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {int err;if (static_key_true(&supports_deactivate))gic_write_eoir(irqnr);elseisb();
/* 中断控制器中断处理的主体 */err = handle_domain_irq(gic_data.domain, irqnr, regs); if (err) {WARN_ONCE(true, "Unexpected interrupt received!\n");if (static_key_true(&supports_deactivate)) {if (irqnr < 8192)gic_write_dir(irqnr);} else {gic_write_eoir(irqnr);}}continue;}
/* 软件触发的中断 */if (irqnr < 16) { gic_write_eoir(irqnr);if (static_key_true(&supports_deactivate))gic_write_dir(irqnr);
#ifdef CONFIG_SMP/** Unlike GICv2, we don't need an smp_rmb() here.* The control dependency from gic_read_iar to* the ISB in gic_write_eoir is enough to ensure* that any shared data read by handle_IPI will* be read after the ACK.*/
/* 核间交互触发的中断 */ handle_IPI(irqnr, regs);
#elseWARN_ONCE(true, "Unexpected SGI received!\n");
#endifcontinue;}} while (irqnr != ICC_IAR1_EL1_SPURIOUS);
}
中断控制器中断处理的主体,如下所示:
nt __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,bool lookup, struct pt_regs *regs)
{struct pt_regs *old_regs = set_irq_regs(regs); unsigned int irq = hwirq;int ret = 0;/* 进入中断上下文 */irq_enter(); /* 根据 hwirq 去查找 linux 中断号 */
#ifdef CONFIG_IRQ_DOMAINif (lookup)irq = irq_find_mapping(domain, hwirq);
#endif/** Some hardware gives randomly wrong interrupts. Rather* than crashing, do something sensible.*/if (unlikely(!irq || irq >= nr_irqs)) {ack_bad_irq(irq);ret = -EINVAL;} else {
/* 通过中断号找到全局中断描述符数组 irq_desc[NR_IRQS] 中的一项,然后调用 generic_handle_irq_desc,执行该 irq 号注册的 action */ generic_handle_irq(irq); /* */}
/* 退出中断上下文 */irq_exit(); set_irq_regs(old_regs);return ret;
}
恢复现场:
SYM_CODE_START_LOCAL(ret_to_user)disable_daif //DAIF分别为PSTAT中的四个异常屏蔽标志位,此处屏蔽这4中异常gic_prio_kentry_setup tmp=x3
#ifdef CONFIG_TRACE_IRQFLAGSbl trace_hardirqs_off
#endifldr x19, [tsk, #TSK_TI_FLAGS] //获取 thread_info 中的flags变量的值and x2, x19, #_TIF_WORK_MASKcbnz x2, work_pending
finish_ret_to_user:user_enter_irqoff/* Ignore asynchronous tag check faults in the uaccess routines */clear_mte_async_tcfenable_step_tsk x19, x2
#ifdef CONFIG_GCC_PLUGIN_STACKLEAKbl stackleak_erase
#endifkernel_exit 0 //恢复 pt_regs 中的寄存器上下文
ARM GIC 与Linux kernel的中断子系统(4)GIC和中断处理相关推荐
- linux kernel的中断子系统之(三):IRQ number和中断描述符【转】
转自:http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html 一.前言 本文主要围绕IRQ number和中断描述符(interr ...
- linux kernel的中断子系统之(三):IRQ number和中断描述符
原文地址 http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html linux kernel的中断子系统之(三):IRQ numbe ...
- Linux kernel的中断子系统之(九):tasklet
返回目录:<ARM-Linux中断系统>. 总结: 二介绍了tasklet存在的意义. 三介绍了通过tasklet_struct来抽想一个tasklet,每个CPU维护一个tasklet链 ...
- Linux kernel的中断子系统之(二):IRQ Domain介绍
一.概述 在linux kernel中,我们使用下面两个ID来标识一个来自外设的中断: 1.IRQ number.CPU需要为每一个外设中断编号,我们称之IRQ Number.这个IRQ number ...
- Linux中断子系统(一)中断控制器GIC架构
Linux中断子系统(一)中断控制器GIC架构 备注: 1. Kernel版本:5.4 2. 使用工具:Source Insight 4.0 3. 参考博客: Linux中断子系统(一)中 ...
- Linux中断子系统(二)中断控制器GIC驱动分析
Linux中断子系统(二)中断控制器GIC驱动分析 备注: 1. Kernel版本:5.4 2. 使用工具:Source Insight 4.0 3. 参考博客: Linux中断子系统(一 ...
- Linux中断子系统(三)之GIC中断处理过程
Linux中断子系统(三)之GIC中断处理过程 备注: 1. Kernel版本:5.4 2. 使用工具:Source Insight 4.0 3. 参考博客: Linux中断子系统(一)中 ...
- 嵌入式Linux驱动笔记(二十七)------中断子系统框架分析
你好!这里是风筝的博客, 欢迎和我一起交流. 中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行. 从硬 ...
- 漫画-Linux中断子系统综述
1.中断引发的面试教训 2.什么是中断? 中断: (英语:Interrupt)指当出现需要时,CPU暂时停止当前程序的执行转而执行处理新情况的程序和执行过程. 即在程序运行过程中,系统出现了一个必须由 ...
最新文章
- 数据库防火墙onefirewall,如何防范黑客物理删除?避免携程事件再次上演
- 阿里云性能测试服务 PTS 新面貌 - 压测协议、施压能力全新升级
- J2EE互联网产品打造
- python爬虫之urllib库详解
- GNN上用到的Tasks,Dataset and Benchmark
- 23、jQuery九类选择器/jQuery常用Method-API/jQuery常用Event-API
- C++ Primer 笔记——嵌套类 局部类
- Filter(过滤器)Listene(监听器)笔记
- 学习RAID磁盘阵列
- 如何把视频和音频合并?手把手教你合并
- 基于MATLAB的机器人学、机器视觉与控制
- electron 获取电脑mac地址遇到的坑
- 智能世代的工业/嵌入式网络与I/O桥接芯片解决方案
- dpi、dp、sp、px、mm之间的关系
- 服装行业施行ERP体系的首要好处是什么?
- 王菲离婚后首发微博谈及与李亚鹏离婚原因
- 出货量第一的三星为何在手机AI芯片竞争中落后华为和苹果?
- 时代互联报道:骗子盯上网银用户,认清银行网站域名,谨防上当
- Linux安装gbk字体,Linux安装GBK/GB2312程序显示乱码的五种解决方法 - 软件教程网
- 运放稳定性连载11:电容性负载稳定性:RISO、高增益及 CF、噪声增益(2)
热门文章
- 张恭庆院士:数学的意义(最全最牛的解释)
- 小学带计算机2000的检讨书,【精选】小学学生检讨书模板集合10篇
- 使用electron中的webView标签
- 模拟演讲者视图_PPT演讲心慌慌?用演讲者视图一边看一边说
- css实现的卡片式渐变色卡html页面前端源码
- 解决WIN7 无法登陆MicroSoft Edge问题
- 栈与队列及其应用 - 1.算术表达式求值
- 授课点评:如何通俗地讲授概念?什么是图像?
- 关于fluent中亚松弛因子under-ralexation factors的思考
- 网络营销团队打造 如何生化出让同行垂涎三尺的网络营销团队