On 2014/6/19 17:45, Andre Przywara wrote: > With everything separated and prepared, we implement a model of a > GICv3 distributor and redistributors by using the existing framework > to provide handler functions for each register group. > Currently we limit the emulation to a model enforcing a single > security state, with SRE==1 (forcing system register access) and > ARE==1 (allowing more than 8 VCPUs). > We share some of functions provided for GICv2 emulation, but take > the different ways of addressing (v)CPUs into account. > Save and restore is currently not implemented. > > Similar to the split-off GICv2 specific code, the new emulation code > goes into a new file (vgic-v3-emul.c). > > Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> > + > +/* > + * triggered by a system register access trap, called from the sysregs > + * handling code there. > + * The register contains the upper three affinity levels of the target > + * processors as well as a bitmask of 16 Aff0 CPUs. > + * Iterate over all VCPUs to check for matching ones or signal on > + * all-but-self if the mode bit is set. > + */ > +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg) > +{ > + struct kvm *kvm = vcpu->kvm; > + struct kvm_vcpu *c_vcpu; > + struct vgic_dist *dist = &kvm->arch.vgic; > + u16 target_cpus; > + u64 mpidr, mpidr_h, mpidr_l; > + int sgi, mode, c, vcpu_id; > + int updated = 0; > + > + vcpu_id = vcpu->vcpu_id; > + > + sgi = (reg >> 24) & 0xf; > + mode = (reg >> 40) & 0x1; > + target_cpus = reg & 0xffff; > + mpidr = ((reg >> 48) & 0xff) << MPIDR_LEVEL_SHIFT(3); > + mpidr |= ((reg >> 32) & 0xff) << MPIDR_LEVEL_SHIFT(2); > + mpidr |= ((reg >> 16) & 0xff) << MPIDR_LEVEL_SHIFT(1); > + mpidr &= ~MPIDR_LEVEL_MASK; > + > + /* > + * We take the dist lock here, because we come from the sysregs > + * code path and not from MMIO (where this is already done) > + */ > + spin_lock(&dist->lock); > + kvm_for_each_vcpu(c, c_vcpu, kvm) { > + if (target_cpus == 0) > + break; I can't understand here ! First, when target_cpus == 0, if you want to break and return, it should take if (target_cpus == 0) break; code out of the loop, is it? Second, I think this case (target_cpus == 0) should be not break, when mode == 1, it should send SGI to all processors in the system, excluding itself.(spec 18) > + if (mode && c == vcpu_id) /* not to myself */ > + continue; Is there a mistake? for example: vcpu3 want to send sgi to all *other* vcpu, but , it will send SGI to all vcpu, *INCLUDE* vcpu3. > + if (!mode) { > + mpidr_h = kvm_vcpu_get_mpidr(c_vcpu); > + mpidr_l = MPIDR_AFFINITY_LEVEL(mpidr_h, 0); > + mpidr_h &= ~MPIDR_LEVEL_MASK; > + if (mpidr != mpidr_h) > + continue; > + if (!(target_cpus & BIT(mpidr_l))) > + continue; > + target_cpus &= ~BIT(mpidr_l); > + } > + /* Flag the SGI as pending */ > + vgic_dist_irq_set(c_vcpu, sgi); > + updated = 1; > + kvm_debug("SGI%d from CPU%d to CPU%d\n", sgi, vcpu_id, c); > + } > + if (updated) > + vgic_update_state(vcpu->kvm); > + spin_unlock(&dist->lock); > + if (updated) > + vgic_kick_vcpus(vcpu->kvm); > +} > diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h > index 9078e2a..f24cdd0 100644 > --- a/virt/kvm/arm/vgic.h > +++ b/virt/kvm/arm/vgic.h > @@ -34,6 +34,8 @@ > > #define VCPU_NOT_ALLOCATED ((u8)-1) > > +#define VCPU_NOT_ALLOCATED ((u8)-1) This are two same defines... > + > unsigned long *vgic_bitmap_get_shared_map(struct vgic_bitmap *x); > > void vgic_update_state(struct kvm *kvm); > @@ -112,3 +114,4 @@ int vgic_set_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr); > int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr); > > bool vgic_v2_init_emulation_ops(struct kvm *kvm, int type); > +bool vgic_v3_init_emulation_ops(struct kvm *kvm, int type); > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c > index 4b6c01b..c2fac5d 100644 > --- a/virt/kvm/kvm_main.c > +++ b/virt/kvm/kvm_main.c > @@ -2286,6 +2286,9 @@ static int kvm_ioctl_create_device(struct kvm *kvm, > case KVM_DEV_TYPE_ARM_VGIC_V2: > ops = &kvm_arm_vgic_v2_ops; > break; > + case KVM_DEV_TYPE_ARM_VGIC_V3: > + ops = &kvm_arm_vgic_v3_ops; > + break; > #endif > #ifdef CONFIG_S390 > case KVM_DEV_TYPE_FLIC: _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm