Petalinux2018.3でPLとDevice Treeを動的に変更する のバックアップ差分(No.7)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

* 再起動せずにプログラマブルロジック及び Device Tree を更新する [#m94ce4dd]

Device Tree Overlay を使うと、再起動なしに Device Tree を更新できる
- https://okchan08.hateblo.jp/entry/2019/02/05/000000

FPGA Region という機能を使うと再起動なしにプログラマブルロジックを更新できる
- https://okchan08.hateblo.jp/entry/zynq-fpga_region

作業手順としては、
- [[電気回路/zynq/Petalinux2018.3環境を整える]]
- [[電気回路/zynq/Petalinux2018.3によるzynq-7000ブート用SDカード作成]]

の続き。

** 目次 [#p702fcfb]

#contents


* Device Tree Overlay [#v5d9c94b]

[[電気回路/zynq/Device Tree Overlay]] ではまだできなかった、
configfs を用いた方法が使えるようになっているみたいだ。

** カーネル設定 [#j404620e]

[[電気回路/zynq/Petalinux2018.3によるzynq-7000ブート用SDカード作成#t9b088e3]] の続きから、

 LANG:console
 $ cd ~/petalinux/zturn-v2018.3/kernel-source
 $ make ARCH=arm menuconfig
  Device Tree and Open Firmware support  ---> 
      [*]   Device Tree overlays
      [*]   Device Tree Overlay ConfigFS interface

Petalinux からカーネルソースを取ってきた場合には
これらは元々チェックが付いていた。

** やりかた [#j424db65]

ブート直後、すでに /sys/kernel/config が使えるようになっていた。

 LANG:console
 $ mount | grep configfs
  configfs on /sys/kernel/config type configfs (rw,relatime)

Device Tree Overlay の手順は:
- 追加したい部分を記述した some-name.dts を作成する
- dtc でコンパイルして .dtb ファイルを作る
- /sys/kernel/config/device-tree/overlays/some_name といったフォルダを作る
- .dtb ファイルを /sys/kernel/config/device-tree/overlays/some_name/dtbo へ書き込む
- 元に戻すには /sys/kernel/config/device-tree/overlays/some_name フォルダを rmdir する

 LANG:console
 $ cat << EOT > some-name.dts # dts fragment を記述したソースファイル
 > /dts-v1/;
 > /plugin/;
 > / {
 >   fragment@0 {
 >     target-path = "/brabra";
 >     #address-cells = <1>;
 >     #size-cells = <1>;
 >     __overlay__ {
 >       #address-cells = <1>;
 >       #size-cells = <1>;
 >       property1;
 >       property2 = "value";
 >       property3 = <1 2 3>;
 >       some : some@1234 {
 >         property1;
 >         property2 = "value";
 >         property3 = <1 2 3>;
 >       }
 >     };
 >   };
 > };
 > EOT
 $ dtc -O dtb some-name.dts -o some-name.dtbo # .dts を .dtbo に変換
 $ sudo mkdir -p /sys/kernel/config/device-tree/overlays/some_name # 書き込み先を作る
 $ sudo cp some-name.dtbo /sys/kernel/config/device-tree/overlays/some_name/dtbo # これで反映される
 $ # 使う
 $ sudo rmdir /sys/kernel/config/device-tree/overlays/some_name # 取り消す

** Device Tree Ovelay 用スクリプト [#b87fd39f]

dts ファイルを直接登録できるスクリプト

file-name.dtso を folder-name とうフォルダに登録するための使い方は以下の通り。

 LANG:console
 $ dto                             # 使い方を表示
  USAGE: sudo dto folder-name [file-name.dts]
 $ dto folder-name file-name.dtso  # 登録
 $ dto folder-name                 # 解除

dts ファイルを dtb ファイルに変換しておく必要がないため、
いろいろ試すのにはとても便利。

/usr/local/dto

#gist(osamutake/cf9ec69d9cc5e8d552a57fe4646816ee)

* FPGA Region によるプログラマブルロジック書き換え [#qc05dbec]

** カーネル設定 [#f82da98e]

[[電気回路/zynq/Petalinux2018.3によるzynq-7000ブート用SDカード作成#t9b088e3]] の続きから、

 LANG:console
 $ cd ~/petalinux/zturn-v2018.3/kernel-source
 $ make ARCH=arm menuconfig
  Device Drivers  ---> 
      FPGA Configuration Framework  --->    
          <*> FPGA Region
          <*> Xilinx Zynq FPGA
          <*> FPGA Bridge Framework
          <*> Xilinx LogiCORE PR Decoupler

Petalinux からカーネルソースを取ってきた場合には
これらは元々チェックが付いているようだ。



** .bin ファイルを生成する [#rd04c9cc]

*** fpga-bit-to-bin.py で .bit ファイルを .bin ファイルに変換する [#s2cc5137]

https://github.com/topic-embedded-products/meta-topic/blob/master/recipes-bsp/fpga/fpga-bit-to-bin/fpga-bit-to-bin.py

を使うと、bit ファイルを bin ファイルに変換できる。

 LANG:console
 $ cd
 $ sudo curl https://raw.githubusercontent.com/topic-embedded-products/meta-topic/master/recipes-bsp/fpga/fpga-bit-to-bin/fpga-bit-to-bin.py -o /usr/local/bin/fpga-bit-to-bin.py
 $ sudo chown root:root /usr/local/bin/fpga-bit-to-bin.py
 $ sudo chmod a+x /usr/local/bin/fpga-bit-to-bin.py
 $ sudo mkdir -p /lib/firmware/bit.bin
 $ sudo fpga-bit-to-bin.py --flip /boot/system.bit /lib/firmware/bit.bin/system.bit.bin

ただ、この変換にはかなり時間がかかるみたい。

fpga へ書き込むための bin ファイルはビッグエンディアンになっていなければならなくて、
リトルエンディアンの bit ファイルからエンディアンの変換を行うのが python 
とても時間がかかる。

*** vivado で .bin ファイルを作る [#o589f9e5]

vivado の [Flow Navigator] の [Generate Bitstream] の上で右クリックして、
[Bitstream Setting...] を選ぶと、bit ファイルと同時に bin ファイルも生成してくれるようになる。

&ref(bin_file-creation.png,,50%);

ところが、こうしてできる .bin ファイルはリトルエンディアン形式なので、
書き込む前にはやはりビッグエンディアンに直さなければならない。

 LANG:console
 $ od -tx1 ~/design_1_wrapper.bin | head -5
  0000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  *
  0000040 00 00 00 bb 11 22 00 44 ff ff ff ff ff ff ff ff
  0000060 aa 99 55 66 20 00 00 00 30 02 20 01 00 00 00 00
  0000100 30 02 00 01 00 00 00 00 30 00 80 01 00 00 00 00
 $ od -tx1 /lib/firmware/bit.bin/system.bit.bin | head -5
  0000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  *
  0000040 bb 00 00 00 44 00 22 11 ff ff ff ff ff ff ff ff
  0000060 66 55 99 aa 00 00 00 20 01 20 02 30 00 00 00 00
  0000100 01 00 02 30 00 00 00 00 01 80 00 30 00 00 00 00

*** エンディアンネス変更プログラム [#zb2c4ddb]

 LANG:console
 $ flip32 design_1_wrapper.bin_LE > design_1_wrapper.bin_BE

のようにして使えるプログラムを C で書いた。

これなら短時間でバイトオーダーをひっくり返せる。

/usr/local/bin/flip32
 LANG:c
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 int main(int argc, const char *argv[])
 {
     if (argc != 2) {
         fprintf(stderr, "USAGE: flip32 input_file\n");
         return -1;
     }
    
     int fd;
     FILE *fp;
     struct stat stbuf;
     long file_size, i;
     u_int32_t *buffer;
     
     fd = open(argv[1], O_RDONLY);
     if (fd == -1) {
         fprintf(stderr, "Input file not found.\n");
         return -1;
      }
    
     if (fstat(fd, &stbuf) == -1) {
         fprintf(stderr, "fstat failed.\n");
         return -1;
     }
 
     file_size = stbuf.st_size;
     buffer = (u_int32_t*)malloc(file_size);
     if (buffer == NULL) {
         fprintf(stderr, "malloc failed.\n");
         return -1;
     }
    
     if (read(fd, buffer, file_size)!=file_size) {
         fprintf(stderr, "read failed.\n");
         return -1;
     }
    
     close(fd);
    
     for(i=0; i<file_size/4; i++) {
         buffer[i] = __builtin_bswap32(buffer[i]);
     }
    
     fwrite(buffer, 1, file_size, stdout);
 }


** fpga region デバイス [#qd5ca1ee]

 LANG:console
 $ dtc -I dtb -O dts /boot/devicetree.dtb
  /dts-v1/;
  
  / {
          #address-cells = <0x1>;
          #size-cells = <0x1>;
          compatible = "xlnx,zynq-7000";
  
          cpus {
                ...
          };
  
          fpga-full {
                  compatible = "fpga-region";
                  fpga-mgr = <0x3>;
                  #address-cells = <0x1>;
                  #size-cells = <0x1>;
                  ranges;
          };
          ...

のように /fpga-full として定義されている。

** ロジックの書き込み [#mc0ccfe8]

- vivado で作成された design_1_wrap.bin を flip32 に通す
- 結果を /lib/firmware の下に保存する
- device tree の /fpga-full の firmware-name というプロパティに、
/lib/firmware からの相対パスで bin のありかを指定する


 LANG:console
 $ mkdir fpga-region
 $ cd fpga-region/
 $ flip32 design_1_wrap.bin > /lib/firmware/fpga-full/big-endian.bin # /lib/firmware 以下にコピーする
 $ cat << EOT > fpga-region.dtso
 > /dts-v1/;
 > /plugin/;
 > / {
 >     fragment@0 {
 >         target-path = "/fpga-full";
 >         #address-cells = <1>;
 >         #size-cells = <1>;
 >         __overlay__ {
 >             #address-cells = <1>;
 >             #size-cells = <1>;
 >             firmware-name = "fpga-full/big-endian.bin";
 >         };
 >     };
 > };
 > EOT
 $ dto fpga-region fpga-region.dtso

これでできた。




** PL 領域書き換え用のスクリプト [#gb07ac62]

vivado で design_1_wrapper.bit を作成する際に同時に出力させた
リトルエンディアンの design_1_wrapper.bin を指定して、

 LANG:console
 $ fpga-program design_1_wrapper.bin

とすれば、自動でビッグエンディアンに変更してサクッと書き込める。

/usr/local/bin/fpga-program

 LANG:sh
 #!/bin/sh
 
 if [ -z $1 ]; then
   echo "USAGE: fpga-program design_1_wrapper-little_endian.bin"
   exit 0
 fi
 
 flip32 $1 > /lib/firmware/fpga-full/big-endian.bin
 
 cat << EOT > /tmp/fpga-region.dtso
 /dts-v1/;
 /plugin/;
 / {
     fragment@0 {
         target-path = "/fpga-full";
         #address-cells = <1>;
         #size-cells = <1>;
         __overlay__ {
             #address-cells = <1>;
             #size-cells = <1>;
             firmware-name = "fpga-full/big-endian.bin";
         };
     };
 };
 EOT
 
 exec dto fpga-region /tmp/fpga-region.dtso

*** ちょっと危ないところもある [#y3191c3b]

上記の2つのスクリプト、
少し違う書き方をするだけで危ういエラーが出たりする。

 LANG:console
 $ sudo fpga-load design_1_wrapper.bin
  Unable to handle kernel NULL pointer dereference at virtual address 00000008
  pgd = c0004000
  [00000008] *pgd=00000000
  Internal error: Oops - BUG: 5 [#1] PREEMPT SMP ARM
  Modules linked in:
  CPU: 1 PID: 1707 Comm: dtc Not tainted 4.14.0-xilinx-v2018.3 #1
  Hardware name: Xilinx Zynq Platform
  task: ee56d900 task.stack: ee9ea000
  PC is at set_root+0x30/0xb0
  LR is at path_init+0x12c/0x2c4
  pc : [<c01dbd2c>]    lr : [<c01dc1cc>]    psr: 20010013
  sp : ee9ebbc8  ip : 00000014  fp : ee42b000
  r10: ef3c1c60  r9 : ee41f4c4  r8 : c0a55b54
  r7 : 00000001  r6 : 00000041  r5 : 00000000  r4 : ee9ebc68
  r3 : ee9ebbc8  r2 : ee9ebc80  r1 : 00000041  r0 : ee9ebc68
  Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
  Control: 18c5387d  Table: 2e5e004a  DAC: 00000051
  Process dtc (pid: 1707, stack limit = 0xee9ea210)
  Stack: (0xee9ebbc8 to 0xee9ec000)
  bbc0:                   ee9ebc68 ef157010 00000041 c01dc1cc ee9ebc68 ee9ebd04
  ...
  [<c01dbd2c>] (set_root) from [<c01dc1cc>] (path_init+0x12c/0x2c4)
  [<c01dc1cc>] (path_init) from [<c01e046c>] (path_openat+0x1ac/0xc94)
  [<c01e046c>] (path_openat) from [<c01e0f84>] (do_filp_open+0x30/0x78)
  [<c01e0f84>] (do_filp_open) from [<c01d1948>] (file_open_name+0xcc/0xf8)
  [<c01d1948>] (file_open_name) from [<c01d199c>] (filp_open+0x28/0x40)
  [<c01d199c>] (filp_open) from [<c01d8a74>] (kernel_read_file_from_path+0x2c/0x78)
  [<c01d8a74>] (kernel_read_file_from_path) from [<c03bee00>] (_request_firmware+0x2bc/0x55c)
  [<c03bee00>] (_request_firmware) from [<c03bf0dc>] (request_firmware+0x3c/0x54)
  [<c03bf0dc>] (request_firmware) from [<c0511104>] (fpga_mgr_firmware_load+0x3c/0x98)
  [<c0511104>] (fpga_mgr_firmware_load) from [<c05127e4>] (of_fpga_region_notify+0x2fc/0x4d8)
  [<c05127e4>] (of_fpga_region_notify) from [<c01344ec>] (notifier_call_chain+0x40/0x64)
  [<c01344ec>] (notifier_call_chain) from [<c01348b0>] (__blocking_notifier_call_chain+0x40/0x58)
  [<c01348b0>] (__blocking_notifier_call_chain) from [<c01348dc>] (blocking_notifier_call_chain+0x14/0x1c)
  [<c01348dc>] (blocking_notifier_call_chain) from [<c0501a30>] (of_overlay_notify+0x48/0x78)
  [<c0501a30>] (of_overlay_notify) from [<c0501e94>] (of_overlay_create+0x220/0x4dc)
  [<c0501e94>] (of_overlay_create) from [<c04fc728>] (create_overlay+0x8c/0xd0)
  [<c04fc728>] (create_overlay) from [<c04fc7c4>] (cfs_overlay_item_dtbo_write+0x58/0x88)
  [<c04fc7c4>] (cfs_overlay_item_dtbo_write) from [<c022c414>] (configfs_release_bin_file+0x50/0x84)
  [<c022c414>] (configfs_release_bin_file) from [<c01d4b68>] (__fput+0xd8/0x1ac)
  [<c01d4b68>] (__fput) from [<c0132124>] (task_work_run+0x9c/0xac)
  [<c0132124>] (task_work_run) from [<c011d36c>] (do_exit+0x3f8/0x8b4)
  [<c011d36c>] (do_exit) from [<c011e3f8>] (do_group_exit+0x58/0xc0)
  [<c011e3f8>] (do_group_exit) from [<c011e470>] (__wake_up_parent+0x0/0x18)
  Code: e3120040 0a000015 e2802018 e285c014 (e595e008)
  ---[ end trace 296e080d10983c60 ]---
  Fixing recursive fault but reboot is needed!
  ...

エラーはエラーでも Kernel Panic 的な。

システムの再起動が必要になっちゃう。

えー?!

現時点ではなんだかよくわからない。
* system.dtb にシンボルを埋め込む [#fc20918e]

https://qiita.com/ikwzm/items/03d518b7c46d1ee49943#device-tree-compilerdtc-%E3%82%92%E7%9B%B4%E6%8E%A5%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88

を参考にすると、dtb にシンボルを埋め込むには dtc 1.4.2 以上でなければならないらしい。
ところが petalinux のツールチェインに含まれる dtc は 1.4.2 なのでシンボルに対応していない。
ちなみに母艦の Ubuntu 16.04LTS の dtc は 14.0 だった。

そこで、zynq 側に入れた Ubuntu 18.04LTS の dtc 1.4.5 を使ってコンパイルする。

system.dtb のソースファイルは
components/plnx_workspace/device-tree/device-tree/system-top.dts
にあるのだけれど、これは C のプリプロセッサを通し #include 
を処理しないとそのままでは dtc でコンパイルできない。

そのため、母艦の gcc のプリプロセッサを通して dts を1つにまとめてから
zynq に持っていく。ただ、dtc でのコンパイル時に
components/plnx_workspace/device-tree/device-tree/system-conf.dtsi
を必要とするので、こちらも一緒に zynq に移す必要がある。

https://qiita.com/ikwzm/items/b07af1a861d6f1c0fde2

を参考に、

 LANG:console
 $ which dtc
  /opt/petalinux_2018.3/tools/linux-i386/petalinux/bin/dtc
 $ dtc -v
  Version: DTC 1.4.1
 $ sudo apt-get install -y device-tree-compiler
 $ /usr/bin/dtc -v
  Version: DTC 1.4.0
 $ gcc -E -P -x assembler-with-cpp -I project-spec/meta-user/recipes-bsp/device-tree/files/ components/plnx_workspace/device-tree/device-tree/system-top.dts > images/linux/system.dts
 $ sudo mount /mnt/sdcard1/
 $ sudo cp images/linux/system.dts /mnt/sdcard1/
 $ sudo cp components/plnx_workspace/device-tree/device-tree/system-conf.dtsi /mnt/sdcard1/
 $ sudo umount /mnt/sdcard1/

としておいて、zynq 側で

 LANG:console
 $ dtc -v
  Version: DTC 1.4.5
 $ sudo dtc -I dts -O dtb -@ -i /boot /boot/system.dts -o /boot/devicetree.dtb
  /boot/devicetree.dtb: Warning (unit_address_vs_reg): Node /memory has a reg or ranges property, but no unit name
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00000000 unit name should not have leading "0x"
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00000000 unit name should not have leading 0s
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00500000 unit name should not have leading "0x"
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00500000 unit name should not have leading 0s
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00520000 unit name should not have leading "0x"
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00520000 unit name should not have leading 0s
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00fa0000 unit name should not have leading "0x"
  /boot/devicetree.dtb: Warning (unit_address_format): Node /amba/spi@e000d000/flash@0/partition@0x00fa0000 unit name should not have leading 0s
 $ dtc -O dts /boot/devicetree.dtb
  ...
         __symbols__ {
                  cpu0 = "/cpus/cpu@0";
                  cpu1 = "/cpus/cpu@1";
                  fpga_full = "/fpga-full";
                  regulator_vccpint = "/fixedregulator";
                  amba = "/amba";
                  adc = "/amba/adc@f8007100";
                  ...
  ...

警告は出るけれど何とかコンパイルできた。
起動も問題ないみたい。

* コメント・質問 [#ved01a20]

#article_kcaptcha


Counter: 2149 (from 2010/06/03), today: 1, yesterday: 0