[PATCH for-4.22] xen/arm: derive GIC CPU interface ID fields from the vGIC

Mykola Kvach posted 1 patch 1 week, 6 days ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/ba4f779d68c54efc80c4a566dca38ac2e6f9a073.1783675708.git.mykola._5Fkvach@epam.com
xen/arch/arm/arm64/vsysreg.c | 35 ++++++++++++++++++++++++++++++++++-
xen/arch/arm/vcpreg.c        | 25 ++++++++++++++++++++++++-
2 files changed, 58 insertions(+), 2 deletions(-)
[PATCH for-4.22] xen/arm: derive GIC CPU interface ID fields from the vGIC
Posted by Mykola Kvach 1 week, 6 days ago
Xen exposes ID_AA64PFR0_EL1.GIC and ID_PFR1.GIC from
domain_cpuinfo, which is initialized from the sanitized host CPU feature
state. This does not necessarily match the virtual interrupt controller
configured for a domain.

On a GICv3 or newer host, a vGICv2 domain can observe a nonzero GIC
field even though Xen disables EL1 access to the GIC CPU system register
interface for that domain. On a GICv4.1 host, a vGICv3 domain can
observe encoding 0b0011, which advertises GICv4.1 CPU interface support
that Xen's vGICv3 model does not expose.

Derive both fields from d->arch.vgic.version in every trap path. Expose
0b0000 for vGICv2 and 0b0001 for vGICv3. This covers
ID_AA64PFR0_EL1 and the ID_PFR1_EL1 alias in AArch64 state, as well as
ID_PFR1 accessed through CP15 in AArch32 state.

This is consistent with KVM, which derives both ID fields from the
configured virtual GIC model.

Fixes: 07b9acea116e ("xen/arm: Add handler for ID registers on arm64")
Fixes: 8f81064a07c6 ("xen/arm: Add handler for cp15 ID registers")
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
---
 xen/arch/arm/arm64/vsysreg.c | 35 ++++++++++++++++++++++++++++++++++-
 xen/arch/arm/vcpreg.c        | 25 ++++++++++++++++++++++++-
 2 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/arm64/vsysreg.c b/xen/arch/arm/arm64/vsysreg.c
index d14258290f..6b898f13f3 100644
--- a/xen/arch/arm/arm64/vsysreg.c
+++ b/xen/arch/arm/arm64/vsysreg.c
@@ -21,6 +21,7 @@
 #include <asm/arm64/cpufeature.h>
 #include <asm/arm64/sve.h>
 #include <asm/current.h>
+#include <asm/gic.h>
 #include <asm/regs.h>
 #include <asm/traps.h>
 #include <asm/vreg.h>
@@ -79,6 +80,24 @@ TVM_REG(CONTEXTIDR_EL1)
                                   1, domain_cpuinfo.field.bits[offset]); \
     }
 
+#define ID_REG_GIC_WIDTH 4
+
+static unsigned int vgic_id_gic_field(const struct domain *d)
+{
+    ASSERT(d->arch.vgic.version == GIC_V2 ||
+           d->arch.vgic.version == GIC_V3);
+
+    return d->arch.vgic.version == GIC_V3;
+}
+
+static register_t id_reg_set_gic_field(register_t val, unsigned int shift,
+                                       const struct domain *d)
+{
+    register_t mask = GENMASK(shift + ID_REG_GIC_WIDTH - 1, shift);
+
+    return (val & ~mask) | ((register_t)vgic_id_gic_field(d) << shift);
+}
+
 void do_sysreg(struct cpu_user_regs *regs,
                const union hsr hsr)
 {
@@ -304,7 +323,17 @@ void do_sysreg(struct cpu_user_regs *regs,
      * to identify the processor features
      */
     GENERATE_TID3_INFO(ID_PFR0_EL1, pfr32, 0)
-    GENERATE_TID3_INFO(ID_PFR1_EL1, pfr32, 1)
+    case HSR_SYSREG_ID_PFR1_EL1:
+    {
+        register_t guest_reg_value = domain_cpuinfo.pfr32.bits[1];
+
+        guest_reg_value = id_reg_set_gic_field(guest_reg_value,
+                                               ID_PFR1_GIC_SHIFT,
+                                               v->domain);
+
+        return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 1,
+                                  guest_reg_value);
+    }
     GENERATE_TID3_INFO(ID_PFR2_EL1, pfr32, 2)
     GENERATE_TID3_INFO(ID_DFR0_EL1, dbg32, 0)
     GENERATE_TID3_INFO(ID_DFR1_EL1, dbg32, 1)
@@ -343,6 +372,10 @@ void do_sysreg(struct cpu_user_regs *regs,
             guest_reg_value |= (sysval << ID_AA64PFR0_SVE_SHIFT) & mask;
         }
 
+        guest_reg_value = id_reg_set_gic_field(guest_reg_value,
+                                               ID_AA64PFR0_GIC_SHIFT,
+                                               v->domain);
+
         return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 1,
                                   guest_reg_value);
     }
diff --git a/xen/arch/arm/vcpreg.c b/xen/arch/arm/vcpreg.c
index e7c484f2c1..88351b91d3 100644
--- a/xen/arch/arm/vcpreg.c
+++ b/xen/arch/arm/vcpreg.c
@@ -12,6 +12,7 @@
 #include <asm/cpufeature.h>
 #include <asm/cpregs.h>
 #include <asm/current.h>
+#include <asm/gic.h>
 #include <asm/regs.h>
 #include <asm/traps.h>
 #include <asm/vreg.h>
@@ -173,6 +174,17 @@ TVM_REG32(CONTEXTIDR, CONTEXTIDR_EL1)
                                   domain_cpuinfo.field.bits[offset]);\
     }
 
+#define ID_PFR1_GIC_SHIFT 28
+#define ID_REG_GIC_WIDTH 4
+
+static unsigned int vgic_id_gic_field(const struct domain *d)
+{
+    ASSERT(d->arch.vgic.version == GIC_V2 ||
+           d->arch.vgic.version == GIC_V3);
+
+    return d->arch.vgic.version == GIC_V3;
+}
+
 /* helper to define cases for all registers for one CRm value */
 #define HSR_CPREG32_TID3_CASES(REG)     case HSR_CPREG32(p15,0,c0,REG,0): \
                                         case HSR_CPREG32(p15,0,c0,REG,1): \
@@ -321,7 +333,18 @@ void do_cp15_32(struct cpu_user_regs *regs, const union hsr hsr)
      * to identify the processor features
      */
     GENERATE_TID3_INFO(ID_PFR0, pfr32, 0)
-    GENERATE_TID3_INFO(ID_PFR1, pfr32, 1)
+    case HSR_CPREG32(ID_PFR1):
+    {
+        register_t guest_reg_value = domain_cpuinfo.pfr32.bits[1];
+
+        guest_reg_value &= ~GENMASK(ID_PFR1_GIC_SHIFT + ID_REG_GIC_WIDTH - 1,
+                                    ID_PFR1_GIC_SHIFT);
+        guest_reg_value |= (register_t)vgic_id_gic_field(v->domain) <<
+                           ID_PFR1_GIC_SHIFT;
+
+        return handle_ro_read_val(regs, regidx, cp32.read, hsr, 1,
+                                  guest_reg_value);
+    }
     GENERATE_TID3_INFO(ID_PFR2, pfr32, 2)
     GENERATE_TID3_INFO(ID_DFR0, dbg32, 0)
     GENERATE_TID3_INFO(ID_DFR1, dbg32, 1)
-- 
2.43.0
Re: [PATCH for-4.22] xen/arm: derive GIC CPU interface ID fields from the vGIC
Posted by Orzel, Michal 1 day, 9 hours ago

On 10-Jul-26 11:31, Mykola Kvach wrote:
> Xen exposes ID_AA64PFR0_EL1.GIC and ID_PFR1.GIC from
> domain_cpuinfo, which is initialized from the sanitized host CPU feature
> state. This does not necessarily match the virtual interrupt controller
> configured for a domain.
> 
> On a GICv3 or newer host, a vGICv2 domain can observe a nonzero GIC
> field even though Xen disables EL1 access to the GIC CPU system register
> interface for that domain. On a GICv4.1 host, a vGICv3 domain can
> observe encoding 0b0011, which advertises GICv4.1 CPU interface support
> that Xen's vGICv3 model does not expose.
> 
> Derive both fields from d->arch.vgic.version in every trap path. Expose
> 0b0000 for vGICv2 and 0b0001 for vGICv3. This covers
> ID_AA64PFR0_EL1 and the ID_PFR1_EL1 alias in AArch64 state, as well as
> ID_PFR1 accessed through CP15 in AArch32 state.
> 
> This is consistent with KVM, which derives both ID fields from the
> configured virtual GIC model.
> 
> Fixes: 07b9acea116e ("xen/arm: Add handler for ID registers on arm64")
> Fixes: 8f81064a07c6 ("xen/arm: Add handler for cp15 ID registers")
> Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
> ---
>  xen/arch/arm/arm64/vsysreg.c | 35 ++++++++++++++++++++++++++++++++++-
>  xen/arch/arm/vcpreg.c        | 25 ++++++++++++++++++++++++-
>  2 files changed, 58 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/arm64/vsysreg.c b/xen/arch/arm/arm64/vsysreg.c
> index d14258290f..6b898f13f3 100644
> --- a/xen/arch/arm/arm64/vsysreg.c
> +++ b/xen/arch/arm/arm64/vsysreg.c
> @@ -21,6 +21,7 @@
>  #include <asm/arm64/cpufeature.h>
>  #include <asm/arm64/sve.h>
>  #include <asm/current.h>
> +#include <asm/gic.h>
>  #include <asm/regs.h>
>  #include <asm/traps.h>
>  #include <asm/vreg.h>
> @@ -79,6 +80,24 @@ TVM_REG(CONTEXTIDR_EL1)
>                                    1, domain_cpuinfo.field.bits[offset]); \
>      }
>  
> +#define ID_REG_GIC_WIDTH 4
> +
> +static unsigned int vgic_id_gic_field(const struct domain *d)
> +{
> +    ASSERT(d->arch.vgic.version == GIC_V2 ||
NIT: Put brackets around individual expressions

> +           d->arch.vgic.version == GIC_V3);
> +
> +    return d->arch.vgic.version == GIC_V3;
> +}
> +
> +static register_t id_reg_set_gic_field(register_t val, unsigned int shift,
> +                                       const struct domain *d)
> +{
> +    register_t mask = GENMASK(shift + ID_REG_GIC_WIDTH - 1, shift);
> +
> +    return (val & ~mask) | ((register_t)vgic_id_gic_field(d) << shift);
> +}
vgic_id_gic_field() and ID_REG_GIC_WIDTH are copied 1:1 into vcpreg.c,
and vcpreg.c open-codes the mask/insert that id_reg_set_gic_field() already
provides. Please factor the shared logic into one place that both files include.

~Michal
Re: [PATCH for-4.22] xen/arm: derive GIC CPU interface ID fields from the vGIC
Posted by Oleksii Kurochko 1 week, 3 days ago

On 7/10/26 11:31 AM, Mykola Kvach wrote:
> Xen exposes ID_AA64PFR0_EL1.GIC and ID_PFR1.GIC from
> domain_cpuinfo, which is initialized from the sanitized host CPU feature
> state. This does not necessarily match the virtual interrupt controller
> configured for a domain.
> 
> On a GICv3 or newer host, a vGICv2 domain can observe a nonzero GIC
> field even though Xen disables EL1 access to the GIC CPU system register
> interface for that domain. On a GICv4.1 host, a vGICv3 domain can
> observe encoding 0b0011, which advertises GICv4.1 CPU interface support
> that Xen's vGICv3 model does not expose.
> 
> Derive both fields from d->arch.vgic.version in every trap path. Expose
> 0b0000 for vGICv2 and 0b0001 for vGICv3. This covers
> ID_AA64PFR0_EL1 and the ID_PFR1_EL1 alias in AArch64 state, as well as
> ID_PFR1 accessed through CP15 in AArch32 state.
> 
> This is consistent with KVM, which derives both ID fields from the
> configured virtual GIC model.
> 
> Fixes: 07b9acea116e ("xen/arm: Add handler for ID registers on arm64")
> Fixes: 8f81064a07c6 ("xen/arm: Add handler for cp15 ID registers")
> Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
> ---

Considering that patches mentioned in Fixes are from 2020 it doesn't 
like that the bug is too critical unless maintainers tell that we have 
to take it I think it would be better to postpone the patch until 4.22 
release.

Thanks.

~ Oleksii