Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28077125 authored by Eric Auger's avatar Eric Auger Committed by Christoffer Dall
Browse files

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: default avatarEric Auger <eric.auger@redhat.com>
Reviewed-by: default avatarChristoffer Dall <cdall@linaro.org>
Acked-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent ccb1d791
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -204,6 +204,7 @@ struct kvm_arch_memory_slot {
#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
#define   KVM_DEV_ARM_ITS_SAVE_TABLES		1
#define   KVM_DEV_ARM_ITS_RESTORE_TABLES	2
#define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3

/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT		24
+1 −0
Original line number Diff line number Diff line
@@ -224,6 +224,7 @@ struct kvm_arch_memory_slot {
#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
#define   KVM_DEV_ARM_ITS_SAVE_TABLES           1
#define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
#define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3

/* Device Control API on vcpu fd */
#define KVM_ARM_VCPU_PMU_V3_CTRL	0
+20 −0
Original line number Diff line number Diff line
@@ -580,6 +580,24 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
		reg = tmp32;
		return vgic_v3_attr_regs_access(dev, attr, &reg, 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;
}
@@ -658,6 +676,8 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
		switch (attr->attr) {
		case KVM_DEV_ARM_VGIC_CTRL_INIT:
			return 0;
		case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
			return 0;
		}
	}
	return -ENXIO;
+51 −0
Original line number Diff line number Diff line
@@ -278,6 +278,57 @@ int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
	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 */
static bool vgic_v3_check_base(struct kvm *kvm)
{
+1 −0
Original line number Diff line number Diff line
@@ -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_map_resources(struct kvm *kvm);
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);

void vgic_v3_load(struct kvm_vcpu *vcpu);