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

[PATCH v2 1/3] xen/arm: Add emulation of Debug Data Transfer Registers


  • To: <julien@xxxxxxx>, <ayan.kumar.halder@xxxxxxx>, <sstabellini@xxxxxxxxxx>, <bertrand.marquis@xxxxxxx>, <michal.orzel@xxxxxxx>, <Volodymyr_Babchuk@xxxxxxxx>, <stefano.stabellini@xxxxxxx>
  • From: <michal.orzel@xxxxxxx>
  • Date: Mon, 18 Dec 2023 20:32:42 +0000
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=xen.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=v534rtDojDtHFqs8XoTePK1ktvHssbuLWOgqwn7Byv0=; b=bXW6aHPO8Mfw7+E96n9bTpUOxcH1TNmWXpxO1AU5xxKLhYydl6dKtyJk7yYseLTVwB6Upjdr5+4NiB/4xfDgwvsF4IuPoC7TlOpiwuHGz8CGIL5vfvSCZ4NU/XnbuSn9TeBZsZoVrYDDSPAAwUs/Y2g6Feh59Zn6/rkPNKbLYQaJ16p5klaIGSuRl8XNEb+G/OhZoUZLS+B9VgYw2mhlyWHh2Z8LEZIbCUNWcRAQNtVEglqiNn48WTg2pHQKqgdCuYyhZROBwKDXorKJJd/AEjvB2UGYGlO0ly5/NqJ466Toc/6XM5KqwbDeLbw5uyrEZBwytCkny9rlLAf+50B1qQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=MmIJNx2aAduUVu8CDplXRU1r9CSmC0j7pGsae0b+6i3urGy7dSefOQ8vKl6howTjF5/2Aui16LZCc0Qa3tB6ccMhc8NV/3iujkn3uchattY9OVvtyNNSIWFKbDyOP+EzpcBszyIzN6T52678QZKX1cP9YHBxRt2Vuo+xSkPq0jge0z+aPAaIMudEa1NvKgwTreOmr1Q35cnb2V2GREMzYYgk87T2YMCtg3HZvawxxdBWO4AMgVx+sdViFhGGv4EPjdBkN/t3qmDB8fng/c4D22geOILmjLVF+xJ18EIDz3SX1XTNLwreS7vvyK/lXW2TDvvJB2uipkEixqHOzaSmnw==
  • Cc: <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • Delivery-date: Mon, 18 Dec 2023 20:33:17 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

From: Michal Orzel <michal.orzel@xxxxxxx>

Currently if user enables HVC_DCC config option in Linux, it invokes
access to debug data transfer registers (ie MDCCSR_EL0 on arm64,
DBGDTRTXINT on arm32). As these registers are not emulated, Xen injects
an undefined exception to the guest. And Linux crashes.

We wish to avoid this crash by adding a "partial" emulation. DBGDTR_EL0
is emulated as TXfull.
Refer ARM DDI 0487I.a ID081822, D17.3.8, DBGDTRTX_EL0
"If TXfull is set to 1, set DTRRX and DTRTX to UNKNOWN"

Thus, any OS is expected to read DBGDTR_EL0 and check for TXfull
before using DBGDTRTX_EL0. Linux does it via hvc_dcc_init() --->
hvc_dcc_check() , it returns -ENODEV. In this way, we are preventing
the guest to be aborted.

We also emulate DBGDTRTX_EL0 as RAZ/WI.

We have added emulation for AArch32 variant of these registers as well.

Also in the case of AArch32, DBGOSLSR is emulated in the same way as
its AArch64 variant (ie OSLSR_EL1). This is to ensure that
DBGOSLSR.OSLK is 0, thus MDSCR_EL1.TXfull is treated as UNK/SBZP.
Thus only MDCCSR_EL0 can be emulated (which is DBGDTRTXINT on arm32).
So, DBGDTR[TR]XINT is emulated as RAZ/WI.

Signed-off-by: Michal Orzel <michal.orzel@xxxxxxx>
Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@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.

 xen/arch/arm/arm64/vsysreg.c         | 26 +++++++++++++++----
 xen/arch/arm/include/asm/arm64/hsr.h |  3 +++
 xen/arch/arm/include/asm/cpregs.h    |  2 ++
 xen/arch/arm/include/asm/traps.h     |  4 +++
 xen/arch/arm/traps.c                 | 18 +++++++++++++
 xen/arch/arm/vcpreg.c                | 38 +++++++++++++++++++++++-----
 6 files changed, 79 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/arm64/vsysreg.c b/xen/arch/arm/arm64/vsysreg.c
index b5d54c569b..ebeb83dd65 100644
--- a/xen/arch/arm/arm64/vsysreg.c
+++ b/xen/arch/arm/arm64/vsysreg.c
@@ -159,9 +159,6 @@ void do_sysreg(struct cpu_user_regs *regs,
      *
      * Unhandled:
      *    MDCCINT_EL1
-     *    DBGDTR_EL0
-     *    DBGDTRRX_EL0
-     *    DBGDTRTX_EL0
      *    OSDTRRX_EL1
      *    OSDTRTX_EL1
      *    OSECCR_EL1
@@ -172,11 +169,29 @@ void do_sysreg(struct cpu_user_regs *regs,
     case HSR_SYSREG_MDSCR_EL1:
         return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
     case HSR_SYSREG_MDCCSR_EL0:
+    {
         /*
+         * 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. By setting TX status bit to indicate the transmit 
buffer
+         * is full. This we would hint the OS that the DCC is probably not
+         * working.
+         *
+         * Bit 29: TX full
+         *
          * Accessible at EL0 only if MDSCR_EL1.TDCC is set to 0. We emulate 
that
          * register as RAZ/WI above. So RO at both EL0 and EL1.
          */
-        return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0);
+        return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 0,
+                                  1U << 29);
+    }
+    case HSR_SYSREG_DBGDTR_EL0:
+    /* DBGDTR[TR]X_EL0 share the same encoding */
+    case HSR_SYSREG_DBGDTRTX_EL0:
+        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 0);
     HSR_SYSREG_DBG_CASES(DBGBVR):
     HSR_SYSREG_DBG_CASES(DBGBCR):
     HSR_SYSREG_DBG_CASES(DBGWVR):
@@ -393,7 +408,8 @@ void do_sysreg(struct cpu_user_regs *regs,
      *
      * And all other unknown registers.
      */
-    default:
+    default: goto fail;
+    fail:
         {
             const struct hsr_sysreg sysreg = hsr.sysreg;
 
diff --git a/xen/arch/arm/include/asm/arm64/hsr.h 
b/xen/arch/arm/include/asm/arm64/hsr.h
index e691d41c17..1495ccddea 100644
--- a/xen/arch/arm/include/asm/arm64/hsr.h
+++ b/xen/arch/arm/include/asm/arm64/hsr.h
@@ -47,6 +47,9 @@
 #define HSR_SYSREG_OSDLR_EL1      HSR_SYSREG(2,0,c1,c3,4)
 #define HSR_SYSREG_DBGPRCR_EL1    HSR_SYSREG(2,0,c1,c4,4)
 #define HSR_SYSREG_MDCCSR_EL0     HSR_SYSREG(2,3,c0,c1,0)
+#define HSR_SYSREG_DBGDTR_EL0     HSR_SYSREG(2,3,c0,c4,0)
+#define HSR_SYSREG_DBGDTRTX_EL0   HSR_SYSREG(2,3,c0,c5,0)
+#define HSR_SYSREG_DBGDTRRX_EL0   HSR_SYSREG(2,3,c0,c5,0)
 
 #define HSR_SYSREG_DBGBVRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,4)
 #define HSR_SYSREG_DBGBCRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,5)
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/include/asm/traps.h b/xen/arch/arm/include/asm/traps.h
index 883dae368e..a2692722d5 100644
--- a/xen/arch/arm/include/asm/traps.h
+++ b/xen/arch/arm/include/asm/traps.h
@@ -56,6 +56,10 @@ void handle_ro_raz(struct cpu_user_regs *regs, int regidx, 
bool read,
 void handle_ro_read_val(struct cpu_user_regs *regs, int regidx, bool read,
                         const union hsr hsr, int min_el, register_t val);
 
+/* Read only as value provided with 'val' argument, write ignore */
+void handle_read_val_wi(struct cpu_user_regs *regs, int regidx,
+                        const union hsr hsr, int min_el, register_t val);
+
 /* Co-processor registers emulation (see arch/arm/vcpreg.c). */
 void do_cp15_32(struct cpu_user_regs *regs, const union hsr hsr);
 void do_cp15_64(struct cpu_user_regs *regs, const union hsr hsr);
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 3784e8276e..f5ab555b19 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1676,6 +1676,24 @@ void handle_ro_read_val(struct cpu_user_regs *regs,
     advance_pc(regs, hsr);
 }
 
+/* Read as value provided with 'val' argument of this function, write ignore */
+void handle_read_val_wi(struct cpu_user_regs *regs,
+                        int regidx,
+                        const union hsr hsr,
+                        int min_el,
+                        register_t val)
+{
+    ASSERT((min_el == 0) || (min_el == 1));
+
+    if ( min_el > 0 && regs_mode_is_user(regs) )
+        return inject_undef_exception(regs, hsr);
+
+    set_user_reg(regs, regidx, val);
+
+    advance_pc(regs, hsr);
+}
+
+
 /* Read only as read as zero */
 void handle_ro_raz(struct cpu_user_regs *regs,
                    int regidx,
diff --git a/xen/arch/arm/vcpreg.c b/xen/arch/arm/vcpreg.c
index 39aeda9dab..5087125111 100644
--- a/xen/arch/arm/vcpreg.c
+++ b/xen/arch/arm/vcpreg.c
@@ -549,18 +549,41 @@ void do_cp14_32(struct cpu_user_regs *regs, const union 
hsr hsr)
     }
 
     case HSR_CPREG32(DBGDSCRINT):
+    {
         /*
-         * Read-only register. Accessible by EL0 if DBGDSCRext.UDCCdis
-         * is set to 0, which we emulated below.
+         * 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. By setting TX status bit to indicate the transmit 
buffer
+         * is full. This we would hint the OS that the DCC is probably not
+         * working.
+         *
+         * Bit 29: TX full
+         *
+         * Accessible by EL0 if DBGDSCRext.UDCCdis is set to 0, which we 
emulate
+         * as RAZ/WI in the next case.
          */
-        return handle_ro_raz(regs, regidx, cp32.read, hsr, 1);
+
+        return handle_ro_read_val(regs, regidx, cp32.read, hsr, 0, 1 << 29);
+    }
 
     case HSR_CPREG32(DBGDSCREXT):
+        return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
+
+    case HSR_CPREG32(DBGOSLSR):
+         return handle_ro_read_val(regs, regidx, cp32.read, hsr, 1, 1 << 3);
+
+    case HSR_CPREG32(DBGDTRTXINT):
+    {
         /*
-         * Implement debug status and control register as RAZ/WI.
-         * The OS won't use Hardware debug if MDBGen not set.
+         * As DBGDSCRINT is emulated which is architecturally mapped to AArch64
+         * register MDCCSR_EL0. MDSCR_EL1 is not emulated. So DBGDTR[TR]XINT 
can
+         * only be accessed as EL0 level.
          */
-        return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
+        return handle_raz_wi(regs, regidx, cp32.read, hsr, 0);
+    }
 
     case HSR_CPREG32(DBGVCR):
     case HSR_CPREG32(DBGBVR0):
@@ -590,7 +613,8 @@ void do_cp14_32(struct cpu_user_regs *regs, const union hsr 
hsr)
      *
      * And all other unknown registers.
      */
-    default:
+    default: goto fail;
+    fail:
         gdprintk(XENLOG_ERR,
                  "%s p14, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister"\n",
                   cp32.read ? "mrc" : "mcr",
-- 
2.25.1




 


Rackspace

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