ひまわり

はやく人間になりたい

Linux on RISC-V Linux KVM on RISC-V QEMU

先週,

QEMU: RISC-V 64のhypervisor extensionを有効にするほうほう - ひまわり

QEMU上のHost LinuxKVMが無事動いているところは先週確かめた
今回はその上で実際にGuest Linuxをboot させる

前回つかったv5のパッチの次にv6が出ていたが、とりあえずは前のままでいく KVM RISC-V Support [LWN.net]

KVMのクライアントはQEMUを筆頭にいくつかあるが、既にRISC-V patchが用意されているkvmtoolを使う

kvmtoolは, Linuxが動かせるlight weightな, KVM clientらしく、最低限のdevice emulationであり、hostと異なるアーキテクチャに対応いなかったりといった、特徴をもつ
昔は, Linuxに取り込まれていたらしいが、今は離れている

www.phoronix.com

IntelやARMがパッチを投げているらしく、ARMが出している説明の資料はすぐ見つかった https://elinux.org/images/4/44/Przywara.pdf

気になるのであれば, 参照してほしい.

Build kvmtool

これを Host のLinuxで動かすための準備をする

Hostは, RISC-V Linuxなので、gcc, ld, binutils, libc, etcのtoolchainが必要だが、riscv-gnu-toolchainがあるので、準備は簡単。 ビルド方法等は前回のに簡単あり、自分もそれをそのまま使った

kvmtoolは, Linuxのメーリスにあったのをそのまま使おうとしたが、うまく行かなかったので、forkしてちょっと手を加えたものを使う

GitHub - sux2mfgj/kvmtool at riscv_v1

これのビルドには、FDT(Flattened device tree)や、libyamlが必要なので、それもビルドする ビルド前に、CROSS_COMPILEとPATHは適切に変更する 依存的には, kvmtool -> libfdt -> libyaml

まずlibyamlから

$ git clone  git@github.com:yaml/libyaml.git 
$ ./bootstrap
$ ./configure --prefix=${tool installed root} --host=x86_64-pc-linux-gnu
$ make && make install

つぎに、fdt(libfdt), dtc内部にあるので、dtcを持ってくる

$ git clone git://git.kernel.org/pub/scm/utils/dtc/dtc.git   
$ cd dtc
$ export CC=${CROSS_COMPILE}gcc
$ export PKG_CONFIG_LIBDIR=${tool installed root}/lib/pkgconfig
$ make DESTDIR=${tool installed root} PREFIX=${tool installed root} LIBDIR=${tool installed root}/lib install-lib install-includes

そして、kvmtool

$ git clone git@github.com:sux2mfgj/kvmtool.git
$ git checkout -b riscv_v1 remotes/sux2mfgj/riscv_v1 
$ make ARCH=riscv prefix=${tool installed root} lkvm-static

これで生成される、lkvm-staticを initramfsへ入れる

$ cp lkvm-static ${initramfs root}/apps/

あと、boot時に devtmpfsをmountされてほしいので、 busyboxのinitを有効にしてビルドした後、

$ cat ${initramfs root}/etc/init.d/rcS
#!/bin/ash

mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev

となるよう、追加する

次に、これらを内包するinitramfsをつくる

$ cd ${initramfs root}
$ find . | cpio -o -H newc | gzip > ../initrd.img
Boot guest!!

これで準備は完成

後は起動するだけだが、initrdが少し大きくなったのと、Guest Linuxを動かす為, QEMUに与えるメモリはある程度大きくしないと、 HostかGuestの起動時にinitramfsを展開するメモリがなくて死んでしまうので気をつける

Hostの起動は前回と同じ。 うまくHostとなるLinuxが起動できたら、 Guestを実行する

$ ./apps/lkvm-static run -m 1024 -c 2 --console serial -p "console=ttyS0 earlycon=uart8250,mmio,0x3f8" -k ./apps/Image
  # lkvm run -k ./apps/Image -m 1024 -c 2 --name guest-78
  # Warning: The maximum recommended amount of VCPUs is 1
