EMLinux 3.1 (202404) をQEMUでエミュレートしたZCU102で動かしてみた

# はじめに
- EMLinux 3.1 (202404) が[Zynq UltraScale+ MPSoC ZCU102 Evaluation Kit](https://www.xilinx.com/products/boards-and-kits/ek-u1-zcu102-g.html)に対応したので、QEMUで動かしてみました。

# 手順の概要
1. PetaLinux (rel-v2023.2) のビルドを実行し、QEMUでPetaLinuxを実行できる環境を作る。
1. EMLinux 3.1 (202404) をビルドする。
1. EMLinuxのビルド生成物を、上記PetaLinuxのビルド環境にコピーし、runqemuコマンドでEMLinuxを起動する。
   - runqemuコマンド (実体はPython3のスクリプト) を実行すると、以下の記事の付録に記載のように、qemu-system-microblazeelコマンドおよびqemu-system-aarch64コマンドに多くのオプションが指定しされて実行されます。これらのオプションを手動で実行するのが面倒なので、runqemuコマンドを使いました。
     - [PetaLinux (rel-v2023.2) をビルドしてQEMUで動かしてみた](https://qiita.com/fukunagt/items/859fab0bb151c8456d6d#%E4%BB%98%E9%8C%B2) 

# 参考
- [EMLinux](https://www.cybertrust.co.jp/iot/emlinux.html)
  - EMLinux 無償評価版
- [Launching QEMU Using Xilinx Yocto toolchains](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/821854264/Launching+QEMU+Using+Xilinx+Yocto+toolchains)
- [PetaLinux (rel-v2023.2) をビルドしてQEMUで動かしてみた](https://qiita.com/fukunagt/items/859fab0bb151c8456d6d)

# 構成図
```
+------------------------------------------------------+
| +--------------------------------------------------+ |
| | +----------------------------------------------+ | |
| | | +------------------------------------------+ | | |
| | | | EMLinux 3.1 (202404)                     | | | |
| | | +------------------------------------------+ | | |
| | | Zynq UltraScale+ MPSoC ZCU102 Evaluation Kit | | |
| | +----------------------------------------------+ | |
| | QEMU                                             | |
| +--------------------------------------------------+ |
| Ubuntu Server                                        |
+------------------------------------------------------+
```

# 各ソフトウェアのバージョン
## Ubuntu Server
```
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.6 LTS"
```

## QEMU
```
$ ./qemu-system-aarch64 --version 
QEMU emulator version 7.1.0 (v2.6.0-55433-g23b643ba16-dirty)
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers
```
- QEMUはPetaLinuxビルド時に生成されたqemu-system-aarch64コマンドを使用しました。
  ```
  /home/petalinux/github/petalinux-emlinux/build/tmp/work/x86_64-linux/qemu-helper-native/1.0-r1/recipe-sysroot-native/usr/bin
  ```

# 前提条件
- 以降の作業は、sudo権限を持つユーザiotsudoで実行しました。
- iotsudoユーザのホームディレクトリは/hoem/iotsudoです。以降の作業は、/home/iotsudo上で行いました。


# PetaLinux (rel-v2023.2) のビルド
1. 作業用のディレクトリを作成し、そのディレクトリに移動してください。
   ```sh
   mkdir -p /home/iotsudo/github/petalinux-emlinux
   ```
   ```sh
   cd /home/iotsudo/github/petalinux-emlinux
   ```
1. 以下の記事を参考にPetaLinuxをビルドし、起動できることを確認してください。
   - [PetaLinux (rel-v2023.2) をビルドしてQEMUで動かしてみた](https://qiita.com/fukunagt/items/859fab0bb151c8456d6d)
1. 起動確認後、別のターミナルを起動し、killコマンドでqemu-system-aarch64をkillしてください。
   ```
   $ ps ax|grep qemu-system-aarch64
   (snip)
   1633421 pts/1    Sl+    7:14 /home/iotsudo/github/petalinux-emlinux/build/(snip)/qemu-system-aarch64 (snip)
   $ kill -9 1633421
   ```
1. PetaLinuxのOSイメージが保存されているディレクトリを、以下のようにリネームしてください。
   ```sh
   cd /home/iotsudo/github/petalinux-emlinux/build/tmp/deploy/images
   ```
   ```sh
   mv zcu102-zynqmp zcu102-zynqmp_org
   ```

# EMLinux 3.1 (202404) のビルド
1. 以下を参考に、ビルドに必要なパッケージをインストールしてください。また、EMLinuxの展開まで行ってください。
   - [EMLinux 3.0 (202403) をQEMUでエミュレートしたRaspberry Pi 3で動かしてみた](https://qiita.com/fukunagt/items/eed9fb418e8dd84a5af6)
1. EMLinuxの展開後、以下のファイルを参考に作業を進めます。
   - EMLinux_3.1-202404/source/emlinux-3.1-202404/repos/meta-emlinux-ext-mpsoc/SETUP.md
1. PetaLinuxのBSPファイルを以下から入手してください。
   - https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/embedded-design-tools/2023-2.html
     - ダウンロードにはAMDのアカウントが必要です。
   - 本記事では、xilinx-zcu102-v2023.2-10140544.bspを使用しました。
1. 任意のディレクトリ (e.g., petalinux-bsp) を作成し、xilinx-zcu102-v2023.2-10140544.bspを保存してください。
   ```sh
   mkdir -p /home/iotsudo/petalinux-bsp
   ```
1. bspファイルから取り出したfirmwareを保存するディレクトリ (e.g., firmware-2023.2) を作成してください。
   ```sh
   mkdir -p /home/iotsudo/petalinux-bsp/firmware-2023.2
   ```
1. 以下のコマンドを実行し、bspファイルからfirmwareを取り出してください。
   ```sh
   tar xf xilinx-zcu102-v2023.2-10140544.bsp -C firmware-2023.2 --strip-component=4 xilinx-zcu102-2023.2/pre-built/linux/images/pmufw.elf
   ```
   ```sh
   tar xf xilinx-zcu102-v2023.2-10140544.bsp -C firmware-2023.2 --strip-component=4 xilinx-zcu102-2023.2/pre-built/linux/images/zynqmp_fsbl.elf
   ```
   ```sh
   tar xf xilinx-zcu102-v2023.2-10140544.bsp -C firmware-2023.2 --strip-component=4 xilinx-zcu102-2023.2/pre-built/linux/images/system.bit
   ```
1. 上記、pmufw.elf, zynqmp_fsbl.elf, system.bitファイルを、EMLinuxのディレクトリにコピーしてください。
   ```sh
   cd /home/iotsudo/petalinux-bsp/firmware-2023.2
   ```
   ```sh
   cp * /home/iotsudo/EMLinux_3.1-202404/source/emlinux-3.1-202404/repos/meta-emlinux-ext-mpsoc/recipes-bsp/bootbin/files
   ```
1. 以下の記事を参考に、EMLinuxをビルドするためのコンテナを起動してください。
   - [EMLinux 3.0 (202403) をQEMUでエミュレートしたRaspberry Pi 3で動かしてみた](https://qiita.com/fukunagt/items/eed9fb418e8dd84a5af6)
1. シンボリックリンクを作成してください。
   ```sh
   ln -sf ../repos/meta-emlinux-ext-mpsoc/scripts/add-layer-emlinux-ext-mpsoc setup-hooks/30-add-layer-emlinux-ext-mpsoc
   ```
1. ビルドに必要な環境変数を設定してください。
   ```sh
   source setup-emlinux build
   ```
1. conf/local.confファイルに以下を追記してください。
   ```sh
   vi conf/local.conf
   ```
   ```
   MACHINE = "zcu102-zynqmp"
   FSBL_FILE ="zynqmp_fsbl.elf"
   PMU_FILE = "pmufw.elf"
   BITSTREAM_FILE = "system.bit"
   IMAGE_PREINSTALL:append = " \
       connman \
   "
   ```
1. ビルドを実行してください。
   ```sh
   bitbake emlinux-image-base
   ```
1. ビルド完了後、exitコマンドでコンテナを終了してください。

# EMLinuxの起動
1. EMLinuxのビルド完了後、以下のディレクトリに移動してください。
   ```sh
   cd /home/iotsudo/EMLinux_3.1-202404/source/emlinux-3.1-202404/build/tmp/deploy/images/
   ```
1. zcu102-zynqmpをコピーしてください。
   ```sh
   cp -a zcu102-zynqmp /home/iotsudo/github/petalinux-emlinux/build/tmp/deploy/images
   ```
1. cd
   ```sh
   cd /home/iotsudo/github/petalinux-emlinux/build/tmp/deploy/images/zcu102-zynqmp
   ```
1. wicファイルをリネームし、ファイルサイズが2の乗数 (e.g., 1G) になるように変更してください。
   ```sh
   cp emlinux-image-base-emlinux-bookworm-zcu102-zynqmp.wic petalinux-image-minimal-zcu102-zynqmp.wic.qemu-sd
   ```
   ```sh
   qemu-img resize petalinux-image-minimal-zcu102-zynqmp.wic.qemu-sd 1G
   ```
1. devicetreeディレクトリを作成してください。
   ```sh
   mkdir devicetree
   ```
1. devicetreeディレクトリに移動し、シンボリックリンクを作成してください。
   ```sh
   cd devicetree
   ```
   ```sh
   ln -s ../zynqmp-zcu102-rev1.0.dtb system-top.dtb
   ```
1. 1つ上の階層のディレクトリに戻り、qemu-hw-devicetrees/multiarchディレクトリを作成してください。
   ```sh
   cd ../
   ```
   ```sh
   mkdir -p qemu-hw-devicetrees/multiarch
   ```
1. zcu102-zynqmp_orgから、zcu102-arm.dtbとzynqmp-pmu.dtbを、qemu-hw-devicetrees/multiarchにコピーしてください。
   ```sh
   cp ../zcu102-zynqmp_org/qemu-hw-devicetrees/multiarch/zcu102-arm.dtb qemu-hw-devicetrees/multiarch
   ```
   ```sh
   cp ../zcu102-zynqmp_org/qemu-hw-devicetrees/multiarch/zynqmp-pmu.dtb qemu-hw-devicetrees/multiarch
   ```
1. 以下のファイルをコピーしてください。
   ```sh
   cp ../zcu102-zynqmp_org/arm-trusted-firmware.elf .
   ```
   ```sh
   cp ../zcu102-zynqmp_org/petalinux-image-minimal-zcu102-zynqmp.qemuboot.conf .
   ```
   ```sh
   cp ../zcu102-zynqmp_org/pmu-firmware-zcu102-zynqmp.elf .
   ```
   ```sh
   cp ../zcu102-zynqmp_org/system.dtb .
   ```
   ```sh
   cp ../zcu102-zynqmp_org/u-boot.elf .
   ```
1. treeコマンドの実行結果が以下のようになることを確認してください。
   ```
   $ tree
   .
   ├── arm-trusted-firmware.elf
   ├── devicetree
   │   └── system-top.dtb -> ../zynqmp-zcu102-rev1.0.dtb
   ├── emlinux-image-base-emlinux-bookworm-zcu102-zynqmp.dpkg_status
   ├── emlinux-image-base-emlinux-bookworm-zcu102-zynqmp-initrd.img
   ├── emlinux-image-base-emlinux-bookworm-zcu102-zynqmp.manifest
   ├── emlinux-image-base-emlinux-bookworm-zcu102-zynqmp.tar.gz
   ├── emlinux-image-base-emlinux-bookworm-zcu102-zynqmp.wic
   ├── emlinux-image-base-emlinux-bookworm-zcu102-zynqmp.wic.bmap
   ├── emlinux-image-base-emlinux-bookworm-zcu102-zynqmp.wic.gz
   ├── files.modified_timestamps
   ├── Image
   ├── petalinux-image-minimal-zcu102-zynqmp.qemuboot.conf
   ├── petalinux-image-minimal-zcu102-zynqmp.wic.qemu-sd
   ├── pmu-firmware-zcu102-zynqmp.elf
   ├── pmu-rom.elf
   ├── qemu-hw-devicetrees
   │   └── multiarch
   │       ├── zcu102-arm.dtb
   │       └── zynqmp-pmu.dtb
   ├── system.dtb
   ├── u-boot.elf
   └── zynqmp-zcu102-rev1.0.dtb
   ```
1. /home/iotsudo/github/petalinux-emlinux/に移動し、環境変数を設定してください。
   ```sh
   cd /home/iotsudo/github/petalinux-emlinux/
   ```
   ```sh
   source setupsdk
   ```
1. 以下のコマンドを実行してください。
   ```sh
   MACHINE=zcu102-zynqmp runqemu petalinux-image-minimal nographic
   ```
1. ログインプロンプトが出てきたら、ユーザ名root、パスワードrootでログインしてください。
   ```
   (snip)
   Starting kernel ...
   
   [    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
   [    0.000000] Linux version 6.1.80-cip16 (isar-users@googlegroups.com) (aarch64-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #1 SMP Thu, 01 Jan 1970 01:00:00 +0000
   [    0.000000] Machine model: ZynqMP ZCU102 Rev1.0
   (snip)
   EMLinux 3.1 EMLinux3 ttyPS0
   EMLinux3 login: root
   Password: 
   Linux EMLinux3 6.1.80-cip16 #1 SMP Thu, 01 Jan 1970 01:00:00 +0000 aarch64
   (snip)
   ```
# さいごに
~~まだ、残項目はあるものの、EMLinux 3.1 (202404) をQEMUでエミュレートしたZCU102で動かしてみました。~~
2024/06/19 訂正
EMLinux 3.1 (202404) をQEMUでエミュレートしたZCU102で動かすことに成功しました。IPアドレスも付与されるようになったので、いろいろ試してみようと思います。

## 残項目
### ~~IPアドレスが有効にならない~~
```
root@EMLinux3:~# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
3: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN group default qlen 10
    link/can 
4: end0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 1a:60:57:80:25:cf brd ff:ff:ff:ff:ff:ff
```

### 2024/06/19 追記
ホスト OS を再起動したところ、IP アドレスが付与されない事象が解決されました。他の仮想マシンを起動したときのごみが残っていたのだろうか…
```
root@EMLinux3:~# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
3: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN group default qlen 10
    link/can 
4: end0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 86:4c:72:ac:6d:f2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.16/24 metric 10 brd 192.168.122.255 scope global dynamic end0
       valid_lft 3406sec preferred_lft 3406sec
    inet6 fe80::844c:72ff:feac:6df2/64 scope link 
       valid_lft forever preferred_lft forever
```