Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime)を動かす(2.8ビルド編)







# はじめに


筆者は Ultra96/Ultra96-V2(ZynqMP) 向けに Debian GNU/Linux を提供しています[1]。また、XRT(Xilinx Runtime) はXilinx社が提供する開発環境(Vitis)で開発したプログラムをプラットフォームで動かすための環境です[2]。

本来なら MPSoC Edge Device 用の [XRT] は Xilinx が提供する Linux 環境(Petalinux) でしか動きませんが、XRT を Ultra96/Ultra96-V2 向け Debian GNU/Linux で動かすための Debian  Package のビルド方法を以下の記事で紹介しました。



  * [『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(ビルド編)』@Qiita]



上の記事は XRT のバージョンは2.6.0でした。 この記事はその続編で、 XRTの 2.8.0 を Ultra96/Ultra96-V2 向け Debian GNU/Linux または Ubuntu 20.04 用にビルドする手順について説明します。




## 注意


  __この記事で紹介している Debian Package は Xilinx 社の公式なものではありません。__  


# XRT Debian Package の提供


XRT の Debian Package をビルドするためにはビルド環境を整えなければならず、とても面倒です。そこでビルド済みの Debian Package を用意しています。自分でビルドするのが面倒なかたはこちらをお使いください。


## Debian 10 用


* リポジトリ: https://github.com/ikwzm/ZynqMP-FPGA-XRT
* ブランチ名: 2020.2_EDGE_1\_Debian_10
* パッケージファイル名: xrt_202020.2.8.1_Edge_Debian_10-arm64.deb


```console
fpga@ubuntu-fpga:~/work$ git clone --depth 1 --branch 2020.2_EDGE_1_Debian_10 https://github.com/ikwzm/ZynqMP-FPGA-XRT.git
fpga@ubuntu-fpga:~/work$ sudo apt install ./ZynqMP-FPGA-XRT/xrt_202020.2.8.1_Edge_Debian_10-arm64.deb
```



## Ubuntu 20.04 用


* リポジトリ: https://github.com/ikwzm/ZynqMP-FPGA-XRT
* ブランチ名: 2020.2_EDGE_1\_Ubuntu_20.04
* パッケージファイル名: xrt_202020.2.8.1_Edge_Ubuntu_20.04-arm64.deb


```console
fpga@ubuntu-fpga:~/work$ git clone --depth 1 --branch 2020.2_EDGE_1_Ubuntu_20.04 https://github.com/ikwzm/ZynqMP-FPGA-XRT.git
fpga@ubuntu-fpga:~/work$ sudo apt install ./ZynqMP-FPGA-XRT/xrt_202020.2.8.1_Edge_Ubuntu_20.04-arm64.deb
```





# XRT のビルド



## ビルド環境


XRT を ZynqMP-FPGA-Linux 向けにビルドするのは少し面倒です。XRT のビルドには Ubuntu や CentOS などの Linux ディストリビューションが必要です。ビルドには色々な開発ツールがインストールされていなければなりません。さらに Debian Package を作るためか、PC をホストにして ARM64 用にクロスコンパイルするのがとても面倒です。

そこで、 Ultra96-V2 に Debian 10 または Ubuntu 18.04 を動かして、その上でセルフビルドします。Ultra96-V2 用の Debian 10 および Ubuntu 18.04 は以下の URL で公開しています。

* https://github.com/ikwzm/ZynqMP-FPGA-Linux 
* https://github.com/ikwzm/ZynqMP-FPGA-Ubuntu20.04-Ultra96




## XRT のダウンロード


以下の URL より XRT のソースコードをダウンロードします。ブランチは 2020.2_EDGE です。

 

* リポジトリ名: https://github.com/ikwzm/XRT
* ブランチ名: 2020.2_EDGE



このリポジトリは、 Xilinx 社が github に公開している https://github.com/Xilinx/XRT を fork して各種修正を加えたものです。修正内容は次章で説明します。


```console
fpga@debian-fpga:~/work$ git clone --depth 1 --branch 2020.2_EDGE https://github.com/Xilinx/XRT
Cloning into 'XRT'...
remote: Enumerating objects: 2142, done.
remote: Counting objects: 100% (2142/2142), done.
remote: Compressing objects: 100% (1885/1885), done.
remote: Total 2142 (delta 653), reused 626 (delta 220), pack-reused 0
Receiving objects: 100% (2142/2142), 20.80 MiB | 1.22 MiB/s, done.
Resolving deltas: 100% (653/653), done.
Checking out files: 100% (1958/1958), done.
```



## ビルドに必要な Debian Package をインストール


ビルドに必要なパッケージをインストールします。幸い XRT には、ビルドに必要なパッケージをインストールするスクリプトが用意されています。

./src/runtime_src/tools/scripts/xrtdeps.sh を super user 権限で実行すると、apt プログラムによって足りない Debian Package がインストールされます。


```console
fpga@debian-fpga:~/work/XRT$ sudo ./src/runtime_src/tools/scripts/xrtdeps.sh
Installing packages...
Reading package lists... Done
Building dependency tree
Reading state information... Done
	:
(中略)
	:
The following packages were automatically installed and are no longer required:
  libgl2ps1.4 libibverbs1 liblept5 libnetcdf-c++4 libnl-route-3-200
  libopencv-flann-dev libopencv-flann3.2 libopencv-ml-dev libopencv-ml3.2
  libopencv-photo-dev libopencv-photo3.2 libopencv-shape-dev
  libopencv-shape3.2 libopencv-ts-dev libopencv-video-dev libopencv-video3.2
  libtcl8.6 libtesseract4 libtk8.6 libxss1
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 26 not upgraded.
```





## ビルド


build ディレクトリに移動して、そこにある build.sh に "-edge" オプションをつけて実行することで、ビルドが開始されます。Ultra96/Ultra96-V2 だとけっこう時間がかかります。私の環境では１時間30分ほどかかりました。


```console
fpga@debian-fpga:~/work/XRT$ cd build/
fpga@ubuntu-fpga:~/work/XRT/build$ ./build.sh -edge
env XRT_EDGE_BUILD=yes cmake -DRDI_CCACHE=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../src
-- The C compiler identification is GNU 8.3.0
-- The CXX compiler identification is GNU 8.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Host system processor is aarch64
-- Target system processor is aarch64
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29")
-- Checking for module 'libdrm'
--   Found libdrm, version 2.4.97
-- Looking for DRM - found at /usr 2.4.97
-- Checking for module 'OpenCL'
--   Found OpenCL, version 2.2
-- Looking for OPENCL - found at /usr 2.2 /usr/include
	:
(後略)
	:
real    1m28.030s
user    1m8.790s
sys     0m15.279s
fpga@debian-fpga:~/work/XRT/build$ 
```


ビルドが終了すると、build/Edge ディレクトリの下に Debian Package が出来ています。


```console
fpga@debian-fpga:~/work/XRT/build$ ls -1 Edge/xrt_*
Edge/xrt_202020.2.8.1_Edge_Debian_10-arm64.deb
Edge/xrt_202020.2.8.1_Edge_Debian_10-arm64.tar.gz
```


このうち Ultra96/Ultra96-V2 に必要な Debian Package は、Edge/xrt_202020.2.8.1_Edge_Debian_10-arm64.deb です。


# XRT の変更内容


この章では、オリジナルの XRT(https://github.com/Xilinx/XRT ブランチ2020.2) に対して、私が独自に変更した点について説明します。


## XRT_EDGE_BUILD を追加


オリジナルではホストプロセッサとターゲットプロセッサが同じ場合に XRT_NATIVE_BUILD という変数が "yes" にセットされます。 そして、XRT_NATIVE_BUILD が "yes" の時(ホストプロセッサとターゲットプロセッサが同じ時)に src/runtime_src/core/pcie が、"no" の時(ホストプロセッサとターゲットプロセッサが異なる時)に src/runtime_src/core/edge がビルドされるように src/runtime_src/core/CMakeLists.txt が定義されています。


```Makefile:src/runtime_src/core/CMakeLists.txt
include_directories(
  ${CMAKE_CURRENT_SOURCE_DIR}
  )
add_subdirectory(include)
add_subdirectory(common)
 if (${XRT_NATIVE_BUILD} STREQUAL "yes")
   add_subdirectory(pcie)
   add_subdirectory(tools)
 else()
   add_subdirectory(edge)
 endif()
```




また、XRT_NATIVE_BUILD が "yes" の時(ホストプロセッサとターゲットプロセッサが同じ時)にインクルードされる src/CMake/nativeLnx.cmake には、次のようにホスト用のドライバをビルド＆インストールするようになっています。 


```Makefile:src/CMake/nativeLnx.cmakext
	:
	(前略)
	:
include (CMake/dkms.cmake)
include (CMake/dkms-aws.cmake)
include (CMake/dkms-azure.cmake)
include (CMake/dkms-container.cmake)
	:
	(後略)
```




 Ultra96-V2 に Ubuntu 18.04 を動かしてその上でセルフビルドする場合は、ホストプロセッサとターゲットプロセッサが同じ arm64 になります。このままだと、edge 用のではなく pcie 用にビルドされてしまいます。



そこで、次のように src/CMakfile.txt に XRT_EDGE_BUILD 変数を追加します。


```Makefile:src/CMakeLists.txt
	:
	(前略)
	:	
set(XRT_EDGE_BUILD "no")
if (XRT_NATIVE_BUILD STREQUAL "no")
  set(XRT_EDGE_BUILD "no")
endif()
if (DEFINED ENV{XRT_EDGE_BUILD})
  set(XRT_EDGE_BUILD $ENV{XRT_EDGE_BUILD})
endif():
	:
	(後略)
```




そして XRT_EDGE_BUILD が "yes" の場合は edge 用のビルドを行うように、それぞれのファイルを変更します。


```Makefile:src/runtime_src/core/CMakeLists.txt
include_directories(
  ${CMAKE_CURRENT_SOURCE_DIR}
  )
add_subdirectory(include)
 if (${XRT_EDGE_BUILD} STREQUAL "yes")
   add_subdirectory(common)
   add_subdirectory(edge)
   add_subdirectory(tools)
 else()
   add_subdirectory(common)
   add_subdirectory(pcie)
   add_subdirectory(tools)
 endif()

```


 




```Makefile:src/CMake/nativeLnx.cmakext
	:
	(前略)
	:
if (${XRT_EDGE_BUILD} STREQUAL "yes")
  include (CMake/dkms-edge.cmake)
else()
  include (CMake/dkms.cmake)
  include (CMake/dkms-aws.cmake)
  include (CMake/dkms-azure.cmake)
  include (CMake/dkms-container.cmake)
endif()
	:
	(後略)
```


また、XRT_NATIVE_BUILD が "yes" の時(ホストプロセッサとターゲットプロセッサが同じ時)、コンパイルのオプションに "-Wall" と -"Werror" が追加されるような設定が src/runtime_src/CMakeLists.txt にあります。


```Makefile:src/runtime_src/CMakeLists.txt
	:
	(前略)
	:
# TODO CL_TARGET_OPENCL_VERSION is not defined..
if (${XRT_NATIVE_BUILD} STREQUAL "yes")
  add_compile_options("-Wall" "-Werror")
endif()
	:
	(後略)
```




"-Werror" オプションがあると src/runtime_src/core/edge 以下のビルド時にエラーが出てコンパイルに失敗します。そこで XRT_EDGE_BUILD が "yes" の時はコンパイルオプションに "-Wall" と "-Werror" が追加されないように src/runtime_src/CMakeLists.txt を修正します。


```Makefile:src/runtime_src/CMakeLists.txt
	:
	(前略)
	:
# TODO CL_TARGET_OPENCL_VERSION is not defined..
if (${XRT_EDGE_BUILD} STREQUAL "no")
  add_compile_options("-Wall" "-Werror")
endif()	:
	(後略)
```


最後に build/build.sh を修正して、ホストプロセッサが arm64 かつ "-edge" オプションが追加された場合は XRT_EDGE_BUILD が "yes" になるように修正します。


```Shell:build/build.sh
	:
	(前略)
	:
if [[ $CPU == "aarch64" ]] && [[ $edge == 1 ]]; then
  mkdir -p $edge_dir
  cd $edge_dir
  if [[ $nocmake == 0 ]]; then
    echo "env XRT_EDGE_BUILD=yes $CMAKE -DRDI_CCACHE=$ccache -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../src"
    time  env XRT_EDGE_BUILD=yes $CMAKE -DRDI_CCACHE=$ccache -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../src
  fi
  if [[ $nobuild == 0 ]]; then
      echo "make -j $jcore $verbose DESTDIR=$PWD install"
      time make -j $jcore $verbose DESTDIR=$PWD install
      if [[ $noctest == 0 ]]; then
          time ctest --output-on-failure
      fi
      time make package
  fi
  if [[ $docs == 1 ]]; then
      echo "make xrt_docs"
      make xrt_docs
  fi
fi
	:
	(後略)
```





## パッケージファイル名を変更


オリジナルの XRT では、ビルドした Debian Package の名前は xrt_202010.2.8.0_18.04-arm64-xrt.deb になりますが、Debian 10 用またはUbuntu 用のパッケージであることを明示するために、次のようにEdge というキーワードとともに Linux のフレーバー名を追加しておきます。


```diff
diff --git a/src/CMake/cpackLin.cmake b/src/CMake/cpackLin.cmake
index 4f45f97a..9f6eebe4 100644
--- a/src/CMake/cpackLin.cmake
+++ b/src/CMake/cpackLin.cmake
@@ -79,7 +79,7 @@ else ()
   SET (CPACK_GENERATOR "TGZ")
 endif()
 
-SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${XRT_VERSION_RELEASE}.${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CPACK_REL_VER}-${CPACK_ARCH}")
+if (${XRT_EDGE_BUILD} STREQUAL "yes")
+   SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${XRT_VERSION_RELEASE}.${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_Edge_${LINUX_FLAVOR}_${CPACK_REL_VER}-${CPACK_ARCH}")
+else()
+   SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${XRT_VERSION_RELEASE}.${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CPACK_REL_VER}-${CPACK_ARCH}")
+endif()
 
 message("-- ${CMAKE_BUILD_TYPE} ${PACKAGE_KIND} package")
 

```





## dkms-edge 関連の修正


ビルドした Debian パッケージを Debian 10 または Ubuntu 20.04 にインストールした時、dkms(Dynamic Kernel Module Support) というメカニズムによって、XRT の Edge 用の Linux Kernel Module である zocl を、自動的にコンパイルします。しかし、残念ながら、Xilinx オリジナルのままでは上手くいきませんでした。そのためいくつかの修正を加えます。




### postinst と prerm の追加


Xilinx オリジナルのままでは Debian パッケージをインストールする時に自動的に実行されるスクリプト postinst と、アンインストールする時に自動的に実行されるスクリプト prerm が Debian パッケージに含まれません。これらのスクリプトが Debian パッケージに含まれるようにするために、src/CMake/cpackLin.cmake を次のように修正します。


```diff
diff --git a/src/CMake/cpackLin.cmake b/src/CMake/cpackLin.cmake
index 0f38c922..3d32674f 100644
--- a/src/CMake/cpackLin.cmake
+++ b/src/CMake/cpackLin.cmake
@@ -84,6 +84,11 @@ if (${LINUX_FLAVOR} MATCHES "^(Ubuntu|Debian)")
     SET(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_XRT_PACKAGE_DEPENDS})
   endif()
 
+  if (${XRT_EDGE_BUILD} STREQUAL "yes")
+    SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/prerm")
+    SET(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_XRT_PACKAGE_DEPENDS})
+  endif()
+
 elseif (${LINUX_FLAVOR} MATCHES "^(RedHat|CentOS|Amazon|Fedora)")
   execute_process(
     COMMAND uname -m
@@ -140,7 +145,11 @@ else ()
   SET (CPACK_GENERATOR "TGZ")
 endif()

```





### 足りないファイルを追加


さらに Xilinx オリジナルのままでは、dkms に必要なファイルが幾つか含まれません。そこで、src/CMake/dkms-edge.cmake と次のように修正して足りないファイルを追加します。


```diff
diff --git a/src/CMake/dkms-edge.cmake b/src/CMake/dkms-edge.cmake
index 48e4ad1e..83d9d8ec 100644
--- a/src/CMake/dkms-edge.cmake
+++ b/src/CMake/dkms-edge.cmake
@@ -35,6 +35,7 @@ SET (XRT_DKMS_CORE_COMMON_DRV ${XRT_DKMS_CORE_DIR}/common/drv)
 
 SET (XRT_DKMS_DRIVER_SRCS
   zocl/include/sched_exec.h
+  zocl/include/zocl_aie.h
   zocl/include/zocl_bo.h
   zocl/include/zocl_cu.h
   zocl/include/zocl_dma.h
@@ -53,6 +54,7 @@ SET (XRT_DKMS_DRIVER_SRCS
   zocl/LICENSE
   zocl/Makefile
   zocl/sched_exec.c
+  zocl/zocl_aie.c
   zocl/zocl_bo.c
   zocl/zocl_cu.c
   zocl/zocl_dma.c
@@ -86,6 +88,7 @@ SET (XRT_DKMS_COMMON_XRT_DRV
   common/drv/xrt_cu.c
   common/drv/cu_hls.c
   common/drv/cu_plram.c
+  common/drv/fast_adapter.c
   common/drv/xrt_xclbin.c
   common/drv/Makefile
   )

```





### -D\_\_NONE_PETALINUX\_\_ の追加


PetaLinux 環境以外で zocl をコンパイルするためには -D\_\_NONE_PETALINUX\_\_ という C のオプションが必要なようです。このオプションをつけてビルドするように src/CMake/config/dkms-zocl/dkms.conf.in を次のように修正します。


```diff
diff --git a/src/CMake/config/dkms-zocl/dkms.conf.in b/src/CMake/config/dkms-zocl/dkms.conf.in
index c79c23c2..78fd5a90 100644
--- a/src/CMake/config/dkms-zocl/dkms.conf.in
+++ b/src/CMake/config/dkms-zocl/dkms.conf.in
@@ -1,7 +1,7 @@
 PACKAGE_NAME="xrt-zocl"
 PACKAGE_VERSION="@XRT_VERSION_STRING@"
-MAKE[0]="cd driver/zocl; make -j KERNEL_SRC=${kernel_source_dir}; cd ../.."
-CLEAN="cd driver/zocl; make clean KERNEL_SRC=${kernel_source_dir}; cd ../.."
+MAKE[0]="cd driver/zocl; make -j KERNEL_SRC=${kernel_source_dir} cflags_zocl=-D__NONE_PETALINUX__; cd ../.."
+CLEAN="cd driver/zocl; make clean KERNEL_SRC=${kernel_source_dir} cflags_zocl=-D__NONE_PETALINUX__; cd ../.."
 BUILT_MODULE_NAME[0]="zocl"
 BUILT_MODULE_LOCATION[0]="driver/zocl"
 DEST_MODULE_LOCATION[0]="/kernel/extras"

```





## 不要なテストの削除


Debian Package のビルド時に、ビルドしたツールが正常に動作するかテストが行われます。しかし、Xilinx オリジナルのままでは、Edge 用の Debian Package にもかかわらず、PCI-Express 用のツールである xbmgmt と xbutil のテストを試みようとして失敗します。どこで、src/CMake/NativeTests.cmake を次のように修正して不要なテストを行わないようにします。


```diff
diff --git a/src/CMake/nativeTests.cmake b/src/CMake/nativeTests.cmake
index 9f53ad61..25e0d19d 100644
--- a/src/CMake/nativeTests.cmake
+++ b/src/CMake/nativeTests.cmake
@@ -3,13 +3,17 @@
 # XRT_INSTALL_BIN_DIR
 
 enable_testing()
+if (${XRT_EDGE_BUILD} STREQUAL "no")
 add_test(NAME xbmgmt
   COMMAND ${CMAKE_BINARY_DIR}/runtime_src/core/pcie/tools/xbmgmt/xbmgmt scan
   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+endif()
 
+if (${XRT_EDGE_BUILD} STREQUAL "no")
 add_test(NAME xbutil
   COMMAND ${CMAKE_BINARY_DIR}/runtime_src/core/pcie/tools/xbutil/xbutil scan
   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+endif()
 
 add_test(NAME xbutil2
   COMMAND ${CMAKE_BINARY_DIR}/runtime_src/core/tools/xbutil2/xbutil2 --new scan
@@ -19,4 +23,6 @@ add_test(NAME xbmgmt2
   COMMAND ${CMAKE_BINARY_DIR}/runtime_src/core/tools/xbmgmt2/xbmgmt2 --new scan
   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
 
-set_tests_properties(xbutil xbmgmt PROPERTIES ENVIRONMENT INTERNAL_BUILD=1)
+if (${XRT_EDGE_BUILD} STREQUAL "no")
+  set_tests_properties(xbutil xbmgmt PROPERTIES ENVIRONMENT INTERNAL_BUILD=1)
+endif()

```





## zocl ドライバオープン時の修正


Xilinx オリジナルでは、XRT が zocl(XRT Edge 用の Linux Kernel Module) をオープンする際に指定するファイル名を "/dev/dri/renderD128" に固定しています。このままでは、例えば[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で Lima Driverを動かす』]で紹介したように、他の DRM ドライバと共存するのが難しくなります。そこで、zocl をオープンする際、/dev/dri をサーチして "zocl" を探すようにします。

具体的には、src/runtime_src_core/edge/user/shim.cpp に /dev/dri から zocl を探すためのクラス ZYNQ::scanner を定義します。


```diff:files/2020.2-01-xrt.patch
diff --git a/src/runtime_src/core/edge/user/shim.cpp b/src/runtime_src/core/edge/user/shim.cpp
index df0ff366..143e3264 100644
--- a/src/runtime_src/core/edge/user/shim.cpp
+++ b/src/runtime_src/core/edge/user/shim.cpp
@@ -38,6 +38,7 @@
 #include <cassert>
 #include <cstdarg>
 
+#include <dirent.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <unistd.h>
@@ -90,6 +91,98 @@ namespace ZYNQ {
 //initializing static member
 std::map<uint64_t, uint32_t *> shim::mKernelControl;
 
+class scanner {
+private:
+  std::mutex lock;
+  std::vector<std::string> dev_name_list;

+  void rescan_nolock(void)
+  {
+    const std::string dri_path      = "/dev/dri";
+    const std::string render_prefix = "renderD";
+    const std::string drm_name      = "zocl";
+
+    DIR* dp = opendir(dri_path.c_str());
+    if (dp) {
+      struct dirent* entry;
+      drm_version    version;
+      const std::unique_ptr<char[]> path(new char[512]);
+      const std::unique_ptr<char[]> name(new char[128]);
+      const std::unique_ptr<char[]> desc(new char[512]);
+      const std::unique_ptr<char[]> date(new char[128]);
+      std::memset(&version, 0, sizeof(version));
+      version.name     = name.get();
+      version.name_len = 128;
+      version.desc     = desc.get();
+      version.desc_len = 512;
+      version.date     = date.get();
+      version.date_len = 128;
+        
+      while ((entry = readdir(dp))) {
+        int fd;
+        if (std::strncmp(entry->d_name, render_prefix.c_str(), render_prefix.length()) != 0)
+          continue;
+        sprintf(path.get(), "%s/%s", dri_path.c_str(), entry->d_name);
+        if ((fd = open(path.get(), O_RDWR, 0)) < 0)
+          continue;
+        if (ioctl(fd, DRM_IOCTL_VERSION, &version) == 0) {
+          if (std::strncmp(version.name, drm_name.c_str(), drm_name.length()) == 0) {
+            std::string dev_name(path.get());
+            dev_name_list.insert(dev_name_list.begin(), dev_name);
+          }
+        }
+        close(fd);
+      }
+      std::sort(dev_name_list.begin(), dev_name_list.end());
+      closedir(dp);
+    }
+  }
+
+public:
+  static scanner *get()
+  {
+    static scanner scanner;
+    return &scanner;
+  }
+  void rescan(void)
+  {
+    std::lock_guard<std::mutex> l(lock);
+    rescan_nolock();
+  }
+
+  size_t dev_num_total(void)
+  {
+    std::lock_guard<std::mutex> l(lock);
+    return dev_name_list.size();
+  }
+
+  const std::string& dev_name(int index)
+  {
+    static const std::string null;
+    std::lock_guard<std::mutex> l(lock);
+    if (index >= dev_name_list.size())
+      return null;
+    else
+      return dev_name_list[index];
+  }
+
+private:
+  scanner(void) { rescan_nolock();}
+  scanner(const scanner&  s);
+  scanner& operator=(const scanner& s);
+};
+void rescan(void)
+{
+  scanner::get()->rescan();
+}
+size_t dev_num_total(void)
+{
+  return scanner::get()->dev_num_total();
+}
+const std::string& dev_name(int index)
+{
+  return scanner::get()->dev_name(index);
+}
+

```




次に src/runtime_src_core/edge/user/shim.cpp にあるクラス shim のコンストラクタを次のように修正して /dev/dri から該当するデバイスファイルをオープンするようにします。


```diff:files/2020.2-01-xrt.patch
 shim::
 shim(unsigned index, const char *logfileName, xclVerbosityLevel verbosity)
   : mCoreDevice(xrt_core::edge_linux::get_userpf_device(this, index))
@@ -103,9 +196,13 @@ shim(unsigned index, const char *logfileName, xclVerbosityLevel verbosity)
 
   xclLog(XRT_INFO, "XRT", "%s", __func__);
 
-  mKernelFD = open("/dev/dri/renderD128", O_RDWR);
+  const std::string device_name = dev_name(index);
+  if (device_name.empty()) {
+    xclLog(XRT_ERROR, "XRT", "%s: Card [%d] not found", __func__, index);
+  }
+  mKernelFD = open(device_name.c_str(), O_RDWR, 0);
   if (!mKernelFD) {
-    xclLog(XRT_ERROR, "XRT", "%s: Cannot open /dev/dri/renderD128", __func__);
+    xclLog(XRT_ERROR, "XRT", "%s: Cannot open device %s", __func__, device_name.c_str());
   }
   mCmdBOCache = std::make_unique<xrt_core::bo_cache>(this, xrt_core::config::get_cmdbo_cache());
   mDev = zynq_device::get_dev();

```




さらに、src/runtime_src_core/edge/user/shim.cpp にある xclProbe() を次のように修正します。


```diff:files/2020.2-01-xrt.patch
 @@ -1536,28 +1633,7 @@ unsigned
 xclProbe()
 {
   PROBE_CB;
-
-  int fd = open("/dev/dri/renderD128", O_RDWR);
-  if (fd < 0) {
-    return 0;
-  }
-  drm_version version;
-  std::memset(&version, 0, sizeof(version));
-  version.name = new char[128];
-  version.name_len = 128;
-  version.desc = new char[512];
-  version.desc_len = 512;
-  version.date = new char[128];
-  version.date_len = 128;
-
-  int result = ioctl(fd, DRM_IOCTL_VERSION, &version);
-  if (result)
-    return 0;
-
-  result = std::strncmp(version.name, "zocl", 4);
-  close(fd);
-
-  return (result == 0) ? 1 : 0;
+  return (ZYNQ::dev_num_total() > 0);
 }
 #endif

```




最後にソースコード自体に修正を加えたことを示すために、src/CMakeList.txt で丁未されているDebian Package のパッチレベルを0から1に変更します。


```diff:files/2020.2-01-xrt.patch
 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8cb46a32..dca721a9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -70,7 +70,7 @@ SET(XRT_VERSION_MINOR 8)
 if (DEFINED ENV{XRT_VERSION_PATCH})
   SET(XRT_VERSION_PATCH $ENV{XRT_VERSION_PATCH})
 else(DEFINED $ENV{XRT_VERSION_PATCH})
-  SET(XRT_VERSION_PATCH 0)
+  SET(XRT_VERSION_PATCH 1)
 endif(DEFINED ENV{XRT_VERSION_PATCH})
 
 #set(XRT_SOVERSION ${XRT_VERSION_MAJOR}.${XRT_VERSION_MINOR})

```



# 参考


* https://github.com/Xilinx/XRT
* https://github.com/ikwzm/ZynqMP-FPGA-XRT
* https://github.com/ikwzm/ZynqMP-FPGA-Linux
* https://github.com/ikwzm/ZynqMP-FPGA-Ubuntu20.04-Ultra96
* [『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(概要編)』@Qiita]
* [『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(ビルド編)』@Qiita]
* [『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(インストール編)』@Qiita]
* [『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(実践編)』@Qiita]
* [『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(Vitis編)』@Qiita]
* [『UltraZed/Ultra96/Ultra96-V2 向け Debian GNU/Linux (v2020.2版) ブートイメージの提供』@Qiita]
* [『Ultra96/Ultra96-V2 向け Debian GNU/Linux で Lima Driverを動かす』@Qiita]


[1]: https://github.com/ikwzm/ZynqMP-FPGA-Linux "https://github.com/ikwzm/ZynqMP-FPGA-Linux"
[2]: https://github.com/Xilinx/XRT "https://github.com/Xilinx/XRT"
[ZynqMP-FPGA-Linux]: https://github.com/ikwzm/ZynqMP-FPGA-Linux "https://github.com/ikwzm/ZynqMP-FPGA-Linux"
[XRT]: https://github.com/Xilinx/XRT "https://github.com/Xilinx/XRT"
[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(概要編)』@Qiita]: https://qiita.com/ikwzm/items/0d3a8adfe725cd17f932 "『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(概要編)』@Qiita"
[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(ビルド編)』@Qiita]: https://qiita.com/ikwzm/items/d8013ea91125a3fc46aa "『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(ビルド編)』@Qiita"
[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(ビルド編)』]: https://qiita.com/ikwzm/items/d8013ea91125a3fc46aa "『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(ビルド編)』@Qiita"
[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(インストール編)』@Qiita]: https://qiita.com/ikwzm/items/6612eacc4a0d324a0a68 "『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(インストール編)』@Qiita"
[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(実践編)』@Qiita]: https://qiita.com/ikwzm/items/58cfea3f9d0f42840511 "『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(実践編)』@Qiita"
[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(Vitis編)』@Qiita]: https://qiita.com/ikwzm/items/e70d8d0e44fe3784a708 "『Ultra96/Ultra96-V2 向け Debian GNU/Linux で XRT(Xilinx Runtime) を動かす(Vitis編)』@Qiita"
[『UltraZed/Ultra96/Ultra96-V2 向け Debian GNU/Linux (v2020.2版) ブートイメージの提供』@Qiita]: https://qiita.com/ikwzm/items/c7687406e82ab95ac697 "『UltraZed/Ultra96/Ultra96-V2 向け Debian GNU/Linux (v2020.2版) ブートイメージの提供』@Qiita"
[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で Lima Driverを動かす』@Qiita]: https://qiita.com/ikwzm/items/6481729ae63b0ec316e5 "『Ultra96/Ultra96-V2 向け Debian GNU/Linux で Lima Driverを動かす』@Qiita"