INTEL GVT-G: COMPARTILHANDO A GPU COM CONVIDADOS QEMU/KVM

O QUE É INTEL GVT-G

 

Intel GVT (iGVT, Intel® Graphics Virtualization Technology) é uma solução desenvolvida pela Intel para permitir que parte ou toda a capacidade das GPU (Graphics Processing Unit) Intel seja cedida para convidados KVM ou Xen, suas implementações chamadas KVMGT e XenGT, respectivamente. Há três formas diferentes de se aplicar a tecnologia iGVT:

  • Aceleração gráfica virtual dedicada (iGVT-d): um convidado por GPU;
  • Aceleração gráfica virtual compartilhada (iGVT-s): múltiplos convidados por GPU;
  • GPU virtual: (iGVT-g): múltiplos convidados por GPU. Nesse artigo, será dado foco nessa implementação.

Intel GVT-g (ou iGVT-g, Intel® Graphics Virtualization Technology-g) é uma tecnologia que permite criar GPU virtuais que podem ser utilizadas por convidados KVM ou Xen. Dependendo da quantidade de memória RAM disponível e da fatia de memória dada a cada convidado, é possível ter até sete convidados utilizando a mesma GPU Intel.

Através dela, é possível criar máquinas virtuais capazes de utilizar as capacidades de codificação e decodificação de vídeo da Intel (Intel QSV e/ou VAAPI), é possível utilizar a aceleração 3D para o uso de programas de CAD (Computer Aided Design) e jogos. Tudo isso dentro do convidado e ainda permitindo ao hospedeiro utilizar a GPU.

REQUISITOS PARA O HOSPEDEIRO

Para utilizar a tecnologia iGVT-g, é necessário ter um processador Intel, ao menos, da 5ª Geração com GPU Intel Graphics, com a virtualização ativada (VT-d e VT-x) e uma placa-mãe compatível. A quantidade de memória disponível para ceder aos convidados e a quantidade de convidados simultâneos dependem de quanta memória RAM o sistema hospedeiro possui instalada.

Nesse caso, será utilizado o QEMU/KVM para criar os convidados. A necessidade ou não de construir o QEMU dependerá de qual alternativa será escolhida a respeito da tela do convidado (isso será explicado adiante).

O hospedeiro utilizado no exemplo é o Xubuntu 18.04. O Ubuntu 18.04 vem com o kernel Linux na versão 4.15 (no momento em que escrevo, 4.15.0-23). Essa versão possui as configurações necessárias para o funcionamento do Intel GVT-g com KVM. A partir da versão 4.16 uma opção essencial para permitir a estabilidade de convidados Windows passou a funcionar. Portanto, recomenda-se usar o kernel Linux com a versão ao menos 4.16.

Caso seja necessário construir um kernel porque o que determinada distribuição provê não possui as configurações necessárias, é preciso garantir que as seguintes configurações estejam presentes e configuradas: CONFIG_DRM_I915_GVT, CONFIG_DRM_I915_GVT_KVMGT, CONFIG_VFIO_MDEV e CONFIG_VFIO_MDEV_DEVICE

Um exemplo, baseando-se nas configurações do kernel do Ubuntu 18.04:

CONFIG_DRM_I915_GVT=y
CONFIG_DRM_I915_GVT_KVMGT=m
CONFIG_VFIO_MDEV=m
CONFIG_VFIO_MDEV_DEVICE=m

Tenha certeza de que as opções acima estão no arquivo .config ANTES de construir o kernel. Para construir o kernel (o foco não é ensinar a construir o kernel, mas ainda assim há essa pequena explicação):

 git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
$ make oldconfig

Antes do comando abaixo, veja se as opções CONFIG_* acima estão configuradas corretamente no arquivo .config:

 make -j `nproc` bindeb-pkg

Recomenda-se grandemente ler a ajuda do makefile do kernel Linux (make help), há opções que criam pacotes DEB (como a do exemplo) e pacotes RPM prontos para serem instalados em distribuições que utilizam tais pacotes.

Uma vez com o kernel construído e instalado com as configurações necessárias, é preciso adicionar alguns módulos no initramfs. No caso do Xubuntu 18.04, é necessário adicionar no arquivo /etc/initramfs-tools/modules as seguintes três linhas:

kvmgt
vfio-iommu-type1
vfio-mdev

E atualizar o initramfs com:

 sudo update-initramfs -u -k all

Caso haja muitas versões do kernel Linux instaladas, isso pode demorar. -u significa update (atualizar), -k define a versão do kernel. Com “all”, todas as versões são atualizadas.

Com o kernel configurado e instalado e o initramfs atualizado, é preciso adicionar algumas opções na linha de comando da inicialização do sistema. No caso do GRUB2 no Xubuntu 18.04, o arquivo é o /etc/default/grub, para editá-lo, pode-se usar o seguinte comando:

 sudo nano /etc/default/grub

Na linha que contém:

GRUB_CMDLINE_LINUX_DEFAULT=

Algumas opções precisam ser adicionadas entre as aspas. Por padrão, há apenas “quiet splash”. É NECESSÁRIO ADICIONAR:

intel_iommu=on i915.enable_gvt=1

A linha de comando fica semelhante a:

GRUB_CMDLINE_LINUX_DEFAULT=”quiet splash intel_iommu=on i915.enable_gvt=1″

Outras opções são recomendadas. kvm.ignore_msrs=1 é importante caso os convidados sejam Windows, sem ela o sistema se torna instável pois o convidado pode tentar ler registros de forma direta onde o KVM não definiu valores. kvm.halt_poll_ns=0 e kvm.halt_poll_ns_grow=0 são opções relevantes para o som, sem elas configuradas os convidados tornam-se cada vez mais lentos conformes sons são reproduzidos neles, especialmente convidados Windows. A linha de comando ficaria algo como:

GRUB_CMDLINE_LINUX_DEFAULT=”quiet splash intel_iommu=on i915.enable_gvt=1 kvm.ignore_msrs=1 kvm.halt_poll_ns=0 kvm.halt_poll_ns_grow=0″

Então um:

 sudo update-grub

Atualiza o GRUB2 para que as opções estejam presentes ao iniciar o sistema. Ao reiniciá-lo, o sistema irá iniciar com essas opções adicionais.

Caso tudo tenha ocorrido corretamente, deve ser possível ver quais são os modos disponíveis em que se pode criar as GPUs virtuais. Para isso, há um diretório no sysfs onde as opções podem ser vistas. Nesse exemplo, o Intel HD Graphics é o dispositivo PCI 00:02.0, o endereço PCI pode ser diferente, logo pode ser necessário adaptar o caminho do diretório, isso pode ser visto com o comando:

 lspci

Com o endereço PCI sendo 00:02.0, o diretório é:

/sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/

Dentro desse diretório devem haver outros, cada um representando um modo. No exemplo, tem-se:

i915-GVTg_V5_4
i915-GVTg_V5_8

E, dentro de cada um desses diretórios, há três arquivos com informações. O arquivo available_instances mostra quantas GPUs virtuais podem ser criadas com aquela configuração, o arquivo device_api mostra a API utilizada, nesse caso, vfio-pci, e o arquivo description tem detalhes do modo:

low_gm_size: 128MB
high_gm_size: 512MB
fence: 4
resolution: 1920×1200
weight: 4

O diretório devices tem ligações simbólicas para as GPUs virtuais criadas. O arquivo create é utilizado para criar as GPUs virtuais, seu uso será explicado nas configurações do convidado.

Enquanto com o que foi feito até agora já seria possível inicializar o QEMU, na experiência utilizando iGVT-g sem configurar o driver de vídeo do hospedeiro em um Lenovo Ideapad 310-14ISK com um Intel Core i3-6100U e uma Intel HD Graphics 520, podem ocorrer piscadas na tela por um motivo ainda desconhecido.

Para corrigir é preciso alterar o driver de vídeo que é utilizado de “modesetting” para “intel”. Inicialmente é preciso instalar o driver Intel caso não esteja instalado. No caso do Ubuntu 18.04, para instalar o pacote necessário se utiliza:

 sudo apt install xserver-xorg-video-intel

Então deve-se editar ou criar o arquivo /etc/X11/xorg.conf usando:

 sudo nano /etc/X11/xorg.conf

Deixando-o com o seguinte conteúdo:

Section "Device"
   Identifier  "Intel Graphics"
   Driver      "intel"
   Option      "DRI"    "3"
EndSection

E então se pode reiniciar a sessão do X com, por exemplo:

 sudo systemctl restart lightdm.service

Ou reiniciar o sistema para aplicar a nova configuração do driver de vídeo.

Além disso, é recomendável utilizar UEFI para os convidados. Usando iGVT-g muitas das capacidades de vídeo estão disponíveis, mas os modos VGA não estão, devido a sua complexidade. Isso significa que a tela inicial do GRUB2, ou a tela inicial do ISOLINUX não aparecem no modo BIOS, o que compromete o funcionamento dos convidados. Enquanto o GRUB2 consegue lidar com o fato de não poder ser exibido, o ISOLINUX faz com que o convidado trave.

Como alternativa, há um framebuffer básico que funciona apenas em UEFI. Ele é capaz de prover a tela inicial do GRUB2 de forma limitada, mas suficiente para escolher e editar opções do GRUB2.

Para usar convidados com UEFI, o hospedeiro precisa do OVMF. Há o pacote ovmf no Ubuntu 18.04:

 sudo apt install ovmf

Ou há a possibilidade de construir o OVMF do Git https://github.com/tianocore/edk2, mas o processo não é tão trivial, leia a documentação disponível primeiro.

DMA-BUF E SUA IMPORTÂNCIA

 

dma-buf é como se fosse uma tela virtual, onde o convidado pode exibir a imagem como se ele estivesse conectado a um monitor físico. O uso é bem simples: exibir a tela do convidado em uma janela no hospedeiro.

É importante saber que não é necessário utilizar o dma-buf para os convidados. Isso é opcional. No entanto, sem o dma-buf, para poder visualizar a tela do convidado será preciso usar algum protocolo como o VNC ou RDP, que podem não ser suficientes dependendo do tipo de uso que será feito do sistema convidado.

Exemplos: caso o convidado será um servidor sem interface gráfica para codificação de mídia, SSH é o suficiente. Caso ele tenha uma interface gráfica mas os vídeos não são intensos e a latência não é crítica, VNC ou RDP podem ser suficientes. Caso o convidado seja utilizado para CAD ou para jogos, onde as ineficiências dos protocolos remotos podem causar perda de produtividade ou de partidas, dma-buf é a melhor opção.

Há mais de uma interface pela qual é possível utilizar o dma-buf:

  • Spice – Utiliza o protocolo Spice para exibir a tela;
  • GTK – Cria uma janela GTK, padrão do QEMU;
  • VNC – Utiliza o protocolo VNC para exibir a tela;
  • Libvirt – Utiliza o Spice também, mas pode ser gerenciado através do virt-manager.

Não há recomendações específicas, mas como as demais opções são protocolos remotos, a interface GTK foi a que se mostrou mais rápida, sendo limitada pelo gerenciador de janelas do hospedeiro: percebeu-se significativa redução no desempenho do convidado ao desativar a composição de tela no hospedeiro (xfwm4). Há vantagens interessantes ao utilizar Spice, como copiar e colar e arrastar e soltar (dependentes de drivers) que podem fazer o Spice ser a melhor opção. O melhor é testar cada uma.

QEMU

Caso se tenha chegado à conclusão de que será necessário utilizar o dma-buf, será preciso construir o QEMU do código fonte. Isso acontece porque o QEMU disponibilizado no Ubuntu 18.04 não possui as configurações necessárias para acelerar o vídeo, nem usando Spice, VNC ou GTK. Nesse caso, só seria possível criar convidados que não utilizam o dma-buf.

