Vengineerの戯言

人生は短いけど、長いです。人生を楽しみましょう!

vfio (Virtual Funtion I/O) と SystemC を繋げる (その1)

@Vengineerの戯言 : Twitter
SystemVerilogの世界へようこそすべては、SystemC v0.9公開から始まった 

はじめに

今までは、Xilinx QEMU と SystemC側を繋げるケースについて見てきました。
今回からは、Linux の vfio (Virtual Function I/O と SystemC を繋げ、SystemCから vfio 経由で PCIe Device へアクセスするケースを見ていきます。
実際にどうやって動かすかは、ここ に詳しく書いてあります。

vfio について

vfio (Virtual Function I/O) については、下記に詳しく書いてありました。

mmi.hatenablog.com

vfio で PCIバイスを操作するためには、vfio-pci ドライバをデバイスに bind すればいいようです。
上記のサイトから引用すると、下記のようにすればいいようです。Ethernet driver (Intel 82574) を前提にしています。

% lspci -nn | grep -i Ether
86:00.0 Ethernet controller [0200]: Intel Corporation 82574L Gigabit Network Connection [8086:10d3]
% sudo modprobe vfio-pci
% echo 0000:86:00.0 | sudo tee -a /sys/bus/pci/devices/0000:86:00.0/driver/unbind
% echo 8086 10d3 | sudo tee -a /sys/bus/pci/drivers/vfio-pci/new_id

バイスに vfio-pci を割り当てると、

 /dev/vfio/vfio
 /dev/vfio/<num>  <num> は、I/O MMU のグルーブ番号

ができるようです。

バイスがどの I/O MMU のグループ番号に属するかは、

$ ls -l /sys/bus/pci/devices/<ssss:bb:dd.f>/iommu_group/devices

のようなコマンドでわかるようです。

ちなみに、Linux Kernel の vfio のドキュメントは、ここ にあります。

Ubuntu cloud image で QEMUを起動

x86-64マシン上で動作する Ubuntuの vfio ではなく、x86-64マシン上のQEMU上で Ubuntu cloud image を起動して、Ubuntu cloud image 上のSystemC側と接続します。
Ubuntu cloud image VM を ダウンロードし、イメージのサイズを 10GB にし、cloud image を qemu-system-x86_64 で起動します。

$ mkdir /tmp/machine-x86
$ qemu-system-x86_64                                                              \
    -M q35,accel=kvm,kernel-irqchip=split -m 4G -smp 4 -enable-kvm                \
    -device virtio-net-pci,netdev=net0 -netdev type=user,id=net0                  \
    -serial mon:stdio -machine-path /tmp/machine-x86 -display none                \
    -device intel-iommu,intremap=on,device-iotlb=on                               \
    -device ioh3420,id=rootport,slot=0 -device ioh3420,id=rootport1,slot=1        \
    -drive file=~/Downloads/ubuntu-20.04-server-cloudimg-amd64.img,format=qcow2   \
    -drive file=~/Downloads/user-data.img,format=raw                              \
    -kernel ~/Downloads/ubuntu-20.04-server-cloudimg-amd64-vmlinuz-generic        \
    -append "root=/dev/sda1 ro console=tty1 console=ttyS0 intel_iommu=on"         \
    -initrd ~/Downloads/ubuntu-20.04-server-cloudimg-amd64-initrd-generic

Ubuntu cloud image に SystemC および Verilator をインストール

Zynq、ZynqMP、Versalの時と違って、QEMUで起動した Ubuntu cloud image の中に、SystemC と Verilator をインストールする必要があります。
Ubuntu cloud image に login した後に、下記のように必要なパッケージをインストールします。

$ sudo apt-get update
$ sudo apt-get install git build-essential autoconf flex bison

また、I/O MMU が on になっていることを確かめます。

$ cat /proc/cmdline
"...ro quiet splash intel_iommu=on..."

次に、SystemC をインストールします。ここでは、2.3.2 をインストールしています。そして、Verilator もインストールします。ここでは、v4.010 をインストールしています。

SystemC側のモデルのビルド

SystemC側のモデル (PCIe RTL VFIO demos) をビルドします。.config.mk に SYSTEMCの環境を設定して、tests/rtl-bridges/pcie ディレクトリで make を実行します。

$ cd ~/github/
$ git clone https://github.com/Xilinx/libsystemctlm-soc.git
$ cd libsystemctlm-soc
$ cat <<EOF > .config.mk
SYSTEMC = /opt/systemc-2.3.2/
EOF
$ cd tests/rtl-bridges/pcie
$ make

make コマンドが終了してら、下記のように2つのコマンドが生成されます。

$ ls test-pcie-ep-master-vfio test-pcie-ep-slave-vfio

Cloud image 上での vfio-pcie の登録

SystemC側のモデルを実行する前に、vfio-pcie を登録します。
test/rtl-bridges/pcie ディレクトリに移動し、modprobe コマンドにて vfio-pci を登録します。
/sys/bus/pci/drivers/vfio-pcie/new_id に対して、VendorID/DeviceIDを10ee d004に設定します。また、I/O MMUのグループを確認します。この例では、I/O MMU のグループは 3 という想定しています。

$ cd ~/github/libsystemctlm-soc/tests/rtl-bridges/pcie
$ sudo modprobe vfio-pci nointxmask=1
$ sudo sh -c 'echo 10ee d004 > /sys/bus/pci/drivers/vfio-pci/new_id'
$ # Find the iommu group
$ ls -l /sys/bus/pci/devices/0000\:01\:00.0/iommu_group
$ # The iommu group was 3

おわりに

今回は、QEMU 上で起動した Ubuntu cloud image に SystemC/Verilatorをインストールし、SystemC側のモデルをビルド後、vfio-pciバイスを登録しました。
次回は、SystemC側のモデルの中を見ていきます。