[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[XEN v5 3/3] xen/arm: arm32: Add emulation of Debug Data Transfer Registers


  • To: <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Ayan Kumar Halder <ayan.kumar.halder@xxxxxxx>
  • Date: Tue, 20 Feb 2024 12:17:43 +0000
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=lists.xenproject.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=PhMwKyVo3kV6ClvTBpqbApB6tIudAzmtxwRqsvXdrFs=; b=BaMhWqkfMNVLZVPykLAlaaubHTtmeyarrZyNFWGYqf7qLJra9VMOuZ8cxyP34TIVYJ+5KtHpki7CA9Wd72gYP+DgxrPpSaRIQw/YQmipGVcKXwo5+PM8Ty/dB+OdT/W6VyEC89xhvkyMZp6HSvSOW7vZ/TC31h8SvYOnzIBBAGhAKaB7fLSFqXjozU9d7OMOjFqB9YxGadB8stL2Mon0KnHlRMuV4Dm/MDwGyyiFG1PS5MDMOSBdBjtfks/boxk0qo37ayw35jvxG177QRCOHD1HYYse3BtXgKCmaIyq3v9L0JZdY23ikEefn0ReOW7lrExJancaS0cxeuAl4R/S9Q==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=WSsUIBUGmcyd7LuDyoccMlqiRxnGzGDhK2hU3YOdVzJfr7TvsLcFxemCph24hJZaRDEFW638npeauQKY6esEiJ9oSwFQeTIR2g6+8GB1xBygjf0oq9J8EMYEJ3q7RaVXXO1TspQopaJYnInkJGKSa3O+bOa9zXWcqC9pGA241m5PZtEs4ebaD+VgpKGyA7dBUNOMscm3e5vcjTSyNr/LsqnwnUOe1VT5XQyItr9bd40ICufKG3Qs39dtOCTcakOlLr4594MWWNodAcM72DpnYpK+KTzPqdWQihsvLcK/32U4l487lOBde0O6w4JlEGbZVxUeR/4TyC92ZCvjnE3xtg==
  • Cc: <sstabellini@xxxxxxxxxx>, <stefano.stabellini@xxxxxxx>, <julien@xxxxxxx>, <Volodymyr_Babchuk@xxxxxxxx>, <bertrand.marquis@xxxxxxx>, <michal.orzel@xxxxxxx>, Ayan Kumar Halder <ayan.kumar.halder@xxxxxxx>
  • Delivery-date: Tue, 20 Feb 2024 12:19:24 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

When user enables HVC_DCC config option in Linux, it invokes access to debug
transfer register (i.e. DBGDTRTXINT). As this register is not emulated, Xen
injects an undefined exception to the guest and Linux crashes.
To prevent this crash, introduce a partial emulation of DBGDTRTXINT as RAZ/WI
and TXfull should be set to 1. So that Linux will see that TXfull is set, and
it will not thereafter access DBGDTRTXINT (it will access it at least once to
later check if TXfull is set).

As a pre-requisite, DBGOSLSR should be emulated in the same way as its AArch64
variant (ie OSLSR_EL1).
This is to ensure that DBGOSLSR.OSLK is 0, thus DBGDSCRINT.TXfull is treated
as UNK/SBZP. DBGOSLSR.OSLM[1] is set to 1 to mantain consistency with OSLSR_EL1.

Only DBGDSCRINT can be emulated. DBGDSCRINT can be accessed at EL0 as DBGDSCREXT
is emulated as RAZ (as DBGOSLSR.OSLK == 0). So, we took the opportunity to fix
the minimum EL for DBGDSCRINT.DBGDSCRINT.TXfull is set to 1.

Refer ARM DDI 0487J.a ID042523, G8.3.19, DBGDTRTXint
"If TXfull is set to 1, set DTRTX to UNKNOWN".
So, DBGDTR[TR]XINT is emulated as RAZ/WI.

Thus, any OS is expected to read DBGDSCRINT and check for TXfull before using
DBGDTRTXINT.

Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@xxxxxxx>
Reviewed-by: Michal Orzel <michal.orzel@xxxxxxx>
---
Changes from

v1 :- 1. DBGDTR_EL0 does not emulate RXfull. This is to avoid giving the OS any
indication that the RX buffer is full and is waiting to be read.

2. In Arm32, DBGOSLSR is emulated. Also DBGDTRTXINT is emulated at EL0 only.

3. Fixed the commit message and inline code comments.

v2 :- 1. Split the patch into two (separate patches for arm64 and arm32).
2. Fixed in line comments and style related issues.
3. Updated commit message to mention DBGDSCRINT handling.

v3 :- 1. The original emulation of DBGDSCRINT is retained when
'partial_emulation' is false.

2. If 'partial_emulation' is false, then access to DBGDTRTXINT will
lead to undefined exception.

v4 :- 1. Invoked "goto fail" from "default:" to ensure compliance with
MISRA 15.3.

 xen/arch/arm/include/asm/cpregs.h |  2 +
 xen/arch/arm/vcpreg.c             | 63 ++++++++++++++++++++++---------
 2 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/xen/arch/arm/include/asm/cpregs.h 
b/xen/arch/arm/include/asm/cpregs.h
index 6b083de204..aec9e8f329 100644
--- a/xen/arch/arm/include/asm/cpregs.h
+++ b/xen/arch/arm/include/asm/cpregs.h
@@ -75,6 +75,8 @@
 #define DBGDIDR         p14,0,c0,c0,0   /* Debug ID Register */
 #define DBGDSCRINT      p14,0,c0,c1,0   /* Debug Status and Control Internal */
 #define DBGDSCREXT      p14,0,c0,c2,2   /* Debug Status and Control External */
+#define DBGDTRRXINT     p14,0,c0,c5,0   /* Debug Data Transfer Register, 
Receive */
+#define DBGDTRTXINT     p14,0,c0,c5,0   /* Debug Data Transfer Register, 
Transmit */
 #define DBGVCR          p14,0,c0,c7,0   /* Vector Catch */
 #define DBGBVR0         p14,0,c0,c0,4   /* Breakpoint Value 0 */
 #define DBGBCR0         p14,0,c0,c0,5   /* Breakpoint Control 0 */
diff --git a/xen/arch/arm/vcpreg.c b/xen/arch/arm/vcpreg.c
index a2d0500704..1a2d79b818 100644
--- a/xen/arch/arm/vcpreg.c
+++ b/xen/arch/arm/vcpreg.c
@@ -493,11 +493,12 @@ void do_cp14_32(struct cpu_user_regs *regs, const union 
hsr hsr)
      * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58
      *
      * Unhandled:
-     *    DBGOSLSR
      *    DBGPRCR
      */
     case HSR_CPREG32(DBGOSLAR):
         return handle_wo_wi(regs, regidx, cp32.read, hsr, 1);
+    case HSR_CPREG32(DBGOSLSR):
+        return handle_ro_read_val(regs, regidx, cp32.read, hsr, 1, 1U << 3);
     case HSR_CPREG32(DBGOSDLR):
         return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
 
@@ -509,8 +510,6 @@ void do_cp14_32(struct cpu_user_regs *regs, const union hsr 
hsr)
      *
      * Unhandled:
      *    DBGDCCINT
-     *    DBGDTRRXint
-     *    DBGDTRTXint
      *    DBGWFAR
      *    DBGDTRTXext
      *    DBGDTRRXext,
@@ -548,12 +547,27 @@ void do_cp14_32(struct cpu_user_regs *regs, const union 
hsr hsr)
         break;
     }
 
+    /*
+     * Xen doesn't expose a real (or emulated) Debug Communications Channel
+     * (DCC) to a domain. Yet the Arm ARM implies this is not an optional
+     * feature. So some domains may start to probe it. For instance, the
+     * HVC_DCC driver in Linux (since f377775dc083 and at least up to v6.7),
+     * will try to write some characters and check if the transmit buffer has
+     * emptied.
+     */
     case HSR_CPREG32(DBGDSCRINT):
         /*
-         * Read-only register. Accessible by EL0 if DBGDSCRext.UDCCdis
-         * is set to 0, which we emulated below.
+         * By setting TX status bit (only if partial emulation is enabled) to
+         * indicate the transmit buffer is full, we would hint the OS that the
+         * DCC is probably not working.
+         *
+         * Bit 29: TX full
+         *
+         * Accessible at EL0 only if DBGDSCRext.UDCCdis is set to 0. We emulate
+         * this as RAZ/WI in the next case. So RO at both EL0 and EL1.
          */
-        return handle_ro_raz(regs, regidx, cp32.read, hsr, 1);
+        return handle_ro_read_val(regs, regidx, cp32.read, hsr, 0,
+                                  partial_emulation ? (1U << 29) : 0);
 
     case HSR_CPREG32(DBGDSCREXT):
         /*
@@ -562,6 +576,18 @@ void do_cp14_32(struct cpu_user_regs *regs, const union 
hsr hsr)
          */
         return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
 
+    /* DBGDTR[TR]XINT share the same encoding */
+    case HSR_CPREG32(DBGDTRTXINT):
+        /*
+         * Emulate as RAZ/WI (only if partial emulation is enabled) to prevent
+         * injecting undefined exception.
+         * Accessible at EL0 only if DBGDSCREXT is set to 0. We emulate that
+         * register as RAZ/WI.
+         */
+        if ( !partial_emulation )
+            goto fail;
+        return handle_raz_wi(regs, regidx, cp32.read, hsr, 0);
+
     case HSR_CPREG32(DBGVCR):
     case HSR_CPREG32(DBGBVR0):
     case HSR_CPREG32(DBGBCR0):
@@ -591,17 +617,21 @@ void do_cp14_32(struct cpu_user_regs *regs, const union 
hsr hsr)
      * And all other unknown registers.
      */
     default:
-        gdprintk(XENLOG_ERR,
-                 "%s p14, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister"\n",
-                  cp32.read ? "mrc" : "mcr",
-                  cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc);
-        gdprintk(XENLOG_ERR, "unhandled 32-bit cp14 access %#"PRIregister"\n",
-                 hsr.bits & HSR_CP32_REGS_MASK);
-        inject_undef_exception(regs, hsr);
-        return;
+        goto fail;
     }
 
     advance_pc(regs, hsr);
+    return;
+
+ fail:
+    gdprintk(XENLOG_ERR,
+             "%s p14, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister"\n",
+             cp32.read ? "mrc" : "mcr",
+             cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc);
+    gdprintk(XENLOG_ERR, "unhandled 32-bit cp14 access %#"PRIregister"\n",
+             hsr.bits & HSR_CP32_REGS_MASK);
+    inject_undef_exception(regs, hsr);
+    return;
 }
 
 void do_cp14_64(struct cpu_user_regs *regs, const union hsr hsr)
@@ -659,10 +689,7 @@ void do_cp14_dbg(struct cpu_user_regs *regs, const union 
hsr hsr)
      * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58
      *
      * Unhandled:
-     *    DBGDTRTXint
-     *    DBGDTRRXint
-     *
-     * And all other unknown registers.
+     * All unknown registers.
      */
     gdprintk(XENLOG_ERR,
              "%s p14, %d, r%d, r%d, cr%d @ 0x%"PRIregister"\n",
-- 
2.25.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.