Para construir o QEMU capaz de usar dma-buf, é preciso baixar o código fonte e configurá-lo. A partir da versão 2.10 estável já deve ser possível construir o QEMU com as opções necessárias, para os corajosos há o Git, mas é melhor usar a versão 2.12 por ser a versão estável mais recente. Há várias dependências que precisam ser instaladas. No caso de uma instalação limpa do Xubuntu 18.04, as dependências podem ser instaladas através do seguinte comando:

 sudo apt install gcc pkg-config zlib1g-dev libgtk-3-dev libgtk-3-dev libsdl2-dev libjpeg-turbo8-dev libbluetooth-dev libsasl2-dev libepoxy-dev libdrm-dev libgbm-dev libspice-server-dev libusb-dev libusb-1.0-0-dev libusbredirhost-dev

São muitos pacotes mesmo. Um exemplo para construir a versão 2.12 do QEMU com as opções necessárias é:

 wget -c -t 0 https://download.qemu.org/qemu-2.12.0.tar.xz
$ tar xf qemu-2.12.0.tar.xz
$ cd qemu-2.12.0
$ ./configure –target-list=x86_64-softmmu –audio-drv-list=pa,alsa,sdl
–prefix=$HOME/qemu-2.12-build –enable-opengl –enable-gtk
–enable-sdl –enable-libusb –enable-bluez –enable-kvm –enable-spice
–enable-vnc –enable-vnc-png –enable-vnc-jpeg –enable-vnc-sasl
–enable-membarrier –enable-vhost-net –enable-usb-redir
$ make -j `nproc`
$ make install

Provavelmente será necessário trocar o local de instalação. A opção –enable-membarrier não existe nas versões anteriores à 2.12. Pode ser que o configure falhe por determinadas bibliotecas de desenvolvimentos não estarem instaladas, o componente faltante é especificado na mensagem de erro. Instale a(s) biblioteca(s) faltante(s) e repita o uso do configure.

Uma vez com o QEMU pronto, pode-se configurar o convidado.

 

PREPARANDO O CONVIDADO LINUX SEM DMA-BUF

 

Com o hospedeiro preparado e o QEMU construído, pode-se começar a preparação do convidado. A instalação do convidado é feita utilizando uma VGA virtual do QEMU, como QXL, Cirrus or STD. Uma vez com o sistema instalado e configurado, pode-se remover a VGA virtual e utilizar apenas a GPU Intel, acessando o convidado usando SSH, VNC ou RDP. Usar a VGA virtual e a GPU Intel ao mesmo pode causar sérios problemas de estabilidade, inclusive no hospedeiro. Por isso, é melhor utilizar a VGA virtual apenas para instalar o sistema.

ESSAS ETAPAS AINDA OCORREM NO HOSPEDEIRO

Inicialmente, é preciso criar a GPU virtual que será utilizada por esse convidado. Para isso, deve-se usar um comando echo com o nome que se deseja dar para a GPU virtual. A Intel, no seu guia, usa o comando uuid para gerar os nomes para as GPUs virtuais e, por isso, uuid também é utilizado nesse exemplo. Pode ser necessário instalar o pacote uuid, disponível no Ubuntu 18.04 usando:

 sudo apt install uuid

Por exemplo:

 uuid
334b65fc-731c-11e8-8325-1ffce6ac7959

Com esse uuid, pode-se criar a GPU virtual usando o seguinte comando, lembrando-se que o endereço PCI pode ser diferente e que o diretório do modo também pode ser diferente, dependendo da opção escolhida:

 sudo sh -c ‘echo 334b65fc-731c-11e8-8325-1ffce6ac7959 > /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_8/create’

O modo da i915-GVTg_V5_8 cria uma GPU virtual com 64 MB de memória com resolução máxima de 1024×768 nesse exemplo.

Para criar a imagem do HD, pode-se utilizar o seguinte comando:

 qemu-img create -f qcow2 bionic.qcow2 10G

create: criar; -f qcow2: formato da imagem QCOW2; o nome da imagem; o tamanho da imagem (nesse caso, 10 GB).

Uma vez com a GPU virtual criada e com o a imagem do HD criada, pode-se iniciar a máquina virtual com QEMU. Um exemplo de comando pode ser visto a seguir (altere o caminho para o QEMU 2.12 que foi construído anteriormente, adaptações serão necessárias para versões anteriores à 2.12):

 sudo qemu-system-x86_64 -m 1280 -enable-kvm -cpu host -smp cores=2,threads=2
-device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/334b65fc-731c-11e8-8325-1ffce6ac7959,rombar=0,x-igd-opregion=on,display=off,x-vga=off
-monitor vc -display gtk -vga std -serial stdio -hda bionic.qcow2
-cdrom “xubuntu-18.04-core-amd64.iso”
-bios /usr/share/ovmf/OVMF.fd -netdev user,id=net0,hostfwd=::59000-:5900 -device e1000,netdev=net0

Explicação da linha de comando:

A máquina virtual tem 1280 MB de memória RAM. Usa KVM, a CPU é do mesmo modelo do hospedeiro, foram designadas dois núcleos da CPU, cada um deles com duas threads.

A GPU virtual foi designada com o display=off, ou seja, sem dma-buf. A falta da opção igd-opregion=on pode gerar graves problemas de estabilidade no hospedeiro, mas com versões mais antigas do kernel (de 4.15 para baixo) ela não funciona, sendo necessário removê-la. O modo vga não funciona, então está desligado, rombar=0 porque não há nenhuma ROM a ser utilizada.

O terminal (ele é chamado de monitor, de onde se podem adicionar dispositivos USB ou enviar comandos ao convidado enquanto o convidado está em execução, por exemplo) do QEMU está em um console virtual que pode ser acessado da própria interface (depende da opção -display), foi escolhida a interface GTK para exibir a máquina virtual, a VGA virtual foi escolhida como a STD, a porta serial está no stdio (no terminal se aberto por ele).

Uma imagem QCOW2 foi escolhida como HD (pode ser criado com qemu-img), uma ISO é usada como CD-ROM e o firmware UEFI do OVMF foi escolhida como o firmware da máquina virtual.

A rede escolhida é do tipo usuário, com o id net0, em que a porta 59000 do hospedeiro é passada para a 5900 do convidado. Ou seja, ao se conectar na porta 59000 do hospedeiro, a conexão ocorre, na verdade, na porta 5900 do convidado. O controlador Ethernet virtual é um 82540EM Gigabit Ethernet Controller, que usa a netdev com o id net0.

ESSAS ETAPAS DEVEM SER FEITAS NO(S) SISTEMA(S) CONVIDADO(S)

Com aquele comando do QEMU, o convidado é iniciado e é aberta uma janela GTK, onde deve aparecer por alguns segundos o logo do TianoCore e o terminal de onde o comando foi executado deve ficar vazio. Na janela deve aparecer o GRUB2 com as opções para testar sem instalar/instalar o Xubuntu 18.04. Então pode-se instalar o Xubuntu 18.04 normalmente, nesse estágio não há configurações especiais a se fazer.

Quando a instalação terminar, reinicie o convidado e acesse sua conta recém criada. A primeira configuração a se fazer é no GRUB2. Edite o arquivo /etc/default/grub usando:

 sudo nano /etc/default/grub

E remova a opção splash da linha. A corrupção na tela usando a VGA virtual e a GPU Intel simultaneamente enquanto o convidado inicializa deixa de existir. Aplique a nova configuração do GRUB2 usando o comando:

 sudo update-grub

Para ser possível usar o convidado sem dma-buf e sem a VGA virtual é necessário configurar algum protocolo remoto, como o SSH ou o VNC. Nesse exemplo será utilizado o VNC.

Inicialmente, o pacote x11vnc precisa ser instalado. No Ubuntu 18.04, pode-se utilizar o seguinte comando para instalá-lo:

 sudo apt install x11vnc

Então é necessário criar um serviço do systemd que vai permitir que o convidado seja acessado através do protocolo VNC já na tela de login. Na página de ajuda do Ubuntu há uma explicação muito clara de como criá-lo e configurá-lo, as únicas alterações feitas foram desativar a senha e escolher o modo de autenticação do LightDM (o convidado é Xubuntu 18.04, que usa LightDM).

Para iniciar a edição do serviço, use o seguinte comando:

 sudo nano /lib/systemd/system/x11vnc.service

Esse é o conteúdo que precisa ser inserido no arquivo:

[Unit]
Description=Start x11vnc at startup.
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/x11vnc -auth /var/run/lightdm/root/:0 -forever -loop -noxdamage -repeat -rfbport 5900 -shared

[Install]
WantedBy=multi-user.target

Após isso, o systemd precisa ser recarregado, o serviço ativado e iniciado para poder testar o acesso:

 sudo systemctl daemon-reload
$ sudo systemctl enable x11vnc.service
$ sudo systemctl start x11vnc.service

Na próxima inicialização, o serviço x11vnc.service iniciará automaticamente já na tela de login. Tente acessar o convidado através de um visualizador VNC e veja se funcionou. TESTE ANTES DE REMOVER A VGA VIRTUAL. Caso não seja possível conectar ao servidor VNC, investigue as causas:

1) Não tenho acesso à porta 5900 do convidado!

Isso pode acontecer quando opções a respeito da rede não são escolhidas no QEMU. Uma alternativa é redirecionar uma porta do hospedeiro para o convidado. Um exemplo de opções que fazem isso é:

-netdev user,id=net0,hostfwd=::59000-:5900 -device e1000,netdev=net0

Existem alternativas mais avançadas de configuração da rede, mas que fogem do escopo do artigo.

2) Adicionei a opção para passar a porta para o convidado mas ainda não tenho acesso!

Se o firewall foi ativado, pode ser que o acesso esteja sendo negado. Libere as portas necessárias no convidado.

3) A porta funciona, mas o servidor VNC não!

O serviço do systemd foi testado com o LightDM. Outros gerenciadores de login precisam de configurações um pouco diferentes.

Uma vez com o servidor VNC funcionando, é necessário trocar o driver de “modesetting” para “intel” também. Em primeiro lugar, veja se o driver intel está instalado. Para instalá-lo no Ubuntu 18.04, use:

 sudo apt install xserver-xorg-video-intel

Então crie/edite o arquivo /etc/X11/xorg.conf no convidado também:

 sudo nano /etc/X11/xorg.conf

O conteúdo é o mesmo utilizado no hospedeiro, pois é a mesma GPU:

Section "Device"
   Identifier  "Intel Graphics"
   Driver      "intel"
   Option      "DRI"    "3"
EndSection

Enquanto usar o driver intel não é NECESSÁRIO, é EXTREMAMENTE RECOMENDÁVEL. Sem ele, prepare-se para travamentos no hospedeiro durante a inicialização do convidado e mensagens no dmesg do hospedeiro como:

[75756.681054] i915 0000:00:02.0: Resetting rcs0 after gpu hang

Com essa configuração realizada, desligue o convidado, pois a linha de comando do QEMU precisa ser alterada para remover a VGA virtual.

RETORNANDO AO HOSPEDEIRO

Uma vez com o servidor VNC configurado e funcionando, deve ser possível utilizar o convidado sem uma VGA virtual. Um exemplo de comando para ser usado no hospedeiro para iniciar o convidado pode ser visto a seguir:

 sudo qemu-system-x86_64 -m 1280 -enable-kvm -cpu host -smp cores=2,threads=2
-device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/334b65fc-731c-11e8-8325-1ffce6ac7959,rombar=0,x-igd-opregion=on,display=off,x-vga=off
-monitor vc -display none -vga none -serial stdio -hda bionic.qcow2
-bios /usr/share/ovmf/OVMF.fd -netdev user,id=net0,hostfwd=::59000-:5900 -device e1000,netdev=net0

As diferenças em relação ao comando anterior são:

  • Não há display;
  • Não há VGA virtual;
  • Não há CD-ROM.

Não vai abrir nenhuma janela e o terminal de onde o comando foi executado, dessa vez, exibirá algumas mensagens:

erro: nenhum modo de vídeo adequado encontrado.
erro: nenhum modo de vídeo adequado encontrado.
Iniciando no modo cego

Por que elas surgem? Porque nenhum modo VGA existe. Tenha paciência enquanto o convidado inicia, pois nada será visível durante a inicialização, exceto essas três mensagens.

Após esperar um tempo, use um visualizador VNC (vinagre, por exemplo). Para instalar no Ubuntu 18.04, use:

 sudo apt install vinagre

Para iniciar, execute no terminal:

 vinagre

Ou utilize outro visualizador de área de trabalho remota de sua escolha e conecte-se ao localhost na porta 59000 (conforme o exemplo). Se tudo deu certo, a tela de login do LightDM deve ter aparecido e o convidado está pronto.

Uma vez com o convidado desligado, talvez se queira criar uma GPU virtual com mais capacidade, mas a GPU virtual criada anteriormente ainda existe. Para removê-la, se utiliza o seguinte comando:

 sudo sh -c ‘echo 1 > /sys/bus/pci/devices/0000:00:02.0/334b65fc-731c-11e8-8325-1ffce6ac7959/remove’

Para facilitar a inicialização, pode-se criar um script onde a GPU virtual é adicionada e removida automaticamente, como por exemplo:

#!/bin/bash
sudo sh -c ‘echo 334b65fc-731c-11e8-8325-1ffce6ac7959 > /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_8/create’
sudo qemu-system-x86_64 -m 1280 -enable-kvm -cpu host
-smp cores=2,threads=2 -device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/334b65fc-731c-11e8-8325-1ffce6ac7959,rombar=0,x-igd-opregion=on,display=off,x-vga=off
-monitor vc -display none -vga none -serial stdio -hda bionic.qcow2
-bios /usr/share/ovmf/OVMF.fd -netdev user,id=net0,hostfwd=::59000-:5900 -device e1000,netdev=net0
sudo sh -c ‘echo 1 > /sys/bus/pci/devices/0000:00:02.0/334b65fc-731c-11e8-8325-1ffce6ac7959/remove’

 

PREPARANDO O CONVIDADO LINUX COM DMA-BUF

 

Para usar o dma-buf, é necessário usar o kernel Linux com a versão mínima 4.16. Com a versão 4.15 a tela não é carregada, impossibilitando visualizar o convidado.

AINDA NO HOSPEDEIRO

Tendo a versão mínima do kernel Linux e o QEMU construído com GTK e OpenGL (explicado anteriormente), pode-se criar o convidado. Nesse exemplo é criada uma GPU virtual com 128 MB de memória e resolução máxima de 1920×1200 (é necessário ver se a GPU tem esse modo disponível):

 uuid
d4253d2e-73d8-11e8-a4b7-cb5f65b15073

 sudo sh -c ‘echo d4253d2e-73d8-11e8-a4b7-cb5f65b15073 > /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_4/create’

Com a GPU virtual criada, pode-se iniciar o convidado usando um comando como (adapte conforme suas configurações e caminhos):

 sudo qemu-system-x86_64 -m 1280 -enable-kvm -cpu host
-smp cores=2,threads=2 -device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/d4253d2e-73d8-11e8-a4b7-cb5f65b15073,x-igd-opregion=on,rombar=0,display=on,x-vga=off
-monitor vc -display gtk,gl=on -vga none -serial stdio -hda bionicdma.vdi
-cdrom “xubuntu-18.04-desktop-amd64.iso”
-bios /usr/share/ovmf/OVMF.fd -netdev user,id=net0 -device e1000,netdev=net0

Explicação do comando (não se surpreenda se algumas partes forem iguais à página anterior):

A máquina virtual tem 1280 MB de memória RAM. Usa KVM, a CPU é do mesmo modelo do hospedeiro, foram designadas dois núcleos da CPU, cada um deles com duas threads.

A GPU virtual foi designada com o display=on, ou seja, com dma-buf. A falta da opção igd-opregion=on pode gerar graves problemas de estabilidade no hospedeiro. O modo vga não funciona, então está desligado, rombar=0 porque não há nenhuma ROM a ser utilizada.

O terminal (ele é chamado de monitor, de onde se podem adicionar dispositivos USB ou enviar comandos ao convidado enquanto o convidado está em execução, por exemplo) do QEMU está em um console virtual que pode ser acessado da própria interface (depende da opção -display), foi escolhida a interface GTK para exibir a máquina virtual e a aceleração OpenGL será utilizada na janela GTK, não há uma VGA virtual pois não há necessidade e a porta serial está no stdio (no terminal se aberto por ele).

Uma imagem VDI foi escolhida como HD, uma ISO é usada como CD-ROM e o firmware UEFI do OVMF foi escolhido como o firmware da máquina virtual.

A rede escolhida é do tipo usuário, com o id net0. O controlador Ethernet virtual é um 82540EM Gigabit Ethernet Controller, que usa a netdev com o id net0. Não há a necessidade de redirecionar portas dessa vez, pois não há a necessidade de visualizar a tela com protocolos remotos.

HOSPEDEIRO E CONVIDADO JUNTOS, ATENÇÃO

A inicialização da máquina virtual nesse modo é bastante peculiar. O GRUB2 aparece, mas não na janela da máquina virtual, e sim no terminal! Isso ocorre porque o framebuffer está sendo passado pela porta serial, e no comando do QEMU foi configurado que a porta serial fosse o stdio. Relevando esse fato, o GRUB2 funciona como o GRUB2, permitindo escolher as opções e editá-las.

Uma vez escolhida, a inicialização começa e as mesmas mensagens avisando sobre a inicialização em modo cego aparecem, mas então a janela GTK é inicializada. Devem aparecer algumas mensagens referente ao UEFI e pode surgir uma mensagem de erro da GPU virtual, acusando a ausência do firmware (devido a rombar=0 e x-vga=off), mas o convidado inicia normalmente. Instale o convidado como se fosse um convidado comum e reinicie quando a instalação terminar.

O convidado está pronto.

Não se assustem, é Xubuntu 18.04 mesmo.

Isso funciona com outras distribuições também, como com o openSUSE Tumbleweed:

Linux: Intel GVT-g: compartilhando a GPU Intel com convidados QEMU/KVM

Pode parecer inacreditável, mas é isso mesmo. Utilizando o dma-buf é mais complicado de deixar o hospedeiro pronto, mas a configuração necessária no convidado Linux é zero.

A configuração opcional no convidado é trocar o driver de vídeo de “modesetting” para “intel”, como foi feito no hospedeiro e no convidado sem dma-buf. Inicialmente, deve-se ter certeza de que o driver intel está instalado. No Ubuntu 18.04, para instalá-lo pode se utilizar:

 sudo apt install xserver-xorg-video-intel

Então criar/editar o arquivo /etc/X11/xorg.conf:

 sudo nano /etc/X11/xorg.conf

E deixá-lo com o seguinte conteúdo:

Section "Device"
   Identifier  "Intel Graphics"
   Driver      "intel"
   Option      "DRI"    "3"
EndSection

Reiniciando a sessão do LightDM altera o modo:

 sudo systemctl restart lightdm

Uma vez que foi concluído o uso do convidado, remova a GPU virtual:

 sudo sh -c ‘echo 1 > /sys/bus/pci/devices/0000:00:02.0/d4253d2e-73d8-11e8-a4b7-cb5f65b15073/remove’

 

PREPARANDO O CONVIDADO WINDOWS

 

Convidados Windows não são muito difíceis de serem configurados, mas falhar em configurá-los de forma apropriada causa muitos problemas, podendo tornar o sistema hospedeiro inoperante. A versão a ser utilizada no sistema convidado é o Windows 10 Single Language (pt-BR) Pro x86_64. A recomendação é usar o kernel Linux ao menos na versão 4.16 no hospedeiro.

Inicialmente, tenha certeza de que na linha de comando da inicialização do hospedeiro Linux as seguintes opções estejam configuradas:

kvm.ignore_msrs=1 kvm.halt_poll_ns=0 kvm.halt_poll_ns_grow=0 intel_iommu=on i915.enable_gvt=1

As opções intel_iommu=on e i915.enable_gvt=1 são requeridas para usar o iGVT-g.

A opção kvm.ignore_msrs=1 é essencial para a estabilidade dos sistemas hospedeiro e convidado, pois sem ela o Windows pode tentar acessar endereços da memória não definidos ou não acessíveis pelo KVM, causando telas azuis e/ou corrupção.

Veja as consequência de ignorar a opção do parágrafo acima:

A corrupção chegou ao sistema hospedeiro, tornando-o inoperante.

As opções kvm.halt_poll_ns=0 e kvm.halt_poll_ns_grow=0 diminuem a degradação de desempenho que a emulação de som causa (após algumas horas ligado, o convidado fica lento sem elas mesmo sem uma saída de áudio).

Tendo certeza de que o hospedeiro está pronto, é possível começar as preparações para o convidado. A primeira observação: o convidado Windows precisa de bem mais espaço que o convidado Linux. Ao invés de criar imagens de 10 GB, é melhor criar images de, no mínimo, 32 GB. Mesmo assim, o convidado Windows tende a ficar sem espaço devido às atualizações do sistema, então é necessário cuidado com o espaço em disco.

Inicialmente, deve-se criar a GPU virtual para o Windows. Use o comando uuid para criar um identificador para nomear a GPU virtual. Se não estiver instalado, instale usando:

 sudo apt install uuid

Então:

 uuid
185802b6-7405-11e8-9e14-6ff0319bd0dc

 sudo sh -c ‘echo 185802b6-7405-11e8-9e14-6ff0319bd0dc > /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_4/create’

Várias opções que não eram relevantes em convidados Linux serão requeridas em convidados Windows, por isso a linha de comando do QEMU fica bastante grande:

 sudo env PULSE_LATENCY_MSEC=0 QEMU_PA_SAMPLES=98875 QEMU_AUDIO_DAC_FIXED_FREQ=48000
qemu-system-x86_64
-hda win10.raw -enable-kvm -cpu host -smp cores=2,threads=2 -m 3G
-device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/185802b6-7405-11e8-9e14-6ff0319bd0dc,rombar=0,x-igd-opregion=on,display=off,x-vga=off
-usb -device usb-mouse -bios /usr/share/ovmf/OVMF.fd -monitor vc -serial stdio
-vga cirrus -display gtk -cdrom “Win10_1709_BrazilianPortuguese_x64.iso”
-netdev user,id=net0,hostfwd=::33890-:3389 -device e1000,netdev=net0,bus=pci.0,addr=0x8

Em primeiro lugar, há algumas variáveis de ambiente. A primeira (PULSE_LATENCY_MSEC=0) faz com que a latência do PulseAudio seja de 0 ms (isso não é perfeito e há aplicações que podem ter problemas, mas essa não teve). A segunda (QEMU_AUDIO_DRV=pa) escolhe o driver de áudio do QEMU, nesse caso PulseAudio. A terceira (QEMU_PA_SAMPLES=98875) define quantas amostras serão armazenadas no buffer do som. A quarta (QEMU_AUDIO_DAC_FIXED_FREQ=48000) é a taxa de amostragem utilizada pelo QEMU. Mesmo com todas essas opções, o som emulado ainda pode ter problemas, mas eles serão muito menores do que antes. Os valores foram iterados até chegar a uma experiência boa.

A respeito do comando do QEMU em si:

A imagem do HD é raw, KVM é habilitado, a CPU escolhida é a mesma do hospedeiro, foram alocados dois núcleos, cada um com duas threads e foram alocados 3 GB de memória RAM.

A GPU virtual é configurada, sem passar ROM para ela, com x-igd-opregion=on (com convidados Windows, é necessário pela estabilidade), o display e a VGA estão desativados, ou seja, sem dma-buf.

Foi definido que a máquina virtual tem dispositivos USB, um mouse USB foi definido (isso é importante), é utilizado o firmware UEFI do OVMF, o monitor (terminal do QEMU) está no console virtual (na mesma janela onde aparece a tela do convidado) e a porta serial está no stdio (no terminal de onde o comando foi executado, por exemplo).

A VGA virtual é Cirrus, o display (a interface) é GTK, o CD-ROM é a mídia de instalação do Windows 10, a rede foi escolhida em modo usuário e redireciona a porta 33890 do hospedeiro para a 3389 do convidado (para utilizar com o protocolo RDP). O endereço PCI do adaptador de rede foi selecionado bem alto para evitar conflitos com as GPUs (tanto a VGA virtual como a GPU Intel).

A instalação procede normalmente, mas atenção: para usar como convidado, não é possível usar o Windows 10 Home, é necessário ter uma licença, ao menos, do Windows 10 Pro.

Uma vez com o sistema instalado, será pedido sua conta da Microsoft (se houver) ou poderá criar um novo usuário e senha, e haverá a possibilidade de configurar quais informações são enviadas. Uma vez com tudo pronto, o sistema deve iniciar e quase que imediatamente avisar a respeito da ausência de um driver de vídeo, e ele está correto. No entanto, o que ele faz a seguir é ruim (mais sobre isso adiante), ele instala o driver genérico.

É preciso ativar o acesso remoto do convidado Windows. Para isso, abra o Meu Computador, vá em Propriedades -> Configurações remotas -> Remoto e escolha a opção “Permitir conexões remotas com este computador”. Aplique e teste tentando conectar-se ao localhost:33890 com o vinagre ou outro programa. Se falhar, tente desmarcar a opção “Permitir conexões somente de computadores que estejam executando a Área de Trabalho Remota com Autenticação no Nível da Rede (recomendável)” e aplique. Só desative se a tentativa falhar.

Uma vez com o protocolo RDP funcionando, é preciso instalar o driver da Intel. Para isso, acesse o site da Intel pelo convidado e busque pelo driver adequado para sua GPU Intel (sim, é o mesmo driver que seria utilizado se o Windows 10 fosse o hospedeiro). Qual é a versão do driver depende da GPU, mas é necessário que seja baixado o arquivo ZIP, pois o arquivo EXE tende a falhar por não ser certificado (explicações a frente). A página onde se podem buscar os driver é https://downloadcenter.intel.com/ .

Pode haver mais de um driver disponível. Os certificados pela Intel são da versão 15.45, mas eles não têm DirectX12, têm desempenho pior e será uma luta constante para impedir que o Windows Update instale o driver genérico. A versão 15.45 do driver era mais estável com versões 4.15 do kernel Linux. A partir do kernel 4.16, a diferença de estabilidade diminuiu muito ou deixou de existir, mas a de desempenho ainda é gritante. Busque pelo modelo de sua GPU e baixe a versão ZIP do driver que desejar.

Os drivers mais antigos da Intel podem fazer o convidado nunca iniciar a tela, e podem fazer o seguinte erro surgir no dmesg:

[26948.391884] Detected your guest driver doesn’t support GVT-g.
[26948.391888] Now vgpu 1 will enter failsafe mode.

Se as mensagens acima surgirem ao iniciar o convidado, a tela nunca será iniciada. Reinicie o convidado para tentar novamente.

Evite o driver genérico a todo o custo (é aquele com data 11/11/2016). O driver genérico causa erros 43 de forma consistente e impede que o driver Intel seja atualizado normalmente. Caso ele acabe instalado, é melhor removê-lo no Modo de Segurança e então, ao reiniciar e voltar ao modo normal, desativar a internet para poder instalar o driver da Intel sem o genérico reaparecer. Com as versões 24.xxx, o genérico não será mais oferecido.

Uma vez que os drivers corretos tenham sido devidamente instalados, abra o dxdiag. Se não der tela azul no momento ou alguns segundos depois, é sucesso. O Windows 10 convidado está estável.

O dxdiag deve mostrar algo semelhante a:

Nas configurações de energia, é melhor desabilitar a opção de apagar a tela devido a inatividade e desabilitar a suspensão do sistema (uma das poucas ocasiões em que telas azuis ainda ocorrem).

O convidado Windows 10 sem dma-buf está pronto para ser usado e a VGA virtual pode ser removida.

Para criar um convidado com dma-buf, os cuidados com o hospedeiro são os mesmos, mas o comando usado no QEMU é um pouco diferente:

 sudo env PULSE_LATENCY_MSEC=0 QEMU_PA_SAMPLES=98875 QEMU_AUDIO_DAC_FIXED_FREQ=48000
qemu-system-x86_64
-hda win10.raw -enable-kvm -cpu host -smp cores=2,threads=2 -m 3G
-device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/185802b6-7405-11e8-9e14-6ff0319bd0dc,rombar=0,x-igd-opregion=on,display=on,x-vga=off
-usb -device usb-mouse -bios bios.bin -monitor vc -serial stdio
-vga cirrus -display gtk,gl=on -cdrom “Win10_1709_BrazilianPortuguese_x64.iso”
-netdev user,id=net0,hostfwd=::33890-:3389 -device e1000,netdev=net0,bus=pci.0,addr=0x8

Boa parte do comando é igual, mas a opção display=on foi configurada para ativar o dma-buf, a opção -bios foi trocada para a bios.bin, que é a SeaBIOS, construída junto com o QEMU 2.12 (ela pode ser localizada no diretório onde o QEMU 2.12 foi instalado, dentro do diretório share/qemu), pois o convidado Windows 10 não inicializa a tela em modo UEFI (só pode ser acessado remotamente). Na opção -display, adicionou-se o gtk,gl=on para que a janela GTK seja acelerada por OpenGL.

Os procedimentos para configurar o convidado Windows 10 com dma-buf são iguais aos do convidado Windows 10 sem dma-buf, incluindo o RDP, que precisa ser ativado no convidado com dma-buf também.

Quando usando o modo BIOS, o dxdiag deve mostrar algo como:

Preste atenção nos valores exibidos em BIOS: veja como o dxdiag não é capaz de apresentar os valores. Sem a opção kvm.ignore_msrs=1 na linha de comando do kernel Linux e sem a opção x-igd-opregion=on na linha de comando do QEMU, quando o Windows tenta ler os valores que deveriam preencher o local das variáveis, o convidado sofre uma pane e dá tela azul, podendo comprometer a funcionalidade do hospedeiro também.

Uma vez que o uso do convidado tenha terminado, pode-se remover a GPU virtual usando (vide exemplo):

 sudo sh -c ‘echo 1 > /sys/bus/pci/devices/0000:00:02.0/185802b6-7405-11e8-9e14-6ff0319bd0dc/remove’

 

OBSERVAÇÕES ADICIONAIS, RESULTADOS OBTIDOS E REFERÊNCIAS

 

Inicialmente: não me responsabilizo por danos ou perda de capacidade consequentes de seguir esses passos. É por sua própria conta e risco. O que está descrito aqui foi testado e funcionou de forma adequada, mas não é possível garantir o pleno funcionamento de nada descrito aqui ou outros casos implícitos.

Algumas etapas como a configuração do servidor VNC sem senha e a não ativação do firewall foram feitas de tal forma porque considera-se que o sistema convidado pode ter plena confiança no hospedeiro e ele só pode ser acessado a partir do hospedeiro. Não exponha um computador configurado daquela forma direto na internet!

Nas referências, há algumas opções adicionais que são utilizadas nos exemplos, mas que não foi possível encontrar suas funções e, aparentemente, a ausência não prejudicou o desempenho ou a estabilidade dos convidados ou do hospedeiro. Por isso, foram omitidas.

Prepare-se para o dmesg ficar vermelho: muitíssimas mensagens de erro surgem, praticamente todas inofensivas. A partir da versão 4.17 do kernel Linux, várias delas deixaram de existir, tornando a leitura do dmesg mais fácil.

O quão capazes são os convidados criados com iGVT-g? Os resultados variam bastante, mas geralmente eles são muito positivos. Referente às capacidades de codificação de vídeo com VA-API, um vídeo de teste foi usado como referência. O teste realizado é codificar esse vídeo usando o FFmpeg com o seguinte comando:

 ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -i input.webm -vf format=nv12,hwupload -acodec aac -vcodec h264_vaapi output.mp4

O hospedeiro com Xubuntu 18.04 codifica o vídeo a uma velocidade de 13,5x o tempo real. O convidado com Xubuntu 18.04, executando o mesmo comando com a mesma versão do FFmpeg para codificar o vídeo o codifica a uma velocidade de 8x o tempo real.

Foi percebida uma diferença notável no uso de recursos do hospedeiro entre o comando ser executado no hospedeiro ou no convidado. Usando o programa intel-gpu-overlay junto com o Xephyr, foi possível capturar a tela mostrando a diferença existente:

Hospedeiro:

Convidado:

No Windows 10, o FFmpeg utiliza os codificados Intel QSV (Quick Sync Video) ao invés de VA-API. O comando no Windows ficaria algo como:

 ffmpeg -i input.webm -acodec aac -vcodec h264_qsv output.mp4

E a velocidade obtida foi de 5,5x o tempo real. A versão do FFmpeg era diferente, o sistema era diferente e, mesmo assim, o codificador Intel QSV funcionou corretamente.

Os resultados de benchmark foram bastante interessantes. Foi utilizado o PassMark PerformanceTest 9.0 para obter os resultados. O sistema hospedeiro com Windows 10 obteve o seguinte resultado:

O convidado Windows 10 com o driver versão 15.45:

O convidado Windows 10 com o driver versão 24.20:

Chegou-se ao ponto de o convidado ter um desempenho 3D maior que o hospedeiro, mesmo com a sobrecarga do KVM mais o hospedeiro Linux. Evidentemente, um teste do “mundo real” deveria ser feito:

Esse é um dos exemplos de modelos de simulação disponíveis no Tecnomatix Plant Simulation 13, da Siemens. Sistemas Windows já penam para exibir simulações mais complexas em 3D, o convidado lidou super bem com ela.

Esses vales no uso de GPU ocorriam puramente devido à configuração do som. O som mal configurado prejudica muito o funcionamento do convidado Windows 10.

Praticamente todos os aplicativos testados funcionam corretamente no convidado Windows 10. Há um único jogo que, por um motivo conhecido (port mal-feito) não abre. A primeira tela carrega, mas então o logo da desenvolvedora não aparece e o jogo trava.

É raro um projeto chamar tanto a minha atenção, mas ver do que a solução Intel GVT-g é capaz, ter visto esse projeto evoluir de “tela azul a cada 2 minutos com o sistema sem uso” para “5 horas de teste de tortura” e podendo usar algo tão avançado com um simples Intel Core i3-6100U e uma Intel HD Graphics 520 é realmente espetacular.

Rolar para cima