QEMUでRISC-Vベアメタルプログラミング(ヨロシク編)
Mac上のQEMUでRISC-Vベアメタルプログラミングしてみる。
事前準備
QEMUとRISC-Vのツールチェインは事前にインストールしておく。
ソース
レジスタs0に値(0x4649 = ヨロシク)をセットして無限ループするだけのサンプルプログラムを用意する。
code:my_loop.S
.text
.globl _start
.type _start, @function
_start:
li s0, 0x4649
loop:
j loop
リンカスクリプト
リンカスクリプトも用意する。今回ターゲットとするVirtIOボードはアドレス0x80000000番地から実行が始まるのでそこにプログラムを配置する。
code:my_baremetal.ld
MEMORY {
RAM (RWX) : ORIGIN = 0x80000000, LENGTH = 0x40000000
}
SECTIONS {
.text : {
*(.text)
_end = .; /* 後日 malloc で使う予定 */
}
}
ビルド
asでオブジェクトファイルを生成、ldでオブジェクトファイルから実行ファイル(ELFファイル)を生成する。
code:sh
$ riscv-none-embed-as -march=rv32if -mabi=ilp32f my_loop.S -o my_loop.o
$ riscv-none-embed-ld -m elf32lriscv -b elf32-littleriscv --no-relax -Tmy_baremetal.ld my_loop.o -o my_loop.elf
(上記はFemtoRVインストール時にインストールされるRISC-Vツールチェインを使ってるけど、riscv64の方でも大丈夫)
code:sh
$ riscv64-unknown-elf-as -march=rv32if -mabi=ilp32f my_loop.S -o my_loop.o
$ riscv64-unknown-elf-ld -m elf32lriscv -b elf32-littleriscv --no-relax -Tmy_baremetal.ld my_loop.o -o my_loop.elf 
逆アセンブル(これはやらなくてもいい)
出来上がった my_loop.elf を逆アセンブルして中身を確認。問題なさそう。
code:sh
$ riscv-none-embed-objdump -S my_loop.elf
my_loop.elf:     file format elf32-littleriscv
Disassembly of section .text:
80000000 <_start>:
80000000:       00004437                lui     s0,0x4
80000004:       64940413                addi    s0,s0,1609 # 4649 <_start-0x7fffb9b7>
80000008 <loop>:
80000008:       0000006f                j       80000008 <loop>
実行
先ほど作成したELFファイルを指定してQEMUを実行する。
code:sh
$ qemu-system-riscv32 -M virt -monitor stdio -bios my_loop.elf
引数の意味は以下のとおり。
-bios my_loop.elf
先ほど作成した実行ファイル
-M virt
ターゲットボード。何でもいいんだけど今回は「RISC-V VirtIO board = virt」で
-monitor stdio
QEMUモニタはターミナルに表示した方が見やすいため「-monitor stdio」を指定
実行結果を確認
QEMUを起動してプログラムを実行すると一緒にQEMUモニタも立ち上がるので、info registersコマンドでレジスタの中身を確認する。レジスタs0に「4649」がセットされている。また、プログラムカウンタ(PC)の値が「80000008」で、ちゃんと無限ループできてるっぽい。
code:sh
$ qemu-system-riscv32 -M virt -monitor stdio -bios my_loop.elf
(qemu) info registers
pc       80000008
mhartid  00000000
mstatus  00000000
mstatush 00000000
mip      00000000
mie      00000000
mideleg  00000000
medeleg  00000000
mtvec    00000000
stvec    00000000
mepc     00000000
sepc     00000000
mcause   00000000
scause   00000000
mtval    00000000
stval    00000000
mscratch 00000000
sscratch 00000000
satp     00000000
x0/zero  00000000 x1/ra    00000000 x2/sp    00000000 x3/gp    00000000
x4/tp    00000000 x5/t0    80000000 x6/t1    00000000 x7/t2    00000000
x8/s0    00004649 x9/s1    00000000 x10/a0   00000000 x11/a1   87000000
x12/a2   00001028 x13/a3   00000000 x14/a4   00000000 x15/a5   00000000
x16/a6   00000000 x17/a7   00000000 x18/s2   00000000 x19/s3   00000000
x20/s4   00000000 x21/s5   00000000 x22/s6   00000000 x23/s7   00000000
x24/s8   00000000 x25/s9   00000000 x26/s10  00000000 x27/s11  00000000
x28/t3   00000000 x29/t4   00000000 x30/t5   00000000 x31/t6   00000000
参考
RISC-V QEMU で動作するベアメタルプログラム - How do you like Quantum ?
RISC-V OSを作ろう (1) ~ブート処理
リンカスクリプトを理解しよう
QEMUに入門してみる(10. QEMUでのベアメタルバイナリの実行方法調査)
RISC-Vのベアメタル入門(自分用)
RISC-V from scratch 2: Hardware layouts, linker scripts, and C runtimes