@samitouri / QOSamiQemu / commits / 907b8d5635

hw/char/pl011: Only log "data written to disabled UART" once

We log a GUEST_ERROR message "PL011 data written to disabled UART" if the guest writes data to the TX FIFO when it has not set the enable bit in the UART. The idea is to note that the guest has done something dubious but let it work anyway. However, since we print this message for every output character, it floods the logs when running a guest that does this. Keep a note of whether we've printed the log message or not, so we only output it once. If the guest actively disables the UART, we re-arm the log message. Notably, the Linux kernel does not bother to enable the UART if it is used for earlycon, relying on the firmware having already done that. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr> Message-id: 20260210101702.3980804-1-peter.maydell@linaro.org

Peter Maydell committed Feb 26, 2026 at 11:27 UTC 907b8d56351b1ba6c97953edaca6a08f02fa2048
2 files changed +23 -2
hw/char/pl011.c
+22 -2
@@ -227,10 +227,25 @@ static void pl011_loopback_tx(PL011State *s, uint32_t value)
227 static void pl011_write_txdata(PL011State *s, uint8_t data)
228 {
229 if (!(s->cr & CR_UARTEN)) {
230 - qemu_log_mask(LOG_GUEST_ERROR,
231 - "PL011 data written to disabled UART\n");
230 + /*
231 + * Only log this message once, not every time the guest outputs:
232 + * otherwise we would flood the logs with this message, making
233 + * harder to debug guests. (Some very popular guests like Linux
234 + * don't actively enable the UART.)
235 + */
236 + if (!s->logged_disabled_uart) {
237 + qemu_log_mask(LOG_GUEST_ERROR,
238 + "PL011 data written to disabled UART\n");
239 + s->logged_disabled_uart = true;
240 + }
241 }
242 if (!(s->cr & CR_TXE)) {
243 + /*
244 + * We don't bother with the only-log-once machinery for this check
245 + * because TXE is enabled by default from PL011 reset, so there
246 + * isn't likely to be existing in-the-wild guest code that trips
247 + * over this one.
248 + */
249 qemu_log_mask(LOG_GUEST_ERROR,
250 "PL011 data written to disabled TX UART\n");
251 }
@@ -457,6 +472,10 @@ static void pl011_write(void *opaque, hwaddr offset,
472 break;
473 case 12: /* UARTCR */
474 /* ??? Need to implement the enable bit. */
475 + if ((s->cr ^ value) & CR_UARTEN) {
476 + /* Re-arm the log warning when the guest toggles UARTEN */
477 + s->logged_disabled_uart = false;
478 + }
479 s->cr = value;
480 pl011_loopback_mdmctrl(s);
481 break;
@@ -665,6 +684,7 @@ static void pl011_reset(DeviceState *dev)
684 s->ifl = 0x12;
685 s->cr = 0x300;
686 s->flags = 0;
687 + s->logged_disabled_uart = false;
688 pl011_reset_rx_fifo(s);
689 pl011_reset_tx_fifo(s);
690 }
include/hw/char/pl011.h
+1
@@ -51,6 +51,7 @@ struct PL011State {
51 qemu_irq irq[6];
52 Clock *clk;
53 bool migrate_clk;
54 + bool logged_disabled_uart;
55 const unsigned char *id;
56 /*
57 * Since some users embed this struct directly, we must