3.3.1 Linux中断的使能与屏蔽

news2024/9/22 19:26:43

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

3.3.1 Linux中断的使能与屏蔽

3.3.1.1 中断使能与屏蔽的三重关卡

        本章的主题是hard_local_irq_disable(),它是对中断的关闭操作。为了彻底搞清楚中断关闭的机制,这里先对Linux使能与屏蔽中断的API做详细的分析,然后再分析IPIPE做了哪些针对性地改造。这里分析的范围已经超过了hard_local_irq_disable()。

        硬件控制器的物理中断发生后,到执行中断处理程序IRQ Handler,这中间要经历3重关卡。

3.3.1.2 第一重关卡IMR

        第一重关卡指的是硬件控制器自身的中断屏蔽寄存器IMR。以SPI控制器为例,SPI_IMR[4]为0时代表RX FIFO FULL中断被屏蔽,为1时代表RX FIFO FULL中断被使能。在driver/spi/spi-rockchip.c驱动中,由驱动自行根据需要来管理中断屏蔽位。例如使能RX FIFO FULL中断,则调用:

writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR);

3.3.1.3 第二重关卡中断控制器的使能bit

        第二重关卡指的是中断控制器的使能bit。以GIC V3为例,每个中断号都有一个enable bit,可以通过GICD_ISENABLER<n>寄存器来set-enable使能中断,通过GICD_ICENABLER<n>寄存器来clear-enable屏蔽中断。在kernel/irq/manage.c,定义了如下接口:

//关闭中断,在非中断处理程序中使用,会等待中断处理程序完成
void disable_irq(unsigned int irq) 

//关闭中断:在中断处理程序中使用,不会等待,避免自己等待自己造成死锁
void disable_irq_nosync(unsigned int irq) 

//使能中断
void enable_irq(unsigned int irq)

        以disable_irq为例,来追踪一下是如何修改中断控制器的使能bit的:

disable_irq <kernel/irq/manage.c>
 ->	__disable_irq_nosync <kernel/irq/manage.c>
	 ->	__disable_irq  <kernel/irq/manage.c>
		 ->	irq_disable <kernel/irq/chip.c>
			 ->	__irq_disable <kernel/irq/chip.c>

        接下来__irq_disable开始了一顿让人迷惑的操作,下面展开说一下。

第1行,第一个入参struct irq_desc *desc是指向中断描述符的指针,为方便讨论,以下简称中断描述符。第二个入参mask涉及到内核的一个精巧的设计。先看一下这个参数是如何传递下来的。

kernel/irq/chip.c:

void irq_disable(struct irq_desc *desc)
{
	__irq_disable(desc, irq_settings_disable_unlazy(desc));
}

kernel/irq/settings.h
static inline bool irq_settings_disable_unlazy(struct irq_desc *desc)
{
	return desc->status_use_accessors & _IRQ_DISABLE_UNLAZY;
}

根据上述代码可以知道,mask的值取决于中断描述符是否设置了标志位_IRQ_DISABLE_UNLAZY。那到底是否定义了呢?在分配sturct irq_desc的过程,desc->status_use_accessors是初始化为0的,所以_IRQ_DISABLE_UNLAZY是没有置位的,入参mask的值为0。为了后续方便讨论,把这种默认情况称为UNLAZY模式。

alloc_desc
->desc_set_defaults
-> irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS) 

#ifndef ARCH_IRQ_INIT_FLAGS
# define ARCH_IRQ_INIT_FLAGS	0
#endif
#define IRQ_DEFAULT_INIT_FLAGS	ARCH_IRQ_INIT_FLAGS

第3行,调用irqd_irq_disabled判断中断描述符是否已经处于IRQD_IRQ_DISABLED。如果是IRQD_IRQ_DISABLED,因为mask默认是0,所以其实什么都不做。如果不是IRQD_IRQ_DISABLED,跳转到第7行。

第7行,调用irq_state_set_disabled,将中断描述符设置为IRQD_IRQ_DISABLED。

第8行,判断中断描述符所在的中断控制器是否定义了回调函数desc->irq_data.chip->irq_disable。以drivers/irqchip/irq-gic-v3.c为例,static struct irq_chip gic_chip并没有定义此回调函数,所以第8行的判断不成立,第9~10行不会执行,直接跳转到第11行。

第11行,因为mask为0,所以判断不成立。

综上所述,在默认的UNLAZY模式下,__irq_disable仅仅设置了一个IRQD_IRQ_DISABLED标记,并没有真正的操作中断控制器的使能bit呀?是的,在调用disable_irq <kernel/irq/manage.c>关闭某个中断号后,如果中断发生了,是会触发中断处理流程的,以GIC V3为例,中断处理流程走到irq_desc->handle_irq->handle_fasteoi_irq<kernel/irq/chip.c>时,会检查IRQD_IRQ_DISABLED标记。如果IRQD_IRQ_DISABLED标记置位了,则调用mask_irq(desc)清空中断控制器的使能bit: desc->irq_data.chip->irq_mask(&desc->irq_data)->gic_mask_irq-> gic_poke_irq(d, GICD_ICENABLER)

kernel/irq/chip.c:
void mask_irq(struct irq_desc *desc)
{
	if (irqd_irq_masked(&desc->irq_data))
		return;

	if (desc->irq_data.chip->irq_mask) {
		desc->irq_data.chip->irq_mask(&desc->irq_data);
		irq_state_set_masked(desc);
	}
}

drivers/irqchip/irq-gic-v3.c:
static struct irq_chip gic_chip = {
	.name			= "GICv3",
	.irq_mask		= gic_mask_irq,
	.irq_unmask		= gic_unmask_irq,
……
}

static void gic_mask_irq(struct irq_data *d)
{
	gic_poke_irq(d, GICD_ICENABLER);
}

        绕了这么一大圈,好处是啥?调用disable_irq <kernel/irq/manage.c>关闭某个中断号后,是不一定有中断发生的。如果在调用enable_irq <kernel/irq/manage.c>之前,确实如预测的一样,没有中断发生,那么disable_irq就省掉了一次对中断控制器寄存器(使能bit)的操作。

3.3.1.4 第三重关卡

        第三重关卡指的是CPU core的异常掩码标志。以ARM64为例,DAIF寄存器用来控制异常是否被屏蔽,具体状态通过PSTATE.DAIF查看。

CPU的每个core的DAIF时独立的,所以对DAIF操作的函数都有local_前缀,并且有两对API:

include/linux/irqflags.h:

//第一对API
#define local_irq_enable()	do { raw_local_irq_enable(); } while (0)
#define local_irq_disable()	do { raw_local_irq_disable(); } while (0)

//第二对API
#define local_irq_save(flags)					\
	do {							\
		raw_local_irq_save(flags);			\
	} while (0)
#define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)

两对API的区别是什么?一个粗暴,一个温柔。

local_irq_disable()/local_irq_enable是简单粗暴,直接关闭和打开中断。以ARM64为例,最终调用arch_local_irq_disable和arch_local_irq_enable来操作DAIF。

arch/arm64/include/asm/irqflags.h:

static inline void arch_local_irq_enable(void)
{
	asm volatile(
		"msr	daifclr, #2		// arch_local_irq_enable"
		:
		:
		: "memory");
}

static inline void arch_local_irq_disable(void)
{
	asm volatile(
		"msr	daifset, #2		// arch_local_irq_disable"
		:
		:
		: "memory");
}

        简单粗暴是要付出代价的。在调用local_irq_disable()之前,DAIF可能已经处于关闭状态了。当配对使用local_irq_enable时,肯定会直接打开DAIF,这不就破坏了原来DAIF关闭的状态了,无法回到当初的状态了。

       local_irq_save(flags)和local_irq_restore(flags)就显得很温柔了。local_irq_save先保存DAIF的状态到flags,然后再关闭DAIF。当配对使用local_irq_restore(flags)时,把flags保存的状态恢复到DAIF,而不是简单的打开DAIF,以此来保证恢复当初的状态。

arch/arm64/include/asm/irqflags.h:

static inline unsigned long arch_local_irq_save(void)
{
	unsigned long flags;
	asm volatile(
		"mrs	%0, daif		// arch_local_irq_save\n"
		"msr	daifset, #2"
		: "=r" (flags)
		:
		: "memory");
	return flags;
}

static inline void arch_local_irq_restore(unsigned long flags)
{
	asm volatile(
		"msr	daif, %0		// arch_local_irq_restore"
	:
	: "r" (flags)
	: "memory");
}

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2085001.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解HTTP的doGet与doPost

深入理解HTTP的doGet与doPost 1、doGet方法2、doPost方法3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Web开发中&#xff0c;HTTP的GET和POST请求通过Servlet的doGet和doPost方法实现&#xff0c;两者在处理方式和适用场景上有…

那些令人惊艳的产品细节

随着智能手机的普及和互联网的发展&#xff0c;互联网产品已经渐渐渗透到我们的生活当中。 小编打开手机数了一下&#xff0c;不下50个APP&#xff0c;五花八门&#xff0c;最基本的生活服务类的&#xff0c;娱乐类的&#xff0c;社交等等。大家都会面临的一个问题是&#xff…

矩阵分块乘法的证明

设A是一个的矩阵&#xff0c;B是一个的矩阵&#xff0c; &#xff0c; A和B的分块矩阵分别记为 和 &#xff0c; 证明. 证明&#xff1a;设 要证明&#xff0c;可以首先证AB和是同型矩阵&#xff0c;即证明是一个的矩阵&#xff0c;接着再证&#xff0c;可以把AB做一个与同样…

1.C语言(变量和常量)

一、变量和常量的概念 变量&#xff1a;可以变的量 常量&#xff1a;不可变的量 变量举例&#xff1a; 1.变量的分类 1.1 分为全局变量和局部变量 全局变量&#xff1a;大括号外定义的变量 局部变量&#xff1a;大括号内的变量 1.2注意&#xff1a; 注入在同一范围内&am…

MAC多版本Java环境变量切换

在Mac上切换不同版本的Java环境变量可以通过以下步骤进行&#xff1a; 1. 打开终端&#xff08;Terminal&#xff09;应用程序。 2. 使用vi或者nano等编辑器打开.zshrc文件。如果该文件不存在&#xff0c;可以创建一个新的文件。 3.使用命令查看当前电脑已安装的JAVA版本 /usr…

不改一行代码轻松玩转 Go 应用微服务治理

作者&#xff1a;赵源筱 Go 应用微服务治理简介 Go 语言具有简洁、高效、并发性强等特性&#xff0c;已经被广泛认为是构建微服务的理想选择之一。Go 语言作为构建 Kubernetes、Docker 的主要编程语言&#xff0c;目前不仅在云原生基础组件领域中被广泛使用&#xff0c;也逐渐…

深入浅出LangChain:从模型调用到Agents开发的全流程指南

2024最新LangChain全面解析:从基础组件到AI应用构建 LangChain、LangGraph、LangSmith:打造完整AI解决方案的利器 本文将对于LangChain的基本组件、用途、用法进行介绍。 LangChain、LangGraph以及LangSmith的组合&#xff0c;极大的简化了开发者构建AI应用、Agents、Tools的…

看新闻知补贴不用专门薅羊毛!让工作变舒服的5个黄金法则——早读(逆天打工人爬取热门微信文章解读)

你们都不看新闻吗&#xff1f; 引言Python 代码第一篇 洞见 让工作变舒服的5个黄金法则第二篇 故事之散户结尾 (发了3000亿以旧换新补贴&#xff0c;大家没有感觉到力度吗&#xff1f; 时间到今年年底&#xff0c;9月-12月是消费区&#xff0c;中间夹杂个双十一&#xff0c;现在…

[易聊]软件项目测试报告

一、项目背景 随着互联网发展&#xff0c;各种各样的软件&#xff0c;比如游戏、短视频、购物软件中都有好友聊天功能&#xff0c;这是一个可在浏览器中与好友进行实时聊天的网页程序。“ 易聊 ”相对于一般的聊天软件&#xff0c;可以让用户免安装、随时随地的通过浏览器网页…

页面内容---复制粘贴【收藏版】【H5 web端亲测有效】

js中的复制粘贴 . 页面内容—复制粘贴【收藏版】【H5 web端亲测有效】 navigator.clipboard.writeText(copyText) 是 Web API 中的一个方法&#xff0c;用于将指定的文本内容复制到用户的剪贴板。这个方法属于 Clipboard API&#xff0c;它使得网页能够读取和写入剪贴板的内容…

【笔记】数据结构笔记02

toc 前话 算法学习网站&#xff1a; itcharge 代码随想录 labuladong 参考严蔚敏数据结构 树与等价问题 typedef PTree MFSet;//查找算法int find_mfset(MFSet S,int i){if(i<1||i>S.n) return -1;//i不属于任一集合for(ji;S.nodes[j].parent>0;jnodes[j].paren…

用宝塔部署项目到阿里云服务器访问不到的问题

今天用宝塔部署项目到阿里云&#xff0c;开始前端部署到了80端口&#xff0c;能正常访问&#xff0c;后端部署到了8081&#xff0c;但是后端接口一直无响应&#xff0c;最后超时。 但是java正常运行 系统防火墙的状态正常&#xff0c;策略也是放行 阿里云安全组也已经配置了 …

【性能优化】:从理论中来到实践中去(三)

本文主要介绍真实代码实现 序言 根据前面两篇文章的梳理 【性能优化】&#xff1a;探索系统瓶颈的根源&#xff08;一&#xff09; 【性能优化】&#xff1a;设计模式与技术方案解析&#xff08;二&#xff09; 我们已经知道了自动化跑批系统的核心功能&#xff0c;今天就来真…

如何使用混合搜索实现更好的 LLM RAG 检索

通过结合密集嵌入和BM25构建高级本地LLM RAG管道 基本的检索增强生成&#xff08;RAG&#xff09;管道使用编码器模型在给定查询时搜索相似文档。 这也被称为语义搜索&#xff0c;因为编码器将文本转换为高维向量表示&#xff08;称为嵌入&#xff09;&#xff0c;在该表示中&…

【计算机组成原理】汇总五、中央处理器

五、中央处理器 文章目录 五、中央处理器1.CPU的功能与结构1.1CPU功能1.2运算器1.2.1基本结构1.2.2 ALU和寄存器的数据通路 1.3控制器1.3.1基本结构1.3.2控制器功能 1.4CPU的基本结构 2.指令执行过程2.1指令周期2.2指令周期流程2.3数据流2.4指令执行方案&#xff1a;如何安排多…

Type-C接口诱骗取电快充方案

Type-C XSP08Q 快充协议芯片是一种新型电源管理芯片&#xff0c;主要负责控制充电电流和电压等相关参数&#xff0c;从而实现快速充电功能。Type-C XSP08Q快充协议是在Type-C接口基础上&#xff0c;加入了XSP08Q协议芯片的支持&#xff0c;很大程度上提升了充电速度。 正常情况…

ConcurrentHashMap扩容原理 | 存储流程 | 源码探究

新人写手&#xff0c;代码菜鸡&#xff1b;笔下生涩&#xff0c;诚惶诚恐。 初试锋芒&#xff0c;尚显青涩&#xff1b;望君指点&#xff0c;愿受教诲。 本篇文章将从源码的层面&#xff0c;探讨ConcurrentHashMap的存储流程以及扩容原理 Java版本为JDK17&#xff0c;源代码可…

Ollama 本地部署

文章目录 前言一、Ollama是什么&#xff1f;二、使用步骤1.安装 OllamaWindows检验是否安装成功 2.运行ollama 模型库运行模型提问修改配置&#xff08;可选&#xff09;如果有个性化需求&#xff0c;需要修改默认配置&#xff1a; 参考 前言 Ollama是一个易于使用的本地大模型…

LivePortraitV3,支持图像驱动和区域控制,更精确的人像控制(WIN,MAC)

LivePortrait又又又又更新了&#xff01;这速度真是&#x1f44d;&#x1f3fb;&#x1f44d;&#x1f3fb; 【LivePortraitV3&#xff0c;支持图像驱动和区域控制&#xff0c;更精确的人像控制&#xff08;WIN&#xff0c;MAC&#xff09;】 https://www.bilibili.com/video/…

别暑气 迎秋意

今年长达40天的“三伏”结束啦&#xff01; 伏天过后&#xff0c;暑热逐渐消退&#xff0c;天气开始转凉&#xff0c;秋季逐渐来临。我们也该调整好生活节奏&#xff0c;去迎接收获季节的开始。 1、注意防寒保暖 天气逐渐转凉&#xff0c;昼夜温差不断增大&#xff0c;所以要…