RISC-V Linuxを動かしてみる(on QEMU/SPIKE)

# 動機
最近良く聞くRISC-Vを動かしてみたい。
基本は手順どおり進めただけだけど、いくつかエラーに遭遇したので備忘のために投稿しとく。

# 環境
- OS: Ubuntu 16.04
- CPU: Intel(R) Core(TM) i7-3517U CPU @ 1.90GHz x4

# 方法1. Fedoraの作成済イメージを動かす
[RISC-V版QEMUでLinuxを立ち上げる試行](http://msyksphinz.hatenablog.com/entry/2018/05/07/040000)
めちゃくちゃ楽。感謝感謝です。
ただ楽すぎてほとんどやることがない。

# 方法2. yoctoでビルドする
[riscv-poky](https://github.com/riscv/riscv-poky)
結構楽。ビルドに結構時間はかかるけど。
※ちなみに試したのは、[こちら](https://github.com/riscv/riscv-poky/commit/cd3cba2bb49b9366ed10f2b81bffed071da5dc85)の状態。


## ビルド手順

```shell
$ git clone https://github.com/riscv/riscv-poky.git
$ cd riscv-poky
$ source oe-init-build-env
$ bitbake core-image-riscv
```

## Trouble Shooting
### 1. gitのバージョン
yoctoなので、ほとんどのホストツールも自動でビルドしてくれるが、gitはnativeのものをそのまま使う。
Ubuntu 16.04のaptで入るgit 2.18.0 (2018/7/20時点)ではobsoleteされている`--set-upstream`オプションが使われているので、エラーになってしまう。

```diff
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py
index 534c93d3c5..88b99bdc03 100644
--- a/bitbake/lib/bb/fetch2/git.py
+++ b/bitbake/lib/bb/fetch2/git.py
@@ -485,7 +485,7 @@ class Git(FetchMethod):
                 branchname =  ud.branches[ud.names[0]]
                 runfetchcmd("%s checkout -B %s %s" % (ud.basecmd, branchname, \
                             ud.revisions[ud.names[0]]), d, workdir=destdir)
-                runfetchcmd("%s branch --set-upstream %s origin/%s" % (ud.basecmd, branchname, \
+                runfetchcmd("%s branch --set-upstream-to=origin/%s %s" % (ud.basecmd, branchname, \
                             branchname), d, workdir=destdir)
             else:
                 runfetchcmd("%s checkout %s" % (ud.basecmd, ud.revisions[ud.names[0]]), d, workdir=destdir)
```

### 2. riscv-qemuのfetchに失敗する

recipeで指定しているrevisionがfetchできないというエラーに遭遇する。
riscv-pokyの[issue#15](https://github.com/riscv/riscv-poky/issues/15)に回避策も上がっていた。

```diff
diff --git a/meta-riscv/recipes-devtools/qemu/qemu_2.5.0.bb b/meta-riscv/recipes-devtools/qemu/qemu_2.5.0.bb
index 578c74dd51..235bdffe5a 100644
--- a/meta-riscv/recipes-devtools/qemu/qemu_2.5.0.bb
+++ b/meta-riscv/recipes-devtools/qemu/qemu_2.5.0.bb
@@ -1,6 +1,6 @@
 require recipes-devtools/qemu/qemu.inc
 
-SRC_URI = "gitsm://github.com/riscv/riscv-qemu.git;destsuffix=${S}"
+SRC_URI = "git://github.com/riscv/riscv-qemu.git;rev=9bfcd4717b3010eb7efc50057232e92ecb741cac;nobranch=1;destsuffix=${S}"
 SRCREV_pn-qemu-native = "9bfcd4717b3010eb7efc50057232e92ecb741cac"
 SRCREV_pn-nativesdk-qemu = "9bfcd4717b3010eb7efc50057232e92ecb741cac"
 
```

## SPIKE起動
ちなみにSPIKEというのは、RISC-Vの標準シミュレータのこと。

```
$ runspike riscv64

Continuing with the following parameters:
KERNEL: [riscv-poky/build/tmp/deploy/images/riscv64/vmlinux-riscv64.bin]
ROOTFS: [riscv-poky/build/tmp/deploy/images/riscv64/core-image-riscv-riscv64-20180720134101.rootfs.ext2]
FSTYPE: [ext2]
SPIKE_BIN: [riscv-poky/build/tmp/work/riscv64-poky-linux/core-image-riscv/1.0-r0/recipe-sysroot-native/usr/bin/spike]
BBL_PATH: [riscv-poky/build/tmp/work/riscv64-poky-linux/riscv-pk/1.0-r0/build/bbl]

[    0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[    0.000000] Linux version 4.13.0 (oe-user@oe-host) (gcc version 7.2.0 (GCC)) #1 Fri Jul 20 23:41:04 JST 2018
[    0.000000] bootconsole [early0] enabled
[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x0000000080200000-0x00000000ffffffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000080200000-0x00000000ffffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x00000000ffffffff]
[    0.000000] elf_hwcap is 0x112d
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 516615
[    0.000000] Kernel command line: root=/dev/sbi-disk 
[    0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
[    0.000000] Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.000000] Inode-cache hash table entries: 131072 (order: 8, 1048576 bytes)
[    0.000000] Sorting __ex_table...
[    0.000000] software IO TLB [mem 0xfa0ed000-0xfe0ed000] (64MB) mapped at [ffffffe079eed000-ffffffe07deecfff]
[    0.000000] Memory: 1994216K/2095104K available (1660K kernel code, 148K rwdata, 466K rodata, 76K init, 750K bss, 100888K reserved, 0K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
[    0.000000] riscv,cpu_intc,0: 64 local interrupts mapped
[    0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x24e6a1710, max_idle_ns: 440795202120 ns
[    0.000000] console [hvc0] enabled
[    0.000000] console [hvc0] enabled
[    0.000000] bootconsole [early0] disabled
[    0.000000] bootconsole [early0] disabled
[    0.000000] Calibrating delay loop (skipped), value calculated using timer frequency.. 20.00 BogoMIPS (lpj=40000)
[    0.000000] pid_max: default: 32768 minimum: 301
[    0.000000] Mount-cache hash table entries: 4096 (order: 3, 32768 bytes)
[    0.004000] Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes)
[    0.004000] devtmpfs: initialized
[    0.004000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.004000] futex hash table entries: 256 (order: 0, 6144 bytes)
[    0.008000] random: get_random_u32 called from bucket_table_alloc+0x7c/0x1e6 with crng_init=0
[    0.008000] NET: Registered protocol family 16
[    0.008000] vgaarb: loaded
[    0.008000] clocksource: Switched to clocksource riscv_clocksource
[    0.008000] NET: Registered protocol family 2
[    0.008000] TCP established hash table entries: 16384 (order: 5, 131072 bytes)
[    0.012000] TCP bind hash table entries: 16384 (order: 5, 131072 bytes)
[    0.012000] TCP: Hash tables configured (established 16384 bind 16384)
[    0.012000] UDP hash table entries: 1024 (order: 3, 32768 bytes)
[    0.012000] UDP-Lite hash table entries: 1024 (order: 3, 32768 bytes)
[    0.012000] NET: Registered protocol family 1
[    0.012000] workingset: timestamp_bits=62 max_order=19 bucket_order=0
[    0.012000] random: fast init done
[    0.028000] jitterentropy: Initialization failed with host not compliant with requirements: 2
[    0.028000] io scheduler noop registered
[    0.028000] io scheduler cfq registered (default)
[    0.028000] io scheduler mq-deadline registered
[    0.028000] io scheduler kyber registered
[    0.036000] disk [sbi-disk] of 737095680 bytes loaded
[    0.040000] VFS: Mounted root (ext2 filesystem) readonly on device 254:0.
[    0.040000] devtmpfs: mounted
[    0.040000] Freeing unused kernel memory: 76K
[    0.040000] This architecture does not have kernel memory protection.
INIT: version 2.88 booting
hwclock: can't open '/dev/misc/rtc': No such file or directory
Fri Jul 20 15:53:09 UTC 2018
hwclock: can't open '/dev/misc/rtc': No such file or directory
INIT: Entering runlevel: 5
Configuring network interfaces... ifconfig: SIOCGIFFLAGS: No such device
hwclock: can't open '/dev/misc/rtc': No such file or directory
Starting syslogd/klogd: done

Poky (Yocto Project Reference Distro) 2.3 riscv64 /dev/console

riscv64 login: root
root
root@riscv64:~# cat /proc/cpuinfo
cat /proc/cpuinfo
hart	: 0
isa	: rv64imafdc
mmu	: sv48

root@riscv64:~# readelf -h /usr/bin/readelf
readelf -h /usr/bin/readelf
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           RISC-V
  Version:                           0x1
  Entry point address:               0x122d4
  Start of program headers:          64 (bytes into file)
  Start of section headers:          467296 (bytes into file)
  Flags:                             0x5, RVC, double-float ABI
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         8
  Size of section headers:           64 (bytes)
  Number of section headers:         27
  Section header string table index: 26
root@riscv64:~# uname -a
Linux riscv64 4.13.0 #1 Fri Jul 20 23:41:04 JST 2018 riscv64 riscv64 riscv64 GNU/Linux
```

動いた！
ちゃんとRISC-Vになってる！


# 感想
先人たちのおかげでもう十分遊べる。
情報が不足していることを危惧していたが、今回試した範囲ぐらいだったら、むしろ情報がまとまってる印象。
まだ試せてないけど、[riscv-tools](https://github.com/riscv/riscv-tools)に書かれてい手順で最低限のrootfsでLinux起動できるっぽいので、それも今度やってみよう。