Rust編程語(yǔ)言因其獨(dú)特的安全性、性能和生產(chǎn)力組合而受到關(guān)注。Rust旨在消除常見(jiàn)的編程負(fù)擔(dān)并處理編譯時(shí)use-after-free錯(cuò)誤等問(wèn)題。值得注意的是,它在不使用垃圾回收器的情況下實(shí)現(xiàn)了這一點(diǎn),生成的機(jī)器代碼的性能可與C和C++相媲美。
在這個(gè)由三部分組成的博客系列中,Ferrous Systems 的高級(jí)工程師兼培訓(xùn)師Jonathan Pallant概述了Arm架構(gòu)的Rust支持,包括對(duì) Ferrocene的介紹,F(xiàn)errocene 是用于任務(wù)關(guān)鍵型和安全關(guān)鍵型應(yīng)用的合格Rust工具鏈。對(duì)于任何考慮將Rust用于下一個(gè)基于Arm的項(xiàng)目的人來(lái)說(shuō),這個(gè)概述都是必不可少的。
本系列探討了從廣泛的Arm領(lǐng)域中挑選的三個(gè)示例,研究了在裸機(jī)、RTOS和Rich OS應(yīng)用程序上使用Rust的細(xì)節(jié)。此外,它還討論了Ruston Arm的現(xiàn)狀,重點(diǎn)介紹了Rust項(xiàng)目和第三方提供的功能和庫(kù),無(wú)論是否有商業(yè)支持。

圖1:編寫Rust應(yīng)用程序的方法
第1部分:裸機(jī)系統(tǒng)
我們將探討的第一個(gè)領(lǐng)域是運(yùn)行純Rust編寫的裸機(jī)應(yīng)用的微控制器案例。在第二部分中,我們將在其基礎(chǔ)上加入一個(gè)已有的用C或C++編寫的實(shí)時(shí)操作系統(tǒng)(RTOS)。
這里使用的術(shù)語(yǔ)“微控制器”指的是帶有集成SRAM(可能還有Flash)的小型片上系統(tǒng)(SoC)。在Arm架構(gòu)上,這些設(shè)備在AArch32模式下執(zhí)行T32指令集,但有些系統(tǒng)可能會(huì)使用A32指令集。這里討論的許多“裸機(jī)”問(wèn)題同樣適用于較大應(yīng)用處理器上的低級(jí)代碼,比如安全啟動(dòng)固件或虛擬機(jī)監(jiān)視器。然而,本節(jié)將著眼于運(yùn)行在nRF52-DK開(kāi)發(fā)套件上的NordicnRF52840微控制器。這款流行的微控制器包含一個(gè)ArmCortex-M4處理器,以及256KiB的SRAM和1MiB的Flash。
針對(duì)ArmCortex-M的裸機(jī)Rust固件可以依賴由Rust嵌入式設(shè)備工作組提供的啟動(dòng)代碼,這些代碼封裝在一個(gè)名為cortex-m-rt的crate中。這個(gè)crate允許固件完全用Rust編寫——所需的少量?jī)?nèi)聯(lián)匯編(例如,在main之前初始化數(shù)據(jù)段)被捆綁在cortex-m-rt內(nèi)部,它只需帶你走到Rust的fn main()函數(shù)處即可。
當(dāng)系統(tǒng)啟動(dòng)并運(yùn)行Rust代碼時(shí),有一個(gè)豐富的驅(qū)動(dòng)程序生態(tài)系統(tǒng)可供選擇。例如,nrf-hal項(xiàng)目為我們的nRF52840中的每個(gè)外設(shè)提供了驅(qū)動(dòng)程序。實(shí)際上,許多基于Arm的微控制器都有一套出色的開(kāi)源驅(qū)動(dòng)程序,包括來(lái)自NordicSemi、STMicro和RaspberryPi的許多驅(qū)動(dòng)。
像embedded-hal這樣的跨平臺(tái)抽象讓這些驅(qū)動(dòng)程序可以用標(biāo)準(zhǔn)化的方式描述外設(shè),使用戶能夠構(gòu)建可重用的組件和庫(kù),這些組件和庫(kù)可以在任何合適的實(shí)現(xiàn)上工作,即使跨越不同的芯片制造商。在2021年最近的芯片短缺期間,許多使用Rust的嵌入式系統(tǒng)開(kāi)發(fā)者發(fā)現(xiàn)這一點(diǎn)非常有用,因?yàn)楦鶕?jù)可用性更換微控制器變得容易得多。
如果您以前沒(méi)有見(jiàn)過(guò)裸機(jī)Rust代碼,圖2提供了一個(gè)針對(duì)nRF52840的完整“blinky”示例。

圖2:用于nRF52-DK的最小但完整的Rust“blinky”,使用提供UART驅(qū)動(dòng)程序,GPIO等的開(kāi)源板支持包。
如示例所示,Rust允許開(kāi)發(fā)豐富的API來(lái)描述各種硬件接口,如LED和UART。然而,Rust編譯器內(nèi)置的強(qiáng)大優(yōu)化器產(chǎn)生的機(jī)器代碼與C編譯器產(chǎn)生的機(jī)器代碼大致相似。
圖1中顯示的Led類型(支持nrf52.leds.led_2值)在運(yùn)行時(shí)不占用內(nèi)存。它是所謂的零大小類型。這意味著系統(tǒng)類型可用于將安全性和穩(wěn)健性引入API,而絕對(duì)沒(méi)有運(yùn)行時(shí)開(kāi)銷。
當(dāng)然,對(duì)于許多應(yīng)用程序來(lái)說(shuō),這已經(jīng)足夠了,但開(kāi)發(fā)人員不僅限于使用Rust在微控制器上編寫基本的事件循環(huán)和中斷例程。
基于ArmCortex-M的微控制器可以運(yùn)行AsyncRust,使用純Rust編寫的小型輕量級(jí)異步執(zhí)行器,例如embassy。這通常是啟動(dòng)完整RTOS的一種高效且經(jīng)濟(jì)的替代方案,尤其是當(dāng)您只需要同時(shí)執(zhí)行少量任務(wù)時(shí)。
但有時(shí),完整的RTOS才是正確的解決方案。在第2部分中,我們將探討如何將Rust與現(xiàn)有的C API集成,包括使用Free RTOS和Eclipse ThreadX等RTOS的實(shí)際示例。

圖3:nRF52840 DK(來(lái)源:Nordic Semiconductor)
第二部分:Arm上高級(jí)Rust與RTOS的集成
在本博客系列的第1部分中,我們探討了如何使用Rust在Arm微控制器上構(gòu)建裸機(jī)應(yīng)用程序。在第2部分中,我們將重點(diǎn)介紹如何將Rust與微控制器和中型微處理器上的實(shí)時(shí)操作系統(tǒng)(RTOS)進(jìn)行集成。
大多數(shù)現(xiàn)有的RTOS都是用C編寫的,因此在其上運(yùn)行的任何Rust程序都需要與現(xiàn)有的CAPI交互。RTOS的示例包括但不限于Eclipse ThreadX、Free RTOS或Zephyr。
在Arm上,這些系統(tǒng)通常在AArch32模式下在Cortex-R52等處理器上執(zhí)行A32指令;盡管這里的概念同樣適用于Cortex-M4、Cortex-M55或類似產(chǎn)品。

圖1:編寫Rust應(yīng)用程序的方法
Rust支持導(dǎo)入和導(dǎo)出兼容C的函數(shù)、原始指針、易失性內(nèi)存訪問(wèn)以及內(nèi)聯(lián)匯編,以實(shí)現(xiàn)低級(jí)別的硬件交互。一個(gè)完整的演示超出了博客文章的范圍,因此FerrousSystems發(fā)布了一個(gè)開(kāi)源示例應(yīng)用,該應(yīng)用使用Eclipse ThreadXRTOS,并針對(duì)Arm Cortex-R5在Arm Versatile ApplicationBoard上(以及Arm PL011UART、Arm PL190向量中斷控制器和Arm SP804雙定時(shí)器)。
這個(gè)例子將ThreadX編譯為靜態(tài)C庫(kù),然后將其鏈接到由Rust和Arm匯編混合編寫的二進(jìn)制文件中。此示例可以使用Ferrocene或標(biāo)準(zhǔn)Rust工具鏈進(jìn)行編譯。
就像第一部分提到的裸機(jī)微控制器一樣,在這些實(shí)時(shí)系統(tǒng)上,通常無(wú)法使用完整的Rust標(biāo)準(zhǔn)庫(kù)。相反,用戶被限制在一個(gè)更為基本的子集libcore中。
雖然不是不可能做到——對(duì)于FreeRTOS和NuttX等存在Rust標(biāo)準(zhǔn)庫(kù)移植版,但這些系統(tǒng)通常非常關(guān)注資源分配和性能,因此創(chuàng)建高性能綁定到所需的RTOS部分比嘗試將RTOS抽象到更適合應(yīng)用處理器API的做法更有意義。這種方法對(duì)功能安全系統(tǒng)也有利,因?yàn)樵赗ust中認(rèn)證一個(gè)小的自定義RTOS接口比認(rèn)證整個(gè)Rust標(biāo)準(zhǔn)庫(kù)更實(shí)際。
在ThreadX的例子中,匯編語(yǔ)言啟動(dòng)代碼設(shè)置堆棧指針并啟用浮點(diǎn)單元(FPU)后,執(zhí)行權(quán)被交給用Rust編寫的main函數(shù)。Rust代碼初始化外設(shè)驅(qū)動(dòng)程序,然后將執(zhí)行權(quán)交給ThreadX調(diào)度器。ThreadX設(shè)置的一部分涉及通過(guò)一個(gè)名為tx_application_define的函數(shù)回調(diào)到Rust固件中,該函數(shù)是用Rust編寫的,但聲明為具有“C兼容”的接口。此函數(shù)用于為任務(wù)堆棧創(chuàng)建字節(jié)池和生成各種任務(wù)。圖2展示了如何輕松地用Rust調(diào)用CAPI的一個(gè)片段。

圖2:使用Rust創(chuàng)建ThreadX字節(jié)池的示例。threadx_sys crate包含基于RTOS的C頭文件自動(dòng)生成的綁定。
threadx_syscrate包含基于RTOSC頭文件自動(dòng)生成的綁定。代替手動(dòng)轉(zhuǎn)換ThreadX頭文件為Rust,示例使用bindgen工具自動(dòng)為ThreadX生成Rust綁定。
這個(gè)最初由Mozilla開(kāi)發(fā)并由Ferrous Systems支持的工具幾乎可以應(yīng)用于任何帶有標(biāo)準(zhǔn)C頭文件的庫(kù),例如ThreadX提供的庫(kù)。示例使用來(lái)自bindgen的自動(dòng)生成綁定,允許Rust代碼調(diào)用任何ThreadX函數(shù),而RTOS可以回調(diào)到任何標(biāo)記為extern"C"鏈接的Rust函數(shù)。
ThreadX源代碼必須使用標(biāo)準(zhǔn)C編譯器編譯,這在示例中是自動(dòng)處理的。然后告訴Rust將生成的libthreadx.a鏈接到編譯后的Rust代碼,以生成最終的二進(jìn)制文件。
在我們的示例中,啟動(dòng)代碼是用Rust編寫的,但你可能更傾向于讓RTOS從C處理啟動(dòng)和驅(qū)動(dòng)初始化,只將任務(wù)用Rust編寫。或者,你可以使用完全用Rust編寫的RTOS,如OxidOS。一般步驟保持不變:將你需要的庫(kù)代碼編譯成靜態(tài)庫(kù),然后使用這些靜態(tài)庫(kù)編譯和鏈接二進(jìn)制文件。無(wú)論是RTOS作為庫(kù)還是作為二進(jìn)制文件,變化不大,只是編譯順序有所不同。
請(qǐng)參閱第3部分,我們將探討如何在Arm處理器上使用Rust和Linux、Windows和macOS等成熟的操作系統(tǒng)。

圖3:實(shí)時(shí)操作系統(tǒng)通常用于工業(yè)和汽車應(yīng)用程序。
第三部分,我們將探索在Arm處理器上使用Rust與完整操作系統(tǒng)如Linux、Windows和macOS的應(yīng)用。
在本博客系列的第一部分中,我們探討了使用Rust在Arm微控制器上構(gòu)建裸機(jī)應(yīng)用程序。第二部分深入研究了將Rust與實(shí)時(shí)操作系統(tǒng)(RTOS)集成在微控制器和中型微處理器上的應(yīng)用。現(xiàn)在,在第三部分中,我們將注意力轉(zhuǎn)向使用Rust與完整操作系統(tǒng)如Linux、Windows、macOS、QNX或Android在Arm處理器上的應(yīng)用。
在Arm架構(gòu)上,這些系統(tǒng)通常執(zhí)行A64指令,在AArch64模式下運(yùn)行,例如在RaspberryPi5中找到的Cortex-A76,或者最新AWSGraviton云服務(wù)器中的NeoverseV2。Rust還為32位Arm系統(tǒng)提供了良好的支持,例如Cortex-A8和Arm11,甚至可以追溯到1990年代的Arm7。圖1展示了編寫Rust應(yīng)用程序的方法。

圖1:編寫Rust應(yīng)用程序的方法
在應(yīng)用處理器上,你通常可以訪問(wèn)完整的Rust標(biāo)準(zhǔn)庫(kù)。這個(gè)庫(kù)抽象了許多特定于操作系統(tǒng)的接口,提供了一致的API用于線程、文件系統(tǒng)、網(wǎng)絡(luò)等,無(wú)論操作系統(tǒng)是什么。這意味著開(kāi)發(fā)者可以使用他們喜歡的開(kāi)發(fā)平臺(tái),并且可以確信相同的源代碼可以在比如基于Linux的生產(chǎn)系統(tǒng)上編譯。
為了展示Rust的高層次表達(dá)能力,圖2顯示了一個(gè)示例Rust應(yīng)用程序。

圖2:在Rust中處理文本文件
圖1中的代碼讀取一個(gè)UTF-8編碼的文本文件到堆分配的String中,如果文件無(wú)法打開(kāi)則干凈地退出。隨后逐行處理它變得非常簡(jiǎn)單,這要?dú)w功于內(nèi)置的迭代器支持——這個(gè)例子查找以"MESSAGE:"開(kāi)頭的行并打印匹配行的其余部分。這種高層API的感覺(jué)像Java或C#,但具有C應(yīng)用程序的性能——這是Rust的獨(dú)特優(yōu)勢(shì)。
開(kāi)箱即用的交叉編譯
Rust工具鏈不僅僅包括編譯器;它還包括一個(gè)結(jié)合了構(gòu)建系統(tǒng)和包管理器的工具叫做cargo。這個(gè)工具大大簡(jiǎn)化了構(gòu)建Rust應(yīng)用程序的過(guò)程——通常只需要一條簡(jiǎn)單的cargobuild--release命令就可以構(gòu)建最復(fù)雜的項(xiàng)目。作為構(gòu)建的一部分,cargo可以從第三方包倉(cāng)庫(kù)(如crates.io)下載依賴項(xiàng),解析語(yǔ)義版本,并為你的項(xiàng)目構(gòu)建一個(gè)完整的依賴樹——包括重要的開(kāi)源許可信息。
Rust編譯器本身也是一個(gè)開(kāi)箱即用的交叉編譯器。這意味著不像某些C編譯器,你不需要安裝特定版本的編譯器來(lái)適應(yīng)任何給定的主機(jī)或目標(biāo)組合。相反,你可以使用rustup(Rust工具鏈管理器),下載并安裝適合你所選目標(biāo)的預(yù)編譯Rust標(biāo)準(zhǔn)庫(kù),然后就可以開(kāi)始工作了。圖3展示了如何使用rustup添加對(duì)新目標(biāo)的支持,例如針對(duì)Armv7架構(gòu)的32位ArmLinux的交叉編譯。

圖3:使用rust up添加對(duì)新目標(biāo)的支持
Rust項(xiàng)目將其支持的目標(biāo)分為幾個(gè)級(jí)別。一級(jí)是最高級(jí)別,這里的任何目標(biāo)都會(huì)在每次Rust發(fā)布時(shí)進(jìn)行編譯和測(cè)試。這一級(jí)包括64位ArmLinux,以及x86Linux、Windows和macOS。
二級(jí)目標(biāo)會(huì)進(jìn)行編譯,但不會(huì)運(yùn)行測(cè)試套件。這一級(jí)包括上面提到的Armv7Linux示例。三級(jí)目標(biāo)僅提供盡力而為的支持,這里是更奇特的目標(biāo)所在——例如NintendoSwitch上的Rust,或者LinuxonArm7上的Rust。目前,三級(jí)目標(biāo)僅支持使用‘nightly’Rust工具鏈,而不支持穩(wěn)定版本。值得注意的是,Rust就像C和C++一樣,需要一個(gè)適合你目標(biāo)平臺(tái)的鏈接器。對(duì)于許多目標(biāo),捆綁的LLVM鏈接器‘lld’可以工作,但在某些情況下,你可能需要安裝特定的鏈接器。
對(duì)于那些需要超出標(biāo)準(zhǔn)Rust層級(jí)系統(tǒng)提供的支持的人來(lái)說(shuō),F(xiàn)errocene提供了解決方案。Ferrocene是商業(yè)支持的Rust工具鏈下游產(chǎn)品,由Ferrous Systems制作。Arm和Ferrous Systems緊密合作,使得特定硬件目標(biāo)能夠在Ferrocene中可用,這些目標(biāo)在上游Rust項(xiàng)目中可能只作為二級(jí)或三級(jí)目標(biāo)。Ferrocene目標(biāo)通過(guò)了Rust測(cè)試套件,并且其中一部分已經(jīng)通過(guò)TüVSüd認(rèn)證,適用于ISO26262ASIL-D和IEC61508SIL-4,還有更多的行業(yè)特定認(rèn)證正在計(jì)劃中。
掌握整個(gè)Arm譜系上的Rust
本博客系列探討了從廣泛的Arm設(shè)備譜系中選取的三個(gè)例子,并深入研究了在這個(gè)平臺(tái)上使用Rust的具體情況。我們看到,無(wú)論是要在現(xiàn)有的完全成熟的操作系統(tǒng)上構(gòu)建,還是與實(shí)時(shí)操作系統(tǒng)協(xié)作,或者是裸機(jī)開(kāi)發(fā),Rust都能幫助開(kāi)發(fā)者構(gòu)建高性能、安全和可靠的軟件。它提供的特性使開(kāi)發(fā)者能夠比使用傳統(tǒng)語(yǔ)言更快地進(jìn)入生產(chǎn)階段。
類型檢查允許構(gòu)造難以誤用的API,這意味著你更有可能正確使用它們——節(jié)省寶貴的調(diào)試時(shí)間。借用檢查意味著緩沖區(qū)溢出和釋放后使用錯(cuò)誤在“安全”Rust中實(shí)際上是不可能的,而你只需要在我們的項(xiàng)目可能用來(lái)與硬件或操作系統(tǒng)交互的那一小部分“不安全”Rust代碼中檢查這些問(wèn)題。來(lái)自使用LLVM優(yōu)化的結(jié)果是,無(wú)論是在應(yīng)用處理器、實(shí)時(shí)系統(tǒng)還是微控制器上,Rust生成的二進(jìn)制文件在性能上都與C和C++相當(dāng)。
如果你正在尋找?guī)в猩虡I(yè)支持和可選功能安全認(rèn)證的Rust編譯器,請(qǐng)查看FerrousSystems提供的Ferrocene。Ferrocene當(dāng)前提供經(jīng)過(guò)ISO26262ASIL-D和IEC61508SIL-4認(rèn)證的AArch64裸機(jī)目標(biāo)編譯器,同時(shí)面向32位ArmCortex-R和Cortex-M目標(biāo)的資格認(rèn)證也正在進(jìn)行中。

圖4:樹莓派5 https://www.raspberrypi.com/documentation/computers/raspberry-pi.html
本文翻譯自“community.arm.com”
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
關(guān)于億道電子
上海億道電子技術(shù)有限公司是國(guó)內(nèi)資深的研發(fā)工具軟件提供商,公司成立于2009年,面向中國(guó)廣大的制造業(yè)客戶提供研發(fā)、設(shè)計(jì)、管理過(guò)程中使用的各種軟件開(kāi)發(fā)工具,致力于幫助客戶提高研發(fā)管理效率、縮短產(chǎn)品設(shè)計(jì)周期,提升產(chǎn)品可靠性。
十多年來(lái),先后與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等多家全球知名公司建立戰(zhàn)略合作伙伴關(guān)系,并作為他們?cè)谥袊?guó)區(qū)的主要分銷合作伙伴服務(wù)了數(shù)千家中國(guó)本土客戶,為客戶提供從芯片級(jí)開(kāi)發(fā)工具、EDA設(shè)計(jì)工具、軟件編譯以及測(cè)試工具、結(jié)構(gòu)設(shè)計(jì)工具、仿真工具、電氣設(shè)計(jì)工具、以及嵌入式GUI工具等等。億道電子憑借多年的經(jīng)驗(yàn)積累,真正的幫助客戶實(shí)現(xiàn)了讓研發(fā)更簡(jiǎn)單、更可靠、更高效的目標(biāo)。

歡迎關(guān)注“億道電子”公眾號(hào)
了解更多研發(fā)工具軟件知識(shí)

首頁(yè) > 新聞資訊
