QEMU 4.2 で動いていた Raspberry Piのmini uartの受信割り込みがQEMU 6.1.0だと動かないのでデバッグしてみました。
問題の現象
以前の動作はドキュメントの実行例によると
$ make run
qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf
qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c
int02
a c_irq_handler
b c_irq_handler
c c_irq_handler
のようにキーボードから一文字入力毎に割り込みが1回発生した。
このプログラムをQEMU 6.1.0を動かすと
$ qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -kernel kernel.elf
qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c
int02
c_irq_handler
c_irq_handler
c_irq_handler
c_irq_handler
c_irq_handler
c_irq_handler
のようにキーを入力してないのに割り込みが入り続ける。
デバッグ
QEMUのソースを見てみます。
hw/char/bcm2835_aux.c
が該当のファイルです。
割り込みを生成している部分のコード
static void bcm2835_aux_update(BCM2835AuxState *s)
{
/* signal an interrupt if either:
* 1. rx interrupt is enabled and we have a non-empty rx fifo, or
* 2. the tx interrupt is enabled (since we instantly drain the tx fifo)
*/
s->iir = 0;
if ((s->ier & RX_INT) && s->read_count != 0) {
s->iir |= RX_INT;
}
if (s->ier & TX_INT) {
s->iir |= TX_INT;
}
qemu_set_irq(s->irq, s->iir != 0);
}
これをみたら原因らしきものが分かったかもです。送信割り込みがイネーブルだと常に割り込みが入るみたいです。
あれ、受信割り込みしか有効にしてないはずだけどなぁと思って確認したところ、datasheetの送信割り込み有効ビットと受信割り込み有効ビットが間違っていた。
https://datasheets.raspberrypi.org/bcm2835/bcm2835-peripherals.pdf
だとbit1がEnable receive interruptでEnable transmit interruptです。
https://elinux.org/BCM2835_datasheet_errata
にBits 1:0 are swaped. bit 0 is receive interrupt and bit 1 is transmit.
の記載があります。
ということで以下の変更で解決しました。
/* enable UART RX interrupt. */
*AUX_ENABLES = 1;
//*AUX_MU_IIR = 4;
- *AUX_MU_IER = 2;
+ *AUX_MU_IER = 1;
変更をpushしときました。
以上です。