2018年12月04日

Xilinx QEMUのWindows版をUbuntu上でクロスビルドする

QEMU の Windows 版のビルド方法は、このブログでも何度も取り上げていますが、QEMU が要求する GLib ライブラリのバージョンが上がり続けているなどの理由により、正常動作する QEMU をビルドできる環境を構築し、QEMU のバージョンアップに追従し続けることが、現状かなり難しくなっています。(少なくとも現在の MSYS2 の GCC 8.2.0 環境でビルドした QEMU は正常動作しません。)

そこで本記事では、QEMU のメンテナの一人であり、長年 Windows 版を開発、バイナリの配布をし続けている Stefan Weil さんがメンテナンスしているビルド環境をお借りして、Ubuntu 18.04 上で Windows 64-bit 版 QEMU をクロスビルドする方法を解説します。



注意:本記事のビルド方法では、APT リストに Stefan Weil さんを信頼できるディストリビューターとして登録し、そこから deb パッケージを apt-get することになります。もちろん Stefan Weil さんは信頼できる方だと思われますが、非公式のパッケージをシステムにインストールすることは、本質的に重大なセキュリティリスクを伴う行為となりますので、重要なデータが含まれるシステムにはインストールせず、ビルド専用の環境か、仮想マシン上にインストールすることを強く推奨します。

〇 ビルド環境の準備

- 公式パッケージのインストール

まずは MinGW-w64 の 64-bit 版をインストールします。ここでは、今回は不要なものもありますが、私が MinGW GCC をビルドする時のパッケージを全部入れます。また、QEMU のビルドに pkg-config が必要なので、mingw-w64-tools も追加しました。

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install build-essential gitk mingw-w64 g++-mingw-w64-i686 autoconf autopoint flex bison gettext texinfo texlive dejagnu ruby zip libxml2-utils dblatex doxygen libncurses5-dev qemu-user-static groff zlib1g-dev autogen mingw-w64-tools
- 非公式パッケージのインストール

参考サイト:Packages for Mingw-w64 cross compilation on Debian GNU Linux

Stefan Weil さんの GPG キーを APT システムの信頼リストに追加します。サイトに書いてあるコマンドラインでは上手く行かなかったので、一度ファイルを DL してから追加しました。
$ wget https://qemu.weilnetz.de/debian/gpg.key
$ sudo apt-key add gpg.key
続いて、APT リストに新規ファイルを追加します。適当なエディタでファイルを作ってください。
$ sudo vi /etc/apt/sources.list.d/cygwin.list
deb https://qemu.weilnetz.de/debian/ testing contrib
非公式パッケージをインストールします。x86_64 パッケージは /usr/x86_64-w64-mingw32/sys-root/ 以下に展開されるので、公式パッケージとバッティングすることは無いと思います。

参考サイト:QEMU for Windows - Build instructions
$ sudo apt-get update
$ sudo apt-get install mingw64-x86-64-curl mingw64-x86-64-gnutls mingw64-x86-64-gtk3 mingw64-x86-64-libxml2 mingw64-x86-64-ncurses mingw64-x86-64-sdl2 mingw64-x86-64-libusb1.0 mingw64-x86-64-usbredir mingw64-x86-64-glib2.0 mingw64-x86-64-pixman
... (省略) ...
以下の追加パッケージがインストールされます:
  mingw64-x86-64-atk1.0 mingw64-x86-64-bzip2 mingw64-x86-64-cairo
  mingw64-x86-64-expat mingw64-x86-64-fontconfig mingw64-x86-64-freetype2
  mingw64-x86-64-gdk-pixbuf2.0 mingw64-x86-64-gettext mingw64-x86-64-gmp
  mingw64-x86-64-harfbuzz mingw64-x86-64-jasper mingw64-x86-64-jbigkit
  mingw64-x86-64-libepoxy mingw64-x86-64-libffi mingw64-x86-64-libgnurx
  mingw64-x86-64-libidn2 mingw64-x86-64-libjpeg-turbo mingw64-x86-64-libpng
  mingw64-x86-64-libssh2 mingw64-x86-64-libtasn1 mingw64-x86-64-libunistring
  mingw64-x86-64-lzo2 mingw64-x86-64-nettle mingw64-x86-64-nghttp2
  mingw64-x86-64-openssl mingw64-x86-64-p11-kit mingw64-x86-64-pango1.0
  mingw64-x86-64-pcre mingw64-x86-64-tiff mingw64-x86-64-win-iconv
  mingw64-x86-64-xz mingw64-x86-64-zlib
