Skip to content

Commit

Permalink
KVM: arm/arm64: Implement KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
Browse files Browse the repository at this point in the history
Now all the internals are ready to handle multiple redistributor
regions, let's allow the userspace to register them.

Signed-off-by: Eric Auger <[email protected]>
Reviewed-by: Christoffer Dall <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
  • Loading branch information
eauger authored and Marc Zyngier committed May 25, 2018
1 parent 6e40767 commit 04c1109
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 4 deletions.
40 changes: 39 additions & 1 deletion virt/kvm/arm/vgic/vgic-kvm-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
if (r)
break;
if (write) {
r = vgic_v3_set_redist_base(kvm, *addr);
r = vgic_v3_set_redist_base(kvm, 0, *addr, 0);
goto out;
}
rdreg = list_first_entry(&vgic->rd_regions,
Expand All @@ -103,6 +103,43 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
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 = (*addr & KVM_VGIC_V3_RDIST_COUNT_MASK)
>> KVM_VGIC_V3_RDIST_COUNT_SHIFT;
u8 flags = (*addr & KVM_VGIC_V3_RDIST_FLAGS_MASK)
>> KVM_VGIC_V3_RDIST_FLAGS_SHIFT;

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;
}
Expand Down Expand Up @@ -674,6 +711,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
switch (attr->attr) {
case KVM_VGIC_V3_ADDR_TYPE_DIST:
case KVM_VGIC_V3_ADDR_TYPE_REDIST:
case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION:
return 0;
}
break;
Expand Down
4 changes: 2 additions & 2 deletions virt/kvm/arm/vgic/vgic-mmio-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,11 +764,11 @@ static int vgic_v3_insert_redist_region(struct kvm *kvm, uint32_t index,
return ret;
}

int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr)
int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
{
int ret;

ret = vgic_v3_insert_redist_region(kvm, 0, addr, 0);
ret = vgic_v3_insert_redist_region(kvm, index, addr, count);
if (ret)
return ret;

Expand Down
14 changes: 14 additions & 0 deletions virt/kvm/arm/vgic/vgic-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,20 @@ struct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rd_regions)
return NULL;
}

struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm,
u32 index)
{
struct list_head *rd_regions = &kvm->arch.vgic.rd_regions;
struct vgic_redist_region *rdreg;

list_for_each_entry(rdreg, rd_regions, list) {
if (rdreg->index == index)
return rdreg;
}
return NULL;
}


int vgic_v3_map_resources(struct kvm *kvm)
{
struct vgic_dist *dist = &kvm->arch.vgic;
Expand Down
13 changes: 12 additions & 1 deletion virt/kvm/arm/vgic/vgic.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@
/* we only support 64 kB translation table page size */
#define KVM_ITS_L1E_ADDR_MASK GENMASK_ULL(51, 16)

#define KVM_VGIC_V3_RDIST_INDEX_MASK GENMASK_ULL(11, 0)
#define KVM_VGIC_V3_RDIST_FLAGS_MASK GENMASK_ULL(15, 12)
#define KVM_VGIC_V3_RDIST_FLAGS_SHIFT 12
#define KVM_VGIC_V3_RDIST_BASE_MASK GENMASK_ULL(51, 16)
#define KVM_VGIC_V3_RDIST_COUNT_MASK GENMASK_ULL(63, 52)
#define KVM_VGIC_V3_RDIST_COUNT_SHIFT 52

/* Requires the irq_lock to be held by the caller. */
static inline bool irq_is_pending(struct vgic_irq *irq)
{
Expand Down Expand Up @@ -215,7 +222,7 @@ 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_v3_set_redist_base(struct kvm *kvm, u64 addr);
int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count);
int vgic_register_redist_iodev(struct kvm_vcpu *vcpu);
bool vgic_v3_check_base(struct kvm *kvm);

Expand Down Expand Up @@ -284,6 +291,10 @@ vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg)
else
return rdreg->count * KVM_VGIC_V3_REDIST_SIZE;
}

struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm,
u32 index);

bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size);

static inline bool vgic_dist_overlap(struct kvm *kvm, gpa_t base, size_t size)
Expand Down

0 comments on commit 04c1109

Please sign in to comment.