Support virtio-console - #139
shengwen-tw wants to merge 4 commits into
Conversation
1ab73d0 to
d1bfc1d
Compare
There was a problem hiding this comment.
3 issues found across 11 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="main.c">
<violation number="1" location="main.c:268">
P2: When the primary UART and secondary virtio-console are enabled together, this exclusive branch prevents `/dev/hvc0` from receiving input and leaves its device state uninitialized. Initialize and refresh each enabled console independently instead of making virtio-console the UART `#else` path.</violation>
</file>
<file name="virtio-console.c">
<violation number="1" location="virtio-console.c:203">
P2: TX processing performs unbounded blocking writes to the host output fd inside the guest's QueueNotify MMIO handler, which runs on the emulator's single thread. When the host output (pipe or PTY) backpressures (e.g. `semu | head -1` or a full terminal buffer), the guest `write()` to hvc0 blocks the entire emulator instead of yielding or dropping output. The previous UART path deliberately buffered output and dropped bytes on overflow (see `u8250_handle_out`), so this is a robustness regression for the new console.</violation>
</file>
<file name="Makefile">
<violation number="1" location="Makefile:219">
P2: The `SEMU_CONSOLE ?= virtio` default flips the build from the previous primary 8250 UART console to virtio-console, but the selection is mutually exclusive: when `SEMU_CONSOLE` is left at `virtio` the `else` branch is taken and `uart.o` is not compiled at all. This contradicts the PR description, which states the existing 8250 UART "remains the primary console and early boot path" and that virtio-console is a secondary console. With the default, the 8250 console (and its early-boot UART path) is silently removed from the default build, and the backend cannot be a "secondary" console since only one console object is built and main.c dispatches via `#if SEMU_HAS(UART8250) ... #else virtio_console ... #endif`. Keep `uart8250` as the default (or build both backends so virtio can genuinely be secondary) unless removing the 8250 primary console is the intended behavior.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| if (emu->uart.in_ready) | ||
| emu_update_uart_interrupts(vm); | ||
| #else | ||
| virtio_console_refresh(&emu->vconsole); |
There was a problem hiding this comment.
P2: When the primary UART and secondary virtio-console are enabled together, this exclusive branch prevents /dev/hvc0 from receiving input and leaves its device state uninitialized. Initialize and refresh each enabled console independently instead of making virtio-console the UART #else path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At main.c, line 268:
<comment>When the primary UART and secondary virtio-console are enabled together, this exclusive branch prevents `/dev/hvc0` from receiving input and leaves its device state uninitialized. Initialize and refresh each enabled console independently instead of making virtio-console the UART `#else` path.</comment>
<file context>
@@ -223,10 +259,16 @@ static inline void emu_tick_peripherals(emu_state_t *emu)
if (emu->uart.in_ready)
emu_update_uart_interrupts(vm);
+#else
+ virtio_console_refresh(&emu->vconsole);
+ if (emu->vconsole.InterruptStatus)
+ emu_update_vconsole_interrupts(vm);
</file context>
| } | ||
| const void *buf = | ||
| (const uint8_t *) vcon->ram + (uintptr_t) chain[i].addr; | ||
| if (!vcon_write_all(vcon->out_fd, buf, chain[i].len)) { |
There was a problem hiding this comment.
P2: TX processing performs unbounded blocking writes to the host output fd inside the guest's QueueNotify MMIO handler, which runs on the emulator's single thread. When the host output (pipe or PTY) backpressures (e.g. semu | head -1 or a full terminal buffer), the guest write() to hvc0 blocks the entire emulator instead of yielding or dropping output. The previous UART path deliberately buffered output and dropped bytes on overflow (see u8250_handle_out), so this is a robustness regression for the new console.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At virtio-console.c, line 203:
<comment>TX processing performs unbounded blocking writes to the host output fd inside the guest's QueueNotify MMIO handler, which runs on the emulator's single thread. When the host output (pipe or PTY) backpressures (e.g. `semu | head -1` or a full terminal buffer), the guest `write()` to hvc0 blocks the entire emulator instead of yielding or dropping output. The previous UART path deliberately buffered output and dropped bytes on overflow (see `u8250_handle_out`), so this is a robustness regression for the new console.</comment>
<file context>
@@ -0,0 +1,474 @@
+ }
+ const void *buf =
+ (const uint8_t *) vcon->ram + (uintptr_t) chain[i].addr;
+ if (!vcon_write_all(vcon->out_fd, buf, chain[i].len)) {
+ fprintf(stderr, "virtio-console: output failed: %s\n",
+ strerror(errno));
</file context>
| endif | ||
|
|
||
| # Guest console: UART-8250 or virtio-console | ||
| SEMU_CONSOLE ?= virtio |
There was a problem hiding this comment.
P2: The SEMU_CONSOLE ?= virtio default flips the build from the previous primary 8250 UART console to virtio-console, but the selection is mutually exclusive: when SEMU_CONSOLE is left at virtio the else branch is taken and uart.o is not compiled at all. This contradicts the PR description, which states the existing 8250 UART "remains the primary console and early boot path" and that virtio-console is a secondary console. With the default, the 8250 console (and its early-boot UART path) is silently removed from the default build, and the backend cannot be a "secondary" console since only one console object is built and main.c dispatches via #if SEMU_HAS(UART8250) ... #else virtio_console ... #endif. Keep uart8250 as the default (or build both backends so virtio can genuinely be secondary) unless removing the 8250 primary console is the intended behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Makefile, line 219:
<comment>The `SEMU_CONSOLE ?= virtio` default flips the build from the previous primary 8250 UART console to virtio-console, but the selection is mutually exclusive: when `SEMU_CONSOLE` is left at `virtio` the `else` branch is taken and `uart.o` is not compiled at all. This contradicts the PR description, which states the existing 8250 UART "remains the primary console and early boot path" and that virtio-console is a secondary console. With the default, the 8250 console (and its early-boot UART path) is silently removed from the default build, and the backend cannot be a "secondary" console since only one console object is built and main.c dispatches via `#if SEMU_HAS(UART8250) ... #else virtio_console ... #endif`. Keep `uart8250` as the default (or build both backends so virtio can genuinely be secondary) unless removing the 8250 primary console is the intended behavior.</comment>
<file context>
@@ -215,6 +215,27 @@ ifeq ($(call has, VIRTIOGPU), 1)
endif
+# Guest console: UART-8250 or virtio-console
+SEMU_CONSOLE ?= virtio
+SEMU_CONSOLE := $(strip $(SEMU_CONSOLE))
+override ENABLE_UART8250 := 0
</file context>
Overview
This adds a
virtio-consoledevice and makes it the default guest console. It uses the host standard input and output directly, and guest Linux exposes the console as/dev/hvc0.The existing 8250/16550 UART remains available for early-boot diagnostics with
SEMU_CONSOLE=uart8250. The two console devices are mutually exclusive at build time so that only one device owns the host terminal and appears in the generated device tree.Test procedures
The command line should contain
console=hvc0, and/dev/hvc0should exist inthe guest. Verify both keyboard input and console output, then exit with
Ctrl-a x.The guest command line should contain
earlycon console=ttyS0, and the consoleshould be available as
/dev/ttyS0.