以下のパッケージが新たにインストールされます:
  mingw64-x86-64-atk1.0 mingw64-x86-64-bzip2 mingw64-x86-64-cairo
  mingw64-x86-64-curl mingw64-x86-64-expat mingw64-x86-64-fontconfig
  mingw64-x86-64-freetype2 mingw64-x86-64-gdk-pixbuf2.0 mingw64-x86-64-gettext
  mingw64-x86-64-glib2.0 mingw64-x86-64-gmp mingw64-x86-64-gnutls
  mingw64-x86-64-gtk3 mingw64-x86-64-harfbuzz mingw64-x86-64-jasper
  mingw64-x86-64-jbigkit mingw64-x86-64-libepoxy mingw64-x86-64-libffi
  mingw64-x86-64-libgnurx mingw64-x86-64-libidn2 mingw64-x86-64-libjpeg-turbo
  mingw64-x86-64-libpng mingw64-x86-64-libssh2 mingw64-x86-64-libtasn1
  mingw64-x86-64-libunistring mingw64-x86-64-libusb1.0 mingw64-x86-64-libxml2
  mingw64-x86-64-lzo2 mingw64-x86-64-ncurses mingw64-x86-64-nettle
  mingw64-x86-64-nghttp2 mingw64-x86-64-openssl mingw64-x86-64-p11-kit
  mingw64-x86-64-pango1.0 mingw64-x86-64-pcre mingw64-x86-64-pixman
  mingw64-x86-64-sdl2 mingw64-x86-64-tiff mingw64-x86-64-usbredir
  mingw64-x86-64-win-iconv mingw64-x86-64-xz mingw64-x86-64-zlib


これらのファイルは、MinGW GCC が使用するライブラリファイル(データ)であり、何かが実行されるわけではないので、ホスト環境の Ubuntu のバージョンには依存しないはずです。(もともとは cygwin のパッケージだったものを、Stefan Weil さんが cyg2deb というツールで Debian 用に変換して使用しているものを、Ubuntu にインストールしているわけなので、けっこう無茶なことしてます。deb パッケージとか言ってますが Windows のようなインストーラではなく、実体は単なるアーカイブファイルを依存関係をチェックした後に展開しているだけなので問題無いのでしょう。)

〇 QEMU のビルド

公式の QEMU 3.0.0 がビルドでき、動作することも確認済みですが、ここでは Xilinx QEMU をビルドしてみます。(Xilinx QEMU は Yocto/OpenEmbedded で Windows 版がビルドできると公式 wiki で解説されていますが、私が不慣れなせいもあり、いろいろ試してみてもすぐエラーで止まってしまい、どうもよくわかりませんでした…。)

現在最新の SDK である Xilinx SDK 2018.2 に合わせて、tag をチェックアウトしてビルドします。

参考 PDF:Xilinx Quick Emulator User Guide QEMU UG1169(v2018.2) June 6, 2018.PDF
$ mkdir xilinx
$ cd xilinx/
$ git clone https://github.com/Xilinx/qemu.git
$ cd qemu/
$ git checkout -b xilinx-v2018.2 refs/tags/xilinx-v2018.2
Switched to a new branch 'xilinx-v2018.2'
$ git branch
  master
