1dc0e058eSEric Auger // SPDX-License-Identifier: GPL-2.0
2dc0e058eSEric Auger /*
3dc0e058eSEric Auger * vgic init sequence tests
4dc0e058eSEric Auger *
5dc0e058eSEric Auger * Copyright (C) 2020, Red Hat, Inc.
6dc0e058eSEric Auger */
7dc0e058eSEric Auger #define _GNU_SOURCE
8dc0e058eSEric Auger #include <linux/kernel.h>
9*59e9cd63SOliver Upton #include <linux/bitfield.h>
10dc0e058eSEric Auger #include <sys/syscall.h>
11dc0e058eSEric Auger #include <asm/kvm.h>
12dc0e058eSEric Auger #include <asm/kvm_para.h>
13dc0e058eSEric Auger
14dc0e058eSEric Auger #include "test_util.h"
15dc0e058eSEric Auger #include "kvm_util.h"
16dc0e058eSEric Auger #include "processor.h"
17250b8d6cSRaghavendra Rao Ananta #include "vgic.h"
18dc0e058eSEric Auger
19dc0e058eSEric Auger #define NR_VCPUS 4
20dc0e058eSEric Auger
21dc0e058eSEric Auger #define REG_OFFSET(vcpu, offset) (((uint64_t)vcpu << 32) | offset)
22dc0e058eSEric Auger
23dc0e058eSEric Auger #define GICR_TYPER 0x8
24dc0e058eSEric Auger
253f4db37eSRicardo Koller #define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2)
263f4db37eSRicardo Koller #define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3)
273f4db37eSRicardo Koller
28dc0e058eSEric Auger struct vm_gic {
29dc0e058eSEric Auger struct kvm_vm *vm;
30dc0e058eSEric Auger int gic_fd;
3146fb941bSRicardo Koller uint32_t gic_dev_type;
32dc0e058eSEric Auger };
33dc0e058eSEric Auger
342dcd9aa1SRicardo Koller static uint64_t max_phys_size;
35dc0e058eSEric Auger
36114eef6eSSean Christopherson /*
37114eef6eSSean Christopherson * Helpers to access a redistributor register and verify the ioctl() failed or
38114eef6eSSean Christopherson * succeeded as expected, and provided the correct value on success.
39114eef6eSSean Christopherson */
v3_redist_reg_get_errno(int gicv3_fd,int vcpu,int offset,int want,const char * msg)40114eef6eSSean Christopherson static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset,
41114eef6eSSean Christopherson int want, const char *msg)
42dc0e058eSEric Auger {
43114eef6eSSean Christopherson uint32_t ignored_val;
44114eef6eSSean Christopherson int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
45114eef6eSSean Christopherson REG_OFFSET(vcpu, offset), &ignored_val);
46114eef6eSSean Christopherson
47114eef6eSSean Christopherson TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want);
48114eef6eSSean Christopherson }
49114eef6eSSean Christopherson
v3_redist_reg_get(int gicv3_fd,int vcpu,int offset,uint32_t want,const char * msg)50114eef6eSSean Christopherson static void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t want,
51114eef6eSSean Christopherson const char *msg)
52114eef6eSSean Christopherson {
53114eef6eSSean Christopherson uint32_t val;
54114eef6eSSean Christopherson
55114eef6eSSean Christopherson kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
56114eef6eSSean Christopherson REG_OFFSET(vcpu, offset), &val);
57114eef6eSSean Christopherson TEST_ASSERT(val == want, "%s; want '0x%x', got '0x%x'", msg, want, val);
58dc0e058eSEric Auger }
59dc0e058eSEric Auger
60dc0e058eSEric Auger /* dummy guest code */
guest_code(void)61dc0e058eSEric Auger static void guest_code(void)
62dc0e058eSEric Auger {
63dc0e058eSEric Auger GUEST_SYNC(0);
64dc0e058eSEric Auger GUEST_SYNC(1);
65dc0e058eSEric Auger GUEST_SYNC(2);
66dc0e058eSEric Auger GUEST_DONE();
67dc0e058eSEric Auger }
68dc0e058eSEric Auger
69dc0e058eSEric Auger /* we don't want to assert on run execution, hence that helper */
run_vcpu(struct kvm_vcpu * vcpu)7045f56808SSean Christopherson static int run_vcpu(struct kvm_vcpu *vcpu)
71dc0e058eSEric Auger {
72768e9a61SSean Christopherson return __vcpu_run(vcpu) ? -errno : 0;
73dc0e058eSEric Auger }
74dc0e058eSEric Auger
vm_gic_create_with_vcpus(uint32_t gic_dev_type,uint32_t nr_vcpus,struct kvm_vcpu * vcpus[])7545f56808SSean Christopherson static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type,
7645f56808SSean Christopherson uint32_t nr_vcpus,
7745f56808SSean Christopherson struct kvm_vcpu *vcpus[])
78dc0e058eSEric Auger {
79dc0e058eSEric Auger struct vm_gic v;
80dc0e058eSEric Auger
8146fb941bSRicardo Koller v.gic_dev_type = gic_dev_type;
8245f56808SSean Christopherson v.vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
83f3165dc0SSean Christopherson v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
84dc0e058eSEric Auger
85dc0e058eSEric Auger return v;
86dc0e058eSEric Auger }
87dc0e058eSEric Auger
vm_gic_create_barebones(uint32_t gic_dev_type)88*59e9cd63SOliver Upton static struct vm_gic vm_gic_create_barebones(uint32_t gic_dev_type)
89*59e9cd63SOliver Upton {
90*59e9cd63SOliver Upton struct vm_gic v;
91*59e9cd63SOliver Upton
92*59e9cd63SOliver Upton v.gic_dev_type = gic_dev_type;
93*59e9cd63SOliver Upton v.vm = vm_create_barebones();
94*59e9cd63SOliver Upton v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
95*59e9cd63SOliver Upton
96*59e9cd63SOliver Upton return v;
97*59e9cd63SOliver Upton }
98*59e9cd63SOliver Upton
99*59e9cd63SOliver Upton
vm_gic_destroy(struct vm_gic * v)100dc0e058eSEric Auger static void vm_gic_destroy(struct vm_gic *v)
101dc0e058eSEric Auger {
102dc0e058eSEric Auger close(v->gic_fd);
103dc0e058eSEric Auger kvm_vm_free(v->vm);
104dc0e058eSEric Auger }
105dc0e058eSEric Auger
106c44df5f9SRicardo Koller struct vgic_region_attr {
107c44df5f9SRicardo Koller uint64_t attr;
108c44df5f9SRicardo Koller uint64_t size;
109c44df5f9SRicardo Koller uint64_t alignment;
110c44df5f9SRicardo Koller };
111c44df5f9SRicardo Koller
112c44df5f9SRicardo Koller struct vgic_region_attr gic_v3_dist_region = {
113c44df5f9SRicardo Koller .attr = KVM_VGIC_V3_ADDR_TYPE_DIST,
114c44df5f9SRicardo Koller .size = 0x10000,
115c44df5f9SRicardo Koller .alignment = 0x10000,
116c44df5f9SRicardo Koller };
117c44df5f9SRicardo Koller
118c44df5f9SRicardo Koller struct vgic_region_attr gic_v3_redist_region = {
119c44df5f9SRicardo Koller .attr = KVM_VGIC_V3_ADDR_TYPE_REDIST,
120c44df5f9SRicardo Koller .size = NR_VCPUS * 0x20000,
121c44df5f9SRicardo Koller .alignment = 0x10000,
122c44df5f9SRicardo Koller };
123c44df5f9SRicardo Koller
124c44df5f9SRicardo Koller struct vgic_region_attr gic_v2_dist_region = {
125c44df5f9SRicardo Koller .attr = KVM_VGIC_V2_ADDR_TYPE_DIST,
126c44df5f9SRicardo Koller .size = 0x1000,
127c44df5f9SRicardo Koller .alignment = 0x1000,
128c44df5f9SRicardo Koller };
129c44df5f9SRicardo Koller
130c44df5f9SRicardo Koller struct vgic_region_attr gic_v2_cpu_region = {
131c44df5f9SRicardo Koller .attr = KVM_VGIC_V2_ADDR_TYPE_CPU,
132c44df5f9SRicardo Koller .size = 0x2000,
133c44df5f9SRicardo Koller .alignment = 0x1000,
134c44df5f9SRicardo Koller };
135c44df5f9SRicardo Koller
136dc0e058eSEric Auger /**
137c44df5f9SRicardo Koller * Helper routine that performs KVM device tests in general. Eventually the
138c44df5f9SRicardo Koller * ARM_VGIC (GICv2 or GICv3) device gets created with an overlapping
139c44df5f9SRicardo Koller * DIST/REDIST (or DIST/CPUIF for GICv2). Assumption is 4 vcpus are going to be
140c44df5f9SRicardo Koller * used hence the overlap. In the case of GICv3, A RDIST region is set at @0x0
141c44df5f9SRicardo Koller * and a DIST region is set @0x70000. The GICv2 case sets a CPUIF @0x0 and a
142c44df5f9SRicardo Koller * DIST region @0x1000.
143dc0e058eSEric Auger */
subtest_dist_rdist(struct vm_gic * v)144c44df5f9SRicardo Koller static void subtest_dist_rdist(struct vm_gic *v)
145dc0e058eSEric Auger {
146dc0e058eSEric Auger int ret;
147dc0e058eSEric Auger uint64_t addr;
148c44df5f9SRicardo Koller struct vgic_region_attr rdist; /* CPU interface in GICv2*/
149c44df5f9SRicardo Koller struct vgic_region_attr dist;
150c44df5f9SRicardo Koller
151c44df5f9SRicardo Koller rdist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_redist_region
152c44df5f9SRicardo Koller : gic_v2_cpu_region;
153c44df5f9SRicardo Koller dist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_dist_region
154c44df5f9SRicardo Koller : gic_v2_dist_region;
155dc0e058eSEric Auger
156dc0e058eSEric Auger /* Check existing group/attributes */
1579367504fSSean Christopherson kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, dist.attr);
158dc0e058eSEric Auger
1599367504fSSean Christopherson kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, rdist.attr);
160dc0e058eSEric Auger
161dc0e058eSEric Auger /* check non existing attribute */
1629367504fSSean Christopherson ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, -1);
1634cffb2dfSEric Auger TEST_ASSERT(ret && errno == ENXIO, "attribute not supported");
164dc0e058eSEric Auger
165dc0e058eSEric Auger /* misaligned DIST and REDIST address settings */
166c44df5f9SRicardo Koller addr = dist.alignment / 0x10;
16740918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
16840918184SSean Christopherson dist.attr, &addr);
169c44df5f9SRicardo Koller TEST_ASSERT(ret && errno == EINVAL, "GIC dist base not aligned");
170dc0e058eSEric Auger
171c44df5f9SRicardo Koller addr = rdist.alignment / 0x10;
17240918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
17340918184SSean Christopherson rdist.attr, &addr);
174c44df5f9SRicardo Koller TEST_ASSERT(ret && errno == EINVAL, "GIC redist/cpu base not aligned");
175dc0e058eSEric Auger
176dc0e058eSEric Auger /* out of range address */
1772dcd9aa1SRicardo Koller addr = max_phys_size;
17840918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
17940918184SSean Christopherson dist.attr, &addr);
1804cffb2dfSEric Auger TEST_ASSERT(ret && errno == E2BIG, "dist address beyond IPA limit");
181dc0e058eSEric Auger
18240918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
18340918184SSean Christopherson rdist.attr, &addr);
1844cffb2dfSEric Auger TEST_ASSERT(ret && errno == E2BIG, "redist address beyond IPA limit");
1852dcd9aa1SRicardo Koller
1862dcd9aa1SRicardo Koller /* Space for half a rdist (a rdist is: 2 * rdist.alignment). */
1872dcd9aa1SRicardo Koller addr = max_phys_size - dist.alignment;
18840918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
18940918184SSean Christopherson rdist.attr, &addr);
1902dcd9aa1SRicardo Koller TEST_ASSERT(ret && errno == E2BIG,
1912dcd9aa1SRicardo Koller "half of the redist is beyond IPA limit");
192dc0e058eSEric Auger
193dc0e058eSEric Auger /* set REDIST base address @0x0*/
194dc0e058eSEric Auger addr = 0x00000;
19540918184SSean Christopherson kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
19640918184SSean Christopherson rdist.attr, &addr);
197dc0e058eSEric Auger
198dc0e058eSEric Auger /* Attempt to create a second legacy redistributor region */
199dc0e058eSEric Auger addr = 0xE0000;
20040918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
20140918184SSean Christopherson rdist.attr, &addr);
202c44df5f9SRicardo Koller TEST_ASSERT(ret && errno == EEXIST, "GIC redist base set again");
203dc0e058eSEric Auger
2049367504fSSean Christopherson ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
205c44df5f9SRicardo Koller KVM_VGIC_V3_ADDR_TYPE_REDIST);
206c44df5f9SRicardo Koller if (!ret) {
207dc0e058eSEric Auger /* Attempt to mix legacy and new redistributor regions */
208dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 0, 0);
20940918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
21040918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
211c44df5f9SRicardo Koller TEST_ASSERT(ret && errno == EINVAL,
212c44df5f9SRicardo Koller "attempt to mix GICv3 REDIST and REDIST_REGION");
213c44df5f9SRicardo Koller }
214dc0e058eSEric Auger
215dc0e058eSEric Auger /*
216dc0e058eSEric Auger * Set overlapping DIST / REDIST, cannot be detected here. Will be detected
217dc0e058eSEric Auger * on first vcpu run instead.
218dc0e058eSEric Auger */
219c44df5f9SRicardo Koller addr = rdist.size - rdist.alignment;
22040918184SSean Christopherson kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
22140918184SSean Christopherson dist.attr, &addr);
222dc0e058eSEric Auger }
223dc0e058eSEric Auger
224dc0e058eSEric Auger /* Test the new REDIST region API */
subtest_v3_redist_regions(struct vm_gic * v)2253f4db37eSRicardo Koller static void subtest_v3_redist_regions(struct vm_gic *v)
226dc0e058eSEric Auger {
227dc0e058eSEric Auger uint64_t addr, expected_addr;
228dc0e058eSEric Auger int ret;
229dc0e058eSEric Auger
230d2752e2eSSean Christopherson ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
231dc0e058eSEric Auger KVM_VGIC_V3_ADDR_TYPE_REDIST);
232dc0e058eSEric Auger TEST_ASSERT(!ret, "Multiple redist regions advertised");
233dc0e058eSEric Auger
234dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 2, 0);
23540918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
23640918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2374cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with flags != 0");
238dc0e058eSEric Auger
239dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(0, 0x100000, 0, 0);
24040918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
24140918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2424cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with count== 0");
243dc0e058eSEric Auger
244dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
24540918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
24640918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2474cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL,
2484cffb2dfSEric Auger "attempt to register the first rdist region with index != 0");
249dc0e058eSEric Auger
250dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x201000, 0, 1);
25140918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
25240918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2534cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL, "rdist region with misaligned address");
254dc0e058eSEric Auger
255dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
25640918184SSean Christopherson kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
25740918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
258dc0e058eSEric Auger
259dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
26040918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
26140918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2624cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL, "register an rdist region with already used index");
263dc0e058eSEric Auger
264dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(1, 0x210000, 0, 2);
26540918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
26640918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2674cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL,
2684cffb2dfSEric Auger "register an rdist region overlapping with another one");
269dc0e058eSEric Auger
270dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 2);
27140918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
27240918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2734cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL, "register redist region with index not +1");
274dc0e058eSEric Auger
275dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
27640918184SSean Christopherson kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
27740918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
278dc0e058eSEric Auger
2792dcd9aa1SRicardo Koller addr = REDIST_REGION_ATTR_ADDR(1, max_phys_size, 0, 2);
28040918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
28140918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2824cffb2dfSEric Auger TEST_ASSERT(ret && errno == E2BIG,
2834cffb2dfSEric Auger "register redist region with base address beyond IPA range");
284dc0e058eSEric Auger
2852dcd9aa1SRicardo Koller /* The last redist is above the pa range. */
2862dcd9aa1SRicardo Koller addr = REDIST_REGION_ATTR_ADDR(2, max_phys_size - 0x30000, 0, 2);
28740918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
28840918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
2892dcd9aa1SRicardo Koller TEST_ASSERT(ret && errno == E2BIG,
2902dcd9aa1SRicardo Koller "register redist region with top address beyond IPA range");
2912dcd9aa1SRicardo Koller
292dc0e058eSEric Auger addr = 0x260000;
29340918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
29440918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
2954cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL,
2964cffb2dfSEric Auger "Mix KVM_VGIC_V3_ADDR_TYPE_REDIST and REDIST_REGION");
297dc0e058eSEric Auger
298dc0e058eSEric Auger /*
299dc0e058eSEric Auger * Now there are 2 redist regions:
300dc0e058eSEric Auger * region 0 @ 0x200000 2 redists
301dc0e058eSEric Auger * region 1 @ 0x240000 1 redist
302dc0e058eSEric Auger * Attempt to read their characteristics
303dc0e058eSEric Auger */
304dc0e058eSEric Auger
305dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 0);
306dc0e058eSEric Auger expected_addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
30740918184SSean Christopherson ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
30840918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
309dc0e058eSEric Auger TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #0");
310dc0e058eSEric Auger
311dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 1);
312dc0e058eSEric Auger expected_addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
31340918184SSean Christopherson ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
31440918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
315dc0e058eSEric Auger TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #1");
316dc0e058eSEric Auger
317dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 2);
31840918184SSean Christopherson ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
31940918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
3204cffb2dfSEric Auger TEST_ASSERT(ret && errno == ENOENT, "read characteristics of non existing region");
321dc0e058eSEric Auger
322dc0e058eSEric Auger addr = 0x260000;
32340918184SSean Christopherson kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
32440918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
325dc0e058eSEric Auger
326dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(1, 0x260000, 0, 2);
32740918184SSean Christopherson ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
32840918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
3294cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL, "register redist region colliding with dist");
330dc0e058eSEric Auger }
331dc0e058eSEric Auger
332dc0e058eSEric Auger /*
333dc0e058eSEric Auger * VGIC KVM device is created and initialized before the secondary CPUs
334dc0e058eSEric Auger * get created
335dc0e058eSEric Auger */
test_vgic_then_vcpus(uint32_t gic_dev_type)336c44df5f9SRicardo Koller static void test_vgic_then_vcpus(uint32_t gic_dev_type)
337dc0e058eSEric Auger {
33845f56808SSean Christopherson struct kvm_vcpu *vcpus[NR_VCPUS];
339dc0e058eSEric Auger struct vm_gic v;
340dc0e058eSEric Auger int ret, i;
341dc0e058eSEric Auger
34245f56808SSean Christopherson v = vm_gic_create_with_vcpus(gic_dev_type, 1, vcpus);
343dc0e058eSEric Auger
344c44df5f9SRicardo Koller subtest_dist_rdist(&v);
345dc0e058eSEric Auger
346dc0e058eSEric Auger /* Add the rest of the VCPUs */
347dc0e058eSEric Auger for (i = 1; i < NR_VCPUS; ++i)
34845f56808SSean Christopherson vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
349dc0e058eSEric Auger
35045f56808SSean Christopherson ret = run_vcpu(vcpus[3]);
351dc0e058eSEric Auger TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
352dc0e058eSEric Auger
353dc0e058eSEric Auger vm_gic_destroy(&v);
354dc0e058eSEric Auger }
355dc0e058eSEric Auger
356dc0e058eSEric Auger /* All the VCPUs are created before the VGIC KVM device gets initialized */
test_vcpus_then_vgic(uint32_t gic_dev_type)357c44df5f9SRicardo Koller static void test_vcpus_then_vgic(uint32_t gic_dev_type)
358dc0e058eSEric Auger {
35945f56808SSean Christopherson struct kvm_vcpu *vcpus[NR_VCPUS];
360dc0e058eSEric Auger struct vm_gic v;
361dc0e058eSEric Auger int ret;
362dc0e058eSEric Auger
36345f56808SSean Christopherson v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, vcpus);
364dc0e058eSEric Auger
365c44df5f9SRicardo Koller subtest_dist_rdist(&v);
366dc0e058eSEric Auger
36745f56808SSean Christopherson ret = run_vcpu(vcpus[3]);
368dc0e058eSEric Auger TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
369dc0e058eSEric Auger
370dc0e058eSEric Auger vm_gic_destroy(&v);
371dc0e058eSEric Auger }
372dc0e058eSEric Auger
373*59e9cd63SOliver Upton #define KVM_VGIC_V2_ATTR(offset, cpu) \
374*59e9cd63SOliver Upton (FIELD_PREP(KVM_DEV_ARM_VGIC_OFFSET_MASK, offset) | \
375*59e9cd63SOliver Upton FIELD_PREP(KVM_DEV_ARM_VGIC_CPUID_MASK, cpu))
376*59e9cd63SOliver Upton
377*59e9cd63SOliver Upton #define GIC_CPU_CTRL 0x00
378*59e9cd63SOliver Upton
test_v2_uaccess_cpuif_no_vcpus(void)379*59e9cd63SOliver Upton static void test_v2_uaccess_cpuif_no_vcpus(void)
380*59e9cd63SOliver Upton {
381*59e9cd63SOliver Upton struct vm_gic v;
382*59e9cd63SOliver Upton u64 val = 0;
383*59e9cd63SOliver Upton int ret;
384*59e9cd63SOliver Upton
385*59e9cd63SOliver Upton v = vm_gic_create_barebones(KVM_DEV_TYPE_ARM_VGIC_V2);
386*59e9cd63SOliver Upton subtest_dist_rdist(&v);
387*59e9cd63SOliver Upton
388*59e9cd63SOliver Upton ret = __kvm_has_device_attr(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
389*59e9cd63SOliver Upton KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0));
390*59e9cd63SOliver Upton TEST_ASSERT(ret && errno == EINVAL,
391*59e9cd63SOliver Upton "accessed non-existent CPU interface, want errno: %i",
392*59e9cd63SOliver Upton EINVAL);
393*59e9cd63SOliver Upton ret = __kvm_device_attr_get(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
394*59e9cd63SOliver Upton KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val);
395*59e9cd63SOliver Upton TEST_ASSERT(ret && errno == EINVAL,
396*59e9cd63SOliver Upton "accessed non-existent CPU interface, want errno: %i",
397*59e9cd63SOliver Upton EINVAL);
398*59e9cd63SOliver Upton ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
399*59e9cd63SOliver Upton KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val);
400*59e9cd63SOliver Upton TEST_ASSERT(ret && errno == EINVAL,
401*59e9cd63SOliver Upton "accessed non-existent CPU interface, want errno: %i",
402*59e9cd63SOliver Upton EINVAL);
403*59e9cd63SOliver Upton
404*59e9cd63SOliver Upton vm_gic_destroy(&v);
405*59e9cd63SOliver Upton }
406*59e9cd63SOliver Upton
test_v3_new_redist_regions(void)4073f4db37eSRicardo Koller static void test_v3_new_redist_regions(void)
408dc0e058eSEric Auger {
40945f56808SSean Christopherson struct kvm_vcpu *vcpus[NR_VCPUS];
410dc0e058eSEric Auger void *dummy = NULL;
411dc0e058eSEric Auger struct vm_gic v;
412dc0e058eSEric Auger uint64_t addr;
413dc0e058eSEric Auger int ret;
414dc0e058eSEric Auger
41545f56808SSean Christopherson v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
4163f4db37eSRicardo Koller subtest_v3_redist_regions(&v);
41740918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
41840918184SSean Christopherson KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
419dc0e058eSEric Auger
42045f56808SSean Christopherson ret = run_vcpu(vcpus[3]);
421dc0e058eSEric Auger TEST_ASSERT(ret == -ENXIO, "running without sufficient number of rdists");
422dc0e058eSEric Auger vm_gic_destroy(&v);
423dc0e058eSEric Auger
424dc0e058eSEric Auger /* step2 */
425dc0e058eSEric Auger
42645f56808SSean Christopherson v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
4273f4db37eSRicardo Koller subtest_v3_redist_regions(&v);
428dc0e058eSEric Auger
429dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
43040918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
43140918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
432dc0e058eSEric Auger
43345f56808SSean Christopherson ret = run_vcpu(vcpus[3]);
434dc0e058eSEric Auger TEST_ASSERT(ret == -EBUSY, "running without vgic explicit init");
435dc0e058eSEric Auger
436dc0e058eSEric Auger vm_gic_destroy(&v);
437dc0e058eSEric Auger
438dc0e058eSEric Auger /* step 3 */
439dc0e058eSEric Auger
44045f56808SSean Christopherson v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
4413f4db37eSRicardo Koller subtest_v3_redist_regions(&v);
442dc0e058eSEric Auger
44340918184SSean Christopherson ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
44440918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy);
4454cffb2dfSEric Auger TEST_ASSERT(ret && errno == EFAULT,
4464cffb2dfSEric Auger "register a third region allowing to cover the 4 vcpus");
447dc0e058eSEric Auger
448dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
44940918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
45040918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
451dc0e058eSEric Auger
45240918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
45340918184SSean Christopherson KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
454dc0e058eSEric Auger
45545f56808SSean Christopherson ret = run_vcpu(vcpus[3]);
456dc0e058eSEric Auger TEST_ASSERT(!ret, "vcpu run");
457dc0e058eSEric Auger
458dc0e058eSEric Auger vm_gic_destroy(&v);
459dc0e058eSEric Auger }
460dc0e058eSEric Auger
test_v3_typer_accesses(void)4613f4db37eSRicardo Koller static void test_v3_typer_accesses(void)
462dc0e058eSEric Auger {
4634cffb2dfSEric Auger struct vm_gic v;
464dc0e058eSEric Auger uint64_t addr;
4654cffb2dfSEric Auger int ret, i;
466dc0e058eSEric Auger
4676e1d13bfSSean Christopherson v.vm = vm_create(NR_VCPUS);
46845f56808SSean Christopherson (void)vm_vcpu_add(v.vm, 0, guest_code);
469dc0e058eSEric Auger
470f3165dc0SSean Christopherson v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
471dc0e058eSEric Auger
47245f56808SSean Christopherson (void)vm_vcpu_add(v.vm, 3, guest_code);
473dc0e058eSEric Auger
474114eef6eSSean Christopherson v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL,
475114eef6eSSean Christopherson "attempting to read GICR_TYPER of non created vcpu");
476dc0e058eSEric Auger
47745f56808SSean Christopherson (void)vm_vcpu_add(v.vm, 1, guest_code);
478dc0e058eSEric Auger
479114eef6eSSean Christopherson v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY,
480114eef6eSSean Christopherson "read GICR_TYPER before GIC initialized");
481dc0e058eSEric Auger
48245f56808SSean Christopherson (void)vm_vcpu_add(v.vm, 2, guest_code);
483dc0e058eSEric Auger
48440918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
48540918184SSean Christopherson KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
486dc0e058eSEric Auger
487dc0e058eSEric Auger for (i = 0; i < NR_VCPUS ; i++) {
488114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, i, GICR_TYPER, i * 0x100,
489ff624e57SSean Christopherson "read GICR_TYPER before rdist region setting");
490dc0e058eSEric Auger }
491dc0e058eSEric Auger
492dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
49340918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
49440918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
495dc0e058eSEric Auger
496dc0e058eSEric Auger /* The 2 first rdists should be put there (vcpu 0 and 3) */
497114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x0, "read typer of rdist #0");
498114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #1");
499dc0e058eSEric Auger
500dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(10, 0x100000, 0, 1);
50140918184SSean Christopherson ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
50240918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
5034cffb2dfSEric Auger TEST_ASSERT(ret && errno == EINVAL, "collision with previous rdist region");
504dc0e058eSEric Auger
505114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100,
506dc0e058eSEric Auger "no redist region attached to vcpu #1 yet, last cannot be returned");
507114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200,
508dc0e058eSEric Auger "no redist region attached to vcpu #2, last cannot be returned");
509dc0e058eSEric Auger
510dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(10, 0x20000, 0, 1);
51140918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
51240918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
513dc0e058eSEric Auger
514114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
515114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210,
516dc0e058eSEric Auger "read typer of rdist #1, last properly returned");
517dc0e058eSEric Auger
5184cffb2dfSEric Auger vm_gic_destroy(&v);
519dc0e058eSEric Auger }
520dc0e058eSEric Auger
vm_gic_v3_create_with_vcpuids(int nr_vcpus,uint32_t vcpuids[])52145f56808SSean Christopherson static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus,
52245f56808SSean Christopherson uint32_t vcpuids[])
52345f56808SSean Christopherson {
52445f56808SSean Christopherson struct vm_gic v;
52545f56808SSean Christopherson int i;
52645f56808SSean Christopherson
5276e1d13bfSSean Christopherson v.vm = vm_create(nr_vcpus);
52845f56808SSean Christopherson for (i = 0; i < nr_vcpus; i++)
52945f56808SSean Christopherson vm_vcpu_add(v.vm, vcpuids[i], guest_code);
53045f56808SSean Christopherson
53145f56808SSean Christopherson v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
53245f56808SSean Christopherson
53345f56808SSean Christopherson return v;
53445f56808SSean Christopherson }
53545f56808SSean Christopherson
536dc0e058eSEric Auger /**
537dc0e058eSEric Auger * Test GICR_TYPER last bit with new redist regions
538dc0e058eSEric Auger * rdist regions #1 and #2 are contiguous
539dc0e058eSEric Auger * rdist region #0 @0x100000 2 rdist capacity
540dc0e058eSEric Auger * rdists: 0, 3 (Last)
541dc0e058eSEric Auger * rdist region #1 @0x240000 2 rdist capacity
542dc0e058eSEric Auger * rdists: 5, 4 (Last)
543dc0e058eSEric Auger * rdist region #2 @0x200000 2 rdist capacity
544dc0e058eSEric Auger * rdists: 1, 2
545dc0e058eSEric Auger */
test_v3_last_bit_redist_regions(void)5463f4db37eSRicardo Koller static void test_v3_last_bit_redist_regions(void)
547dc0e058eSEric Auger {
548dc0e058eSEric Auger uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
5494cffb2dfSEric Auger struct vm_gic v;
550dc0e058eSEric Auger uint64_t addr;
551dc0e058eSEric Auger
55245f56808SSean Christopherson v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
553dc0e058eSEric Auger
55440918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
55540918184SSean Christopherson KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
556dc0e058eSEric Auger
557dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x100000, 0, 0);
55840918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
55940918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
560dc0e058eSEric Auger
561dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x240000, 0, 1);
56240918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
56340918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
564dc0e058eSEric Auger
565dc0e058eSEric Auger addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 2);
56640918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
56740918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
568dc0e058eSEric Auger
569114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
570114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
571114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200, "read typer of rdist #2");
572114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #3");
573114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #5");
574114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, 0x410, "read typer of rdist #4");
575dc0e058eSEric Auger
5764cffb2dfSEric Auger vm_gic_destroy(&v);
577dc0e058eSEric Auger }
578dc0e058eSEric Auger
579dc0e058eSEric Auger /* Test last bit with legacy region */
test_v3_last_bit_single_rdist(void)5803f4db37eSRicardo Koller static void test_v3_last_bit_single_rdist(void)
581dc0e058eSEric Auger {
582dc0e058eSEric Auger uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
5834cffb2dfSEric Auger struct vm_gic v;
584dc0e058eSEric Auger uint64_t addr;
585dc0e058eSEric Auger
58645f56808SSean Christopherson v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
587dc0e058eSEric Auger
58840918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
58940918184SSean Christopherson KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
590dc0e058eSEric Auger
591dc0e058eSEric Auger addr = 0x10000;
59240918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
59340918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
594dc0e058eSEric Auger
595114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
596114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x300, "read typer of rdist #1");
597114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #2");
598114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #3");
599114eef6eSSean Christopherson v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210, "read typer of rdist #3");
600dc0e058eSEric Auger
6014cffb2dfSEric Auger vm_gic_destroy(&v);
602dc0e058eSEric Auger }
603dc0e058eSEric Auger
60418834586SRicardo Koller /* Uses the legacy REDIST region API. */
test_v3_redist_ipa_range_check_at_vcpu_run(void)60518834586SRicardo Koller static void test_v3_redist_ipa_range_check_at_vcpu_run(void)
60618834586SRicardo Koller {
60745f56808SSean Christopherson struct kvm_vcpu *vcpus[NR_VCPUS];
60818834586SRicardo Koller struct vm_gic v;
60918834586SRicardo Koller int ret, i;
61018834586SRicardo Koller uint64_t addr;
61118834586SRicardo Koller
61245f56808SSean Christopherson v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus);
61318834586SRicardo Koller
61418834586SRicardo Koller /* Set space for 3 redists, we have 1 vcpu, so this succeeds. */
61518834586SRicardo Koller addr = max_phys_size - (3 * 2 * 0x10000);
61640918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
61740918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
61818834586SRicardo Koller
61918834586SRicardo Koller addr = 0x00000;
62040918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
62140918184SSean Christopherson KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
62218834586SRicardo Koller
62318834586SRicardo Koller /* Add the rest of the VCPUs */
62418834586SRicardo Koller for (i = 1; i < NR_VCPUS; ++i)
62545f56808SSean Christopherson vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
62618834586SRicardo Koller
62740918184SSean Christopherson kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
62840918184SSean Christopherson KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
62918834586SRicardo Koller
63018834586SRicardo Koller /* Attempt to run a vcpu without enough redist space. */
63145f56808SSean Christopherson ret = run_vcpu(vcpus[2]);
63218834586SRicardo Koller TEST_ASSERT(ret && errno == EINVAL,
63318834586SRicardo Koller "redist base+size above PA range detected on 1st vcpu run");
63418834586SRicardo Koller
63518834586SRicardo Koller vm_gic_destroy(&v);
63618834586SRicardo Koller }
63718834586SRicardo Koller
test_v3_its_region(void)6383e197f17SRicardo Koller static void test_v3_its_region(void)
6393e197f17SRicardo Koller {
64045f56808SSean Christopherson struct kvm_vcpu *vcpus[NR_VCPUS];
6413e197f17SRicardo Koller struct vm_gic v;
6423e197f17SRicardo Koller uint64_t addr;
6433e197f17SRicardo Koller int its_fd, ret;
6443e197f17SRicardo Koller
64545f56808SSean Christopherson v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
646f3165dc0SSean Christopherson its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS);
6473e197f17SRicardo Koller
6483e197f17SRicardo Koller addr = 0x401000;
64940918184SSean Christopherson ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
65040918184SSean Christopherson KVM_VGIC_ITS_ADDR_TYPE, &addr);
6513e197f17SRicardo Koller TEST_ASSERT(ret && errno == EINVAL,
6523e197f17SRicardo Koller "ITS region with misaligned address");
6533e197f17SRicardo Koller
6543e197f17SRicardo Koller addr = max_phys_size;
65540918184SSean Christopherson ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
65640918184SSean Christopherson KVM_VGIC_ITS_ADDR_TYPE, &addr);
6573e197f17SRicardo Koller TEST_ASSERT(ret && errno == E2BIG,
6583e197f17SRicardo Koller "register ITS region with base address beyond IPA range");
6593e197f17SRicardo Koller
6603e197f17SRicardo Koller addr = max_phys_size - 0x10000;
66140918184SSean Christopherson ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
66240918184SSean Christopherson KVM_VGIC_ITS_ADDR_TYPE, &addr);
6633e197f17SRicardo Koller TEST_ASSERT(ret && errno == E2BIG,
6643e197f17SRicardo Koller "Half of ITS region is beyond IPA range");
6653e197f17SRicardo Koller
6663e197f17SRicardo Koller /* This one succeeds setting the ITS base */
6673e197f17SRicardo Koller addr = 0x400000;
66840918184SSean Christopherson kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
66940918184SSean Christopherson KVM_VGIC_ITS_ADDR_TYPE, &addr);
6703e197f17SRicardo Koller
6713e197f17SRicardo Koller addr = 0x300000;
67240918184SSean Christopherson ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
67340918184SSean Christopherson KVM_VGIC_ITS_ADDR_TYPE, &addr);
6743e197f17SRicardo Koller TEST_ASSERT(ret && errno == EEXIST, "ITS base set again");
6753e197f17SRicardo Koller
6763e197f17SRicardo Koller close(its_fd);
6773e197f17SRicardo Koller vm_gic_destroy(&v);
6783e197f17SRicardo Koller }
6793e197f17SRicardo Koller
6803f4db37eSRicardo Koller /*
6813f4db37eSRicardo Koller * Returns 0 if it's possible to create GIC device of a given type (V2 or V3).
6823f4db37eSRicardo Koller */
test_kvm_device(uint32_t gic_dev_type)6833f4db37eSRicardo Koller int test_kvm_device(uint32_t gic_dev_type)
684dc0e058eSEric Auger {
68545f56808SSean Christopherson struct kvm_vcpu *vcpus[NR_VCPUS];
686dc0e058eSEric Auger struct vm_gic v;
6873f4db37eSRicardo Koller uint32_t other;
688279eacbeSSean Christopherson int ret;
689dc0e058eSEric Auger
69045f56808SSean Christopherson v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
691dc0e058eSEric Auger
692dc0e058eSEric Auger /* try to create a non existing KVM device */
69398f94ce4SSean Christopherson ret = __kvm_test_create_device(v.vm, 0);
6944cffb2dfSEric Auger TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
695dc0e058eSEric Auger
6963f4db37eSRicardo Koller /* trial mode */
69798f94ce4SSean Christopherson ret = __kvm_test_create_device(v.vm, gic_dev_type);
6983f4db37eSRicardo Koller if (ret)
6993f4db37eSRicardo Koller return ret;
700f3165dc0SSean Christopherson v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
701dc0e058eSEric Auger
702279eacbeSSean Christopherson ret = __kvm_create_device(v.vm, gic_dev_type);
703279eacbeSSean Christopherson TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
704dc0e058eSEric Auger
7053f4db37eSRicardo Koller /* try to create the other gic_dev_type */
7063f4db37eSRicardo Koller other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3
7073f4db37eSRicardo Koller : KVM_DEV_TYPE_ARM_VGIC_V2;
7083f4db37eSRicardo Koller
70998f94ce4SSean Christopherson if (!__kvm_test_create_device(v.vm, other)) {
7108a6ffcbeSZenghui Yu ret = __kvm_create_device(v.vm, other);
7118a6ffcbeSZenghui Yu TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
7123f4db37eSRicardo Koller "create GIC device while other version exists");
713dc0e058eSEric Auger }
714dc0e058eSEric Auger
715dc0e058eSEric Auger vm_gic_destroy(&v);
7163f4db37eSRicardo Koller
7173f4db37eSRicardo Koller return 0;
7183f4db37eSRicardo Koller }
7193f4db37eSRicardo Koller
run_tests(uint32_t gic_dev_type)7203f4db37eSRicardo Koller void run_tests(uint32_t gic_dev_type)
7213f4db37eSRicardo Koller {
722c44df5f9SRicardo Koller test_vcpus_then_vgic(gic_dev_type);
723c44df5f9SRicardo Koller test_vgic_then_vcpus(gic_dev_type);
724c44df5f9SRicardo Koller
725*59e9cd63SOliver Upton if (VGIC_DEV_IS_V2(gic_dev_type))
726*59e9cd63SOliver Upton test_v2_uaccess_cpuif_no_vcpus();
727*59e9cd63SOliver Upton
7283f4db37eSRicardo Koller if (VGIC_DEV_IS_V3(gic_dev_type)) {
7293f4db37eSRicardo Koller test_v3_new_redist_regions();
7303f4db37eSRicardo Koller test_v3_typer_accesses();
7313f4db37eSRicardo Koller test_v3_last_bit_redist_regions();
7323f4db37eSRicardo Koller test_v3_last_bit_single_rdist();
73318834586SRicardo Koller test_v3_redist_ipa_range_check_at_vcpu_run();
7343e197f17SRicardo Koller test_v3_its_region();
7353f4db37eSRicardo Koller }
736dc0e058eSEric Auger }
737dc0e058eSEric Auger
main(int ac,char ** av)738dc0e058eSEric Auger int main(int ac, char **av)
739dc0e058eSEric Auger {
7403f4db37eSRicardo Koller int ret;
7412dcd9aa1SRicardo Koller int pa_bits;
7426a4f7fcdSMarc Zyngier int cnt_impl = 0;
7433f4db37eSRicardo Koller
7442dcd9aa1SRicardo Koller pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
7452dcd9aa1SRicardo Koller max_phys_size = 1ULL << pa_bits;
746dc0e058eSEric Auger
7473f4db37eSRicardo Koller ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V3);
7483f4db37eSRicardo Koller if (!ret) {
7493f4db37eSRicardo Koller pr_info("Running GIC_v3 tests.\n");
7503f4db37eSRicardo Koller run_tests(KVM_DEV_TYPE_ARM_VGIC_V3);
7516a4f7fcdSMarc Zyngier cnt_impl++;
7523f4db37eSRicardo Koller }
753dc0e058eSEric Auger
7543f4db37eSRicardo Koller ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V2);
7553f4db37eSRicardo Koller if (!ret) {
7563f4db37eSRicardo Koller pr_info("Running GIC_v2 tests.\n");
7573f4db37eSRicardo Koller run_tests(KVM_DEV_TYPE_ARM_VGIC_V2);
7586a4f7fcdSMarc Zyngier cnt_impl++;
7593f4db37eSRicardo Koller }
7603f4db37eSRicardo Koller
7616a4f7fcdSMarc Zyngier if (!cnt_impl) {
7623f4db37eSRicardo Koller print_skip("No GICv2 nor GICv3 support");
7633f4db37eSRicardo Koller exit(KSFT_SKIP);
7646a4f7fcdSMarc Zyngier }
765dc0e058eSEric Auger return 0;
766dc0e058eSEric Auger }
767