From nobody Mon Jan 26 07:42:01 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=quarantine dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1769045737; cv=none; d=zohomail.com; s=zohoarc; b=ga1GPNzQnNEA/BjGhShL/OBAIeGwdvFJxzBGYKHyAE0w8MJGQweFxy6fMZpNCaozLgnEdAZ9rAigrAMlGvkejIr6ekST+8kwagUsPvbUqZgt2LhBD2fjbw9zGs+W3NPFdPiB2+ONOIPpt6v2dSlE5urlvbihIf3s3Ym4eLIVHAE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1769045737; h=Content-Type:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=IsoL1gkKaMrZeYiDL329Pyp93DipRVOXlANbLmgSWPw=; b=DlxPAlyfJBgzxZeBQMa6N60RbQ0zGw6Bwy0ddhcwpiY7LEuE9s6fcLda/7IxzHn/eII6iaPLaAAwOEIM1/wpQAl3kQdC/MfT4+8SdqfLVkch+qwHQVrMlQ41PR55k8s5MK0CYeFYZ1YZKZuw+Z++JKC7DCxx5M9Rc4Qj1RX6xU0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1769045737859308.64232306701444; Wed, 21 Jan 2026 17:35:37 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1210329.1522048 (Exim 4.92) (envelope-from ) id 1vijbE-0000FP-QP; Thu, 22 Jan 2026 01:35:04 +0000 Received: by outflank-mailman (output) from mailman id 1210329.1522048; Thu, 22 Jan 2026 01:35:04 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vijbE-0000FH-Li; Thu, 22 Jan 2026 01:35:04 +0000 Received: by outflank-mailman (input) for mailman id 1210329; Thu, 22 Jan 2026 01:35:02 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vijbC-0000F9-Qa for xen-devel@lists.xenproject.org; Thu, 22 Jan 2026 01:35:02 +0000 Received: from sea.source.kernel.org (sea.source.kernel.org [2600:3c0a:e001:78e:0:1991:8:25]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 9012099c-f732-11f0-9ccf-f158ae23cfc8; Thu, 22 Jan 2026 02:35:00 +0100 (CET) Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sea.source.kernel.org (Postfix) with ESMTP id E274E40448; Thu, 22 Jan 2026 01:34:57 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7C066C4CEF1; Thu, 22 Jan 2026 01:34:56 +0000 (UTC) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 9012099c-f732-11f0-9ccf-f158ae23cfc8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769045697; bh=YmwG5XqwcJY3E9hnlisguppPgD11x4/SdCrdc5SMDE8=; h=Date:From:To:cc:Subject:From; b=btAfPPcshxTpTna23/cM20kqvtSxSLOlVArYCiRJKF9D2yfBGpenN9/RUHaJmHJrh IpcPK4hXySGIkaA6UXA+KjrwUp6ApcD53wnmapMGSCu2Glfxvl9w5EeHiG3M09PNwY giLZmDJtdyTIzNRj7PVYv0fwbCojMo1yLTq8JLBw3wA+KetIcS+Y1NTgQsThbvqgXY 6LdjUUhMFrzr3lYPASjrYtz9ilEafHJ0NZNvur4s+ji/Cj3RrJvrYSIXkgReE5ETwu E9gfsVvpiuyLXuxfv4xFylZuOiKbIzXJdkA65KmG+PtevOdudaTqf+7MWoGKBALxKX Gg9DgEOAKcUVA== Date: Wed, 21 Jan 2026 17:34:54 -0800 (PST) From: Stefano Stabellini X-X-Sender: sstabellini@ubuntu-linux-20-04-desktop To: xen-devel@lists.xenproject.org cc: grygorii_strashko@epam.com, Anthony PERARD , Michal Orzel , Julien Grall , =?UTF-8?Q?Roger_Pau_Monn=C3=A9?= , Jason Andryuk , Victor Lira , andrew.cooper3@citrix.com, sstabellini@kernel.org, jbeulich@suse.com Subject: [PATCH v6] xen/console: handle multiple domains using console_io hypercalls Message-ID: User-Agent: Alpine 2.22 (DEB 394 2020-01-19) MIME-Version: 1.0 X-ZohoMail-DKIM: pass (identity @kernel.org) X-ZM-MESSAGEID: 1769045741637154100 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Allow multiple dom0less domains to use the console_io hypercalls to print to the console. Handle them in a similar way to vpl011: only the domain which has focus can read from the console. All domains can write to the console but the ones without focus have a prefix. In this case the prefix is applied by using guest_printk instead of printk or console_puts which is what the original code was already doing. When switching focus using Ctrl-AAA, discard any unread data in the input buffer. Input is read quickly and the user would be aware of it being slow or stuck as they use Ctrl-AAA to switch focus domain. In that situation, it is to be expected that the unread input is lost. The domain writes are buffered when the domain is not in focus. Push out the buffer after the domain enters focus on the first guest write. Move the vpl011 check first so that if vpl011 is enabled, it will be used. In the future, the is_hardware_domain path might also be used by other predefined domains so it makes sense to prioritize vpl011 to retain the current behavior on ARM. Locking updates: - Guard every mutation of serial_rx_cons/prod with console_lock and discard unread input under the lock when switching focus (including when returning to Xen) so that cross-domain reads can't see stale data - Require is_focus_domain() callers to hold console_lock, and take that lock around the entire CONSOLEIO_read loop, re-checking focus after each chunk so a focus change simply stops further copies without duplicating or leaking input - Hold cd->pbuf_lock while flushing buffered writes in the focus path so the direct-write fast path does not race buffered guests or HVM debug output Signed-off-by: Stefano Stabellini --- Changes in v6: - moved locks out of console_get/put_domain - reworked locking from the ground up - introduced is_focus_domain - improved commit message --- xen/drivers/char/console.c | 64 +++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 2bdb4d5fb4..d586572c5e 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -540,6 +540,11 @@ void console_put_domain(struct domain *d) rcu_unlock_domain(d); } =20 +static bool is_focus_domain(struct domain *d) +{ + return d !=3D NULL && d->domain_id =3D=3D console_rx - 1; +} + static void console_switch_input(void) { unsigned int next_rx =3D console_rx; @@ -555,8 +560,11 @@ static void console_switch_input(void) =20 if ( next_rx++ >=3D max_console_rx ) { - console_rx =3D 0; printk("*** Serial input to Xen"); + nrspin_lock_irq(&console_lock); + console_rx =3D 0; + serial_rx_cons =3D serial_rx_prod; + nrspin_unlock_irq(&console_lock); break; } =20 @@ -575,8 +583,12 @@ static void console_switch_input(void) =20 rcu_unlock_domain(d); =20 - console_rx =3D next_rx; printk("*** Serial input to DOM%u", domid); + nrspin_lock_irq(&console_lock); + console_rx =3D next_rx; + /* Don't let the next dom read the previous dom's unread data.= */ + serial_rx_cons =3D serial_rx_prod; + nrspin_unlock_irq(&console_lock); break; } } @@ -599,14 +611,25 @@ static void __serial_rx(char c) if ( !d ) return; =20 +#ifdef CONFIG_SBSA_VUART_CONSOLE + /* Prioritize vpl011 if enabled for this domain */ + if ( d->arch.vpl011.base_addr ) + { + /* Deliver input to the emulated UART. */ + rc =3D vpl011_rx_char_xen(d, c); + } + else +#endif if ( is_hardware_domain(d) ) { /* * Deliver input to the hardware domain buffer, unless it is * already full. */ + nrspin_lock_irq(&console_lock); if ( (serial_rx_prod - serial_rx_cons) !=3D SERIAL_RX_SIZE ) serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] =3D c; + nrspin_unlock_irq(&console_lock); =20 /* * Always notify the hardware domain: prevents receive path from @@ -614,11 +637,6 @@ static void __serial_rx(char c) */ send_global_virq(VIRQ_CONSOLE); } -#ifdef CONFIG_SBSA_VUART_CONSOLE - else - /* Deliver input to the emulated UART. */ - rc =3D vpl011_rx_char_xen(d, c); -#endif =20 if ( consoled_is_enabled() ) /* Deliver input to the PV shim console. */ @@ -730,6 +748,7 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(= char) buffer, unsigned int flags =3D opt_console_to_ring ? CONSOLE_ALL : CONSOLE_DEFAULT; struct domain *cd =3D current->domain; + struct domain_console *cons =3D cd->console; =20 while ( count > 0 ) { @@ -742,18 +761,25 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARA= M(char) buffer, if ( copy_from_guest(kbuf, buffer, kcount) ) return -EFAULT; =20 - if ( is_hardware_domain(cd) ) + spin_lock(&cons->lock); + nrspin_lock_irq(&console_lock); + if ( is_focus_domain(cd) ) { + if ( cons->idx ) + { + console_send(cons->buf, cons->idx, flags); + cons->idx =3D 0; + } /* Use direct console output as it could be interactive */ - nrspin_lock_irq(&console_lock); console_send(kbuf, kcount, flags); nrspin_unlock_irq(&console_lock); + spin_unlock(&cons->lock); } else { char *kin =3D kbuf, *kout =3D kbuf, c; - struct domain_console *cons =3D cd->console; =20 + nrspin_unlock_irq(&console_lock); /* Strip non-printable characters */ do { @@ -765,7 +791,6 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(= char) buffer, } while ( --kcount > 0 ); =20 *kout =3D '\0'; - spin_lock(&cons->lock); kcount =3D kin - kbuf; if ( c !=3D '\n' && (cons->idx + (kout - kbuf) < (ARRAY_SIZE(cons->buf) - 1))= ) @@ -815,6 +840,13 @@ long do_console_io( if ( count > INT_MAX ) break; =20 + nrspin_lock_irq(&console_lock); + if ( !is_focus_domain(current->domain) ) + { + nrspin_unlock_irq(&console_lock); + return 0; + } + rc =3D 0; while ( (serial_rx_cons !=3D serial_rx_prod) && (rc < count) ) { @@ -824,14 +856,16 @@ long do_console_io( len =3D SERIAL_RX_SIZE - idx; if ( (rc + len) > count ) len =3D count - rc; + nrspin_unlock_irq(&console_lock); if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], le= n) ) - { - rc =3D -EFAULT; - break; - } + return -EFAULT; rc +=3D len; + nrspin_lock_irq(&console_lock); + if ( !is_focus_domain(current->domain) ) + break; serial_rx_cons +=3D len; } + nrspin_unlock_irq(&console_lock); break; default: rc =3D -ENOSYS; --=20 2.25.1