• 正文
  • 相关推荐
申请入驻 产业图谱

一个跟安全属性相关的DMA方式UART发送异常话题

22小时前
143
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

有人使用STM32H563芯片并开启TrustZone。UART3位于Secure侧且启用DMA发送。ADC1位于Non-Secure侧,转换结果在NS侧处理完毕后,通过NSC接口调用Secure侧的UART3实施打印。调试中发现,NSC函数写法不同,现象也不同——要么正常输出,要么完全没有打印输出。

下面先看看两种代码的写法。

写法1、拷贝方式

在NSC函数里,先把NS侧待打印的字符串拷贝到Secure 侧的缓冲区,然后启动DMA方式的UART打印。代码类似这样:

CMSE_NS_ENTRY voidSECURE_UART_PrintString(constchar *str){ uint32_tlen = 0U; staticuint8_ts_tx_buf[MaxStringLength]; if((str == NULL) || (uart_tx_busy != 0U)) {return; } while((str[len] != '') && (len < (sizeof(s_tx_buf) - 1U))) {s_tx_buf[len] = (uint8_t)str[len];len++; }s_tx_buf[len] = ''; if(len == 0U) {return; }uart_tx_busy = 1U; if(HAL_UART_Transmit_DMA(&huart3, s_tx_buf, len) != HAL_OK) {uart_tx_busy = 0U; }}

写法2、地址传送方式

在NSC函数里直接将NS侧字符串地址交给DMA,即不做数据拷贝。代码类似这样:

CMSE_NS_ENTRY voidSECURE_UART_PrintString(constchar *str){ uint32_tlen = 0U; if((str == NULL) || (uart_tx_busy != 0U)) {return; } while((str[len] != '') && (len < (MaxStringLength - 1U))) {len++; } if(len == 0U) {return; }uart_tx_busy = 1U; if(HAL_UART_Transmit_DMA(&huart3, (uint8_t *)str, len) != HAL_OK) {uart_tx_busy = 0U; }}

调试过程中,刚开始使用的就是第一种拷贝方式的写法,即将NS侧的数据拷贝到S侧后再让DMA来使用,此时的打印输出是正常的。如下图所示:

后来,可能觉得NSC函数里的拷贝操作有点多余,就拿掉了拷贝操作相关代码,直接将待打印的数据缓冲地址给DMA来使用。这一改却导致没有ADC结果的输出显示了。如果改回拷贝方式又回归正常,这是怎么回事呢?DMA目前在S侧,访问NS侧数据应该没啥毛病啊?还是说是有别的原因?

直到尝试从S侧的DMA配置找原因,发现DMA的安全属性并不只是通道可以配置,访问的源端及目的端的安全属性也可以配置。刚开始的配置【基于CubeMx配置后自动生成的】是这样的:

显然,目前所用DMA通道本身为Secure属性。不过,我们还得关注它要访问的两端的安全属性,这里赫然显示,源端应是Secure属性才符合它的访问要求。至于目的端,就是UART3 TX寄存器,自然是Secure属性。

上面拷贝方式的NSC函数,借助拷贝操作,实则将NS侧的数据复制进了S侧,正好符合此时DMA的访问规则,故功能正常。而采用地址传送方式的NSC函数,只是将NS侧数据的地址给到了DMA,作为DMA的访问源端,此时就意味着本应访问S属性源的,结果去访问NS属性的源,发生安全属性不匹配,导致传输失败。

既然这样,如果我们将DMA要访问的源端属性改成NoSecure是否就可以采用地址传送方式,最终实现UART的打印输出呢?

其实确实可以。即当DMA的配置成上面样子时,采用地址传送方式调用UART打印也就成功了。对于STM32H5系列的GPDMA,其安全属性配置粒度可以细到DMA通道,即同一DMA模块不同通道可能呈现不同的安全属性。

若某DMA通道为安全属性,它将访问的源端或目的端的属性是可以配置的。当然,若该DMA通道为非安全属性,不难理解,它能访问的源端或目的端都只能是非安全侧。

OK,今天话题就分享到这里,供君参考。下次再聊~!

相关推荐