Commit 49a1a2c7 authored by Marc Zyngier's avatar Marc Zyngier

KVM: arm64: vgic-v3: Advertise GICR_CTLR.{IR, CES} as a new GICD_IIDR revision

Since adversising GICR_CTLR.{IC,CES} is directly observable from
a guest, we need to make it selectable from userspace.

For that, bump the default GICD_IIDR revision and let userspace
downgrade it to the previous default. For GICv2, the two distributor
revisions are strictly equivalent.
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220405182327.205520-5-maz@kernel.org
parent 4645d11f
...@@ -319,7 +319,12 @@ int vgic_init(struct kvm *kvm) ...@@ -319,7 +319,12 @@ int vgic_init(struct kvm *kvm)
vgic_debug_init(kvm); vgic_debug_init(kvm);
dist->implementation_rev = 2; /*
* If userspace didn't set the GIC implementation revision,
* default to the latest and greatest. You know want it.
*/
if (!dist->implementation_rev)
dist->implementation_rev = KVM_VGIC_IMP_REV_LATEST;
dist->initialized = true; dist->initialized = true;
out: out:
......
...@@ -73,9 +73,13 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu, ...@@ -73,9 +73,13 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len, gpa_t addr, unsigned int len,
unsigned long val) unsigned long val)
{ {
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
u32 reg;
switch (addr & 0x0c) { switch (addr & 0x0c) {
case GIC_DIST_IIDR: case GIC_DIST_IIDR:
if (val != vgic_mmio_read_v2_misc(vcpu, addr, len)) reg = vgic_mmio_read_v2_misc(vcpu, addr, len);
if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK)
return -EINVAL; return -EINVAL;
/* /*
...@@ -87,8 +91,16 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu, ...@@ -87,8 +91,16 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu,
* migration from old kernels to new kernels with legacy * migration from old kernels to new kernels with legacy
* userspace. * userspace.
*/ */
vcpu->kvm->arch.vgic.v2_groups_user_writable = true; reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
return 0; switch (reg) {
case KVM_VGIC_IMP_REV_2:
case KVM_VGIC_IMP_REV_3:
vcpu->kvm->arch.vgic.v2_groups_user_writable = true;
dist->implementation_rev = reg;
return 0;
default:
return -EINVAL;
}
} }
vgic_mmio_write_v2_misc(vcpu, addr, len, val); vgic_mmio_write_v2_misc(vcpu, addr, len, val);
......
...@@ -155,13 +155,27 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu, ...@@ -155,13 +155,27 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
unsigned long val) unsigned long val)
{ {
struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
u32 reg;
switch (addr & 0x0c) { switch (addr & 0x0c) {
case GICD_TYPER2: case GICD_TYPER2:
case GICD_IIDR:
if (val != vgic_mmio_read_v3_misc(vcpu, addr, len)) if (val != vgic_mmio_read_v3_misc(vcpu, addr, len))
return -EINVAL; return -EINVAL;
return 0; return 0;
case GICD_IIDR:
reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK)
return -EINVAL;
reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
switch (reg) {
case KVM_VGIC_IMP_REV_2:
case KVM_VGIC_IMP_REV_3:
dist->implementation_rev = reg;
return 0;
default:
return -EINVAL;
}
case GICD_CTLR: case GICD_CTLR:
/* Not a GICv4.1? No HW SGIs */ /* Not a GICv4.1? No HW SGIs */
if (!kvm_vgic_global_state.has_gicv4_1) if (!kvm_vgic_global_state.has_gicv4_1)
...@@ -232,8 +246,13 @@ static unsigned long vgic_mmio_read_v3r_ctlr(struct kvm_vcpu *vcpu, ...@@ -232,8 +246,13 @@ static unsigned long vgic_mmio_read_v3r_ctlr(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len) gpa_t addr, unsigned int len)
{ {
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
unsigned long val;
val = atomic_read(&vgic_cpu->ctlr);
if (vgic_get_implementation_rev(vcpu) >= KVM_VGIC_IMP_REV_3)
val |= GICR_CTLR_IR | GICR_CTLR_CES;
return vgic_cpu->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0; return val;
} }
static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu, static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
......
...@@ -98,6 +98,11 @@ ...@@ -98,6 +98,11 @@
#define DEBUG_SPINLOCK_BUG_ON(p) #define DEBUG_SPINLOCK_BUG_ON(p)
#endif #endif
static inline u32 vgic_get_implementation_rev(struct kvm_vcpu *vcpu)
{
return vcpu->kvm->arch.vgic.implementation_rev;
}
/* Requires the irq_lock to be held by the caller. */ /* Requires the irq_lock to be held by the caller. */
static inline bool irq_is_pending(struct vgic_irq *irq) static inline bool irq_is_pending(struct vgic_irq *irq)
{ {
......
...@@ -231,6 +231,9 @@ struct vgic_dist { ...@@ -231,6 +231,9 @@ struct vgic_dist {
/* Implementation revision as reported in the GICD_IIDR */ /* Implementation revision as reported in the GICD_IIDR */
u32 implementation_rev; u32 implementation_rev;
#define KVM_VGIC_IMP_REV_2 2 /* GICv2 restorable groups */
#define KVM_VGIC_IMP_REV_3 3 /* GICv3 GICR_CTLR.{IW,CES,RWP} */
#define KVM_VGIC_IMP_REV_LATEST KVM_VGIC_IMP_REV_3
/* Userspace can write to GICv2 IGROUPR */ /* Userspace can write to GICv2 IGROUPR */
bool v2_groups_user_writable; bool v2_groups_user_writable;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment