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_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 @@ int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
 | 
				
			||||||
	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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue