2023年04月28日
RustでAArch64(QEMU)ベアメタルプログラミング
私は担当ではないので詳しくないのですが、弊社では Rust の開発環境を提供しています。
https://www.kmckk.co.jp/pdf/20211020_solid_press.pdf
それとは特に関係なく、諸事情で Rust で書かれたライブラリをベアメタル環境で使う必要が出てきたので、遅ればせながら Rust の勉強を始めました。
まずはこのチュートリアルをやってみた所、予想外にいろいろハマってしまい、情報も少なくて困ったので、うまくいった方法をメモしておきます。(私も初心者なので、このやり方が正しいとは限りません。)
AArch64 Bare-Metal program in Rust
https://lowenware.com/blog/aarch64-bare-metal-program-in-rust/
https://www.kmckk.co.jp/pdf/20211020_solid_press.pdf
それとは特に関係なく、諸事情で Rust で書かれたライブラリをベアメタル環境で使う必要が出てきたので、遅ればせながら Rust の勉強を始めました。
まずはこのチュートリアルをやってみた所、予想外にいろいろハマってしまい、情報も少なくて困ったので、うまくいった方法をメモしておきます。(私も初心者なので、このやり方が正しいとは限りません。)
AArch64 Bare-Metal program in Rust
https://lowenware.com/blog/aarch64-bare-metal-program-in-rust/
使用したのは以下のインストーラです。これは SOLID-rust で使用している(自動でインストールされる)ものをそのまま使用したということですが、今思うとこれが良くなかったのかもしれません。(後述する "is-builtin": true 問題)
https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe
Rust で aarch64 クロスコンパイルする都合上、MinGW x64 のツールが誤って実行されないように、MSYS2 MSYS 上で作業しました。以下はチュートリアルの通りです。
https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe
Rust で aarch64 クロスコンパイルする都合上、MinGW x64 のツールが誤って実行されないように、MSYS2 MSYS 上で作業しました。以下はチュートリアルの通りです。
$ rustup update $ rustup default nightly $ cargo install cargo-xbuild $ rustup component add rust-src $ cargo new aarch64-bare-metal --bin --edition 2018ファイルを準備します。panic.rs、start.s、aarch64-qemu.ld はチュートリアルと同じで問題ありませんでしたが、main.rs のみ global_asm が stable 入りした影響で少し修正する必要がありました。
#![no_std]
#![no_main]
use core::ptr;
use core::arch::global_asm;
mod panic;
global_asm!(include_str!("start.s"));
#[no_mangle]
pub extern "C" fn not_main() {
const UART0: *mut u8 = 0x0900_0000 as *mut u8;
let out_str = b"AArch64 Bare Metal";
for byte in out_str {
unsafe {
ptr::write_volatile(UART0, *byte);
}
}
}
以下で生成される json もチュートリアルとは大きく異なりました。
$ rustc -Z unstable-options --print target-spec-json --target aarch64-unknown-none > aarch64-unknown-none.jsonハマったのは "is-builtin" が true だと、以下のようなエラーが出ることです。
$ cargo xbuild --target=aarch64-unknown-none.json error: failed to run `rustc` to learn about target-specific information Caused by: process didn't exit successfully: `rustc - --crate-name ___ --print=file-names -Cembed-bitcode=yes --target '\\?\C:\msys64\home\kmc\test\rust\test\aarch64-bare-metal\aarch64-unknown-none.json' --cra te-type bin --crate-type rlib --crate-type dylib --crate-type cdylib --crate-type staticlib --crate- type proc-macro --print=sysroot --print=split-debuginfo --print=crate-name --print=cfg` (exit code: 1) --- stderr error: Error loading target specification: may not set is_builtin for targets not built-in. Run `r ustc --print target-list` for a list of built-in targets error: `"\\\\?\\C:\\Users\\kmc\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\\bin\\cargo.exe" "rustc" "-p" "alloc" "--release" "--manifest-path" "C:\\msys64\\tmp\\cargo-xbuildAY7le5\\Cargo.toml " "--target" "aarch64-unknown-none.json" "--" "-Z" "force-unstable-if-unmarked"` failed with exit co de: Some(101)aarch64-unknown-none.json に、リンカスクリプトの定義を追加して "is-builtin":false に変更し、最終的には以下のようになりました。
{
"arch": "aarch64",
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
"disable-redzone": true,
"features": "+v8a,+strict-align,+neon,+fp-armv8",
"is-builtin": false,
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"pre-link-args": {
"ld.lld": ["-Taarch64-qemu.ld"]
},
"llvm-target": "aarch64-unknown-none",
"max-atomic-width": 128,
"panic-strategy": "abort",
"relocation-model": "static",
"supported-sanitizers": [
"kcfi",
"kernel-address"
],
"target-pointer-width": "64"
}
これでコンパイルしたバイナリを、先日のブログの QEMU で実行して動作しました。
$ PATH=/c/msys64/mingw64/bin/:$PATH ~/test/QEMU/install/qemu-system-aarch64.exe -machine virt -m 1024M -cpu cortex-a53 -nographic -kernel target/aarch64-unknown-none/debug/aarch64-bare-metal AArch64 Bare Metal(ビルドした QEMU は MSYS2 MinGW x64 の dll に依存しているので、PATH を通しています。)