▲
点击上方 关注
STM32
在此基础上,S/NS App 还需要使用片上外设等资源,实现应用程序的业务逻辑和功
能,这时候往往会遇到一些与外设使用相关的问题。
在这一篇中,我们将把重点放在 Trust Zone 架构下应用开发中使用外设的环节,从外设中断、DMA、GPIO 及其与 IO 连接的外设等几个方面,介绍这些部分与传统的不带TrustZone 的 STM32 开发相比有哪些变化,同时会列举一些相关开发中的常见问题,并给出问题的分析与解决方法,供开发者参考。
2.1 CM33 内核 TrustZone 架构下的中断
2.11 中断向量表 Vector Table
传统的 ARM V6/V7 内核,例如 CM4、CM7,都只有一套中断向量表,而带 Security
Extension 的 CM33 内核有两套中断向量表,分别对应 CPU 的 S 和 NS 两种状态,如图 1所示。在 TrustZone 的双工程开发中,S 工程和 NS 工程都会有各自的中断处理程序(interrupt handler)。他们也有各自的 VTOR,即 VTOR_S 和 VTOR_NS。体现在 linker 文件中,也都有各自的 initial vector 的地址和向量表部分。
系统上电复位后,CPU 总是处于安全状态,因此一定首先从 Secure 的 Reset Handler
开始执行代码。当 S 代码完成相关的初始化和系统配置之后,通常会跳转至 NS 代码的Reset Handler 开始执行 NS 代码。但是这里的 NS Reset Handler 其实并不是真正意义上的 interrupt handler,因为没有任何中断会直接进入这个 Handler,它仅仅是 S 代码跳转NS 代码时候的跳转入口。当发生系统复位时,硬件会忽略 NS 的 reset handler 和初始SP。系统永远都是复位到 Secure,加载 Secure 的初始 SP,并从 Secure 的 ResetHandler 开始执行。图 2 给出了 TrustZone 环境下的代码执行顺序示例。
▲
图1 带 TrustZone 的 CM33 内核的两个中断向量表
▲
图2 TrustZone 环境下的 S/NS 代码运行顺序示例
内核的两个 Vector table 中都包括系统中断和外设中断两个部分,系统中断里有一部分
是 bank 的,也就是说 S 和 NS 各有一套,互不相干,例如 Systick,PendSV,SVCall,MemoryFault,Usage Fault,这些中断的 handler 可以在 S/NS 中被各自触发,各自有各自的处理程序。有些中断只会出现在 S 侧,例如 SecureFault,而 HardFault,NMI,BusFault 则默认在 S 侧,但可以通过寄存器配置,允许 NS 侧触发相关的异常。
2.12 外设中断
中断表中的最后一类则是外设中断,即图 1 中 IRQx。这类中断属于目标二选一的中断。上电复位缺省所有 IRQx 都是 target 到 S 的,即任何一个 IRQx 都只会触发 Vectortable S 里面的中断句柄,NS 侧虽然也有同样的 IRQx 和对应的 handler,但是并不会被触发。为了能够选择 IRQx 的 target 目标世界,NVIC 中增加了一组寄存器 NVIC_ITNS0 -NVIC_ITNS15,用于指定某个 IRQx 是否 target 到 NS。上电复位后,ITNSx 寄存器默认值总是 0,也就是所有 IRQ 都 target 到 S,如果需要让某个 IRQ 触发 NS 侧的中断句柄,则需要将对应的 ITNSx 的 bit 设置为 1。
具体设置方法有两种:
在 STM32 CubeFW 软件包的 TrustZone Template 工程中通常我们会看到一个与TrustZone 有关的配置文件,文件名类似 partition_xxxx.h,这个文件里面会包含 SAU 的配置,中断的 Target 配置等等。其中,中断 target 的配置就是通过直接写 NVIC->ITNS[x]寄存器的方式完成的。需要修改配置的时候只需要定义相关的 NVIC_INIT_ITNSx 宏并修改 NVIC_INIT_ITNSx_VAL 的值即可。例如
#define NVIC_INIT_ITNS0 1
#define NVIC_INIT_ITNS0_VAL 0xFFFFFC7F
2.2 NS App 中 IRQ Handler 无法进入问题
有很多时候,客户可能是将原有其他 STM32 系列的平台上已经开发过的应用移植到CM33 内核带 TrustZone 的 STM32 产品上,通常原有的业务逻辑会放在 NS 非安全侧,安全侧则主要实现一些与信息安全相关的功能。也有可能项目本身就是在支持 TrustZone 的STM32 MCU 上进行的开发,但是刚开始并没有使能 TrustZone 功能,后面再把TrustZone 使能起来,进行完整的开发和集成。这时候,开发者往往会遇到 NS App 的外设中断无法触发的问题。
【问题现象】
NS App 外设中断在不使能 TrustZone 的环境下都能够正常工作,但是移到 TrustZone使能的环境之后,发现 NS App 的外设中断总是无法被触发,例如 UART 中断,GPIO EXTI 中断,DMA 中断等等。如果在调试器中将断点设置在中断句柄函数中,则会发现本来硬件应当触发中断的时候,NS App 的 IRQ handler 却从未进入。
【分析】
CM33 TrustZone 架构下,内核有两套中断向量表,上电复位所有的 IRQ 都缺省Target 到 S,也就是说,不做特别配置的话,外设中断只会触发 S 侧的 IRQ Handler,因此 NS App 的 IRQ Handler 一定不会有响应。通常在 Trust Zone 开发中发现 IRQ 中断句柄应当被触发却并未被触发,应当首先检查该 IRQ 的安全目标配置是否正确。
【解决方法】
在 S 工程的初始化代码中,将需要被 NS App 处理的 IRQ 都配置为 target 到 NS,可以参考 2.1.2 小节的相关说明。
这种问题往往出现在开发者直接手写代码(或者从 STM32CubeFW 软件包的TrustZone 模板工程开始)进行 TrustZone 配置的时候,因为需要配置的点可能比较多,又未必是集中在同一个代码文件中,有可能忽略了某个配置,造成问题。如果选择使用STM32CubeMX 工具生成相关的工程框架和初始化代码,用 GUI 界面的方式进行配置,则会更加简单明了,相对来说会降低出错几率。在第 5 章节中将对这部分加以简要介绍。
3.1 DMA 的 TrustZone aware 特性
STM32 MCU 中的 DMA 单元(例如 GPDMA, LPDMA)在 Trust Zone 框架下属于 TZ
aware IP,DMA 能够直接支持 AHB5 总线。
作为总线主设备,DMA 可以发出 S 安全或者 NS 非安全的 transaction。以 STM32U5
GPDMA 为例,通过 GPDMA_SECCFGR.SECx 寄存器,可以将 DMA 的 Channel 设置为安全或者非安全通道。
如果一个 Channel 具有安全属性,那么它就是一个安全 DMA 通道,Secure DMA
Channel 有能力发出 S 安全或者 NS 非安全访问,同时,S 安全代码还可以配置安全 DMA通道的 source 和 destination 数据传输的安全访问属性,安全通道对 source 和 destination的安全访问属性配置是独立的,互相之间没有依赖关系,因此配置为安全的 DMA 通道可以任意地在安全或者非安全资源之间做数据搬移,如图 3 所示。红色表示非安全访问/非安全资源,绿色表示安全访问/安全资源,从图中可以看到安全 DMA 可以访问所有不同安全属性的 source 和 destination,包括 Flash,SRAM,外设等。
这里要注意一点,如果安全 DMA 通道访问的资源是存储器,那么安全通道配置的
source 和 destination 的安全属性应当与目标资源的安全属性一致,否则无法正常访问资源的数据,会出现 RAZ/WI 的效果。
▲
图3 安全 DMA Channel 可以访问安全或者非安全资源
注意:当使用 DMA 的 link list 模式时,从 memory 中读取 link list 表数据结构时的安全访问属性与 Channel 的安全属性一致。所以 Secure Channel 加载 link list 表时,读取memory 也使用安全访问模式。
如果一个 Channel 配置为非安全属性(这也是上电复位后 DMA 的缺省状态),那么非安全 DMA Channel 只能发出 NS transaction,只能在 NS 属性的资源之间做数据搬移,
如图 3 所示。如果非安全 DMA 通道试图访问安全资源,将无法正常读写数据,通常效果是 RAZ/WI。
▲
图4 非安全 DMA Channel 只能访问非安全资源
作为总线从设备,DMA 的寄存器被访问时,也能够识别总线上的安全访问标志信号HNONSEC,根据 Channel 的安全、非安全属性会允许或者阻止对某些寄存器的访问。
当某个 Channel 被设置为 Secure,NS 代码尝试读取 Secure Channel 的寄存器会返回 0,某些寄存器除外,例如 GPDMA 的 GPDMA_SECCFGR,GPDMA_PRIVCFGR 和GPDMA_RCFGLOCKR 可以被非安全代码读取。NS 代码尝试写 S DAM Channel 的寄存器将没有任何效果。
除了安全、非安全属性,DMA Channel 还可以配置其 PRIV/NPRIV 属性(特权/非特权模式访问)。依旧以 STM32U5 GPDMA 为例,GPDMA_PRIVCFGR.PRIVx 寄存器用于配置某个 Channel 的特权模式访问属性。当某个 Channel 配置为特权模式时,这个Channel 的寄存器也只能被特权模式访问,包括读和写。某些寄存器可能存在例外,例如GPMDA 的 GPDMA_PRIVCFGR, GPDMA_SECCFGR,GPDMA_RCFGLOCKR 可以被NPRIV 模式读取。
PRIV 属性的 Channel 发出的访问都是 PRIV 特权模式访问,NPRIV 属性的 Channel发出的访问都是 NPRIV 非特权模式访问。
注意:当使用 link list 模式时,从 memory 加载 link list 表数据结构时候的访问模式与Channel 的 PRIV/NPRIV 属性一致。
当 DMA 对资源进行读写的时候,任何一个访问都会带有 S/NS 以及 PRIV/NPRIV 属性,因此 DMA 通道的 Secure 属性和 PRIV 属性配置是共同起作用的,他们会同时体现在DMA 对资源访问的 transaction 中。图 5 给出了两种 Channel 以及 Channel 对
source/destination 访问可能携带的 Secure 和 PRIV 标记的例子。Channel1 是 S+PRIV 通道,Channel2 是 NS+NPRIV 通道。当然还有可能出现其他的组合,例如 S+NPRIV 通道和 NS+PRIV 通道。DMA 访问 source 和 destination 时的 PRIV/NPRIV 属性直接遵循Channel 自身的 PRIV/NPRIV 属性,所以无论对 source 还是 destination,DMA 发出访问的 PRIV/NPRIV 属性一定是相同的;访问的 S/NS 属性在 NS Channel 中只能是 NS 访问,对 source 和 destination 都一样,而在 S Channel 中可能出现 S 或者 NS 访问,且source 和 destination 访问的安全属性可能不一样。
▲
图5 DMA Channel 的 Secure+PRIV 属性组合示例
3.2 TrustZone 架构下带有 DMA 的 Securable 外设
STM32 MCU 中可能含多个具有 DMA 功能的硬件单元,并不是所有的带 DMA 功能的硬件都是 TrustZone aware 外设。系统中除了有作为独立的总线主设备出现的GPDMA/LPDMA 等之外,还可能包含其他一些带有 DMA 功能的总线主设备,例如SDMMC、Ethernet、DMA2D 等。这些设备在使用过程中也有可能通过自身的 DMA 进行数据搬移。但是他们并不是 TZ aware 外设。
在 TrustZone 使能的环境中,这类主线主设备一般是 Securable 外设,他们并不具备像 GPDMA/LPDMA 那样的对 TrustZone AHB5 总线及 HNONSEC 信号直接支持的能力。
作为 Securable 总线主设备,他们的 TrustZone 特性通过 GTZC TZSC 的 PPC(Peripheral Protection Controller)来支持。具体说就是通过配置 TZSC 的 SECCFGRx寄存器可以让某个 Securable 外设具有安全或者非安全属性,通过配置 TSZC 的PRIVCFGRx 寄存器可以设置 Securable 外设的 PRIV/NPRIV 属性。
具体到这些总线主设备,当使用他们的 DMA 功能做数据搬移时,DMA 发出的读写操作在总线上的访问方式就取决于 SECCFGRx、PRIVCFGRx 对这个 IP 的配置。
以 SDMMC 举例
-
SDMMC 被配置为 NS+NPRIV 属性(一般这是外设上电默认所具有的安全属性),那么它的 DMA 访问就都是 NS+NPRIV 属性的。
-
SDMMC 被配置为 S+PRIV 属性,那么它的 DMA 访问都是 S+PRIV 的。
-
当然也可以是另外的两种组合:NS+PRIV,S+NPRIV。
当这类 IP 的寄存器作为总线从设备被访问的时候,它的一般访问规则是:Secure IP只允许 Secure 访问,NonSecure IP 允许 Secure 或者 NonSecure 访问;PRIV IP 只允许PRIV 访问,NPRIV IP 允许 PRIV 或者 NPRIV 访问。图 6 给出了带 DMA 功能的Securable IP 的寄存器的安全访问规则,以及他们的 DMA 发出的 transaction 与 IP 自身的
Secure/PRIV 属性的关系。类似于 TZ aware 的 DMA,当使用 link list 模式时,DMA 从memory 加载 link list 表项数据结构的时候,对 memory 的 Secure/PRIV 访问属性与 IP 自身的 Secure/PRIV 属性配置也一致。
▲
图6 Securable IP 的 Secure/PRIV 属性及 DMA 访问具有的安全属性
3.3 TrustZone 环境下使用 DMA 的常见问题
本小节总结了几个在 TrustZone 项目中使用 DMA 遇到的问题,可能也是比较常见的一类问题,给开发者做参考。
3.3.1. 问题 1:NS App 无法驱动 DMA Channel
【问题现象】
NS App 需要使用 DMA,用于 SPI 数据传输,应用中已经有相关初始化代码,但是代码运行后 App 无法控制 GPDMA Channel0。
【分析】
初始化配置后观察 DMA Channel 的寄存器,发现 GPDMA_SECCFGR 的 bit0 为 1,也就是说 DMA Channel0 被设置为了 S 安全通道。这样 NS App 肯定就无法控制Channel0 的寄存器,肯定不能正常驱动 DMA Channel0。
进一步查看 S App 的代码,客户使用了 TF-M 用来提供安全侧的一系列服务。在 TF-M代码中缺省使能了针对 TrustZone 隔离的一些测试功能,其中包括 DMA Channel 访问的测试,而这部分代码会在初始化阶段将 DMA Channle0 配置为 S+PRIV 属性,这导致了NS App 无法驱动 DMA Channel0。
【解决方法】
由于 S App 实际并不使用 DMA 实现应用功能,仅仅是为了测试目的,因此可以关闭这段与测试相关的置 DMA Channel0 为 Secure Channel 的初始化代码,保持 DMA Channel0 的 NonSecure 属性,这样 NS App 就可以正常操作这个 DMA 通道了。
3.3.2. 问题 2:NS App 中 DMA link list 模式无法正常工作
【问题现象】
NS App 需要使用 SRAM1,片外 PSRAM,DCMI 以及 DMA 等。DMA 需要对
PSRAM 数据进行搬移,并且使用了链表结构。
在 S 工程中已经将需要的资源配置为
NonSecure,且 NS App 能够正常运行起来。
但是 DMA 无法按照 link list 的数据定义完成
数据搬移。
【分析】
通过调试发现,初始化后,DMA 的配置都可以正常完成,SRAM1 中也有正确的 link list 链表数据,但是当 DMA 完成第一组搬移后,需要从链表数据结构中加载下一组搬移配置时,链表数据加载完成后,对应 DMA 寄存器的值是 0。这说明 DMA 没有从 SRAM1 中正确加载链表数据。
由于 NS App 本身需要使用 SRAM1,而 NS App 是可以正常执行的,这说明 SRAM1
已经配置为 NS 属性,允许 NS 访问。
进一步查看代码发现,S 工程中对 SRAM1 的
GTZC MPCBB 配置中,仅仅配置了 NS 属性,而 SRAM 上电默认具有 S+PRIV 属性,也
就是说,经过 GTZC MPCBB 对 SRAM1 的配置,SRAM1 的属性为 NS+PRIV,因此不允
许 NPRIV 的访问。
而 GPDMA Channel 上电默认属性为 NS+NPRIV。
那么他做任何访问
都只能是 NS+NPRIV 属性。
这解释了为什么 DMA 从 SRAM1 中加载链表数据结构时出
错。
【解决方法】
要解决问题这个问题,只要保证 DMA 的访问权限等于或者高于被访问目标允许的访问
权限就可以。
那么修改方法有两个:
这两种方法都可以让 NS App 中的 DMA 成功完成链表模式的数据搬移操作。
在这个小节的内容中我们可以看到 DMA 在 TrustZone 架构下有额外的安全访问配置,
当然这些配置可以通过直接手写代码完成,其实也可以通过 STM32CubeMX 工具在图形
界面中完成所有的配置。
这样产生的初始化代码更加容易保持配置的一致性。
在第 5 章节
中也会对这部分做出简要介绍。
微信推文篇幅有限,点击按钮下载《
STM32 TrustZone 开发调试技巧 | 外设使用常见问题》全文
。