SiFive HiFive 1 Rev Bで遊んだ

セキュリティキャンプ2019にチューターとして参加しているときにhikalium先生からHiFive1 RevBというものを借りて、https://github.com/PG-MANA/RuscV (Rustで書かれたOSもどき)を試してみようとビルドしたので記録します。

まずHiFive1はRISCV-32 IMACなアーキテクチャなのですが、RuscVはRISCV-64 IMAC向けに書いていたので(というよりテストしていたので)、大幅に書き換えました。

地味にメモリ配置もHiFive1とHiFive1 Rev Bで違うのでつまづきました。

まずriscv32-unknown-none.jsonを作成して以下の内容にします。

{
  "abi-blacklist": [
    "cdecl",
    "stdcall",
    "fastcall",
    "vectorcall",
    "thiscall",
    "aapcs",
    "win64",
    "sysv64",
    "ptx-kernel",
    "msp430-interrupt",
    "x86-interrupt",
    "amdgpu-kernel"
  ],
  "llvm-target": "riscv32-unknown-none",
  "data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
  "linker-flavor": "gcc",
  "cpu": "generic-rv32",
  "target-endian": "little",
  "target-pointer-width": "32",
  "target-c-int-width": "32",
  "arch": "riscv32",
  "os": "none",
  "features": "+m,+a",
  "disable-redzone": true,
  "panic-strategy": "abort",
  "relocation-model": "static",
  "atomic-cas": true,
  "max-atomic-width": "32"
}

次にリンカスクリプトをconfig/riscv32/hifive.ldとして

MEMORY {
    rom : ORIGIN = 0x20010000, LENGTH = 0x6a120
    ram : ORIGIN = 0x80000000, LENGTH = 0x4000
}

ENTRY(_main)

SECTIONS {
    .boot_entry : {} > rom
    .text : {*(.text*)} > rom
    .rodata : {*(.rodata*)} > rom
    .bss : {*(.bss*)} > ram
} 

としてください。(サンプルなどを漁って適当に作ったので実用化のときはもっとちゃんとしてください…)

ツールチェーンはビルドしても良いですが、公式(https://www.sifive.com/boards)からPrebuilt RISC‑V GCC Toolchainを持ってきてください。(riscv64のバイナリだがriscv32も扱えるみたい)。またexportでもしてパスを通してください。

Makefileを以下のようにします。

#環境設定
##名前
NAME = ruscv

##ターゲット
TARGET_ARCH = $(2)
ifeq ($(strip $(TARGET_ARCH)),)
    TARGET_ARCH = riscv32
endif
RUST_TARGET = $(TARGET_ARCH)-unknown-none
#RUST_TARGET_FILE_FOLDER = target-json/ # https://github.com/japaric/xargo/issues/146

##ディレクトリ
SRC = src/
MAKE_BASEDIR ?= $(shell pwd)/
MAKE_BINDIR = $(MAKE_BASEDIR)bin/
MAKE_IMGDIR = $(MAKE_BINDIR)img/
MAKE_TMPDIR = $(MAKE_BASEDIR)tmp/
MAKE_OBJDIR = $(MAKE_TMPDIR)obj/
MAKE_CONGIGDIR =  $(MAKE_BASEDIR)config/$(TARGET_ARCH)/

##ソフトウェア
STRIP= riscv64-unknown-elf-strip
##↑変更
MKDIR = mkdir -p
CP = cp -r
RM = rm -rf
LD = riscv64-unknown-elf-ld -n --gc-sections -Map $(MAKE_TMPDIR)$(NAME).map -nostartfiles -nodefaultlibs -m elf32lriscv -nostdlib -T $(MAKE_CONGIGDIR)hifive1.ld
CARGO = cargo
QEMU = qemu-system-riscv32 --nographic -machine sifive_e

##ビルドファイル
KERNELFILES = kernel.elf
RUST_OBJ = target/$(RUST_TARGET)/release/lib$(NAME).a
BOOT_SYS_LIST = $(RUST_OBJ)

#初期設定
export TARGET_ARCH
export MAKE_BINDIR
export MAKE_TMPDIR
export MAKE_OBJDIR


#各コマンド
##デフォルト動作
default:
	$(MAKE) kernel
	-$(STRIP) $(MAKE_BINDIR)*.elf #できなくてもいい

##初期化動作
init:
	-$(MKDIR) $(MAKE_BINDIR)
	-$(MKDIR) $(MAKE_TMPDIR)
	-$(MKDIR) $(MAKE_OBJDIR)

clean:
	$(RM) $(MAKE_TMPDIR)
	$(CARGO) clean

kernel:
	$(MAKE) init
	$(MAKE) $(KERNELFILES)

#run:
#	$(MAKE) kernel
#	$(QEMU) -kernel bin/kernel.elf

# ファイル生成規則
kernel.elf : $(BOOT_SYS_LIST)
	$(LD) -o $(MAKE_BINDIR)kernel.elf $(BOOT_SYS_LIST)

$(RUST_OBJ) :  .FORCE
	$(CARGO) xbuild --release --target $(RUST_TARGET_FILE_FOLDER) $(RUST_TARGET)

.FORCE:

そんなわけでmakeする(make runは動きません)とkernel.elfができるので

riscv64-unknown-elf-objcopy  -O ihex kernel.elf kernel.hex
とするとhexファイルができるので、HiFive1をUSB接続してUSBメモリとして認識されたのちにkernel.hexを放り込むとフラッシュされて再起動します。
リセットと同時にcuコマンドなどでUSBシリアル通信をすると「Hello, RISC-V!」と表示されると思います。

もとのWelcome表示に戻すにはサンプルをビルドしないといけないのですが、ビルドチェーンは配布されてるバイナリを利用してnano.specsの記述を削除するなり、色々手間が必要だったので注意してください。せっかくなので、Welcomeサンプルの
HiFive1 RevB用のHexファイルを上げておきます。(Apache Licence 2.0)
https://repo.taprix.org/pg_mana/riscv/hifive1revb/

投稿者: PG_MANA

支離滅裂な自称プログラマー。 C,C++,Rust,JavaScript,PHP,HTML,CSS,OS自作,openSUSE,Arch,旅行 なんか色々してる人 #seccamp 17 19 20 23 #OtakuAssembly