* xilinx-v2018.2
$ cd ..
$ mkdir build install
$ cd build
prefix は必ず絶対パスで指定してください。(相対パスで指定してしまうと、それぞれの生成物をビルドしたディレクトリからの相対パスにインストールされてしまいます。)
追記: --enable-debug を付けたままでした。最適化無しのデバッグ用バイナリが生成されます。-O2 最適化したリリース用バイナリを作りたい場合はオプションを外してください。デバッグ情報が不要な場合は --disable-strip も外してください。
$ ../qemu/configure --prefix=/home/kmc/xilinx/install --enable-fdt --enable-gtk --enable-sdl --with-sdlabi=2.0 --target-list=aarch64-softmmu,microblazeel-softmmu,arm-softmmu --enable-debug --disable-strip --disable-werror --cross-prefix=x86_64-w64-mingw32- --extra-cflags="-I/usr/x86_64-w64-mingw32/sys-root/mingw/include/" --extra-ldflags="-L/usr/x86_64-w64-mingw32/sys-root/mingw/lib/"
Install prefix    /home/kmc/xilinx/install
BIOS directory    /home/kmc/xilinx/install
firmware path     /home/kmc/xilinx/install/share/qemu-firmware
binary directory  /home/kmc/xilinx/install
library directory /home/kmc/xilinx/install/lib
module directory  /home/kmc/xilinx/install/lib
libexec directory /home/kmc/xilinx/install/libexec
include directory /home/kmc/xilinx/install/include
config directory  /home/kmc/xilinx/install
local state directory   queried at runtime
Windows SDK       no
Source path       /home/kmc/xilinx/qemu
GIT binary        git
GIT submodules    ui/keycodemapdb dtc capstone
C compiler        x86_64-w64-mingw32-gcc
Host C compiler   cc
C++ compiler      x86_64-w64-mingw32-g++
Objective-C compiler x86_64-w64-mingw32-gcc
ARFLAGS           rv
CFLAGS            -g
QEMU_CFLAGS       -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/pixman-1 -I$(SRC_PATH)/dtc/libfdt -DHAS_LIBSSH2_SFTP_FSYNC -mms-bitfields -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0 -I/usr/x86_64-w64-mingw32/sys-root/mingw/lib/glib-2.0/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -DNCURSES_WIDECHAR -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=199506L -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -m64 -mcx16 -mthreads -D__USE_MINGW_ANSI_STDIO=1 -DWIN32_LEAN_AND_MEAN -DWINVER=0x501 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv  -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/ -Wexpansion-to-defined -Wendif-labels -Wno-shift-negative-value -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-strong -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/p11-kit-1 -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include  -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/libpng16 -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -I$(SRC_PATH)/capstone/include
LDFLAGS           -Wl,--nxcompat -Wl,--no-seh -Wl,--dynamicbase -Wl,--warn-common -m64 -g  -L/usr/x86_64-w64-mingw32/sys-root/mingw/lib/
make              make
install           install
python            python -B
smbd              /usr/sbin/smbd
module support    no
host CPU          x86_64
host big endian   no
target list       aarch64-softmmu microblazeel-softmmu arm-softmmu
gprof enabled     no
sparse enabled    no
strip binaries    no
profiler          no
static build      no
SDL support       yes (2.0.7)
GTK support       yes (3.22.28)
GTK GL support    no
VTE support       no
TLS priority      NORMAL
GNUTLS support    yes
GNUTLS rnd        yes
libgcrypt         no
libgcrypt kdf     no
nettle            yes (3.4)
nettle kdf        yes
libtasn1          yes
curses support    yes
virgl support     no
curl support      yes
mingw32 support   yes
Audio drivers     dsound
Block whitelist (rw)
Block whitelist (ro)
VirtFS support    no
Multipath support no
VNC support       yes
VNC SASL support  no
VNC JPEG support  yes
VNC PNG support   yes
xen support       no
brlapi support    no
bluez  support    no
Documentation     yes
PIE               no
vde support       no
netmap support    no
Linux AIO support no
ATTR/XATTR support no
Install blobs     yes
KVM support       no
HAX support       yes
TCG support       yes
TCG debug enabled yes
TCG interpreter   no
RDMA support      no
fdt support       yes
preadv support    no
fdatasync         no
madvise           no
posix_madvise     no
libcap-ng support no
vhost-net support no
vhost-scsi support no
vhost-vsock support no
vhost-user support no
Trace backends    log
spice support     no
rbd support       no
xfsctl support    no
smartcard support no
libusb            yes
usb net redir     yes
OpenGL support    no
OpenGL dmabufs    no
libiscsi support  no
libnfs support    no
build guest agent yes
QGA VSS support   no
QGA w32 disk info yes
QGA MSI support   no
seccomp support   no
coroutine backend win32
coroutine pool    yes
debug stack usage no
crypto afalg      no
GlusterFS support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   yes
TPM passthrough   no
TPM emulator      no
QOM debugging     yes
Live block migration yes
lzo support       yes
snappy support    no
bzip2 support     yes
NUMA host support no
tcmalloc support  no
jemalloc support  no
avx2 optimization yes
replication support yes
VxHS block device no
capstone          git

$ make -j8
$ make install
$ ls ../install/
QEMU,cgthree.bin   openbios-sparc64          qemu-system-arm.exe
QEMU,tcx.bin       palcode-clipper           qemu-system-armw.exe
acpi-dsdt.aml      petalogix-ml605.dtb       qemu-system-microblazeel.exe
bamboo.dtb         petalogix-s3adsp1800.dtb  qemu-system-microblazeelw.exe
bios-256k.bin      ppc_rom.bin               qemu_logo_no_text.svg
bios.bin           pxe-e1000.rom             qemu_vga.ndrv
efi-e1000.rom      pxe-eepro100.rom          s390-ccw.img
efi-e1000e.rom     pxe-ne2k_pci.rom          s390-netboot.img
efi-eepro100.rom   pxe-pcnet.rom             sgabios.bin
efi-ne2k_pci.rom   pxe-rtl8139.rom           share
efi-pcnet.rom      pxe-virtio.rom            skiboot.lid
efi-rtl8139.rom    qemu-doc.html             slof.bin
efi-virtio.rom     qemu-doc.txt              spapr-rtas.bin
efi-vmxnet3.rom    qemu-ga.exe               trace-events-all
keymaps            qemu-icon.bmp             u-boot.e500
kvmvapic.bin       qemu-img.exe              vgabios-cirrus.bin
linuxboot.bin      qemu-io.exe               vgabios-qxl.bin
linuxboot_dma.bin  qemu-qmp-ref.html         vgabios-stdvga.bin
multiboot.bin      qemu-qmp-ref.txt          vgabios-virtio.bin
openbios-ppc       qemu-system-aarch64.exe   vgabios-vmware.bin
openbios-sparc32   qemu-system-aarch64w.exe  vgabios.bin

〇 必要な dll のコピー

