KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
This patch adds a new attribute to GICV3 KVM device KVM_DEV_ARM_VGIC_GRP_CTRL group. This allows userspace to flush all GICR pending tables into guest RAM. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Christoffer Dall <cdall@linaro.org> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
Родитель
ccb1d791ab
Коммит
280771252c
|
@ -204,6 +204,7 @@ struct kvm_arch_memory_slot {
|
||||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||||
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
||||||
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
||||||
|
#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3
|
||||||
|
|
||||||
/* KVM_IRQ_LINE irq field index values */
|
/* KVM_IRQ_LINE irq field index values */
|
||||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||||
|
|
|
@ -224,6 +224,7 @@ struct kvm_arch_memory_slot {
|
||||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||||
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
||||||
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
||||||
|
#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3
|
||||||
|
|
||||||
/* Device Control API on vcpu fd */
|
/* Device Control API on vcpu fd */
|
||||||
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
|
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
|
||||||
|
|
|
@ -580,6 +580,24 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
|
||||||
reg = tmp32;
|
reg = tmp32;
|
||||||
return vgic_v3_attr_regs_access(dev, attr, ®, true);
|
return vgic_v3_attr_regs_access(dev, attr, ®, true);
|
||||||
}
|
}
|
||||||
|
case KVM_DEV_ARM_VGIC_GRP_CTRL: {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (attr->attr) {
|
||||||
|
case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
|
||||||
|
mutex_lock(&dev->kvm->lock);
|
||||||
|
|
||||||
|
if (!lock_all_vcpus(dev->kvm)) {
|
||||||
|
mutex_unlock(&dev->kvm->lock);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
ret = vgic_v3_save_pending_tables(dev->kvm);
|
||||||
|
unlock_all_vcpus(dev->kvm);
|
||||||
|
mutex_unlock(&dev->kvm->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
@ -658,6 +676,8 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
|
||||||
switch (attr->attr) {
|
switch (attr->attr) {
|
||||||
case KVM_DEV_ARM_VGIC_CTRL_INIT:
|
case KVM_DEV_ARM_VGIC_CTRL_INIT:
|
||||||
return 0;
|
return 0;
|
||||||
|
case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
|
@ -278,6 +278,57 @@ retry:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vgic_its_save_pending_tables - Save the pending tables into guest RAM
|
||||||
|
* kvm lock and all vcpu lock must be held
|
||||||
|
*/
|
||||||
|
int vgic_v3_save_pending_tables(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
struct vgic_dist *dist = &kvm->arch.vgic;
|
||||||
|
int last_byte_offset = -1;
|
||||||
|
struct vgic_irq *irq;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
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 stored;
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
vcpu = irq->target_vcpu;
|
||||||
|
if (!vcpu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
|
||||||
|
|
||||||
|
byte_offset = irq->intid / BITS_PER_BYTE;
|
||||||
|
bit_nr = irq->intid % BITS_PER_BYTE;
|
||||||
|
ptr = pendbase + byte_offset;
|
||||||
|
|
||||||
|
if (byte_offset != last_byte_offset) {
|
||||||
|
ret = kvm_read_guest(kvm, ptr, &val, 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
last_byte_offset = byte_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
stored = val & (1U << bit_nr);
|
||||||
|
if (stored == irq->pending_latch)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (irq->pending_latch)
|
||||||
|
val |= 1 << bit_nr;
|
||||||
|
else
|
||||||
|
val &= ~(1 << bit_nr);
|
||||||
|
|
||||||
|
ret = kvm_write_guest(kvm, ptr, &val, 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* check for overlapping regions and for regions crossing the end of memory */
|
/* check for overlapping regions and for regions crossing the end of memory */
|
||||||
static bool vgic_v3_check_base(struct kvm *kvm)
|
static bool vgic_v3_check_base(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
|
|
|
@ -173,6 +173,7 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu);
|
||||||
int vgic_v3_probe(const struct gic_kvm_info *info);
|
int vgic_v3_probe(const struct gic_kvm_info *info);
|
||||||
int vgic_v3_map_resources(struct kvm *kvm);
|
int vgic_v3_map_resources(struct kvm *kvm);
|
||||||
int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
|
int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
|
||||||
|
int vgic_v3_save_pending_tables(struct kvm *kvm);
|
||||||
int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
|
int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
|
||||||
|
|
||||||
void vgic_v3_load(struct kvm_vcpu *vcpu);
|
void vgic_v3_load(struct kvm_vcpu *vcpu);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче