RISC-VボードNezhaでFreeBSDを使う

2026年1月。 Ubuntu 25.10 以降はRVA23 命令セットを要求する都合でNezha で動かなくなった今、この安価なRISC-Vボードを便利に使うためのOS を探していた。 できればSD カードにイメージを書くだけで動作するようなお手軽さが欲しいのだが、 Nezha では起動時にSD カードの固定オフセットからU-BootとOpenSBI をくっつけたブートローダを読む [fedoraproject.org]都合で、 イメージを作る際にNezha 固有の配慮が必要で、一般的に配布されているイメージでNezha で動作するもの探すのは難しい。

FreeBSD 15.0-RELEASE では、対応プラットフォームとしてNezha (Allwinner D1) が掲載されている。 しかし、この場合でも起動できるSD カードを作るには一工夫必要だったので、ここではその工夫を記録しておく。 また、工夫の結果のビルド成果物を配布して、Nezha を持ってる人たちがお手軽にFreeBSD やその他のOS を試せるようにする。 U-Boot はUEFI 実装として機能するので、Linux を含むFreeBSD 以外のOS を使う場合でも概ね同じ手順でいけそうだ。

このページの手順は、手元の環境としてLinux (OpenSUSE Tumbleweed) の2026年1月18日ごろの状態を使って実施している。

関連情報

FreeBSD Wiki - riscv/AllwinnerD1 [wiki.freebsd.org]にはここで紹介する手順をFreeBSD で実施した場合の流れが掲載されている。 細かいコマンドやビルド環境依存の違いはあるものの、流れは同じ。

FreeBSD をダウンロードする

15.0-RELEASE をダウンロードしてmicroSDカードに書き込む。 GENERICSD というイメージを使う。

$ curl -LOf --compressed https://download.freebsd.org/releases/ISO-IMAGES/15.0/FreeBSD-15.0-RELEASE-riscv-riscv64-GENERICSD.img.xz
$ unxz FreeBSD-15.0-RELEASE-riscv-riscv64-GENERICSD.img.xz
$ sudo dd if=FreeBSD-15.0-RELEASE-riscv-riscv64-GENERICSD.img of=/dev/sdc bs=$((2*1024*1024))

GENERICSD イメージにはHiFive のシステム向けのパーティションがあり、必要ないので削除しておく。

> sudo fdisk /dev/sdc
fdisk (util-linux 2.41.2) へようこそ。
ここで設定した内容は、書き込みコマンドを実行するまでメモリのみに保持されます。
書き込みコマンドを使用する際は、注意して実行してください。

GPT PMBR のサイズが合致していません (12582911 != 62333951) が、w (書き込み) コマンドで修正されます。
GPTテーブルのバックアップがデバイスの終端にありません。この問題は、書き込むと修正されます。

コマンド (m でヘルプ): p

ディスク /dev/sdc: 29.72 GiB, 31914983424 バイト, 62333952 セクタ
ディスク型式: SD/MMC          
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスクラベルのタイプ: gpt
ディスク識別子: 627FA1D3-CC07-11F0-A254-0CC47AD8B808

デバイス   開始位置 終了位置   セクタ サイズ タイプ
/dev/sdc1      4096     8191     4096     2M HiFive FSBL
/dev/sdc2      8192    16383     8192     4M HiFive BBL
/dev/sdc3     16384   126975   110592    54M EFI システム
/dev/sdc4    126976 12582783 12455808   5.9G FreeBSD UFS

コマンド (m でヘルプ): d
パーティション番号 (1-4, 既定値 4): 1

パーティション 1 を削除しました。

コマンド (m でヘルプ): d
パーティション番号 (2-4, 既定値 4): 2

パーティション 2 を削除しました。

コマンド (m でヘルプ): w
パーティション情報が変更されました。
ioctl() を呼び出してパーティション情報を再読み込みします。
ディスクを同期しています。

U-Boot をビルドする

とりあえず動かしたいだけの方は、私がビルドしたU-Boot のバイナリをダウンロードして次のステップへ

ビルド環境を整える

riscv64-elf-gccを中心に、U-Bootのビルドに必要なツールが使えるようにする。 幸いOpenSUSEではパッケージがあるのでそのまま利用できた。

$ sudo zypper in cross-riscv64-elf-gcc15 swig python313-pylibfdt
$ riscv64-elf-gcc -v
Using built-in specs.
COLLECT_GCC=riscv64-elf-gcc
COLLECT_LTO_WRAPPER=/usr/lib64/gcc/riscv64-elf/15/lto-wrapper
Target: riscv64-elf
Configured with: ../configure CFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' CXXFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' XCFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' TCFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' GDCFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g' --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++ --enable-checking=release --disable-werror --with-gxx-include-dir=/usr/include/c++/15 --with-libstdcxx-zoneinfo=/usr/share/zoneinfo --enable-ssp --disable-libssp --disable-libvtv --enable-cet=auto --disable-libcc1 --disable-plugin --with-bugurl=https://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --with-slibdir=/usr/riscv64-suse-linux/sys-root/lib64 --with-system-zlib --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --with-gcc-major-version-only --enable-linux-futex --enable-gnu-indirect-function --program-prefix=riscv64-elf- --target=riscv64-elf --disable-nls --with-sysroot=/usr/riscv64-suse-linux/sys-root --with-build-sysroot=/usr/riscv64-suse-linux/sys-root --with-build-time-tools=/usr/riscv64-suse-linux/bin --with-newlib --disable-multilib --disable-bootstrap --enable-link-serialization --disable-libsanitizer --build=x86_64-suse-linux --host=x86_64-suse-linux
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 15.2.1 20251006 (SUSE Linux)

OpenSBI のイメージを取得する

OpenSBI のイメージは公式ビルド, v1.8.1 [github.com]をそのまま利用可能だった。

$ curl -LOf --compressed https://github.com/riscv-software-src/opensbi/releases/download/v1.8.1/opensbi-1.8.1-rv-bin.tar.xz
$ tar xf opensbi-1.8.1-rv-bin.tar.xz
$ stat opensbi-1.8.1-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin

何らかの事情でこのバイナリが手に入りにくくなった場合は、私のビルドのアーカイブにこのファイルも含めておいたので使っても良い。

U-Bootビルド

パッチが当たったU-Boot をビルドする。 最新の環境だとSwig のAPI が変わっていて、以下実行例中にあるようにsed で機械的に 手続き名SWIG_Python_AppendOutputSWIG_AppendOutputに書き換えるとビルドが通って起動も問題なかった。

$ git clone https://github.com/smaeul/u-boot -b d1-wip u-boot-d1
$ cd u-boot-d1/
$ git rev-parse --short HEAD
2e89b706f5c
$ make nezha_defconfig
$ sed -i 's/SWIG_Python_AppendOutput/SWIG_AppendOutput/' scripts/dtc/pylibfdt/libfdt.i
$ make -j16 CROSS_COMPILE=riscv64-elf- OPENSBI=/full/path/to/opensbi-1.8.1-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin

このビルドでできるu-boot-sunxi-with-spl.bin が最終的に必要なファイル。 ここまで読んでやっぱり面倒になった方向けに、私のビルドを利用可能:

U-Boot書き込み

FreeBSD のイメージを書き込んだmicroSD カードの特定のオフセットにU-Boot のイメージを書き込む。 都合の良いことにこの場所はパーティションに割り当てられていないので、大きな工夫なくそのままdd(1) だけすればよい。

$ sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdc bs=1024 seek=128

起動

これだけ! 簡単でしょう? ここまででできたmicroSD カードをNezha に挿入し、 シリアルコンソールに接続した端末の速度を115200 bps, 8n1 に設定して電源を入れる。 FreeBSD の起動の様子はこちら。 起動後はユーザ名/パスワードとして root/root または freebsd/freebsd でログインできた。

起動後の使用メモリ量は56 MB Wired で 920 MB Free なので、Ubuntu と比較して、やりたいことのために残されているメモリ量は多そう。