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

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]
[[電気回路/zynq]]

* 再起動せずにプログラマブルロジック及び 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 する

https://okchan08.hateblo.jp/entry/zynq-device_tree_overlay#ConfigFS%E3%81%AE%E6%BA%96%E5%82%99
となる。

などを参考にすればいいはず。
dtbo へ書き込んだ内容を反映するために status というファイルに 1 を入れる、とか、
反映した内容を取り消すために 0 を入れるとか、そういった情報もあるようだけれど、
ここでの環境では上記が正しいようだ。

下記の fpga region も device tree overlay 
を用いた設定方法なので、以下では fpga region を試す。
 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 ファイルを dtb に直すことなく直接指定して登録できるスクリプトを書いた。

dto : https://github.com/osamutake/zynq-utils/tree/master/src/dto

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 ファイルに変換するのも手間になるので、
いろいろ試すのには直接 dts を指定できるのはとても便利なはず。


* 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 からカーネルソースを取ってきた場合には
これらは元々チェックが付いているようだ。



** .bit ファイルを .bin ファイルに変換する [#rd04c9cc]
** .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 で書いた。

flip32 : https://github.com/osamutake/zynq-utils/tree/master/src/flip32

こちらは C で機械語に相当する関数を呼び出して書いてるおかげもあり
かなり短時間でバイトオーダーをひっくり返せる。

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

petalinux が標準で作成する dtb に、すでに

 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/
 $ cat << EOT > fpga-region.dts
 > // Device Tree File for FPGA Region:   fpga_reg.dts
 $ flip32 design_1_wrap.bin > /lib/firmware/fpga-full/big-endian.bin # /lib/firmware 以下にコピーする
 $ cat << EOT > fpga-region.dtso
 > /dts-v1/;
 > /plugin/;
 > / {
 >     fragment@1 {
 >     fragment@0 {
 >         target-path = "/fpga-full";
 >         #address-cells = <1>;
 >         #size-cells = <1>;
 >         __overlay__ {
 >             #address-cells = <1>;
 >             #size-cells = <1>;
 >             firmware-name = "bit.bin/system.bit.bin";
 >             firmware-name = "fpga-full/big-endian.bin";
 >         };
 >     };
 > };
 > EOT
 $ dtc -I dts -O dtb fpga-region.dts -o fpga-region.dtbo
 $ sudo mkdir -p /sys/kernel/config/device-tree/overlays/fpga-region
 $ cat /sys/kernel/config/device-tree/overlays/fpga-region/status
  unapplied
 $ sudo cp fpga-region.dtbo /sys/kernel/config/device-tree/overlays/fpga-region/dtbo
 $ cat /sys/kernel/config/device-tree/overlays/fpga-region/status
  applied
 $ dto fpga-region fpga-region.dtso

これでできた。
これで書き込めた。

標準で /fpga-full というラベルで fpga region のデバイスが宣言されているので、
そこをめがけて device tree ovelay すればいいらしい。
** PL 領域書き換え用のスクリプト [#gb07ac62]

status に 1 を書き込む必要はなく、dtbo への書き込みだけでいい。
vivado で design_1_wrapper.bit を作成する際に同時に出力させた
「リトルエンディアンの design_1_wrapper.bin」 を指定して、

ただ、もう一度 dtbo へ書き込んでも DONE の LED に変化がないので、
内容を更新できているのかどうかよく分からない。
 LANG:console
 $ fpga-program design_1_wrapper.bin

とすれば、自動でビッグエンディアンに変更してサクッと書き込めるようスクリプトを作成した。

fpga-program : https://github.com/osamutake/zynq-utils/tree/master/src/fpga-program


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

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

dtso への書き込みをリダイレクトではなく -o で指定しただけでエラーになったり、
ほんとよく分からない。

 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";
                  ...
  ...

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


作業履歴へ戻る → [[電気回路/zynq]]

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

#article_kcaptcha


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