Reviewed-by: Kostiantyn Kostiuk <[email protected]> On Sat, Oct 17, 2026 at 11:22 PM Oleksij Samorukov <[email protected]> wrote:
> On FreeBSD the virtio-console port is a tty, unlike Linux's > /dev/virtio-ports which is a character device. It defaults to canonical > mode with echo and software flow control enabled, so the QGA stream > protocol does not work: the initial guest-sync handshake is held in the > line discipline and the host eventually times out. > > The existing FreeBSD-specific code only clears ECHO. Configure the port > the same way as the ISA serial path: disable canonical mode, echo and > software flow control, and set VMIN/VTIME. Use TCSANOW instead of > TCSAFLUSH so a handshake that arrives between open() and tcsetattr() is > not discarded. > > Tested on FreeBSD 15.1 aarch64 under UTM/QEMU. Before the change > utmctl ip-address timed out and the guest received zero bytes; after the > change QGA commands and guest-set-time work. > > Cc: [email protected] > Fixes: c6cd588bb3a29a831c862780631a7d2145ade5de ("qga: Add initial FreeBSD > support") > Signed-off-by: Oleksij Samorukov <[email protected]> > --- > qga/channel-posix.c | 22 +++++++++++++++++----- > 1 file changed, 17 insertions(+), 5 deletions(-) > > diff --git a/qga/channel-posix.c b/qga/channel-posix.c > index 9ccc8b7..c6dfb2d 100644 > --- a/qga/channel-posix.c > +++ b/qga/channel-posix.c > @@ -156,9 +156,10 @@ static gboolean ga_channel_open(GAChannel *c, const > gchar *path, > #endif > #ifdef __FreeBSD__ > /* > - * In the default state channel sends echo of every command to a > - * client. The client program doesn't expect this and raises an > - * error. Suppress echo by resetting ECHO terminal flag. > + * FreeBSD's virtio-console port is a tty (unlike Linux's > + * /dev/virtio-ports, which is a character device) and defaults to > + * canonical mode with echo and software flow control enabled. > + * QGA uses a raw stream protocol, so put the port in raw mode. > */ > struct termios tio; > if (tcgetattr(fd, &tio) < 0) { > @@ -166,8 +167,19 @@ static gboolean ga_channel_open(GAChannel *c, const > gchar *path, > close(fd); > return false; > } > - tio.c_lflag &= ~ECHO; > - if (tcsetattr(fd, TCSAFLUSH, &tio) < 0) { > + tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | > ISTRIP | > + INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY | > + IMAXBEL); > + tio.c_oflag = 0; > + tio.c_lflag = 0; > + tio.c_cflag |= CLOCAL | CREAD; > + tio.c_cc[VMIN] = 1; > + tio.c_cc[VTIME] = 0; > + /* > + * Use TCSANOW rather than TCSAFLUSH: the host may already have > sent > + * the initial handshake between open() and tcsetattr(). > + */ > + if (tcsetattr(fd, TCSANOW, &tio) < 0) { > error_setg_errno(errp, errno, "error setting channel termios > attrs"); > close(fd); > return false; > -- > 2.54.0 (Apple Git-157) > > >
