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

[XEN PATCH v2 08/25] arm: new VGIC: Add GICv3 SGI system register trap handler


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>
  • Date: Fri, 10 Nov 2023 12:56:18 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • 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=CsuUkMvf5gI06/kh6Aitv9g+GlzsqEZAOIWBAFgXeMY=; b=bZxCZQy/qzCEKWnbvx2bGBXUxp6XfIMBiVn5vKUByHC7Le5zVjGXewyAlPIKAsVdmgsJywZsZRUj6NCS0Ohhf8sdpROWEZjN+G3yybbuDo617Md0NVmLbw42XWpOBuzW822XutQTEpzPqL2TiIOzd98WrAxU2JTRuGjhNTf+Qe3jQN3V2rScBgSoDk2Y/MOxfEdWadgeznd0owZFkkDdcchCi7o1ZY3E8Gs22PwiI+4T7G8FfbG2fl/yit8mi3NYf7wGNQH1Matuck8INIKc/QsJvq1qUw5sBg2xsoEOKudlaOIODqp6ZLemeVeckuY9cOcM0PO0U1A+SPCeEJXoGA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=RDoMlsltv1Id5HvBr6cJHeq4tVbHIE0zBAXvg5Qfy/oidW93shzwlOyqDmik3oRqdi29W16GlJngUIeWkg2ya62JDWAB94QN2UDKWmZMyPRDJ2mCFqmvF6HU9N1v6mgPUgQ41aP4cFenJDvaE4/j+FCFaAlOPrBi1K7YWNaToHDZKmhOFEXbxj/D6Ba9MlM56xDZf/deDqgmsoPaU2iDTDHVXGeFE/aPVknurNJUuV0N1W614ONSOI9T7yvZI8Thnp1yQkYgFmPON+TkV45KyL10PK4ZzqKLib/Ycjaepy6KHYAxW0IuA2xYHahjxkPsK+O3kHzNbEkf3LwcMFqJ3A==
  • Cc: Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>
  • Delivery-date: Fri, 10 Nov 2023 12:56:55 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHaE9VMyTFmCIij9kWiuYpeUQUfzA==
  • Thread-topic: [XEN PATCH v2 08/25] arm: new VGIC: Add GICv3 SGI system register trap handler

In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
by a MMIO write, but with a system register write. Xen knows about
that register already, we just need to implement the handler and wire
it up to the core Xen/ARM code.

Base on Linux commit 621ecd8d2123bc13 by Andre Przywara

Signed-off-by: Mykyta Poturai <mykyta_poturai@xxxxxxxx>
---
 xen/arch/arm/include/asm/gic_v3_defs.h |   2 +-
 xen/arch/arm/vgic/vgic-mmio-v3.c       | 147 +++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.c               |  10 +-
 xen/arch/arm/vgic/vgic.h               |   5 +
 4 files changed, 160 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/include/asm/gic_v3_defs.h 
b/xen/arch/arm/include/asm/gic_v3_defs.h
index e0d536e887..1e81687818 100644
--- a/xen/arch/arm/include/asm/gic_v3_defs.h
+++ b/xen/arch/arm/include/asm/gic_v3_defs.h
@@ -204,7 +204,7 @@
 #define ICH_SGI_IRQ_SHIFT            24
 #define ICH_SGI_IRQ_MASK             0xf
 #define ICH_SGI_TARGETLIST_MASK      0xffff
