xref: /linux/tools/testing/selftests/kvm/arm64/vgic_init.c (revision 1260ed77798502de9c98020040d2995008de10cc)
1*67730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0
2*67730e6cSSean Christopherson /*
3*67730e6cSSean Christopherson  * vgic init sequence tests
4*67730e6cSSean Christopherson  *
5*67730e6cSSean Christopherson  * Copyright (C) 2020, Red Hat, Inc.
6*67730e6cSSean Christopherson  */
7*67730e6cSSean Christopherson #include <linux/kernel.h>
8*67730e6cSSean Christopherson #include <sys/syscall.h>
9*67730e6cSSean Christopherson #include <asm/kvm.h>
10*67730e6cSSean Christopherson #include <asm/kvm_para.h>
11*67730e6cSSean Christopherson 
12*67730e6cSSean Christopherson #include "test_util.h"
13*67730e6cSSean Christopherson #include "kvm_util.h"
14*67730e6cSSean Christopherson #include "processor.h"
15*67730e6cSSean Christopherson #include "vgic.h"
16*67730e6cSSean Christopherson 
17*67730e6cSSean Christopherson #define NR_VCPUS		4
18*67730e6cSSean Christopherson 
19*67730e6cSSean Christopherson #define REG_OFFSET(vcpu, offset) (((uint64_t)vcpu << 32) | offset)
20*67730e6cSSean Christopherson 
21*67730e6cSSean Christopherson #define GICR_TYPER 0x8
22*67730e6cSSean Christopherson 
23*67730e6cSSean Christopherson #define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2)
24*67730e6cSSean Christopherson #define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3)
25*67730e6cSSean Christopherson 
26*67730e6cSSean Christopherson struct vm_gic {
27*67730e6cSSean Christopherson 	struct kvm_vm *vm;
28*67730e6cSSean Christopherson 	int gic_fd;
29*67730e6cSSean Christopherson 	uint32_t gic_dev_type;
30*67730e6cSSean Christopherson };
31*67730e6cSSean Christopherson 
32*67730e6cSSean Christopherson static uint64_t max_phys_size;
33*67730e6cSSean Christopherson 
34*67730e6cSSean Christopherson /*
35*67730e6cSSean Christopherson  * Helpers to access a redistributor register and verify the ioctl() failed or
36*67730e6cSSean Christopherson  * succeeded as expected, and provided the correct value on success.
37*67730e6cSSean Christopherson  */
38*67730e6cSSean Christopherson static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset,
39*67730e6cSSean Christopherson 				    int want, const char *msg)
40*67730e6cSSean Christopherson {
41*67730e6cSSean Christopherson 	uint32_t ignored_val;
42*67730e6cSSean Christopherson 	int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
43*67730e6cSSean Christopherson 					REG_OFFSET(vcpu, offset), &ignored_val);
44*67730e6cSSean Christopherson 
45*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want);
46*67730e6cSSean Christopherson }
47*67730e6cSSean Christopherson 
48*67730e6cSSean Christopherson static void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t want,
49*67730e6cSSean Christopherson 			      const char *msg)
50*67730e6cSSean Christopherson {
51*67730e6cSSean Christopherson 	uint32_t val;
52*67730e6cSSean Christopherson 
53*67730e6cSSean Christopherson 	kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
54*67730e6cSSean Christopherson 			    REG_OFFSET(vcpu, offset), &val);
55*67730e6cSSean Christopherson 	TEST_ASSERT(val == want, "%s; want '0x%x', got '0x%x'", msg, want, val);
56*67730e6cSSean Christopherson }
57*67730e6cSSean Christopherson 
58*67730e6cSSean Christopherson /* dummy guest code */
59*67730e6cSSean Christopherson static void guest_code(void)
60*67730e6cSSean Christopherson {
61*67730e6cSSean Christopherson 	GUEST_SYNC(0);
62*67730e6cSSean Christopherson 	GUEST_SYNC(1);
63*67730e6cSSean Christopherson 	GUEST_SYNC(2);
64*67730e6cSSean Christopherson 	GUEST_DONE();
65*67730e6cSSean Christopherson }
66*67730e6cSSean Christopherson 
67*67730e6cSSean Christopherson /* we don't want to assert on run execution, hence that helper */
68*67730e6cSSean Christopherson static int run_vcpu(struct kvm_vcpu *vcpu)
69*67730e6cSSean Christopherson {
70*67730e6cSSean Christopherson 	return __vcpu_run(vcpu) ? -errno : 0;
71*67730e6cSSean Christopherson }
72*67730e6cSSean Christopherson 
73*67730e6cSSean Christopherson static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type,
74*67730e6cSSean Christopherson 					      uint32_t nr_vcpus,
75*67730e6cSSean Christopherson 					      struct kvm_vcpu *vcpus[])
76*67730e6cSSean Christopherson {
77*67730e6cSSean Christopherson 	struct vm_gic v;
78*67730e6cSSean Christopherson 
79*67730e6cSSean Christopherson 	v.gic_dev_type = gic_dev_type;
80*67730e6cSSean Christopherson 	v.vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
81*67730e6cSSean Christopherson 	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
82*67730e6cSSean Christopherson 
83*67730e6cSSean Christopherson 	return v;
84*67730e6cSSean Christopherson }
85*67730e6cSSean Christopherson 
86*67730e6cSSean Christopherson static struct vm_gic vm_gic_create_barebones(uint32_t gic_dev_type)
87*67730e6cSSean Christopherson {
88*67730e6cSSean Christopherson 	struct vm_gic v;
89*67730e6cSSean Christopherson 
90*67730e6cSSean Christopherson 	v.gic_dev_type = gic_dev_type;
91*67730e6cSSean Christopherson 	v.vm = vm_create_barebones();
92*67730e6cSSean Christopherson 	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
93*67730e6cSSean Christopherson 
94*67730e6cSSean Christopherson 	return v;
95*67730e6cSSean Christopherson }
96*67730e6cSSean Christopherson 
97*67730e6cSSean Christopherson 
98*67730e6cSSean Christopherson static void vm_gic_destroy(struct vm_gic *v)
99*67730e6cSSean Christopherson {
100*67730e6cSSean Christopherson 	close(v->gic_fd);
101*67730e6cSSean Christopherson 	kvm_vm_free(v->vm);
102*67730e6cSSean Christopherson }
103*67730e6cSSean Christopherson 
104*67730e6cSSean Christopherson struct vgic_region_attr {
105*67730e6cSSean Christopherson 	uint64_t attr;
106*67730e6cSSean Christopherson 	uint64_t size;
107*67730e6cSSean Christopherson 	uint64_t alignment;
108*67730e6cSSean Christopherson };
109*67730e6cSSean Christopherson 
110*67730e6cSSean Christopherson struct vgic_region_attr gic_v3_dist_region = {
111*67730e6cSSean Christopherson 	.attr = KVM_VGIC_V3_ADDR_TYPE_DIST,
112*67730e6cSSean Christopherson 	.size = 0x10000,
113*67730e6cSSean Christopherson 	.alignment = 0x10000,
114*67730e6cSSean Christopherson };
115*67730e6cSSean Christopherson 
116*67730e6cSSean Christopherson struct vgic_region_attr gic_v3_redist_region = {
117*67730e6cSSean Christopherson 	.attr = KVM_VGIC_V3_ADDR_TYPE_REDIST,
118*67730e6cSSean Christopherson 	.size = NR_VCPUS * 0x20000,
119*67730e6cSSean Christopherson 	.alignment = 0x10000,
120*67730e6cSSean Christopherson };
121*67730e6cSSean Christopherson 
122*67730e6cSSean Christopherson struct vgic_region_attr gic_v2_dist_region = {
123*67730e6cSSean Christopherson 	.attr = KVM_VGIC_V2_ADDR_TYPE_DIST,
124*67730e6cSSean Christopherson 	.size = 0x1000,
125*67730e6cSSean Christopherson 	.alignment = 0x1000,
126*67730e6cSSean Christopherson };
127*67730e6cSSean Christopherson 
128*67730e6cSSean Christopherson struct vgic_region_attr gic_v2_cpu_region = {
129*67730e6cSSean Christopherson 	.attr = KVM_VGIC_V2_ADDR_TYPE_CPU,
130*67730e6cSSean Christopherson 	.size = 0x2000,
131*67730e6cSSean Christopherson 	.alignment = 0x1000,
132*67730e6cSSean Christopherson };
133*67730e6cSSean Christopherson 
134*67730e6cSSean Christopherson /**
135*67730e6cSSean Christopherson  * Helper routine that performs KVM device tests in general. Eventually the
136*67730e6cSSean Christopherson  * ARM_VGIC (GICv2 or GICv3) device gets created with an overlapping
137*67730e6cSSean Christopherson  * DIST/REDIST (or DIST/CPUIF for GICv2). Assumption is 4 vcpus are going to be
138*67730e6cSSean Christopherson  * used hence the overlap. In the case of GICv3, A RDIST region is set at @0x0
139*67730e6cSSean Christopherson  * and a DIST region is set @0x70000. The GICv2 case sets a CPUIF @0x0 and a
140*67730e6cSSean Christopherson  * DIST region @0x1000.
141*67730e6cSSean Christopherson  */
142*67730e6cSSean Christopherson static void subtest_dist_rdist(struct vm_gic *v)
143*67730e6cSSean Christopherson {
144*67730e6cSSean Christopherson 	int ret;
145*67730e6cSSean Christopherson 	uint64_t addr;
146*67730e6cSSean Christopherson 	struct vgic_region_attr rdist; /* CPU interface in GICv2*/
147*67730e6cSSean Christopherson 	struct vgic_region_attr dist;
148*67730e6cSSean Christopherson 
149*67730e6cSSean Christopherson 	rdist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_redist_region
150*67730e6cSSean Christopherson 						: gic_v2_cpu_region;
151*67730e6cSSean Christopherson 	dist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_dist_region
152*67730e6cSSean Christopherson 						: gic_v2_dist_region;
153*67730e6cSSean Christopherson 
154*67730e6cSSean Christopherson 	/* Check existing group/attributes */
155*67730e6cSSean Christopherson 	kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, dist.attr);
156*67730e6cSSean Christopherson 
157*67730e6cSSean Christopherson 	kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, rdist.attr);
158*67730e6cSSean Christopherson 
159*67730e6cSSean Christopherson 	/* check non existing attribute */
160*67730e6cSSean Christopherson 	ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, -1);
161*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == ENXIO, "attribute not supported");
162*67730e6cSSean Christopherson 
163*67730e6cSSean Christopherson 	/* misaligned DIST and REDIST address settings */
164*67730e6cSSean Christopherson 	addr = dist.alignment / 0x10;
165*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
166*67730e6cSSean Christopherson 				    dist.attr, &addr);
167*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "GIC dist base not aligned");
168*67730e6cSSean Christopherson 
169*67730e6cSSean Christopherson 	addr = rdist.alignment / 0x10;
170*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
171*67730e6cSSean Christopherson 				    rdist.attr, &addr);
172*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "GIC redist/cpu base not aligned");
173*67730e6cSSean Christopherson 
174*67730e6cSSean Christopherson 	/* out of range address */
175*67730e6cSSean Christopherson 	addr = max_phys_size;
176*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
177*67730e6cSSean Christopherson 				    dist.attr, &addr);
178*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == E2BIG, "dist address beyond IPA limit");
179*67730e6cSSean Christopherson 
180*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
181*67730e6cSSean Christopherson 				    rdist.attr, &addr);
182*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == E2BIG, "redist address beyond IPA limit");
183*67730e6cSSean Christopherson 
184*67730e6cSSean Christopherson 	/* Space for half a rdist (a rdist is: 2 * rdist.alignment). */
185*67730e6cSSean Christopherson 	addr = max_phys_size - dist.alignment;
186*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
187*67730e6cSSean Christopherson 				    rdist.attr, &addr);
188*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == E2BIG,
189*67730e6cSSean Christopherson 			"half of the redist is beyond IPA limit");
190*67730e6cSSean Christopherson 
191*67730e6cSSean Christopherson 	/* set REDIST base address @0x0*/
192*67730e6cSSean Christopherson 	addr = 0x00000;
193*67730e6cSSean Christopherson 	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
194*67730e6cSSean Christopherson 			    rdist.attr, &addr);
195*67730e6cSSean Christopherson 
196*67730e6cSSean Christopherson 	/* Attempt to create a second legacy redistributor region */
197*67730e6cSSean Christopherson 	addr = 0xE0000;
198*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
199*67730e6cSSean Christopherson 				    rdist.attr, &addr);
200*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EEXIST, "GIC redist base set again");
201*67730e6cSSean Christopherson 
202*67730e6cSSean Christopherson 	ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
203*67730e6cSSean Christopherson 				     KVM_VGIC_V3_ADDR_TYPE_REDIST);
204*67730e6cSSean Christopherson 	if (!ret) {
205*67730e6cSSean Christopherson 		/* Attempt to mix legacy and new redistributor regions */
206*67730e6cSSean Christopherson 		addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 0, 0);
207*67730e6cSSean Christopherson 		ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
208*67730e6cSSean Christopherson 					    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
209*67730e6cSSean Christopherson 		TEST_ASSERT(ret && errno == EINVAL,
210*67730e6cSSean Christopherson 			    "attempt to mix GICv3 REDIST and REDIST_REGION");
211*67730e6cSSean Christopherson 	}
212*67730e6cSSean Christopherson 
213*67730e6cSSean Christopherson 	/*
214*67730e6cSSean Christopherson 	 * Set overlapping DIST / REDIST, cannot be detected here. Will be detected
215*67730e6cSSean Christopherson 	 * on first vcpu run instead.
216*67730e6cSSean Christopherson 	 */
217*67730e6cSSean Christopherson 	addr = rdist.size - rdist.alignment;
218*67730e6cSSean Christopherson 	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
219*67730e6cSSean Christopherson 			    dist.attr, &addr);
220*67730e6cSSean Christopherson }
221*67730e6cSSean Christopherson 
222*67730e6cSSean Christopherson /* Test the new REDIST region API */
223*67730e6cSSean Christopherson static void subtest_v3_redist_regions(struct vm_gic *v)
224*67730e6cSSean Christopherson {
225*67730e6cSSean Christopherson 	uint64_t addr, expected_addr;
226*67730e6cSSean Christopherson 	int ret;
227*67730e6cSSean Christopherson 
228*67730e6cSSean Christopherson 	ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
229*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST);
230*67730e6cSSean Christopherson 	TEST_ASSERT(!ret, "Multiple redist regions advertised");
231*67730e6cSSean Christopherson 
232*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 2, 0);
233*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
234*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
235*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with flags != 0");
236*67730e6cSSean Christopherson 
237*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(0, 0x100000, 0, 0);
238*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
239*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
240*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with count== 0");
241*67730e6cSSean Christopherson 
242*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
243*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
244*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
245*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
246*67730e6cSSean Christopherson 		    "attempt to register the first rdist region with index != 0");
247*67730e6cSSean Christopherson 
248*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x201000, 0, 1);
249*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
250*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
251*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "rdist region with misaligned address");
252*67730e6cSSean Christopherson 
253*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
254*67730e6cSSean Christopherson 	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
255*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
256*67730e6cSSean Christopherson 
257*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
258*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
259*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
260*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "register an rdist region with already used index");
261*67730e6cSSean Christopherson 
262*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(1, 0x210000, 0, 2);
263*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
264*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
265*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
266*67730e6cSSean Christopherson 		    "register an rdist region overlapping with another one");
267*67730e6cSSean Christopherson 
268*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 2);
269*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
270*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
271*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "register redist region with index not +1");
272*67730e6cSSean Christopherson 
273*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
274*67730e6cSSean Christopherson 	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
275*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
276*67730e6cSSean Christopherson 
277*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(1, max_phys_size, 0, 2);
278*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
279*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
280*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == E2BIG,
281*67730e6cSSean Christopherson 		    "register redist region with base address beyond IPA range");
282*67730e6cSSean Christopherson 
283*67730e6cSSean Christopherson 	/* The last redist is above the pa range. */
284*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, max_phys_size - 0x30000, 0, 2);
285*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
286*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
287*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == E2BIG,
288*67730e6cSSean Christopherson 		    "register redist region with top address beyond IPA range");
289*67730e6cSSean Christopherson 
290*67730e6cSSean Christopherson 	addr = 0x260000;
291*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
292*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
293*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
294*67730e6cSSean Christopherson 		    "Mix KVM_VGIC_V3_ADDR_TYPE_REDIST and REDIST_REGION");
295*67730e6cSSean Christopherson 
296*67730e6cSSean Christopherson 	/*
297*67730e6cSSean Christopherson 	 * Now there are 2 redist regions:
298*67730e6cSSean Christopherson 	 * region 0 @ 0x200000 2 redists
299*67730e6cSSean Christopherson 	 * region 1 @ 0x240000 1 redist
300*67730e6cSSean Christopherson 	 * Attempt to read their characteristics
301*67730e6cSSean Christopherson 	 */
302*67730e6cSSean Christopherson 
303*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 0);
304*67730e6cSSean Christopherson 	expected_addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
305*67730e6cSSean Christopherson 	ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
306*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
307*67730e6cSSean Christopherson 	TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #0");
308*67730e6cSSean Christopherson 
309*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 1);
310*67730e6cSSean Christopherson 	expected_addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
311*67730e6cSSean Christopherson 	ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
312*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
313*67730e6cSSean Christopherson 	TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #1");
314*67730e6cSSean Christopherson 
315*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 2);
316*67730e6cSSean Christopherson 	ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
317*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
318*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == ENOENT, "read characteristics of non existing region");
319*67730e6cSSean Christopherson 
320*67730e6cSSean Christopherson 	addr = 0x260000;
321*67730e6cSSean Christopherson 	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
322*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
323*67730e6cSSean Christopherson 
324*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(1, 0x260000, 0, 2);
325*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
326*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
327*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "register redist region colliding with dist");
328*67730e6cSSean Christopherson }
329*67730e6cSSean Christopherson 
330*67730e6cSSean Christopherson /*
331*67730e6cSSean Christopherson  * VGIC KVM device is created and initialized before the secondary CPUs
332*67730e6cSSean Christopherson  * get created
333*67730e6cSSean Christopherson  */
334*67730e6cSSean Christopherson static void test_vgic_then_vcpus(uint32_t gic_dev_type)
335*67730e6cSSean Christopherson {
336*67730e6cSSean Christopherson 	struct kvm_vcpu *vcpus[NR_VCPUS];
337*67730e6cSSean Christopherson 	struct vm_gic v;
338*67730e6cSSean Christopherson 	int ret, i;
339*67730e6cSSean Christopherson 
340*67730e6cSSean Christopherson 	v = vm_gic_create_with_vcpus(gic_dev_type, 1, vcpus);
341*67730e6cSSean Christopherson 
342*67730e6cSSean Christopherson 	subtest_dist_rdist(&v);
343*67730e6cSSean Christopherson 
344*67730e6cSSean Christopherson 	/* Add the rest of the VCPUs */
345*67730e6cSSean Christopherson 	for (i = 1; i < NR_VCPUS; ++i)
346*67730e6cSSean Christopherson 		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
347*67730e6cSSean Christopherson 
348*67730e6cSSean Christopherson 	ret = run_vcpu(vcpus[3]);
349*67730e6cSSean Christopherson 	TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
350*67730e6cSSean Christopherson 
351*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
352*67730e6cSSean Christopherson }
353*67730e6cSSean Christopherson 
354*67730e6cSSean Christopherson /* All the VCPUs are created before the VGIC KVM device gets initialized */
355*67730e6cSSean Christopherson static void test_vcpus_then_vgic(uint32_t gic_dev_type)
356*67730e6cSSean Christopherson {
357*67730e6cSSean Christopherson 	struct kvm_vcpu *vcpus[NR_VCPUS];
358*67730e6cSSean Christopherson 	struct vm_gic v;
359*67730e6cSSean Christopherson 	int ret;
360*67730e6cSSean Christopherson 
361*67730e6cSSean Christopherson 	v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, vcpus);
362*67730e6cSSean Christopherson 
363*67730e6cSSean Christopherson 	subtest_dist_rdist(&v);
364*67730e6cSSean Christopherson 
365*67730e6cSSean Christopherson 	ret = run_vcpu(vcpus[3]);
366*67730e6cSSean Christopherson 	TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
367*67730e6cSSean Christopherson 
368*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
369*67730e6cSSean Christopherson }
370*67730e6cSSean Christopherson 
371*67730e6cSSean Christopherson #define KVM_VGIC_V2_ATTR(offset, cpu) \
372*67730e6cSSean Christopherson 	(FIELD_PREP(KVM_DEV_ARM_VGIC_OFFSET_MASK, offset) | \
373*67730e6cSSean Christopherson 	 FIELD_PREP(KVM_DEV_ARM_VGIC_CPUID_MASK, cpu))
374*67730e6cSSean Christopherson 
375*67730e6cSSean Christopherson #define GIC_CPU_CTRL	0x00
376*67730e6cSSean Christopherson 
377*67730e6cSSean Christopherson static void test_v2_uaccess_cpuif_no_vcpus(void)
378*67730e6cSSean Christopherson {
379*67730e6cSSean Christopherson 	struct vm_gic v;
380*67730e6cSSean Christopherson 	u64 val = 0;
381*67730e6cSSean Christopherson 	int ret;
382*67730e6cSSean Christopherson 
383*67730e6cSSean Christopherson 	v = vm_gic_create_barebones(KVM_DEV_TYPE_ARM_VGIC_V2);
384*67730e6cSSean Christopherson 	subtest_dist_rdist(&v);
385*67730e6cSSean Christopherson 
386*67730e6cSSean Christopherson 	ret = __kvm_has_device_attr(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
387*67730e6cSSean Christopherson 				    KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0));
388*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
389*67730e6cSSean Christopherson 		    "accessed non-existent CPU interface, want errno: %i",
390*67730e6cSSean Christopherson 		    EINVAL);
391*67730e6cSSean Christopherson 	ret = __kvm_device_attr_get(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
392*67730e6cSSean Christopherson 				    KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val);
393*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
394*67730e6cSSean Christopherson 		    "accessed non-existent CPU interface, want errno: %i",
395*67730e6cSSean Christopherson 		    EINVAL);
396*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
397*67730e6cSSean Christopherson 				    KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val);
398*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
399*67730e6cSSean Christopherson 		    "accessed non-existent CPU interface, want errno: %i",
400*67730e6cSSean Christopherson 		    EINVAL);
401*67730e6cSSean Christopherson 
402*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
403*67730e6cSSean Christopherson }
404*67730e6cSSean Christopherson 
405*67730e6cSSean Christopherson static void test_v3_new_redist_regions(void)
406*67730e6cSSean Christopherson {
407*67730e6cSSean Christopherson 	struct kvm_vcpu *vcpus[NR_VCPUS];
408*67730e6cSSean Christopherson 	void *dummy = NULL;
409*67730e6cSSean Christopherson 	struct vm_gic v;
410*67730e6cSSean Christopherson 	uint64_t addr;
411*67730e6cSSean Christopherson 	int ret;
412*67730e6cSSean Christopherson 
413*67730e6cSSean Christopherson 	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
414*67730e6cSSean Christopherson 	subtest_v3_redist_regions(&v);
415*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
416*67730e6cSSean Christopherson 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
417*67730e6cSSean Christopherson 
418*67730e6cSSean Christopherson 	ret = run_vcpu(vcpus[3]);
419*67730e6cSSean Christopherson 	TEST_ASSERT(ret == -ENXIO, "running without sufficient number of rdists");
420*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
421*67730e6cSSean Christopherson 
422*67730e6cSSean Christopherson 	/* step2 */
423*67730e6cSSean Christopherson 
424*67730e6cSSean Christopherson 	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
425*67730e6cSSean Christopherson 	subtest_v3_redist_regions(&v);
426*67730e6cSSean Christopherson 
427*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
428*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
429*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
430*67730e6cSSean Christopherson 
431*67730e6cSSean Christopherson 	ret = run_vcpu(vcpus[3]);
432*67730e6cSSean Christopherson 	TEST_ASSERT(ret == -EBUSY, "running without vgic explicit init");
433*67730e6cSSean Christopherson 
434*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
435*67730e6cSSean Christopherson 
436*67730e6cSSean Christopherson 	/* step 3 */
437*67730e6cSSean Christopherson 
438*67730e6cSSean Christopherson 	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
439*67730e6cSSean Christopherson 	subtest_v3_redist_regions(&v);
440*67730e6cSSean Christopherson 
441*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
442*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy);
443*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EFAULT,
444*67730e6cSSean Christopherson 		    "register a third region allowing to cover the 4 vcpus");
445*67730e6cSSean Christopherson 
446*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
447*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
448*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
449*67730e6cSSean Christopherson 
450*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
451*67730e6cSSean Christopherson 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
452*67730e6cSSean Christopherson 
453*67730e6cSSean Christopherson 	ret = run_vcpu(vcpus[3]);
454*67730e6cSSean Christopherson 	TEST_ASSERT(!ret, "vcpu run");
455*67730e6cSSean Christopherson 
456*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
457*67730e6cSSean Christopherson }
458*67730e6cSSean Christopherson 
459*67730e6cSSean Christopherson static void test_v3_typer_accesses(void)
460*67730e6cSSean Christopherson {
461*67730e6cSSean Christopherson 	struct vm_gic v;
462*67730e6cSSean Christopherson 	uint64_t addr;
463*67730e6cSSean Christopherson 	int ret, i;
464*67730e6cSSean Christopherson 
465*67730e6cSSean Christopherson 	v.vm = vm_create(NR_VCPUS);
466*67730e6cSSean Christopherson 	(void)vm_vcpu_add(v.vm, 0, guest_code);
467*67730e6cSSean Christopherson 
468*67730e6cSSean Christopherson 	v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
469*67730e6cSSean Christopherson 
470*67730e6cSSean Christopherson 	(void)vm_vcpu_add(v.vm, 3, guest_code);
471*67730e6cSSean Christopherson 
472*67730e6cSSean Christopherson 	v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL,
473*67730e6cSSean Christopherson 				"attempting to read GICR_TYPER of non created vcpu");
474*67730e6cSSean Christopherson 
475*67730e6cSSean Christopherson 	(void)vm_vcpu_add(v.vm, 1, guest_code);
476*67730e6cSSean Christopherson 
477*67730e6cSSean Christopherson 	v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY,
478*67730e6cSSean Christopherson 				"read GICR_TYPER before GIC initialized");
479*67730e6cSSean Christopherson 
480*67730e6cSSean Christopherson 	(void)vm_vcpu_add(v.vm, 2, guest_code);
481*67730e6cSSean Christopherson 
482*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
483*67730e6cSSean Christopherson 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
484*67730e6cSSean Christopherson 
485*67730e6cSSean Christopherson 	for (i = 0; i < NR_VCPUS ; i++) {
486*67730e6cSSean Christopherson 		v3_redist_reg_get(v.gic_fd, i, GICR_TYPER, i * 0x100,
487*67730e6cSSean Christopherson 				  "read GICR_TYPER before rdist region setting");
488*67730e6cSSean Christopherson 	}
489*67730e6cSSean Christopherson 
490*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
491*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
492*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
493*67730e6cSSean Christopherson 
494*67730e6cSSean Christopherson 	/* The 2 first rdists should be put there (vcpu 0 and 3) */
495*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x0, "read typer of rdist #0");
496*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #1");
497*67730e6cSSean Christopherson 
498*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(10, 0x100000, 0, 1);
499*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
500*67730e6cSSean Christopherson 				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
501*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL, "collision with previous rdist region");
502*67730e6cSSean Christopherson 
503*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100,
504*67730e6cSSean Christopherson 			  "no redist region attached to vcpu #1 yet, last cannot be returned");
505*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200,
506*67730e6cSSean Christopherson 			  "no redist region attached to vcpu #2, last cannot be returned");
507*67730e6cSSean Christopherson 
508*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(10, 0x20000, 0, 1);
509*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
510*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
511*67730e6cSSean Christopherson 
512*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
513*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210,
514*67730e6cSSean Christopherson 			  "read typer of rdist #1, last properly returned");
515*67730e6cSSean Christopherson 
516*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
517*67730e6cSSean Christopherson }
518*67730e6cSSean Christopherson 
519*67730e6cSSean Christopherson static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus,
520*67730e6cSSean Christopherson 						   uint32_t vcpuids[])
521*67730e6cSSean Christopherson {
522*67730e6cSSean Christopherson 	struct vm_gic v;
523*67730e6cSSean Christopherson 	int i;
524*67730e6cSSean Christopherson 
525*67730e6cSSean Christopherson 	v.vm = vm_create(nr_vcpus);
526*67730e6cSSean Christopherson 	for (i = 0; i < nr_vcpus; i++)
527*67730e6cSSean Christopherson 		vm_vcpu_add(v.vm, vcpuids[i], guest_code);
528*67730e6cSSean Christopherson 
529*67730e6cSSean Christopherson 	v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
530*67730e6cSSean Christopherson 
531*67730e6cSSean Christopherson 	return v;
532*67730e6cSSean Christopherson }
533*67730e6cSSean Christopherson 
534*67730e6cSSean Christopherson /**
535*67730e6cSSean Christopherson  * Test GICR_TYPER last bit with new redist regions
536*67730e6cSSean Christopherson  * rdist regions #1 and #2 are contiguous
537*67730e6cSSean Christopherson  * rdist region #0 @0x100000 2 rdist capacity
538*67730e6cSSean Christopherson  *     rdists: 0, 3 (Last)
539*67730e6cSSean Christopherson  * rdist region #1 @0x240000 2 rdist capacity
540*67730e6cSSean Christopherson  *     rdists:  5, 4 (Last)
541*67730e6cSSean Christopherson  * rdist region #2 @0x200000 2 rdist capacity
542*67730e6cSSean Christopherson  *     rdists: 1, 2
543*67730e6cSSean Christopherson  */
544*67730e6cSSean Christopherson static void test_v3_last_bit_redist_regions(void)
545*67730e6cSSean Christopherson {
546*67730e6cSSean Christopherson 	uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
547*67730e6cSSean Christopherson 	struct vm_gic v;
548*67730e6cSSean Christopherson 	uint64_t addr;
549*67730e6cSSean Christopherson 
550*67730e6cSSean Christopherson 	v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
551*67730e6cSSean Christopherson 
552*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
553*67730e6cSSean Christopherson 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
554*67730e6cSSean Christopherson 
555*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x100000, 0, 0);
556*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
557*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
558*67730e6cSSean Christopherson 
559*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x240000, 0, 1);
560*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
561*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
562*67730e6cSSean Christopherson 
563*67730e6cSSean Christopherson 	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 2);
564*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
565*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
566*67730e6cSSean Christopherson 
567*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
568*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
569*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200, "read typer of rdist #2");
570*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #3");
571*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #5");
572*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, 0x410, "read typer of rdist #4");
573*67730e6cSSean Christopherson 
574*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
575*67730e6cSSean Christopherson }
576*67730e6cSSean Christopherson 
577*67730e6cSSean Christopherson /* Test last bit with legacy region */
578*67730e6cSSean Christopherson static void test_v3_last_bit_single_rdist(void)
579*67730e6cSSean Christopherson {
580*67730e6cSSean Christopherson 	uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
581*67730e6cSSean Christopherson 	struct vm_gic v;
582*67730e6cSSean Christopherson 	uint64_t addr;
583*67730e6cSSean Christopherson 
584*67730e6cSSean Christopherson 	v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
585*67730e6cSSean Christopherson 
586*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
587*67730e6cSSean Christopherson 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
588*67730e6cSSean Christopherson 
589*67730e6cSSean Christopherson 	addr = 0x10000;
590*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
591*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
592*67730e6cSSean Christopherson 
593*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
594*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x300, "read typer of rdist #1");
595*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #2");
596*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #3");
597*67730e6cSSean Christopherson 	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210, "read typer of rdist #3");
598*67730e6cSSean Christopherson 
599*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
600*67730e6cSSean Christopherson }
601*67730e6cSSean Christopherson 
602*67730e6cSSean Christopherson /* Uses the legacy REDIST region API. */
603*67730e6cSSean Christopherson static void test_v3_redist_ipa_range_check_at_vcpu_run(void)
604*67730e6cSSean Christopherson {
605*67730e6cSSean Christopherson 	struct kvm_vcpu *vcpus[NR_VCPUS];
606*67730e6cSSean Christopherson 	struct vm_gic v;
607*67730e6cSSean Christopherson 	int ret, i;
608*67730e6cSSean Christopherson 	uint64_t addr;
609*67730e6cSSean Christopherson 
610*67730e6cSSean Christopherson 	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus);
611*67730e6cSSean Christopherson 
612*67730e6cSSean Christopherson 	/* Set space for 3 redists, we have 1 vcpu, so this succeeds. */
613*67730e6cSSean Christopherson 	addr = max_phys_size - (3 * 2 * 0x10000);
614*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
615*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
616*67730e6cSSean Christopherson 
617*67730e6cSSean Christopherson 	addr = 0x00000;
618*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
619*67730e6cSSean Christopherson 			    KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
620*67730e6cSSean Christopherson 
621*67730e6cSSean Christopherson 	/* Add the rest of the VCPUs */
622*67730e6cSSean Christopherson 	for (i = 1; i < NR_VCPUS; ++i)
623*67730e6cSSean Christopherson 		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
624*67730e6cSSean Christopherson 
625*67730e6cSSean Christopherson 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
626*67730e6cSSean Christopherson 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
627*67730e6cSSean Christopherson 
628*67730e6cSSean Christopherson 	/* Attempt to run a vcpu without enough redist space. */
629*67730e6cSSean Christopherson 	ret = run_vcpu(vcpus[2]);
630*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
631*67730e6cSSean Christopherson 		"redist base+size above PA range detected on 1st vcpu run");
632*67730e6cSSean Christopherson 
633*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
634*67730e6cSSean Christopherson }
635*67730e6cSSean Christopherson 
636*67730e6cSSean Christopherson static void test_v3_its_region(void)
637*67730e6cSSean Christopherson {
638*67730e6cSSean Christopherson 	struct kvm_vcpu *vcpus[NR_VCPUS];
639*67730e6cSSean Christopherson 	struct vm_gic v;
640*67730e6cSSean Christopherson 	uint64_t addr;
641*67730e6cSSean Christopherson 	int its_fd, ret;
642*67730e6cSSean Christopherson 
643*67730e6cSSean Christopherson 	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
644*67730e6cSSean Christopherson 	its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS);
645*67730e6cSSean Christopherson 
646*67730e6cSSean Christopherson 	addr = 0x401000;
647*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
648*67730e6cSSean Christopherson 				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
649*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EINVAL,
650*67730e6cSSean Christopherson 		"ITS region with misaligned address");
651*67730e6cSSean Christopherson 
652*67730e6cSSean Christopherson 	addr = max_phys_size;
653*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
654*67730e6cSSean Christopherson 				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
655*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == E2BIG,
656*67730e6cSSean Christopherson 		"register ITS region with base address beyond IPA range");
657*67730e6cSSean Christopherson 
658*67730e6cSSean Christopherson 	addr = max_phys_size - 0x10000;
659*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
660*67730e6cSSean Christopherson 				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
661*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == E2BIG,
662*67730e6cSSean Christopherson 		"Half of ITS region is beyond IPA range");
663*67730e6cSSean Christopherson 
664*67730e6cSSean Christopherson 	/* This one succeeds setting the ITS base */
665*67730e6cSSean Christopherson 	addr = 0x400000;
666*67730e6cSSean Christopherson 	kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
667*67730e6cSSean Christopherson 			    KVM_VGIC_ITS_ADDR_TYPE, &addr);
668*67730e6cSSean Christopherson 
669*67730e6cSSean Christopherson 	addr = 0x300000;
670*67730e6cSSean Christopherson 	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
671*67730e6cSSean Christopherson 				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
672*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == EEXIST, "ITS base set again");
673*67730e6cSSean Christopherson 
674*67730e6cSSean Christopherson 	close(its_fd);
675*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
676*67730e6cSSean Christopherson }
677*67730e6cSSean Christopherson 
678*67730e6cSSean Christopherson /*
679*67730e6cSSean Christopherson  * Returns 0 if it's possible to create GIC device of a given type (V2 or V3).
680*67730e6cSSean Christopherson  */
681*67730e6cSSean Christopherson int test_kvm_device(uint32_t gic_dev_type)
682*67730e6cSSean Christopherson {
683*67730e6cSSean Christopherson 	struct kvm_vcpu *vcpus[NR_VCPUS];
684*67730e6cSSean Christopherson 	struct vm_gic v;
685*67730e6cSSean Christopherson 	uint32_t other;
686*67730e6cSSean Christopherson 	int ret;
687*67730e6cSSean Christopherson 
688*67730e6cSSean Christopherson 	v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
689*67730e6cSSean Christopherson 
690*67730e6cSSean Christopherson 	/* try to create a non existing KVM device */
691*67730e6cSSean Christopherson 	ret = __kvm_test_create_device(v.vm, 0);
692*67730e6cSSean Christopherson 	TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
693*67730e6cSSean Christopherson 
694*67730e6cSSean Christopherson 	/* trial mode */
695*67730e6cSSean Christopherson 	ret = __kvm_test_create_device(v.vm, gic_dev_type);
696*67730e6cSSean Christopherson 	if (ret)
697*67730e6cSSean Christopherson 		return ret;
698*67730e6cSSean Christopherson 	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
699*67730e6cSSean Christopherson 
700*67730e6cSSean Christopherson 	ret = __kvm_create_device(v.vm, gic_dev_type);
701*67730e6cSSean Christopherson 	TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
702*67730e6cSSean Christopherson 
703*67730e6cSSean Christopherson 	/* try to create the other gic_dev_type */
704*67730e6cSSean Christopherson 	other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3
705*67730e6cSSean Christopherson 					     : KVM_DEV_TYPE_ARM_VGIC_V2;
706*67730e6cSSean Christopherson 
707*67730e6cSSean Christopherson 	if (!__kvm_test_create_device(v.vm, other)) {
708*67730e6cSSean Christopherson 		ret = __kvm_create_device(v.vm, other);
709*67730e6cSSean Christopherson 		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
710*67730e6cSSean Christopherson 				"create GIC device while other version exists");
711*67730e6cSSean Christopherson 	}
712*67730e6cSSean Christopherson 
713*67730e6cSSean Christopherson 	vm_gic_destroy(&v);
714*67730e6cSSean Christopherson 
715*67730e6cSSean Christopherson 	return 0;
716*67730e6cSSean Christopherson }
717*67730e6cSSean Christopherson 
718*67730e6cSSean Christopherson void run_tests(uint32_t gic_dev_type)
719*67730e6cSSean Christopherson {
720*67730e6cSSean Christopherson 	test_vcpus_then_vgic(gic_dev_type);
721*67730e6cSSean Christopherson 	test_vgic_then_vcpus(gic_dev_type);
722*67730e6cSSean Christopherson 
723*67730e6cSSean Christopherson 	if (VGIC_DEV_IS_V2(gic_dev_type))
724*67730e6cSSean Christopherson 		test_v2_uaccess_cpuif_no_vcpus();
725*67730e6cSSean Christopherson 
726*67730e6cSSean Christopherson 	if (VGIC_DEV_IS_V3(gic_dev_type)) {
727*67730e6cSSean Christopherson 		test_v3_new_redist_regions();
728*67730e6cSSean Christopherson 		test_v3_typer_accesses();
729*67730e6cSSean Christopherson 		test_v3_last_bit_redist_regions();
730*67730e6cSSean Christopherson 		test_v3_last_bit_single_rdist();
731*67730e6cSSean Christopherson 		test_v3_redist_ipa_range_check_at_vcpu_run();
732*67730e6cSSean Christopherson 		test_v3_its_region();
733*67730e6cSSean Christopherson 	}
734*67730e6cSSean Christopherson }
735*67730e6cSSean Christopherson 
736*67730e6cSSean Christopherson int main(int ac, char **av)
737*67730e6cSSean Christopherson {
738*67730e6cSSean Christopherson 	int ret;
739*67730e6cSSean Christopherson 	int pa_bits;
740*67730e6cSSean Christopherson 	int cnt_impl = 0;
741*67730e6cSSean Christopherson 
742*67730e6cSSean Christopherson 	pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
743*67730e6cSSean Christopherson 	max_phys_size = 1ULL << pa_bits;
744*67730e6cSSean Christopherson 
745*67730e6cSSean Christopherson 	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V3);
746*67730e6cSSean Christopherson 	if (!ret) {
747*67730e6cSSean Christopherson 		pr_info("Running GIC_v3 tests.\n");
748*67730e6cSSean Christopherson 		run_tests(KVM_DEV_TYPE_ARM_VGIC_V3);
749*67730e6cSSean Christopherson 		cnt_impl++;
750*67730e6cSSean Christopherson 	}
751*67730e6cSSean Christopherson 
752*67730e6cSSean Christopherson 	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V2);
753*67730e6cSSean Christopherson 	if (!ret) {
754*67730e6cSSean Christopherson 		pr_info("Running GIC_v2 tests.\n");
755*67730e6cSSean Christopherson 		run_tests(KVM_DEV_TYPE_ARM_VGIC_V2);
756*67730e6cSSean Christopherson 		cnt_impl++;
757*67730e6cSSean Christopherson 	}
758*67730e6cSSean Christopherson 
759*67730e6cSSean Christopherson 	if (!cnt_impl) {
760*67730e6cSSean Christopherson 		print_skip("No GICv2 nor GICv3 support");
761*67730e6cSSean Christopherson 		exit(KSFT_SKIP);
762*67730e6cSSean Christopherson 	}
763*67730e6cSSean Christopherson 	return 0;
764*67730e6cSSean Christopherson }
765