Criando um ambiente de desenvolvimento com o QEMU
Resumo
Emuladores são ferramentas essenciais desde o desenvolvimento de aplicativos que serão executados em uma plataforma diferente da qual são desenvolvidos, até a criação de aplicações que trabalham diretamente com o hardware, como sistemas operacionais. Este artigo aborda a criação de um ambiente completo de desenvolvimento utilizando o emulador QEMU[1], que é licensiado sob a GPL[2].
- Introdução
Em computação, um Emulador é um software capaz de executar instruções de uma outra, ou da mesma arquitetura em que é executado, podendo criar ambientes virtuais completos. Os exemplos mais comuns são emuladores de vídeo games, que executam jogos (software) de um determinado hardware em PCs comuns, sendo possível, por exemplo, executar jogos do Atari em um PC.
O QEMU[1] é um emulador de máquina e um virtualizador. Como emulador, é capaz de executar instruções de processadores de várias arquiteturas, dentre elas x86[3], ARM[4], SPARC[5], PowerPC[6], e várias outras. Assim, num computador x86 pode-se ter várias instâncias do QEMU emulando máquinas x86, ARM, podendo executar outros sistemas operacionais ou até mesmo diferente tipos de BIOS. Já como virtualizador, o QEMU é capaz somente de executar instruções x86 rodando em uma máquina x86, isto porque o QEMU cria um ambiente virtual mas executa determinadas instruções diretamente no processador em que está sendo executado.
Toda a documentação (lista de processadores suportados, etc) pode ser obtida no site oficial do projeto[1]. Neste artigo será tratado apenas o modo emulador, portanto, a partir de agora, qualquer referência ao QEMU refere-se ao modo emulador.
O QEMU pode ser extramamente util não só no desenvolvimento de sistemas operacionais, mas também de distribuições Linux, as figuras abaixo mostram a sua execução tanto no Windows® quando no Linux:
- Instalação
O QEMU foi escrito para Linux, mas possui ports para Windows® e MAC, que podem ser obtidos em:
- Windows®: http://www.h7.dion.ne.jp/~qemu-win/
- MAC: http://qemu.darwinports.com/
A maioria das distribuições linux já possuem pacotes do QEMU. No Ubuntu e família, a instalação pode ser feita através do comando:
$ sudo apt-get install qemu
- Compilando o QEMU
O código-fonte do QEMU pode ser obtido no site oficial[1] do projeto. A compilação deve ser feita com a versão 3.x do gcc, pois versões superiores podem gerar problemas na compilação ou produzirem binários instáveis. Atualmente a maioria as distriuições já vêm com a versão 4.x do gcc, sendo necessária a instalação da versão 3, para verificar qual a versão instalada no sistema utilize o comando gcc -v:
$ gcc -v Usando especificações internas. Destino: i486-linux-gnu Configurado com: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Modelo de fluxo de execução (thread): posix gcc versão 4.2.3 (Ubuntu 4.2.3-2ubuntu7) $
No exemplo acima a versão instalada (padrão) do sistema é a 4.2.3, necessitando assim da instalação da versão 3.x. No Ubuntu e família pode-se instalar a versão 3.4:
$ sudo apt-get install gcc-3.4
Possuindo as ferramentas básicas de compilação (gcc, make) a compilação e instalação é simples:
$ tar -xvzf qemu-0.9.1.tar.gz $ cd qemu-0.9.1 $ ./configure $ make $ sudo make install
Caso a versão padrão do gcc não seja 3.x, deve-se informar qual versão a ser utilizada, por exemplo:
$ ./configure --cc=gcc-3.4
- Módulo de aceleração
O qemu pode ser acelerado através da instalação de um módulo para o kernel que o permite executar instruções diretamente no processador. Este módulo, o kqemu, já possui pacote para a maioria das distribuições, mas também pode ser baixado no site oficial do projeto. A compilação e instalação é simples:
$ tar -xvzf kqemu-1.3.0pre11.tar.gz $ cd kqemu-1.3.0pre11/ $ ./configure $ make $ sudo make install
No Ubuntu e família o kqemu pode ser compilado e instalado através dos comandos:
$ sudo apt-get install kqemu-source module-assistant $ sudo module-assistant
Na janela do module-assitant deve-se selecionar as opções PREPARE e depois SELECT, marcando o módulo kqemu para compilação. Em seguida, basta selecionar a opções BUILD e INSTALL.
- Configurando kqemu
Para ser utilizado o módulo deve ser carregado no kernel, criando o dispositivo /dev/kqemu. Por padrão, somente o root terá acesso a este dispositivo, assim o qemu deverá ser executado com o root para ter a aceleração ativada. Para permitir que outros usuários possam executar o qemu com aceleração siga os passos abaixo:
- Crie o grupo qemu:
- Crie o arquivo /etc/udev/rules.d/40-kqemu.rules com o seguinte conteudo:
- Adicione kqemu no arquivo /etc/modules para carregar o módulo na inicialização do sistema:
- Adicione o usuário que poderá utilizar o módulo de aceleração no grupo qemu:
$ sudo groupadd qemu
1 2
# Arquivo para setar permissoes do dispositivo de aceleracao do kqemu KERNEL=="kqemu" GROUP="qemu"
$ su root# echo kqemu >> /etc/modules
O módulo também pode ser carregado manualmente, através do comando:
$ sudo modprobe kqemu
$ sudo usermod -a -G qemu usuario
Somente os usuários pertencentes ao grupo qemu possuirão acesso a aceleração, que é ativada quando o qemu é chamado com o parâmetro -kernel-kqemu, por exemplo:
$ qemu -kernel-kqemu -hda minix204.img -boot c
- Configurando kqemu
- Executando o QEMU
O qemu é composto por vários executáveis, um para cada tipo de arquitetura:
$ qemu qemu qemu-m68k qemu-sh4 qemu-system-m68k qemu-system-ppcemb qemu-alpha qemu-make-debian-root qemu-sh4eb qemu-system-mips qemu-system-sh4 qemu-arm qemu-mips qemu-sparc qemu-system-mips64 qemu-system-sh4eb qemu-armeb qemu-mipsel qemu-sparc32plus qemu-system-mips64el qemu-system-sparc qemu-cris qemu-ppc qemu-sparc64 qemu-system-mipsel qemu-system-x86_64 qemu-i386 qemu-ppc64 qemu-system-arm qemu-system-ppc qemu-x86_64 qemu-ppc64abi32 qemu-system-cris qemu-system-ppc6 $ qemu
Iremos utilizar o executável qemu, que é um emulador de PC (arquitetura x86).
O qemu utiliza a BIOS do projeto Bochs e suporta multiprocessamento simétrico (SMP) podendo emular até 255 CPUs. Os seguintes periféricos são simulados:
- Ponte PCI i440FX e Ponte PCI-ISA PIIX3
- Placa de vídeo VGA PCI Cirrus CLGD 5446
- Placa de vídeo genérica com extensões VESA do Bochs
- Mouse e teclado PS/2
- 2 interfaces IDE com suporte a disco rígido e CD-ROM
- Disquetes
- Adaptadores de Rede PCI/ISA
- Portas seriais
- Placa de som Creative SoundBlaster 16
- Placa de som ENSONIQ AudioPCI ES1370
- Adlib(OPL2) - Chip compatível com o Yamaha YM3812
- Controlador USB PCI UHCI e hub USB virtual
O qemu deve ser executado da seguinte forma:
- qemu [opções] [arquivo_imagem]
arquivo_imagem é o arquivo de imagem que o qemu irá emular. Este arquivo deve ser a imagem de um disco. O site http://www.oszoo.org contém centenas de imagem prontas (com diversos sistemas operacionais instalados) para serem utilizadas no qemu, por exemplo, acesse a sessão download e baixe a imagem do Minix 3.1.1 (Minix3_1_1 x86.tar). Para inciar a emulação basta descompactar a imagem e executar o qemu:
$ tar -xvf minix3_1_1_x86.tar $ cd minix3_1_1_x86/ $ qemu -hda minix_3_1_1.img -boot c
A figura abaixo ilustra a emulação do Minix:
Alguns atalhos facilitam o uso do qemu:
- Ctrl+Alt - Ativa/Desativa o mouse dentro do qemu
- Ctrl+Alt+F - Ativa/Desativa tela cheia (fullscreen)
- Ctrl+Alt+2 - Entra no monitor do qemu
- Ctrl+Alt+1 - Entra na tela de emulação (sai do monitor)
O monitor permite que várias ações de máquina sejam executadas: reset, adicionar/remover dispositivos USB, enviar eventos de teclado e mouse, capturar tela e áudio, dentre outras. Para listar os comandos disponíveis digite help.
O qemu também pode ser util em algumas tarefas, como:
- Testar um disquete de boot:
- Testar um live CD:
- Testar a iso de um live CD:
$ sudo qemu -fda /dev/fd0 -boot a
$ qemu -cdrom /dev/cdrom -boot d
$ qemu -cdrom imagem.iso -boot d
O qemu possui uma infinidade de opções, todas descritas na documentação oficial do projeto http://bellard.org/qemu/qemu-doc.html, as mais básicas são:
- -M machine : Especifíca qual máquina emular, para listar as disponíveis utilize -M ?
- -fda ou -fdb file : file indica o arquivo de imagem para ser emulado como um disquete (drive a ou b). O arquivo de dispositivo correspondente ao drive de disquete (por exemplo, /dev/fd0) também pode ser utilizado.
- -hda, -hdb, -hdc ou -hdd file : file indica o arquivo de imagem para ser emulado como um disco rígido (0, 1, 2 ou 3).
- -cdrom file : file indica o arquivo para ser emulado como um CD-ROM. O arquivo de dispositivo correspondente ao drive de CD também pode ser utilizado (por exemplo, /dev/cdrom).
- -boot X : X indica qual dispositivo “bootar” (a - disquete, c - HD, d - cdrom, n - Rede).
- Criando imagens
O utilitário qemu-img, que acompanha o qemu, permite a criação de imagens de disco em diversos formatos, inclusive no formato vmdk (utilizado pelo VMware 3 e 4). Sua sintaxe é simples, por exemplo, para criar a imagem teste.img de 30MB no formato qcow (com criptografia), utilize o comando abaixo:
$ qemu-img create -f qcow -e teste.img 30M
O qemu também suporta imagens raw (sem formato, contém apenas o conteúdo do disco), que serão abordadas neste artigo. A criação deste tipo de imagem é simples e pode ser feita através do comando dd:
$ dd if=/dev/zero of=teste.img bs=1024 count=10K
Neste caso, a imagem teste.img, de 10MB é criada. Para saber mais sobre o comando dd e seus multiplicadores (b, K, MB, etc), consulte man dd.
Criar o arquivo de imagem é apenas o primeiro passo na montagem de um sistema completo para emulação. Para que um sistema com boot possa ser instalado na imagem, é preciso que a mesma seja emulada como um dispositivo de bloco pelo Linux (haja emulação!!), este processo é feito através de dois utilitários: losetup, que faz parte do pacote util-linux-ng, presente por padrão em várias distribuições, e kpartx, que também possui pacote para inúmeras distros.
DICA:
Para que o kpartx funcione é preciso que a opção Device Drivers->Multiple devices driver support->Device mapper support esteja ativada na configuração do kernel ou se estiver como módulo, o mesmo deve ser carregado (modprobe dm_mod).
O utilitário debootstrap permite a instalação de um sistema debian dentro de um diretório qualquer, o que é extremamente útil na criação de imagens. A idéia é simples: Criar uma imagem através do dd, emular um dispositivo de blocos com essa imagem (para criar as partições e instalar o sistema através do debootstrap), deixando-a pronta para ser emulada posteriormente pelo qemu.
No Ubuntu e família, os utilitários citados podem ser instalados através do comando:
$ sudo apt-get install debootstrap kpartx
Primeiro passo, criar o arquivo de imagem, iremos utilizar um arquivo com 671MB:
$ dd if=/dev/zero of=mydebian.img bs=4096 count=160K
Segundo passo, verificar qual dispositivo de loop pode ser utilizado para emularmos a imagem como um dispositivo de bloco:
$ sudo losetup -f /dev/loop0
Terceiro passo, montar a imagem como um dispositivo de bloco e ajustar o número de cilindros do HD “virtual”:
$ sudo losetup /dev/loop0 mydebian.img $ sudo kpartx -av /dev/loop0 gpt: 0 slices dos: 4 slices $ $ sudo fdisk /dev/loop0 Comando (m para ajuda): x Comando avançado (m para ajuda): c Número de cilindros (1-1048576, padrão 81): 81 Comando avançado (m para ajuda): w A tabela de partições foi alterada! Chamando ioctl() para reler tabela de partições. AVISO: Re-leitura da tabela de partição falhou com erro 22: Argumento inválido. O kernel ainda está usando a tabela antiga. A nova tabela será usada no próximo reboot. Sincronizando discos.
Quarto passo, criar as partições:
$ sudo fdisk /dev/loop0 Comando (m para ajuda): n Comando - ação e estendida p partição primária (1-4) p Número da partição (1-4): 1 Primeiro cilindro (1-81, padrão 1): Usando valor padrão 1 Último cilindro ou +tamanho ou +tamanho M ou +tamanho K (1-81, padrão 81): 75 Comando (m para ajuda): n Comando - ação e estendida p partição primária (1-4) p Número da partição (1-4): 2 Primeiro cilindro (76-81, padrão 76): Usando valor padrão 76 Último cilindro ou +tamanho ou +tamanho M ou +tamanho K (76-81, padrão 81): Usando valor padrão 81 Comando (m para ajuda): t Número da partição (1-4): 2 Código hexadecimal (digite L para listar os códigos): 82 O tipo da partição 2 foi alterado para 82 (Linux swap / Solaris) Comando (m para ajuda): a Número da partição (1-4): 1 Comando (m para ajuda): p Disco /dev/loop0: 671 MB, 671088640 bytes 255 heads, 63 sectors/track, 81 cylinders Units = cilindros of 16065 * 512 = 8225280 bytes Disk identifier: 0x849a0b60 Dispositivo Boot Início Fim Blocos Id Sistema /dev/loop0p1 * 1 75 602406 83 Linux /dev/loop0p2 76 81 48195 82 Linux swap / Solaris Comando (m para ajuda): w A tabela de partições foi alterada! Chamando ioctl() para reler tabela de partições. AVISO: Re-leitura da tabela de partição falhou com erro 22: Argumento inválido. O kernel ainda está usando a tabela antiga. A nova tabela será usada no próximo reboot. Sincronizando discos.
Repare na configuração das partições, a primária conterá o sistema (Linux) e a secundária será utilizada para swap (Linux swap / Solaris).
Quinto passo, “emular” as partições:
$ sudo kpartx -dv /dev/loop0 gpt: 0 slices dos: 4 slices $ sudo kpartx -av /dev/loop0 gpt: 0 slices dos: 4 slices add map loop0p1 (254:0): 0 1204812 linear /dev/loop0 63 add map loop0p2 (254:1): 0 96390 linear /dev/loop0 1204875
Pronto, a imagem está funcionando como um dispositivo de blocos comum, o quinto passo consiste em gravar o sistema de arquivo e montar a partição de sistema:
$ sudo mkfs.ext3 /dev/mapper/loop0p1 $ sudo mount /dev/mapper/loop0p1 /mnt/
Sexto passo, instalar o sistema debian na imagem, o sistema escolhido foi o debian (versão etch) para i386:
sudo debootstrap --arch=i386 etch /mnt http://limbo.ime.usp.br/debian
O processo pode leval algum tempo, após concluído, a imagem mydebian.img já conterá o sistema debian instalado, porém sem nenhum kernel. O sétimo passo consiste em instalar um kernel na imagem:
$ sudo mount proc /mnt/proc -t proc $ sudo mount -o bind /dev /mnt/dev/ $ sudo chroot /mnt/ /bin/bash
Após o comando chroot estaremos dentro do “ambiente” da imagem, bastando apenas instalar o novo kernel:
$latex export PS1="chroot \w $ " chroot / $ apt-get install grub chroot / $ echo "do_initrd=yes" > /etc/kernel-img.conf chroot / $ apt-get install linux-image-2.6-486
Responda sim para todas as perguntas.
Continuando, o oitavo passo é instalar o grub para deixar a imagem “bootável”. Aqui precisaremos de um pequeno truque, será necessário a criação de um link na pasta /dev/mapper para representar o dispositivo /dev/loop0 (no nosso caso) de acordo com as partições criadas para que a instalação do grub proceda de forma correta, os comandos abaixo farão a criação do link necessário (de acordo com seu sistema) automaticamente:
chroot / $ apt-get install grub chroot / $ mkdir /boot/grub chroot / $ cp -r /usr/lib/grub/i386-pc/* /boot/grub/ chroot / $ ls /dev/mapper/loop*p1 | sed "s#/dev/mapper/loop\(.*\)p[0-9]# -s /dev/loop\1 /dev/mapper/loop\1p#" | xargs ln
Depois de criado o link (no nosso caso, /dev/mapper/loop0p), a instalação do grub pode ser feita:
chroot / $ grub --no-floppy GNU GRUB version 0.97 (640K lower / 3072K upper memory) [ Minimal BASH-like line editing is supported. For the first word, TAB lists possible command completions. Anywhere else TAB lists the possible completions of a device/filename. ] grub> device (hd1) /dev/mapper/loop0p grub> root (hd1,0) Filesystem type is ext2fs, partition type 0x83 grub> setup (hd1) Checking if "/boot/grub/stage1" exists... yes Checking if "/boot/grub/stage2" exists... yes Checking if "/boot/grub/e2fs_stage1_5" exists... yes Running "embed /boot/grub/e2fs_stage1_5 (hd1)"... 15 sectors are embedded. succeeded Running "install /boot/grub/stage1 (hd1) (hd1)1+15 p (hd1,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded Done. grub> quit chroot / $ update-grub Searching for GRUB installation directory ... found: /boot/grub Cannot determine root device. Assuming /dev/hda1 This error is probably caused by an invalid /etc/fstab Searching for default file ... Generating /boot/grub/default file and setting the default boot entry to 0 Searching for GRUB installation directory ... found: /boot/grub Testing for an existing GRUB menu.lst file ... Could not find /boot/grub/menu.lst file. Would you like /boot/grub/menu.lst generated for you? (y/N) Y Searching for splash image ... none found, skipping ... Found kernel: /boot/vmlinuz-2.6.18-6-486 Updating /boot/grub/menu.lst ... done chroot / $ echo "(hd0) /dev/hda" > /boot/grub/device.map chroot / $Nono e penultimo passo, a imagem está quase pronta, basta apenas algumas configurações no sistema, gravação da senha de root e uma limpeza para manter a “sanidade”:
chroot / $ cat > /etc/fstab # My fstab proc /proc proc defaults 0 0 /dev/hda1 / ext3 defaults,errors=remount-ro 0 1 /dev/hda2 none swap sw 0 0 (Pressione Ctrl+D para sair do cat) chroot / $ chroot / $ echo "mydebian" > /etc/hostname chroot / $ cat > /etc/hosts 127.0.0.1 localhost 127.0.0.1 mydebian (Pressione Ctrl+D para sair do cat) chroot / $ chroot / $ apt-get clean chroot / $ passwd Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully chroot / $ exit
Ultimo passo (ufa!), basta “desmontarmos” as partições e dispositivos, a imagem está pronta para ser emulada no qemu!
$ sudo umount /mnt/proc/ $ sudo umount /mnt/dev/ $ sudo umount /mnt/ $ sudo rm /dev/mapper/loop0p $ sudo kpartx -dv /dev/loop0 $ sudo losetup -d /dev/loop0
Imagem pronta, vamos testar!
$ qemu -hda mydebian.img -boot c
- Desenvolvendo
Após os 10 passos citados no tópico anterior a imagem já está utilizável, sendo emulada perfeitamente no qemu, porém, o sistema instalado é básico, sem servidor X, gcc, etc.
A internet pode ser ativada por DHCP:
$ dhclient eth0
Alguns pacotes podem ser instalados para tornar a imagem um ambiente de desenvolvimento mais amigável:
$ apt-get intall xserver-xorg xfce4 xfonts-100dpi xfonts-75dpi xfonts-base xfonts-encodings xfonts-scalable xfonts-utils gdm pciutils build-essential
Outras personalizações ficam a critério do leitor.
- Conclusão
Este artigo apresentou o emulador QEMU, uma ferramenta robusta e extremamente útil, que pode ajudar no desenvolvimento de distribuições Linux, Sistemas Operacionais e outras aplicações. Um método para criação de uma imagem de disco foi apresentado, assim como instalar um sistema debian nesta imagem.
- Bibliografia
- QEMU, website oficial, http://bellard.org/qemu/
- The GNU General Public License, http://www.gnu.org/licenses/gpl.html
- Arquitetura x86, http://pt.wikipedia.org/wiki/X86
- Arquitetura ARM, http://pt.wikipedia.org/wiki/Arquitetura_ARM
- Arquitetura de Processadores SPARC SUN, http://www.ic.unicamp.br/~pannain/mc722/aulas/trab05/sparc.pdf
- Arquitetura PowerPC, http://www.inf.ufrgs.br/procpar/disc/cmp134/trabs/T1/991/PowerPC/capi3.html
- Equivocation, http://equivocation.org/node/107

“Criando um ambiente de desenvolvimento com o QEMU”, por Renê de Souza Pinto, é licensiado sob a Creative Commons Atribuição-Uso Não-Comercial 2.5 Brasil License.
Baixar versão em PDF




Deixe um comentário