Merge branch 'kvm-arm64/vlpi-save-restore' into kvmarm-master/next

Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2021-04-13 15:41:45 +01:00
commit e629003215
6 changed files with 119 additions and 12 deletions

View File

@ -80,7 +80,7 @@ KVM_DEV_ARM_VGIC_GRP_CTRL
-EFAULT Invalid guest ram access
-EBUSY One or more VCPUS are running
-EACCES The virtual ITS is backed by a physical GICv4 ITS, and the
state is not available
state is not available without GICv4.1
======= ==========================================================
KVM_DEV_ARM_VGIC_GRP_ITS_REGS

View File

@ -2218,10 +2218,10 @@ static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
/*
* If an LPI carries the HW bit, this means that this
* interrupt is controlled by GICv4, and we do not
* have direct access to that state. Let's simply fail
* the save operation...
* have direct access to that state without GICv4.1.
* Let's simply fail the save operation...
*/
if (ite->irq->hw)
if (ite->irq->hw && !kvm_vgic_global_state.has_gicv4_1)
return -EACCES;
ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz);

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <kvm/arm_vgic.h>
@ -356,6 +358,32 @@ int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
return 0;
}
/*
* The deactivation of the doorbell interrupt will trigger the
* unmapping of the associated vPE.
*/
static void unmap_all_vpes(struct vgic_dist *dist)
{
struct irq_desc *desc;
int i;
for (i = 0; i < dist->its_vm.nr_vpes; i++) {
desc = irq_to_desc(dist->its_vm.vpes[i]->irq);
irq_domain_deactivate_irq(irq_desc_get_irq_data(desc));
}
}
static void map_all_vpes(struct vgic_dist *dist)
{
struct irq_desc *desc;
int i;
for (i = 0; i < dist->its_vm.nr_vpes; i++) {
desc = irq_to_desc(dist->its_vm.vpes[i]->irq);
irq_domain_activate_irq(irq_desc_get_irq_data(desc), false);
}
}
/**
* vgic_v3_save_pending_tables - Save the pending tables into guest RAM
* kvm lock and all vcpu lock must be held
@ -365,13 +393,28 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
struct vgic_dist *dist = &kvm->arch.vgic;
struct vgic_irq *irq;
gpa_t last_ptr = ~(gpa_t)0;
int ret;
bool vlpi_avail = false;
int ret = 0;
u8 val;
if (unlikely(!vgic_initialized(kvm)))
return -ENXIO;
/*
* A preparation for getting any VLPI states.
* The above vgic initialized check also ensures that the allocation
* and enabling of the doorbells have already been done.
*/
if (kvm_vgic_global_state.has_gicv4_1) {
unmap_all_vpes(dist);
vlpi_avail = true;
}
list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
int byte_offset, bit_nr;
struct kvm_vcpu *vcpu;
gpa_t pendbase, ptr;
bool is_pending;
bool stored;
vcpu = irq->target_vcpu;
@ -387,24 +430,35 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
if (ptr != last_ptr) {
ret = kvm_read_guest_lock(kvm, ptr, &val, 1);
if (ret)
return ret;
goto out;
last_ptr = ptr;
}
stored = val & (1U << bit_nr);
if (stored == irq->pending_latch)
is_pending = irq->pending_latch;
if (irq->hw && vlpi_avail)
vgic_v4_get_vlpi_state(irq, &is_pending);
if (stored == is_pending)
continue;
if (irq->pending_latch)
if (is_pending)
val |= 1 << bit_nr;
else
val &= ~(1 << bit_nr);
ret = kvm_write_guest_lock(kvm, ptr, &val, 1);
if (ret)
return ret;
goto out;
}
return 0;
out:
if (vlpi_avail)
map_all_vpes(dist);
return ret;
}
/**

View File

@ -203,6 +203,25 @@ void vgic_v4_configure_vsgis(struct kvm *kvm)
kvm_arm_resume_guest(kvm);
}
/*
* Must be called with GICv4.1 and the vPE unmapped, which
* indicates the invalidation of any VPT caches associated
* with the vPE, thus we can get the VLPI state by peeking
* at the VPT.
*/
void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val)
{
struct its_vpe *vpe = &irq->target_vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
int mask = BIT(irq->intid % BITS_PER_BYTE);
void *va;
u8 *ptr;
va = page_address(vpe->vpt_page);
ptr = va + irq->intid / BITS_PER_BYTE;
*val = !!(*ptr & mask);
}
/**
* vgic_v4_init - Initialize the GICv4 data structures
* @kvm: Pointer to the VM being initialized
@ -385,6 +404,7 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq,
struct vgic_its *its;
struct vgic_irq *irq;
struct its_vlpi_map map;
unsigned long flags;
int ret;
if (!vgic_supports_direct_msis(kvm))
@ -430,6 +450,24 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq,
irq->host_irq = virq;
atomic_inc(&map.vpe->vlpi_count);
/* Transfer pending state */
raw_spin_lock_irqsave(&irq->irq_lock, flags);
if (irq->pending_latch) {
ret = irq_set_irqchip_state(irq->host_irq,
IRQCHIP_STATE_PENDING,
irq->pending_latch);
WARN_RATELIMIT(ret, "IRQ %d", irq->host_irq);
/*
* Clear pending_latch and communicate this state
* change via vgic_queue_irq_unlock.
*/
irq->pending_latch = false;
vgic_queue_irq_unlock(kvm, irq, flags);
} else {
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
}
out:
mutex_unlock(&its->its_lock);
return ret;

View File

@ -318,5 +318,6 @@ bool vgic_supports_direct_msis(struct kvm *kvm);
int vgic_v4_init(struct kvm *kvm);
void vgic_v4_teardown(struct kvm *kvm);
void vgic_v4_configure_vsgis(struct kvm *kvm);
void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val);
#endif

View File

@ -794,8 +794,13 @@ static struct its_vpe *its_build_vmapp_cmd(struct its_node *its,
its_encode_alloc(cmd, alloc);
/* We can only signal PTZ when alloc==1. Why do we have two bits? */
its_encode_ptz(cmd, alloc);
/*
* GICv4.1 provides a way to get the VLPI state, which needs the vPE
* to be unmapped first, and in this case, we may remap the vPE
* back while the VPT is not empty. So we can't assume that the
* VPT is empty on map. This is why we never advertise PTZ.
*/
its_encode_ptz(cmd, false);
its_encode_vconf_addr(cmd, vconf_addr);
its_encode_vmapp_default_db(cmd, desc->its_vmapp_cmd.vpe->vpe_db_lpi);
@ -4554,6 +4559,15 @@ static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,
its_send_vmapp(its, vpe, false);
}
/*
* There may be a direct read to the VPT after unmapping the
* vPE, to guarantee the validity of this, we make the VPT
* memory coherent with the CPU caches here.
*/
if (find_4_1_its() && !atomic_read(&vpe->vmapp_count))
gic_flush_dcache_to_poc(page_address(vpe->vpt_page),
LPI_PENDBASE_SZ);
}
static const struct irq_domain_ops its_vpe_domain_ops = {