From: Christoffer Dall <hidden> Date: 2017-09-06 12:26:07
This series illustrates an alternative approach to Eric Auger's direct EOI
setup patches [1] in terms of the KVM VGIC support.
The idea is to maintain existing semantics for the VGIC for mapped
level-triggered IRQs and think support for the timer into it.
Patch 1 is necessary to align the timer and VFIO ways of signaling the
VGIC. Patch 2 is stolen from Eric's series and is necessary for these
patches to compile as well. Patch 3 includes the core support for
mapped level-triggered interrupts. Patch 4 handles guest MMIO access to
the virtual distributor. Patch 5 moves some code around for patch 6.
Patch 6 implements an optimization for the timer. The last two patches
could be deferred until the timer optimization series.
Based on v4.13
Changes since v2:
- Removed patch 5 from v2 and integrating the changes in what's now
patch 5 to make it easier to reuse code when adding VFIO integration.
- Changed the virtual distributor MMIO handling to use the
pending_latch and more closely match the semantics of SPENDR and
CPENDR for both level and edge mapped interrupts.
Changes since v1:
- Added necessary changes to the timer (Patch 1)
- Added handling of guest MMIO accesses to the virtual distributor
(Patch 4)
- Addressed Marc's comments from the initial RFC (mostly renames)
Thanks,
-Christoffer
---
Christoffer Dall (4):
KVM: arm/arm64: Don't cache the timer IRQ level
KVM: arm/arm64: vgic: Support level-triggered mapped interrupts
KVM: arm/arm64: Support VGIC dist pend/active changes for mapped IRQs
KVM: arm/arm64: Provide a vgic interrupt line level sample function
Eric Auger (1):
KVM: arm/arm64: vgic: restructure kvm_vgic_(un)map_phys_irq
include/kvm/arm_vgic.h | 19 +++++++--
virt/kvm/arm/arch_timer.c | 52 +++++++++++------------
virt/kvm/arm/vgic/vgic-mmio.c | 33 +++++++++++++++
virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 29 +++++++++++++
virt/kvm/arm/vgic/vgic.c | 96 ++++++++++++++++++++++++++++++++++++-------
virt/kvm/arm/vgic/vgic.h | 8 ++++
7 files changed, 219 insertions(+), 47 deletions(-)
--
2.9.0
From: Christoffer Dall <hidden> Date: 2017-09-06 12:26:08
The timer was modeled after a strict idea of modelling an interrupt line
level in software, meaning that only transitions in the level needed to
be reported to the VGIC. This works well for the timer, because the
arch timer code is in complete control of the device and can track the
transitions of the line.
However, as we are about to support using the HW bit in the VGIC not
just for the timer, but also for VFIO which cannot track transitions of
the interrupt line, we have to decide on an interface for level
triggered mapped interrupts to the GIC, which both the timer and VFIO
can use.
VFIO only sees an asserting transition of the physical interrupt line,
and tells the VGIC when that happens. That means that part of the
interrupt flow is offloaded to the hardware.
To use the same interface for VFIO devices and the timer, we therefore
have to change the timer (we cannot change VFIO because it doesn't know
the details of the device it is assigning to a VM).
Luckily, changing the timer is simple, we just need to stop 'caching'
the line level, but instead let the VGIC know the state of the timer on
every entry to the guest, and the VGIC can ignore notifications using
its validate mechanism.
Signed-off-by: Christoffer Dall <redacted>
---
virt/kvm/arm/arch_timer.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
From: Christoffer Dall <hidden> Date: 2017-09-06 12:26:09
From: Eric Auger <eric.auger@redhat.com>
We want to reuse the core of the map/unmap functions for IRQ forwarding.
Let's move the computation of the hwirq in kvm_vgic_map_phys_irq and
pass the linux IRQ as parameter.
The host_irq is added to struct vgic_irq because it is needed in later
patches which manipulate the physical GIC state to support forwarded
IRQs.
We introduce kvm_vgic_map/unmap_irq which take a struct vgic_irq handle
as a parameter.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <redacted>
Acked-by: Marc Zyngier <redacted>
---
include/kvm/arm_vgic.h | 8 ++++---
virt/kvm/arm/arch_timer.c | 24 +------------------
virt/kvm/arm/vgic/vgic.c | 60 +++++++++++++++++++++++++++++++++++------------
3 files changed, 51 insertions(+), 41 deletions(-)
@@ -403,38 +405,66 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,return0;}-intkvm_vgic_map_phys_irq(structkvm_vcpu*vcpu,u32virt_irq,u32phys_irq)+/* @irq->irq_lock must be held */+staticintkvm_vgic_map_irq(structkvm_vcpu*vcpu,structvgic_irq*irq,+unsignedinthost_irq){-structvgic_irq*irq=vgic_get_irq(vcpu->kvm,vcpu,virt_irq);+structirq_desc*desc;+structirq_data*data;-BUG_ON(!irq);--spin_lock(&irq->irq_lock);+/*+*FindthephysicalIRQnumbercorrespondingto@host_irq+*/+desc=irq_to_desc(host_irq);+if(!desc){+kvm_err("%s: no interrupt descriptor\n",__func__);+return-EINVAL;+}+data=irq_desc_get_irq_data(desc);+while(data->parent_data)+data=data->parent_data;irq->hw=true;-irq->hwintid=phys_irq;+irq->host_irq=host_irq;+irq->hwintid=data->hwirq;+return0;+}++/* @irq->irq_lock must be held */+staticinlinevoidkvm_vgic_unmap_irq(structvgic_irq*irq)+{+irq->hw=false;+irq->hwintid=0;+}++intkvm_vgic_map_phys_irq(structkvm_vcpu*vcpu,unsignedinthost_irq,+u32vintid)+{+structvgic_irq*irq=vgic_get_irq(vcpu->kvm,vcpu,vintid);+intret;+BUG_ON(!irq);++spin_lock(&irq->irq_lock);+ret=kvm_vgic_map_irq(vcpu,irq,host_irq);spin_unlock(&irq->irq_lock);vgic_put_irq(vcpu->kvm,irq);-return0;+returnret;}-intkvm_vgic_unmap_phys_irq(structkvm_vcpu*vcpu,unsignedintvirt_irq)+intkvm_vgic_unmap_phys_irq(structkvm_vcpu*vcpu,unsignedintvintid){structvgic_irq*irq;if(!vgic_initialized(vcpu->kvm))return-EAGAIN;-irq=vgic_get_irq(vcpu->kvm,vcpu,virt_irq);+irq=vgic_get_irq(vcpu->kvm,vcpu,vintid);BUG_ON(!irq);spin_lock(&irq->irq_lock);--irq->hw=false;-irq->hwintid=0;-+kvm_vgic_unmap_irq(irq);spin_unlock(&irq->irq_lock);vgic_put_irq(vcpu->kvm,irq);
From: Christoffer Dall <hidden> Date: 2017-09-06 12:26:10
Level-triggered mapped IRQs are special because we only observe rising
edges as input to the VGIC, and we don't set the EOI flag and therefore
are not told when the level goes down, so that we can re-queue a new
interrupt when the level goes up.
One way to solve this problem is to side-step the logic of the VGIC and
special case the validation in the injection path, but it has the
unfortunate drawback of having to peak into the physical GIC state
whenever we want to know if the interrupt is pending on the virtual
distributor.
Instead, we can maintain the current semantics of a level triggered
interrupt by sort of treating it as an edge-triggered interrupt,
following from the fact that we only observe an asserting edge. This
requires us to be a bit careful when populating the LRs and when folding
the state back in though:
* We lower the line level when populating the LR, so that when
subsequently observing an asserting edge, the VGIC will do the right
thing.
* If the guest never acked the interrupt while running (for example if
it had masked interrupts at the CPU level while running), we have
to preserve the pending state of the LR and move it back to the
line_level field of the struct irq when folding LR state.
If the guest never acked the interrupt while running, but changed the
device state and lowered the line (again with interrupts masked) then
we need to observe this change in the line_level.
Both of the above situations are solved by sampling the physical line
and set the line level when folding the LR back.
* Finally, if the guest never acked the interrupt while running and
sampling the line reveals that the device state has changed and the
line has been lowered, we must clear the physical active state, since
we will otherwise never be told when the interrupt becomes asserted
again.
This has the added benefit of making the timer optimization patches
(https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026343.html) a
bit simpler, because the timer code doesn't have to clear the active
state on the sync anymore. It also potentially improves the performance
of the timer implementation because the GIC knows the state or the LR
and only needs to clear the
active state when the pending bit in the LR is still set, where the
timer has to always clear it when returning from running the guest with
an injected timer interrupt.
Signed-off-by: Christoffer Dall <redacted>
Reviewed-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 29 +++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 23 +++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 7 +++++++
4 files changed, 88 insertions(+)
@@ -161,6 +181,15 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)val|=GICH_LR_EOI;}+/*+*Level-triggeredmappedIRQsarespecialbecauseweonlyobserve+*risingedgesasinputtotheVGIC.Wethereforelowertheline+*levelhere,sothatwecantakenewvirtualIRQs.See+*vgic_v2_fold_lr_stateformoreinfo.+*/+if(vgic_irq_is_mapped_level(irq)&&(val&GICH_LR_PENDING_BIT))+irq->line_level=false;+/* The GICv2 LR only holds five bits of priority. */val|=(irq->priority>>3)<<GICH_LR_PRIORITY_SHIFT;
@@ -140,6 +140,29 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)kfree(irq);}+/* Get the input level of a mapped IRQ directly from the physical GIC */+boolvgic_get_phys_line_level(structvgic_irq*irq)+{+boolline_level;++BUG_ON(!irq->hw);++WARN_ON(irq_get_irqchip_state(irq->host_irq,+IRQCHIP_STATE_PENDING,+&line_level));+returnline_level;+}++/* Set/Clear the physical active state */+voidvgic_irq_set_phys_active(structvgic_irq*irq,boolactive)+{++BUG_ON(!irq->hw);+WARN_ON(irq_set_irqchip_state(irq->host_irq,+IRQCHIP_STATE_ACTIVE,+active));+}+/***kvm_vgic_target_oracle-computethetargetvcpuforanirq*
From: Christoffer Dall <hidden> Date: 2017-09-06 12:26:11
For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture. One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.
This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.
However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.
We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2. So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.
When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.
When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.
Signed-off-by: Christoffer Dall <redacted>
---
virt/kvm/arm/vgic/vgic-mmio.c | 33 +++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 7 +++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 41 insertions(+)
@@ -140,6 +140,13 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)kfree(irq);}+voidvgic_irq_set_phys_pending(structvgic_irq*irq,boolpending)+{+WARN_ON(irq_set_irqchip_state(irq->host_irq,+IRQCHIP_STATE_PENDING,+pending));+}+/* Get the input level of a mapped IRQ directly from the physical GIC */boolvgic_get_phys_line_level(structvgic_irq*irq){
From: Christoffer Dall <hidden> Date: 2017-09-06 12:26:12
The GIC sometimes need to sample the physical line of a mapped
interrupt. As we know this to be notoriously slow, provide a callback
function for devices (such as the timer) which can do this much faster
than talking to the distributor, for example by comparing a few
in-memory values. Fall back to the good old method of poking the
physical GIC if no callback is provided.
Signed-off-by: Christoffer Dall <redacted>
Reviewed-by: Marc Zyngier <redacted>
---
include/kvm/arm_vgic.h | 13 ++++++++++++-
virt/kvm/arm/arch_timer.c | 16 +++++++++++++++-
virt/kvm/arm/vgic/vgic.c | 12 +++++++++---
3 files changed, 36 insertions(+), 5 deletions(-)
@@ -645,6 +645,19 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)returntrue;}+staticbooltimer_get_input_level(intvintid)+{+structkvm_vcpu*vcpu=kvm_arm_get_running_vcpu();+structarch_timer_context*timer;++if(vintid==vcpu_vtimer(vcpu)->irq.irq)+timer=vcpu_vtimer(vcpu);+else+BUG();/* We only map the vtimer so far */++returnkvm_timer_should_fire(timer);+}+intkvm_timer_enable(structkvm_vcpu*vcpu){structarch_timer_cpu*timer=&vcpu->arch.timer_cpu;
@@ -666,7 +679,8 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)return-EINVAL;}-ret=kvm_vgic_map_phys_irq(vcpu,host_vtimer_irq,vtimer->irq.irq);+ret=kvm_vgic_map_phys_irq(vcpu,host_vtimer_irq,vtimer->irq.irq,+timer_get_input_level);if(ret)returnret;
@@ -437,7 +440,8 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,/* @irq->irq_lock must be held */staticintkvm_vgic_map_irq(structkvm_vcpu*vcpu,structvgic_irq*irq,-unsignedinthost_irq)+unsignedinthost_irq,+bool(*get_input_level)(intvindid)){structirq_desc*desc;structirq_data*data;
Hi Christoffer,
On 06/09/2017 14:26, Christoffer Dall wrote:
quoted hunk
For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture. One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.
This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.
However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.
We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2. So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.
When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.
When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.
Signed-off-by: Christoffer Dall <redacted>
---
virt/kvm/arm/vgic/vgic-mmio.c | 33 +++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 7 +++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 41 insertions(+)
I fail in understanding why the active state is reset here. Can you
provide an example?
If the physical dist has an active state can't the virtual IRQ be in
active state, in which case you may later on deactivate a phys IRQ which
is not active?
Thanks
Eric
quoted hunk
+ }
irq->pending_latch = false;
@@ -214,6 +231,22 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq, irq->vcpu->cpu != -1) /* VCPU thread is running */ cond_resched_lock(&irq->irq_lock);+ if (irq->hw) {+ /*+ * We cannot support setting the physical active state for+ * private interrupts from another CPU than the one running+ * the VCPU which identifies which private interrupt it is+ * trying to modify.+ */+ if (irq->intid < VGIC_NR_PRIVATE_IRQS &&+ irq->target_vcpu != requester_vcpu) {+ spin_unlock(&irq->irq_lock);+ return;+ }++ vgic_irq_set_phys_active(irq, new_active_state);+ }+ irq->active = new_active_state; if (new_active_state) vgic_queue_irq_unlock(vcpu->kvm, irq);
@@ -140,6 +140,13 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)kfree(irq);}+voidvgic_irq_set_phys_pending(structvgic_irq*irq,boolpending)+{+WARN_ON(irq_set_irqchip_state(irq->host_irq,+IRQCHIP_STATE_PENDING,+pending));+}+/* Get the input level of a mapped IRQ directly from the physical GIC */boolvgic_get_phys_line_level(structvgic_irq*irq){
From: Marc Zyngier <hidden> Date: 2017-09-08 13:32:37
On 08/09/17 14:04, Auger Eric wrote:
Hi Christoffer,
On 06/09/2017 14:26, Christoffer Dall wrote:
quoted
For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture. One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.
This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.
However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.
We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2. So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.
When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.
When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.
Signed-off-by: Christoffer Dall <redacted>
---
virt/kvm/arm/vgic/vgic-mmio.c | 33 +++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 7 +++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 41 insertions(+)
I fail in understanding why the active state is reset here. Can you
provide an example?
If we're clearing the pending state on the virtual side, we need to be
able to let an incoming physical interrupt fire so that it can be made
pending again. We may have to check that the virtual active state is
clear though.
If the physical dist has an active state can't the virtual IRQ be in
active state, in which case you may later on deactivate a phys IRQ which
is not active?
Well, I think we must be able to handle both cases:
- CPENDR write:
clear physical pending
if (virtual active clear)
clear physical active
- CACTIVER write:
clear physical active
Does this work for you?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
Hi Christoffer,
On 06/09/2017 14:26, Christoffer Dall wrote:
quoted
For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture. One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.
This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.
However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.
We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2. So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.
When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.
When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.
Signed-off-by: Christoffer Dall <redacted>
---
virt/kvm/arm/vgic/vgic-mmio.c | 33 +++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 7 +++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 41 insertions(+)
I fail in understanding why the active state is reset here. Can you
provide an example?
If we're clearing the pending state on the virtual side, we need to be
able to let an incoming physical interrupt fire so that it can be made
pending again. We may have to check that the virtual active state is
clear though.
quoted
If the physical dist has an active state can't the virtual IRQ be in
active state, in which case you may later on deactivate a phys IRQ which
is not active?
Well, I think we must be able to handle both cases:
- CPENDR write:
clear physical pending
if (virtual active clear)
clear physical active
- CACTIVER write:
clear physical active
Does this work for you?
From: Christoffer Dall <hidden> Date: 2017-09-08 16:05:58
On Fri, Sep 8, 2017 at 4:27 PM, Auger Eric [off-list ref] wrote:
Hi Marc,
On 08/09/2017 15:32, Marc Zyngier wrote:
quoted
On 08/09/17 14:04, Auger Eric wrote:
quoted
Hi Christoffer,
On 06/09/2017 14:26, Christoffer Dall wrote:
quoted
For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture. One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.
This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.
However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.
We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2. So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.
When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.
When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.
Signed-off-by: Christoffer Dall <redacted>
---
virt/kvm/arm/vgic/vgic-mmio.c | 33 +++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 7 +++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 41 insertions(+)
I fail in understanding why the active state is reset here. Can you
provide an example?
If we're clearing the pending state on the virtual side, we need to be
able to let an incoming physical interrupt fire so that it can be made
pending again. We may have to check that the virtual active state is
clear though.
quoted
If the physical dist has an active state can't the virtual IRQ be in
active state, in which case you may later on deactivate a phys IRQ which
is not active?
Well, I think we must be able to handle both cases:
- CPENDR write:
clear physical pending
if (virtual active clear)
clear physical active
- CACTIVER write:
clear physical active
Does this work for you?
yes it does with that change!
I agree, I should fix that.
But then I wondered, are we properly handling PPIs for
setting/clearing the pending state? Don't we actually need to do
something similar like the active cpu where we check the requester CPU
and make sure we're not fiddling with some random hardware state when
accessed by userspace?
Thanks,
-Christoffer
From: Marc Zyngier <hidden> Date: 2017-09-08 16:30:54
On 08/09/17 17:05, Christoffer Dall wrote:
On Fri, Sep 8, 2017 at 4:27 PM, Auger Eric [off-list ref] wrote:
quoted
Hi Marc,
On 08/09/2017 15:32, Marc Zyngier wrote:
quoted
On 08/09/17 14:04, Auger Eric wrote:
quoted
Hi Christoffer,
On 06/09/2017 14:26, Christoffer Dall wrote:
quoted
For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture. One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.
This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.
However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.
We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2. So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.
When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.
When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.
Signed-off-by: Christoffer Dall <redacted>
---
virt/kvm/arm/vgic/vgic-mmio.c | 33 +++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 7 +++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 41 insertions(+)
I fail in understanding why the active state is reset here. Can you
provide an example?
If we're clearing the pending state on the virtual side, we need to be
able to let an incoming physical interrupt fire so that it can be made
pending again. We may have to check that the virtual active state is
clear though.
quoted
If the physical dist has an active state can't the virtual IRQ be in
active state, in which case you may later on deactivate a phys IRQ which
is not active?
Well, I think we must be able to handle both cases:
- CPENDR write:
clear physical pending
if (virtual active clear)
clear physical active
- CACTIVER write:
clear physical active
Does this work for you?
yes it does with that change!
I agree, I should fix that.
But then I wondered, are we properly handling PPIs for
setting/clearing the pending state? Don't we actually need to do
something similar like the active cpu where we check the requester CPU
and make sure we're not fiddling with some random hardware state when
accessed by userspace?
Hmmm. Yeah, that's another can of worm. We should certainly make sure
that whatever userspace does is not directly impacting the HW state (and
only the guest does).
I think. I'm not quite sure...
M. (GIC-ed, again).
--
Jazz is not dead. It just smells funny...