Petalinux2018.3でPLとDevice Treeを動的に変更する
再起動せずにプログラマブルロジック及び Device Tree を更新する†
Device Tree Overlay を使うと、再起動なしに Device Tree を更新できる
FPGA Region という機能を使うと再起動なしにプログラマブルロジックを更新できる
作業手順としては、
の続き。
目次†
Device Tree Overlay†
電気回路/zynq/Device Tree Overlay ではまだできなかった、 configfs を用いた方法が使えるようになっているみたいだ。
カーネル設定†
電気回路/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 からカーネルソースを取ってきた場合には これらは元々チェックが付いていた。
やりかた†
ブート直後、すでに /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 する
となる。
dtbo へ書き込んだ内容を反映するために status というファイルに 1 を入れる、とか、 反映した内容を取り消すために 0 を入れるとか、そういった情報もあるようだけれど、 ここでの環境では上記が正しいようだ。
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 用スクリプト†
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 によるプログラマブルロジック書き換え†
カーネル設定†
電気回路/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 ファイルを生成する†
fpga-bit-to-bin.py で .bit ファイルを .bin ファイルに変換する†
を使うと、以下のようにして 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 ファイルを作る†
vivado の [Flow Navigator] の [Generate Bitstream] の上で右クリックして、 [Bitstream Setting...] を選ぶと、bit ファイルと同時に bin ファイルも生成してくれるようになる。
ところが、こうしてできる .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
エンディアンネス変更プログラム†
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 デバイス†
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 として定義されている。
ロジックの書き込み†
以下の手順で書き込めば良い
- 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 領域書き換え用のスクリプト†
vivado で design_1_wrapper.bit を作成する際に同時に出力させた 「リトルエンディアンの design_1_wrapper.bin」 を指定して、
LANG:console $ fpga-program design_1_wrapper.bin
とすれば、自動でビッグエンディアンに変更してサクッと書き込めるようスクリプトを作成した。
fpga-program : https://github.com/osamutake/zynq-utils/tree/master/src/fpga-program
ちょっと危ないところもある†
上記の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 にシンボルを埋め込む†
を参考にすると、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