TOPPERS開発者会議2021のLTで発表した内容のスライドです。
ベアメタル向けRust std クレートの実装調査TOPPERS開発者会議2021 LT 2021/10/24Kenta Ida (@ciniml)
View Slide
自己紹介•井田 健太 (@ciniml)•仕事:FPGAの論理設計•使用言語:C++, SystemVerilog, Rust, C#•組込みRust本の1割くらい書きました(サンプルアプリ作ったり、デバッガ試したり)→2021/10/24ベアメタル向けRust std クレートの実装調査 2
ベアメタルRust2021/10/24ベアメタル向けRust std クレートの実装調査•OSが無い環境 (ベアメタル) 向けのソフトウェアをRustで開発する方法•OS機能に依存している std クレート無しでの開発• core, alloc クレートのみに依存• #[no_std]3
stdクレートが提供する機能2021/10/24ベアメタル向けRust std クレートの実装調査•process - プロセス操作•thread - スレッド操作•fs - ファイル操作• path - パス操作•net - TCP/UDP通信•io - I/O関連4
no_stdの難点2021/10/24ベアメタル向けRust std クレートの実装調査• stdクレートの提供する機能が使えない• stdクレートに依存しているクレートが使えない (e.g. ネットワーク周りなど)• no_std対応クレートのみ使用可• 一方、stdクレートの機能はベアメタルの組込みシステムでも一般的な機能• ファイル操作• TCP/UDP通信• スレッド (タスク)• RTOSがある場合5
stdクレートのベアメタル向け実装2021/10/24ベアメタル向けRust std クレートの実装調査•そもそもstdクレートが提供する機能がベアメタル向けのフレームワークにあるのであればstdクレートも実装できるはずでは?• というか、今日のメインセッションでSOLID向け実装されてましたね。• 今朝stdのソースを確認していて気づきました6
stdクレートの構造2021/10/24ベアメタル向けRust std クレートの実装調査•各トップレベルのモジュールはsys, sys_common, os サブモジュールを使って実装• sys - 各プラットフォーム向けのstdクレート実装の実体• sys_common- 各プラットフォームで共通の処理の実装• socket APIによる通信処理など• os - OS固有の処理の実装...├── os│ ├── espidf│ ├── linux│ ├── solid│ ├── unix│ ├── vxworks│ ├── wasi│ └── windows├── sys│ ├── common│ ├── itron│ ├── solid│ ├── unix│ ├── unsupported│ ├── wasi│ └── windows├── sys_common│ ├── fs.rs│ ├── io.rs│ ├── net.rs│ ├── thread.rs...7
stdクレートの依存関係2021/10/24ベアメタル向けRust std クレートの実装調査• I/O周り• 大体のプラットフォームで libc クレートにあるlibcが提供する関数を使って実装されている• net周り• 大体socket APIで実装されている• thread周り• OS依存• POSIX向け - pthreads• つまり、libc, socket, pthreadsがある環境であればそれぞれの部分は比較的容易に実装可能…なはず8
ESP32の開発環境2021/10/24ベアメタル向けRust std クレートの実装調査•ESP32• 中国Espressifが製造している無線機能付きMCU• ESP32 - CPUはXtensa LX6 (カスタム版rustcで対応)• ESP32-C3 - CPUはRISC-V RV32IMC9
ESP32の開発環境2021/10/24ベアメタル向けRust std クレートの実装調査•ESP-IDF• ESP32シリーズ向けの公式フレームワーク• C/C++で開発可能• FreeRTOS, lwIP, mbedtlsを含む• libcとしてnewlibを使用• pthreadsにある程度対応• C++11のthread対応のために元々実装されていた。• FreeRTOSの機能で実装10
ESP32のRust対応2021/10/24ベアメタル向けRust std クレートの実装調査• 2018年頃からLLVMをforkしてclang対応• LLVMはXtensaに対応していない• 有志がfork版LLVMをつかってrustcをXtensa対応• fork版LLVMの更新は継続中• 最新のLLVMに対応• upstreamにパッチを投げているが2021/5より進捗なし• RISC-V版ESP32 (ESP32-C3)登場後 stdクレート対応• 元々第3者による開発だったが、開発者はEspressifに入った模様• ESP-IDF向けだったので、Xtensa版でも動作する11
ESP-IDF向けstdクレート2021/10/24ベアメタル向けRust std クレートの実装調査•newlibによるlibc機能unix向けに条件分岐を追加して対応• https://github.com/rust-lang/rust/pull/87666•libcクレートをESP-IDFのnewlib, lwIPに合わせて修正• https://github.com/rust-lang/libc/pull/231012
libcクレートの修正 (一部)2021/10/24ベアメタル向けRust std クレートの実装調査•newlib向け実装 (src/newlib) を修正• ESP-IDF向け実装を追加 (src/newlib/espidf)•lwIP向けに定義を分岐 (例: bind関数 → lwip_bind)#[cfg_attr(target_os = "espidf", link_name = "lwip_bind")]pub fn bind(fd: ::c_int, addr: *const sockaddr, len: socklen_t) ‐> ::c_int;cfg_if! {if #[cfg(target_os = "espidf")] {mod espidf;pub use self::espidf::*;13
stdクレートの修正 (一部)2021/10/24ベアメタル向けRust std クレートの実装調査•processをサポートしないのでダミーの定義を追加impl Command {pub fn spawn(&mut self,default: Stdio,needs_stdin: bool,) ‐> io::Result<(Process, StdioPipes)> {unsupported() // Unsupportedを返す}14
stdクレートの修正 (一部)2021/10/24ベアメタル向けRust std クレートの実装調査•thread周り• スタックサイズなどが違うので条件分岐• sleepの実装を分岐#[cfg(target_os = "espidf")]pub fn sleep(dur: Duration) {let mut micros = dur.as_micros();unsafe {while micros > 0 {let st = if micros > u32::MAX as u128 { u32::MAX } else { micros as u32 };libc::usleep(st);micros ‐= st as u128;}}}15
stdクレート実装を眺めた雑感2021/10/24ベアメタル向けRust std クレートの実装調査•思ったよりも実装量は多くなさそう• libc, lwIP, pthreadsがあれば• unixモジュールに対してひたすら条件分岐追加• それ以外の場合は対応した実装が必要•使いたいプラットフォーム向けの実装をしてみたい• ESP32向けは既に公式で出たので…16
おしまい2021/10/24ベアメタル向けRust std クレートの実装調査 17