In this walk-through, we'll use an Ubuntu cloudimg along with the gpio sample server to emulate a very simple GPIO device.
vfio-user
client support is not yet merged into qemu
. Instead, download and
build jlevon's master.vfio-user branch of
qemu; for example:
git clone -b master.vfio-user git@github.com:jlevon/qemu.git
cd qemu
./configure --prefix=/usr --enable-kvm --enable-vnc --target-list=x86_64-softmmu --enable-debug --enable-vfio-user-client
make -j
Set up the necessary metadata files:
sudo apt install cloud-image-utils
$ cat metadata.yaml
instance-id: iid-local01
local-hostname: cloudimg
$ cat user-data.yaml
#cloud-config
ssh_import_id:
- gh:jlevon
cloud-localds seed.img user-data.yaml metadata.yaml
don't forget to replace jlevon
with your github user name.
Start the gpio
server process:
rm -f /tmp/vfio-user.sock
./build/samples/gpio-pci-idio-16 -v /tmp/vfio-user.sock &
Make sure your system has hugepages available:
$ cat /proc/sys/vm/nr_hugepages
1024
Now you should be able to start qemu:
$ imgpath=/path/to/bionic-server-cloudimg-amd64.img
$ sudo ~/src/build/qemu-system-x86_64 \
-machine accel=kvm,type=q35 -cpu host -m 2G \
-mem-prealloc -object memory-backend-file,id=ram-node0,prealloc=yes,mem-path=/dev/hugepages/gpio,share=yes,size=2G \
-numa node,memdev=ram-node0 \
-nographic \
-device virtio-net-pci,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-drive if=virtio,format=qcow2,file=$imgpath \
-drive if=virtio,format=raw,file=seed.img \
-device vfio-user-pci,socket=/tmp/vfio-user.sock
Log in to your VM and load the kernel driver:
$ ssh -p 2222 ubuntu@localhost
...
$ sudo apt install linux-modules-extra-$(uname -r)
$ sudo modprobe gpio-pci-idio-16
Now we should be able to observe the emulated GPIO device's pins:
$ sudo su -
# cat /sys/class/gpio/gpiochip480/base > /sys/class/gpio/export
# for ((i=0;i<12;i++)); do cat /sys/class/gpio/OUT0/value; done
and the server should output something like:
gpio: region2: read 0 from (0:1)
gpio: region2: read 0 from (0:1)
gpio: region2: read 0 from (0:1)
gpio: region2: read 0x1 from (0:1)
gpio: region2: read 0x1 from (0:1)
gpio: region2: read 0x1 from (0:1)
gpio: region2: read 0x2 from (0:1)
gpio: region2: read 0x2 from (0:1)
gpio: region2: read 0x2 from (0:1)
gpio: region2: read 0x3 from (0:1)
gpio: region2: read 0x3 from (0:1)
gpio: region2: read 0x3 from (0:1)