mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									ccb1d791ab
								
							
						
					
					
						commit
						280771252c
					
				
					 5 changed files with 74 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -580,6 +580,24 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 | 
			
		|||
		reg = tmp32;
 | 
			
		||||
		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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue