异构核间通信框架(一):异构核间通信概述

冲冲冲

SoC指的是在一个芯片上集成了一个系统,SoC 往往有多个核心,例如 M 核、A 核,以及异构的 RISC-V核等。如下图所示,某个SoC可能在一个芯片中同时搭载了四个 A55 核心和一个 M33 核心;
具有多个核心的的SoC示意图
在该SoC中,核心 ①、②、③、④ 之间如何进行通信?这四颗核心又如何与异构的核心 ⑤ 进行通信?这就是:核间通信,前者为同构核间通信,后者为异构核间通信。在实际的应用中,我们先不考虑安全模式等情况,可以在 ①、②、③、④ 四个核心上运行一个 Linux 实例,在 ⑤ 上运行一个 RT-Thread 实例,那么上图就可以转换为下图所示的情况;
运行操作系统后的SoC示意图
在上图中,SoC 系统同时运行了两个 OS 实例,一个四核 Linux OS 实例,一个单核 RT-Thread 实例。此时核间通信就转化为了 Linux 内部之间的通信和 Linux 与 RT-Thread 之间的通信。

Linux 内部的通信我们可以很轻易的想到例如信号量、互斥锁、共享内存等传统的核间通信方式,这是因为 Linux OS 的四个核心共享了地址空间,那么 Linux 与 RT-Thread 之间如何进行通信呢?

首先如果摒弃 Soc 前提,我们可以使用串口、网络等方式进行通信,但是当两种核心在同一个 SoC 时就可以使用另外一种方式进行通信:异构核间共享内存,其示意图如下;
异构核间共享内存

上图只是一种示意,并非具体总线连接方案

当 Linux 和 RT-Thread 的核心可以通过某种硬件总线连接方式访问到同一块内存时,异构的核心就可以通过这块内存直接进行通信,就类似于 Linux 系统内部的共享内存通信一样。这块异构核心间的共享内存与 Linux 传统共享内存并不一定一样,原因如下:

  1. Linux 共享内存存在于 Linux 所有核心的共享地址空间中,且这些核心与该共享内存的总线连接一致,因此,支持各核心之间的原子化互斥访问,也就是支持 CAS 操作。同样,那块被异构核间共享的内存也能被 Linux 各核心间 CAS 互斥访问;同理,RT-Thread 的多个核心(如果有)也可以对那块异构核间共享内存 CAS 互斥访问;
  2. Linux 和 RT-Thread 虽然都可以访问异构核间共享内存,但是其总线连接不一定一致,由于指令集也不一定一致,所以 Linux 内的核心几乎常常无法与 RT-Thread 内的核心实现对异构核间共享内存的 CAS 互斥访问,也就是说 Linux 任务无法通过使用 CAS 设置位于核间共享内存中的标志位实现与 RT-Thread 任务互斥。

由于主要讨论的是异构核间通信,后续将以共享内存代替异构核间共享内存,注意与 Linux 内部共享内存的区分。

到目前为止,我们知道了异构核间通信可以使用共享内存传递数据,但是仅此还不足以实现核间通信任务框架,我们还需要解决通信任务的发起方如何通知通信任务的接收方有通信任务需要处理的问题,方法并不是唯一,接下来介绍两种方式解决核间任务通知问题。

  1. 基于共享内存标志位实现核间任务通知
    共享内存无法解决异构核间互斥问题,但是可以解决异构核间同步问题。在共享内存中设置标志位,当 A 核需要发送消息时,先将需要发送的数据放入共享内存中,然后设置共享内存中特殊位置的标志位,然后轮询该标志位是否被清除,如果被清除,表示消息已经送达;B 核启动轮询线程轮询该标志位,当发现标志位被设置后,从共享内存中拿出通信数据并进行处理,将响应数据写入共享内存后清除该标志位,如此方可实现核间任务通知,示意图如下:
    基于共享内存的核间任务通知
    从上面的示意图我们可以发现一个问题,消息接收方标志位轮询任务的轮询间隔会影响到核间通信任务的响应时间,并不是说这种方式就不行,它能只消耗较小的核心性能,但是有些时候,我们更关心通信任务的实时性,这就需要另外一种更实时的方式:核间中断;

  2. 基于核间中断的核间通信任务通知
    核间中断是核心之间触发的中断,即在 A 核进行一定的操作后会在 B 核触发一个中断,这个中断与串口中断、定时器中断并没有本质区别,仅仅是目的不同而已。核间中断需要特定的核间中断硬件支持,下面介绍 RZ-G2UL 的 MHU 核间中断硬件;

文档链接:RZ-G2UL参考手册
文档位置
下载后解压,rzgg2ul.pdf 就是参考手册
RZ-G2UL参考手册
找到文档 12 单元可以详细了解该硬件

在介绍具体细节之前,我们先了解一个概念:通道(channel),示意图如下:

通道示意图
通道是一个抽象化的概念,其本质就是一组特殊寄存器。常常这组寄存器中有中断状态寄存器、中断触发寄存器、中断清除寄存器、中断屏蔽寄存器等,每种通道不一定都有上述寄存器,但至少存在中断触发寄存器。以 RZ-G2UL 的 MHU 为例,其包含状态、触发、清除三种寄存器:

  1. STS 中断状态寄存器:只读不可写,0 标识没有中断,1 标识存在中断;
  2. SET 中断触发寄存器:读恒为 0,只能写 1,向该寄存器写 1 将触发核间中断;
  3. CLR 中断清除寄存器:读恒为 0,只能写 1,向该寄存器写 1 将清除核间中断;
    需要注意的是,一组三个寄存器可以控制一个核间中断,但是这个核间中断可以在两个核心中同时触发,例如 SET1 寄存器会同时触发 A55CPU 和 M33CPU 中的某个中断,所以,不需要该中断的核心不要实现对应中断处理函数。
    接下来继续回到通道的概念,一个通道的目的是 核心A 向 核心B 发送消息且 核心B 确认 核心A的消息,那么一个通道需要至少两个中断,也就是需要两组寄存器,示意图如下:
    通道示意图
    在上图中 A55CPU 和 M33CPU 之间利用一个通道构建了一个单向的消息传递通道,再加上一个通道即可构建 A55CPU 和 M33CPU 之间的双向通信信道。

例如假设 SEND_(STS1、SET1、CLR1)可以在 A55CPU 触发 108 号中断,可以在 M33CPU 触发 79 号中断,中断名为 ch1_send。假设我们将这组寄存器用作 A55CPU 向 M33CPU 发送消息的中断,那么 A55CPU 就不要实现 ch1_send 中断,而 M33CPU 需要实现该中断。当 A55CPU 需要向 M33CPU 发送消息时,A55CPU 设置 SEND_SET1 为 1,M33CPU 的 ch1_send 中断即可得知需要消息处理,M33CPU 的 ch1_send 中断中,设置 SEND_CLR1 为 1 即可清除该中断,从而实现 A55CPU 到 M33CPU 的消息通知。
例如假设 RSP_(STS2、SET2、CLR2)可以在 A55CPU 触发 109 号中断,可以在 M33CPU 触发 80 号中断,中断名为 ch1_rsp。假设我们将这组寄存器用作 M33CPU 向 A55CPU 响应消息的中断,那么 M33CPU 就不要实现 ch1_rsp 中断,而 A55CPU 需要实现该中断。当 M33CPU 需要向 A55CPU 响应消息时,M33CPU 设置 RSP_SET2 为 1,A55CPU 的 ch1_rsp 中断即可得知消息已经被处理,A55CPU 的 ch1_rsp 中断中,设置 RSP_CLR2 为 1 即可清除该中断,从而实现 M33CPU 到 A55CPU 的消息响应。

注意,ch1_send 不一定非得是发送,也可以是响应,这么定义是为了方便而已,此外还需要重点注意的是 MHU 并没有中断屏蔽寄存器,在进行软件设计的时候需要特别注意。

到目前为止,我们了解了共享内存和核间中断,已经具备核间通信框架的基础,以 RZ-G2UL 为例,核间通信的基本流程如下:
M33CPU 发送消息到 A55CPU
M33 -> A55
A55CPU 发送消息到 M33CPU
A55 -> M33
总结:本文大致介绍了异构核间通信的基础,共享内存和异构核间中断硬件基础,还大致了解了核间通信的基础流程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

安果尤拉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值