今回は以下のクロス MinGW GCC でビルドしたので、Windows 上で exe を実行するためには、対応する dll をコピーする必要があります。
$ x86_64-w64-mingw32-gcc -v
Using built-in specs.
COLLECT_GCC=x86_64-w64-mingw32-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/lto-wrapper
Target: x86_64-w64-mingw32
Configured with: ../../src/configure --build=x86_64-linux-gnu --prefix=/usr --includedir='/usr/include' --mandir='/usr/share/man' --infodir='/usr/share/info' --sysconfdir=/etc --localstatedir=/var --disable-silent-rules --libdir='/usr/lib/x86_64-linux-gnu' --libexecdir='/usr/lib/x86_64-linux-gnu' --disable-maintainer-mode --disable-dependency-tracking --prefix=/usr --enable-shared --enable-static --disable-multilib --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --libdir=/usr/lib --enable-libstdcxx-time=yes --with-tune=generic --with-headers=/usr/x86_64-w64-mingw32/include --enable-version-specific-runtime-libs --enable-fully-dynamic-string --enable-libgomp --enable-languages=c,c++,fortran,objc,obj-c++,ada --enable-lto --with-plugin-ld --enable-threads=win32 --program-suffix=-win32 --program-prefix=x86_64-w64-mingw32- --target=x86_64-w64-mingw32 --with-as=/usr/bin/x86_64-w64-mingw32-as --with-ld=/usr/bin/x86_64-w64-mingw32-ld --enable-libatomic --enable-libstdcxx-filesystem-ts=yes
Thread model: win32
gcc version 7.3-win32 20180312 (GCC)
$ cp /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/*.dll ../install/
$ cp /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll ../install/
$ cp /usr/x86_64-w64-mingw32/sys-root/mingw/bin/*.dll ../install/
ここまでは Ubuntu Linux 上での作業でしたが、以後の動作確認は Windows のコマンドプロンプト上となります。
samba でファイルを共有し、install ディレクトリを丸ごとコピーしても良いですし、net use で Windows にマウントしても良いです。
以後の例は net use で home を U ドライブにマウントしている状況で実行するので、適宜読み替えてください。

〇 簡単な動作確認
U:\>cd xilinx
U:\xilinx>install\qemu-system-aarch64.exe --version
QEMU emulator version 2.11.1 (v2.6.0-12948-gf5fb2a88ff-dirty)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers

〇 Xilinx SDK でベアメタルの hello, world をビルドし、動作確認

Xilinx 社のソフトウェア開発キット スタンドアロン WebInstall Client - 2018.2 Lightweight Installer Windows 64 用 SDK 2018.2 ウェブ インストール (EXE - 50.4 MB) をインストールしてください。

ダウンロードとインストールには Xilinx 社のアカウントとパスワード、開発者情報の入力が必要です。

インストールした後、「Xilinx Design Tools > Xilinx SDK 2018.2」を起動し、初期設定をした後、新規 Application プロジェクトを作成します。プロジェクト名を適当に設定し(今回は hello_world)、Hardware Platform を ZCU102_hw_platform に指定する以外は全てデフォルトで構いません。プロジェクトを作成し、eclipse で開けたら、「Build All」でビルドします。できた hello_world.elf を使用し、以下のように起動します。(hello_world.elf の場所は適宜読み替えてください。全てデフォルトで設定していれば、ユーザー名以外は同じはずです。)
U:\xilinx>install\qemu-system-aarch64.exe -nographic -M arm-generic-fdt -dtb c:/Xilinx/SDK/2018.2/data/qemu/zynqMP/SINGLE_ARCH/zcu102-arm.dtb -device loader,file=C:/Users/kmc/workspace/hello_world/Debug/hello_world.elf,cpu-num=0 -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4
ちょっと他のエラーも出ていますが、無事に Hello World が UART に出力されました。
dsound: Could not initialize DirectSoundCapture
dsound: Reason: No sound driver is available for use, or the given GUID is not a valid DirectSound device ID
Hello World
Xilinx QEMU は、バニラの QEMU とはほぼ別物になっていて、ZCU102(AArch64)の場合は Cortex-A53 が 4 コアと、Cortex-R5f が 2 コアの、計 6 コアのヘテロジニアスマルチコア構成がデフォルトになっていて、私は確認してませんが qemu-system-arm や aarch64 の QEMU と、qemu-system-microblazeel をファイルシステム経由で協調動作させる MULT_ARCH 構成もサポートしているそうです。

上記の確認では AArch64 QEMU 単体の SINGLE_ARCH (実機では microblaze で PMU をコントロールするようですが、そこはたぶんオミットされている?)の dtb を使用し、コア 0 のみを有効にして hello_world.elf を実行しています。

マルチコアを活かすプログラムをスクラッチから開発することはあまり現実的ではないので、実用上は RPU(R コアのような Real-time Processing Unit)で RTOS を、APU (A コアのような Application Processing Unit)で Linux を動かすことになりますが、こうしてサクッと(プラットフォームの知識ゼロで)ベアメタルのコードが IDE でビルドできて実機が無くても動作確認できる Xilinx 社の開発環境は素晴らしいですね。(弊社のハードウェアチームや、FPGA に関わるソフトの人たちは普通にずっとバリバリ使ってるようです。私が今まで知らなかっただけ。)

追記: ZCU102 ターゲットの APU 4 コア、RPU 2 コアの 6 コア構成は本家 QEMU にもマージされていました。-machine-path オプションによるマルチアーキテクチャ連携(MULTI_ARCH)機能はマージされていないようです。また、hw/misc/xilinx_zynqmp_* は一切マージされていないようです。ターゲットマシンに arm-generic-fdt を指定し、-hw-dtb (device tree binary) オプションで指定した dtb でエミュレーションする仮想ハードウェアを設定するという Xilinx QEMU の肝となる機能もマージされていません。(非常に紛らわしいですが、-dtb で指定可能な dtb は Linux が使用するブート ROM (BIOS のようなソフトウェア)で、こちらは本家でも使える機能です。)

kmckk at 15:49コメント(0)qemu | 若槻 

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード