Linux Kernel5.10的核间通信(SGI中断)的本质

本文详细介绍了ARMv8-aarch64架构下的核间中断(SGI)机制,包括SGI中断的产生、LinuxKernel5.14中对IPI中断的使用,以及核间中断处理函数的注册和调用过程。通过smp_call_function等API可以触发核间通信,中断处理最终由ipi_handler执行特定任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

快速链接:
.
👉👉👉 个人博客笔记导读目录(全部) 👈👈👈


说明:
在默认情况下,本文讲述的都是ARMV8-aarch64架构,linux kernel 5.14


1、核间中断本质

核间中断其实就是SGI中断(Software Generated Interrupt),在gicv3架构中,共有16个SGI中断(不算后来extension的),ARM推荐的软件规定,0-7 SGI给REE使用,8-15 SGI给TEE使用。 我们查看Linux Kernel 5.14的代码也可以看到,它恰好只用了0-7 SGI.

补充SGI中断的介绍

在gicv3中断控制器中,0-15号中断是SGI中断

在这里插入图片描述
产生SGI中断的寄存器,如ICC_SGI0R_EL1ICC_SGI1R_EL1ICC_ASGI1R_EL1所示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、核间中断概念

处理器间中断就是一个 CPU 向系统中的目标 CPU发送中断信号,以使目标CPU执行特定的操作

在Linux Kernel操作系统中,默认定义了8中IPI中断(SGI0-SGI7)

(linux/arch/arm64/kernel/smp.c)

enum ipi_msg_type {
	IPI_RESCHEDULE,
	IPI_CALL_FUNC,
	IPI_CPU_STOP,
	IPI_CPU_CRASH_STOP,
	IPI_TIMER,
	IPI_IRQ_WORK,
	IPI_WAKEUP,
	NR_IPI
};
  • IPI_RESCHEDULE :0号中断, 重新调度进程,scheduler_ipi()
  • IPI_CALL_FUNC :1号中断, 调用generic_smp_call_function_interrupt()
  • IPI_CPU_STOP :2号中断,调用local_cpu_stop(), 使处理器停止
  • IPI_CPU_CRASH_STOP :3号中断,调用ipi_cpu_crash_stop(),使处理器停止
  • IPI_TIMER :4号中断,调用tick_receive_broadcast(),广播时钟事件
  • IPI_IRQ_WORK :5号中断,调用irq_work_run()
  • IPI_WAKEUP :6号中断,调用acpi_parking_protocol_valid(cpu), 唤醒处理器
  • NR_IPI :7号中断,没有使用
3、核间中断处理函数的注册和调用
  • 在Linux Kernel5.0之前,在gic_handle_irq()的gic处理函数中,会判断硬件中断号,中断小于16的属于SGI中断,单独走handle_IPI()函数,用于处理核间中断。
  • 而到了Linux Kernel 5.0之后,就不再单独将handle_IPI()拎出区分了。
    在这里插入图片描述
    那么在Linux Kernel 5.0之后是怎么实现的?
    在Linux Kernel 5.0为硬件中断号0-7的每个中断号都注册了一个中断处理函数,其指向ipi_handler()函数
    在这里插入图片描述
4、触发一个核间通信

核间中断的相关的API:

  • smp_call_function(func, info, wait) //在所有其它处理器执行一个函数
  • smp_call_function_single(int cpuid, smp_call_func_t func, void *info,int wait) //在指定处理器执行一个函数
  • smp_send_reschedule(int cpu) //指定处理器重新调度进程

SMP(IPI)的这类函数,最终都是调用到gic_send_sgi(),给core发送要给SGI中断
在这里插入图片描述

5、核间通信–任务的调用

ipi_handler()就是中断号0-7所注册的handler程序,在触发中断异常后,它和一般的request_irq注册的中断没有什么不同,都是从异常向量表调过来,然后调用到这个ipi_handler()程序,该程序再调用do_handle_IPI() 真正处理核间通信的任务。
在这里插入图片描述
在这里插入图片描述

### MPSOC SGI中断处理方法及配置 #### 初始化全局中断控制器(GIC) 为了在MPSOC平台上实现SGI (Software Generated Interrupts) 中断功能,首先需要初始化GIC。这一步骤确保了整个系统能够接收并响应来自软件触发的中断信号[^2]。 ```c #include "xil_exception.h" #include "xpseudo_asm.h" // GIC实例声明 XScuGic IntcInstance; int InitInterruptSystem(XScuGic *IntcInstancePtr, XScuGic_Config *ConfigPtr){ int Status; // 配置GIC Status = XScuGic_CfgInitialize(IntcInstancePtr, ConfigPtr, ConfigPtr->CpuBaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } // 注册处理器异常表项 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, (void *)IntcInstancePtr); // 启用CPU上的中断 Xil_ExceptionEnable(); } ``` #### 设置SGI目标列表 对于SGI而言,不同于硬件产生的物理中断,其可以通过编程方式指定哪些CPU心会接收到该中断请求。此过程涉及设置特定寄存器来定义目标CPU掩码。 ```assembly mrs x0, MPIDR_EL1 // 获取当前处理器身份识别符(MPIDR) and x0, x0, #0xFF // 提取Affinity Level 0部分作为CPU ID orr x1, xzr, #(1 << x0)// 创建对应于单个CPU的目标位图 msr ICH_VTR_EL2, x1 // 将目标位图写入ICH_VTR_EL2寄存器 ``` #### 发送SGI指令 当准备好发送SGI时,需向`ICH_HCR`寄存器写入适当值以激活所需类型的SGI,并通过操作`ICH_SGI0R`至`ICH_SGI7R`之的一个或多个寄存器来指明具体哪个SGI编号以及它应该被送往哪台或多台CPU上执行。 ```c #define SGI_NUM 0 // 定义要发出的SGI号码(范围为0~15) #define TARGET_CPU_MASK 0b0001 // 设定目的CPU掩码 void SendSgi(int sgiNumber, unsigned long targetMask){ asm volatile( "mov x0, %0\n\t" // 加载SGI数目到x0 "movk x0, %1, lsl #8\n\t" // 添加目标CPU掩码 "str x0, [x1]\n\t" // 存储组合后的参数到SGI寄存器 : : "r"(sgiNumber), "r"(targetMask), "r"(PERIPH_BASE + 0x4F00 + ((sgiNumber & 0xF) << 2)) : "memory", "cc"); } SendSgi(SGI_NUM, TARGET_CPU_MASK); // 调用函数发送SGI ``` #### 处理SGI中断服务程序(ISR) 最后,在应用程序层面还需编写专门用于处理SGI事件的服务例程。每当发生由上述代码片段所引发的SGI时,操作系统将会调用这个ISR来进行进一步的动作。 ```c static void MySgiIsr(void *CallBackRef){ printf("Received Software Generated Interrupt!\n\r"); // 清除挂起状态标志... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arm精选

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值