Skip to content

hw/char/riscv_htif.c and hw/char/sifive_uart call qemu_chr_fe_write() and ignore return value

The riscv_htif.c and sifive_uart.c code for doing console output calls qemu_chr_fe_write() and ignores the return value. This is bad, because the return value tells you if the chardev frontend was able to accept all the data, or if you need to arrange to call it again later when it is no longer full. The result is that the console output can drop characters, which makes the avocado tests that use this device flaky. For instance on my machine

./build/clang/pyvenv/bin/avocado run ./build/clang/tests/avocado/riscv_opensbi.py:RiscvOpenSBI.test_riscv64_spike

fails about 50% of the time, and if you look at the debug log you can clearly see that characters get dropped:

2024-01-19 14:38:33,613 machine          L0903 DEBUG| Opening console socket
2024-01-19 14:38:33,662 __init__         L0153 DEBUG| OpenSBI v1.4
2024-01-19 14:38:33,662 __init__         L0153 DEBUG| ____                    _____ ____ _____
2024-01-19 14:38:33,662 __init__         L0153 DEBUG| / __ \                  / ____|  _ \_   _|
2024-01-19 14:38:33,663 __init__         L0153 DEBUG| | |  | |_ __   ___ _ __ | (___ | |_) || |
2024-01-19 14:38:33,663 __init__         L0153 DEBUG| | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
2024-01-19 14:38:33,664 __init__         L0153 DEBUG| | |__| | |_) |  __/ | | |____) | |_) || |_
2024-01-19 14:38:33,664 __init__         L0153 DEBUG| \____/| .__/ \___|_| |_|_____/|____/_____|
2024-01-19 14:38:33,664 __init__         L0153 DEBUG| | |
2024-01-19 14:38:33,664 __init__         L0153 DEBUG| |_|
2024-01-19 14:38:33,678 __init__         L0153 DEBUG| Platform Name             : ucbbar,spike-bare,qemu
2024-01-19 14:38:33,679 __init__         L0153 DEBUG| Platform Features         : medeleg
2024-01-19 14:38:33,679 __init__         L0153 DEBUG| Platform HART Count       : 1
2024-01-19 14:38:33,679 __init__         L0153 DEBUG| Platform IPI Device       : aclint-mswi
2024-01-19 14:38:33,680 __init__         L0153 DEBUG| Platform Timer Device     : aclint-mtimer @ 10000000Hz
2024-01-19 14:38:33,680 __init__         L0153 DEBUG| Platform Console Device   : htif
2024-01-19 14:38:33,680 __init__         L0153 DEBUG| Platform HSM Device       : ---
2024-01-19 14:38:33,681 __init__         L0153 DEBUG| Platform PMU Device       : ---
2024-01-19 14:38:33,681 __init__         L0153 DEBUG| Platform Reboot Device    : htif
2024-01-19 14:38:33,681 __init__         L0153 DEBUG| Platform Shutdown Device  : htif
2024-01-19 14:38:33,682 __init__         L0153 DEBUG| Platform Suspend Device   : ---
2024-01-19 14:38:33,682 __init__         L0153 DEBUG| Platform CPPC Device      : ---
2024-01-19 14:38:33,682 __init__         L0153 DEBUG| Firmware Base             : 0x80000000
2024-01-19 14:38:33,682 __init__         L0153 DEBUG| Firmware Size             : 323 KB
2024-01-19 14:38:33,683 __init__         L0153 DEBUG| Firmware RW Offset        : 0x40000
2024-01-19 14:38:33,683 __init__         L0153 DEBUG| Firmware RW Size          : 67 KB
2024-01-19 14:38:33,684 __init__         L0153 DEBUG| Firmware Heap Offset   :0x80^MFirmware Heap Size        : 35 KB (K rsre),9K ued,2 B (re^MFirmware Se  :496 (oa) 04B(se) 79  fee^MRuntn     .0
2024-01-19 14:38:33,684 __init__         L0153 DEBUG| Domain0 Name              : rDomain Bo HR
2024-01-19 14:38:33,684 __init__         L0153 DEBUG| Domain0 ARs     0*
2024-01-19 14:38:33,685 __init__         L0153 DEBUG| Domain0 Region00          : 0x0000000001000000-0x0000000001000fff M: (I,R,W) S/U: (R,W)
2024-01-19 14:38:33,685 __init__         L0153 DEBUG| Domain0 Region01          : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
2024-01-19 14:38:33,686 __init__         L0153 DEBUG| Domain0 Region02          : 0x00000080400-x0000005ff M (R,W) S/U: ()
2024-01-19 14:38:33,686 __init__         L0153 DEBUG| Domain Rgon3 00000fffM (R,X) S/U:0      :0x000000000-xfffffffff M () S/U: (R,W,X)
2024-01-19 14:38:33,687 __init__         L0153 DEBUG| Domain0 Next Address      : 0x000000000  0000007etMd       S-mode
2024-01-19 14:38:33,687 __init__         L0153 DEBUG| Domain0st     :ye^MDomain0 SysSuspend      ys
2024-01-19 14:38:33,688 __init__         L0153 DEBUG| Boot HART ID              : 0
2024-01-19 14:38:33,688 __init__         L0153 DEBUG| Boot HART Domain           ro
2024-01-19 14:38:33,688 __init__         L0153 DEBUG| Boot HART Priv VersBoot HART Base ISA        : rv64imafdch
2024-01-19 14:38:33,689 __init__         L0153 DEBUG| Boot HART ISA Extensions  : sstc,zihpm,zicboz,zicbom
2024-01-19 14:38:33,689 __init__         L0153 DEBUG| Boot HART PMP Count       : 16
2024-01-19 14:38:33,689 __init__         L0153 DEBUG| Boot HART PMP Granularity : 2 bits
2024-01-19 14:38:33,689 __init__         L0153 DEBUG| Boot HART PMP Address Bits: 54
2024-01-19 14:38:33,690 __init__         L0153 DEBUG| Boot HART MHPM Info       : 16 (0x0007fff8)
2024-01-19 14:38:33,690 __init__         L0153 DEBUG| Boot HART MIDELEG         : 0x0000000000001666

These devices need to either make sure they honours the return value from qemu_chr_fe_write() (eg by telling the guest the UART FIFO is full) or else they should use qemu_chr_fe_write_all(), which will block until the data is accepted. The latter is less preferable because then you potentially get deadlocks if nothing ever reads from the chardev frontend, but many of our UART models still use it.

Edited by Peter Maydell
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information