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