目次: GCC
目次: Linux
Linuxをデバッグするにはkgdbを使うと思いますが、QEMU + GDBでよりお手軽にデバッグができます。お手軽とは書いたものの、実際やったところQEMUでかなり苦戦したのでメモしておきます。
対象のアーキテクチャはAArch64を選びました。お好きなアーキテクチャを使っていただいて構いませんが、Linuxのコンフィグをどうするべきかと、QEMUの動かし方を知っているアーキテクチャにしてください。せっかくLinuxをビルドしても動かせなくて詰みます。
ツールチェーンの構築の方法は昔の日記(2018年7月15日の日記参照)で構築手段をご紹介しています。crosstool-ngはデフォルトだとGDBがビルドされなかった気がするので、
CT_DEBUG_GDB=y Debug facilities ---> [*] gdb --->
この変更が必要になると思います。
Linuxカーネルはlinux-nextを使いました。新し目のLTSカーネルなども十分動くはずです。コンフィグの変更点は下記のとおりです。
CONFIG_RANDOMIZE_BASE=n(gdbでデバッグするときは、アドレスをランダムに変えられると困るため) Kernel Features ---> [ ] Randomize the address of the kernel image CONFIG_DEBUG_INFO_REDUCED=n(yだとgdbで構造体などの情報が見えなくなるため) Kernel hacking ---> Compile-time checks and compiler options ---> [*] Compile the kernel with debug info [ ] Reduce debugging information CONFIG_MODULES=n(モジュールのインストールが面倒なので) [ ] Enable loadable module support ----
デフォルトのコンフィグだと、やたらと色々なドライバをビルドするので時間がかかります。グラフィクス系のドライバなどの明らかに不要なドライバは外しても良いと思います。
QEMUは様々なハードウェアを模倣できます。そのなかにRaspberry Pi 3bがありましたのでこれを使います。initrdイメージはbuildrootで作りました。
qemu-system-aarch64 \ -machine raspi3b \ -kernel arch/arm64/boot/Image \ -append "earlycon=pl011,0x3f201000 console=ttyAMA0" \ -dtb arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dtb \ -initrd ../buildroot/output/images/rootfs.cpio \ -serial stdio \ -s
起動してプロンプトまで表示されますが、キー入力を全く受け付けず操作不能になってしまいます。解決方法がわからなかったので諦めました。
ちなみに最近のlinux-nextを使う場合は、GPIOとpinctrlの初期化順を修正するパッチを当てないといけません。これを当てないとpinctrlが無効になってしまい、連鎖的にpinctrlに依存しているSDカードのドライバなども無効化され「rootfsがマウントできない!」とpanicになってしまいます。
この問題に気づくまでかなり時間がかかりました。バグだと思ってめっちゃ調べたのに、もうパッチがLKMLに投稿されていたという体験は、linux-nextを使っていると珍しくないですけどね。よりによってRaspberry Piだけで起きるバグをタイムリーに引くとは思わなかった……完全に油断してた。
Raspberry Piマシンの代わりにvirtマシンを使うことにしました。
今回はユーザーランドは動けばOKですから、Raspberry PiのディスクイメージRaspberry Pi OS Lite 64bit(公式ダウンロードサイト)を使用します。
QEMUで起動する場合virtioを使用します。QEMUのvirtマシンは残念ながらSDやmtdには対応していません。パラレルフラッシュはサイズが64MBまでのためにRaspberry Pi OSのイメージは大きすぎると言われ起動できません。
qemu-system-aarch64 \ -machine virt -cpu cortex-a53 -smp 1 \ -kernel arch/arm64/boot/Image -append "rw root=/dev/vda2" \ -drive file=2022-01-28-raspios-bullseye-arm64-lite_resize.img,format=raw,if=virtio \ -serial stdio \ -s
最後の -sオプションはGDBの接続をポート1234で待機するオプション -gdb tcp::1234の短縮形です。カーネルのブート部分などをデバッグする場合は、GDBを接続するまで停止していてほしいので -Sも一緒に付けると良いです。
前置きがだいぶ長くなりましたがこれでデバッグ環境が整いました。GDBをQEMUに接続するにはtarget remoteコマンドを使います。
$ aarch64-unknown-linux-gnu-gdb vmlinux GNU gdb (crosstool-NG 1.24.0.501_5bf4485) 10.2 Copyright (C) 2021 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=aarch64-unknown-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from vmlinux... (gdb) b start_kernel Breakpoint 1 at 0xffff800009e10c64: file init/main.c, line 931. (gdb) target remote :1234 Remote debugging using :1234 0x0000000040000000 in ?? () (gdb) c Continuing. Breakpoint 1, start_kernel () at init/main.c:931 931 {
実行、ブレーク、ソースコードの表示もできています。良い感じですね!
目次: OpenOCD
HiFive1のJTAGを使う際はJ-Linkの設定(tcl/interface/jlink.cfg)を使えばOKです。しかしSEGGER J-LinkのJTAG箱が見当たらないのに、なぜこの設定で動くのか若干気になりました。調べたら納得だったのでメモしておきます。
回路図を見るとマイコンでUSB-JTAG変換を実現しています。USB端子はNXP MK22FN128VLH10(MK22FN128VLH10 Product Information - NXP)に接続されており、このICからJTAGの信号(TDIなど)が出ています。JTAGの信号線はSiFive FE310に接続されています。
なぜ突然NXPのマイコンICが出てくるのか?J-Linkはどこから来た??と思いきや、実はこれSEGGER J-LinkのオンチップJTAG、J-Link-OBというシリーズの1つで使われているマイコンです(参考: J-Link OB Debug Probe - SEGGER)。SEGGER J-Linkは専用のICがあるわけではなく、NXPやSTのマイコンで実現しているんですね、なるほど。
カタログ上はCortex-M/Cortex-A用となっていますが、これはSEGGER独自の機能が使えるか使えないかを表しているのでしょう。JTAGは4つの信号線(TMS, TCK, TDI, TDO)でJTAGのプロトコルを理解するデバイスが相手であれば良くて、CPUの種類は特に気にしないはず……。
目次: OpenOCD
SiFiveのHiFive1というボード(SiFiveのサイトへのリンク)をデバッグするときは、HiFive1のオンボードUSB-JTAGを使うことが多いと思います。
非常に便利ですがUSB接続ゆえに近くにPCが必要です。PCを作業机の横に置けば何の問題もないんですけど、我が家の場合は諸事情でちょっと困った配置になっています。
PCを作業机の横に持ってくる手も考えましたが、悪あがきとしてRaspberry Pi 3でOpenOCDを実行してサーバー代わりにしてみました。結果から言うと、思っていたよりうまく動いてくれました。嬉しい、Raspberry Pi偉い。
各機器の接続関係はこんな感じです。各ソフトに改造は不要です。GDBのTCP経由でデバッグできる機能と、OpenOCDのGDB serverとして振る舞う機能の合わせ技で実現できます。
(通常) PCのGDB <-(TCP local接続)-> PCのOpenOCD <-(USB)-> HiFive1 (今回) PCのGDB <-(TCP接続)-> Raspberry Pi 3のOpenOCD <-(USB)-> HiFive1
こんな変な使い方まで想定内とは驚きです。GDBもOpenOCDも良くできています。
Raspberry Pi 3ではOpenOCDを実行します。
$ ./src/openocd -c 'bindto 0.0.0.0' -f tcl/interface/jlink.cfg -f ./tcl/board/sifive-hifive1-revb.cfg Open On-Chip Debugger 0.11.0+dev-00551-gaad871805 (2022-01-16-22:30) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Warn : Interface already configured, ignoring Info : J-Link OB-K22-SiFive compiled Nov 22 2019 12:57:38 Info : Hardware version: 1.00 Info : VTarget = 3.300 V Info : clock speed 4000 kHz Info : JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2) Info : datacount=1 progbufsize=16 Info : Disabling abstract command reads from CSRs. Info : Examined RISC-V core; found 1 harts Info : hart 0: XLEN=32, misa=0x40101105 Info : starting gdb server for riscv.cpu.0 on 3333 Info : Listening on port 3333 for gdb connections Info : Found flash device 'issi is25lp032' (ID 0x0016609d) Ready for Remote Connections Info : Listening on port 6666 for tcl connections Info : Listening on port 4444 for telnet connections Info : JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2) Warn : keep_alive() was not invoked in the 1000 ms timelimit. GDB alive packet not sent! (1606 ms). Workaround: increase "set remotetimeout" in GDB Info : JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2) Warn : keep_alive() was not invoked in the 1000 ms timelimit. GDB alive packet not sent! (1523 ms). Workaround: increase "set remotetimeout" in GDB Info : JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2) Warn : keep_alive() was not invoked in the 1000 ms timelimit. GDB alive packet not sent! (1599 ms). Workaround: increase "set remotetimeout" in GDB Info : JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2) Warn : keep_alive() was not invoked in the 1000 ms timelimit. GDB alive packet not sent! (1610 ms). Workaround: increase "set remotetimeout" in GDB Warn : Error writing to GDB socket. Dropping the connection. Info : dropped 'gdb' connection Info : accepting 'gdb' connection on tcp/3333 Info : JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2) Warn : keep_alive() was not invoked in the 1000 ms timelimit. GDB alive packet not sent! (1614 ms). Workaround: increase "set remotetimeout" in GDB
PC側からmonitor resetを実行すると「1,000ms以内に返事が来ない!タイムアウトしたぞ!」というWarningログが頻発します。HiFive1の反応が遅いのか、Raspberry Pi 3の判断が遅いのか、どちらかよくわかりません。両方かな……?
PCではGDBを実行します。例ではZephyrのバイナリを送っていますが、Zephyr以外でも手順は同じです。
$ riscv64-zephyr-elf-gdb build/zephyr/zephyr.elf GNU gdb (crosstool-NG 1.24.0.378_e011758) 9.2 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=riscv64-zephyr-elf". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from build/zephyr/zephyr.elf... (gdb) target remote 192.168.1.106:3333 Remote debugging using 192.168.1.106:3333 0x00001004 in ?? () (gdb) monitor reset halt JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2) keep_alive() was not invoked in the 1000 ms timelimit. GDB alive packet not sent! (1615 ms). Workaround: increase "set remotetimeout" in GDB
GDBもタイムアウトがどうのこうのと怒っています。特に異常動作はしないので放っておいても良いですけど、邪魔であればメッセージのおススメ通りにset remotetimeoutの値を伸ばすと良いでしょう。
基本的には以上です動きました良かったね!で終わりなんですけど、Raspberry Pi 3のdmesgを見ていたら見慣れないエラーが出ていたのでメモしておきます。
[ 253.885123] usb 1-1.5: new full-speed USB device number 6 using dwc_otg [ 254.021413] usb 1-1.5: New USB device found, idVendor=1366, idProduct=1051, bcdDevice= 1.00 [ 254.021440] usb 1-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 254.021475] usb 1-1.5: Product: J-Link [ 254.021490] usb 1-1.5: Manufacturer: SEGGER [ 254.021505] usb 1-1.5: SerialNumber: 000979016829 [ 254.023795] cdc_acm 1-1.5:1.0: ttyACM0: USB ACM device [ 254.027758] cdc_acm 1-1.5:1.2: ttyACM1: USB ACM device [ 254.031278] usb-storage 1-1.5:1.5: USB Mass Storage device detected [ 254.032081] scsi host0: usb-storage 1-1.5:1.5 [ 254.875197] Under-voltage detected! (0x00050005) ★★★★これと★★★★ [ 255.037642] scsi 0:0:0:0: Direct-Access SEGGER MSD Volume 1.00 PQ: 0 ANSI: 4 [ 255.038948] sd 0:0:0:0: Attached scsi generic sg0 type 0 [ 255.043115] sd 0:0:0:0: [sda] 21829 512-byte logical blocks: (11.2 MB/10.7 MiB) [ 255.052887] sd 0:0:0:0: [sda] Write Protect is off [ 255.052914] sd 0:0:0:0: [sda] Mode Sense: 0b 00 00 08 [ 255.055179] sd 0:0:0:0: [sda] No Caching mode page found [ 255.055202] sd 0:0:0:0: [sda] Assuming drive cache: write through [ 255.148361] sda: [ 255.166356] sd 0:0:0:0: [sda] Attached SCSI removable disk [ 259.035120] Voltage normalised (0x00000000) ★★★★これ★★★★
このエラーはRaspberry Pi 3とHiFive1のUSB端子を接続したときに出現します(私の環境だと接続のたびに必ず発生)。電力供給ラインであるUSBのVBus端子電圧が下がっているという意味ですかねえ……?可能性としてはHiFive1が起動時だけ一気に大電力を消費することが考えられますが、深追いしておらず真相はわかりません。
正月、北海道から帰ってきて車の様子を見たら、完全にバッテリーが上がっていました。気づいたのはちょっと前(2022年1月10日の日記参照)くらいです。セルモーターは微塵も動かず、そもそもリモコンキーも効きません。ドアはカギで開けました。ドアを開けても室内灯すら点きませんね……。
今まで何度となくバッテリーをダメにしてきた悲しい経験から、これはバッテリー交換コースだと確信しました。またかよー。
JAFに来てもらう間、暇だったのでバッテリーの電圧を測りました。電圧は2.16Vでした。これは乾電池でしたっけ??正常な車のバッテリーは12V前後(セル電圧2V程度x6セル)であり、放電終止電圧は10V前後(セル電圧1.8V程度x6セル)です。2.16Vがいかに論外な状態であるか、おわかりいただけるかと思います。
バッテリーから流れる電流も測りました。電流はほぼ流れていないか、クランプメーターの検出限界以下と思われます。余談ですが、このクランプメーターはゼロ点が狂ってきたようで、何も繋がず、ゼロ点補正なしだと -0.31Aになってしまいます。直し方がわからない。
JAFさんにエンジンかけてもらった後に電流を測りました。やはり電流はほぼ流れておらず、充電されているように見えません。バッテリーが死んでいるのか、エンジン始動直後のせいか?どっちでしょうね?
バッテリーの液量インジケーターは元々どうなっていたのかわからなくて、正常か異常か判別できませんでした。
仮に液量が正常でも、過放電でサルフェーション現象が発生して電極が死んでいる(=充電ができない=次止めたらエンジンが掛からない)でしょうから、素直にバッテリー交換に行きますか。
近所のイエローハットまで20分くらい走って、エンジンを切ってみたところ、電圧は11.8Vとなっていました。ん?充電されている?もしかしてバッテリーは生きてたのかな?
このまま帰ってまたバッテリーが上がったり、旅先で立ち往生されるのは困るため、潔くバッテリーを交換しました。当たり前ですが交換後は12.6Vと元気な電圧になっていました。
バッテリーは今載っているものと全く同じものを買いました。特に変更する理由もないし。はー、こんなことで35,000円の出費は痛いな……。
メーターを見ると、エラーEr IUが出てました。なんじゃろ?これ??
Facebookで会社の皆さまに教えていただいたところ、統合ユニットの通信エラーが発生したときに記録されるエラーとのこと。ずっと出続けていて気になりますけど、普通に走れて実害もなさそうなので、しばし放っておこうと思います。
< | 2022 | > | ||||
<< | < | 02 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | - | - | - | - | - |
合計:
本日: