Subject: [PATCH v3 18/19] arm/arm64: KVM: enable kernel side of GICv3 emulation

From: [email-masked] (Christoffer Dall)
Date: Mon, 10 Nov 2014 14:24:38 +0100

On Mon, Nov 10, 2014 at 12:19:09PM +0000, Andre Przywara wrote:
> Hej Christoffer,

  ^^^ Nice, Hej Andre,

> 
> On 07/11/14 16:07, Christoffer Dall wrote:
> > On Fri, Oct 31, 2014 at 05:26:53PM +0000, Andre Przywara wrote:
> >> With all the necessary GICv3 emulation code in place, we can now
> >> connect the code to the GICv3 backend in the kernel.
> >> The LR register handling is different depending on the emulated GIC
> >> model, so provide different implementations for each.
> >> Also allow non-v2-compatible GICv3 implementations (which don't
> >> provide MMIO regions for the virtual CPU interface in the DT), but
> >> restrict those hosts to use GICv3 guests only.
> > 
> > s/use/support/
> > 
> >>
> >> Signed-off-by: Andre Przywara <[email-masked]>
> >> ---
> >>  virt/kvm/arm/vgic-v3.c |  168 ++++++++++++++++++++++++++++++++++++------------
> >>  virt/kvm/arm/vgic.c    |    4 ++
> >>  2 files changed, 130 insertions(+), 42 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
> >> index ce50918..c0e901c 100644
> >> --- a/virt/kvm/arm/vgic-v3.c
> >> +++ b/virt/kvm/arm/vgic-v3.c
> >> @@ -34,6 +34,7 @@
> >>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> >>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
> >>  #define GICH_LR_PHYSID_CPUID		(7UL << GICH_LR_PHYSID_CPUID_SHIFT)
> >> +#define ICH_LR_VIRTUALID_MASK		(BIT_ULL(32) - 1)
> >>  
> >>  /*
> >>   * LRs are stored in reverse order in memory. make sure we index them
> >> @@ -43,7 +44,35 @@
> >>  
> >>  static u32 ich_vtr_el2;
> >>  
> >> -static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
> >> +static u64 sync_lr_val(u8 state)
> > 
> > is this lr_state_to_val ?
> > 
> >> +{
> >> +	u64 lr_val = 0;
> >> +
> >> +	if (state & LR_STATE_PENDING)
> >> +		lr_val |= ICH_LR_PENDING_BIT;
> >> +	if (state & LR_STATE_ACTIVE)
> >> +		lr_val |= ICH_LR_ACTIVE_BIT;
> >> +	if (state & LR_EOI_INT)
> >> +		lr_val |= ICH_LR_EOI;
> >> +
> >> +	return lr_val;
> >> +}
> >> +
> >> +static u8 sync_lr_state(u64 lr_val)
> > 
> > and lr_val_to_state ?
> > 
> > at least these sync names don't make much sense to me...
> > 
> >> +{
> >> +	u8 state = 0;
> >> +
> >> +	if (lr_val & ICH_LR_PENDING_BIT)
> >> +		state |= LR_STATE_PENDING;
> >> +	if (lr_val & ICH_LR_ACTIVE_BIT)
> >> +		state |= LR_STATE_ACTIVE;
> >> +	if (lr_val & ICH_LR_EOI)
> >> +		state |= LR_EOI_INT;
> >> +
> >> +	return state;
> >> +}
> >> +
> >> +static struct vgic_lr vgic_v2_on_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
> >>  {
> >>  	struct vgic_lr lr_desc;
> >>  	u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)];
> >> @@ -53,30 +82,53 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
> >>  		lr_desc.source	= (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7;
> >>  	else
> >>  		lr_desc.source = 0;
> >> -	lr_desc.state	= 0;
> >> +	lr_desc.state	= sync_lr_state(val);
> >>  
> >> -	if (val & ICH_LR_PENDING_BIT)
> >> -		lr_desc.state |= LR_STATE_PENDING;
> >> -	if (val & ICH_LR_ACTIVE_BIT)
> >> -		lr_desc.state |= LR_STATE_ACTIVE;
> >> -	if (val & ICH_LR_EOI)
> >> -		lr_desc.state |= LR_EOI_INT;
> >> +	return lr_desc;
> >> +}
> >> +
> >> +static struct vgic_lr vgic_v3_on_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
> >> +{
> >> +	struct vgic_lr lr_desc;
> >> +	u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)];
> >> +
> >> +	lr_desc.irq	= val & ICH_LR_VIRTUALID_MASK;
> >> +	lr_desc.source	= 0;
> >> +	lr_desc.state	= sync_lr_state(val);
> >>  
> >>  	return lr_desc;
> >>  }
> >>  
> >> -static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
> >> -			   struct vgic_lr lr_desc)
> >> +static void vgic_v3_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
> >> +				 struct vgic_lr lr_desc)
> >>  {
> >> -	u64 lr_val = (((u32)lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT) |
> >> -		      lr_desc.irq);
> >> +	u64 lr_val;
> >>  
> >> -	if (lr_desc.state & LR_STATE_PENDING)
> >> -		lr_val |= ICH_LR_PENDING_BIT;
> >> -	if (lr_desc.state & LR_STATE_ACTIVE)
> >> -		lr_val |= ICH_LR_ACTIVE_BIT;
> >> -	if (lr_desc.state & LR_EOI_INT)
> >> -		lr_val |= ICH_LR_EOI;
> >> +	lr_val = lr_desc.irq;
> >> +
> >> +	/*
> >> +	 * currently all guest IRQs are Group1, as Group0 would result
> > 
> > Can you guess my comment here?
> > 
> >> +	 * in a FIQ in the guest, which it wouldn't expect.
> >> +	 * Eventually we want to make this configurable, so we may revisit
> >> +	 * this in the future.
> >> +	 */
> >> +	lr_val |= ICH_LR_GROUP;
> >> +
> >> +	lr_val |= sync_lr_val(lr_desc.state);
> >> +
> >> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val;
> >> +}
> >> +
> >> +static void vgic_v2_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
> >> +				 struct vgic_lr lr_desc)
> >> +{
> >> +	u64 lr_val;
> >> +
> >> +	lr_val = lr_desc.irq;
> >> +
> >> +	lr_val |= (u32)lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +
> >> +	lr_val |= sync_lr_val(lr_desc.state);
> >>  
> >>  	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val;
> >>  }
> >> @@ -145,9 +197,8 @@ static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >>  
> >>  static void vgic_v3_enable(struct kvm_vcpu *vcpu)
> >>  {
> >> -	struct vgic_v3_cpu_if *vgic_v3;
> >> +	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
> >>  
> >> -	vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
> > 
> > unnecessary change?
> > 
> >>  	/*
> >>  	 * By forcing VMCR to zero, the GIC will restore the binary
> >>  	 * points to their reset values. Anything else resets to zero
> 
> So most of the code above is gone now in this form due to the drop of
> init_emul and friends I did earlier last week due to your comments.
> So I will skip those comments for now (or better: try to translate them
> to the new code structure if possbile) and eagerly wait for them to
> reappear in a different form in the v4 comments ;-)

sounds good, I'll go hunt again in the v4 :)

> 
> >> @@ -155,7 +206,14 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu)
> >>  	 */
> >>  	vgic_v3->vgic_vmcr = 0;
> >>  
> >> -	vgic_v3->vgic_sre = 0;
> >> +	/*
> >> +	 * Set the SRE_EL1 value depending on the configured
> >> +	 * emulated vGIC model.
> >> +	 */
> >> +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
> >> +		vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
> > 
> > If we're on hardware with the GICv2 backwards compatibility can the
> > guest not actually set ICC_SRE_EL1_SRE to 0 but then we are not
> > preserving this because we wouldn't be trapping such accesses anymore?
> > 
> > Also, this is really about the reset value of that field, which the
> > comment above is not being specific about.
> > 
> > Further, that would mean that the field is NOT actually RAO/WI, and thus
> > the spec dictates that the field should reset to zero if EL1 is the
> > highest implemented exception level and the field is not RAO/WI, which
> > is what the guest expects, no?
> 
> I am still thinking about this (because it is probably true). Need to
> discuss with Marc what we can do about this.
> 

Kudos for understanding my cryptic comment.

-Christoffer