arch/arm64/kvm/vgic/vgic-kvm-device.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/vgic/vgic-kvm-device.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/vgic/vgic-kvm-device.c
Extension
.c
Size
19629 bytes
Lines
820
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (write) {
			r = vgic_v3_set_redist_base(kvm, 0, addr, 0);
			goto out;
		}
		rdreg = list_first_entry_or_null(&vgic->rd_regions,
						 struct vgic_redist_region, list);
		if (!rdreg)
			addr_ptr = &undef_value;
		else
			addr_ptr = &rdreg->base;
		break;
	}
	case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION:
	{
		struct vgic_redist_region *rdreg;
		u8 index;

		r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3);
		if (r)
			break;

		index = addr & KVM_VGIC_V3_RDIST_INDEX_MASK;

		if (write) {
			gpa_t base = addr & KVM_VGIC_V3_RDIST_BASE_MASK;
			u32 count = FIELD_GET(KVM_VGIC_V3_RDIST_COUNT_MASK, addr);
			u8 flags = FIELD_GET(KVM_VGIC_V3_RDIST_FLAGS_MASK, addr);

			if (!count || flags)
				r = -EINVAL;
			else
				r = vgic_v3_set_redist_base(kvm, index,
							    base, count);
			goto out;
		}

		rdreg = vgic_v3_rdist_region_from_index(kvm, index);
		if (!rdreg) {
			r = -ENOENT;
			goto out;
		}

		addr = index;
		addr |= rdreg->base;
		addr |= (u64)rdreg->count << KVM_VGIC_V3_RDIST_COUNT_SHIFT;
		goto out;
	}
	default:
		r = -ENODEV;
	}

	if (r)
		goto out;

	mutex_lock(&kvm->arch.config_lock);
	if (write) {
		r = vgic_check_iorange(kvm, *addr_ptr, addr, alignment, size);
		if (!r)
			*addr_ptr = addr;
	} else {
		addr = *addr_ptr;
	}
	mutex_unlock(&kvm->arch.config_lock);

out:
	mutex_unlock(&kvm->slots_lock);

	if (!r && !write)
		r =  put_user(addr, uaddr);

	return r;
}

static int vgic_set_common_attr(struct kvm_device *dev,
				struct kvm_device_attr *attr)
{
	int r;

	switch (attr->group) {
	case KVM_DEV_ARM_VGIC_GRP_ADDR:
		r = kvm_vgic_addr(dev->kvm, attr, true);
		return (r == -ENODEV) ? -ENXIO : r;
	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
		u32 val;
		int ret = 0;

		if (get_user(val, uaddr))
			return -EFAULT;

Annotation

Implementation Notes