-#define ICH_SGI_AFFx_MASK            0xff
+#define ICH_SGI_AFFx_MASK            0xffULL
 #define ICH_SGI_AFFINITY_LEVEL(x)    (16 * (x))
 
 struct rdist_region {
diff --git a/xen/arch/arm/vgic/vgic-mmio-v3.c b/xen/arch/arm/vgic/vgic-mmio-v3.c
index 3d892a68cb..19ebf723ee 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v3.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v3.c
@@ -42,6 +42,153 @@ unsigned long extract_bytes(uint64_t data, unsigned int 
offset,
     return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
 }
 
+static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct vcpu *vcpu)
+{
+    unsigned long affinity;
+    int level0;
+
+    /*
+     * Split the current VCPU's MPIDR into affinity level 0 and the
+     * rest as this is what we have to compare against.
+     */
+    affinity = vcpuid_to_vaffinity(vcpu->vcpu_id);
+    level0   = MPIDR_AFFINITY_LEVEL(affinity, 0);
+    affinity &= ~MPIDR_LEVEL_MASK;
+
+    /* bail out if the upper three levels don't match */
+    if ( sgi_aff != affinity )
+        return -1;
+
+    /* Is this VCPU's bit set in the mask ? */
+    if ( !(sgi_cpu_mask & BIT(level0, ULL)) )
+        return -1;
+
+    return level0;
+}
+
+#define SGI_AFFINITY_LEVEL(reg, level)                                         
\
+    ((((reg) & (ICH_SGI_AFFx_MASK << ICH_SGI_AFFINITY_LEVEL(level))) >>        
\
+      ICH_SGI_AFFINITY_LEVEL(level))                                           
\
+     << MPIDR_LEVEL_SHIFT(level))
+
+static bool vgic_v3_emulate_sgi1r(struct cpu_user_regs *regs, uint64_t *r,
+                                  bool read)
+{
+    struct domain *d  = current->domain;
+    struct vcpu *vcpu = current;
+    struct vcpu *c_vcpu;
+    u16 target_cpus;
+    u64 mpidr;
+    int sgi;
+    int vcpu_id = vcpu->vcpu_id;
+    bool broadcast;
+    unsigned long flags;
+
+    if ( read )
+    {
+        gdprintk(XENLOG_WARNING, "Reading SGI1R_EL1 - WO register\n");
+        return false;
+    }
+
+    sgi         = (*r >> ICH_SGI_IRQ_SHIFT) & ICH_SGI_IRQ_MASK;
+    broadcast   = *r & BIT(ICH_SGI_IRQMODE_SHIFT, ULL);
+    target_cpus = (*r & ICH_SGI_TARGETLIST_MASK);
+
+    mpidr  = SGI_AFFINITY_LEVEL(*r, 3);
+    mpidr |= SGI_AFFINITY_LEVEL(*r, 2);
+    mpidr |= SGI_AFFINITY_LEVEL(*r, 1);
+
+    /*
+     * We iterate over all VCPUs to find the MPIDRs matching the request.
+     * If we have handled one CPU, we clear its bit to detect early
+     * if we are already finished. This avoids iterating through all
+     * VCPUs when most of the times we just signal a single VCPU.
+     */
+    for_each_vcpu(d, c_vcpu)
+    {
+        struct vgic_irq *irq;
+
+        /* Exit early if we have dealt with all requested CPUs */
+        if ( !broadcast && target_cpus == 0 )
+            break;
+
+        /* Don't signal the calling VCPU */
+        if ( broadcast && c_vcpu->vcpu_id == vcpu_id )
+            continue;
+
+        if ( !broadcast )
+        {
+            int level0;
+
+            level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
+            if ( level0 == -1 )
+                continue;
+
+            /* remove this matching VCPU from the mask */
+            target_cpus &= ~BIT(level0, UL);
+        }
+
+        irq = vgic_get_irq(vcpu->domain, c_vcpu, sgi);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        if ( !irq->hw )
+        {
+            irq->pending_latch = true;
+            vgic_queue_irq_unlock(vcpu->domain, irq, flags);
+        }
+        else
+        {
+            printk(XENLOG_ERR "HW SGIs are not implemented\n");
+            BUG();
+            spin_unlock_irqrestore(&irq->irq_lock, flags);
+        }
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return true;
+}
+
+static bool vgic_v3_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
+{
+    struct hsr_sysreg sysreg = hsr.sysreg;
+
+    ASSERT(hsr.ec == HSR_EC_SYSREG);
+
+    if ( sysreg.read )
+        perfc_incr(vgic_sysreg_reads);
+    else
+        perfc_incr(vgic_sysreg_writes);
+
+    switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
+    {
+    case HSR_SYSREG_ICC_SGI1R_EL1:
+        return vreg_emulate_sysreg(regs, hsr, vgic_v3_emulate_sgi1r);
+
+    default:
+        return false;
+    }
+}
+
+bool vgic_v3_emulate_reg(struct cpu_user_regs *regs, union hsr hsr)
+{
+    switch ( hsr.ec )
+    {
+#ifdef CONFIG_ARM_64
+    case HSR_EC_SYSREG:
+        return vgic_v3_emulate_sysreg(regs, hsr);
+#endif
+    case HSR_EC_CP15_64:
+        printk(XENLOG_ERR
+               "vgic_v3_emulate_reg: HSR_EC_CP15_64 not implemented");
+        BUG();
+        break;
+    default:
+        return false;
+    }
+}
+
 /*
  * The Revision field in the IIDR have the following meanings:
  *
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 97ca827fc4..946877bbac 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -865,9 +865,13 @@ struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, 
struct vcpu *v,
 
 bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
 {
-    ASSERT(current->domain->arch.vgic.version == GIC_V3);
-
-    return false;
+    switch ( current->domain->arch.vgic.version )
+    {
+    case GIC_V3:
+        return vgic_v3_emulate_reg(regs, hsr);
+    default:
+        return false;
+    }
 }
 
 /*
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index b3bba7b5f3..0e0cf7b213 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -74,6 +74,7 @@ int vgic_register_dist_iodev(struct domain *d, gfn_t 
dist_base_fn,
 #ifdef CONFIG_GICV3
 void vgic_v3_fold_lr_state(struct vcpu *vcpu);
 void vgic_v3_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
+bool vgic_v3_emulate_reg(struct cpu_user_regs *regs, union hsr hsr);
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
 int vgic_v3_set_redist_base(struct domain *d, u32 index, u64 addr, u32 count);
 int vgic_register_redist_iodev(struct vcpu *vcpu);
@@ -88,6 +89,10 @@ static inline unsigned int vgic_v3_init_dist_iodev(struct 
vgic_io_device *dev)
 {
     return 0;
 }
+static inline bool vgic_v3_emulate_reg(struct cpu_user_regs *regs, union hsr 
hsr)
+{
+    return false;
+}
 static inline int vgic_v3_set_redist_base(struct domain *d, u32 index, u64 
addr, u32 count)
 {
     return 0;
-- 
2.34.1



 


Rackspace

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