[    0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[    0.000000] Linux version 5.3.0-rc5-00771-g1b24712aa35b (hima@arch) (gcc version 8.3.0 (GCC)) #3 SMP Sat Aug 24 22:32:46 JST 2019
[    0.000000] earlycon: uart8250 at MMIO 0x00000000000003f8 (options '')
[    0.000000] printk: bootconsole [uart8250] enabled
[    0.000000] initrd not found or empty - disabling initrd
[    0.000000] Zone ranges:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] software IO TLB: mapped [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] riscv: ISA extensions acdfimsu
[    0.000000] riscv: ELF capabilities acdfim
[    0.000000] percpu: Embedded 18 pages/cpu s34776 r8192 d30760 u73728
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 258055
[    0.000000] Kernel command line:  console=ttyS0 rw rootflags=trans=virtio,version=9p2000.L,cache=loose rootfstype=9p init=/virt/init  ip=dhcp console=ttyS0 earlycon=uart8250,mmio,0x3f8
[    0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)
[    0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes, linear)
[    0.000000] Sorting __ex_table...
[    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.000000] Memory: 955716K/1046528K available (6053K kernel code, 381K rwdata, 1886K rodata, 213K init, 305K bss, 90812K reserved, 0K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=2.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
[    0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
[    0.000000] plic: mapped 1024 interrupts with 2 handlers for 4 contexts.
[    0.000000] riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [0]
[    0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x24e6a1710, max_idle_ns: 440795202120 ns
[    0.000234] sched_clock: 64 bits at 10MHz, resolution 100ns, wraps every 4398046511100ns
[    0.086763] Console: colour dummy device 80x25
[    0.126351] Calibrating delay loop (skipped), value calculated using timer frequency.. 20.00 BogoMIPS (lpj=40000)
[    0.206320] pid_max: default: 32768 minimum: 301
[    0.247120] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)
[    0.307492] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)
[    0.511313] rcu: Hierarchical SRCU implementation.
[    0.566149] smp: Bringing up secondary CPUs ...
[    0.641731] smp: Brought up 1 node, 2 CPUs
[    0.812298] devtmpfs: initialized
[    0.873259] random: get_random_u32 called from bucket_table_alloc.isra.10+0x4e/0x160 with crng_init=0
[    0.955936] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    1.034756] futex hash table entries: 512 (order: 3, 32768 bytes, linear)
[    1.108563] NET: Registered protocol family 16
[    1.515961] vgaarb: loaded
[    1.546718] SCSI subsystem initialized
[    1.593928] usbcore: registered new interface driver usbfs
[    1.636677] usbcore: registered new interface driver hub
[    1.686459] usbcore: registered new device driver usb
[    1.774402] clocksource: Switched to clocksource riscv_clocksource
[    1.988600] NET: Registered protocol family 2
[    2.048295] tcp_listen_portaddr_hash hash table entries: 512 (order: 1, 8192 bytes, linear)
[    2.118335] TCP established hash table entries: 8192 (order: 4, 65536 bytes, linear)
[    2.182753] TCP bind hash table entries: 8192 (order: 5, 131072 bytes, linear)
[    2.246221] TCP: Hash tables configured (established 8192 bind 8192)
[    2.310814] UDP hash table entries: 512 (order: 2, 16384 bytes, linear)
[    2.366717] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes, linear)
[    2.432442] NET: Registered protocol family 1
[    2.503368] RPC: Registered named UNIX socket transport module.
[    2.551473] RPC: Registered udp transport module.
[    2.589999] RPC: Registered tcp transport module.
[    2.624481] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    2.678811] PCI: CLS 0 bytes, default 64
[    2.731055] kvm [1]: hypervisor extension not available
[    2.802988] workingset: timestamp_bits=62 max_order=18 bucket_order=0
[    2.970825] NFS: Registering the id_resolver key type
[    3.012073] Key type id_resolver registered
[    3.050028] Key type id_legacy registered
[    3.082409] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[    3.146508] 9p: Installing v9fs 9p2000 file system support
[    3.196277] NET: Registered protocol family 38
[    3.234913] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
[    3.291897] io scheduler mq-deadline registered
[    3.330202] io scheduler kyber registered
[    7.582375] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[    7.687378] printk: console [ttyS0] disabled
[    7.727071] 3f8.U6_16550A: ttyS0 at MMIO 0x3f8 (irq = 3, base_baud = 115200) is a 16550A
[    7.799061] printk: console [ttyS0] enabled
[    7.799061] printk: console [ttyS0] enabled
[    7.870531] printk: bootconsole [uart8250] disabled
[    7.870531] printk: bootconsole [uart8250] disabled
[    7.978343] 2f8.U6_16550A: ttyS1 at MMIO 0x2f8 (irq = 4, base_baud = 115200) is a 16550A
[    8.066577] 3e8.U6_16550A: ttyS2 at MMIO 0x3e8 (irq = 6, base_baud = 115200) is a 16550A
[    8.146497] 2e8.U6_16550A: ttyS3 at MMIO 0x2e8 (irq = 7, base_baud = 115200) is a 16550A
[    8.239570] [drm] radeon kernel modesetting enabled.
[    8.498927] loop: module loaded
[    8.539095] libphy: Fixed MDIO Bus: probed
[    8.643404] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
[    8.698051] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
[    8.746714] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    8.796702] ehci-pci: EHCI PCI platform driver
[    8.836471] ehci-platform: EHCI generic platform driver
[    8.886504] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    8.942023] ohci-pci: OHCI PCI platform driver
[    8.975609] ohci-platform: OHCI generic platform driver
[    9.023401] usbcore: registered new interface driver uas
[    9.070282] usbcore: registered new interface driver usb-storage
[    9.126332] mousedev: PS/2 mouse device common for all mice
[    9.190198] usbcore: registered new interface driver usbhid
[    9.232204] usbhid: USB HID core driver
[    9.279822] NET: Registered protocol family 10
[    9.359466] Segment Routing with IPv6
[    9.391165] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[    9.462311] NET: Registered protocol family 17
[    9.504346] 9pnet: Installing 9P2000 support
[    9.566966] Key type dns_resolver registered
[    9.711043] Sending DHCP requests ., OK
[    9.795801] IP-Config: Got DHCP answer from 192.168.33.1, my address is 192.168.33.15
[    9.859806] IP-Config: Complete:
[    9.884633]      device=eth0, hwaddr=02:15:15:15:15:15, ipaddr=192.168.33.15, mask=255.255.255.0, gw=192.168.33.1
[    9.972286]      host=192.168.33.15, domain=, nis-domain=(none)
[   10.018618]      bootserver=192.168.33.1, rootserver=0.0.0.0, rootpath=
[   10.018726]      nameserver0=192.168.33.1
[   10.339242] VFS: Mounted root (9p filesystem) on device 0:13.
[   10.444184] devtmpfs: mounted
[   10.540462] Freeing unused kernel memory: 212K
[   10.578479] This architecture does not have kernel memory protection.
[   10.628057] Run /virt/init as init process
Mounting...
[   13.522093] random: fast init done
#
[    0.000000] riscv: ISA extensions acdfimsu
[    0.000000] riscv: ELF capabilities acdfim

となっていることから、これが、Privileged ISA Specificationにある
hypervisor-extended supervisor mode (HS-mode)上で動く、virtual S-mode (VS-mode)ということなのだろう
firmwareを設定していないことや、initramfsを設定していないくても動くのだが、どうなっているかまだ分かっていない

この動いているKVMとkvmtoolのコードは今追っているところだが、
このKVMに関しては、流石後発なRISC-Vだけあって、x86等の仮想化で問題となる、PopekとGoldbergの仮想化要件を満たさない命令が存在しないため(CSR等が隠されるようになっている)、
sysenter等の特殊な命令ではなく、hypervisorのために追加されたレジスタを適切に設定したうえで、sretでguestに入ることができる

実装まで行かないが、概要説明は

を見ると良さそう、2つ目のものがWestern Digitalの資料で、今回patchを投げているのもWestern Digitalの人

PLIC( 割り込みコントローラー)の振る舞いとが、RISC-V特有でちょっとまだ追っているところ.

kvmtoolはlightweightと言うだけあって、小さくできているのでこちらも読みやすい
現状のメモはscrapboxにあるので、気になる人ように

kvmtool code reading - risc-v-vmm

recursive(nested vmm)もできるとあるけど、どうするのかまだいまいちわかっていないので、それもおいおい
今回も、コマンドを乗っけているが、雑なので、動かしたいけど、だめだったみたいなのがあれば、一報をください