目次: Zephyr
先日はZepphyrをQEMUのSpikeモードに移植しましたが、SpikeモードだとCPU数は1以外選べないので、マルチプロセッサにできません。これは知りませんでした。最初に調べておけば良かったですね……。
マルチプロセッサでZephyrを動かしてみたかったので、QEMU RISC-V 32のvirtモード(qemu-system-riscv32のmachineをvirtにすること)に、前回同様にシリアルとメモリだけ動くようなSoCとボードの定義ファイルを作りました。
QEMU virtモードでは、シリアルのハードウェアとして16550をエミュレーションします。Zephyr側には既に16550用のドライバがあるので、わざわざ実装する必要もありません。とても楽です、素晴らしいです、とか何とか思いつつ動かしてみると、シリアルドライバがクラッシュします。んあー。
ZephyrをGDBで追うと16550のLCRレジスタを読もうとして、ロードアクセスフォルトが起きていました。アドレスのオフセットを見ると、0xcになっています。正しいオフセットは3のはずです。
シリアルドライバの実装を見ると、オフセットの計算が0x3 x 4 = 0xcとなっていて、おそらくレジスタサイズが4バイト単位だと思ってアクセスしているのでしょう。
世の中にはレジスタが4バイトの実装もあるかもしれませんが、残念なことにQEMUは由緒正しい(?)実装なので16550のレジスタは「1バイト」単位です。4バイト単位でアクセスすると、全く関係ない領域が破壊されます。困りました。
問題を解決するには、SoCの定義ファイルのどこか(soc.h辺りかな?)で、
#define DT_NS16550_REG_SHIFT 0
を定義し、レジスタのサイズが2^0つまり1バイト単位であることを16550シリアルドライバに教える必要があるみたいです。とても大事なことだと思いますが、全くドキュメントに書いていないように見えます。
そこそこコード見ないとわからないので、つらいです……。
無事シリアルが動作したので、QEMUを4 CPUのマルチプロセッサ設定で起動し、GDBで覗いてみます。
$ qemu-system-riscv32 -nographic -machine virt -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -kernel zephyr/build/zephyr/zephyr.elf -cpu rv32 -smp cpus=4 -s -S qemu-system-riscv32: warning: No -bios option specified. Not loading a firmware. qemu-system-riscv32: warning: This default will change in a future QEMU release. Please use the -bios option to avoid breakages when this happens. qemu-system-riscv32: warning: See QEMU's deprecation documentation for details. *** Booting Zephyr OS build v2.2.0-rc1-123-gcaca3f60b012 *** threadA: Hello World from QEMU RV32 virt board! threadB: Hello World from QEMU RV32 virt board! threadA: Hello World from QEMU RV32 virt board! threadB: Hello World from QEMU RV32 virt board! ... $ riscv64-zephyr-elf-gdb zephyr/build/zephyr/zephyr.elf ... Type "apropos word" to search for commands related to "word"... Reading symbols from build/zephyr/zephyr.elf... (gdb) target remote localhost:1234 Remote debugging using localhost:1234 0x00001000 in ?? () (gdb) info threads Id Target Id Frame * 1 Thread 1.1 (CPU#0 [running]) 0x00001000 in ?? () 2 Thread 1.2 (CPU#1 [running]) 0x00001000 in ?? () 3 Thread 1.3 (CPU#2 [running]) 0x00001000 in ?? () 4 Thread 1.4 (CPU#3 [running]) 0x00001000 in ?? ()
確かに4 CPUが存在していることがわかります。ZephyrのログはGDB側でcontinueすると出てきます。アプリケーションは、hello_worldではなくsamples/synchronizationを使っています。
メモ: 技術系の話はFacebookから転記しておくことにした。大幅に加筆した。
< | 2020 | > | ||||
<< | < | 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 | 29 |
合計:
本日: