Rust编程语言因其独特的安全性、性能和生产力组合而受到关注。Rust旨在消除常见的编程负担并处理编译时use-after-free错误等问题。值得注意的是,它在不使用垃圾回收器的情况下实现了这一点,生成的机器代码的性能可与C和C++相媲美。
在这个由三部分组成的博客系列中,Ferrous Systems 的高级工程师兼培训师Jonathan Pallant概述了Arm架构的Rust支持,包括对 Ferrocene的介绍,Ferrocene 是用于任务关键型和安全关键型应用的合格Rust工具链。对于任何考虑将Rust用于下一个基于Arm的项目的人来说,这个概述都是必不可少的。
本系列探讨了从广泛的Arm领域中挑选的三个示例,研究了在裸机、RTOS和Rich OS应用程序上使用Rust的细节。此外,它还讨论了Ruston Arm的现状,重点介绍了Rust项目和第三方提供的功能和库,无论是否有商业支持。
图1:编写Rust应用程序的方法
第1部分:裸机系统
我们将探讨的第一个领域是运行纯Rust编写的裸机应用的微控制器案例。在第二部分中,我们将在其基础上加入一个已有的用C或C++编写的实时操作系统(RTOS)。
这里使用的术语“微控制器”指的是带有集成SRAM(可能还有Flash)的小型片上系统(SoC)。在Arm架构上,这些设备在AArch32模式下执行T32指令集,但有些系统可能会使用A32指令集。这里讨论的许多“裸机”问题同样适用于较大应用处理器上的低级代码,比如安全启动固件或虚拟机监视器。然而,本节将着眼于运行在nRF52-DK开发套件上的NordicnRF52840微控制器。这款流行的微控制器包含一个ArmCortex-M4处理器,以及256KiB的SRAM和1MiB的Flash。
针对ArmCortex-M的裸机Rust固件可以依赖由Rust嵌入式设备工作组提供的启动代码,这些代码封装在一个名为cortex-m-rt的crate中。这个crate允许固件完全用Rust编写——所需的少量内联汇编(例如,在main之前初始化数据段)被捆绑在cortex-m-rt内部,它只需带你走到Rust的fn main()函数处即可。
当系统启动并运行Rust代码时,有一个丰富的驱动程序生态系统可供选择。例如,nrf-hal项目为我们的nRF52840中的每个外设提供了驱动程序。实际上,许多基于Arm的微控制器都有一套出色的开源驱动程序,包括来自NordicSemi、STMicro和RaspberryPi的许多驱动。
像embedded-hal这样的跨平台抽象让这些驱动程序可以用标准化的方式描述外设,使用户能够构建可重用的组件和库,这些组件和库可以在任何合适的实现上工作,即使跨越不同的芯片制造商。在2021年最近的芯片短缺期间,许多使用Rust的嵌入式系统开发者发现这一点非常有用,因为根据可用性更换微控制器变得容易得多。
如果您以前没有见过裸机Rust代码,图2提供了一个针对nRF52840的完整“blinky”示例。
图2:用于nRF52-DK的最小但完整的Rust“blinky”,使用提供UART驱动程序,GPIO等的开源板支持包。
如示例所示,Rust允许开发丰富的API来描述各种硬件接口,如LED和UART。然而,Rust编译器内置的强大优化器产生的机器代码与C编译器产生的机器代码大致相似。
图1中显示的Led类型(支持nrf52.leds.led_2值)在运行时不占用内存。它是所谓的零大小类型。这意味着系统类型可用于将安全性和稳健性引入API,而绝对没有运行时开销。
当然,对于许多应用程序来说,这已经足够了,但开发人员不仅限于使用Rust在微控制器上编写基本的事件循环和中断例程。
基于ArmCortex-M的微控制器可以运行AsyncRust,使用纯Rust编写的小型轻量级异步执行器,例如embassy。这通常是启动完整RTOS的一种高效且经济的替代方案,尤其是当您只需要同时执行少量任务时。
但有时,完整的RTOS才是正确的解决方案。在第2部分中,我们将探讨如何将Rust与现有的C API集成,包括使用Free RTOS和Eclipse ThreadX等RTOS的实际示例。
图3:nRF52840 DK(来源:Nordic Semiconductor)
第二部分:Arm上高级Rust与RTOS的集成
在本博客系列的第1部分中,我们探讨了如何使用Rust在Arm微控制器上构建裸机应用程序。在第2部分中,我们将重点介绍如何将Rust与微控制器和中型微处理器上的实时操作系统(RTOS)进行集成。
大多数现有的RTOS都是用C编写的,因此在其上运行的任何Rust程序都需要与现有的CAPI交互。RTOS的示例包括但不限于Eclipse ThreadX、Free RTOS或Zephyr。
在Arm上,这些系统通常在AArch32模式下在Cortex-R52等处理器上执行A32指令;尽管这里的概念同样适用于Cortex-M4、Cortex-M55或类似产品。
图1:编写Rust应用程序的方法
Rust支持导入和导出兼容C的函数、原始指针、易失性内存访问以及内联汇编,以实现低级别的硬件交互。一个完整的演示超出了博客文章的范围,因此FerrousSystems发布了一个开源示例应用,该应用使用Eclipse ThreadXRTOS,并针对Arm Cortex-R5在Arm Versatile ApplicationBoard上(以及Arm PL011UART、Arm PL190向量中断控制器和Arm SP804双定时器)。
这个例子将ThreadX编译为静态C库,然后将其链接到由Rust和Arm汇编混合编写的二进制文件中。此示例可以使用Ferrocene或标准Rust工具链进行编译。
就像第一部分提到的裸机微控制器一样,在这些实时系统上,通常无法使用完整的Rust标准库。相反,用户被限制在一个更为基本的子集libcore中。
虽然不是不可能做到——对于FreeRTOS和NuttX等存在Rust标准库移植版,但这些系统通常非常关注资源分配和性能,因此创建高性能绑定到所需的RTOS部分比尝试将RTOS抽象到更适合应用处理器API的做法更有意义。这种方法对功能安全系统也有利,因为在Rust中认证一个小的自定义RTOS接口比认证整个Rust标准库更实际。
在ThreadX的例子中,汇编语言启动代码设置堆栈指针并启用浮点单元(FPU)后,执行权被交给用Rust编写的main函数。Rust代码初始化外设驱动程序,然后将执行权交给ThreadX调度器。ThreadX设置的一部分涉及通过一个名为tx_application_define的函数回调到Rust固件中,该函数是用Rust编写的,但声明为具有“C兼容”的接口。此函数用于为任务堆栈创建字节池和生成各种任务。图2展示了如何轻松地用Rust调用CAPI的一个片段。
图2:使用Rust创建ThreadX字节池的示例。threadx_sys crate包含基于RTOS的C头文件自动生成的绑定。
threadx_syscrate包含基于RTOSC头文件自动生成的绑定。代替手动转换ThreadX头文件为Rust,示例使用bindgen工具自动为ThreadX生成Rust绑定。
这个最初由Mozilla开发并由Ferrous Systems支持的工具几乎可以应用于任何带有标准C头文件的库,例如ThreadX提供的库。示例使用来自bindgen的自动生成绑定,允许Rust代码调用任何ThreadX函数,而RTOS可以回调到任何标记为extern"C"链接的Rust函数。
ThreadX源代码必须使用标准C编译器编译,这在示例中是自动处理的。然后告诉Rust将生成的libthreadx.a链接到编译后的Rust代码,以生成最终的二进制文件。
在我们的示例中,启动代码是用Rust编写的,但你可能更倾向于让RTOS从C处理启动和驱动初始化,只将任务用Rust编写。或者,你可以使用完全用Rust编写的RTOS,如OxidOS。一般步骤保持不变:将你需要的库代码编译成静态库,然后使用这些静态库编译和链接二进制文件。无论是RTOS作为库还是作为二进制文件,变化不大,只是编译顺序有所不同。
请参阅第3部分,我们将探讨如何在Arm处理器上使用Rust和Linux、Windows和macOS等成熟的操作系统。
图3:实时操作系统通常用于工业和汽车应用程序。
第三部分,我们将探索在Arm处理器上使用Rust与完整操作系统如Linux、Windows和macOS的应用。
在本博客系列的第一部分中,我们探讨了使用Rust在Arm微控制器上构建裸机应用程序。第二部分深入研究了将Rust与实时操作系统(RTOS)集成在微控制器和中型微处理器上的应用。现在,在第三部分中,我们将注意力转向使用Rust与完整操作系统如Linux、Windows、macOS、QNX或Android在Arm处理器上的应用。
在Arm架构上,这些系统通常执行A64指令,在AArch64模式下运行,例如在RaspberryPi5中找到的Cortex-A76,或者最新AWSGraviton云服务器中的NeoverseV2。Rust还为32位Arm系统提供了良好的支持,例如Cortex-A8和Arm11,甚至可以追溯到1990年代的Arm7。图1展示了编写Rust应用程序的方法。
图1:编写Rust应用程序的方法
在应用处理器上,你通常可以访问完整的Rust标准库。这个库抽象了许多特定于操作系统的接口,提供了一致的API用于线程、文件系统、网络等,无论操作系统是什么。这意味着开发者可以使用他们喜欢的开发平台,并且可以确信相同的源代码可以在比如基于Linux的生产系统上编译。
为了展示Rust的高层次表达能力,图2显示了一个示例Rust应用程序。
图2:在Rust中处理文本文件
图1中的代码读取一个UTF-8编码的文本文件到堆分配的String中,如果文件无法打开则干净地退出。随后逐行处理它变得非常简单,这要归功于内置的迭代器支持——这个例子查找以"MESSAGE:"开头的行并打印匹配行的其余部分。这种高层API的感觉像Java或C#,但具有C应用程序的性能——这是Rust的独特优势。
开箱即用的交叉编译
Rust工具链不仅仅包括编译器;它还包括一个结合了构建系统和包管理器的工具叫做cargo。这个工具大大简化了构建Rust应用程序的过程——通常只需要一条简单的cargobuild--release命令就可以构建最复杂的项目。作为构建的一部分,cargo可以从第三方包仓库(如crates.io)下载依赖项,解析语义版本,并为你的项目构建一个完整的依赖树——包括重要的开源许可信息。
Rust编译器本身也是一个开箱即用的交叉编译器。这意味着不像某些C编译器,你不需要安装特定版本的编译器来适应任何给定的主机或目标组合。相反,你可以使用rustup(Rust工具链管理器),下载并安装适合你所选目标的预编译Rust标准库,然后就可以开始工作了。图3展示了如何使用rustup添加对新目标的支持,例如针对Armv7架构的32位ArmLinux的交叉编译。
图3:使用rust up添加对新目标的支持
Rust项目将其支持的目标分为几个级别。一级是最高级别,这里的任何目标都会在每次Rust发布时进行编译和测试。这一级包括64位ArmLinux,以及x86Linux、Windows和macOS。
二级目标会进行编译,但不会运行测试套件。这一级包括上面提到的Armv7Linux示例。三级目标仅提供尽力而为的支持,这里是更奇特的目标所在——例如NintendoSwitch上的Rust,或者LinuxonArm7上的Rust。目前,三级目标仅支持使用‘nightly’Rust工具链,而不支持稳定版本。值得注意的是,Rust就像C和C++一样,需要一个适合你目标平台的链接器。对于许多目标,捆绑的LLVM链接器‘lld’可以工作,但在某些情况下,你可能需要安装特定的链接器。
对于那些需要超出标准Rust层级系统提供的支持的人来说,Ferrocene提供了解决方案。Ferrocene是商业支持的Rust工具链下游产品,由Ferrous Systems制作。Arm和Ferrous Systems紧密合作,使得特定硬件目标能够在Ferrocene中可用,这些目标在上游Rust项目中可能只作为二级或三级目标。Ferrocene目标通过了Rust测试套件,并且其中一部分已经通过TÜVSüd认证,适用于ISO26262ASIL-D和IEC61508SIL-4,还有更多的行业特定认证正在计划中。
掌握整个Arm谱系上的Rust
本博客系列探讨了从广泛的Arm设备谱系中选取的三个例子,并深入研究了在这个平台上使用Rust的具体情况。我们看到,无论是要在现有的完全成熟的操作系统上构建,还是与实时操作系统协作,或者是裸机开发,Rust都能帮助开发者构建高性能、安全和可靠的软件。它提供的特性使开发者能够比使用传统语言更快地进入生产阶段。
类型检查允许构造难以误用的API,这意味着你更有可能正确使用它们——节省宝贵的调试时间。借用检查意味着缓冲区溢出和释放后使用错误在“安全”Rust中实际上是不可能的,而你只需要在我们的项目可能用来与硬件或操作系统交互的那一小部分“不安全”Rust代码中检查这些问题。来自使用LLVM优化的结果是,无论是在应用处理器、实时系统还是微控制器上,Rust生成的二进制文件在性能上都与C和C++相当。
如果你正在寻找带有商业支持和可选功能安全认证的Rust编译器,请查看FerrousSystems提供的Ferrocene。Ferrocene当前提供经过ISO26262ASIL-D和IEC61508SIL-4认证的AArch64裸机目标编译器,同时面向32位ArmCortex-R和Cortex-M目标的资格认证也正在进行中。
图4:树莓派5 https://www.raspberrypi.com/documentation/computers/raspberry-pi.html
本文翻译自“community.arm.com”
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
关于亿道电子
上海亿道电子技术有限公司是国内资深的研发工具软件提供商,公司成立于2009年,面向中国广大的制造业客户提供研发、设计、管理过程中使用的各种软件开发工具,致力于帮助客户提高研发管理效率、缩短产品设计周期,提升产品可靠性。
十多年来,先后与ARM、Altium、Ansys、QT、Green Hills、Minitab、EPLAN、QA Systems、OpenText、Visu-IT、HighTec、PLS、Ashling、MSC Software、Autodesk、Source Insight、IncrediBuild、Lauterbach、Adobe、Testplant、TeamEDA等多家全球知名公司建立战略合作伙伴关系,并作为他们在中国区的主要分销合作伙伴服务了数千家中国本土客户,为客户提供从芯片级开发工具、EDA设计工具、软件编译以及测试工具、结构设计工具、仿真工具、电气设计工具、以及嵌入式GUI工具等等。亿道电子凭借多年的经验积累,真正的帮助客户实现了让研发更简单、更可靠、更高效的目标。
欢迎关注“亿道电子”公众号
了解更多研发工具软件知识