【SemiDrive源码分析】【X9芯片启动流程】24 - MailBox 核间通信机制介绍(寄存器分析篇)
- 一、MailBox 简介
- 1.1 MailBox 的主要功能
- 二、MailBox Inter-Processor Message
- 2.1 Message Format 格式
- 2.2 Message Header 相关寄存器
- 2.3 Message Buffer 消息缓冲区
- 2.4 Message Transmit Control 消息发送控制寄存器
- 2.5 Message Receive Control 消息接收控制寄存器
- 2.6 Message Status 消息状态
- 2.7 Message Cancelation 取消发送消息
- 2.8 Inter-Processor Wakeup 处理器内部唤醒
- 三、Hardware Semaphore 硬件信号量
- 3.1 Semaphore Gate Control Register 信号门控制寄存器
- 3.2 Lock and Unlock 加锁与解锁操作
- 3.3 Interrupt 中断
- 3.3.1 Interrupt on Lock Fail 上锁失败触发中断
- 3.3.2 Interrupt on Status Change 状态修改中断
- 3.4 Semaphore Gates Reset
本 SemiDrive源码分析 之 Yocto源码分析 系列文章汇总如下:
- 《【SemiDrive源码分析】【Yocto源码分析】01 - yocto/base目录源码分析(编译环境初始化流程)》
- 《【SemiDrive源码分析】【Yocto源码分析】02 - yocto/meta-openembedded目录源码分析》
- 《【SemiDrive源码分析】【Yocto源码分析】03 - yocto/meta-semidrive目录及Yocto Kernel编译过程分析(上)》
- 《【SemiDrive源码分析】【Yocto源码分析】04 - yocto/meta-semidrive目录及Yocto Kernel编译过程分析(下)》
- 《【SemiDrive源码分析】【Yocto源码分析】05 - 找一找Yocto Kernel编译过程中所有Task的源码在哪定义的呢?》
- 《【SemiDrive源码分析】【Yocto源码分析】06 - Kernel编译生成的Image.bin、Image_nobt.dtb、modules.tgz 这三个文件分别是如何生成的?》
- 《【SemiDrive源码分析】【Yocto源码分析】07 - core-image-base-x9h_ref_serdes.rootfs.ext4 文件系统是如何生成的》
- 《【SemiDrive源码分析】【X9芯片启动流程】08 - X9平台 lk 目录源码分析 之 目录介绍》
- 《【SemiDrive源码分析】【X9芯片启动流程】09 - X9平台系统启动流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】10 - BareMetal_Suite目录R5 DIL.bin 引导程序源代码分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】11 - freertos_safetyos目录Cortex-R5 DIL2.bin 引导程序源代码分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析》
- 《【SemiDrive源码分析】【X9芯片驱动调试】13 - GPIO 配置方法》
- 《【SemiDrive源码分析】【X9芯片启动流程】14 - freertos_safetyos目录Cortex-R5 SafetyOS/RTOS工作流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】15 - freertos_safetyos目录 R5 SafetyOS 之 tcpip_init() 代码流程分析》
- 《【SemiDrive源码分析】【X9 Audio音频模块分析】16 - 音频模块框图及硬件原理图分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】17 - R5 SafetyOS 之 LK_INIT_LEVEL_PLATFORM 阶段代码流程分析(上)dcf_init 核间通信初始化》
- 《【SemiDrive源码分析】【X9芯片启动流程】18 - R5 SafetyOS 之 LK_INIT_LEVEL_PLATFORM 阶段代码流程分析(下)》
- 《【SemiDrive源码分析】【X9芯片启动流程】19 - MailBox 核间通信机制介绍(理论篇)》
- 《【SemiDrive源码分析】【X9芯片启动流程】20 - MailBox 核间通信机制介绍(代码分析篇)之 MailBox for RTOS 篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】21 - MailBox 核间通信机制介绍(代码分析篇)之 Mailbox for Linux 篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】22 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-VIRTIO Kernel 篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】23 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC Kernel 篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】24 - MailBox 核间通信机制介绍(寄存器分析篇)》
- 《【SemiDrive源码分析】【X9芯片启动流程】25 - MailBox 核间通信机制介绍(代码分析篇)之 Property篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】26 - MailBox 核间通信机制介绍(代码分析篇)之 RPCall篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】27 - MailBox 核间通信机制介绍(代码分析篇)之 Notify篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】28 - MailBox 核间通信机制介绍(代码分析篇)之 Socket篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】29 - MailBox 核间通信机制介绍(代码分析篇)之 /dev/vircan篇》
- 《【SemiDrive源码分析】【X9芯片启动流程】30 - freertos_safetyos目录 R5 SafetyOS 之 LK_INIT_LEVEL_TARGET 阶段代码流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】31 - freertos_safetyos目录 R5 SafetyOS 之 .apps 应用启动代码流程分析》
一直在纠结要不要分析下 MailBox
核间通信机制相关寄存器,最终决定先简单过一遍,寄存器熟悉了,再看代码,估计会更好理解些,毕竟代码也可以说是给硬件打工的,貌似有点惨,哈哈,开玩笑的。
开始吧^_^
一、MailBox 简介
MailBox
模块通过传递数据、控制和状态信息,使SoC
中的多个处理器能够相互通信和协调。
它支持以下处理器间通信的硬件机制:
•处理器间消息
•硬件信号量
基于这些硬件机制,可以利用SoC
中的代码和其他硬件资源来实现复杂的处理器间通信协议。
1.1 MailBox 的主要功能
处理器间消息
- 集中式消息单元,可在多达8个处理器之间进行消息传输和通知
- 支持1对1消息、1对N消息和1对所有广播消息
- 灵活的消息缓冲区分配
每个处理器最多可向其他处理器发送4条消息;
1到4条消息可以组合成1条巨型消息;
每个处理器的4KB消息缓冲区; - 通过中断发出消息就绪通知
- 源处理器和目标处理器可通过
reset
信号中止消息传输。 - 一个处理器的唤醒中断,使其他处理器退出低功耗模式
- 跨处理器的消息访问权限处理
硬件信号量
- 支持多达8个处理器和多达64个硬件信号量门
- 锁定处理器复位时信号灯门释放
- 可选信号量锁定失败中断
- 信号量锁定失败的可选信号量状态更改中断
MailBox
支持以下处理器之间的通信:
Processor ID | Master ID | Processor |
0 | 7’b 0000000 | Safety Processor |
1 | 7’b 0000001 | Secure Processor |
3 | 7’b 0000011 | Application Processor |
5 | 7’b 0000101 | AI 加速器 |
-
Processor
意思是CPU Cores
、DSP Cores
或者 可编程的硬件加速器programmable hardware accelerators
。 -
Sorce Processor
意思是 传输消息的处理器 -
Destination Porcessor
意思是 接收消息的处理器
二、MailBox Inter-Processor Message
2.1 Message Format 格式
-
Message Header
头信息
消息头包含两部分信息。
第一部分是关于消息的基本信息,如消息长度、消息缓冲区使用情况。
第二部分是用户信息,可用于多种用途,完全由软件定义。消息头的长度为 3x32
位字,存储在消息头寄存器中。 -
Message body
正文
消息体用于存储消息的内容,它可以支持最大 4KB
的消息大小。消息正文的长度是可变的。
注意每条消息的Message Header
是必须携带的,而Message Body
可带可不带。
MailBox
消息格式如下:
头信息详细描述如下:
Component | Field | Definition | Description |
Message Header 0 | [10:0] | Message Length | 定义消息正文的长度,有效范围为0到2047,对应于 (1x2)字节到(2048x2)字节的消息长度 |
Message Header 0 | [11] | Message Buffer Usage | 定义是否使用消息缓冲区存储消息正文 |
Message Header 0 | [15:12] | Message Buffer Mask | MBM[3:0]的每一位表示使用的MB或此消息。 如MBM[3:0]=4’b 0101表示消息存储在MB0和MB2中。 |
Message Header 0 | [23:16] | Message Destination Processor | 定义目标地址。 如当MDP[7:0]=8’b10000001时,此消息将由处理器0和处理器7接收。 此字段仅用于传输消息。 |
Message Header 0 | [16] | Message Valid Flag | 当此位设置为1时,此消息有效,并准备由目标处理器接收。 仅用于接收消息。 |
Message Header 0 | [25:24] | Message Index | 定义当前消息的索引。 由于每个处理器只支持4条未完成的消息,因此MID[1:0]用于物理消息索引解码。 |
Message Header 0 | [31:26] | Reserved | 预留 |
Message Header 1 | [31:0] | Generic Data | 用户自定义消息,可以用作短消息的数据 |
Message Header 2 | [31:0] | Generic Data | 用户自定义消息,可以用作短消息的数据 |
Message Body | 长度可变 | Generic Data | 消息正文 |
2.2 Message Header 相关寄存器
Message Header Register
寄存器控制着Message Header
的传输和接收。
对于每个处理器,有4组Message Header Register
寄存器,每条消息有3个32位寄存器。这允许每个处理器在目标处理器接收到任何一条未完成的消息之前发送4条未完成的消息。
由于邮箱最多可支持8个处理器(只有部分处理器用于SoC),因此消息总数为32,称为CPUn_MSGm
,其中n
为0-7
,m
为0-3
,如CPU0_MSG0
说明向CPU0
发送MSG1
。
在传输端,处理器使用TMH0
、TMH1
和TMH2
寄存器对消息头进行编程。相同的寄存器用于所有4条消息。
TMH0
寄存器中的2
位MID[1:0]
用于选择正在编程的消息。
处理器写一个Message Header
时,它必须先对TMH0
寄存器进行编程,然后对TMH1
和TMH2
进行编程。
对于作为发送器的每个处理器,它只能对自己的 4
个头寄存器进行读这与。
为了提供统一的编程模型,TMH0/1/2
寄存器的地址对于所有处理器都是相同的。
在接收端,由于32条消息可能由8个处理器中的任何一个接收,因此每个处理器都需要访问所有32条消息的所有头寄存器。为了满足这一要求,每个消息头寄存器都映射到一个唯一的地址,以便处理器可以直接读取它,
称为CPUn_MSGm_ RMH0/1/2
。
下图仅显示了处理器0和处理器1的寄存器,其余处理器的寄存器以相同的方式实现:
2.3 Message Buffer 消息缓冲区
message body
消息正文通过message buffer
消息缓冲区发送和接收。
对于每个处理器,都有一个专用的4KB
消息缓冲区。
处理器可以通过内存映射寄存器空间(称为TX_BUFFER
)直接对消息缓冲区进行编程。
由于邮箱最多可支持8
个处理器(只有部分处理器用于SoC
),因此邮箱中有8个消息缓冲区,总缓冲区大小为32KB
。
对于作为发送器的每个处理器,它只能编写自己的消息缓冲区。为了提供统一的编程模型,所有处理器的TX_BUFFER
地址都是相同的。在接收端,由于消息可能由8个处理器中的任何一个接收,因此每个处理器都需要访问所有消息缓冲区。为了满足这一要求,每个消息缓冲区都映射到一个唯一的地址空间,以便处理器可以直接读取它,称为CPUn_RX_BUFFER
下图显示了邮箱中的邮件缓冲区。
该图仅显示处理器 0
和处理器 1
的消息缓冲区,其余处理器的消息缓冲区以相同的方式实现。
对于每个处理器的 4KB
消息缓冲区,它可以分为 4
部分,即 MB0
、MB1
、MB2
和 MB3
。
每个缓冲区的最大大小或最小大小没有限制,但 4
个缓冲区的总大小不应大于 4KB
。
还允许将 4KB
内存仅用作 3
个缓冲区或 2
个缓冲区,甚至 1
个缓冲区。
每个消息缓冲区的分配完全由软件管理,缓冲区大小没有硬件控制。
发送消息的处理器和接收消息的处理器在缓冲区分配上应具有相同的软件配置,包括缓冲区的大小和缓冲区的起始地址。
下图显示了消息缓冲区的三种典型分配:
当处理器传输消息时,它会选择用于消息的消息缓冲区。
消息正文的大小应等于或小于为此消息选择的消息缓冲区的大小。
还允许使用多个消息缓冲区来存储一条消息的消息体。
一个消息正文最多可使用4个消息缓冲区。
例如,一条消息可以使用所有4个消息缓冲区来支持4KB的消息正文大小。
对于每条消息,其消息头包含消息缓冲区的信息,以及消息的长度,因此接收消息的处理器知道消息的位置,只需从消息缓冲区读取有效长度的数据即可获得消息正文。
2.4 Message Transmit Control 消息发送控制寄存器
消息传输由TMC
寄存器控制。
每个处理器有4个TMC
寄存器,分别称为TMC0
、TMC1
、TMC2
和TMC3
,每条消息一个。
消息头和消息体编程到消息头寄存器和消息缓冲区后,处理器可以在TMC
寄存器中写入MSG_SEND
位以传输消息。
设置MSG_SEND
位后,邮箱将向目标处理器发出中断,目标处理器由消息的MDP
字段选择。
当所有目标处理器收到消息时,MSG_SEND
位将自动清除。
2.5 Message Receive Control 消息接收控制寄存器
消息接收由RMC
寄存器控制。
每个处理器都有自己的RMC
寄存器。
RMC
寄存器中有32
个TACK
(消息确认)位,称为CPUn_MSGm_TACK
,其中n
为0-7
,m
为0-3
。
目标处理器读取消息的消息头和消息体后,应设置相应的TACK
位以指示消息已被接收。
这些TACK
位会自动清零。一旦设置了位,相应消息引起的中断请求将被清除。
2.6 Message Status 消息状态
可以从TMS
寄存器检查消息传输状态。
TMS
寄存器中有32
个MIT
(消息传输)位,称为CPUn_MSGm_MIT
,其中n
为0-7
,m
为0-3
。
每个MIT
位表示消息m
到目标处理器n
的状态。如果MIT
位为1
,则消息仍在进行中。
当源处理器发送消息时,此字段自动设置;当目标处理器在接收到消息后设置定位位时,此字段将被清除。
2.7 Message Cancelation 取消发送消息
邮箱还允许发送CPU
取消邮件。
TMC
寄存器中的MSG_CANCEL
位是一个自清除寄存器。源处理器可以向该位写入1
以取消消息。
设置此位后,将清除对目标处理器的中断。然后,可以将为该消息分配的消息头寄存器和消息缓冲区用于新消息。
重置处理器时,处理器发送的消息将自动取消。
2.8 Inter-Processor Wakeup 处理器内部唤醒
邮箱提供了一种机制,允许一个处理器唤醒其他处理器。
每个处理器都可以通过TMC
寄存器中的WAK_REQ
位向所有其他处理器发送唤醒请求。
有8个WAK_REQ
位,每个目标处理器一个。WAK_REQ
位是自清除的。
设置WAK_REQ
后,将断言相应处理器的唤醒中断。
目标处理器接收到唤醒中断后,可以在RWC
寄存器中设置WACK
(唤醒确认)位,以指示其已准备就绪。
WACK
位是自动清除的。设置WACK
位后,来自所有其他处理器的唤醒中断请求将被清除。
也可以从TPWES
寄存器检查唤醒状态。
TPWES
寄存器中有 8
个 WES
(唤醒事件状态)位,称为WESn
,其中n
为0-7
。每个WES
位表示处理器n
的唤醒事件状态。
当源处理器发送唤醒请求时,自动设置此字段,当目标处理器在唤醒后设置WACK
位时,自动清除此字段。
如果目标处理器不想接收来自某个源处理器的唤醒中断,它可以在RWC
寄存器中设置WEM
(唤醒事件掩码)寄存器,
以屏蔽来自某些或所有其他处理器的唤醒事件。
三、Hardware Semaphore 硬件信号量
Mailbox
为 SoC
中的多处理器同步提供 64
个硬件信号门。
硬件信号量的概念非常简单:
- 默认情况下,所有信号灯门都处于解锁状态
- 每个解锁信号门可由一个处理器锁定
- 锁定的信号灯门只能由锁定它的处理器解锁
- 当信号量门被一个处理器锁定时,它不能被其他处理器锁定
锁定和解锁操作以及规则在硬件中得到充分处理,这使得硬件信号量可靠且易于使用。
SoC
中的处理器可以利用硬件信号量实现处理器同步、数据缓冲区管理和硬件资源共享等多核协议。
3.1 Semaphore Gate Control Register 信号门控制寄存器
对于每个处理器,64
个信号量门有64
个控制寄存器,称为信号门,其中n
为0-63
。处理器可以通过这些寄存器控制信号量门。
为了为所有处理器提供统一的编程模型,每个处理器都有自己的64
个SEMAGn
寄存器,8个处理器的寄存器映射到相同的地址空间。
每个处理器只能访问自己的64个SEMAGn
寄存器。
当处理器使用其信号寄存器控制信号量门 n
时,信号量门的硬件控制逻辑知道哪个处理器正在尝试控制信号量,并将正确处理操作。下图显示了每个处理器的信号量门控制寄存器接口。
下图显示了信号量门0
的寄存器,其余信号量门的寄存器以相同的方式实现。
3.2 Lock and Unlock 加锁与解锁操作
当处理器想要锁定信号量门时,它可以通过向信号量寄存器中的SGC
(信号量门控制)位写入1
来请求锁定。
如果此信号量门未被其他处理器锁定,则锁定操作将成功,SGC
位将设置为1
。
信号量门可能已被其他处理器锁定。在这种情况下,锁定操作将失败。由于SGC
位已为1
,将1
写入SGC
位不会更改SGC
值。
锁定操作完成后,处理器可以读取SGLS[7:0]
(信号门锁定状态)字段,以检查信号门是否成功锁定。
SGLS[7:0]
中的每个位都指示哪个处理器锁定了这个信号量门。如,SGLS=8'b 00001000
表示闸门被处理器 3
锁定。
当处理器想要解锁信号量门时,它可以将0
写入SGC
位。解锁操作只能由锁定信号量门的处理器完成。
3.3 Interrupt 中断
邮箱为信号量门提供两个中断。
- 锁定失败中断
- 状态更改中断
3.3.1 Interrupt on Lock Fail 上锁失败触发中断
当处理器尝试锁定信号量门但失败时,可以向处理器触发锁定失败中断。
锁失败中断由SEMAGn
寄存器中的IESGLF
位启用。由于每个处理器都有自己的 SEMAGn
寄存器,因此每个处理器都可以启用或禁用中断。当处理器成功锁定信号量时,锁定失败中断将自动清除。软件还可以通过向SEMAGn
寄存器中的SGLIC
位写入1
来清除此中断。
3.3.2 Interrupt on Status Change 状态修改中断
状态更改中断仅在以下情况下生成:
信号量寄存器中的 IESGLF
位为信号量门 n
设置,此时CPU1
尝试锁定信号量门 n
,但它已被CPU0
锁定了,过一段时间,CPU0
释放了这个信号,此时就会触发CPU1
的中断,告知CPU1
说你要申请的信号量现在有资源了,可以申请了。
这有助于避免处理器持续轮询信号量门的状态以等待其释放的成本。
一旦处理器接收到此中断,它可以读取信号门状态更改中断寄存器 SGI0
和 SGI1
,以检查哪个信号门被释放。
通过将 1
写入 SGI0
和 SGI1
寄存器中的相应位,可以清除每个信号量门的状态更改标志。
例如,如果SGI0=0xFFFFFF
,则将 0x00000001
写入该寄存器将使其更改为 0xFFFFFE
。
当 SGI0
和 SGI1
中的所有位被清除为 0
时,处理器中断将被清除。
3.4 Semaphore Gates Reset
每个处理器都有一个信号门重置控制(SGR
)寄存器,用于将信号门重置为解锁状态。
为了为所有处理器提供统一的编程模型,每个处理器都有自己的SGR
寄存器,8个处理器的SGR
寄存器映射到相同的地址空间。
每个处理器只能访问自己的SGR
寄存器。
PSGR
位是 SGR
寄存器用于重置处理器锁定的所有信号量门。它不会重置被其他处理器锁定的信号量门。
要重置所有信号门,可以使用SGR寄存器中的全局信号门重置(
GSGR)位。向每个
GSGR位写入
1 将重置由相应处理器锁定的信号量门。 向所有8个
SGRG位写入
1`将重置所有信号量门。
在系统初始化期间,全局重置预计仅由一个处理器完成,它由全局信号量门重置启用(GSGRE
)位控制。
当GSGRE
设置为0
时,将禁用全局重置功能。为了避免修改GSGRE
,有一个粘性位GSGREL
来锁定GSGRE
位。一旦设置了GSGREL
,它将始终保持在1
,直到邮箱重置,并且软件无法修改GSGRE
位。
除软件控制的重置外,当处理器重置时,由处理器锁定的信号量门将自动重置为解锁状态。`