Re: [PATCH 11/14] arm/arm64: KVM: add virtual GICv3 distributor emulation

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

 



Hi,

On 14/07/14 04:21, wanghaibin wrote:
> 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?

That is what it does, right? TBH, I don't understand your comment here.

> 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)

That is right, good catch. I added this line later as an optimization to
avoid iterating over all VCPUs after the single one requested has been
served. But mode needs to be taken into account.
I have the fix in my tree already.

> 
>> +		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.

Why that? If this is vcpu3 for instance then we will continue, meaning
skipping the rest of the loop which actually injects the SGI. So
all-but-self. Or am I missing something here?

> 
>> +		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...

Again well spotted. Will fix it.

Thanks for looking at the patches!

Regards,
Andre.

> 
>> +
>>  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
> 
_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm




[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux